nip2-8.7.1/0000755000175000017500000000000013417043453007404 500000000000000nip2-8.7.1/aclocal.m40000644000175000017500000020617713417043240011173 00000000000000# generated automatically by aclocal 1.16.1 -*- Autoconf -*- # Copyright (C) 1996-2018 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) 1995-2002 Free Software Foundation, Inc. # Copyright (C) 2001-2003,2004 Red Hat, Inc. # # This file is free software, distributed under the terms of the GNU # General Public License. As a special exception to the GNU General # Public License, this file may be distributed as part of a program # that contains a configuration script generated by Autoconf, under # the same distribution terms as the rest of that program. # # This file can be copied and used freely without restrictions. It can # be used in projects which are not available under the GNU Public License # but which still want to provide support for the GNU gettext functionality. # # Macro to add for using GNU gettext. # Ulrich Drepper , 1995, 1996 # # Modified to never use included libintl. # Owen Taylor , 12/15/1998 # # Major rework to remove unused code # Owen Taylor , 12/11/2002 # # Added better handling of ALL_LINGUAS from GNU gettext version # written by Bruno Haible, Owen Taylor 5/30/3002 # # Modified to require ngettext # Matthias Clasen 08/06/2004 # Increment this whenever this file is changed. #serial 1 # We need this here as well, since someone might use autoconf-2.5x # to configure GLib then an older version to configure a package # using AM_GLIB_GNU_GETTEXT AC_PREREQ(2.53) dnl dnl We go to great lengths to make sure that aclocal won't dnl try to pull in the installed version of these macros dnl when running aclocal in the glib directory. dnl m4_copy([AC_DEFUN],[glib_DEFUN]) m4_copy([AC_REQUIRE],[glib_REQUIRE]) dnl dnl At the end, if we're not within glib, we'll define the public dnl definitions in terms of our private definitions. dnl # GLIB_LC_MESSAGES #-------------------- glib_DEFUN([GLIB_LC_MESSAGES], [AC_CHECK_HEADERS([locale.h]) if test $ac_cv_header_locale_h = yes; then AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, [AC_TRY_LINK([#include ], [return LC_MESSAGES], am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) if test $am_cv_val_LC_MESSAGES = yes; then AC_DEFINE(HAVE_LC_MESSAGES, 1, [Define if your file defines LC_MESSAGES.]) fi fi]) # GLIB_PATH_PROG_WITH_TEST #---------------------------- dnl GLIB_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) glib_DEFUN([GLIB_PATH_PROG_WITH_TEST], [# Extract the first word of "$2", so it can be a program name with args. set dummy $2; ac_word=[$]2 AC_MSG_CHECKING([for $ac_word]) AC_CACHE_VAL(ac_cv_path_$1, [case "[$]$1" in /*) ac_cv_path_$1="[$]$1" # Let the user override the test with a path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in ifelse([$5], , $PATH, [$5]); do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if [$3]; then ac_cv_path_$1="$ac_dir/$ac_word" break fi fi done IFS="$ac_save_ifs" dnl If no 4th arg is given, leave the cache variable unset, dnl so AC_PATH_PROGS will keep looking. ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ])dnl ;; esac])dnl $1="$ac_cv_path_$1" if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then AC_MSG_RESULT([$]$1) else AC_MSG_RESULT(no) fi AC_SUBST($1)dnl ]) dnl Checks for special options needed on Mac OS X. dnl Defines INTL_MACOSX_LIBS. dnl dnl Copied from intlmacosx.m4 in gettext, GPL. dnl Copyright (C) 2004-2013 Free Software Foundation, Inc. glib_DEFUN([glib_gt_INTL_MACOSX], [ dnl Check for API introduced in Mac OS X 10.2. AC_CACHE_CHECK([for CFPreferencesCopyAppValue], [gt_cv_func_CFPreferencesCopyAppValue], [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [[CFPreferencesCopyAppValue(NULL, NULL)]])], [gt_cv_func_CFPreferencesCopyAppValue=yes], [gt_cv_func_CFPreferencesCopyAppValue=no]) LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], [1], [Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) fi dnl Check for API introduced in Mac OS X 10.3. AC_CACHE_CHECK([for CFLocaleCopyCurrent], [gt_cv_func_CFLocaleCopyCurrent], [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [[CFLocaleCopyCurrent();]])], [gt_cv_func_CFLocaleCopyCurrent=yes], [gt_cv_func_CFLocaleCopyCurrent=no]) LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFLocaleCopyCurrent = yes; then AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], [1], [Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi AC_SUBST([INTL_MACOSX_LIBS]) ]) # GLIB_WITH_NLS #----------------- glib_DEFUN([GLIB_WITH_NLS], dnl NLS is obligatory [USE_NLS=yes AC_SUBST(USE_NLS) gt_cv_have_gettext=no CATOBJEXT=NONE XGETTEXT=: INTLLIBS= glib_gt_INTL_MACOSX AC_CHECK_HEADER(libintl.h, [gt_cv_func_dgettext_libintl="no" libintl_extra_libs="" # # First check in libc # AC_CACHE_CHECK([for ngettext in libc], gt_cv_func_ngettext_libc, [AC_TRY_LINK([ #include ], [return !ngettext ("","", 1)], gt_cv_func_ngettext_libc=yes, gt_cv_func_ngettext_libc=no) ]) if test "$gt_cv_func_ngettext_libc" = "yes" ; then AC_CACHE_CHECK([for dgettext in libc], gt_cv_func_dgettext_libc, [AC_TRY_LINK([ #include ], [return !dgettext ("","")], gt_cv_func_dgettext_libc=yes, gt_cv_func_dgettext_libc=no) ]) fi if test "$gt_cv_func_ngettext_libc" = "yes" ; then AC_CHECK_FUNCS(bind_textdomain_codeset) fi # # If we don't have everything we want, check in libintl # if test "$gt_cv_func_dgettext_libc" != "yes" \ || test "$gt_cv_func_ngettext_libc" != "yes" \ || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then AC_CHECK_LIB(intl, bindtextdomain, [AC_CHECK_LIB(intl, ngettext, [AC_CHECK_LIB(intl, dgettext, gt_cv_func_dgettext_libintl=yes)])]) if test "$gt_cv_func_dgettext_libintl" != "yes" ; then AC_MSG_CHECKING([if -liconv is needed to use gettext]) AC_MSG_RESULT([]) AC_CHECK_LIB(intl, ngettext, [AC_CHECK_LIB(intl, dcgettext, [gt_cv_func_dgettext_libintl=yes libintl_extra_libs=-liconv], :,-liconv)], :,-liconv) fi # # If we found libintl, then check in it for bind_textdomain_codeset(); # we'll prefer libc if neither have bind_textdomain_codeset(), # and both have dgettext and ngettext # if test "$gt_cv_func_dgettext_libintl" = "yes" ; then glib_save_LIBS="$LIBS" LIBS="$LIBS -lintl $libintl_extra_libs" unset ac_cv_func_bind_textdomain_codeset AC_CHECK_FUNCS(bind_textdomain_codeset) LIBS="$glib_save_LIBS" if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then gt_cv_func_dgettext_libc=no else if test "$gt_cv_func_dgettext_libc" = "yes" \ && test "$gt_cv_func_ngettext_libc" = "yes"; then gt_cv_func_dgettext_libintl=no fi fi fi fi if test "$gt_cv_func_dgettext_libc" = "yes" \ || test "$gt_cv_func_dgettext_libintl" = "yes"; then gt_cv_have_gettext=yes fi if test "$gt_cv_func_dgettext_libintl" = "yes"; then INTLLIBS="-lintl $libintl_extra_libs $INTL_MACOSX_LIBS" fi if test "$gt_cv_have_gettext" = "yes"; then AC_DEFINE(HAVE_GETTEXT,1, [Define if the GNU gettext() function is already present or preinstalled.]) GLIB_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl if test "$MSGFMT" != "no"; then glib_save_LIBS="$LIBS" LIBS="$LIBS $INTLLIBS" AC_CHECK_FUNCS(dcgettext) MSGFMT_OPTS= AC_MSG_CHECKING([if msgfmt accepts -c]) GLIB_RUN_PROG([$MSGFMT -c -o /dev/null],[ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Project-Id-Version: test 1.0\n" "PO-Revision-Date: 2007-02-15 12:01+0100\n" "Last-Translator: test \n" "Language-Team: C \n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" ], [MSGFMT_OPTS=-c; AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) AC_SUBST(MSGFMT_OPTS) AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) GLIB_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; return _nl_msg_cat_cntr], [CATOBJEXT=.gmo DATADIRNAME=share], [case $host in *-*-solaris*) dnl On Solaris, if bind_textdomain_codeset is in libc, dnl GNU format message catalog is always supported, dnl since both are added to the libc all together. dnl Hence, we'd like to go with DATADIRNAME=share and dnl and CATOBJEXT=.gmo in this case. AC_CHECK_FUNC(bind_textdomain_codeset, [CATOBJEXT=.gmo DATADIRNAME=share], [CATOBJEXT=.mo DATADIRNAME=lib]) ;; *-*-openbsd*) CATOBJEXT=.mo DATADIRNAME=share ;; *) CATOBJEXT=.mo DATADIRNAME=lib ;; esac]) LIBS="$glib_save_LIBS" INSTOBJEXT=.mo else gt_cv_have_gettext=no fi fi ]) if test "$gt_cv_have_gettext" = "yes" ; then AC_DEFINE(ENABLE_NLS, 1, [always defined to indicate that i18n is enabled]) fi dnl Test whether we really found GNU xgettext. if test "$XGETTEXT" != ":"; then dnl If it is not GNU xgettext we define it as : so that the dnl Makefiles still can work. if $XGETTEXT --omit-header /dev/null 2> /dev/null; then : ; else AC_MSG_RESULT( [found xgettext program is not GNU xgettext; ignore it]) XGETTEXT=":" fi fi # We need to process the po/ directory. POSUB=po AC_OUTPUT_COMMANDS( [case "$CONFIG_FILES" in *po/Makefile.in*) sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile esac]) dnl These rules are solely for the distribution goal. While doing this dnl we only have to keep exactly one list of the available catalogs dnl in configure.ac. for lang in $ALL_LINGUAS; do GMOFILES="$GMOFILES $lang.gmo" POFILES="$POFILES $lang.po" done dnl Make all variables we use known to autoconf. AC_SUBST(CATALOGS) AC_SUBST(CATOBJEXT) AC_SUBST(DATADIRNAME) AC_SUBST(GMOFILES) AC_SUBST(INSTOBJEXT) AC_SUBST(INTLLIBS) AC_SUBST(PO_IN_DATADIR_TRUE) AC_SUBST(PO_IN_DATADIR_FALSE) AC_SUBST(POFILES) AC_SUBST(POSUB) ]) # AM_GLIB_GNU_GETTEXT # ------------------- # Do checks necessary for use of gettext. If a suitable implementation # of gettext is found in either in libintl or in the C library, # it will set INTLLIBS to the libraries needed for use of gettext # and AC_DEFINE() HAVE_GETTEXT and ENABLE_NLS. (The shell variable # gt_cv_have_gettext will be set to "yes".) It will also call AC_SUBST() # on various variables needed by the Makefile.in.in installed by # glib-gettextize. dnl AU_DEFUN([GLIB_GNU_GETTEXT], [AC_REQUIRE([AC_PROG_CC])dnl GLIB_LC_MESSAGES GLIB_WITH_NLS if test "$gt_cv_have_gettext" = "yes"; then if test "x$ALL_LINGUAS" = "x"; then LINGUAS= else AC_MSG_CHECKING(for catalogs to be installed) NEW_LINGUAS= for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then NEW_LINGUAS="$NEW_LINGUAS $presentlang" fi done LINGUAS=$NEW_LINGUAS AC_MSG_RESULT($LINGUAS) fi dnl Construct list of names of catalog files to be constructed. if test -n "$LINGUAS"; then for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done fi fi dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly dnl find the mkinstalldirs script in another subdir but ($top_srcdir). dnl Try to locate is. MKINSTALLDIRS= if test -n "$ac_aux_dir"; then MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" fi if test -z "$MKINSTALLDIRS"; then MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" fi AC_SUBST(MKINSTALLDIRS) dnl Generate list of files to be processed by xgettext which will dnl be included in po/Makefile. test -d po || mkdir po if test "x$srcdir" != "x."; then if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then posrcprefix="$srcdir/" else posrcprefix="../$srcdir/" fi else posrcprefix="../" fi rm -f po/POTFILES sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ < $srcdir/po/POTFILES.in > po/POTFILES ], [[$0: This macro is deprecated. You should use upstream gettext instead.]]) # AM_GLIB_DEFINE_LOCALEDIR(VARIABLE) # ------------------------------- # Define VARIABLE to the location where catalog files will # be installed by po/Makefile. glib_DEFUN([GLIB_DEFINE_LOCALEDIR], [glib_REQUIRE([GLIB_GNU_GETTEXT])dnl glib_save_prefix="$prefix" glib_save_exec_prefix="$exec_prefix" glib_save_datarootdir="$datarootdir" test "x$prefix" = xNONE && prefix=$ac_default_prefix test "x$exec_prefix" = xNONE && exec_prefix=$prefix datarootdir=`eval echo "${datarootdir}"` if test "x$CATOBJEXT" = "x.mo" ; then localedir=`eval echo "${libdir}/locale"` else localedir=`eval echo "${datadir}/locale"` fi prefix="$glib_save_prefix" exec_prefix="$glib_save_exec_prefix" datarootdir="$glib_save_datarootdir" AC_DEFINE_UNQUOTED($1, "$localedir", [Define the location where the catalogs will be installed]) ]) dnl dnl Now the definitions that aclocal will find dnl ifdef(glib_configure_ac,[],[ AC_DEFUN([AM_GLIB_GNU_GETTEXT],[GLIB_GNU_GETTEXT($@)]) AC_DEFUN([AM_GLIB_DEFINE_LOCALEDIR],[GLIB_DEFINE_LOCALEDIR($@)]) ])dnl # GLIB_RUN_PROG(PROGRAM, TEST-FILE, [ACTION-IF-PASS], [ACTION-IF-FAIL]) # # Create a temporary file with TEST-FILE as its contents and pass the # file name to PROGRAM. Perform ACTION-IF-PASS if PROGRAM exits with # 0 and perform ACTION-IF-FAIL for any other exit status. AC_DEFUN([GLIB_RUN_PROG], [cat >conftest.foo <<_ACEOF $2 _ACEOF if AC_RUN_LOG([$1 conftest.foo]); then m4_ifval([$3], [$3], [:]) m4_ifvaln([$4], [else $4])dnl echo "$as_me: failed input was:" >&AS_MESSAGE_LOG_FD sed 's/^/| /' conftest.foo >&AS_MESSAGE_LOG_FD fi]) dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- dnl serial 11 (pkg-config-0.29.1) dnl dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson 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 2 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, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl 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, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.1]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR # Copyright (C) 2002-2018 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.1], [], [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.1])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-2018 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-2018 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-2018 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-2018 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. 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}"])]) # Copyright (C) 1996-2018 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. AC_DEFUN([AM_WITH_DMALLOC], [AC_MSG_CHECKING([if malloc debugging is wanted]) AC_ARG_WITH([dmalloc], [AS_HELP_STRING([--with-dmalloc], [use dmalloc, as in http://www.dmalloc.com])], [if test "$withval" = yes; then AC_MSG_RESULT([yes]) AC_DEFINE([WITH_DMALLOC], [1], [Define if using the dmalloc debugging malloc package]) LIBS="$LIBS -ldmalloc" LDFLAGS="$LDFLAGS -g" else AC_MSG_RESULT([no]) fi], [AC_MSG_RESULT([no])]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2018 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: # # 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: 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: . 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-2018 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-2018 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-2018 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-2018 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 case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac 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-2018 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-2018 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-2018 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-2018 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-2018 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-2018 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-2018 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-2018 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 /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 m4_include([m4/libtool.m4]) m4_include([m4/ltoptions.m4]) m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) nip2-8.7.1/share/0000755000175000017500000000000013417043452010505 500000000000000nip2-8.7.1/share/nip2/0000755000175000017500000000000013417043452011355 500000000000000nip2-8.7.1/share/nip2/rc/0000755000175000017500000000000013417043452011761 500000000000000nip2-8.7.1/share/nip2/rc/ipgtkrc0000644000175000017500000000341213351443023013262 00000000000000 # style for parent widgets style "parent_style" { bg[NORMAL] = "#887FA3" bg[PRELIGHT] = "#ADA7C8" bg[ACTIVE] = "#887FA3" bg[SELECTED] = "#887FA3" bg[INSENSITIVE] = "#625B81" } # style for child widgets style "child_style" { bg[NORMAL] = "#7590AE" bg[PRELIGHT] = "#9DB8D2" bg[ACTIVE] = "#7590AE" bg[SELECTED] = "#7590AE" bg[INSENSITIVE] = "#4B6983" } # style for selected widgets style "selected_style" { bg[NORMAL] = "#83A67F" bg[PRELIGHT] = "#C5D2C8" bg[ACTIVE] = "#83A67F" bg[SELECTED] = "#83A67F" bg[INSENSITIVE] = "#5D7555" } # style for unselected column headers style "column_style" { bg[NORMAL] = "#C5D2C8" bg[PRELIGHT] = "#C5D2C8" bg[ACTIVE] = "#C5D2C8" bg[SELECTED] = "#C5D2C8" bg[INSENSITIVE] = "#C5D2C8" } # style for widgets with errors in them style "error_style" { bg[NORMAL] = "#C1665A" bg[PRELIGHT] = "#E0B6AF" bg[ACTIVE] = "#C1665A" bg[SELECTED] = "#C1665A" bg[INSENSITIVE] = "#884631" } # style for dirty widgets (need recalculation) style "dirty_style" { bg[NORMAL] = "#E0C39E" bg[PRELIGHT] = "#EFE0CD" bg[ACTIVE] = "#E0C39E" bg[SELECTED] = "#E0C39E" bg[INSENSITIVE] = "#B39169" } # style for captions ... eg. the line of text under the image thumbnails style "caption_style" { bg[NORMAL] = "#EED680" } widget "*parent_widget*" style "parent_style" widget "*child_widget*" style "child_style" widget "*selected_widget*" style "selected_style" widget "*column_widget*" style "column_style" widget "*error_widget*" style "error_style" widget "*dirty_widget*" style "dirty_style" widget "*caption_widget*" style "caption_style" widget "*centre_widget*" style "child_style" widget "*shadow_widget*" style "column_style" # turn this on here ... no one will find this useful thing unless we turn it # on by default gtk-can-change-accels = 1 nip2-8.7.1/share/nip2/rc/Makefile.am0000644000175000017500000000010513351443023013724 00000000000000rcdir = $(pkgdatadir)/rc rc_DATA = ipgtkrc EXTRA_DIST = $(rc_DATA) nip2-8.7.1/share/nip2/rc/Makefile.in0000644000175000017500000003630713417043242013754 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/rc ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(rcdir)" DATA = $(rc_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ rcdir = $(pkgdatadir)/rc rc_DATA = ipgtkrc EXTRA_DIST = $(rc_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/rc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/rc/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-rcDATA: $(rc_DATA) @$(NORMAL_INSTALL) @list='$(rc_DATA)'; test -n "$(rcdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(rcdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(rcdir)" || 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)$(rcdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(rcdir)" || exit $$?; \ done uninstall-rcDATA: @$(NORMAL_UNINSTALL) @list='$(rc_DATA)'; test -n "$(rcdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(rcdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(rcdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-rcDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-rcDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-rcDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-rcDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/start/0000755000175000017500000000000013417043452012512 500000000000000nip2-8.7.1/share/nip2/start/Image.def0000644000175000017500000015445613351443023014146 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process = [ // we can't use id here since we want to "declass" // the members of x ... consider if x is a crop class, // for example, we don't want to inherit from crop, we // want to make a new image class rot180 @ rot180, rot90, rot180, rot270 ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel h v image, aspect = resize kernel fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize kernel fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_map_item = class Menuaction "_Map" "map an image through a 2D transform image" { action a b = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_binary trans a b { trans a b = mapim interp.value in index { // get the index image first [index, in] = sortc (const is_twocomponent) [a, b]; // is a two-component image, ie. one band complex, or // two-band non-complex is_twocomponent x = is_nonc x || is_c x; is_nonc x = has_bands x && get_bands x == 2 && has_format x && !is_complex_format (get_format x); is_c x = has_bands x && get_bands x == 1 && has_format x && is_complex_format (get_format x); is_complex_format f = f == Image_format.COMPLEX || f == Image_format.DPCOMPLEX; } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1a = Menuseparator; Bandand_item = class Menuaction "Bitwise Band AND" "bitwise AND of image bands" { action x = bandand x; } Bandor_item = class Menuaction "Bitwise Band OR" "bitwise OR of image bands" { action x = bandor x; } sep2 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_alpha_item = class Menupullright "_Alpha" "manipulate image alpha" { Add_item = class Menuaction "_Add" "add alpha" { action x = class _result { _vislevel = 3; opacity = Expression "Opacity (255 == solid)" 255; _result = x ++ to_real opacity; } } Flatten_item = class Menuaction "_Flatten" "flatten alpha out of image" { action x = class _result { _vislevel = 3; bg = Expression "Background" 0; _result = map_unary (flattenimage bg) x; } } Extract_item = class Menuaction "_Extract" "extract alpha" { action x = map_unary exb x { exb x = extract_bands (x.bands - 1) 1 x; } } Drop_item = class Menuaction "_Drop" "drop alpha" { action x = map_unary exb x { exb x = extract_bands 0 (x.bands - 1) x; } } sep1 = Menuseparator; Premultiply_item = class Menuaction "_Premultiply" "premultiply alpha" { action x = premultiply x; } Unpremultiply_item = class Menuaction "_Unpremultiply" "unpremultiply alpha" { action x = unpremultiply x; } sep2 = Menuseparator; Composite2_item = class Menuaction "_Composite two" "composite a pair of images" { action x y = class _result { _vislevel = 3; blend = Option_enum (_ "Blend mode") modes "over" { modes = Blend_type.types; } compositing_space = Option_enum (_ "Compositing space") spaces "sRGB" { spaces = Image_type.image_colour_spaces; } premultiplied = Toggle (_ "Premultiplied") false; _result = Image output { [output] = vips_call "composite" [[y.value, x.value], blend.value] [$compositing_space => compositing_space.value_thing, $premultiplied => premultiplied.value ]; } } } Composite3_item = class Menuaction "_Composite three" "composite three images" { action x y z = class _result { _vislevel = 3; blend1 = Option_enum (_ "Blend mode") modes "over" { modes = Blend_type.types; } blend2 = Option_enum (_ "Blend mode") modes "over" { modes = Blend_type.types; } compositing_space = Option_enum (_ "Compositing space") spaces "sRGB" { spaces = Image_type.image_colour_spaces; } premultiplied = Toggle (_ "Premultiplied") false; _result = Image output { [output] = vips_call "composite" [[z.value, y.value, x.value], [blend1.value, blend2.value]] [$compositing_space => compositing_space.value_thing, $premultiplied => premultiplied.value ]; } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = crop x [l, t, w, h] { fields = [ [has_left, get_left, 0], [has_top, get_top, 0], [has_width, get_width, 100], [has_height, get_height, 100] ]; [l, t, w, h] = map get_default fields { get_default line = get x, has x = default { [has, get, default] = line; } } } crop x geo = class _result { _vislevel = 3; l = Expression "Crop left" ((int) (geo?0 + geo?2 / 4)); t = Expression "Crop top" ((int) (geo?1 + geo?3 / 4)); w = Expression "Crop width" (max_pair 1 ((int) (geo?2 / 2))); h = Expression "Crop height" (max_pair 1 ((int) (geo?3 / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 0; sy = Expression "Start y" 0; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise Join" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; snake = Toggle "Reverse the order of every other row" false; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _l' = map2 reverse_if_odd [0..] _l, snake = _l { reverse_if_odd n x = reverse x, n % 2 == 1 = x; } _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l')); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Noise_item = class Menupullright "_Noise" "various noise generators" { Gaussian_item = class Menuaction "_Gaussian" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (gaussnoise nwidth nheight mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal noise image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Perlin_item = class Menuaction "_Perlin" "Perlin noise image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; cell_size = Expression "Cell size (pixels)" 8; eight = Toggle "Eight bit output" true; _result = 128 * im + 128, eight = im { im = perlin cell_size nwidth nheight; } } } Worley_item = class Menuaction "_Worley" "Worley noise image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 512; nheight = Expression "Image height (pixels)" 512; cell_size = Expression "Cell size (pixels)" 256; _result = worley cell_size nwidth nheight; } } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; fontfile = Pathname "Font file" ""; width = Expression "Text width" 0; height = Expression "Text height" 0; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; fit = Toggle "Fit text to box" false; spacing = Expression "Line spacing" 0; _result = Image out { base_options = [ $font => font.value, $align => align.value ]; set_option name default value = [name => value], value != default = []; options = base_options ++ concat [ set_option $width 0 (to_real width), set_option $height 0 (to_real height), set_option $fontfile "" fontfile.value, if !fit then set_option $dpi 72 (to_real dpi) else [], set_option $spacing 0 (to_real spacing) ]; [out] = vips_call "text" [text.value] options; } } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/start/_convert.def0000644000175000017500000005063113351443023014731 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make a Vector ... works for Vector/Image/Real, plus image/real */ to_vector x = to_vector x.expr, is_Expression x = x, is_Vector x = oo_unary_function to_vector_op x, is_class x = tov x { to_vector_op = Operator "to_vector" tov Operator_type.COMPOUND false; tov x = Vector (itov x), is_image x = Vector [x], is_real x = Vector x, is_real_list x = Vector x?0, is_matrix x && len x == 1 = Vector (transpose x)?0, is_matrix x && len x?0 == 1 = error (_ "bad arguments to " ++ "to_vector"); itov i = v, is_image i = error (_ "not image") { m = im_vips2mask ((double) i); v = m.value?0, m.height == 1 = (transpose m.value)?0, m.width == 1 = error (_ "image is not 1xN or Nx1"); } } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = Image x.value, is_Plot x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The outermost list objects become Group()'d. */ to_group x = Group x, is_list x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = sign * (abs ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; sign = 1, ipart >= 0 = -1; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* The vips8 scRGB functions. */ im_sRGB2scRGB in = out { [out] = vips_call "sRGB2scRGB" [in] []; } im_scRGB2sRGB in = out { [out] = vips_call "scRGB2sRGB" [in] []; } im_scRGB2XYZ in = out { [out] = vips_call "scRGB2XYZ" [in] []; } im_XYZ2scRGB in = out { [out] = vips_call "XYZ2scRGB" [in] []; } /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, scRGB, im_sRGB2scRGB @ im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, scRGB, im_XYZ2scRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, scRGB, im_XYZ2scRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, scRGB, im_XYZ2scRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, scRGB, im_sRGB2scRGB @ im_clip], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_Lab2LabS @ im_sRGB2Lab @ im_clip], [scRGB, B_W, im_sRGB2mono @ im_scRGB2sRGB], [scRGB, XYZ, im_scRGB2XYZ], [scRGB, YXY, im_XYZ2Yxy @ im_scRGB2XYZ], [scRGB, LAB, im_XYZ2Lab @ im_scRGB2XYZ], [scRGB, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_scRGB2XYZ], [scRGB, UCS, im_XYZ2UCS @ im_scRGB2XYZ], [scRGB, RGB, im_XYZ2disp @ im_scRGB2XYZ], [scRGB, sRGB, im_scRGB2sRGB], [scRGB, scRGB, image_set_type scRGB], [scRGB, RGB16, image_set_type RGB16 @ im_8216 @ im_scRGB2sRGB], [scRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono @ im_scRGB2sRGB], [scRGB, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_scRGB2XYZ], [scRGB, LABS, im_Lab2LabS @ im_XYZ2Lab @ im_scRGB2XYZ], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, scRGB, im_sRGB2scRGB], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, scRGB, im_sRGB2scRGB @ im_mono2sRGB], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabS2Lab @ im_clip2s], [LABS, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LabS2Lab @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; scRGB = 28; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; /* Return $PATH, reformatted as [["comp1", "comp2"], ["comp1", "comp2"] ..] */ system_search_path = [vipsbin] ++ map path_parse (split (equal path_sep) (expand "$PATH")) { /* On some platforms we ship vips with a few extra progs. Search * $VIPSHOME/bin first. */ vipsbin = path_parse (expand "$VIPSHOME") ++ ["bin"]; path_sep = ':', expand "$SEP" == "/" = ';'; } /* Search $PATH for the first occurence of name, or "". */ search_for name = hits?0, hits != [] = "" { exe_name = name ++ expand "$EXEEXT"; form_path p = path_absolute (p ++ [exe_name]); paths = map form_path system_search_path; hits = dropwhile (equal []) (map search paths); } /* Search $PATH for the first occurence of name, error on failure. */ search_for_error name = path, path != "" = error (exe_name ++ " not found on your search path. " ++ "Check you have installed the program and it is on your PATH.") { exe_name = name ++ expand "$EXEEXT"; path = search_for name; } nip2-8.7.1/share/nip2/start/Filter.def0000644000175000017500000011767613351443023014354 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 2; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 20; fs = Scale "Sharpen flat areas by" 0 5 0.5; js = Scale "Sharpen jaggy areas by" 0 5 1; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x; } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Canny_item = class Menuaction "Canny" "Canny edge detector" { action x = class _result { _vislevel = 3; sigma = Scale "Sigma" 0.1 10 2; prec = Option "Precision" ["Int", "Float", "Approximate"] 1; _result = map_unary process x { process in = canny sigma prec.value in; } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; max_slope = Scale "Maxium slope" 0 10 0; _result = map_unary process x { process in = hist_equalize_local window_width window_height max_slope in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_hough_item = class Menupullright "_Hough Transform" "transform to parameter space" { Line_item = class Menuaction "_Line" "find straight line Hough transform" { action a = class _result { _vislevel = 3; pspace_width = Expression "Parameter space width" 64; pspace_height = Expression "Parameter space height" 64; _result = map_unary line a { line a = hough_line (to_real pspace_width) (to_real pspace_height) a; } } } Circle_item = class Menuaction "_Circle" "find circle Hough transform" { action a = class _result { _vislevel = 3; scale = Expression "Scale down parameter space by" 10; min_radius = Expression "Minimum radius" 10; max_radius = Expression "Maximum radius" 30; _result = map_unary circle a { circle a = hough_circle (to_real scale) (to_real min_radius) (to_real max_radius) a; } } } } Filter_coordinate_item = class Menupullright "_Coordinate Transform" "various coordinate transforms" { // run a function which wants a complex arg on a non-complex two-band // image run_cmplx fn x = re x' ++ im x' { x' = fn (x?0, x?1); } Polar_item = class Menuaction "_Polar" "transform to polar coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_polar a { to_polar im = mapim interp.value map' im { // xy image, origin in the centre, scaled to fit image to // a circle xy = make_xy im.width im.height; xy' = xy - Vector [im.width / 2, im.height / 2]; scale = min [im.width, im.height] / im.width; xy'' = 2 * xy' / scale; // to polar, scale vertical axis to 360 degrees map = run_cmplx polar xy''; map' = map * Vector [1, im.height / 360]; } } } } Rectangular_item = class Menuaction "_Rectangular" "transform to rectangular coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_rect a { to_rect im = mapim interp.value map'' im { // xy image, vertical scaled to 360 degrees xy = make_xy im.width im.height; xy' = xy * Vector [1, 360 / im.height]; // to rect, scale to image rect map = run_cmplx rectangular xy'; scale = min [im.width, im.height] / im.width; map' = map * scale / 2; map'' = map' + Vector [im.width / 2, im.height / 2]; } } } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "Blend _Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } Autotrace_item = class Menuaction "_Trace" "convert a bitmap to an SVG file" { action x = class _result { _vislevel = 3; despeckle = Scale "Despeckle level" 1 20 1; line = Scale "Line threshold" 1 20 1; center = Toggle "Trace centreline" false; scale = Scale "SVG scale" 0.1 10 1; command = "autotrace %s " ++ join_sep " " [ofmt, ofile, desp, lint, cent] { prog = search_for_error "autotrace"; ofmt = "-output-format svg"; ofile = "-output-file %s"; desp = "-despeckle-level " ++ print despeckle.value; lint = "-line-threshold " ++ print line.value; cent = if center then "-centerline " else ""; } _result = Image output { [output] = vips_call "system" [command] [$in => [x.value], $in_format => "%s.ppm", $out => true, $out_format => "%s.svg[scale=" ++ print scale.value ++ "]" ]; } } } nip2-8.7.1/share/nip2/start/_joe_extra.def0000644000175000017500000003225713351443023015235 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use an Arrow or Region x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { im = x.image; mask = Image m { rx = x.region_rect, is_Region x = x; b = image_new im.width im.height 1 0 0 1 0 0 0; w = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0; m = insert_noexpand rx.nleft rx.ntop w b; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } Fill_item = class Menuaction "_Fill" "fill zero pixels with the nearest non-zero" { action x = class Image _result { _vislevel = 3; distance = Image _distance; [_result, _distance] = vips_call "fill_nearest" [x.value] [ "distance" => true ]; } } fill_nearest x = oo_unary_function nearest_op x, is_class x = near x, is_image x = error (_ "bad arguments to " ++ "fill_nearest") { nearest_op = Operator "fill_nearest" fill_nearest Operator_type.COMPOUND_REWRAP false; near x = [out, distance] { [out, distance] = vips_call "fill_nearest" [x] [ "distance" => true ]; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Kernel_linear f1 1 b1 {b1 = resize Kernel_linear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/start/Preferences.ws0000644000175000017500000010177213351443023015251 00000000000000 nip2-8.7.1/share/nip2/start/Magick.def0000644000175000017500000014112713351443023014306 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate Magick.def 13-Apr-2014 snibgo Put "new image" items into sub-menu. New class VirtualPixlBack. 17-Apr-2014 snibgo Many small changes. A few new menu options. Created sub-menu for multi-input operations. 3-May-2014 jcupitt Put quotes around ( in shadow to help unix Last update: 17-Apr-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ // We don't need Noop. /*=== Magick_noop_item = class Menuaction "_Noop" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_testPar_item = class Menuaction "_TestPar" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "( +clone ) +append ", "\"%s\"" ]; _result = Magick.system command x; } } /* Removed Read_item and Write_item, much better to use nip2 load/save image. * Plus they can load all libMagick formats anyway. */ // Put "new image" items into sub-menu Magick_NewImageMenu_item = class Menupullright "_New image" "make a new image" { Magick_newcanvas_item = class Menuaction "_Solid colour" "make image of solid colour" { action = class _result { _vislevel = 3; size = Magick.Size_widget; colour = Magick.generalcol_widget; command = Magick.command [ size._flag, "\"canvas:" ++ colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_builtin_item = class Menuaction "_Built-in image" "create a built-in image" { action = class _result { _vislevel = 3; builtin = Magick.builtin_widget; command = Magick.command [ builtin._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_gradient_item = class Menuaction "_Gradient" "make a linear gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; topColour = Magick.generalcol_widget; bottomColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"gradient:", topColour._flag, "-", bottomColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } Magick_hald_item = class Menuaction "_Hald-clut image" "create an identity hald-clut image" { action = class _result { _vislevel = 3; order = Expression "order" 8; command = Magick.command [ "hald:" ++ print order.expr, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_pattern_item = class Menuaction "_Pattern" "create pattern" { action = class _result { _vislevel = 3; size = Magick.Size_widget; pattern = Magick.pattern_widget; command = Magick.command [ size._flag, pattern._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_plasma_item = class Menuaction "_Plasma image" "create plasma image" { action = class _result { _vislevel = 3; size = Magick.Size_widget; // FIXME? ColourA-ColourB. // FIXME? Allow plasma:fractal? command = Magick.command [ size._flag, "plasma:", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_radialgradient_item = class Menuaction "_Radial gradient" "make a radial gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; innerColour = Magick.generalcol_widget; outerColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"radial-gradient:", innerColour._flag, "-", outerColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } } // end Magick_NewImageMenu_item Magick_MultiMenu_item = class Menupullright "_Multiple inputs" "make an image from multiple images" { Magick_composite_item = class Menuaction "_Composite" "composite two images (without mask)" { action x y = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_compositeMask_item = class Menuaction "_Composite masked" "composite two images (with mask)" { action x y z = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system3 command x y z; } } // FIXME: other operations like remap that take another image as arguments are: // mask (pointless?), texture, tile (pointless?) // FIXME: operations that take a filename that isn't an image: // cdl, profile Magick_clut_item = class Menuaction "_Clut" "replace values using second image as colour look-up table" { action x y = class _result { _vislevel = 3; // FIXME: uses -intensity "when mapping greyscale CLUT image to alpha channel if set by -channels" command = Magick.command [ "\"%s\"", "\"%s\"", "-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_haldclut_item = class Menuaction "_Hald clut" "replace values using second image as Hald colour look-up table" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"", "-hald-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } // Encipher and decipher: key files can be text or image files. Magick_encipher_item = class Menuaction "_Encipher/Decipher" "encipher or decipher an image image" { action x = class _result { _vislevel = 3; pathname = Pathname "Read key file" ""; isDecipher = Toggle "Decipher" false; command = Magick.command [ "\"%s\"", if pathname.value == "" then "" else ( ( if isDecipher then "-decipher " else "-encipher ") ++ ( "\"" ++ pathname.value ++ "\"" ) ), "\"%s\"" ]; _result = Magick.system command x; } } Magick_profile_item = class Menuaction "_Profile" "assigns/applies an ICC profile" { action x = class _result { _vislevel = 3; pathname1 = Pathname "Read profile file" ""; pathname2 = Pathname "Read profile file" ""; command = Magick.command [ "\"%s\"", if pathname1.value == "" then "" else ( "-profile " ++ "\"" ++ pathname1.value ++ "\""), if pathname2.value == "" then "" else ( "-profile " ++ "\"" ++ pathname2.value ++ "\""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_remap_item = class Menuaction "_Remap" "reduce colours to those in another image" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-remap", "\"%s\"", "\"%s\"" ]; _result = Magick.system2 command x y; } } } // end Magick_MultiMenu_item Magick_image_type_item = class Menuaction "_Image Type" "change image type" { action x = class _result { _vislevel = 3; imagetype = Magick.imagetype_widget; command = Magick.command [ "\"%s\"", imagetype._flag, "\"%s\"" ]; _result = Magick.system command x; } } sep2 = Menuseparator; Magick_alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = Magick.alpha_widget; command = Magick.command [ "\"%s\"", alpha._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = Magick.text_widget; font = Magick.Font_widget; geometry = Magick.AnnotGeometry_widget; gravity = Magick.gravity_widget; foreground = Magick.foreground_widget; undercol = Magick.undercol_widget; antialias = Magick.antialias_widget; command = Magick.command [ "\"%s\"", font._flag, antialias._flag, gravity._flag, foreground._flag, undercol._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoGamma_item = class Menuaction "_AutoGamma" "automatic gamma" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-gamma", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoLevel_item = class Menuaction "_AutoLevel" "automatic level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-level", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blurSharpMenu_item = class Menupullright "_Blur/Sharpen" "blur and sharpen" { Magick_adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; // note: adaptive-blur doesn't regard VP. command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-adaptive-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_blur_item = class Menuaction "_Blur" "blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gaussianBlur_item = class Menuaction "_Gaussian Blur" "blur with a Gaussian operator" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-gaussian-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_motionBlur_item = class Menuaction "_Motion Blur" "simulate motion blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; channels = Magick.ch_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-motion-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotationalBlur_item = class Menuaction "_RotationalBlur" "blur around the centre" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; angle = Scale "angle (degrees)" (-360) 360 20; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-radial-blur", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_selectiveBlur_item = class Menuaction "_Selective Blur" "blur where contrast is less than or equal to threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; threshold = Scale "Threshold (percent)" 0 100 50; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", intensity._flag, virtpixback._flag, channels._flag, "-selective-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print threshold.value ++ "%%", "\"%s\"" ]; _result = Magick.system command x; } } sep1 = Menuseparator; Magick_adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-adaptive-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sharpen_item = class Menuaction "_Sharpen" "sharpen" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_unsharpen_item = class Menuaction "_Unsharp" "sharpen with unsharp mask" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; gain = Scale "Gain" (-10) 10 1; threshold = Scale "Threshold" 0 1 0.05; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-unsharp", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print gain.value ++ "+" ++ print threshold.value, "\"%s\"" ]; _result = Magick.system command x; } } } // end BlurSharpMenu_item Magick_border_item = class Menuaction "_Border" "add border of given colour" { action x = class _result { _vislevel = 3; compose = Magick.compose_widget; width = Expression "Width" 3; bordercol = Magick.bordercol_widget; command = Magick.command [ "\"%s\"", compose._flag, bordercol._flag, "-border", print width.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_brightCont_item = class Menuaction "_Brightness-contrast" "adjust the brightness and/or contrast" { action x = class _result { _vislevel = 3; bri = Scale "brightness" (-100) 100 0; con = Scale "contrast" (-100) 100 0; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-brightness-contrast", print bri.value ++ "x" ++ print con.value, "\"%s\"" ]; _result = Magick.system command x; } } // Note: canny requires ImageMagick 6.8.9-0 or later. Magick_canny_item = class Menuaction "_Canny" "detect a wide range of edges" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; lowPc = Scale "lower percent" 0 100 10; highPc = Scale "lower percent" 0 100 10; command = Magick.command [ "\"%s\"", "-canny", concat ["\"", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print lowPc.value ++ "%%+" ++ print highPc.value ++ "%%" ++ "\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_charcoal_item = class Menuaction "_Charcoal" "simulate a charcoal drawing" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; factor = Scale "factor" 0 50 1; command = Magick.command [ "\"%s\"", intensity._flag, "-charcoal", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_chop_item = class Menuaction "_Chop" "remove pixels from the interior" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-chop", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorize_item = class Menuaction "_Colorize" "colorize by given amount" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; val = Scale "value" 0 100 100; command = Magick.command [ "\"%s\"", foreground._flag, "-colorize", print val.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colors_item = class Menuaction "_Colors" "reduce number of colors" { action x = class _result { _vislevel = 3; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; quantize = Magick.colorspace_widget; colors = Expression "Colours" 3; command = Magick.command [ "\"%s\"", "-quantize", quantize._flag, "-treedepth", print treedepth.expr, dither._flag, "-colors", print colors.expr, "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: color-matrix? Magick_colorspace_item = class Menuaction "_Colourspace" "convert to arbitrary colourspace" { action x = class _result { _vislevel = 3; colsp = Magick.colorspace_widget; command = Magick.command [ "\"%s\"", "-colorspace", colsp._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorspaceGray_item = class Menuaction "_Colourspace gray" "convert to gray using given intensity method" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-colorspace gray", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrast_item = class Menuaction "_Contrast" "increase or reduce the contrast" { action x = class _result { _vislevel = 3; isReduce = Toggle "reduce contrast" false; command = Magick.command [ "\"%s\"", (if isReduce then "+" else "-") ++ "contrast", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrastStretch_item = class Menuaction "_Contrast stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-contrast-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: convolve (bias, kernel) Magick_crop_item = class Menuaction "_Crop" "cut out a rectangular region" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-crop", geometry._flag, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_deskew_item = class Menuaction "_Deskew" "straighten the image" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; // FIXME: toggle auto-crop? command = Magick.command [ "\"%s\"", "-deskew", "\"" ++ print threshold.value ++ "%%\"", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_despeckle_item = class Menuaction "_Despeckle" "reduce the speckles" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-despeckle", "\"%s\"" ]; _result = Magick.system command x; } } Magick_distort_item = class Menuaction "_Distort" "distort using a method and arguments" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; distort = Magick.distort_widget; args = String "Arguments" "1,0"; isPlus = Toggle "Extend to show entire image" false; command = Magick.command [ "\"%s\"", virtpixback._flag, (if isPlus then "+" else "-") ++ "distort", distort._flag, args.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_draw_item = class Menuaction "_Draw" "annotate with one or more graphic primitives" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; args = String "Arguments" "line 0,0 9,9 rectangle 10,10 20,20"; command = Magick.command [ "\"%s\"", foreground._flag, "-draw", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_edge_item = class Menuaction "_Edge" "detect edges" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-edge", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_emboss_item = class Menuaction "_Emboss" "emboss" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-emboss", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_enhance_item = class Menuaction "_Enhance" "enhance a noisy image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-enhance", "\"%s\"" ]; _result = Magick.system command x; } } Magick_equalize_item = class Menuaction "_Equalize" "equalize the histogram" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-equalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_evaluate_item = class Menuaction "_Evaluate" "evaluate an expression on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; operation = Magick.evaluate_widget; val = Expression "value" 5; isPc = Toggle "Value is percent" false; command = Magick.command [ "\"%s\"", channels._flag, operation._flag, print val.expr ++ if isPc then "%%" else "", "\"%s\"" ]; _result = Magick.system command x; } } Magick_extent_item = class Menuaction "_Extent" "set the image size and offset" { action x = class _result { _vislevel = 3; background = Magick.background_widget; compose = Magick.compose_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, background._flag, gravity._flag, "-extent", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_FlipFlopMenu_item = class Menupullright "_Flip/flop" "flip/flop/transverse/transpose" { Magick_flip_item = class Menuaction "_Flip vertically" "mirror upside-down" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flip", "\"%s\"" ]; _result = Magick.system command x; } } Magick_flop_item = class Menuaction "_Flop horizontally" "mirror left-right" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flop", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transpose_item = class Menuaction "_Transpose" "mirror along the top-left to bottom-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transpose +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transverse_item = class Menuaction "_Transverse" "mirror along the bottom-left to top-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transverse +repage", "\"%s\"" ]; _result = Magick.system command x; } } } // end Magick_FlipFlopMenu_item Magick_floodfill_item = class Menuaction "_Floodfill" "recolour neighbours that match" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; fuzz = Magick.fuzz_widget; coordinate = Magick.coordinate_widget; // -draw "color x,y floodfill" command = Magick.command [ "\"%s\"", foreground._flag, "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-draw \" color", coordinate._flag, "floodfill \"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_frame_item = class Menuaction "_Frame" "surround with border or beveled frame" { action x = class _result { _vislevel = 3; border = Magick.bordercol_widget; compose = Magick.compose_widget; matte = Magick.mattecol_widget; geometry = Magick.FrameGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, border._flag, matte._flag, "-frame", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_function_item = class Menuaction "_Function" "evaluate a function on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; function = Magick.function_widget; // FIXME: explain values; use sensible defaults. values = String "values" "0,0,0,0"; command = Magick.command [ "\"%s\"", channels._flag, "-function", function._flag, values.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_fx_item = class Menuaction "_Fx" "apply a mathematical expression" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; interpolate = Magick.interpolate_widget; virtpixback = Magick.VirtualPixelBack_widget; args = String "Expression" "u*1/2"; command = Magick.command [ "\"%s\"", channels._flag, interpolate._flag, virtpixback._flag, "-fx", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_gamma_item = class Menuaction "_Gamma" "apply a gamma correction" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; gamma = Magick.gamma_widget; command = Magick.command [ "\"%s\"", channels._flag, "-gamma", print gamma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradient_item = class Menuaction "_Gradient" "apply a linear gradient" { action x = class _result { _vislevel = 3; colourA = Magick.generalcol_widget; colourB = Magick.generalcol_widget; position = Option "colourA is at" [ "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"] 0; _baryArg = concat ["0,0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 0 = concat ["0,0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 1 = concat ["0,0,", colourA._flag, " %%[fx:w-1],0,", colourB._flag], position.value == 2 = concat ["0,0,", colourB._flag, " %%[fx:w-1],0,", colourA._flag], position.value == 3 = concat ["0,0,", colourA._flag, " %%[fx:w-1],%%[fx:h-1],", colourB._flag], position.value == 4 = concat ["%%[fx:w-1],0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 5 = concat ["%%[fx:w-1],0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 6 = concat ["0,0,", colourB._flag, " %%[fx:w-1],%%[fx:h-1],", colourA._flag], position.value == 7 = "dunno"; command = Magick.command [ "\"%s\"", "-sparse-color barycentric \"" ++ _baryArg ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradientCorn_item = class Menuaction "_Gradient corners" "apply a bilinear gradient between the corners" { action x = class _result { _vislevel = 3; colour_top_left = Magick.generalcol_widget; colour_top_right = Magick.generalcol_widget; colour_bottom_left = Magick.generalcol_widget; colour_bottom_right = Magick.generalcol_widget; command = Magick.command [ "\"%s\"", "-sparse-color bilinear \"" ++ "0,0," ++ colour_top_left._flag ++ ",%%[fx:w-1],0" ++ colour_top_right._flag ++ ",0,%%[fx:h-1]" ++ colour_bottom_left._flag ++ ",%%[fx:w-1],%%[fx:h-1]" ++ colour_bottom_right._flag ++ "\"", "+depth", "\"%s\"" ]; _result = Magick.system command x; } } Magick_histogram_item = class Menuaction "_Histogram" "make a histogram image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-define histogram:unique-colors=false histogram:" ++ "\"%s\"" ]; _result = Magick.system command x; } } Magick_implode_item = class Menuaction "_Implode" "implode pixels about the center" { action x = class _result { _vislevel = 3; factor = Scale "factor" 0 20 1; interpolate = Magick.interpolate_widget; // FIXME: virtual-pixel? command = Magick.command [ "\"%s\"", interpolate._flag, "-implode", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_level_item = class Menuaction "_Level" "adjust the level of channels" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "black point" (-100) 200 0; wht = Scale "white point" (-100) 200 100; gam = Scale "gamma" 0 30 1; isPc = Toggle "Levels are percent" true; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level", "\"" ++ print blk.value ++ "," ++ print wht.value ++ (if isPc then "%%" else "") ++ "," ++ print gam.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_levelCols_item = class Menuaction "_Level colors" "adjust levels to given colours" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; colour_black = Magick.generalcol_widget; colour_white = Magick.generalcol_widget; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level-colors", "\"" ++ colour_black._flag ++ "," ++ colour_white._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_linearStretch_item = class Menuaction "_Linear stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", channels._flag, "-linear-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_magnify_item = class Menuaction "_Magnify" "double the size of the image with pixel art scaling" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-magnify", "\"%s\"" ]; _result = Magick.system command x; } } Magick_modulate_item = class Menuaction "_Modulate" "modulate brightness, saturation and hue" { action x = class _result { _vislevel = 3; modcolsp = Magick.ModColSp_widget; bright = Scale "brightness" 0 200 100; sat = Scale "saturation" 0 200 100; hue = Scale "hue" 0 200 100; command = Magick.command [ "\"%s\"", modcolsp._flag, "-modulate", print bright.value ++ "," ++ print sat.value ++ "," ++ print hue.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_monochrome_item = class Menuaction "_Monochrome" "transform to black and white" { action x = class _result { _vislevel = 3; // FIXME: also intensity? intensity = Magick.intensity_widget; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; command = Magick.command [ "\"%s\"", intensity._flag, dither._flag, "-treedepth", print treedepth.expr, "-monochrome", "\"%s\"" ]; _result = Magick.system command x; } } Magick_morphology_item = class // See http://www.imagemagick.org/Usage/morphology/ Menuaction "_Morphology" "apply a morphological method" { action x = class _result { _vislevel = 3; method = Magick.morphmeth_widget; iter = Expression "Iterations (-1=repeat until done)" 1; kernel = Magick.kernel_widget; // FIXME: custom kernel eg "3x1+2+0:1,0,0" // width x height + offsx + offsy : {w*h values} // each value is 0.0 to 1.0 or "NaN" or "-" // kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0 // but // ring takes: radius1, radius2, scale // rectangle and comet take: width x height + offsx + offsy // blur takes: radius x sigma // FIXME: for now, simply allow any string input. kernel_arg = String "Kernel arguments" ""; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-morphology", method._flag ++ ":" ++ print iter.expr, kernel._flag ++ (if kernel_arg.value == "" then "" else ":") ++ kernel_arg.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_negate_item = class Menuaction "_Negate" "negate" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-negate", "\"%s\"" ]; _result = Magick.system command x; } } Magick_addNoise_item = class Menuaction "_add Noise" "add noise" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; attenuate = Scale "attenuate" 0 1.0 1.0; noise = Magick.noise_widget; command = Magick.command [ "\"%s\"", channels._flag, "-attenuate", print attenuate.value, noise._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_normalize_item = class Menuaction "_Normalize" "normalize" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-normalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_opaque_item = class Menuaction "_Opaque" "change this colour to the fill colour" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; fill = Magick.foreground_widget; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", fill._flag, channels._flag, "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "opaque", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_paint_item = class Menuaction "_Paint" "simulate an oil painting" { action x = class _result { _vislevel = 3; rad = Expression "radius" 10; command = Magick.command [ "\"%s\"", "-paint", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } /*=== FIXME Bug; remove for now. Polaroid_item = class Menuaction "_Polaroid" "simulate a polaroid picture" { action x = class _result { _vislevel = 3; angle = Scale "angle" (-90) 90 20; command = Magick.command [ "\"%s\"", "-polaroid", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_posterize_item = class Menuaction "_Posterize" "reduce to (n) levels per channel" { action x = class _result { _vislevel = 3; levels = Expression "levels" 3; command = Magick.command [ "\"%s\"", "-posterize", print levels.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_raise_item = class Menuaction "_Raise" "lighten or darken image edges" { action x = class _result { _vislevel = 3; thk = Expression "Thickness" 3; command = Magick.command [ "\"%s\"", "-raise", print thk.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_resize_item = class Menuaction "_Resize" "resize to given width and height" { action x = class _result { _vislevel = 3; filter = Magick.filter_widget; type = Magick.ResizeType_widget; width = Scale "Width" 1 100 10; height = Scale "Height" 1 100 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", filter._flag, "-" ++ type._flag, "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "!") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_roll_item = class Menuaction "_Roll" "roll an image horizontally or vertically" { action x = class _result { _vislevel = 3; rollx = Expression "X" 3; rolly = Expression "Y" 3; command = Magick.command [ "\"%s\"", "-roll", (if rollx.expr >= 0 then "+" else "") ++ print rollx.expr ++ (if rolly.expr >= 0 then "+" else "") ++ print rolly.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotate_item = class Menuaction "_Rotate" "rotate" { action x = class _result { _vislevel = 3; angle = Scale "angle (degrees)" (-360) 360 20; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, "+distort", "SRT", print angle.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -segment, but cluster-threshold should be percentage of image area. Magick_sepia_item = class Menuaction "_Sepia tone" "simulate a sepia-toned photo" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; command = Magick.command [ "\"%s\"", "-sepia-tone", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shade_item = class Menuaction "_Shade" "shade with a distant light source" { action x = class _result { _vislevel = 3; azimuth = Scale "Azimuth (degrees)" (-360) 360 0; elevation = Scale "Elevation (degrees)" 0 90 45; command = Magick.command [ "\"%s\"", "-shade", print azimuth.value ++ "x" ++ print elevation.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_shadow_item = class Menuaction "_Shadow" "simulate a shadow" { action x = class _result { _vislevel = 3; shadowCol = Magick.generalcol_widget; opacity = Scale "Opacity (percent)" 0 100 75; sigma = Scale "Sigma" 0 30 2; // FIXME: make offsets a single widget? offsx = Scale "X-offset" (-20) 20 4; offsy = Scale "Y-offset" (-20) 20 4; arePc = Toggle "offsets are percentages" false; // FIXME: raw operation creates page offset, which vips dislikes. // So we take this futher, compositing with source. command = Magick.command [ "\"%s\"", "\"(\" +clone", "-background", "\"" ++ shadowCol._flag ++ "\"", "-shadow", concat [ "\"", print opacity.value, "x", print sigma.value, (if offsx.value >= 0 then "+" else ""), print offsx.value, (if offsy.value >= 0 then "+" else ""), print offsy.value, (if arePc then "%%" else ""), "\"" ], "\")\" +swap -background None -layers merge", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shave_item = class Menuaction "_Shave" "shave pixels from the edges" { action x = class _result { _vislevel = 3; width = Scale "Width" 0 50 10; height = Scale "Height" 0 50 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", "-shave", "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shear_item = class Menuaction "_Shear" "shear along the x-axis and/or y-axis" { action x = class _result { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-shear", print shearX.expr ++ "x" ++ print shearY.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sigmoid_item = class Menuaction "_Sigmoid" "increase or decrease mid-tone contrast sigmoidally" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; contrast = Scale "contrast" 0 30 3; midpoint = Scale "mid-point (percent)" 0 100 50; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "sigmoidal-contrast", "\"" ++ print contrast.value ++ "x" ++ print midpoint.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_sketch_item = class Menuaction "_Sketch" "simulate a pencil sketch" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; command = Magick.command [ "\"%s\"", "-sketch", print radius.value ++ "x" ++ print sigma.value ++ (if angle >= 0 then ("+" ++ print angle.value) else ""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_solarize_item = class Menuaction "_Solarize" "negate all pixels above a threshold level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-solarize", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -sparse-color needs abitrary list of {x,y,colour}. Magick_splice_item = class Menuaction "_Splice" "splice a colour into the image" { action x = class _result { _vislevel = 3; background = Magick.background_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", background._flag, gravity._flag, "-splice", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_spread_item = class Menuaction "_Spread" "displace pixels by random amount" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; amount = Expression "Amount (pixels)" 5; command = Magick.command [ "\"%s\"", virtpixback._flag, "-spread", print amount.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_statistic_item = class Menuaction "_Statistic" "replace each pixel with statistic from neighbourhood" { action x = class _result { _vislevel = 3; width = Expression "Width" 5; height = Expression "Height" 5; statisticType = Magick.StatType_widget; command = Magick.command [ "\"%s\"", "-statistic", statisticType._flag, print width.expr ++ "x" ++ print height.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = Magick.angle_widget; command = Magick.command [ "\"%s\"", "-swirl", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_thresholdMenu_item = class Menupullright "_Threshold" "make black or white" { Magick_threshold_item = class Menuaction "_Threshold" "apply black/white threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blackThreshold_item = class Menuaction "_Black threshold" "where below threshold set to black" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-black-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_whiteThreshold_item = class Menuaction "_White threshold" "where above threshold set to white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-white-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_latThreshold_item = class Menuaction "_Local Adaptive Threshold" "where above average plus offset set to white, otherwise black" { action x = class _result { _vislevel = 3; width = Expression "Width" 10; height = Expression "Height" 10; offset = Scale "Offset (percent)" (-100) 100 0; // note: "-lat" doesn't respond to channels command = Magick.command [ "\"%s\"", "-lat", concat ["\"", print width.expr, "x", print height.expr, (if offset.value >= 0 then "+" else ""), print offset.value, "%%\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_randThreshold_item = class Menuaction "_Random Threshold" "between specified limits, apply random threshold" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; low = Scale "Low threshold" 0 100 10; high = Scale "High threshold" 0 100 90; isPc = Toggle "Thresholds are percent" true; command = Magick.command [ "\"%s\"", channels._flag, "-random-threshold", "\"" ++ print low.value ++ "x" ++ print high.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } } // end ThresholdMenu_item // Note: alternatives include: // convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif Magick_tile_item = class Menuaction "_Tile" "fill given size with tiled image" { action x = class _result { _vislevel = 3; size = Magick.Size_widget; command = Magick.command [ size._flag, "tile:" ++ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_tint_item = class Menuaction "_Tint" "apply a tint" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; amount = Scale "amount (percent)" 0 100 50; command = Magick.command [ "\"%s\"", foreground._flag, "-tint", // snibgo note: although the amount is a percentage, it doesn't need "%" character. print amount.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_transparent_item = class Menuaction "_Transparent" "make this colour transparent" { action x = class _result { _vislevel = 3; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "transparent", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_trim_item = class Menuaction "_Trim" "trims away border" { action x = class _result { _vislevel = 3; fuzz = Magick.fuzz_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-trim +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_uniqueCols_item = class Menuaction "_Unique colours" "discard all but one of any pixel color" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-unique-colors", "\"%s\"" ]; _result = Magick.system command x; } } Magick_vignette_item = class Menuaction "_Vignette" "soften the edges in vignette style" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; rx = Scale "Rolloff x (percent)" 0 100 10; ry = Scale "Rolloff y (percent)" 0 100 10; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-vignette", print radius.value ++ "x" ++ print sigma.value ++ (if rx.value >= 0 then "+" else "") ++ print rx.value ++ (if ry.value >= 0 then "+" else "") ++ print ry.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_wave_item = class Menuaction "_Wave" "shear the columns into a sine wave" { action x = class _result { _vislevel = 3; amplitude = Scale "Amplitude (pixels)" 0 100 10; wavelength = Scale "Wavelength (pixels)" 0 100 10; command = Magick.command [ "\"%s\"", "-wave", print amplitude.value ++ "x" ++ print wavelength.value, "\"%s\"" ]; _result = Magick.system command x; } } nip2-8.7.1/share/nip2/start/Colour.def0000644000175000017500000004032613351443023014355 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } CCT_colour = class Menuaction (_ "Colour from CCT") (_ "pick colour by CCT") { action = widget 6500; widget x = class _result { _vislevel = 3; T = Scale "CCT" 1800 25000 x; _result = colour_from_temp (to_real T); Colour_edit space value = widget (temp_from_colour (Colour space value)); } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } scRGB_item = class Menuaction (_ "_scRGB") (_ "convert to scRGB colourspace") { action x = conv Image_type.scRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } scRGB_item = class Menuaction (_ "_scRGB") (_ "tag as being in scRGB colourspace") { action x = tag Image_type.scRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } sep1 = Menuseparator; CCT_item = class Menuaction (_ "Calculate temperature") (_ "estimate CCT using the McCamy approximation") { action z = map_unary temp_from_colour z; } Colour_item = Colour_new_item.CCT_colour; } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = print_profile, has_type image && get_type image == Image_type.CMYK && has_bands image && get_bands image >= 4 = monitor_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; measure = Scale (_ "Measure area (%)") 1 100 50; // get a representative image from an arg get_image x = get_image x.value?0, is_Group x = x; _im = get_image x; sample = measure_draw (to_real pacross) (to_real pdown) (to_real measure) _im; _result = map_unary chart x { chart in = measure_sample (to_real pacross) (to_real pdown) (to_real measure) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/start/_joe_utilities.def0000644000175000017500000005054213351443023016122 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/start/_Object.def0000644000175000017500000002600513351443023014455 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/start/Object.def0000644000175000017500000000220513351443023014312 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/start/Math.def0000644000175000017500000003162513351443023014005 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_AND" "bitwise AND of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_OR" "bitwise OR of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "_XOR" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_NOT" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Bandand_item = Image_band_item.Bandand_item; Bandor_item = Image_band_item.Bandor_item; } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Skew_item = class Menuaction "S_kew" "skew of image or list or vector" { action a = map_unary skew a; } Kurtosis_item = class Menuaction "Kurtosis" "kurtosis of image or list or vector" { action a = map_unary kurtosis a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/start/_generate.def0000644000175000017500000000755513351443023015052 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } mkim options x y b = Image (image_new x y b (opt $format) (opt $coding) (opt $type) (opt $pixel) (opt $xoffset) (opt $yoffset)) { opt = get_option options [ $format => Image_format.UCHAR, $coding => Image_coding.NOCODING, $type => Image_type.sRGB, $pixel => 0, $xoffset => 0, $yoffset => 0 ]; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } /* Make a colour from a temperature. */ colour_from_temp T = error (_ "T out of range"), T < 1667 || T > 25000 = Colour "Yxy" [50, x, y] { // Kim et all approximation // see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation x = -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 + 0.8776956 * 10 ** 3 / T + 0.179910, T < 4000 = -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 + 0.2226347 * 10 ** 3 / T + 0.240390; y = -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + 2.18555832 * x - 0.20219638, T < 2222 = -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867, T < 4000 = 3.0817580 * x ** 3 - 5.87338670 * x ** 2 + 3.75112997 * x - 0.37001483; } temp_from_colour z = T { c = colour_transform_to Image_type.YXY (to_colour z); x = c.value?1; y = c.value?2; // McCamy's approximation, see eg. // http://en.wikipedia.org/wiki/Color_temperature#Approximation xe = 0.332; ye = 0.1858; n = (x - xe) / (y - ye); T = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33; } nip2-8.7.1/share/nip2/start/_stdenv.def0000644000175000017500000020431713351443023014556 00000000000000/* optional args to functions */ get_option options defaults f = error (_ "unknown parameter " ++ f), hits == [] = hits?0 { hits = [v :: [n, v] <- options ++ defaults; n == f]; } /* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } bandand x = oo_unary_function bandand_op x, is_class x = foldr1 bitwise_and (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandand") { bandand_op = Operator "bandand" bandand Operator_type.COMPOUND_REWRAP false; } bandor x = oo_unary_function bandor_op x, is_class x = foldr1 bitwise_or (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandor") { bandor_op = Operator "bandor" bandor Operator_type.COMPOUND_REWRAP false; } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } skew x = oo_unary_function skew_op x, is_class x = sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x = sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "skew") { skew_op = Operator "skew" skew Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = w * h * b, is_image x' = len x'; } kurtosis x = oo_unary_function kurtosis_op x, is_class x = sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x = sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "kurtosis") { kurtosis_op = Operator "kurtosis" kurtosis Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = len x', is_list x'; = w * h * b; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_tile_cache_random x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } decode im = oo_unary_function decode_op im, is_class im = decode_im im, is_image im = error (_ "bad arguments to " ++ "decode") { decode_op = Operator "decode" decode Operator_type.COMPOUND_REWRAP false; decode_im im = im_LabQ2Lab im, get_coding im == Image_coding.LABPACK = im_rad2float im, get_coding im == Image_coding.RAD = im; } measure_draw across down measure image = mark { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; x = map (extract 0) cods; y = map (extract 1) cods; outer = mkim [$pixel => 255] sample_width sample_height 1; inner = mkim [] (sample_width - 4) (sample_height - 4) 1; patch = insert 2 2 inner outer; bg = mkim [] image.width image.height 1; mask = Image (im_insertset bg.value patch.value x y); image' = colour_transform_to Image_type.sRGB image; mark = if mask then Vector [0, 255, 0] else image'; } measure_sample across down measure image = measures { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; image' = decode image; patches = map (\p extract_area p?0 p?1 sample_width sample_height image') cods; measures = Matrix (map (map mean) (map bandsplit patches)); } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed mode index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) (hist_find_indexed mode)) Operator_type.COMPOUND false; indexed index value = out { [out] = vips_call "hist_find_indexed" [value, index] [ "combine" => mode ]; } } hist_entropy x = oo_unary_function hist_entropy_op x, is_class x = entropy x, is_image x = error (_ "bad arguments to " ++ "hist_entropy") { hist_entropy_op = Operator "hist_entropy" hist_entropy Operator_type.COMPOUND_REWRAP false; entropy x = out { [out] = vips_call "hist_entropy" [x] [ ]; } } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_inv hist = oo_unary_function hist_inv_op hist, is_class hist = inv hist, is_image hist = error (_ "bad arguments to " ++ "hist_inv") { hist_inv_op = Operator "hist_inv" hist_inv Operator_type.COMPOUND_REWRAP false; inv im = im_invertlut (to_matrix im''') len { // need a vertical doublemask im' = rot90 im, get_width im > 1 && get_height im == 1 = im, get_width im == 1 && get_height im > 1 = error (_ "not a hist"); len = get_height im'; // values must be scaled to 0 - 1 im'' = im' / (max im'); // add an index column on the left // again, must be in 0-1 y = ((make_xy 1 len)?1) / len; im''' = y ++ im''; } } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h l image = oo_unary_function hist_equalize_local_op image, is_class image = out, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h l) Operator_type.COMPOUND_REWRAP false; [out] = vips_call "hist_local" [image, to_real w, to_real h] [$max_slope => to_real l]; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } reduce kernel xshr yshr image = oo_unary_function reduce_op image, is_class image = reduce_im image, is_image image = error (_ "bad arguments to " ++ "reduce") { reduce_op = Operator "reduce" reduce_im Operator_type.COMPOUND_REWRAP false; reduce_im im = out { [out] = vips_call "reduce" [im, xshr, yshr] [$kernel => kernel.value]; } } similarity interpolate scale angle image = oo_unary_function similarity_op image, is_class image = similarity_im image, is_image image = error (_ "bad arguments to " ++ "similarity") { similarity_op = Operator "similarity" similarity_im Operator_type.COMPOUND_REWRAP false; similarity_im im = out { [out] = vips_call "similarity" [im] [ $interpolate => interpolate.value, $scale => scale, $angle => angle ]; } } resize kernel xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; is_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn // everything else ... we just pass on to vips_resize() = vips_resize kernel xfac' yfac' im { vips_resize kernel hscale vscale im = out { [out] = vips_call "resize" [im, hscale] [$vscale => vscale, $kernel => kernel.value]; } } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C * * Also calculate R2, see eg.: * https://en.wikipedia.org/wiki/Coefficient_of_determination */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } ss = len xes; sx = sum xes; sy = sum yes; my = sy / ss; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; my = sy / len xes; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* One image in, one out. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } /* Two images in, one out. */ system_image2 command x1 x2 = oo_binary_function system_image2_op x1 x2, is_class x1 = oo_binary'_function system_image2_op x1 x2, is_class x2 = system x1 x2, is_image x1 && is_image x2 = error (_ "bad arguments to " ++ "system_image2") { system_image2_op = Operator "system_image2" (system_image2 command) Operator_type.COMPOUND_REWRAP false; system x1 x2 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Three images in, one out. */ system_image3 command x1 x2 x3 = oo_binary_function system_image2_op x2 x3, is_class x2 = oo_binary'_function system_image2_op x2 x3, is_class x3 = system x1 x2 x3, is_image x1 && is_image x2 && is_image x3 = error (_ "bad arguments to " ++ "system_image3") { system_image2_op = Operator "system_image2" (system_image3 command x1) Operator_type.COMPOUND_REWRAP false; system x1 x2 x3 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2, x3], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Zero images in, one out. */ system_image0 command = Image image_out { [image_out] = vips_call "system" [command] [ $out => true, $out_format => "%s.tif" ]; } hough_line w h x = oo_unary_function hough_line_op x, is_class x = hline (to_real w) (to_real h) x, is_image x = error (_ "bad arguments to " ++ "hough_line") { hough_line_op = Operator "hough_line" (hough_line w h) Operator_type.COMPOUND_REWRAP false; hline w h x = pspace { [pspace] = vips_call "hough_line" [x] [ $width => w, $height => h ]; } } hough_circle s mn mx x = oo_unary_function hough_circle_op x, is_class x = hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x = error (_ "bad arguments to " ++ "hough_circle") { hough_circle_op = Operator "hough_circle" (hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false; hcircle s mn mx x = pspace { [pspace] = vips_call "hough_circle" [x] [ $scale => s, $min_radius => mn, $max_radius => mx ]; } } mapim interp ind in = oo_binary_function mapim_op ind in, is_class ind = oo_binary'_function mapim_op ind in, is_class in = mapim_fn ind in, is_image ind && is_image in = error (_ "bad arguments to " ++ "mapim") { mapim_op = Operator "mapim" (mapim interp) Operator_type.COMPOUND_REWRAP false; mapim_fn ind im = out { [out] = vips_call "mapim" [im, ind] [$interpolate => interp]; } } perlin cell width height = Image im { [im] = vips_call "perlin" [to_real width, to_real height] [ $cell_size => to_real cell ]; } worley cell width height = Image im { [im] = vips_call "worley" [to_real width, to_real height] [ $cell_size => to_real cell ]; } gaussnoise width height mean sigma = im { [im] = vips_call "gaussnoise" [to_real width, to_real height] [ $mean => to_real mean, $sigma => to_real sigma ]; } flattenimage bg x = oo_unary_function flatten_op x, is_class x = flt (to_vector bg) x, is_image x = error (_ "bad arguments to " ++ "flattenimage") { flatten_op = Operator "flatten" (flattenimage bg) Operator_type.COMPOUND_REWRAP false; flt bg x = out { [out] = vips_call "flatten" [x] [ $background => bg.value ]; } } premultiply x = oo_unary_function premultiply_op x, is_class x = prem x, is_image x = error (_ "bad arguments to " ++ "premultiply") { premultiply_op = Operator "premultiply" premultiply Operator_type.COMPOUND_REWRAP false; prem x = out { [out] = vips_call "premultiply" [x] [ ]; } } unpremultiply x = oo_unary_function unpremultiply_op x, is_class x = unprem x, is_image x = error (_ "bad arguments to " ++ "unpremultiply") { unpremultiply_op = Operator "unpremultiply" unpremultiply Operator_type.COMPOUND_REWRAP false; unprem x = out { [out] = vips_call "unpremultiply" [x] [ ]; } } hist_entropy x = oo_unary_function hist_entropy_op x, is_class x = entropy x, is_image x = error (_ "bad arguments to " ++ "hist_entropy") { hist_entropy_op = Operator "hist_entropy" hist_entropy Operator_type.COMPOUND_REWRAP false; entropy x = out { [out] = vips_call "hist_entropy" [x] [ ]; } } canny sigma precision x = oo_unary_function canny_op x, is_class x = canny_im (to_real sigma) (to_int precision) x, is_image x = error (_ "bad arguments to " ++ "canny") { canny_op = Operator "canny" (canny sigma precision) Operator_type.COMPOUND_REWRAP false; canny_im sigma precision x = out { [out] = vips_call "canny" [x] [ $sigma => sigma, $precision => precision ]; } } sobel x = oo_unary_function sobel_op x, is_class x = sobel_im x, is_image x = error (_ "bad arguments to " ++ "sobel") { sobel_op = Operator "sobel" sobel Operator_type.COMPOUND_REWRAP false; sobel_im x = out { [out] = vips_call "sobel" [x] [ ]; } } nip2-8.7.1/share/nip2/start/Histogram.def0000644000175000017500000001656713351443023015061 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "_Identity" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = class _result { _vislevel = 3; combine = Combine_picker Combine_type.SUM; _result = map_binary map x y { map a b = hist_find_indexed combine.value index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_inv_item = class Menuaction "In_vert" "invert a histogram" { action x = map_unary hist_inv x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } Hist_entropy_item = class Menuaction "Entropy" "calculate histogram entropy" { action x = hist_entropy x; } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Kernel_linear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; caption = Expression "Chart caption" "none"; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; xcaption = Expression "X axis caption" "none"; ycaption = Expression "Y axis caption" "none"; series_captions = Expression "Series captions" ["Band 0"]; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range ++ captions; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; captions = concat (map test caption_options) ++ [$series_captions => series_captions.expr] { caption_options = [ $caption => caption.expr, $xcaption => xcaption.expr, $ycaption => ycaption.expr ]; test x = [], value == "none" = [option_name => value] { [option_name, value] = x; } } image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/start/Widgets.def0000644000175000017500000000235313351443023014516 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/start/_types.def0000644000175000017500000007534513351443023014426 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; scRGB = 28; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY, $scRGB => scRGB ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options are generated from this, so match the order to the order in * the Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $scRGB => scRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $scRGB => scRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Kernel_type = class { NEAREST_NEIGHBOUR = 0; LINEAR = 1; CUBIC = 2; MITCHELL = 3; LANCZOS2 = 4; LANCZOS3 = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map kernel numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Linear", _ "Cubic", _ "Mitchell", _ "Lanczos, two lobes", _ "Lanczos, three lobes" ]; /* And to vips enum nicknames. */ types = [ "nearest", "linear", "cubic", "mitchell", "lanczos2", "lanczos3" ]; } Kernel type = class { value = Kernel_type.types?type; } Kernel_linear = Kernel Kernel_type.LINEAR; Kernel_picker default = class Kernel kernel.value { _vislevel = 2; kernel = Option "Kernel" Kernel_type.descriptions default; } Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; to_image dpi = extract_bands 0 3 (graph_export_image (to_real dpi) this); } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } Blend_type = class { CLEAR = 0; SOURCE = 1; OVER = 2; IN = 3; OUT = 4; ATOP = 5; DEST = 6; DEST_OVER = 7; DEST_IN = 8; DEST_OUT = 9; DEST_ATOP = 10; XOR = 11; ADD = 12; SATURATE = 13; MULTIPLY = 14; SCREEN = 15; OVERLAY = 16; DARKEN = 17; LIGHTEN = 18; COLOUR_DODGE = 19; COLOUR_BURN = 20; HARD_LIGHT = 21; SOFT_LIGHT = 22; DIFFERENCE = 23; EXCLUSION = 24; /* Table to map blend numbers to descriptive strings */ descriptions = [ _ "Clear", _ "Source", _ "Over", _ "In", _ "Out", _ "Atop", _ "Dest", _ "Dest over", _ "Dest in", _ "Dest out", _ "Dest atop", _ "Xor", _ "Add", _ "Saturate", _ "Multiply", _ "Screen", _ "Overlay", _ "Darken", _ "Lighten", _ "Colour dodge", _ "Colour burn", _ "Hard light", _ "Soft light", _ "Difference", _ "Exclusion" ]; /* And to vips enum nicknames. */ types = Enum [ $clear => "clear", $source => "source", $over => "over", $in => "in", $out => "out", $atop => "atop", $dest => "dest", $dest_over => "dest_over", $dest_in => "dest_in", $dest_out => "dest_out", $dest_atop => "dest_atop", $xor => "xor", $add => "add", $saturate => "saturate", $multiply => "multiply", $screen => "screen", $overlay => "overlay", $darken => "darken", $lighten => "lighten", $colour_dodge => "colour_dodge", $colour_burn => "colour_burn", $hard_light => "hard_light", $soft_light => "soft_light", $difference => "difference", $exclusion => "exclusion" ]; } Blend type = class { value = Blend_type.types?type; } Blend_over = Blend Blend_type.OVER; Blend_picker default = class Blend blend.value { _vislevel = 2; blend = Option "Blend" Blend_type.descriptions default; } Combine_type = class { MAX = 0; SUM = 1; MIN = 2; enum = Enum [ _ "Maximum" => MAX, _ "Sum" => SUM, _ "Minimum" => MIN ]; } Combine type = class { value = Combine_type.enum.names?type; } Combine_sum = Combine Combine_type.SUM; Combine_picker default = Option "Combine" Combine_type.enum.names default; nip2-8.7.1/share/nip2/start/Matrix.def0000644000175000017500000002573113351443023014361 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = identity (identity_matrix 5); identity v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix (identity_matrix (to_real s)), to_real s != len v; = Matrix v; Matrix_vips value scale offset filename display = identity value; } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = series (mkseries 0 1 5); mkseries s t e = transpose [[to_real s, to_real s + to_real t .. to_real e]]; series v = class _result { _vislevel = 3; _s = v?0?0; _t = v?1?0 - v?0?0; _e = (last v)?0; s = Expression "Start value" _s; t = Expression "Step by" _t; e = Expression "End value" _e; _result = Matrix (mkseries s t e), to_real s != _s || to_real t != _t || to_real e != _e = Matrix v; Matrix_vips value scale offset filename display = series value; } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = square (mksquare 5); mksquare s = replicate s (take s [1, 1 ..]); square v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix_con (sum v) 0 v, len v == to_real s = Matrix_con (sum m) 0 m { m = mksquare (to_real s); } Matrix_vips value scale offset filename display = square value; } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = circle (mkcircle 3); mkcircle r = map2 (map2 pyth) xes yes { line = [-r .. r]; xes = replicate (2 * r + 1) line; yes = transpose xes; pyth a b = 1, (a**2 + b**2) ** 0.5 <= r = 0; } circle v = class _result { _vislevel = 3; r = Expression "Radius" ((len v - 1) / 2); _result = Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1 = Matrix_con (sum m) 0 m { m = mkcircle (to_real r); } Matrix_vips value scale offset filename display = circle value; } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/start/Tasks.def0000644000175000017500000006407313351443023014204 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; measure = Scale (_ "Measure area (%)") 1 100 50; sample = measure_draw 6 4 (to_real measure) image; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linearize from chart greyscale", "Fit intercept from chart greyscale", "Linear input, set brightness from chart", "Linear input" ] 0; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure_sample 6 4 (to_real measure) image; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix [[0, 0], [1, 1]] { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map an image though the lineariser linear x = hist_map linearising_lut.value x, mode == 0 || mode == 1 = x; // map the chart measurements though the lineariser _camera' = (to_matrix @ linear @ to_image) _camera; // solve for RGB -> XYZ // normalise: the 2nd row is what makes Y, so divide by that to // get Y in 0-1. _pinv = (transpose _camera' * _camera') ** -1; _full_M = transpose (_pinv * (transpose _camera' * _true_XYZ)); M = _full_M / scale; scale = sum _full_M.value?1; // now turn the camera to LAB and calculate dE76 _camera'' = (to_matrix @ colour_transform Image_type.XYZ Image_type.LAB @ recomb M @ multiply scale @ to_image) _camera'; _dEs = map abs_vec (_camera'' - _true_Lab).value; avg_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } // normalise brightness ... in linear mode, we optionally don't // set the brightness from the Macbeth chart norm x = x * scale, mode != 3 = x; // convert RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ norm @ recomb M @ cast_float @ linear) image.value; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ calib.norm @ recomb calib.M @ cast_float @ calib.linear) image.value; } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Kernel_linear xfactor yfactor scale_im; _offset_im = resize Kernel_linear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/start/Makefile.am0000644000175000017500000000061413351443023014462 00000000000000startdir = $(pkgdatadir)/start start_DATA = \ Math.def \ Image.def \ Magick.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _magick.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/start/Makefile.in0000644000175000017500000003712013417043242014477 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/start ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/start start_DATA = \ Math.def \ Image.def \ Magick.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _magick.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/start/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/start/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/start/_magick.def0000644000175000017500000005322113351443023014502 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate _magick.def Add 0-ary and 2-ary system Put utility funcs into a Magick class 11-Apr-2014 snibgo Added VirtualPixelBack for cases where background is only relevant when VP=Background 17-Apr-2014 snibgo Many small changes. 2-May-2014 jcupitt Added Magick.version 30-June-2014 Put single-quotes around command exe to help win 1-July-2014 Automatically fall back to gm if we can't find convert 17-July-2014 better GM support Last update: 17-July-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ /* Put these in a class to avoid filling the main namespace with IM stuff. */ Magick = class { // first gm on path, or "" gm_path = search_for "gm"; // first convert on $PATH, or "" // we check for the convert we ship first convert_path = vips_convert, vips_convert != "" = search_for "convert" { // the convert we ship with the vips binary on some platforms, or "" vips_convert = search (path_absolute convert) { vipshome = path_parse (expand "$VIPSHOME"); convert = vipshome ++ ["bin", "convert" ++ expand "$EXEEXT"]; } } use_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK; // Are we in GM or IM mode? use_gm = true, use_gm_pref && gm_path != "" = false, !use_gm_pref && convert_path != "" = false, convert_path != "" = true, gm_path != "" = error "neither IM nor GM executable found"; command_path = gm_path, use_gm = convert_path; // try to get the version as eg. [6, 7, 7, 10] // GM versions are smaller, typically [1, 3, 18] version = map parse_int (split (member ".-") version_string) { [output] = vips_call "system" ["'" ++ command_path ++ "' -version"] [$log=>true]; version_string = (split (equal ' ') output)?1, use_gm = (split (equal ' ') output)?2; } // make a command-line ... args is a [str] we join with spaces command args = "'" ++ command_path ++ "' " ++ join_sep " " args' { args' = ["convert"] ++ args, use_gm = args; } // capabilities ... different versions support different features, we // turn features on and off based on these // would probably be better to test for caps somehow has_intensity = false, use_gm = version?0 > 6 || version?1 > 7; has_channel = false, use_gm = version?0 > 6 || version?1 > 7; system0 cmd = system_image0 cmd; system cmd x = map_unary (system_image cmd) x; system2 cmd x y = map_binary (system_image2 cmd) x y; system3 cmd x y z = map_trinary (system_image3 cmd) x y z; radius_widget = Scale "Radius" 0 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle (degrees)" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; gamma_widget = Scale "Gamma" 0 10 1; colors_widget = Scale "Colors" 1 10 3; resize_widget = Scale "Resize (percent)" 0 500 100; fuzz_widget = Scale "Fuzz (percent)" 0 100 0; blur_rad_widget = Scale "Radius (0=auto)" 0 100 0; // a colour with no enclosing quotes ... use this if we know there are // some quotes at an outer level print_colour_nq triple = concat ["#", concat (map fmt triple)] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } // we need the quotes because # is the comment character in *nix print_colour triple = "\"" ++ print_colour_nq triple ++ "\""; Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; GeneralCol triple = class Colour "sRGB" triple { _flag = print_colour_nq triple; Colour_edit space triple = this.GeneralCol triple; } generalcol_widget = GeneralCol [0, 0, 0]; Background triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" false; _flag = "-background " ++ if isNone then "None" else print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Bordercol triple = class Colour "sRGB" triple { _flag = "-bordercolor " ++ print_colour triple; Colour_edit space triple = this.Bordercol triple; } bordercol_widget = Bordercol [0, 0, 0]; Mattecol triple = class Colour "sRGB" triple { _flag = "-mattecolor " ++ print_colour triple; Colour_edit space triple = this.Mattecol triple; } mattecol_widget = Mattecol [189, 189, 189]; // FIXME: Undercolour, like many others, can have alpha channel. // How does user input this? With a slider? Undercol triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" true; _flag = if isNone then "" else ("-undercolor " ++ print_colour triple); Colour_edit space triple = this.Undercol triple; } undercol_widget = Undercol [0, 0, 0]; changeCol_widget = class { _vislevel = 3; colour = GeneralCol [0, 0, 0]; fuzz = fuzz_widget; nonMatch = Toggle "change non-matching colours" false; } Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Remove", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Builtin builtin = class Option_string "Builtin" [ // See http://www.imagemagick.org/script/formats.php "rose:", "logo:", "wizard:", "granite:", "netscape:" ] builtin { _flag = builtin; Option_edit caption labels value = this.Builtin labels?value; } builtin_widget = Builtin "rose:"; channels_widget = class { // FIXME? Can we grey-out alpha when we have no alpha channel, // show CMY(K) instead of RGB(K) etc? // Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA. ChanR valueR = class Toggle "Red" valueR { _flag = "R", valueR = ""; Toggle_edit caption valueR = this.ChanR valueR; } channelR = ChanR true; ChanG valueG = class Toggle "Green" valueG { _flag = "G", valueG = ""; Toggle_edit caption valueG = this.ChanG valueG; } channelG = ChanG true; ChanB valueB = class Toggle "Blue" valueB { _flag = "B", valueB = ""; Toggle_edit caption valueB = this.ChanB valueB; } channelB = ChanB true; ChanK valueK = class Toggle "Black" valueK { _flag = "K", valueK = ""; Toggle_edit caption valueK = this.ChanK valueK; } channelK = ChanK true; ChanA valueA = class Toggle "Alpha" valueA { _flag = "A", valueA = ""; Toggle_edit caption valueA = this.ChanA valueA; } channelA = ChanA false; ChanSy valueSy = class Toggle "Sync" valueSy { _flag = ",sync", valueSy = ""; Toggle_edit caption valueSy = this.ChanSy valueSy; } channelSy = ChanSy true; _rgbka = concat [channelR._flag, channelG._flag, channelB._flag, channelK._flag, channelA._flag ]; _flag = "", _rgbka == "" || !has_channel = concat [ "-channel ", _rgbka, channelSy._flag ]; } ch_widget = channels_widget; Colorspace colsp = class Option_string "Colorspace" [ "CIELab", "CMY", "CMYK", "Gray", "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "Lab", "LCH", "LCHab", "LCHuv", "LMS", "Log", "Luv", "OHTA", "Rec601Luma", "Rec601YCbCr", "Rec709Luma", "Rec709YCbCr", "RGB", "scRGB", "sRGB", "Transparent", "XYZ", "YCbCr", "YDbDr", "YCC", "YIQ", "YPbPr", "YUV" ] colsp { _flag = colsp; Option_edit caption labels value = this.Colorspace labels?value; } colorspace_widget = Colorspace "sRGB"; Compose comp = class Option_string "Compose method" [ "Atop", "Blend", "Blur", "Bumpmap", "ChangeMask", "Clear", "ColorBurn", "ColorDodge", "Colorize", "CopyBlack", "CopyBlue", "CopyCyan", "CopyGreen", "Copy", "CopyMagenta", "CopyOpacity", "CopyRed", "CopyYellow", "Darken", "DarkenIntensity", "DivideDst", "DivideSrc", "Dst", "Difference", "Displace", "Dissolve", "Distort", "DstAtop", "DstIn", "DstOut", "DstOver", "Exclusion", "HardLight", "Hue", "In", "Lighten", "LightenIntensity", "LinearBurn", "LinearDodge", "LinearLight", "Luminize", "Mathematics", "MinusDst", "MinusSrc", "Modulate", "ModulusAdd", "ModulusSubtract", "Multiply", "None", "Out", "Overlay", "Over", "PegtopLight", "PinLight", "Plus", "Replace", "Saturate", "Screen", "SoftLight", "Src", "SrcAtop", "SrcIn", "SrcOut", "SrcOver", "VividLight", "Xor" ] comp { _flag = "-compose " ++ comp; Option_edit caption labels value = this.Compose labels?value; } compose_widget = Compose "Over"; // FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string. // FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack coordinate_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; _flag = concat [print x.expr, ",", print y.expr]; }; Distort distort = class Option_string "Distort" [ "Affine", "AffineProjection", "ScaleRotateTranslate", "SRT", "Perspective", "PerspectiveProjection", "BilinearForward", "BilinearReverse", "Polynomial", "Arc", "Polar", "DePolar", "Barrel", "BarrelInverse", "Shepards", "Resize" ] distort { _flag = distort; Option_edit caption labels value = this.Distort labels?value; } distort_widget = Distort "SRT"; Dither dither = class Option_string "Dither" [ "None", "FloydSteinberg", "Riemersma" ] dither { _flag = "-dither " ++ dither; Option_edit caption labels value = this.Dither labels?value; } dither_widget = Dither "FloydSteinberg"; Evaluate eval = class Option_string "Evaluate operation" [ "Abs", "Add", "AddModulus", "And", "Cos", "Cosine", "Divide", "Exp", "Exponential", "GaussianNoise", "ImpulseNoise", "LaplacianNoise", "LeftShift", "Log", "Max", "Mean", "Median", "Min", "MultiplicativeNoise", "Multiply", "Or", "PoissonNoise", "Pow", "RightShift", "Set", "Sin", "Sine", "Subtract", "Sum", "Threshold", "ThresholdBlack", "ThresholdWhite", "UniformNoise", "Xor" ] eval { _flag = "-evaluate " ++ eval; Option_edit caption labels value = this.Evaluate labels?value; } evaluate_widget = Evaluate "Add"; Filter filt = class Option_string "Filter" [ "default", "Bartlett", "Blackman", "Bohman", "Box", "Catrom", "Cosine", "Cubic", "Gaussian", "Hamming", "Hann", "Hermite", "Jinc", "Kaiser", "Lagrange", "Lanczos", "Lanczos2", "Lanczos2Sharp", "LanczosRadius", "LanczosSharp", "Mitchell", "Parzen", "Point", "Quadratic", "Robidoux", "RobidouxSharp", "Sinc", "SincFast", "Spline", "Triangle", "Welch" ] filt { _flag = if filt == "default" then "" else "-filter " ++ filt; Option_edit caption labels value = this.Filter labels?value; } filter_widget = Filter "default"; Function func = class Option_string "Function" [ "Polynomial", "Sinusoid", "Arcsin", "Arctan" ] func { _flag = func; Option_edit caption labels value = this.Function labels?value; } function_widget = Function "Polynomial"; // "Polynomial (a[n], a[n-1], ... a[1], a[0])", // "Sinusoid (freq, phase, amp, bias)", // "Arcsin (width, centre, range, bias)", // "Arctan (slope, centre, range, bias)" Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; ImageType imagetype = class Option_string "Image type" [ "Bilevel", "ColorSeparation", "ColorSeparationAlpha", "ColorSeparationMatte", "Grayscale", "GrayscaleAlpha", "GrayscaleMatte", "Optimize", "Palette", "PaletteBilevelAlpha", "PaletteBilevelMatte", "PaletteAlpha", "PaletteMatte", "TrueColorAlpha", "TrueColorMatte", "TrueColor" ] imagetype { _flag = "-type " ++ imagetype; Option_edit caption labels value = this.ImageType labels?value; } imagetype_widget = ImageType "TrueColor"; Intensity intensity = class Option_string "Intensity (gray conversion)" [ "Average", "Brightness", "Lightness", "MS", "Rec601Luma", "Rec601Luminance", "Rec709Luma", "Rec709Luminance", "RMS" ] intensity { _flag = "-intensity " ++ intensity, has_intensity = ""; Option_edit caption labels value = this.Intensity labels?value; } intensity_widget = Intensity "Rec709Luminance"; Interpolate interp = class Option_string "Interpolate" [ "default", "Average", "Average4", "Average9", "Average16", "Background", "Bilinear", "Blend", "Integer", "Mesh", "Nearest", "NearestNeighbor", "Spline" ] interp { _flag = if interp == "default" then "" else "-interpolate " ++ interp; Option_edit caption labels value = this.Interpolate labels?value; } interpolate_widget = Interpolate "default"; Kernel kernel = class Option_string "Kernel" [ "Unity", "Gaussian", "DoG", "LoG", "Blur", "Comet", "Binomial", "Laplacian", "Sobel", "FreiChen", "Roberts", "Prewitt", "Compass", "Kirsch", "Diamond", "Square", "Rectangle", "Disk", "Octagon", "Plus", "Cross", "Ring", "Peaks", "Edges", "Corners", "Diagonals", "LineEnds", "LineJunctions", "Ridges", "ConvexHull", "ThinSe", "Skeleton", "Chebyshev", "Manhattan", "Octagonal", "Euclidean" // FIXME: custom kernel ] kernel { _flag = kernel; Option_edit caption labels value = this.Kernel labels?value; } kernel_widget = Kernel "Unity"; ModColSp msp = class Option_string "modulate colorspace" [ "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "LCH" ] msp { _flag = "-set option:modulate:colorspace " ++ msp; Option_edit caption labels value = this.ModColSp labels?value; } ModColSp_widget = ModColSp "HSL"; MorphMeth morph = class Option_string "Method" [ "Correlate", "Convolve", "Dilate", "Erode", "Close", "Open", "DilateIntensity", "ErodeIntensity", "CloseIntensity", "OpenIntensity", "Smooth", "EdgeOut", "EdgeIn", "Edge", "TopHat", "BottomHat", "HitAndMiss", "Thinning", "Thicken", "Distance", "IterativeDistance" ] morph { _flag = morph; Option_edit caption labels value = this.MorphMeth labels?value; } morphmeth_widget = MorphMeth "Dilate"; Noise noise = class Option_string "Noise" [ "Gaussian", "Impulse", "Laplacian", "Multiplicative", "Poisson", "Random", "Uniform" ] noise { _flag = "+noise " ++ noise; Option_edit caption labels value = this.Noise labels?value; } noise_widget = Noise "Gaussian"; Pattern pattern = class Option_string "Noise" [ // See http://www.imagemagick.org/script/formats.php "bricks", "checkerboard", "circles", "crosshatch", "crosshatch30", "crosshatch45", "gray0", "gray5", "gray10", "gray15", "gray20", "gray25", "gray30", "gray35", "gray40", "gray45", "gray50", "gray55", "gray60", "gray65", "gray70", "gray75", "gray80", "gray85", "gray90", "gray95", "gray100", "hexagons", "horizontal", "horizontal2", "horizontal3", "horizontalsaw", "hs_bdiagonal", "hs_cross", "hs_diagcross", "hs_fdiagonal", "hs_horizontal", "hs_vertical", "left30", "left45", "leftshingle", "octagons", "right30", "right45", "rightshingle", "smallfishscales", "vertical", "vertical2", "vertical3", "verticalbricks", "verticalleftshingle", "verticalrightshingle", "verticalsaw" ] pattern { _flag = "pattern:" ++ pattern; Option_edit caption labels value = this.Pattern labels?value; } pattern_widget = Pattern "bricks"; ResizeType resizet = class Option_string "Resize type" [ "resize", "scale", "sample", "adaptive-resize" ] resizet { _flag = resizet; Option_edit caption labels value = this.ResizeType labels?value; } ResizeType_widget = ResizeType "resize"; Size_widget = class { _vislevel = 3; width = Expression "Width (pixels)" 64; height = Expression "Height (pixels)" 64; _flag = "-size " ++ print width.expr ++ "x" ++ print height.expr; }; StatType statt = class Option_string "Statistic type" [ "Gradient", "Maximum", "Mean", "Median", "Minimum", "Mode", "Nonpeak", "StandardDeviation" ] statt { _flag = statt; Option_edit caption labels value = this.StatType labels?value; } StatType_widget = StatType "Mean"; VirtualPixel vp = class Option_string "Virtual pixel" [ "Background", "Black", "CheckerTile", "Dither", "Edge", "Gray", "HorizontalTile", "HorizontalTileEdge", "Mirror", "None", "Random", "Tile", "Transparent", "VerticalTile", "VerticalTileEdge", "White" ] vp { _flag = "-virtual-pixel " ++ vp; _isBackground = (vp == "Background"); Option_edit caption labels value = this.VirtualPixel labels?value; } VirtualPixel_widget = VirtualPixel "Edge"; VirtualPixelBack_widget = class { virtpix = Magick.VirtualPixel_widget; background = Magick.background_widget; _flag = (if virtpix._isBackground then (background._flag ++ " ") else "") ++ virtpix._flag; } Geometry_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; AnnotGeometry_widget = class { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print shearX.expr, "x", print shearY.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; OffsetGeometry_widget = class { _vislevel = 3; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; WhxyGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; FrameGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; outbev = Expression "Outer bevel thickness" 0; inbev = Expression "Inner bevel thickness" 0; _flag = concat [print x.expr, "x", print y.expr, format outbev, format inbev] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } } nip2-8.7.1/share/nip2/start/_predicate.def0000644000175000017500000003263513351443023015215 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Plot x = is_instanceof "Plot" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = oo_unary_function get_type_op x, is_class x = error (_ "bad arguments to " ++ "get_type") { get_type_op = Operator "get_type" get_type Operator_type.COMPOUND false; // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.scRGB, coding == Image_coding.RAD = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.scRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = oo_unary_function get_format_op x, is_class x = error (_ "bad arguments to " ++ "get_format") { get_format_op = Operator "get_format" get_format Operator_type.COMPOUND false; } has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = oo_unary_function get_bits_op x, is_class x = error (_ "bad arguments to " ++ "get_bits") { get_bits_op = Operator "get_bits" get_format Operator_type.COMPOUND false; } has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = oo_unary_function get_bands_op x, is_class x = error (_ "bad arguments to " ++ "get_bands") { get_bands_op = Operator "get_bands" get_bands Operator_type.COMPOUND false; } has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = oo_unary_function get_coding_op x, is_class x = error (_ "bad arguments to " ++ "get_coding") { get_coding_op = Operator "get_coding" get_coding Operator_type.COMPOUND false; } has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = oo_unary_function get_xres_op x, is_class x = error (_ "bad arguments to " ++ "get_xres") { get_xres_op = Operator "get_xres" get_xres Operator_type.COMPOUND false; } has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = oo_unary_function get_yres_op x, is_class x = error (_ "bad arguments to " ++ "get_yres") { get_yres_op = Operator "get_yres" get_yres Operator_type.COMPOUND false; } has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = oo_unary_function get_xoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_xoffset") { get_xoffset_op = Operator "get_xoffset" get_xoffset Operator_type.COMPOUND false; } has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = oo_unary_function get_yoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_yoffset") { get_yoffset_op = Operator "get_yoffset" get_yoffset Operator_type.COMPOUND false; } has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = oo_unary_function get_image_op x, is_class x = error (_ "bad arguments to " ++ "get_image") { get_image_op = Operator "get_image" get_image Operator_type.COMPOUND false; } has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = oo_unary_function get_number_op x, is_class x = error (_ "bad arguments to " ++ "get_number") { get_number_op = Operator "get_number" get_number Operator_type.COMPOUND false; } has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = oo_unary_function get_real_op x, is_class x = error (_ "bad arguments to " ++ "get_real") { get_real_op = Operator "get_real" get_real Operator_type.COMPOUND false; } has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = oo_unary_function get_width_op x, is_class x = error (_ "bad arguments to " ++ "get_width") { get_width_op = Operator "get_width" get_width Operator_type.COMPOUND false; } has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = oo_unary_function get_height_op x, is_class x = error (_ "bad arguments to " ++ "get_height") { get_height_op = Operator "get_height" get_height Operator_type.COMPOUND false; } has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = oo_unary_function get_left_op x, is_class x = error (_ "bad arguments to " ++ "get_left") { get_left_op = Operator "get_left" get_left Operator_type.COMPOUND false; } has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = oo_unary_function get_top_op x, is_class x = error (_ "bad arguments to " ++ "get_top") { get_top_op = Operator "get_top" get_top Operator_type.COMPOUND false; } // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/start/_list.def0000644000175000017500000002310313351443023014216 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* flatten x: flatten a list of lists of things into a simple list * * flatten :: [[*]] -> [*] */ flatten x = foldr flat [] x, is_list x = x { flat x sofar = foldr flat sofar x, is_list x = x : sofar; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st x) xs { x:xs = l; } /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn x xs { x:xs = l; } /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn x (foldr fn st xs) { x:xs = l; } /* foldr1 fn l: like foldr, but use the last element as the start value * * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = x, xs == [] = fn x (foldr1 fn xs) { x:xs = l; } /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn x = search xs (n + 1) { x:xs = l; } } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = x : init xs { x:xs = l; } /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = x, xs == [] = last xs { x:xs = l; } /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scanl fn st l: apply (foldl fn r) to every initial segment of a list * * scanl add 0 [1,2,3] == [1,3,6] * scanl :: (* -> ** -> *) -> * -> [**] -> [*] */ scanl fn st l = st, l == [] = st' : scanl fn st' xs { x:xs = l; st' = fn st x; } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/0000755000175000017500000000000013417043453012641 500000000000000nip2-8.7.1/share/nip2/compat/7.40/0000755000175000017500000000000013417043453013231 500000000000000nip2-8.7.1/share/nip2/compat/7.40/Image.def0000644000175000017500000014266213351443023014660 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process = [ // we can't use id here since we want to "declass" // the members of x ... consider if x is a crop class, // for example, we don't want to inherit from crop, we // want to make a new image class rot180 @ rot180, rot90, rot180, rot270 ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp h v image, aspect = resize interp fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize interp fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; Bandand_item = class Menuaction "Bitwise Band AND" "bitwise AND of image bands" { action x = bandand x; } Bandor_item = class Menuaction "Bitwise Band OR" "bitwise OR of image bands" { action x = bandor x; } sep2 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = crop x [l, t, w, h] { fields = [ [has_left, get_left, 0], [has_top, get_top, 0], [has_width, get_width, 100], [has_height, get_height, 100] ]; [l, t, w, h] = map get_default fields { get_default line = get x, has x = default { [has, get, default] = line; } } } crop x geo = class _result { _vislevel = 3; l = Expression "Crop left" ((int) (geo?0 + geo?2 / 4)); t = Expression "Crop top" ((int) (geo?1 + geo?3 / 4)); w = Expression "Crop width" (max_pair 1 ((int) (geo?2 / 2))); h = Expression "Crop height" (max_pair 1 ((int) (geo?3 / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 100; sy = Expression "Start y" 100; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise Join" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/7.40/_convert.def0000644000175000017500000004223013351443023015443 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = Image x.value, is_Plot x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The outermost list objects become Group()'d. */ to_group x = Group x, is_list x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = sign * (abs ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; sign = 1, ipart > 0 = -1; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/7.40/Filter.def0000644000175000017500000011642013351443023015054 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 1.5; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 50; fs = Scale "Sharpen flat areas by" (-2) 5 1; js = Scale "Sharpen jaggy areas by" (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_hough_item = class Menupullright "_Hough Transform" "transform to parameter space" { Line_item = class Menuaction "_Line" "find straight line Hough transform" { action a = class _result { _vislevel = 3; pspace_width = Expression "Parameter space width" 64; pspace_height = Expression "Parameter space height" 64; _result = map_unary line a { line a = hough_line (to_real pspace_width) (to_real pspace_height) a; } } } Circle_item = class Menuaction "_Circle" "find circle Hough transform" { action a = class _result { _vislevel = 3; scale = Expression "Scale down parameter space by" 10; min_radius = Expression "Minimum radius" 10; max_radius = Expression "Maximum radius" 30; _result = map_unary circle a { circle a = hough_circle (to_real scale) (to_real min_radius) (to_real max_radius) a; } } } } Filter_greyc_item = class Menupullright "_GREYCstoration" "noise-removing filter" { Denoise_item = class Menuaction "Denoise" "Noise-removing filter" { action x = class _result { _vislevel = 3; iterations = Scale "Iterations" 1 5 1; amplitude = Scale "Amplitude" 1 100 40; sharpness = Scale "Sharpness" 0 3 0.9; anisotropy = Scale "Anisotropy" 0 1 0.15; alpha = Scale "Noise scale" 0 5 0.6; sigma = Scale "Geometry regularity" 0 2 1.1; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) x; } } Enlarge_item = class Menuaction "Enlarge" "Enlarge image" { action x = class _result { _vislevel = 3; scale = Scale "Enlarge" 1 10 3; iterations = Scale "Iterations" 1 5 3; amplitude = Scale "Amplitude" 1 100 20; sharpness = Scale "Sharpness" 0 3 0.2; anisotropy = Scale "Anisotropy" 0 1 0.9; alpha = Scale "Noise scale" 0 5 0.1; sigma = Scale "Geometry regularity" 0 2 1.5; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) (resize Interpolate_bilinear (to_real scale) (to_real scale) x); } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } nip2-8.7.1/share/nip2/compat/7.40/_joe_extra.def0000644000175000017500000003114713351443023015750 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use an Arrow or Region x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { im = x.image; mask = Image m { rx = x.region_rect, is_Region x = x; b = image_new im.width im.height 1 0 0 1 0 0 0; w = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0; m = insert_noexpand rx.nleft rx.ntop w b; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Interpolate_bilinear f1 1 b1 {b1 = resize Interpolate_bilinear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.40/Preferences.ws0000644000175000017500000010177313351443023015770 00000000000000 nip2-8.7.1/share/nip2/compat/7.40/Magick.def0000644000175000017500000014112713351443023015024 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate Magick.def 13-Apr-2014 snibgo Put "new image" items into sub-menu. New class VirtualPixlBack. 17-Apr-2014 snibgo Many small changes. A few new menu options. Created sub-menu for multi-input operations. 3-May-2014 jcupitt Put quotes around ( in shadow to help unix Last update: 17-Apr-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ // We don't need Noop. /*=== Magick_noop_item = class Menuaction "_Noop" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_testPar_item = class Menuaction "_TestPar" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "( +clone ) +append ", "\"%s\"" ]; _result = Magick.system command x; } } /* Removed Read_item and Write_item, much better to use nip2 load/save image. * Plus they can load all libMagick formats anyway. */ // Put "new image" items into sub-menu Magick_NewImageMenu_item = class Menupullright "_New image" "make a new image" { Magick_newcanvas_item = class Menuaction "_Solid colour" "make image of solid colour" { action = class _result { _vislevel = 3; size = Magick.Size_widget; colour = Magick.generalcol_widget; command = Magick.command [ size._flag, "\"canvas:" ++ colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_builtin_item = class Menuaction "_Built-in image" "create a built-in image" { action = class _result { _vislevel = 3; builtin = Magick.builtin_widget; command = Magick.command [ builtin._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_gradient_item = class Menuaction "_Gradient" "make a linear gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; topColour = Magick.generalcol_widget; bottomColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"gradient:", topColour._flag, "-", bottomColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } Magick_hald_item = class Menuaction "_Hald-clut image" "create an identity hald-clut image" { action = class _result { _vislevel = 3; order = Expression "order" 8; command = Magick.command [ "hald:" ++ print order.expr, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_pattern_item = class Menuaction "_Pattern" "create pattern" { action = class _result { _vislevel = 3; size = Magick.Size_widget; pattern = Magick.pattern_widget; command = Magick.command [ size._flag, pattern._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_plasma_item = class Menuaction "_Plasma image" "create plasma image" { action = class _result { _vislevel = 3; size = Magick.Size_widget; // FIXME? ColourA-ColourB. // FIXME? Allow plasma:fractal? command = Magick.command [ size._flag, "plasma:", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_radialgradient_item = class Menuaction "_Radial gradient" "make a radial gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; innerColour = Magick.generalcol_widget; outerColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"radial-gradient:", innerColour._flag, "-", outerColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } } // end Magick_NewImageMenu_item Magick_MultiMenu_item = class Menupullright "_Multiple inputs" "make an image from multiple images" { Magick_composite_item = class Menuaction "_Composite" "composite two images (without mask)" { action x y = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_compositeMask_item = class Menuaction "_Composite masked" "composite two images (with mask)" { action x y z = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system3 command x y z; } } // FIXME: other operations like remap that take another image as arguments are: // mask (pointless?), texture, tile (pointless?) // FIXME: operations that take a filename that isn't an image: // cdl, profile Magick_clut_item = class Menuaction "_Clut" "replace values using second image as colour look-up table" { action x y = class _result { _vislevel = 3; // FIXME: uses -intensity "when mapping greyscale CLUT image to alpha channel if set by -channels" command = Magick.command [ "\"%s\"", "\"%s\"", "-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_haldclut_item = class Menuaction "_Hald clut" "replace values using second image as Hald colour look-up table" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"", "-hald-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } // Encipher and decipher: key files can be text or image files. Magick_encipher_item = class Menuaction "_Encipher/Decipher" "encipher or decipher an image image" { action x = class _result { _vislevel = 3; pathname = Pathname "Read key file" ""; isDecipher = Toggle "Decipher" false; command = Magick.command [ "\"%s\"", if pathname.value == "" then "" else ( ( if isDecipher then "-decipher " else "-encipher ") ++ ( "\"" ++ pathname.value ++ "\"" ) ), "\"%s\"" ]; _result = Magick.system command x; } } Magick_profile_item = class Menuaction "_Profile" "assigns/applies an ICC profile" { action x = class _result { _vislevel = 3; pathname1 = Pathname "Read profile file" ""; pathname2 = Pathname "Read profile file" ""; command = Magick.command [ "\"%s\"", if pathname1.value == "" then "" else ( "-profile " ++ "\"" ++ pathname1.value ++ "\""), if pathname2.value == "" then "" else ( "-profile " ++ "\"" ++ pathname2.value ++ "\""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_remap_item = class Menuaction "_Remap" "reduce colours to those in another image" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-remap", "\"%s\"", "\"%s\"" ]; _result = Magick.system2 command x y; } } } // end Magick_MultiMenu_item Magick_image_type_item = class Menuaction "_Image Type" "change image type" { action x = class _result { _vislevel = 3; imagetype = Magick.imagetype_widget; command = Magick.command [ "\"%s\"", imagetype._flag, "\"%s\"" ]; _result = Magick.system command x; } } sep2 = Menuseparator; Magick_alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = Magick.alpha_widget; command = Magick.command [ "\"%s\"", alpha._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = Magick.text_widget; font = Magick.Font_widget; geometry = Magick.AnnotGeometry_widget; gravity = Magick.gravity_widget; foreground = Magick.foreground_widget; undercol = Magick.undercol_widget; antialias = Magick.antialias_widget; command = Magick.command [ "\"%s\"", font._flag, antialias._flag, gravity._flag, foreground._flag, undercol._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoGamma_item = class Menuaction "_AutoGamma" "automatic gamma" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-gamma", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoLevel_item = class Menuaction "_AutoLevel" "automatic level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-level", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blurSharpMenu_item = class Menupullright "_Blur/Sharpen" "blur and sharpen" { Magick_adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; // note: adaptive-blur doesn't regard VP. command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-adaptive-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_blur_item = class Menuaction "_Blur" "blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gaussianBlur_item = class Menuaction "_Gaussian Blur" "blur with a Gaussian operator" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-gaussian-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_motionBlur_item = class Menuaction "_Motion Blur" "simulate motion blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; channels = Magick.ch_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-motion-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotationalBlur_item = class Menuaction "_RotationalBlur" "blur around the centre" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; angle = Scale "angle (degrees)" (-360) 360 20; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-radial-blur", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_selectiveBlur_item = class Menuaction "_Selective Blur" "blur where contrast is less than or equal to threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; threshold = Scale "Threshold (percent)" 0 100 50; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", intensity._flag, virtpixback._flag, channels._flag, "-selective-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print threshold.value ++ "%%", "\"%s\"" ]; _result = Magick.system command x; } } sep1 = Menuseparator; Magick_adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-adaptive-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sharpen_item = class Menuaction "_Sharpen" "sharpen" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_unsharpen_item = class Menuaction "_Unsharp" "sharpen with unsharp mask" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; gain = Scale "Gain" (-10) 10 1; threshold = Scale "Threshold" 0 1 0.05; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-unsharp", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print gain.value ++ "+" ++ print threshold.value, "\"%s\"" ]; _result = Magick.system command x; } } } // end BlurSharpMenu_item Magick_border_item = class Menuaction "_Border" "add border of given colour" { action x = class _result { _vislevel = 3; compose = Magick.compose_widget; width = Expression "Width" 3; bordercol = Magick.bordercol_widget; command = Magick.command [ "\"%s\"", compose._flag, bordercol._flag, "-border", print width.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_brightCont_item = class Menuaction "_Brightness-contrast" "adjust the brightness and/or contrast" { action x = class _result { _vislevel = 3; bri = Scale "brightness" (-100) 100 0; con = Scale "contrast" (-100) 100 0; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-brightness-contrast", print bri.value ++ "x" ++ print con.value, "\"%s\"" ]; _result = Magick.system command x; } } // Note: canny requires ImageMagick 6.8.9-0 or later. Magick_canny_item = class Menuaction "_Canny" "detect a wide range of edges" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; lowPc = Scale "lower percent" 0 100 10; highPc = Scale "lower percent" 0 100 10; command = Magick.command [ "\"%s\"", "-canny", concat ["\"", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print lowPc.value ++ "%%+" ++ print highPc.value ++ "%%" ++ "\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_charcoal_item = class Menuaction "_Charcoal" "simulate a charcoal drawing" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; factor = Scale "factor" 0 50 1; command = Magick.command [ "\"%s\"", intensity._flag, "-charcoal", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_chop_item = class Menuaction "_Chop" "remove pixels from the interior" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-chop", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorize_item = class Menuaction "_Colorize" "colorize by given amount" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; val = Scale "value" 0 100 100; command = Magick.command [ "\"%s\"", foreground._flag, "-colorize", print val.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colors_item = class Menuaction "_Colors" "reduce number of colors" { action x = class _result { _vislevel = 3; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; quantize = Magick.colorspace_widget; colors = Expression "Colours" 3; command = Magick.command [ "\"%s\"", "-quantize", quantize._flag, "-treedepth", print treedepth.expr, dither._flag, "-colors", print colors.expr, "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: color-matrix? Magick_colorspace_item = class Menuaction "_Colourspace" "convert to arbitrary colourspace" { action x = class _result { _vislevel = 3; colsp = Magick.colorspace_widget; command = Magick.command [ "\"%s\"", "-colorspace", colsp._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorspaceGray_item = class Menuaction "_Colourspace gray" "convert to gray using given intensity method" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-colorspace gray", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrast_item = class Menuaction "_Contrast" "increase or reduce the contrast" { action x = class _result { _vislevel = 3; isReduce = Toggle "reduce contrast" false; command = Magick.command [ "\"%s\"", (if isReduce then "+" else "-") ++ "contrast", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrastStretch_item = class Menuaction "_Contrast stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-contrast-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: convolve (bias, kernel) Magick_crop_item = class Menuaction "_Crop" "cut out a rectangular region" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-crop", geometry._flag, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_deskew_item = class Menuaction "_Deskew" "straighten the image" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; // FIXME: toggle auto-crop? command = Magick.command [ "\"%s\"", "-deskew", "\"" ++ print threshold.value ++ "%%\"", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_despeckle_item = class Menuaction "_Despeckle" "reduce the speckles" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-despeckle", "\"%s\"" ]; _result = Magick.system command x; } } Magick_distort_item = class Menuaction "_Distort" "distort using a method and arguments" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; distort = Magick.distort_widget; args = String "Arguments" "1,0"; isPlus = Toggle "Extend to show entire image" false; command = Magick.command [ "\"%s\"", virtpixback._flag, (if isPlus then "+" else "-") ++ "distort", distort._flag, args.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_draw_item = class Menuaction "_Draw" "annotate with one or more graphic primitives" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; args = String "Arguments" "line 0,0 9,9 rectangle 10,10 20,20"; command = Magick.command [ "\"%s\"", foreground._flag, "-draw", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_edge_item = class Menuaction "_Edge" "detect edges" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-edge", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_emboss_item = class Menuaction "_Emboss" "emboss" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-emboss", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_enhance_item = class Menuaction "_Enhance" "enhance a noisy image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-enhance", "\"%s\"" ]; _result = Magick.system command x; } } Magick_equalize_item = class Menuaction "_Equalize" "equalize the histogram" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-equalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_evaluate_item = class Menuaction "_Evaluate" "evaluate an expression on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; operation = Magick.evaluate_widget; val = Expression "value" 5; isPc = Toggle "Value is percent" false; command = Magick.command [ "\"%s\"", channels._flag, operation._flag, print val.expr ++ if isPc then "%%" else "", "\"%s\"" ]; _result = Magick.system command x; } } Magick_extent_item = class Menuaction "_Extent" "set the image size and offset" { action x = class _result { _vislevel = 3; background = Magick.background_widget; compose = Magick.compose_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, background._flag, gravity._flag, "-extent", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_FlipFlopMenu_item = class Menupullright "_Flip/flop" "flip/flop/transverse/transpose" { Magick_flip_item = class Menuaction "_Flip vertically" "mirror upside-down" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flip", "\"%s\"" ]; _result = Magick.system command x; } } Magick_flop_item = class Menuaction "_Flop horizontally" "mirror left-right" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flop", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transpose_item = class Menuaction "_Transpose" "mirror along the top-left to bottom-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transpose +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transverse_item = class Menuaction "_Transverse" "mirror along the bottom-left to top-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transverse +repage", "\"%s\"" ]; _result = Magick.system command x; } } } // end Magick_FlipFlopMenu_item Magick_floodfill_item = class Menuaction "_Floodfill" "recolour neighbours that match" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; fuzz = Magick.fuzz_widget; coordinate = Magick.coordinate_widget; // -draw "color x,y floodfill" command = Magick.command [ "\"%s\"", foreground._flag, "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-draw \" color", coordinate._flag, "floodfill \"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_frame_item = class Menuaction "_Frame" "surround with border or beveled frame" { action x = class _result { _vislevel = 3; border = Magick.bordercol_widget; compose = Magick.compose_widget; matte = Magick.mattecol_widget; geometry = Magick.FrameGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, border._flag, matte._flag, "-frame", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_function_item = class Menuaction "_Function" "evaluate a function on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; function = Magick.function_widget; // FIXME: explain values; use sensible defaults. values = String "values" "0,0,0,0"; command = Magick.command [ "\"%s\"", channels._flag, "-function", function._flag, values.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_fx_item = class Menuaction "_Fx" "apply a mathematical expression" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; interpolate = Magick.interpolate_widget; virtpixback = Magick.VirtualPixelBack_widget; args = String "Expression" "u*1/2"; command = Magick.command [ "\"%s\"", channels._flag, interpolate._flag, virtpixback._flag, "-fx", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_gamma_item = class Menuaction "_Gamma" "apply a gamma correction" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; gamma = Magick.gamma_widget; command = Magick.command [ "\"%s\"", channels._flag, "-gamma", print gamma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradient_item = class Menuaction "_Gradient" "apply a linear gradient" { action x = class _result { _vislevel = 3; colourA = Magick.generalcol_widget; colourB = Magick.generalcol_widget; position = Option "colourA is at" [ "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"] 0; _baryArg = concat ["0,0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 0 = concat ["0,0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 1 = concat ["0,0,", colourA._flag, " %%[fx:w-1],0,", colourB._flag], position.value == 2 = concat ["0,0,", colourB._flag, " %%[fx:w-1],0,", colourA._flag], position.value == 3 = concat ["0,0,", colourA._flag, " %%[fx:w-1],%%[fx:h-1],", colourB._flag], position.value == 4 = concat ["%%[fx:w-1],0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 5 = concat ["%%[fx:w-1],0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 6 = concat ["0,0,", colourB._flag, " %%[fx:w-1],%%[fx:h-1],", colourA._flag], position.value == 7 = "dunno"; command = Magick.command [ "\"%s\"", "-sparse-color barycentric \"" ++ _baryArg ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradientCorn_item = class Menuaction "_Gradient corners" "apply a bilinear gradient between the corners" { action x = class _result { _vislevel = 3; colour_top_left = Magick.generalcol_widget; colour_top_right = Magick.generalcol_widget; colour_bottom_left = Magick.generalcol_widget; colour_bottom_right = Magick.generalcol_widget; command = Magick.command [ "\"%s\"", "-sparse-color bilinear \"" ++ "0,0," ++ colour_top_left._flag ++ ",%%[fx:w-1],0" ++ colour_top_right._flag ++ ",0,%%[fx:h-1]" ++ colour_bottom_left._flag ++ ",%%[fx:w-1],%%[fx:h-1]" ++ colour_bottom_right._flag ++ "\"", "+depth", "\"%s\"" ]; _result = Magick.system command x; } } Magick_histogram_item = class Menuaction "_Histogram" "make a histogram image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-define histogram:unique-colors=false histogram:" ++ "\"%s\"" ]; _result = Magick.system command x; } } Magick_implode_item = class Menuaction "_Implode" "implode pixels about the center" { action x = class _result { _vislevel = 3; factor = Scale "factor" 0 20 1; interpolate = Magick.interpolate_widget; // FIXME: virtual-pixel? command = Magick.command [ "\"%s\"", interpolate._flag, "-implode", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_level_item = class Menuaction "_Level" "adjust the level of channels" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "black point" (-100) 200 0; wht = Scale "white point" (-100) 200 100; gam = Scale "gamma" 0 30 1; isPc = Toggle "Levels are percent" true; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level", "\"" ++ print blk.value ++ "," ++ print wht.value ++ (if isPc then "%%" else "") ++ "," ++ print gam.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_levelCols_item = class Menuaction "_Level colors" "adjust levels to given colours" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; colour_black = Magick.generalcol_widget; colour_white = Magick.generalcol_widget; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level-colors", "\"" ++ colour_black._flag ++ "," ++ colour_white._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_linearStretch_item = class Menuaction "_Linear stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", channels._flag, "-linear-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_magnify_item = class Menuaction "_Magnify" "double the size of the image with pixel art scaling" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-magnify", "\"%s\"" ]; _result = Magick.system command x; } } Magick_modulate_item = class Menuaction "_Modulate" "modulate brightness, saturation and hue" { action x = class _result { _vislevel = 3; modcolsp = Magick.ModColSp_widget; bright = Scale "brightness" 0 200 100; sat = Scale "saturation" 0 200 100; hue = Scale "hue" 0 200 100; command = Magick.command [ "\"%s\"", modcolsp._flag, "-modulate", print bright.value ++ "," ++ print sat.value ++ "," ++ print hue.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_monochrome_item = class Menuaction "_Monochrome" "transform to black and white" { action x = class _result { _vislevel = 3; // FIXME: also intensity? intensity = Magick.intensity_widget; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; command = Magick.command [ "\"%s\"", intensity._flag, dither._flag, "-treedepth", print treedepth.expr, "-monochrome", "\"%s\"" ]; _result = Magick.system command x; } } Magick_morphology_item = class // See http://www.imagemagick.org/Usage/morphology/ Menuaction "_Morphology" "apply a morphological method" { action x = class _result { _vislevel = 3; method = Magick.morphmeth_widget; iter = Expression "Iterations (-1=repeat until done)" 1; kernel = Magick.kernel_widget; // FIXME: custom kernel eg "3x1+2+0:1,0,0" // width x height + offsx + offsy : {w*h values} // each value is 0.0 to 1.0 or "NaN" or "-" // kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0 // but // ring takes: radius1, radius2, scale // rectangle and comet take: width x height + offsx + offsy // blur takes: radius x sigma // FIXME: for now, simply allow any string input. kernel_arg = String "Kernel arguments" ""; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-morphology", method._flag ++ ":" ++ print iter.expr, kernel._flag ++ (if kernel_arg.value == "" then "" else ":") ++ kernel_arg.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_negate_item = class Menuaction "_Negate" "negate" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-negate", "\"%s\"" ]; _result = Magick.system command x; } } Magick_addNoise_item = class Menuaction "_add Noise" "add noise" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; attenuate = Scale "attenuate" 0 1.0 1.0; noise = Magick.noise_widget; command = Magick.command [ "\"%s\"", channels._flag, "-attenuate", print attenuate.value, noise._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_normalize_item = class Menuaction "_Normalize" "normalize" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-normalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_opaque_item = class Menuaction "_Opaque" "change this colour to the fill colour" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; fill = Magick.foreground_widget; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", fill._flag, channels._flag, "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "opaque", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_paint_item = class Menuaction "_Paint" "simulate an oil painting" { action x = class _result { _vislevel = 3; rad = Expression "radius" 10; command = Magick.command [ "\"%s\"", "-paint", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } /*=== FIXME Bug; remove for now. Polaroid_item = class Menuaction "_Polaroid" "simulate a polaroid picture" { action x = class _result { _vislevel = 3; angle = Scale "angle" (-90) 90 20; command = Magick.command [ "\"%s\"", "-polaroid", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_posterize_item = class Menuaction "_Posterize" "reduce to (n) levels per channel" { action x = class _result { _vislevel = 3; levels = Expression "levels" 3; command = Magick.command [ "\"%s\"", "-posterize", print levels.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_raise_item = class Menuaction "_Raise" "lighten or darken image edges" { action x = class _result { _vislevel = 3; thk = Expression "Thickness" 3; command = Magick.command [ "\"%s\"", "-raise", print thk.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_resize_item = class Menuaction "_Resize" "resize to given width and height" { action x = class _result { _vislevel = 3; filter = Magick.filter_widget; type = Magick.ResizeType_widget; width = Scale "Width" 1 100 10; height = Scale "Height" 1 100 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", filter._flag, "-" ++ type._flag, "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "!") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_roll_item = class Menuaction "_Roll" "roll an image horizontally or vertically" { action x = class _result { _vislevel = 3; rollx = Expression "X" 3; rolly = Expression "Y" 3; command = Magick.command [ "\"%s\"", "-roll", (if rollx.expr >= 0 then "+" else "") ++ print rollx.expr ++ (if rolly.expr >= 0 then "+" else "") ++ print rolly.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotate_item = class Menuaction "_Rotate" "rotate" { action x = class _result { _vislevel = 3; angle = Scale "angle (degrees)" (-360) 360 20; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, "+distort", "SRT", print angle.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -segment, but cluster-threshold should be percentage of image area. Magick_sepia_item = class Menuaction "_Sepia tone" "simulate a sepia-toned photo" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; command = Magick.command [ "\"%s\"", "-sepia-tone", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shade_item = class Menuaction "_Shade" "shade with a distant light source" { action x = class _result { _vislevel = 3; azimuth = Scale "Azimuth (degrees)" (-360) 360 0; elevation = Scale "Elevation (degrees)" 0 90 45; command = Magick.command [ "\"%s\"", "-shade", print azimuth.value ++ "x" ++ print elevation.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_shadow_item = class Menuaction "_Shadow" "simulate a shadow" { action x = class _result { _vislevel = 3; shadowCol = Magick.generalcol_widget; opacity = Scale "Opacity (percent)" 0 100 75; sigma = Scale "Sigma" 0 30 2; // FIXME: make offsets a single widget? offsx = Scale "X-offset" (-20) 20 4; offsy = Scale "Y-offset" (-20) 20 4; arePc = Toggle "offsets are percentages" false; // FIXME: raw operation creates page offset, which vips dislikes. // So we take this futher, compositing with source. command = Magick.command [ "\"%s\"", "\"(\" +clone", "-background", "\"" ++ shadowCol._flag ++ "\"", "-shadow", concat [ "\"", print opacity.value, "x", print sigma.value, (if offsx.value >= 0 then "+" else ""), print offsx.value, (if offsy.value >= 0 then "+" else ""), print offsy.value, (if arePc then "%%" else ""), "\"" ], "\")\" +swap -background None -layers merge", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shave_item = class Menuaction "_Shave" "shave pixels from the edges" { action x = class _result { _vislevel = 3; width = Scale "Width" 0 50 10; height = Scale "Height" 0 50 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", "-shave", "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shear_item = class Menuaction "_Shear" "shear along the x-axis and/or y-axis" { action x = class _result { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-shear", print shearX.expr ++ "x" ++ print shearY.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sigmoid_item = class Menuaction "_Sigmoid" "increase or decrease mid-tone contrast sigmoidally" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; contrast = Scale "contrast" 0 30 3; midpoint = Scale "mid-point (percent)" 0 100 50; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "sigmoidal-contrast", "\"" ++ print contrast.value ++ "x" ++ print midpoint.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_sketch_item = class Menuaction "_Sketch" "simulate a pencil sketch" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; command = Magick.command [ "\"%s\"", "-sketch", print radius.value ++ "x" ++ print sigma.value ++ (if angle >= 0 then ("+" ++ print angle.value) else ""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_solarize_item = class Menuaction "_Solarize" "negate all pixels above a threshold level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-solarize", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -sparse-color needs abitrary list of {x,y,colour}. Magick_splice_item = class Menuaction "_Splice" "splice a colour into the image" { action x = class _result { _vislevel = 3; background = Magick.background_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", background._flag, gravity._flag, "-splice", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_spread_item = class Menuaction "_Spread" "displace pixels by random amount" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; amount = Expression "Amount (pixels)" 5; command = Magick.command [ "\"%s\"", virtpixback._flag, "-spread", print amount.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_statistic_item = class Menuaction "_Statistic" "replace each pixel with statistic from neighbourhood" { action x = class _result { _vislevel = 3; width = Expression "Width" 5; height = Expression "Height" 5; statisticType = Magick.StatType_widget; command = Magick.command [ "\"%s\"", "-statistic", statisticType._flag, print width.expr ++ "x" ++ print height.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = Magick.angle_widget; command = Magick.command [ "\"%s\"", "-swirl", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_thresholdMenu_item = class Menupullright "_Threshold" "make black or white" { Magick_threshold_item = class Menuaction "_Threshold" "apply black/white threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blackThreshold_item = class Menuaction "_Black threshold" "where below threshold set to black" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-black-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_whiteThreshold_item = class Menuaction "_White threshold" "where above threshold set to white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-white-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_latThreshold_item = class Menuaction "_Local Adaptive Threshold" "where above average plus offset set to white, otherwise black" { action x = class _result { _vislevel = 3; width = Expression "Width" 10; height = Expression "Height" 10; offset = Scale "Offset (percent)" (-100) 100 0; // note: "-lat" doesn't respond to channels command = Magick.command [ "\"%s\"", "-lat", concat ["\"", print width.expr, "x", print height.expr, (if offset.value >= 0 then "+" else ""), print offset.value, "%%\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_randThreshold_item = class Menuaction "_Random Threshold" "between specified limits, apply random threshold" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; low = Scale "Low threshold" 0 100 10; high = Scale "High threshold" 0 100 90; isPc = Toggle "Thresholds are percent" true; command = Magick.command [ "\"%s\"", channels._flag, "-random-threshold", "\"" ++ print low.value ++ "x" ++ print high.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } } // end ThresholdMenu_item // Note: alternatives include: // convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif Magick_tile_item = class Menuaction "_Tile" "fill given size with tiled image" { action x = class _result { _vislevel = 3; size = Magick.Size_widget; command = Magick.command [ size._flag, "tile:" ++ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_tint_item = class Menuaction "_Tint" "apply a tint" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; amount = Scale "amount (percent)" 0 100 50; command = Magick.command [ "\"%s\"", foreground._flag, "-tint", // snibgo note: although the amount is a percentage, it doesn't need "%" character. print amount.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_transparent_item = class Menuaction "_Transparent" "make this colour transparent" { action x = class _result { _vislevel = 3; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "transparent", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_trim_item = class Menuaction "_Trim" "trims away border" { action x = class _result { _vislevel = 3; fuzz = Magick.fuzz_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-trim +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_uniqueCols_item = class Menuaction "_Unique colours" "discard all but one of any pixel color" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-unique-colors", "\"%s\"" ]; _result = Magick.system command x; } } Magick_vignette_item = class Menuaction "_Vignette" "soften the edges in vignette style" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; rx = Scale "Rolloff x (percent)" 0 100 10; ry = Scale "Rolloff y (percent)" 0 100 10; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-vignette", print radius.value ++ "x" ++ print sigma.value ++ (if rx.value >= 0 then "+" else "") ++ print rx.value ++ (if ry.value >= 0 then "+" else "") ++ print ry.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_wave_item = class Menuaction "_Wave" "shear the columns into a sine wave" { action x = class _result { _vislevel = 3; amplitude = Scale "Amplitude (pixels)" 0 100 10; wavelength = Scale "Wavelength (pixels)" 0 100 10; command = Magick.command [ "\"%s\"", "-wave", print amplitude.value ++ "x" ++ print wavelength.value, "\"%s\"" ]; _result = Magick.system command x; } } nip2-8.7.1/share/nip2/compat/7.40/Colour.def0000644000175000017500000003762213351443023015100 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } CCT_colour = class Menuaction (_ "Colour from CCT") (_ "pick colour by CCT") { action = widget 6500; widget x = class _result { _vislevel = 3; T = Scale "CCT" 1800 25000 x; _result = colour_from_temp (to_real T); Colour_edit space value = widget (temp_from_colour (Colour space value)); } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } sep1 = Menuseparator; CCT_item = class Menuaction (_ "Calculate temperature") (_ "estimate CCT using the McCamy approximation") { action z = map_unary temp_from_colour z; } Colour_item = Colour_new_item.CCT_colour; } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; measure = Scale (_ "Measure area (%)") 1 100 50; // get a representative image from an arg get_image x = get_image x.value?0, is_Group x = x; _im = get_image x; sample = measure_draw (to_real pacross) (to_real pdown) (to_real measure) _im; _result = map_unary chart x { chart in = measure_sample (to_real pacross) (to_real pdown) (to_real measure) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.40/_joe_utilities.def0000644000175000017500000005054513351443023016643 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/7.40/_Object.def0000644000175000017500000002600513351443023015173 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/7.40/Object.def0000644000175000017500000000220513351443023015030 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/7.40/Math.def0000644000175000017500000003162513351443023014523 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_AND" "bitwise AND of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_OR" "bitwise OR of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "_XOR" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_NOT" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Bandand_item = Image_band_item.Bandand_item; Bandor_item = Image_band_item.Bandor_item; } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Skew_item = class Menuaction "S_kew" "skew of image or list or vector" { action a = map_unary skew a; } Kurtosis_item = class Menuaction "Kurtosis" "kurtosis of image or list or vector" { action a = map_unary kurtosis a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.40/_generate.def0000644000175000017500000000755513351443023015570 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } mkim options x y b = Image (image_new x y b (opt $format) (opt $coding) (opt $type) (opt $pixel) (opt $xoffset) (opt $yoffset)) { opt = get_option options [ $format => Image_format.UCHAR, $coding => Image_coding.NOCODING, $type => Image_type.sRGB, $pixel => 0, $xoffset => 0, $yoffset => 0 ]; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } /* Make a colour from a temperature. */ colour_from_temp T = error (_ "T out of range"), T < 1667 || T > 25000 = Colour "Yxy" [50, x, y] { // Kim et all approximation // see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation x = -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 + 0.8776956 * 10 ** 3 / T + 0.179910, T < 4000 = -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 + 0.2226347 * 10 ** 3 / T + 0.240390; y = -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + 2.18555832 * x - 0.20219638, T < 2222 = -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867, T < 4000 = 3.0817580 * x ** 3 - 5.87338670 * x ** 2 + 3.75112997 * x - 0.37001483; } temp_from_colour z = T { c = colour_transform_to Image_type.YXY (to_colour z); x = c.value?1; y = c.value?2; // McCamy's approximation, see eg. // http://en.wikipedia.org/wiki/Color_temperature#Approximation xe = 0.332; ye = 0.1858; n = (x - xe) / (y - ye); T = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33; } nip2-8.7.1/share/nip2/compat/7.40/_stdenv.def0000644000175000017500000020254213351443023015272 00000000000000/* optional args to functions */ get_option options defaults f = error (_ "unknown parameter " ++ f), hits == [] = hits?0 { hits = [v :: [n, v] <- options ++ defaults; n == f]; } /* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } bandand x = oo_unary_function bandand_op x, is_class x = foldr1 bitwise_and (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandand") { bandand_op = Operator "bandand" bandand Operator_type.COMPOUND_REWRAP false; } bandor x = oo_unary_function bandor_op x, is_class x = foldr1 bitwise_or (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandor") { bandor_op = Operator "bandor" bandor Operator_type.COMPOUND_REWRAP false; } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } skew x = oo_unary_function skew_op x, is_class x = sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x = sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "skew") { skew_op = Operator "skew" skew Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = w * h * b, is_image x' = len x'; } kurtosis x = oo_unary_function kurtosis_op x, is_class x = sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x = sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "kurtosis") { kurtosis_op = Operator "kurtosis" kurtosis Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = len x', is_list x'; = w * h * b; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_tile_cache_random x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } decode im = oo_unary_function decode_op im, is_class im = decode_im im, is_image im = error (_ "bad arguments to " ++ "decode") { decode_op = Operator "decode" decode Operator_type.COMPOUND_REWRAP false; decode_im im = im_LabQ2Lab im, get_coding im == Image_coding.LABPACK = im_rad2float im, get_coding im == Image_coding.RAD = im; } measure_draw across down measure image = mark { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; x = map (extract 0) cods; y = map (extract 1) cods; outer = mkim [$pixel => 255] sample_width sample_height 1; inner = mkim [] (sample_width - 4) (sample_height - 4) 1; patch = insert 2 2 inner outer; bg = mkim [] image.width image.height 1; mask = Image (im_insertset bg.value patch.value x y); image' = colour_transform_to Image_type.sRGB image; mark = if mask then Vector [0, 255, 0] else image'; } measure_sample across down measure image = measures { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; image' = decode image; patches = map (\p extract_area p?0 p?1 sample_width sample_height image') cods; measures = Matrix (map (map mean) (map bandsplit patches)); } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx x = oo_unary_function greyc_op x, is_class x = greyc_im x, is_image x = error (_ "bad argument" ++ " (" ++ print x ++ ") to " ++ "greyc") { greyc_op = Operator "greyc" (greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im x = im_greyc x iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx mask x = oo_binary_function greyc_mask_op mask x, is_class mask = oo_binary'_function greyc_mask_op mask x, is_class x = greyc_im mask x, is_image mask && is_image x = error (_ "bad arguments" ++ " (" ++ print mask ++ ", " ++ print x ++ ") " ++ "to " ++ "greyc") { greyc_mask_op = Operator "greyc_mask" (greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im mask x = im_greyc_mask x mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_inv hist = oo_unary_function hist_inv_op hist, is_class hist = inv hist, is_image hist = error (_ "bad arguments to " ++ "hist_inv") { hist_inv_op = Operator "hist_inv" hist_inv Operator_type.COMPOUND_REWRAP false; inv im = im_invertlut (to_matrix im''') len { // need a vertical doublemask im' = rot90 im, get_width im > 1 && get_height im == 1 = im, get_width im == 1 && get_height im > 1 = error (_ "not a hist"); len = get_height im'; // values must be scaled to 0 - 1 im'' = im' / (max im'); // add an index column on the left // again, must be in 0-1 y = ((make_xy 1 len)?1) / len; im''' = y ++ im''; } } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize interp xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; // is this interpolation nearest-neighbour? is_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor, nearest neighbour // upscale by integer part, then affine to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by any factor, nearest neighbour // downscale by integer part, then affine to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor with affine = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 // downscale by any factor, bilinear // block shrink by integer factor, then resample to // exact with affine = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate_type.descriptions?interp.type ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // resize scale xfac yfac im = im_affinei_all im interp.value xfac 0 0 yfac 0 0; } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; } ss = len xes; sx = sum xes; sy = sum yes; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* One image in, one out. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } /* Two images in, one out. */ system_image2 command x1 x2 = oo_binary_function system_image2_op x1 x2, is_class x1 = oo_binary'_function system_image2_op x1 x2, is_class x2 = system x1 x2, is_image x1 && is_image x2 = error (_ "bad arguments to " ++ "system_image2") { system_image2_op = Operator "system_image2" (system_image2 command) Operator_type.COMPOUND_REWRAP false; system x1 x2 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Three images in, one out. */ system_image3 command x1 x2 x3 = oo_binary_function system_image2_op x2 x3, is_class x2 = oo_binary'_function system_image2_op x2 x3, is_class x3 = system x1 x2 x3, is_image x1 && is_image x2 && is_image x3 = error (_ "bad arguments to " ++ "system_image3") { system_image2_op = Operator "system_image2" (system_image3 command x1) Operator_type.COMPOUND_REWRAP false; system x1 x2 x3 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2, x3], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Zero images in, one out. */ system_image0 command = Image image_out { [image_out] = vips_call "system" [command] [ $out => true, $out_format => "%s.tif" ]; } hough_line w h x = oo_unary_function hough_line_op x, is_class x = hline (to_real w) (to_real h) x, is_image x = error (_ "bad arguments to " ++ "hough_line") { hough_line_op = Operator "hough_line" (hough_line w h) Operator_type.COMPOUND_REWRAP false; hline w h x = pspace { [pspace] = vips_call "hough_line" [x] [ $width => w, $height => h ]; } } hough_circle s mn mx x = oo_unary_function hough_circle_op x, is_class x = hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x = error (_ "bad arguments to " ++ "hough_circle") { hough_circle_op = Operator "hough_circle" (hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false; hcircle s mn mx x = pspace { [pspace] = vips_call "hough_circle" [x] [ $scale => s, $min_radius => mn, $max_radius => mx ]; } } nip2-8.7.1/share/nip2/compat/7.40/Histogram.def0000644000175000017500000001621413351443023015564 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "_Identity" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_inv_item = class Menuaction "In_vert" "invert a histogram" { action x = map_unary hist_inv x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Interpolate_bilinear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; caption = Expression "Chart caption" "none"; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; xcaption = Expression "X axis caption" "none"; ycaption = Expression "Y axis caption" "none"; series_captions = Expression "Series captions" ["Band 0"]; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range ++ captions; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; captions = concat (map test caption_options) ++ [$series_captions => series_captions.expr] { caption_options = [ $caption => caption.expr, $xcaption => xcaption.expr, $ycaption => ycaption.expr ]; test x = [], value == "none" = [option_name => value] { [option_name, value] = x; } } image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/7.40/Widgets.def0000644000175000017500000000235313351443023015234 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/7.40/_types.def0000644000175000017500000006744113351443023015142 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; to_image dpi = extract_bands 0 3 (graph_export_image (to_real dpi) this); } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/7.40/Matrix.def0000644000175000017500000002573113351443023015077 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = identity (identity_matrix 5); identity v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix (identity_matrix (to_real s)), to_real s != len v; = Matrix v; Matrix_vips value scale offset filename display = identity value; } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = series (mkseries 0 1 5); mkseries s t e = transpose [[to_real s, to_real s + to_real t .. to_real e]]; series v = class _result { _vislevel = 3; _s = v?0?0; _t = v?1?0 - v?0?0; _e = (last v)?0; s = Expression "Start value" _s; t = Expression "Step by" _t; e = Expression "End value" _e; _result = Matrix (mkseries s t e), to_real s != _s || to_real t != _t || to_real e != _e = Matrix v; Matrix_vips value scale offset filename display = series value; } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = square (mksquare 5); mksquare s = replicate s (take s [1, 1 ..]); square v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix_con (sum v) 0 v, len v == to_real s = Matrix_con (sum m) 0 m { m = mksquare (to_real s); } Matrix_vips value scale offset filename display = square value; } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = circle (mkcircle 3); mkcircle r = map2 (map2 pyth) xes yes { line = [-r .. r]; xes = replicate (2 * r + 1) line; yes = transpose xes; pyth a b = 1, (a**2 + b**2) ** 0.5 <= r = 0; } circle v = class _result { _vislevel = 3; r = Expression "Radius" ((len v - 1) / 2); _result = Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1 = Matrix_con (sum m) 0 m { m = mkcircle (to_real r); } Matrix_vips value scale offset filename display = circle value; } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/7.40/Tasks.def0000644000175000017500000006411113351443023014713 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; measure = Scale (_ "Measure area (%)") 1 100 50; sample = measure_draw 6 4 (to_real measure) image; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linearize from chart greyscale", "Fit intercept from chart greyscale", "Linear input, set brightness from chart", "Linear input" ] 0; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure_sample 6 4 (to_real measure) image; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix [[0, 0], [1, 1]] { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map an image though the lineariser linear x = hist_map linearising_lut.value x, mode == 0 || mode == 1 = x; // map the chart measurements though the lineariser _camera' = (to_matrix @ linear @ to_image) _camera; // solve for RGB -> XYZ // normalise: the 2nd row is what makes Y, so divide by that to // get Y in 0-1. _pinv = (transpose _camera' * _camera') ** -1; _full_M = transpose (_pinv * (transpose _camera' * _true_XYZ)); M = _full_M / scale; scale = sum _full_M.value?1; // now turn the camera to LAB and calculate dE76 _camera'' = (to_matrix @ colour_transform Image_type.XYZ Image_type.LAB @ recomb M @ multiply scale @ to_image) _camera'; _dEs = map abs_vec (_camera'' - _true_Lab).value; avg_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } // normalise brightness ... in linear mode, we optionally don't // set the brightness from the Macbeth chart norm x = x * scale, mode != 3 = x; // convert RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ norm @ recomb M @ cast_float @ linear) image.value; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ calib.norm @ recomb calib.M @ cast_float @ calib.linear) image.value; } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Interpolate_bilinear xfactor yfactor scale_im; _offset_im = resize Interpolate_bilinear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.40/Makefile.am0000644000175000017500000000062213351443023015177 00000000000000startdir = $(pkgdatadir)/compat/7.40 start_DATA = \ Math.def \ Image.def \ Magick.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _magick.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.40/Makefile.in0000644000175000017500000003715013417043242015220 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.40 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.40 start_DATA = \ Math.def \ Image.def \ Magick.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _magick.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.40/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.40/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.40/_magick.def0000644000175000017500000005416213351443023015225 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate _magick.def Add 0-ary and 2-ary system Put utility funcs into a Magick class 11-Apr-2014 snibgo Added VirtualPixelBack for cases where background is only relevant when VP=Background 17-Apr-2014 snibgo Many small changes. 2-May-2014 jcupitt Added Magick.version 30-June-2014 Put single-quotes around command exe to help win 1-July-2014 Automatically fall back to gm if we can't find convert 17-July-2014 better GM support Last update: 17-July-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ /* Put these in a class to avoid filling the main namespace with IM stuff. */ Magick = class { // turn $PATH into [["comp1", "comp2"], ["comp1", "comp2"] ..] system_search_path = map path_parse (split (equal path_sep) (expand "$PATH")) { path_sep = ':', expand "$SEP" == "/" = ';'; } // the first name[.exe] on $PATH, or "" search_for name = hits?0, hits != [] = "" { exe_name = name ++ expand "$EXEEXT"; form_path p = path_absolute (p ++ [exe_name]); paths = map form_path system_search_path; hits = dropwhile (equal []) (map search paths); } // first gm on path, or "" gm_path = search_for "gm"; // first convert on $PATH, or "" // we check for the convert we ship first convert_path = vips_convert, vips_convert != "" = search_for "convert" { // the convert we ship with the vips binary on some platforms, or "" vips_convert = search (path_absolute convert) { vipshome = path_parse (expand "$VIPSHOME"); convert = vipshome ++ ["bin", "convert" ++ expand "$EXEEXT"]; } } use_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK; // Are we in GM or IM mode? use_gm = true, use_gm_pref && gm_path != "" = false, !use_gm_pref && convert_path != "" = false, convert_path != "" = true, gm_path != "" = error "neither IM nor GM executable found"; command_path = gm_path, use_gm = convert_path; // try to get the version as eg. [6, 7, 7, 10] // GM versions are smaller, typically [1, 3, 18] version = map parse_int (split (member ".-") version_string) { [output] = vips_call "system" ["'" ++ command_path ++ "' -version"] [$log=>true]; version_string = (split (equal ' ') output)?1, use_gm = (split (equal ' ') output)?2; } // make a command-line ... args is a [str] we join with spaces command args = "'" ++ command_path ++ "' " ++ join_sep " " args' { args' = ["convert"] ++ args, use_gm = args; } // capabilities ... different versions support different features, we // turn features on and off based on these // would probably be better to test for caps somehow has_intensity = false, use_gm = version?0 > 6 || version?1 > 7; has_channel = false, use_gm = version?0 > 6 || version?1 > 7; system0 cmd = system_image0 cmd; system cmd x = map_unary (system_image cmd) x; system2 cmd x y = map_binary (system_image2 cmd) x y; system3 cmd x y z = map_trinary (system_image3 cmd) x y z; radius_widget = Scale "Radius" 0 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle (degrees)" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; gamma_widget = Scale "Gamma" 0 10 1; colors_widget = Scale "Colors" 1 10 3; resize_widget = Scale "Resize (percent)" 0 500 100; fuzz_widget = Scale "Fuzz (percent)" 0 100 0; blur_rad_widget = Scale "Radius (0=auto)" 0 100 0; // a colour with no enclosing quotes ... use this if we know there are // some quotes at an outer level print_colour_nq triple = concat ["#", concat (map fmt triple)] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } // we need the quotes because # is the comment character in *nix print_colour triple = "\"" ++ print_colour_nq triple ++ "\""; Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; GeneralCol triple = class Colour "sRGB" triple { _flag = print_colour_nq triple; Colour_edit space triple = this.GeneralCol triple; } generalcol_widget = GeneralCol [0, 0, 0]; Background triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" false; _flag = "-background " ++ if isNone then "None" else print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Bordercol triple = class Colour "sRGB" triple { _flag = "-bordercolor " ++ print_colour triple; Colour_edit space triple = this.Bordercol triple; } bordercol_widget = Bordercol [0, 0, 0]; Mattecol triple = class Colour "sRGB" triple { _flag = "-mattecolor " ++ print_colour triple; Colour_edit space triple = this.Mattecol triple; } mattecol_widget = Mattecol [189, 189, 189]; // FIXME: Undercolour, like many others, can have alpha channel. // How does user input this? With a slider? Undercol triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" true; _flag = if isNone then "" else ("-undercolor " ++ print_colour triple); Colour_edit space triple = this.Undercol triple; } undercol_widget = Undercol [0, 0, 0]; changeCol_widget = class { _vislevel = 3; colour = GeneralCol [0, 0, 0]; fuzz = fuzz_widget; nonMatch = Toggle "change non-matching colours" false; } Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Remove", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Builtin builtin = class Option_string "Builtin" [ // See http://www.imagemagick.org/script/formats.php "rose:", "logo:", "wizard:", "granite:", "netscape:" ] builtin { _flag = builtin; Option_edit caption labels value = this.Builtin labels?value; } builtin_widget = Builtin "rose:"; channels_widget = class { // FIXME? Can we grey-out alpha when we have no alpha channel, // show CMY(K) instead of RGB(K) etc? // Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA. ChanR valueR = class Toggle "Red" valueR { _flag = "R", valueR = ""; Toggle_edit caption valueR = this.ChanR valueR; } channelR = ChanR true; ChanG valueG = class Toggle "Green" valueG { _flag = "G", valueG = ""; Toggle_edit caption valueG = this.ChanG valueG; } channelG = ChanG true; ChanB valueB = class Toggle "Blue" valueB { _flag = "B", valueB = ""; Toggle_edit caption valueB = this.ChanB valueB; } channelB = ChanB true; ChanK valueK = class Toggle "Black" valueK { _flag = "K", valueK = ""; Toggle_edit caption valueK = this.ChanK valueK; } channelK = ChanK true; ChanA valueA = class Toggle "Alpha" valueA { _flag = "A", valueA = ""; Toggle_edit caption valueA = this.ChanA valueA; } channelA = ChanA false; ChanSy valueSy = class Toggle "Sync" valueSy { _flag = ",sync", valueSy = ""; Toggle_edit caption valueSy = this.ChanSy valueSy; } channelSy = ChanSy true; _rgbka = concat [channelR._flag, channelG._flag, channelB._flag, channelK._flag, channelA._flag ]; _flag = "", _rgbka == "" || !has_channel = concat [ "-channel ", _rgbka, channelSy._flag ]; } ch_widget = channels_widget; Colorspace colsp = class Option_string "Colorspace" [ "CIELab", "CMY", "CMYK", "Gray", "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "Lab", "LCH", "LCHab", "LCHuv", "LMS", "Log", "Luv", "OHTA", "Rec601Luma", "Rec601YCbCr", "Rec709Luma", "Rec709YCbCr", "RGB", "scRGB", "sRGB", "Transparent", "XYZ", "YCbCr", "YDbDr", "YCC", "YIQ", "YPbPr", "YUV" ] colsp { _flag = colsp; Option_edit caption labels value = this.Colorspace labels?value; } colorspace_widget = Colorspace "sRGB"; Compose comp = class Option_string "Compose method" [ "Atop", "Blend", "Blur", "Bumpmap", "ChangeMask", "Clear", "ColorBurn", "ColorDodge", "Colorize", "CopyBlack", "CopyBlue", "CopyCyan", "CopyGreen", "Copy", "CopyMagenta", "CopyOpacity", "CopyRed", "CopyYellow", "Darken", "DarkenIntensity", "DivideDst", "DivideSrc", "Dst", "Difference", "Displace", "Dissolve", "Distort", "DstAtop", "DstIn", "DstOut", "DstOver", "Exclusion", "HardLight", "Hue", "In", "Lighten", "LightenIntensity", "LinearBurn", "LinearDodge", "LinearLight", "Luminize", "Mathematics", "MinusDst", "MinusSrc", "Modulate", "ModulusAdd", "ModulusSubtract", "Multiply", "None", "Out", "Overlay", "Over", "PegtopLight", "PinLight", "Plus", "Replace", "Saturate", "Screen", "SoftLight", "Src", "SrcAtop", "SrcIn", "SrcOut", "SrcOver", "VividLight", "Xor" ] comp { _flag = "-compose " ++ comp; Option_edit caption labels value = this.Compose labels?value; } compose_widget = Compose "Over"; // FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string. // FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack coordinate_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; _flag = concat [print x.expr, ",", print y.expr]; }; Distort distort = class Option_string "Distort" [ "Affine", "AffineProjection", "ScaleRotateTranslate", "SRT", "Perspective", "PerspectiveProjection", "BilinearForward", "BilinearReverse", "Polynomial", "Arc", "Polar", "DePolar", "Barrel", "BarrelInverse", "Shepards", "Resize" ] distort { _flag = distort; Option_edit caption labels value = this.Distort labels?value; } distort_widget = Distort "SRT"; Dither dither = class Option_string "Dither" [ "None", "FloydSteinberg", "Riemersma" ] dither { _flag = "-dither " ++ dither; Option_edit caption labels value = this.Dither labels?value; } dither_widget = Dither "FloydSteinberg"; Evaluate eval = class Option_string "Evaluate operation" [ "Abs", "Add", "AddModulus", "And", "Cos", "Cosine", "Divide", "Exp", "Exponential", "GaussianNoise", "ImpulseNoise", "LaplacianNoise", "LeftShift", "Log", "Max", "Mean", "Median", "Min", "MultiplicativeNoise", "Multiply", "Or", "PoissonNoise", "Pow", "RightShift", "Set", "Sin", "Sine", "Subtract", "Sum", "Threshold", "ThresholdBlack", "ThresholdWhite", "UniformNoise", "Xor" ] eval { _flag = "-evaluate " ++ eval; Option_edit caption labels value = this.Evaluate labels?value; } evaluate_widget = Evaluate "Add"; Filter filt = class Option_string "Filter" [ "default", "Bartlett", "Blackman", "Bohman", "Box", "Catrom", "Cosine", "Cubic", "Gaussian", "Hamming", "Hann", "Hermite", "Jinc", "Kaiser", "Lagrange", "Lanczos", "Lanczos2", "Lanczos2Sharp", "LanczosRadius", "LanczosSharp", "Mitchell", "Parzen", "Point", "Quadratic", "Robidoux", "RobidouxSharp", "Sinc", "SincFast", "Spline", "Triangle", "Welch" ] filt { _flag = if filt == "default" then "" else "-filter " ++ filt; Option_edit caption labels value = this.Filter labels?value; } filter_widget = Filter "default"; Function func = class Option_string "Function" [ "Polynomial", "Sinusoid", "Arcsin", "Arctan" ] func { _flag = func; Option_edit caption labels value = this.Function labels?value; } function_widget = Function "Polynomial"; // "Polynomial (a[n], a[n-1], ... a[1], a[0])", // "Sinusoid (freq, phase, amp, bias)", // "Arcsin (width, centre, range, bias)", // "Arctan (slope, centre, range, bias)" Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; ImageType imagetype = class Option_string "Image type" [ "Bilevel", "ColorSeparation", "ColorSeparationAlpha", "ColorSeparationMatte", "Grayscale", "GrayscaleAlpha", "GrayscaleMatte", "Optimize", "Palette", "PaletteBilevelAlpha", "PaletteBilevelMatte", "PaletteAlpha", "PaletteMatte", "TrueColorAlpha", "TrueColorMatte", "TrueColor" ] imagetype { _flag = "-type " ++ imagetype; Option_edit caption labels value = this.ImageType labels?value; } imagetype_widget = ImageType "TrueColor"; Intensity intensity = class Option_string "Intensity (gray conversion)" [ "Average", "Brightness", "Lightness", "MS", "Rec601Luma", "Rec601Luminance", "Rec709Luma", "Rec709Luminance", "RMS" ] intensity { _flag = "-intensity " ++ intensity, has_intensity = ""; Option_edit caption labels value = this.Intensity labels?value; } intensity_widget = Intensity "Rec709Luminance"; Interpolate interp = class Option_string "Interpolate" [ "default", "Average", "Average4", "Average9", "Average16", "Background", "Bilinear", "Blend", "Integer", "Mesh", "Nearest", "NearestNeighbor", "Spline" ] interp { _flag = if interp == "default" then "" else "-interpolate " ++ interp; Option_edit caption labels value = this.Interpolate labels?value; } interpolate_widget = Interpolate "default"; Kernel kernel = class Option_string "Kernel" [ "Unity", "Gaussian", "DoG", "LoG", "Blur", "Comet", "Binomial", "Laplacian", "Sobel", "FreiChen", "Roberts", "Prewitt", "Compass", "Kirsch", "Diamond", "Square", "Rectangle", "Disk", "Octagon", "Plus", "Cross", "Ring", "Peaks", "Edges", "Corners", "Diagonals", "LineEnds", "LineJunctions", "Ridges", "ConvexHull", "ThinSe", "Skeleton", "Chebyshev", "Manhattan", "Octagonal", "Euclidean" // FIXME: custom kernel ] kernel { _flag = kernel; Option_edit caption labels value = this.Kernel labels?value; } kernel_widget = Kernel "Unity"; ModColSp msp = class Option_string "modulate colorspace" [ "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "LCH" ] msp { _flag = "-set option:modulate:colorspace " ++ msp; Option_edit caption labels value = this.ModColSp labels?value; } ModColSp_widget = ModColSp "HSL"; MorphMeth morph = class Option_string "Method" [ "Correlate", "Convolve", "Dilate", "Erode", "Close", "Open", "DilateIntensity", "ErodeIntensity", "CloseIntensity", "OpenIntensity", "Smooth", "EdgeOut", "EdgeIn", "Edge", "TopHat", "BottomHat", "HitAndMiss", "Thinning", "Thicken", "Distance", "IterativeDistance" ] morph { _flag = morph; Option_edit caption labels value = this.MorphMeth labels?value; } morphmeth_widget = MorphMeth "Dilate"; Noise noise = class Option_string "Noise" [ "Gaussian", "Impulse", "Laplacian", "Multiplicative", "Poisson", "Random", "Uniform" ] noise { _flag = "+noise " ++ noise; Option_edit caption labels value = this.Noise labels?value; } noise_widget = Noise "Gaussian"; Pattern pattern = class Option_string "Noise" [ // See http://www.imagemagick.org/script/formats.php "bricks", "checkerboard", "circles", "crosshatch", "crosshatch30", "crosshatch45", "gray0", "gray5", "gray10", "gray15", "gray20", "gray25", "gray30", "gray35", "gray40", "gray45", "gray50", "gray55", "gray60", "gray65", "gray70", "gray75", "gray80", "gray85", "gray90", "gray95", "gray100", "hexagons", "horizontal", "horizontal2", "horizontal3", "horizontalsaw", "hs_bdiagonal", "hs_cross", "hs_diagcross", "hs_fdiagonal", "hs_horizontal", "hs_vertical", "left30", "left45", "leftshingle", "octagons", "right30", "right45", "rightshingle", "smallfishscales", "vertical", "vertical2", "vertical3", "verticalbricks", "verticalleftshingle", "verticalrightshingle", "verticalsaw" ] pattern { _flag = "pattern:" ++ pattern; Option_edit caption labels value = this.Pattern labels?value; } pattern_widget = Pattern "bricks"; ResizeType resizet = class Option_string "Resize type" [ "resize", "scale", "sample", "adaptive-resize" ] resizet { _flag = resizet; Option_edit caption labels value = this.ResizeType labels?value; } ResizeType_widget = ResizeType "resize"; Size_widget = class { _vislevel = 3; width = Expression "Width (pixels)" 64; height = Expression "Height (pixels)" 64; _flag = "-size " ++ print width.expr ++ "x" ++ print height.expr; }; StatType statt = class Option_string "Statistic type" [ "Gradient", "Maximum", "Mean", "Median", "Minimum", "Mode", "Nonpeak", "StandardDeviation" ] statt { _flag = statt; Option_edit caption labels value = this.StatType labels?value; } StatType_widget = StatType "Mean"; VirtualPixel vp = class Option_string "Virtual pixel" [ "Background", "Black", "CheckerTile", "Dither", "Edge", "Gray", "HorizontalTile", "HorizontalTileEdge", "Mirror", "None", "Random", "Tile", "Transparent", "VerticalTile", "VerticalTileEdge", "White" ] vp { _flag = "-virtual-pixel " ++ vp; _isBackground = (vp == "Background"); Option_edit caption labels value = this.VirtualPixel labels?value; } VirtualPixel_widget = VirtualPixel "Edge"; VirtualPixelBack_widget = class { virtpix = Magick.VirtualPixel_widget; background = Magick.background_widget; _flag = (if virtpix._isBackground then (background._flag ++ " ") else "") ++ virtpix._flag; } Geometry_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; AnnotGeometry_widget = class { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print shearX.expr, "x", print shearY.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; OffsetGeometry_widget = class { _vislevel = 3; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; WhxyGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; FrameGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; outbev = Expression "Outer bevel thickness" 0; inbev = Expression "Inner bevel thickness" 0; _flag = concat [print x.expr, "x", print y.expr, format outbev, format inbev] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } } nip2-8.7.1/share/nip2/compat/7.40/_predicate.def0000644000175000017500000003252613351443023015732 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Plot x = is_instanceof "Plot" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = oo_unary_function get_type_op x, is_class x = error (_ "bad arguments to " ++ "get_type") { get_type_op = Operator "get_type" get_type Operator_type.COMPOUND false; // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = oo_unary_function get_format_op x, is_class x = error (_ "bad arguments to " ++ "get_format") { get_format_op = Operator "get_format" get_format Operator_type.COMPOUND false; } has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = oo_unary_function get_bits_op x, is_class x = error (_ "bad arguments to " ++ "get_bits") { get_bits_op = Operator "get_bits" get_format Operator_type.COMPOUND false; } has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = oo_unary_function get_bands_op x, is_class x = error (_ "bad arguments to " ++ "get_bands") { get_bands_op = Operator "get_bands" get_bands Operator_type.COMPOUND false; } has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = oo_unary_function get_coding_op x, is_class x = error (_ "bad arguments to " ++ "get_coding") { get_coding_op = Operator "get_coding" get_coding Operator_type.COMPOUND false; } has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = oo_unary_function get_xres_op x, is_class x = error (_ "bad arguments to " ++ "get_xres") { get_xres_op = Operator "get_xres" get_xres Operator_type.COMPOUND false; } has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = oo_unary_function get_yres_op x, is_class x = error (_ "bad arguments to " ++ "get_yres") { get_yres_op = Operator "get_yres" get_yres Operator_type.COMPOUND false; } has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = oo_unary_function get_xoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_xoffset") { get_xoffset_op = Operator "get_xoffset" get_xoffset Operator_type.COMPOUND false; } has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = oo_unary_function get_yoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_yoffset") { get_yoffset_op = Operator "get_yoffset" get_yoffset Operator_type.COMPOUND false; } has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = oo_unary_function get_image_op x, is_class x = error (_ "bad arguments to " ++ "get_image") { get_image_op = Operator "get_image" get_image Operator_type.COMPOUND false; } has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = oo_unary_function get_number_op x, is_class x = error (_ "bad arguments to " ++ "get_number") { get_number_op = Operator "get_number" get_number Operator_type.COMPOUND false; } has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = oo_unary_function get_real_op x, is_class x = error (_ "bad arguments to " ++ "get_real") { get_real_op = Operator "get_real" get_real Operator_type.COMPOUND false; } has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = oo_unary_function get_width_op x, is_class x = error (_ "bad arguments to " ++ "get_width") { get_width_op = Operator "get_width" get_width Operator_type.COMPOUND false; } has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = oo_unary_function get_height_op x, is_class x = error (_ "bad arguments to " ++ "get_height") { get_height_op = Operator "get_height" get_height Operator_type.COMPOUND false; } has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = oo_unary_function get_left_op x, is_class x = error (_ "bad arguments to " ++ "get_left") { get_left_op = Operator "get_left" get_left Operator_type.COMPOUND false; } has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = oo_unary_function get_top_op x, is_class x = error (_ "bad arguments to " ++ "get_top") { get_top_op = Operator "get_top" get_top Operator_type.COMPOUND false; } // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/7.40/_list.def0000644000175000017500000002310313351443023014734 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* flatten x: flatten a list of lists of things into a simple list * * flatten :: [[*]] -> [*] */ flatten x = foldr flat [] x, is_list x = x { flat x sofar = foldr flat sofar x, is_list x = x : sofar; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st x) xs { x:xs = l; } /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn x xs { x:xs = l; } /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn x (foldr fn st xs) { x:xs = l; } /* foldr1 fn l: like foldr, but use the last element as the start value * * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = x, xs == [] = fn x (foldr1 fn xs) { x:xs = l; } /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn x = search xs (n + 1) { x:xs = l; } } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = x : init xs { x:xs = l; } /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = x, xs == [] = last xs { x:xs = l; } /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scanl fn st l: apply (foldl fn r) to every initial segment of a list * * scanl add 0 [1,2,3] == [1,3,6] * scanl :: (* -> ** -> *) -> * -> [**] -> [*] */ scanl fn st l = st, l == [] = st' : scanl fn st' xs { x:xs = l; st' = fn st x; } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/8.2/0000755000175000017500000000000013417043453013150 500000000000000nip2-8.7.1/share/nip2/compat/8.2/Image.def0000644000175000017500000014444213351443023014575 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process = [ // we can't use id here since we want to "declass" // the members of x ... consider if x is a crop class, // for example, we don't want to inherit from crop, we // want to make a new image class rot180 @ rot180, rot90, rot180, rot270 ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp h v image, aspect = resize interp fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize interp fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_map_item = class Menuaction "_Map" "map an image through a 2D transform image" { action a b = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_binary trans a b { trans a b = mapim interp.value in index { // get the index image first [index, in] = sortc (const is_twocomponent) [a, b]; // is a two-component image, ie. one band complex, or // two-band non-complex is_twocomponent x = is_nonc x || is_c x; is_nonc x = has_bands x && get_bands x == 2 && has_format x && !is_complex_format (get_format x); is_c x = has_bands x && get_bands x == 1 && has_format x && is_complex_format (get_format x); is_complex_format f = f == Image_format.COMPLEX || f == Image_format.DPCOMPLEX; } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; Bandand_item = class Menuaction "Bitwise Band AND" "bitwise AND of image bands" { action x = bandand x; } Bandor_item = class Menuaction "Bitwise Band OR" "bitwise OR of image bands" { action x = bandor x; } sep2 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = crop x [l, t, w, h] { fields = [ [has_left, get_left, 0], [has_top, get_top, 0], [has_width, get_width, 100], [has_height, get_height, 100] ]; [l, t, w, h] = map get_default fields { get_default line = get x, has x = default { [has, get, default] = line; } } } crop x geo = class _result { _vislevel = 3; l = Expression "Crop left" ((int) (geo?0 + geo?2 / 4)); t = Expression "Crop top" ((int) (geo?1 + geo?3 / 4)); w = Expression "Crop width" (max_pair 1 ((int) (geo?2 / 2))); h = Expression "Crop height" (max_pair 1 ((int) (geo?3 / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 100; sy = Expression "Start y" 100; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise Join" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/8.2/_convert.def0000644000175000017500000004223013351443023015362 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = Image x.value, is_Plot x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The outermost list objects become Group()'d. */ to_group x = Group x, is_list x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = sign * (abs ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; sign = 1, ipart > 0 = -1; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/8.2/Filter.def0000644000175000017500000011551413351443023014776 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 2; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 20; fs = Scale "Sharpen flat areas by" 0 5 0.5; js = Scale "Sharpen jaggy areas by" 0 5 1; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_hough_item = class Menupullright "_Hough Transform" "transform to parameter space" { Line_item = class Menuaction "_Line" "find straight line Hough transform" { action a = class _result { _vislevel = 3; pspace_width = Expression "Parameter space width" 64; pspace_height = Expression "Parameter space height" 64; _result = map_unary line a { line a = hough_line (to_real pspace_width) (to_real pspace_height) a; } } } Circle_item = class Menuaction "_Circle" "find circle Hough transform" { action a = class _result { _vislevel = 3; scale = Expression "Scale down parameter space by" 10; min_radius = Expression "Minimum radius" 10; max_radius = Expression "Maximum radius" 30; _result = map_unary circle a { circle a = hough_circle (to_real scale) (to_real min_radius) (to_real max_radius) a; } } } } Filter_coordinate_item = class Menupullright "_Coordinate Transform" "various coordinate transforms" { // run a function which wants a complex arg on a non-complex two-band // image run_cmplx fn x = re x' ++ im x' { x' = fn (x?0, x?1); } Polar_item = class Menuaction "_Polar" "transform to polar coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_polar a { to_polar im = mapim interp.value map' im { // xy image, origin in the centre, scaled to fit image to // a circle xy = make_xy im.width im.height; xy' = xy - Vector [im.width / 2, im.height / 2]; scale = min [im.width, im.height] / im.width; xy'' = 2 * xy' / scale; // to polar, scale vertical axis to 360 degrees map = run_cmplx polar xy''; map' = map * Vector [1, im.height / 360]; } } } } Rectangular_item = class Menuaction "_Rectangular" "transform to rectangular coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_rect a { to_rect im = mapim interp.value map'' im { // xy image, vertical scaled to 360 degrees xy = make_xy im.width im.height; xy' = xy * Vector [1, 360 / im.height]; // to rect, scale to image rect map = run_cmplx rectangular xy'; scale = min [im.width, im.height] / im.width; map' = map * scale / 2; map'' = map' + Vector [im.width / 2, im.height / 2]; } } } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } nip2-8.7.1/share/nip2/compat/8.2/_joe_extra.def0000644000175000017500000003114713351443023015667 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use an Arrow or Region x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { im = x.image; mask = Image m { rx = x.region_rect, is_Region x = x; b = image_new im.width im.height 1 0 0 1 0 0 0; w = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0; m = insert_noexpand rx.nleft rx.ntop w b; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Interpolate_bilinear f1 1 b1 {b1 = resize Interpolate_bilinear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/8.2/Preferences.ws0000644000175000017500000010177313351443023015707 00000000000000 nip2-8.7.1/share/nip2/compat/8.2/Magick.def0000644000175000017500000014112713351443023014743 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate Magick.def 13-Apr-2014 snibgo Put "new image" items into sub-menu. New class VirtualPixlBack. 17-Apr-2014 snibgo Many small changes. A few new menu options. Created sub-menu for multi-input operations. 3-May-2014 jcupitt Put quotes around ( in shadow to help unix Last update: 17-Apr-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ // We don't need Noop. /*=== Magick_noop_item = class Menuaction "_Noop" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_testPar_item = class Menuaction "_TestPar" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "( +clone ) +append ", "\"%s\"" ]; _result = Magick.system command x; } } /* Removed Read_item and Write_item, much better to use nip2 load/save image. * Plus they can load all libMagick formats anyway. */ // Put "new image" items into sub-menu Magick_NewImageMenu_item = class Menupullright "_New image" "make a new image" { Magick_newcanvas_item = class Menuaction "_Solid colour" "make image of solid colour" { action = class _result { _vislevel = 3; size = Magick.Size_widget; colour = Magick.generalcol_widget; command = Magick.command [ size._flag, "\"canvas:" ++ colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_builtin_item = class Menuaction "_Built-in image" "create a built-in image" { action = class _result { _vislevel = 3; builtin = Magick.builtin_widget; command = Magick.command [ builtin._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_gradient_item = class Menuaction "_Gradient" "make a linear gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; topColour = Magick.generalcol_widget; bottomColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"gradient:", topColour._flag, "-", bottomColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } Magick_hald_item = class Menuaction "_Hald-clut image" "create an identity hald-clut image" { action = class _result { _vislevel = 3; order = Expression "order" 8; command = Magick.command [ "hald:" ++ print order.expr, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_pattern_item = class Menuaction "_Pattern" "create pattern" { action = class _result { _vislevel = 3; size = Magick.Size_widget; pattern = Magick.pattern_widget; command = Magick.command [ size._flag, pattern._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_plasma_item = class Menuaction "_Plasma image" "create plasma image" { action = class _result { _vislevel = 3; size = Magick.Size_widget; // FIXME? ColourA-ColourB. // FIXME? Allow plasma:fractal? command = Magick.command [ size._flag, "plasma:", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_radialgradient_item = class Menuaction "_Radial gradient" "make a radial gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; innerColour = Magick.generalcol_widget; outerColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"radial-gradient:", innerColour._flag, "-", outerColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } } // end Magick_NewImageMenu_item Magick_MultiMenu_item = class Menupullright "_Multiple inputs" "make an image from multiple images" { Magick_composite_item = class Menuaction "_Composite" "composite two images (without mask)" { action x y = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_compositeMask_item = class Menuaction "_Composite masked" "composite two images (with mask)" { action x y z = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system3 command x y z; } } // FIXME: other operations like remap that take another image as arguments are: // mask (pointless?), texture, tile (pointless?) // FIXME: operations that take a filename that isn't an image: // cdl, profile Magick_clut_item = class Menuaction "_Clut" "replace values using second image as colour look-up table" { action x y = class _result { _vislevel = 3; // FIXME: uses -intensity "when mapping greyscale CLUT image to alpha channel if set by -channels" command = Magick.command [ "\"%s\"", "\"%s\"", "-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_haldclut_item = class Menuaction "_Hald clut" "replace values using second image as Hald colour look-up table" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"", "-hald-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } // Encipher and decipher: key files can be text or image files. Magick_encipher_item = class Menuaction "_Encipher/Decipher" "encipher or decipher an image image" { action x = class _result { _vislevel = 3; pathname = Pathname "Read key file" ""; isDecipher = Toggle "Decipher" false; command = Magick.command [ "\"%s\"", if pathname.value == "" then "" else ( ( if isDecipher then "-decipher " else "-encipher ") ++ ( "\"" ++ pathname.value ++ "\"" ) ), "\"%s\"" ]; _result = Magick.system command x; } } Magick_profile_item = class Menuaction "_Profile" "assigns/applies an ICC profile" { action x = class _result { _vislevel = 3; pathname1 = Pathname "Read profile file" ""; pathname2 = Pathname "Read profile file" ""; command = Magick.command [ "\"%s\"", if pathname1.value == "" then "" else ( "-profile " ++ "\"" ++ pathname1.value ++ "\""), if pathname2.value == "" then "" else ( "-profile " ++ "\"" ++ pathname2.value ++ "\""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_remap_item = class Menuaction "_Remap" "reduce colours to those in another image" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-remap", "\"%s\"", "\"%s\"" ]; _result = Magick.system2 command x y; } } } // end Magick_MultiMenu_item Magick_image_type_item = class Menuaction "_Image Type" "change image type" { action x = class _result { _vislevel = 3; imagetype = Magick.imagetype_widget; command = Magick.command [ "\"%s\"", imagetype._flag, "\"%s\"" ]; _result = Magick.system command x; } } sep2 = Menuseparator; Magick_alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = Magick.alpha_widget; command = Magick.command [ "\"%s\"", alpha._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = Magick.text_widget; font = Magick.Font_widget; geometry = Magick.AnnotGeometry_widget; gravity = Magick.gravity_widget; foreground = Magick.foreground_widget; undercol = Magick.undercol_widget; antialias = Magick.antialias_widget; command = Magick.command [ "\"%s\"", font._flag, antialias._flag, gravity._flag, foreground._flag, undercol._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoGamma_item = class Menuaction "_AutoGamma" "automatic gamma" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-gamma", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoLevel_item = class Menuaction "_AutoLevel" "automatic level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-level", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blurSharpMenu_item = class Menupullright "_Blur/Sharpen" "blur and sharpen" { Magick_adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; // note: adaptive-blur doesn't regard VP. command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-adaptive-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_blur_item = class Menuaction "_Blur" "blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gaussianBlur_item = class Menuaction "_Gaussian Blur" "blur with a Gaussian operator" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-gaussian-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_motionBlur_item = class Menuaction "_Motion Blur" "simulate motion blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; channels = Magick.ch_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-motion-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotationalBlur_item = class Menuaction "_RotationalBlur" "blur around the centre" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; angle = Scale "angle (degrees)" (-360) 360 20; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-radial-blur", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_selectiveBlur_item = class Menuaction "_Selective Blur" "blur where contrast is less than or equal to threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; threshold = Scale "Threshold (percent)" 0 100 50; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", intensity._flag, virtpixback._flag, channels._flag, "-selective-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print threshold.value ++ "%%", "\"%s\"" ]; _result = Magick.system command x; } } sep1 = Menuseparator; Magick_adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-adaptive-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sharpen_item = class Menuaction "_Sharpen" "sharpen" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_unsharpen_item = class Menuaction "_Unsharp" "sharpen with unsharp mask" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; gain = Scale "Gain" (-10) 10 1; threshold = Scale "Threshold" 0 1 0.05; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-unsharp", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print gain.value ++ "+" ++ print threshold.value, "\"%s\"" ]; _result = Magick.system command x; } } } // end BlurSharpMenu_item Magick_border_item = class Menuaction "_Border" "add border of given colour" { action x = class _result { _vislevel = 3; compose = Magick.compose_widget; width = Expression "Width" 3; bordercol = Magick.bordercol_widget; command = Magick.command [ "\"%s\"", compose._flag, bordercol._flag, "-border", print width.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_brightCont_item = class Menuaction "_Brightness-contrast" "adjust the brightness and/or contrast" { action x = class _result { _vislevel = 3; bri = Scale "brightness" (-100) 100 0; con = Scale "contrast" (-100) 100 0; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-brightness-contrast", print bri.value ++ "x" ++ print con.value, "\"%s\"" ]; _result = Magick.system command x; } } // Note: canny requires ImageMagick 6.8.9-0 or later. Magick_canny_item = class Menuaction "_Canny" "detect a wide range of edges" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; lowPc = Scale "lower percent" 0 100 10; highPc = Scale "lower percent" 0 100 10; command = Magick.command [ "\"%s\"", "-canny", concat ["\"", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print lowPc.value ++ "%%+" ++ print highPc.value ++ "%%" ++ "\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_charcoal_item = class Menuaction "_Charcoal" "simulate a charcoal drawing" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; factor = Scale "factor" 0 50 1; command = Magick.command [ "\"%s\"", intensity._flag, "-charcoal", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_chop_item = class Menuaction "_Chop" "remove pixels from the interior" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-chop", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorize_item = class Menuaction "_Colorize" "colorize by given amount" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; val = Scale "value" 0 100 100; command = Magick.command [ "\"%s\"", foreground._flag, "-colorize", print val.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colors_item = class Menuaction "_Colors" "reduce number of colors" { action x = class _result { _vislevel = 3; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; quantize = Magick.colorspace_widget; colors = Expression "Colours" 3; command = Magick.command [ "\"%s\"", "-quantize", quantize._flag, "-treedepth", print treedepth.expr, dither._flag, "-colors", print colors.expr, "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: color-matrix? Magick_colorspace_item = class Menuaction "_Colourspace" "convert to arbitrary colourspace" { action x = class _result { _vislevel = 3; colsp = Magick.colorspace_widget; command = Magick.command [ "\"%s\"", "-colorspace", colsp._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorspaceGray_item = class Menuaction "_Colourspace gray" "convert to gray using given intensity method" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-colorspace gray", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrast_item = class Menuaction "_Contrast" "increase or reduce the contrast" { action x = class _result { _vislevel = 3; isReduce = Toggle "reduce contrast" false; command = Magick.command [ "\"%s\"", (if isReduce then "+" else "-") ++ "contrast", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrastStretch_item = class Menuaction "_Contrast stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-contrast-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: convolve (bias, kernel) Magick_crop_item = class Menuaction "_Crop" "cut out a rectangular region" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-crop", geometry._flag, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_deskew_item = class Menuaction "_Deskew" "straighten the image" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; // FIXME: toggle auto-crop? command = Magick.command [ "\"%s\"", "-deskew", "\"" ++ print threshold.value ++ "%%\"", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_despeckle_item = class Menuaction "_Despeckle" "reduce the speckles" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-despeckle", "\"%s\"" ]; _result = Magick.system command x; } } Magick_distort_item = class Menuaction "_Distort" "distort using a method and arguments" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; distort = Magick.distort_widget; args = String "Arguments" "1,0"; isPlus = Toggle "Extend to show entire image" false; command = Magick.command [ "\"%s\"", virtpixback._flag, (if isPlus then "+" else "-") ++ "distort", distort._flag, args.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_draw_item = class Menuaction "_Draw" "annotate with one or more graphic primitives" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; args = String "Arguments" "line 0,0 9,9 rectangle 10,10 20,20"; command = Magick.command [ "\"%s\"", foreground._flag, "-draw", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_edge_item = class Menuaction "_Edge" "detect edges" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-edge", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_emboss_item = class Menuaction "_Emboss" "emboss" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-emboss", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_enhance_item = class Menuaction "_Enhance" "enhance a noisy image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-enhance", "\"%s\"" ]; _result = Magick.system command x; } } Magick_equalize_item = class Menuaction "_Equalize" "equalize the histogram" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-equalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_evaluate_item = class Menuaction "_Evaluate" "evaluate an expression on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; operation = Magick.evaluate_widget; val = Expression "value" 5; isPc = Toggle "Value is percent" false; command = Magick.command [ "\"%s\"", channels._flag, operation._flag, print val.expr ++ if isPc then "%%" else "", "\"%s\"" ]; _result = Magick.system command x; } } Magick_extent_item = class Menuaction "_Extent" "set the image size and offset" { action x = class _result { _vislevel = 3; background = Magick.background_widget; compose = Magick.compose_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, background._flag, gravity._flag, "-extent", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_FlipFlopMenu_item = class Menupullright "_Flip/flop" "flip/flop/transverse/transpose" { Magick_flip_item = class Menuaction "_Flip vertically" "mirror upside-down" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flip", "\"%s\"" ]; _result = Magick.system command x; } } Magick_flop_item = class Menuaction "_Flop horizontally" "mirror left-right" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flop", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transpose_item = class Menuaction "_Transpose" "mirror along the top-left to bottom-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transpose +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transverse_item = class Menuaction "_Transverse" "mirror along the bottom-left to top-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transverse +repage", "\"%s\"" ]; _result = Magick.system command x; } } } // end Magick_FlipFlopMenu_item Magick_floodfill_item = class Menuaction "_Floodfill" "recolour neighbours that match" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; fuzz = Magick.fuzz_widget; coordinate = Magick.coordinate_widget; // -draw "color x,y floodfill" command = Magick.command [ "\"%s\"", foreground._flag, "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-draw \" color", coordinate._flag, "floodfill \"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_frame_item = class Menuaction "_Frame" "surround with border or beveled frame" { action x = class _result { _vislevel = 3; border = Magick.bordercol_widget; compose = Magick.compose_widget; matte = Magick.mattecol_widget; geometry = Magick.FrameGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, border._flag, matte._flag, "-frame", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_function_item = class Menuaction "_Function" "evaluate a function on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; function = Magick.function_widget; // FIXME: explain values; use sensible defaults. values = String "values" "0,0,0,0"; command = Magick.command [ "\"%s\"", channels._flag, "-function", function._flag, values.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_fx_item = class Menuaction "_Fx" "apply a mathematical expression" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; interpolate = Magick.interpolate_widget; virtpixback = Magick.VirtualPixelBack_widget; args = String "Expression" "u*1/2"; command = Magick.command [ "\"%s\"", channels._flag, interpolate._flag, virtpixback._flag, "-fx", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_gamma_item = class Menuaction "_Gamma" "apply a gamma correction" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; gamma = Magick.gamma_widget; command = Magick.command [ "\"%s\"", channels._flag, "-gamma", print gamma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradient_item = class Menuaction "_Gradient" "apply a linear gradient" { action x = class _result { _vislevel = 3; colourA = Magick.generalcol_widget; colourB = Magick.generalcol_widget; position = Option "colourA is at" [ "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"] 0; _baryArg = concat ["0,0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 0 = concat ["0,0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 1 = concat ["0,0,", colourA._flag, " %%[fx:w-1],0,", colourB._flag], position.value == 2 = concat ["0,0,", colourB._flag, " %%[fx:w-1],0,", colourA._flag], position.value == 3 = concat ["0,0,", colourA._flag, " %%[fx:w-1],%%[fx:h-1],", colourB._flag], position.value == 4 = concat ["%%[fx:w-1],0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 5 = concat ["%%[fx:w-1],0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 6 = concat ["0,0,", colourB._flag, " %%[fx:w-1],%%[fx:h-1],", colourA._flag], position.value == 7 = "dunno"; command = Magick.command [ "\"%s\"", "-sparse-color barycentric \"" ++ _baryArg ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradientCorn_item = class Menuaction "_Gradient corners" "apply a bilinear gradient between the corners" { action x = class _result { _vislevel = 3; colour_top_left = Magick.generalcol_widget; colour_top_right = Magick.generalcol_widget; colour_bottom_left = Magick.generalcol_widget; colour_bottom_right = Magick.generalcol_widget; command = Magick.command [ "\"%s\"", "-sparse-color bilinear \"" ++ "0,0," ++ colour_top_left._flag ++ ",%%[fx:w-1],0" ++ colour_top_right._flag ++ ",0,%%[fx:h-1]" ++ colour_bottom_left._flag ++ ",%%[fx:w-1],%%[fx:h-1]" ++ colour_bottom_right._flag ++ "\"", "+depth", "\"%s\"" ]; _result = Magick.system command x; } } Magick_histogram_item = class Menuaction "_Histogram" "make a histogram image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-define histogram:unique-colors=false histogram:" ++ "\"%s\"" ]; _result = Magick.system command x; } } Magick_implode_item = class Menuaction "_Implode" "implode pixels about the center" { action x = class _result { _vislevel = 3; factor = Scale "factor" 0 20 1; interpolate = Magick.interpolate_widget; // FIXME: virtual-pixel? command = Magick.command [ "\"%s\"", interpolate._flag, "-implode", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_level_item = class Menuaction "_Level" "adjust the level of channels" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "black point" (-100) 200 0; wht = Scale "white point" (-100) 200 100; gam = Scale "gamma" 0 30 1; isPc = Toggle "Levels are percent" true; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level", "\"" ++ print blk.value ++ "," ++ print wht.value ++ (if isPc then "%%" else "") ++ "," ++ print gam.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_levelCols_item = class Menuaction "_Level colors" "adjust levels to given colours" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; colour_black = Magick.generalcol_widget; colour_white = Magick.generalcol_widget; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level-colors", "\"" ++ colour_black._flag ++ "," ++ colour_white._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_linearStretch_item = class Menuaction "_Linear stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", channels._flag, "-linear-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_magnify_item = class Menuaction "_Magnify" "double the size of the image with pixel art scaling" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-magnify", "\"%s\"" ]; _result = Magick.system command x; } } Magick_modulate_item = class Menuaction "_Modulate" "modulate brightness, saturation and hue" { action x = class _result { _vislevel = 3; modcolsp = Magick.ModColSp_widget; bright = Scale "brightness" 0 200 100; sat = Scale "saturation" 0 200 100; hue = Scale "hue" 0 200 100; command = Magick.command [ "\"%s\"", modcolsp._flag, "-modulate", print bright.value ++ "," ++ print sat.value ++ "," ++ print hue.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_monochrome_item = class Menuaction "_Monochrome" "transform to black and white" { action x = class _result { _vislevel = 3; // FIXME: also intensity? intensity = Magick.intensity_widget; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; command = Magick.command [ "\"%s\"", intensity._flag, dither._flag, "-treedepth", print treedepth.expr, "-monochrome", "\"%s\"" ]; _result = Magick.system command x; } } Magick_morphology_item = class // See http://www.imagemagick.org/Usage/morphology/ Menuaction "_Morphology" "apply a morphological method" { action x = class _result { _vislevel = 3; method = Magick.morphmeth_widget; iter = Expression "Iterations (-1=repeat until done)" 1; kernel = Magick.kernel_widget; // FIXME: custom kernel eg "3x1+2+0:1,0,0" // width x height + offsx + offsy : {w*h values} // each value is 0.0 to 1.0 or "NaN" or "-" // kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0 // but // ring takes: radius1, radius2, scale // rectangle and comet take: width x height + offsx + offsy // blur takes: radius x sigma // FIXME: for now, simply allow any string input. kernel_arg = String "Kernel arguments" ""; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-morphology", method._flag ++ ":" ++ print iter.expr, kernel._flag ++ (if kernel_arg.value == "" then "" else ":") ++ kernel_arg.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_negate_item = class Menuaction "_Negate" "negate" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-negate", "\"%s\"" ]; _result = Magick.system command x; } } Magick_addNoise_item = class Menuaction "_add Noise" "add noise" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; attenuate = Scale "attenuate" 0 1.0 1.0; noise = Magick.noise_widget; command = Magick.command [ "\"%s\"", channels._flag, "-attenuate", print attenuate.value, noise._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_normalize_item = class Menuaction "_Normalize" "normalize" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-normalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_opaque_item = class Menuaction "_Opaque" "change this colour to the fill colour" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; fill = Magick.foreground_widget; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", fill._flag, channels._flag, "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "opaque", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_paint_item = class Menuaction "_Paint" "simulate an oil painting" { action x = class _result { _vislevel = 3; rad = Expression "radius" 10; command = Magick.command [ "\"%s\"", "-paint", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } /*=== FIXME Bug; remove for now. Polaroid_item = class Menuaction "_Polaroid" "simulate a polaroid picture" { action x = class _result { _vislevel = 3; angle = Scale "angle" (-90) 90 20; command = Magick.command [ "\"%s\"", "-polaroid", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_posterize_item = class Menuaction "_Posterize" "reduce to (n) levels per channel" { action x = class _result { _vislevel = 3; levels = Expression "levels" 3; command = Magick.command [ "\"%s\"", "-posterize", print levels.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_raise_item = class Menuaction "_Raise" "lighten or darken image edges" { action x = class _result { _vislevel = 3; thk = Expression "Thickness" 3; command = Magick.command [ "\"%s\"", "-raise", print thk.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_resize_item = class Menuaction "_Resize" "resize to given width and height" { action x = class _result { _vislevel = 3; filter = Magick.filter_widget; type = Magick.ResizeType_widget; width = Scale "Width" 1 100 10; height = Scale "Height" 1 100 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", filter._flag, "-" ++ type._flag, "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "!") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_roll_item = class Menuaction "_Roll" "roll an image horizontally or vertically" { action x = class _result { _vislevel = 3; rollx = Expression "X" 3; rolly = Expression "Y" 3; command = Magick.command [ "\"%s\"", "-roll", (if rollx.expr >= 0 then "+" else "") ++ print rollx.expr ++ (if rolly.expr >= 0 then "+" else "") ++ print rolly.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotate_item = class Menuaction "_Rotate" "rotate" { action x = class _result { _vislevel = 3; angle = Scale "angle (degrees)" (-360) 360 20; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, "+distort", "SRT", print angle.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -segment, but cluster-threshold should be percentage of image area. Magick_sepia_item = class Menuaction "_Sepia tone" "simulate a sepia-toned photo" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; command = Magick.command [ "\"%s\"", "-sepia-tone", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shade_item = class Menuaction "_Shade" "shade with a distant light source" { action x = class _result { _vislevel = 3; azimuth = Scale "Azimuth (degrees)" (-360) 360 0; elevation = Scale "Elevation (degrees)" 0 90 45; command = Magick.command [ "\"%s\"", "-shade", print azimuth.value ++ "x" ++ print elevation.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_shadow_item = class Menuaction "_Shadow" "simulate a shadow" { action x = class _result { _vislevel = 3; shadowCol = Magick.generalcol_widget; opacity = Scale "Opacity (percent)" 0 100 75; sigma = Scale "Sigma" 0 30 2; // FIXME: make offsets a single widget? offsx = Scale "X-offset" (-20) 20 4; offsy = Scale "Y-offset" (-20) 20 4; arePc = Toggle "offsets are percentages" false; // FIXME: raw operation creates page offset, which vips dislikes. // So we take this futher, compositing with source. command = Magick.command [ "\"%s\"", "\"(\" +clone", "-background", "\"" ++ shadowCol._flag ++ "\"", "-shadow", concat [ "\"", print opacity.value, "x", print sigma.value, (if offsx.value >= 0 then "+" else ""), print offsx.value, (if offsy.value >= 0 then "+" else ""), print offsy.value, (if arePc then "%%" else ""), "\"" ], "\")\" +swap -background None -layers merge", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shave_item = class Menuaction "_Shave" "shave pixels from the edges" { action x = class _result { _vislevel = 3; width = Scale "Width" 0 50 10; height = Scale "Height" 0 50 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", "-shave", "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shear_item = class Menuaction "_Shear" "shear along the x-axis and/or y-axis" { action x = class _result { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-shear", print shearX.expr ++ "x" ++ print shearY.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sigmoid_item = class Menuaction "_Sigmoid" "increase or decrease mid-tone contrast sigmoidally" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; contrast = Scale "contrast" 0 30 3; midpoint = Scale "mid-point (percent)" 0 100 50; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "sigmoidal-contrast", "\"" ++ print contrast.value ++ "x" ++ print midpoint.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_sketch_item = class Menuaction "_Sketch" "simulate a pencil sketch" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; command = Magick.command [ "\"%s\"", "-sketch", print radius.value ++ "x" ++ print sigma.value ++ (if angle >= 0 then ("+" ++ print angle.value) else ""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_solarize_item = class Menuaction "_Solarize" "negate all pixels above a threshold level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-solarize", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -sparse-color needs abitrary list of {x,y,colour}. Magick_splice_item = class Menuaction "_Splice" "splice a colour into the image" { action x = class _result { _vislevel = 3; background = Magick.background_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", background._flag, gravity._flag, "-splice", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_spread_item = class Menuaction "_Spread" "displace pixels by random amount" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; amount = Expression "Amount (pixels)" 5; command = Magick.command [ "\"%s\"", virtpixback._flag, "-spread", print amount.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_statistic_item = class Menuaction "_Statistic" "replace each pixel with statistic from neighbourhood" { action x = class _result { _vislevel = 3; width = Expression "Width" 5; height = Expression "Height" 5; statisticType = Magick.StatType_widget; command = Magick.command [ "\"%s\"", "-statistic", statisticType._flag, print width.expr ++ "x" ++ print height.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = Magick.angle_widget; command = Magick.command [ "\"%s\"", "-swirl", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_thresholdMenu_item = class Menupullright "_Threshold" "make black or white" { Magick_threshold_item = class Menuaction "_Threshold" "apply black/white threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blackThreshold_item = class Menuaction "_Black threshold" "where below threshold set to black" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-black-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_whiteThreshold_item = class Menuaction "_White threshold" "where above threshold set to white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-white-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_latThreshold_item = class Menuaction "_Local Adaptive Threshold" "where above average plus offset set to white, otherwise black" { action x = class _result { _vislevel = 3; width = Expression "Width" 10; height = Expression "Height" 10; offset = Scale "Offset (percent)" (-100) 100 0; // note: "-lat" doesn't respond to channels command = Magick.command [ "\"%s\"", "-lat", concat ["\"", print width.expr, "x", print height.expr, (if offset.value >= 0 then "+" else ""), print offset.value, "%%\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_randThreshold_item = class Menuaction "_Random Threshold" "between specified limits, apply random threshold" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; low = Scale "Low threshold" 0 100 10; high = Scale "High threshold" 0 100 90; isPc = Toggle "Thresholds are percent" true; command = Magick.command [ "\"%s\"", channels._flag, "-random-threshold", "\"" ++ print low.value ++ "x" ++ print high.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } } // end ThresholdMenu_item // Note: alternatives include: // convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif Magick_tile_item = class Menuaction "_Tile" "fill given size with tiled image" { action x = class _result { _vislevel = 3; size = Magick.Size_widget; command = Magick.command [ size._flag, "tile:" ++ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_tint_item = class Menuaction "_Tint" "apply a tint" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; amount = Scale "amount (percent)" 0 100 50; command = Magick.command [ "\"%s\"", foreground._flag, "-tint", // snibgo note: although the amount is a percentage, it doesn't need "%" character. print amount.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_transparent_item = class Menuaction "_Transparent" "make this colour transparent" { action x = class _result { _vislevel = 3; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "transparent", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_trim_item = class Menuaction "_Trim" "trims away border" { action x = class _result { _vislevel = 3; fuzz = Magick.fuzz_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-trim +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_uniqueCols_item = class Menuaction "_Unique colours" "discard all but one of any pixel color" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-unique-colors", "\"%s\"" ]; _result = Magick.system command x; } } Magick_vignette_item = class Menuaction "_Vignette" "soften the edges in vignette style" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; rx = Scale "Rolloff x (percent)" 0 100 10; ry = Scale "Rolloff y (percent)" 0 100 10; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-vignette", print radius.value ++ "x" ++ print sigma.value ++ (if rx.value >= 0 then "+" else "") ++ print rx.value ++ (if ry.value >= 0 then "+" else "") ++ print ry.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_wave_item = class Menuaction "_Wave" "shear the columns into a sine wave" { action x = class _result { _vislevel = 3; amplitude = Scale "Amplitude (pixels)" 0 100 10; wavelength = Scale "Wavelength (pixels)" 0 100 10; command = Magick.command [ "\"%s\"", "-wave", print amplitude.value ++ "x" ++ print wavelength.value, "\"%s\"" ]; _result = Magick.system command x; } } nip2-8.7.1/share/nip2/compat/8.2/Colour.def0000644000175000017500000003773013351443023015017 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } CCT_colour = class Menuaction (_ "Colour from CCT") (_ "pick colour by CCT") { action = widget 6500; widget x = class _result { _vislevel = 3; T = Scale "CCT" 1800 25000 x; _result = colour_from_temp (to_real T); Colour_edit space value = widget (temp_from_colour (Colour space value)); } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } sep1 = Menuseparator; CCT_item = class Menuaction (_ "Calculate temperature") (_ "estimate CCT using the McCamy approximation") { action z = map_unary temp_from_colour z; } Colour_item = Colour_new_item.CCT_colour; } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = print_profile, has_type image && get_type image == Image_type.CMYK && has_bands image && get_bands image >= 4 = monitor_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; measure = Scale (_ "Measure area (%)") 1 100 50; // get a representative image from an arg get_image x = get_image x.value?0, is_Group x = x; _im = get_image x; sample = measure_draw (to_real pacross) (to_real pdown) (to_real measure) _im; _result = map_unary chart x { chart in = measure_sample (to_real pacross) (to_real pdown) (to_real measure) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/8.2/_joe_utilities.def0000644000175000017500000005054513351443023016562 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/8.2/_Object.def0000644000175000017500000002600513351443023015112 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/8.2/Object.def0000644000175000017500000000220513351443023014747 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/8.2/Math.def0000644000175000017500000003162513351443023014442 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_AND" "bitwise AND of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_OR" "bitwise OR of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "_XOR" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_NOT" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Bandand_item = Image_band_item.Bandand_item; Bandor_item = Image_band_item.Bandor_item; } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Skew_item = class Menuaction "S_kew" "skew of image or list or vector" { action a = map_unary skew a; } Kurtosis_item = class Menuaction "Kurtosis" "kurtosis of image or list or vector" { action a = map_unary kurtosis a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/8.2/_generate.def0000644000175000017500000000755513351443023015507 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } mkim options x y b = Image (image_new x y b (opt $format) (opt $coding) (opt $type) (opt $pixel) (opt $xoffset) (opt $yoffset)) { opt = get_option options [ $format => Image_format.UCHAR, $coding => Image_coding.NOCODING, $type => Image_type.sRGB, $pixel => 0, $xoffset => 0, $yoffset => 0 ]; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } /* Make a colour from a temperature. */ colour_from_temp T = error (_ "T out of range"), T < 1667 || T > 25000 = Colour "Yxy" [50, x, y] { // Kim et all approximation // see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation x = -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 + 0.8776956 * 10 ** 3 / T + 0.179910, T < 4000 = -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 + 0.2226347 * 10 ** 3 / T + 0.240390; y = -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + 2.18555832 * x - 0.20219638, T < 2222 = -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867, T < 4000 = 3.0817580 * x ** 3 - 5.87338670 * x ** 2 + 3.75112997 * x - 0.37001483; } temp_from_colour z = T { c = colour_transform_to Image_type.YXY (to_colour z); x = c.value?1; y = c.value?2; // McCamy's approximation, see eg. // http://en.wikipedia.org/wiki/Color_temperature#Approximation xe = 0.332; ye = 0.1858; n = (x - xe) / (y - ye); T = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33; } nip2-8.7.1/share/nip2/compat/8.2/_stdenv.def0000644000175000017500000020121613351443023015206 00000000000000/* optional args to functions */ get_option options defaults f = error (_ "unknown parameter " ++ f), hits == [] = hits?0 { hits = [v :: [n, v] <- options ++ defaults; n == f]; } /* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } bandand x = oo_unary_function bandand_op x, is_class x = foldr1 bitwise_and (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandand") { bandand_op = Operator "bandand" bandand Operator_type.COMPOUND_REWRAP false; } bandor x = oo_unary_function bandor_op x, is_class x = foldr1 bitwise_or (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandor") { bandor_op = Operator "bandor" bandor Operator_type.COMPOUND_REWRAP false; } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } skew x = oo_unary_function skew_op x, is_class x = sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x = sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "skew") { skew_op = Operator "skew" skew Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = w * h * b, is_image x' = len x'; } kurtosis x = oo_unary_function kurtosis_op x, is_class x = sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x = sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "kurtosis") { kurtosis_op = Operator "kurtosis" kurtosis Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = len x', is_list x'; = w * h * b; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_tile_cache_random x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } decode im = oo_unary_function decode_op im, is_class im = decode_im im, is_image im = error (_ "bad arguments to " ++ "decode") { decode_op = Operator "decode" decode Operator_type.COMPOUND_REWRAP false; decode_im im = im_LabQ2Lab im, get_coding im == Image_coding.LABPACK = im_rad2float im, get_coding im == Image_coding.RAD = im; } measure_draw across down measure image = mark { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; x = map (extract 0) cods; y = map (extract 1) cods; outer = mkim [$pixel => 255] sample_width sample_height 1; inner = mkim [] (sample_width - 4) (sample_height - 4) 1; patch = insert 2 2 inner outer; bg = mkim [] image.width image.height 1; mask = Image (im_insertset bg.value patch.value x y); image' = colour_transform_to Image_type.sRGB image; mark = if mask then Vector [0, 255, 0] else image'; } measure_sample across down measure image = measures { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; image' = decode image; patches = map (\p extract_area p?0 p?1 sample_width sample_height image') cods; measures = Matrix (map (map mean) (map bandsplit patches)); } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_inv hist = oo_unary_function hist_inv_op hist, is_class hist = inv hist, is_image hist = error (_ "bad arguments to " ++ "hist_inv") { hist_inv_op = Operator "hist_inv" hist_inv Operator_type.COMPOUND_REWRAP false; inv im = im_invertlut (to_matrix im''') len { // need a vertical doublemask im' = rot90 im, get_width im > 1 && get_height im == 1 = im, get_width im == 1 && get_height im > 1 = error (_ "not a hist"); len = get_height im'; // values must be scaled to 0 - 1 im'' = im' / (max im'); // add an index column on the left // again, must be in 0-1 y = ((make_xy 1 len)?1) / len; im''' = y ++ im''; } } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize interp xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; // is this interpolation nearest-neighbour? is_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor, nearest neighbour // upscale by integer part, then affine to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by any factor, nearest neighbour // downscale by integer part, then affine to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor with affine = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 // downscale by any factor, bilinear // block shrink by integer factor, then resample to // exact with affine = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate_type.descriptions?interp.type ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // resize scale xfac yfac im = im_affinei_all im interp.value xfac 0 0 yfac 0 0; } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C * * Also calculate R2, see eg.: * https://en.wikipedia.org/wiki/Coefficient_of_determination */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } ss = len xes; sx = sum xes; sy = sum yes; my = sy / ss; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; my = sy / len xes; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* One image in, one out. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } /* Two images in, one out. */ system_image2 command x1 x2 = oo_binary_function system_image2_op x1 x2, is_class x1 = oo_binary'_function system_image2_op x1 x2, is_class x2 = system x1 x2, is_image x1 && is_image x2 = error (_ "bad arguments to " ++ "system_image2") { system_image2_op = Operator "system_image2" (system_image2 command) Operator_type.COMPOUND_REWRAP false; system x1 x2 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Three images in, one out. */ system_image3 command x1 x2 x3 = oo_binary_function system_image2_op x2 x3, is_class x2 = oo_binary'_function system_image2_op x2 x3, is_class x3 = system x1 x2 x3, is_image x1 && is_image x2 && is_image x3 = error (_ "bad arguments to " ++ "system_image3") { system_image2_op = Operator "system_image2" (system_image3 command x1) Operator_type.COMPOUND_REWRAP false; system x1 x2 x3 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2, x3], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Zero images in, one out. */ system_image0 command = Image image_out { [image_out] = vips_call "system" [command] [ $out => true, $out_format => "%s.tif" ]; } hough_line w h x = oo_unary_function hough_line_op x, is_class x = hline (to_real w) (to_real h) x, is_image x = error (_ "bad arguments to " ++ "hough_line") { hough_line_op = Operator "hough_line" (hough_line w h) Operator_type.COMPOUND_REWRAP false; hline w h x = pspace { [pspace] = vips_call "hough_line" [x] [ $width => w, $height => h ]; } } hough_circle s mn mx x = oo_unary_function hough_circle_op x, is_class x = hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x = error (_ "bad arguments to " ++ "hough_circle") { hough_circle_op = Operator "hough_circle" (hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false; hcircle s mn mx x = pspace { [pspace] = vips_call "hough_circle" [x] [ $scale => s, $min_radius => mn, $max_radius => mx ]; } } mapim interp ind in = oo_binary_function mapim_op ind in, is_class ind = oo_binary'_function mapim_op ind in, is_class in = mapim_fn ind in, is_image ind && is_image in = error (_ "bad arguments to " ++ "mapim") { mapim_op = Operator "mapim" (mapim interp) Operator_type.COMPOUND_REWRAP false; mapim_fn ind im = out { [out] = vips_call "mapim" [im, ind] [$interpolate => interp]; } } nip2-8.7.1/share/nip2/compat/8.2/Histogram.def0000644000175000017500000001621413351443023015503 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "_Identity" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_inv_item = class Menuaction "In_vert" "invert a histogram" { action x = map_unary hist_inv x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Interpolate_bilinear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; caption = Expression "Chart caption" "none"; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; xcaption = Expression "X axis caption" "none"; ycaption = Expression "Y axis caption" "none"; series_captions = Expression "Series captions" ["Band 0"]; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range ++ captions; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; captions = concat (map test caption_options) ++ [$series_captions => series_captions.expr] { caption_options = [ $caption => caption.expr, $xcaption => xcaption.expr, $ycaption => ycaption.expr ]; test x = [], value == "none" = [option_name => value] { [option_name, value] = x; } } image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/8.2/Widgets.def0000644000175000017500000000235313351443023015153 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/8.2/_types.def0000644000175000017500000006744113351443023015061 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; to_image dpi = extract_bands 0 3 (graph_export_image (to_real dpi) this); } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/8.2/Matrix.def0000644000175000017500000002573113351443023015016 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = identity (identity_matrix 5); identity v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix (identity_matrix (to_real s)), to_real s != len v; = Matrix v; Matrix_vips value scale offset filename display = identity value; } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = series (mkseries 0 1 5); mkseries s t e = transpose [[to_real s, to_real s + to_real t .. to_real e]]; series v = class _result { _vislevel = 3; _s = v?0?0; _t = v?1?0 - v?0?0; _e = (last v)?0; s = Expression "Start value" _s; t = Expression "Step by" _t; e = Expression "End value" _e; _result = Matrix (mkseries s t e), to_real s != _s || to_real t != _t || to_real e != _e = Matrix v; Matrix_vips value scale offset filename display = series value; } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = square (mksquare 5); mksquare s = replicate s (take s [1, 1 ..]); square v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix_con (sum v) 0 v, len v == to_real s = Matrix_con (sum m) 0 m { m = mksquare (to_real s); } Matrix_vips value scale offset filename display = square value; } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = circle (mkcircle 3); mkcircle r = map2 (map2 pyth) xes yes { line = [-r .. r]; xes = replicate (2 * r + 1) line; yes = transpose xes; pyth a b = 1, (a**2 + b**2) ** 0.5 <= r = 0; } circle v = class _result { _vislevel = 3; r = Expression "Radius" ((len v - 1) / 2); _result = Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1 = Matrix_con (sum m) 0 m { m = mkcircle (to_real r); } Matrix_vips value scale offset filename display = circle value; } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/8.2/Tasks.def0000644000175000017500000006411113351443023014632 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; measure = Scale (_ "Measure area (%)") 1 100 50; sample = measure_draw 6 4 (to_real measure) image; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linearize from chart greyscale", "Fit intercept from chart greyscale", "Linear input, set brightness from chart", "Linear input" ] 0; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure_sample 6 4 (to_real measure) image; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix [[0, 0], [1, 1]] { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map an image though the lineariser linear x = hist_map linearising_lut.value x, mode == 0 || mode == 1 = x; // map the chart measurements though the lineariser _camera' = (to_matrix @ linear @ to_image) _camera; // solve for RGB -> XYZ // normalise: the 2nd row is what makes Y, so divide by that to // get Y in 0-1. _pinv = (transpose _camera' * _camera') ** -1; _full_M = transpose (_pinv * (transpose _camera' * _true_XYZ)); M = _full_M / scale; scale = sum _full_M.value?1; // now turn the camera to LAB and calculate dE76 _camera'' = (to_matrix @ colour_transform Image_type.XYZ Image_type.LAB @ recomb M @ multiply scale @ to_image) _camera'; _dEs = map abs_vec (_camera'' - _true_Lab).value; avg_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } // normalise brightness ... in linear mode, we optionally don't // set the brightness from the Macbeth chart norm x = x * scale, mode != 3 = x; // convert RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ norm @ recomb M @ cast_float @ linear) image.value; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ calib.norm @ recomb calib.M @ cast_float @ calib.linear) image.value; } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Interpolate_bilinear xfactor yfactor scale_im; _offset_im = resize Interpolate_bilinear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/8.2/Makefile.am0000644000175000017500000000062113351443023015115 00000000000000startdir = $(pkgdatadir)/compat/8.2 start_DATA = \ Colour.def \ _convert.def \ Filter.def \ _generate.def \ Histogram.def \ Image.def \ _joe_extra.def \ _joe_utilities.def \ _list.def \ _magick.def \ Magick.def \ Math.def \ Matrix.def \ _Object.def \ Object.def \ _predicate.def \ Preferences.ws \ _stdenv.def \ Tasks.def \ _types.def \ Widgets.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/8.2/Makefile.in0000644000175000017500000003714413417043242015142 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/8.2 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/8.2 start_DATA = \ Colour.def \ _convert.def \ Filter.def \ _generate.def \ Histogram.def \ Image.def \ _joe_extra.def \ _joe_utilities.def \ _list.def \ _magick.def \ Magick.def \ Math.def \ Matrix.def \ _Object.def \ Object.def \ _predicate.def \ Preferences.ws \ _stdenv.def \ Tasks.def \ _types.def \ Widgets.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/8.2/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/8.2/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/8.2/_magick.def0000644000175000017500000005416213351443023015144 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate _magick.def Add 0-ary and 2-ary system Put utility funcs into a Magick class 11-Apr-2014 snibgo Added VirtualPixelBack for cases where background is only relevant when VP=Background 17-Apr-2014 snibgo Many small changes. 2-May-2014 jcupitt Added Magick.version 30-June-2014 Put single-quotes around command exe to help win 1-July-2014 Automatically fall back to gm if we can't find convert 17-July-2014 better GM support Last update: 17-July-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ /* Put these in a class to avoid filling the main namespace with IM stuff. */ Magick = class { // turn $PATH into [["comp1", "comp2"], ["comp1", "comp2"] ..] system_search_path = map path_parse (split (equal path_sep) (expand "$PATH")) { path_sep = ':', expand "$SEP" == "/" = ';'; } // the first name[.exe] on $PATH, or "" search_for name = hits?0, hits != [] = "" { exe_name = name ++ expand "$EXEEXT"; form_path p = path_absolute (p ++ [exe_name]); paths = map form_path system_search_path; hits = dropwhile (equal []) (map search paths); } // first gm on path, or "" gm_path = search_for "gm"; // first convert on $PATH, or "" // we check for the convert we ship first convert_path = vips_convert, vips_convert != "" = search_for "convert" { // the convert we ship with the vips binary on some platforms, or "" vips_convert = search (path_absolute convert) { vipshome = path_parse (expand "$VIPSHOME"); convert = vipshome ++ ["bin", "convert" ++ expand "$EXEEXT"]; } } use_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK; // Are we in GM or IM mode? use_gm = true, use_gm_pref && gm_path != "" = false, !use_gm_pref && convert_path != "" = false, convert_path != "" = true, gm_path != "" = error "neither IM nor GM executable found"; command_path = gm_path, use_gm = convert_path; // try to get the version as eg. [6, 7, 7, 10] // GM versions are smaller, typically [1, 3, 18] version = map parse_int (split (member ".-") version_string) { [output] = vips_call "system" ["'" ++ command_path ++ "' -version"] [$log=>true]; version_string = (split (equal ' ') output)?1, use_gm = (split (equal ' ') output)?2; } // make a command-line ... args is a [str] we join with spaces command args = "'" ++ command_path ++ "' " ++ join_sep " " args' { args' = ["convert"] ++ args, use_gm = args; } // capabilities ... different versions support different features, we // turn features on and off based on these // would probably be better to test for caps somehow has_intensity = false, use_gm = version?0 > 6 || version?1 > 7; has_channel = false, use_gm = version?0 > 6 || version?1 > 7; system0 cmd = system_image0 cmd; system cmd x = map_unary (system_image cmd) x; system2 cmd x y = map_binary (system_image2 cmd) x y; system3 cmd x y z = map_trinary (system_image3 cmd) x y z; radius_widget = Scale "Radius" 0 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle (degrees)" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; gamma_widget = Scale "Gamma" 0 10 1; colors_widget = Scale "Colors" 1 10 3; resize_widget = Scale "Resize (percent)" 0 500 100; fuzz_widget = Scale "Fuzz (percent)" 0 100 0; blur_rad_widget = Scale "Radius (0=auto)" 0 100 0; // a colour with no enclosing quotes ... use this if we know there are // some quotes at an outer level print_colour_nq triple = concat ["#", concat (map fmt triple)] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } // we need the quotes because # is the comment character in *nix print_colour triple = "\"" ++ print_colour_nq triple ++ "\""; Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; GeneralCol triple = class Colour "sRGB" triple { _flag = print_colour_nq triple; Colour_edit space triple = this.GeneralCol triple; } generalcol_widget = GeneralCol [0, 0, 0]; Background triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" false; _flag = "-background " ++ if isNone then "None" else print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Bordercol triple = class Colour "sRGB" triple { _flag = "-bordercolor " ++ print_colour triple; Colour_edit space triple = this.Bordercol triple; } bordercol_widget = Bordercol [0, 0, 0]; Mattecol triple = class Colour "sRGB" triple { _flag = "-mattecolor " ++ print_colour triple; Colour_edit space triple = this.Mattecol triple; } mattecol_widget = Mattecol [189, 189, 189]; // FIXME: Undercolour, like many others, can have alpha channel. // How does user input this? With a slider? Undercol triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" true; _flag = if isNone then "" else ("-undercolor " ++ print_colour triple); Colour_edit space triple = this.Undercol triple; } undercol_widget = Undercol [0, 0, 0]; changeCol_widget = class { _vislevel = 3; colour = GeneralCol [0, 0, 0]; fuzz = fuzz_widget; nonMatch = Toggle "change non-matching colours" false; } Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Remove", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Builtin builtin = class Option_string "Builtin" [ // See http://www.imagemagick.org/script/formats.php "rose:", "logo:", "wizard:", "granite:", "netscape:" ] builtin { _flag = builtin; Option_edit caption labels value = this.Builtin labels?value; } builtin_widget = Builtin "rose:"; channels_widget = class { // FIXME? Can we grey-out alpha when we have no alpha channel, // show CMY(K) instead of RGB(K) etc? // Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA. ChanR valueR = class Toggle "Red" valueR { _flag = "R", valueR = ""; Toggle_edit caption valueR = this.ChanR valueR; } channelR = ChanR true; ChanG valueG = class Toggle "Green" valueG { _flag = "G", valueG = ""; Toggle_edit caption valueG = this.ChanG valueG; } channelG = ChanG true; ChanB valueB = class Toggle "Blue" valueB { _flag = "B", valueB = ""; Toggle_edit caption valueB = this.ChanB valueB; } channelB = ChanB true; ChanK valueK = class Toggle "Black" valueK { _flag = "K", valueK = ""; Toggle_edit caption valueK = this.ChanK valueK; } channelK = ChanK true; ChanA valueA = class Toggle "Alpha" valueA { _flag = "A", valueA = ""; Toggle_edit caption valueA = this.ChanA valueA; } channelA = ChanA false; ChanSy valueSy = class Toggle "Sync" valueSy { _flag = ",sync", valueSy = ""; Toggle_edit caption valueSy = this.ChanSy valueSy; } channelSy = ChanSy true; _rgbka = concat [channelR._flag, channelG._flag, channelB._flag, channelK._flag, channelA._flag ]; _flag = "", _rgbka == "" || !has_channel = concat [ "-channel ", _rgbka, channelSy._flag ]; } ch_widget = channels_widget; Colorspace colsp = class Option_string "Colorspace" [ "CIELab", "CMY", "CMYK", "Gray", "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "Lab", "LCH", "LCHab", "LCHuv", "LMS", "Log", "Luv", "OHTA", "Rec601Luma", "Rec601YCbCr", "Rec709Luma", "Rec709YCbCr", "RGB", "scRGB", "sRGB", "Transparent", "XYZ", "YCbCr", "YDbDr", "YCC", "YIQ", "YPbPr", "YUV" ] colsp { _flag = colsp; Option_edit caption labels value = this.Colorspace labels?value; } colorspace_widget = Colorspace "sRGB"; Compose comp = class Option_string "Compose method" [ "Atop", "Blend", "Blur", "Bumpmap", "ChangeMask", "Clear", "ColorBurn", "ColorDodge", "Colorize", "CopyBlack", "CopyBlue", "CopyCyan", "CopyGreen", "Copy", "CopyMagenta", "CopyOpacity", "CopyRed", "CopyYellow", "Darken", "DarkenIntensity", "DivideDst", "DivideSrc", "Dst", "Difference", "Displace", "Dissolve", "Distort", "DstAtop", "DstIn", "DstOut", "DstOver", "Exclusion", "HardLight", "Hue", "In", "Lighten", "LightenIntensity", "LinearBurn", "LinearDodge", "LinearLight", "Luminize", "Mathematics", "MinusDst", "MinusSrc", "Modulate", "ModulusAdd", "ModulusSubtract", "Multiply", "None", "Out", "Overlay", "Over", "PegtopLight", "PinLight", "Plus", "Replace", "Saturate", "Screen", "SoftLight", "Src", "SrcAtop", "SrcIn", "SrcOut", "SrcOver", "VividLight", "Xor" ] comp { _flag = "-compose " ++ comp; Option_edit caption labels value = this.Compose labels?value; } compose_widget = Compose "Over"; // FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string. // FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack coordinate_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; _flag = concat [print x.expr, ",", print y.expr]; }; Distort distort = class Option_string "Distort" [ "Affine", "AffineProjection", "ScaleRotateTranslate", "SRT", "Perspective", "PerspectiveProjection", "BilinearForward", "BilinearReverse", "Polynomial", "Arc", "Polar", "DePolar", "Barrel", "BarrelInverse", "Shepards", "Resize" ] distort { _flag = distort; Option_edit caption labels value = this.Distort labels?value; } distort_widget = Distort "SRT"; Dither dither = class Option_string "Dither" [ "None", "FloydSteinberg", "Riemersma" ] dither { _flag = "-dither " ++ dither; Option_edit caption labels value = this.Dither labels?value; } dither_widget = Dither "FloydSteinberg"; Evaluate eval = class Option_string "Evaluate operation" [ "Abs", "Add", "AddModulus", "And", "Cos", "Cosine", "Divide", "Exp", "Exponential", "GaussianNoise", "ImpulseNoise", "LaplacianNoise", "LeftShift", "Log", "Max", "Mean", "Median", "Min", "MultiplicativeNoise", "Multiply", "Or", "PoissonNoise", "Pow", "RightShift", "Set", "Sin", "Sine", "Subtract", "Sum", "Threshold", "ThresholdBlack", "ThresholdWhite", "UniformNoise", "Xor" ] eval { _flag = "-evaluate " ++ eval; Option_edit caption labels value = this.Evaluate labels?value; } evaluate_widget = Evaluate "Add"; Filter filt = class Option_string "Filter" [ "default", "Bartlett", "Blackman", "Bohman", "Box", "Catrom", "Cosine", "Cubic", "Gaussian", "Hamming", "Hann", "Hermite", "Jinc", "Kaiser", "Lagrange", "Lanczos", "Lanczos2", "Lanczos2Sharp", "LanczosRadius", "LanczosSharp", "Mitchell", "Parzen", "Point", "Quadratic", "Robidoux", "RobidouxSharp", "Sinc", "SincFast", "Spline", "Triangle", "Welch" ] filt { _flag = if filt == "default" then "" else "-filter " ++ filt; Option_edit caption labels value = this.Filter labels?value; } filter_widget = Filter "default"; Function func = class Option_string "Function" [ "Polynomial", "Sinusoid", "Arcsin", "Arctan" ] func { _flag = func; Option_edit caption labels value = this.Function labels?value; } function_widget = Function "Polynomial"; // "Polynomial (a[n], a[n-1], ... a[1], a[0])", // "Sinusoid (freq, phase, amp, bias)", // "Arcsin (width, centre, range, bias)", // "Arctan (slope, centre, range, bias)" Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; ImageType imagetype = class Option_string "Image type" [ "Bilevel", "ColorSeparation", "ColorSeparationAlpha", "ColorSeparationMatte", "Grayscale", "GrayscaleAlpha", "GrayscaleMatte", "Optimize", "Palette", "PaletteBilevelAlpha", "PaletteBilevelMatte", "PaletteAlpha", "PaletteMatte", "TrueColorAlpha", "TrueColorMatte", "TrueColor" ] imagetype { _flag = "-type " ++ imagetype; Option_edit caption labels value = this.ImageType labels?value; } imagetype_widget = ImageType "TrueColor"; Intensity intensity = class Option_string "Intensity (gray conversion)" [ "Average", "Brightness", "Lightness", "MS", "Rec601Luma", "Rec601Luminance", "Rec709Luma", "Rec709Luminance", "RMS" ] intensity { _flag = "-intensity " ++ intensity, has_intensity = ""; Option_edit caption labels value = this.Intensity labels?value; } intensity_widget = Intensity "Rec709Luminance"; Interpolate interp = class Option_string "Interpolate" [ "default", "Average", "Average4", "Average9", "Average16", "Background", "Bilinear", "Blend", "Integer", "Mesh", "Nearest", "NearestNeighbor", "Spline" ] interp { _flag = if interp == "default" then "" else "-interpolate " ++ interp; Option_edit caption labels value = this.Interpolate labels?value; } interpolate_widget = Interpolate "default"; Kernel kernel = class Option_string "Kernel" [ "Unity", "Gaussian", "DoG", "LoG", "Blur", "Comet", "Binomial", "Laplacian", "Sobel", "FreiChen", "Roberts", "Prewitt", "Compass", "Kirsch", "Diamond", "Square", "Rectangle", "Disk", "Octagon", "Plus", "Cross", "Ring", "Peaks", "Edges", "Corners", "Diagonals", "LineEnds", "LineJunctions", "Ridges", "ConvexHull", "ThinSe", "Skeleton", "Chebyshev", "Manhattan", "Octagonal", "Euclidean" // FIXME: custom kernel ] kernel { _flag = kernel; Option_edit caption labels value = this.Kernel labels?value; } kernel_widget = Kernel "Unity"; ModColSp msp = class Option_string "modulate colorspace" [ "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "LCH" ] msp { _flag = "-set option:modulate:colorspace " ++ msp; Option_edit caption labels value = this.ModColSp labels?value; } ModColSp_widget = ModColSp "HSL"; MorphMeth morph = class Option_string "Method" [ "Correlate", "Convolve", "Dilate", "Erode", "Close", "Open", "DilateIntensity", "ErodeIntensity", "CloseIntensity", "OpenIntensity", "Smooth", "EdgeOut", "EdgeIn", "Edge", "TopHat", "BottomHat", "HitAndMiss", "Thinning", "Thicken", "Distance", "IterativeDistance" ] morph { _flag = morph; Option_edit caption labels value = this.MorphMeth labels?value; } morphmeth_widget = MorphMeth "Dilate"; Noise noise = class Option_string "Noise" [ "Gaussian", "Impulse", "Laplacian", "Multiplicative", "Poisson", "Random", "Uniform" ] noise { _flag = "+noise " ++ noise; Option_edit caption labels value = this.Noise labels?value; } noise_widget = Noise "Gaussian"; Pattern pattern = class Option_string "Noise" [ // See http://www.imagemagick.org/script/formats.php "bricks", "checkerboard", "circles", "crosshatch", "crosshatch30", "crosshatch45", "gray0", "gray5", "gray10", "gray15", "gray20", "gray25", "gray30", "gray35", "gray40", "gray45", "gray50", "gray55", "gray60", "gray65", "gray70", "gray75", "gray80", "gray85", "gray90", "gray95", "gray100", "hexagons", "horizontal", "horizontal2", "horizontal3", "horizontalsaw", "hs_bdiagonal", "hs_cross", "hs_diagcross", "hs_fdiagonal", "hs_horizontal", "hs_vertical", "left30", "left45", "leftshingle", "octagons", "right30", "right45", "rightshingle", "smallfishscales", "vertical", "vertical2", "vertical3", "verticalbricks", "verticalleftshingle", "verticalrightshingle", "verticalsaw" ] pattern { _flag = "pattern:" ++ pattern; Option_edit caption labels value = this.Pattern labels?value; } pattern_widget = Pattern "bricks"; ResizeType resizet = class Option_string "Resize type" [ "resize", "scale", "sample", "adaptive-resize" ] resizet { _flag = resizet; Option_edit caption labels value = this.ResizeType labels?value; } ResizeType_widget = ResizeType "resize"; Size_widget = class { _vislevel = 3; width = Expression "Width (pixels)" 64; height = Expression "Height (pixels)" 64; _flag = "-size " ++ print width.expr ++ "x" ++ print height.expr; }; StatType statt = class Option_string "Statistic type" [ "Gradient", "Maximum", "Mean", "Median", "Minimum", "Mode", "Nonpeak", "StandardDeviation" ] statt { _flag = statt; Option_edit caption labels value = this.StatType labels?value; } StatType_widget = StatType "Mean"; VirtualPixel vp = class Option_string "Virtual pixel" [ "Background", "Black", "CheckerTile", "Dither", "Edge", "Gray", "HorizontalTile", "HorizontalTileEdge", "Mirror", "None", "Random", "Tile", "Transparent", "VerticalTile", "VerticalTileEdge", "White" ] vp { _flag = "-virtual-pixel " ++ vp; _isBackground = (vp == "Background"); Option_edit caption labels value = this.VirtualPixel labels?value; } VirtualPixel_widget = VirtualPixel "Edge"; VirtualPixelBack_widget = class { virtpix = Magick.VirtualPixel_widget; background = Magick.background_widget; _flag = (if virtpix._isBackground then (background._flag ++ " ") else "") ++ virtpix._flag; } Geometry_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; AnnotGeometry_widget = class { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print shearX.expr, "x", print shearY.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; OffsetGeometry_widget = class { _vislevel = 3; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; WhxyGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; FrameGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; outbev = Expression "Outer bevel thickness" 0; inbev = Expression "Inner bevel thickness" 0; _flag = concat [print x.expr, "x", print y.expr, format outbev, format inbev] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } } nip2-8.7.1/share/nip2/compat/8.2/_predicate.def0000644000175000017500000003252613351443023015651 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Plot x = is_instanceof "Plot" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = oo_unary_function get_type_op x, is_class x = error (_ "bad arguments to " ++ "get_type") { get_type_op = Operator "get_type" get_type Operator_type.COMPOUND false; // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = oo_unary_function get_format_op x, is_class x = error (_ "bad arguments to " ++ "get_format") { get_format_op = Operator "get_format" get_format Operator_type.COMPOUND false; } has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = oo_unary_function get_bits_op x, is_class x = error (_ "bad arguments to " ++ "get_bits") { get_bits_op = Operator "get_bits" get_format Operator_type.COMPOUND false; } has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = oo_unary_function get_bands_op x, is_class x = error (_ "bad arguments to " ++ "get_bands") { get_bands_op = Operator "get_bands" get_bands Operator_type.COMPOUND false; } has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = oo_unary_function get_coding_op x, is_class x = error (_ "bad arguments to " ++ "get_coding") { get_coding_op = Operator "get_coding" get_coding Operator_type.COMPOUND false; } has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = oo_unary_function get_xres_op x, is_class x = error (_ "bad arguments to " ++ "get_xres") { get_xres_op = Operator "get_xres" get_xres Operator_type.COMPOUND false; } has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = oo_unary_function get_yres_op x, is_class x = error (_ "bad arguments to " ++ "get_yres") { get_yres_op = Operator "get_yres" get_yres Operator_type.COMPOUND false; } has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = oo_unary_function get_xoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_xoffset") { get_xoffset_op = Operator "get_xoffset" get_xoffset Operator_type.COMPOUND false; } has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = oo_unary_function get_yoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_yoffset") { get_yoffset_op = Operator "get_yoffset" get_yoffset Operator_type.COMPOUND false; } has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = oo_unary_function get_image_op x, is_class x = error (_ "bad arguments to " ++ "get_image") { get_image_op = Operator "get_image" get_image Operator_type.COMPOUND false; } has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = oo_unary_function get_number_op x, is_class x = error (_ "bad arguments to " ++ "get_number") { get_number_op = Operator "get_number" get_number Operator_type.COMPOUND false; } has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = oo_unary_function get_real_op x, is_class x = error (_ "bad arguments to " ++ "get_real") { get_real_op = Operator "get_real" get_real Operator_type.COMPOUND false; } has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = oo_unary_function get_width_op x, is_class x = error (_ "bad arguments to " ++ "get_width") { get_width_op = Operator "get_width" get_width Operator_type.COMPOUND false; } has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = oo_unary_function get_height_op x, is_class x = error (_ "bad arguments to " ++ "get_height") { get_height_op = Operator "get_height" get_height Operator_type.COMPOUND false; } has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = oo_unary_function get_left_op x, is_class x = error (_ "bad arguments to " ++ "get_left") { get_left_op = Operator "get_left" get_left Operator_type.COMPOUND false; } has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = oo_unary_function get_top_op x, is_class x = error (_ "bad arguments to " ++ "get_top") { get_top_op = Operator "get_top" get_top Operator_type.COMPOUND false; } // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/8.2/_list.def0000644000175000017500000002310313351443023014653 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* flatten x: flatten a list of lists of things into a simple list * * flatten :: [[*]] -> [*] */ flatten x = foldr flat [] x, is_list x = x { flat x sofar = foldr flat sofar x, is_list x = x : sofar; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st x) xs { x:xs = l; } /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn x xs { x:xs = l; } /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn x (foldr fn st xs) { x:xs = l; } /* foldr1 fn l: like foldr, but use the last element as the start value * * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = x, xs == [] = fn x (foldr1 fn xs) { x:xs = l; } /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn x = search xs (n + 1) { x:xs = l; } } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = x : init xs { x:xs = l; } /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = x, xs == [] = last xs { x:xs = l; } /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scanl fn st l: apply (foldl fn r) to every initial segment of a list * * scanl add 0 [1,2,3] == [1,3,6] * scanl :: (* -> ** -> *) -> * -> [**] -> [*] */ scanl fn st l = st, l == [] = st' : scanl fn st' xs { x:xs = l; st' = fn st x; } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/7.14/0000755000175000017500000000000013417043452013231 500000000000000nip2-8.7.1/share/nip2/compat/7.14/Image.def0000644000175000017500000012223213351443023014650 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum Image_type.type_names "Image type" "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum field_names (_ "Field") name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum Image_type.type_names "Image type" (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process in = [ in, rot90 in, rot180 in, rot270 in ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; _result = map_unary process x { process image = rotate angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = map_unary straighten x { straighten arrow = rotate angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { _interp = Option_enum Interpolate.names "Interpolation" "Bilinear"; Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = _interp; _result = map_unary process x { process image = resize xfactor yfactor interp.value_thing image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; interp = _interp; _result = map_unary process x { process image = resize fac fac interp.value_thing image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = max_pair xfac yfac; min_factor = min_pair xfac yfac; fac = [max_factor, min_factor, xfac, yfac]?which; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" (map (extract 0) Interpolate.names.value) Interpolate.BILINEAR; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldr1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = class _result { _vislevel = 3; // try to find the image geometry ... don't bother trying to look // inside groups though _geo = x.rect, is_Image x = Rect 0 0 100 100; l = Expression "Crop left" ((int) (_geo.left + _geo.width / 4)); t = Expression "Crop top" ((int) (_geo.top + _geo.height / 4)); w = Expression "Crop width" (max_pair 1 ((int) (_geo.width / 2))); h = Expression "Crop height" (max_pair 1 ((int) (_geo.height / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 2; ssize = Expression "Step size" 2; _result = Image (colour_transform_to (get_type start) im) { base = colour_transform_to Image_type.LAB start; step = to_real ssize; offset = to_real nstep * step; range c = [c - offset, c - offset + step ... c + offset]; mk_patch b a = image_new 150 150 3 Image_format.FLOAT Image_coding.NOCODING Image_type.LAB (Vector [base?0, a, b]) 0 0; mk_strip b = map (mk_patch b) (range base?1); mk_grid = map mk_strip (range base?2); im = imagearray_assemble 15 15 mk_grid; } } } } nip2-8.7.1/share/nip2/compat/7.14/_convert.def0000644000175000017500000004320213351443023015444 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The innermost list objects become Group()'d. */ to_group x = Group x, is_list x && !contains_Group x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = (ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, im_8216 @ im_mono2sRGB], [B_W, GREY16, im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, im_8216], [RGB, GREY16, im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, im_8216], [sRGB, GREY16, im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* Given a list of things, try to make them all the same size. Don't change * the format. Don't touch non-image things. */ size_alike l = map enlarge l { max_width = foldr (test_prop has_width get_width) 0 l; max_height = foldr (test_prop has_height get_height) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); enlarge x = embed 0 0 0 max_width max_height x, has_width x = x; } /* Given a list of things, look for 1 band objects and bump them to to n - * band objects, where n is the maximum number of bands. Don't change the * format. Don't touch non-image things. */ bands_alike l = map upband l { max_bands = foldr (test_prop has_bands get_bands) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); upband x = bandjoin (replicate max_bands x), has_bands x && get_bands x == 1 = x; } /* Given a list of things, try to match the formats. Don't touch non-image * objects. */ formats_alike l = map upformat l { max_format = foldr (test_prop has_format get_format) Image_format.UCHAR l; test_prop has get x best = best, !has x = max_pair best (get x); upformat x = clip2fmt max_format x, has_format x = x; } /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = foldl1 fn l { fn a b = a ++ path_separator ++ b; } /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 == 2 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/7.14/Filter.def0000644000175000017500000011416213351443023015056 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 1.5; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 50; fs = Scale "Sharpen flat areas by" (-2) 5 1; js = Scale "Sharpen jaggy areas by" (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_convf, !separable && type == 1 = im_convsepf, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 5) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height + 1) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_greyc_item = class Menupullright "_GREYCstoration" "noise-removing filter" { Denoise_item = class Menuaction "Denoise" "Noise-removing filter" { action x = class _result { _vislevel = 3; iterations = Scale "Iterations" 1 5 1; amplitude = Scale "Amplitude" 1 100 40; sharpness = Scale "Sharpness" 0 3 0.9; anisotropy = Scale "Anisotropy" 0 1 0.15; alpha = Scale "Noise scale" 0 5 0.6; sigma = Scale "Geometry regularity" 0 2 1.1; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) x; } } Enlarge_item = class Menuaction "Enlarge" "Enlarge image" { action x = class _result { _vislevel = 3; scale = Scale "Enlarge" 1 10 3; iterations = Scale "Iterations" 1 5 3; amplitude = Scale "Amplitude" 1 100 20; sharpness = Scale "Sharpness" 0 3 0.2; anisotropy = Scale "Anisotropy" 0 1 0.9; alpha = Scale "Noise scale" 0 5 0.1; sigma = Scale "Geometry regularity" 0 2 1.5; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) (resize (to_real scale) (to_real scale) Interpolate.BILINEAR x); } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ [_ "Normal", NORMAL], [_ "If Lighter", IFLIGHTER], [_ "If Darker", IFDARKER], [_ "Multiply", MULTIPLY], [_ "Add", ADD], [_ "Subtract", SUBTRACT], [_ "Screen", SCREEN], [_ "Burn", BURN], [_ "Soft Light", SOFTLIGHT], [_ "Hard Light", HARDLIGHT], [_ "Lighten", LIGHTEN], [_ "Darken", DARKEN], [_ "Dodge", DODGE], [_ "Reflect", REFLECT], [_ "Freeze", FREEZE], [_ "Bitwise OR", OR], [_ "Bitwise AND", AND] ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum names "Blend mode" "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } Filter_draw_line_item = class Menuaction "Draw _Line" "draw a line using an arrow as a guide" { } nip2-8.7.1/share/nip2/compat/7.14/_joe_extra.def0000644000175000017500000003260713351443023015753 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height that * is extracted to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount color" false; ls = Expression "Lower mount section bigger by (cm)" 0; colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 6; control_selection mask im no = (if mask then im * 1.2 else im * 1), no == 0 = (if mask then im * 0.8 else im * 1), no == 1 = (if mask then 0 else im), no == 2 = (if mask then 255 else im), no == 3 = (if mask then im else 0), no == 4 = (if mask then im else 255), no == 5 = mask; Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = a.image; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = ((pt_list.value)?0).image; } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize f1 1 1 b1 {b1 = resize 1 f2 1 b;} } } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.14/Preferences.ws0000644000175000017500000007763413351443023016001 00000000000000 nip2-8.7.1/share/nip2/compat/7.14/Colour.def0000644000175000017500000003531513351443023015076 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Convert to") (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Tag as") (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Colour Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum Whitepoints (_ "Old whitepoint") "D65"; new_white = Option_enum Whitepoints (_ "New whitepoint") "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum Render_intent.names (_ "Render intent") (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; _result = map_unary chart x { chart in = measure 0 0 in.width in.height (to_real pacross) (to_real pdown) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.14/_joe_utilities.def0000644000175000017500000004705113351443023016642 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} } ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; } ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); } ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = line.image; //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = (pt_l?0).image; im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; } ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; } nip2-8.7.1/share/nip2/compat/7.14/_Object.def0000644000175000017500000002635413351443023015203 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0, 1, 2 or 3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, "colour_space"]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide or VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down a bit. */ check_args x = error message, badargs != [] || badalls != [] = check_args x.super, x.super != [] = x { argcheck = x._check_args; allcheck = x._check_all; // join two strings up with a separator string join_sep j a b = a ++ j ++ b; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad arguments to " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "usage" ++ "\n" ++ indent ++ usage ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make usage note usage = x.name ++ " " ++ foldr (join_sep " ") [] (map (extract 1) argcheck); // make arg type notes arg_types = foldr (join_sep "\n") [] (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = foldr (join_sep "\n") [] all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/7.14/Object.def0000644000175000017500000000222013351443023015026 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list (or group) of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/7.14/Math.def0000644000175000017500000003044013351443023014516 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_And" "bitwise and of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_Or" "bitwise or of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "E_xclusive Or" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_Not" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Band_or_item = class Menuaction "Band O_r" "or the bands of an image together" { action im = map_unary (foldr1 bitwise_or @ bandsplit) im; } Band_and_item = class Menuaction "Band A_nd" "and the bands of an image together" { action im = map_unary (foldr1 bitwise_and @ bandsplit) im; } } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.14/_generate.def0000644000175000017500000000514013351443023015555 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black (to_real w) (to_real h) (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = Matrix_con mask_g_sum 0 [mask_g_line] { mask_g = im_gauss_imask (radius / 3) 0.2; mask_g_line = mask_g.value?(mask_g.height / 2); mask_g_sum = sum mask_g_line; } /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } nip2-8.7.1/share/nip2/compat/7.14/_stdenv.def0000644000175000017500000014344513351443023015301 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error "unimplemented vector operation" { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_cache x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend") { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = x, is_image x = x.value, is_Image x = black + x { black = im_black target_width target_height target_bands; } [then_image, else_image] = map (clip2fmt target_format @ to_image) [then_part, else_part]; [c, t, e] = size_alike [cond, then_image, else_image]; blend_result_image = image_set_type target_type (im_blend c t e); } } insert x y small big = oo_binary_function insert_op small big, is_class small = oo_binary'_function insert_op small big, is_class big = im_insert big' small' (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; [small', big'] = bands_alike [small, big]; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big' small' (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; [small', big'] = bands_alike [small, big]; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (_ "bad arguments to " ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_similarity image (cos angle) (sin angle) 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" rotate Operator_type.COMPOUND_REWRAP false; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join a b { join_lr_op = Operator "join_lr" join Operator_type.COMPOUND_REWRAP false; join a b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr"); join_im a b = insert (get_width b) 0 a b; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join a b { join_tb_op = Operator "join_tb" join Operator_type.COMPOUND_REWRAP false; join a b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb"); join_im a b = insert 0 (get_height b) a b; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { image = (unsigned char) im_mask2vips (Matrix m2); m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsepf image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx x = oo_unary_function greyc_op x, is_class x = greyc_im x, is_image x = error (_ "bad argument" ++ " (" ++ print x ++ ") to " ++ "greyc") { greyc_op = Operator "greyc" (greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im x = im_greyc x iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx mask x = oo_binary_function greyc_mask_op mask x, is_class mask = oo_binary'_function greyc_mask_op mask x, is_class x = greyc_im mask x, is_image mask && is_image x = error (_ "bad arguments" ++ " (" ++ print mask ++ ", " ++ print x ++ ") " ++ "to " ++ "greyc") { greyc_mask_op = Operator "greyc_mask" (greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im mask x = im_greyc_mask x mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize xfac yfac interp image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // upscale by any factor, nearest neighbour // can't really do this right ... upscale by integer part, then // bilinear to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // downscale by any factor, nearest neighbour // can't really do this right ... downscale by integer part, // then bilinear to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // upscale by any factor, bilinear = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 && interp == Interpolate.BILINEAR // downscale by any factor, bilinear // block shrink by integer factor, then bilinear resample to // exact = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.BILINEAR = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate.names.lookup 1 0 interp ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // binlinear resize scale xfac yfac im = im_affine im xfac 0 0 yfac 0 0 0 0 (rint (get_width im * xfac)) (rint (get_height im * yfac)); } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } flood_blob x y v image = oo_unary_function flood_blob_op image, is_class image = im_flood_blob_copy image (to_real x) (to_real y) v, is_image image = error (_ "bad arguments to " ++ "flood_blob") { flood_blob_op = Operator "flood_blob" (flood_blob x y v) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = [], any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == []; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Image (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; } ss = len xes; sx = sum xes; sy = sum yes; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } nip2-8.7.1/share/nip2/compat/7.14/Histogram.def0000644000175000017500000001752213351443023015570 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "Histogram" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type field to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } } Hist_map_item = class Menuaction "_Map Histogram" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Cumulativise Histogram" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate Histogram" "find point-to-point differences (inverse of Cumulativise)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise Histogram" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_match_item = class Menuaction "Ma_tch Histogram" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); // extract that area area = extract_area (re p' + displace.value) (im p' - width.value / 2 + vdisplace.value) (re pv) width.value im'; // squish vertically to get an average area' = resize 1 (1 / width.value) Interpolate.BILINEAR area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = area { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); // extract that area area = extract_area (re p' + displace.value) (im p' - width.value / 2 + vdisplace.value) (re pv) width.value im'; } } } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; format = Option_enum Plot_format.names "Format" "YYYY"; style = Option_enum Plot_style.names "Style" "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; image x = image (extract_arrow x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } extract_arrow arrow = extract_area (re p') (im p') (re pv) 1 im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } } } } nip2-8.7.1/share/nip2/compat/7.14/Widgets.def0000644000175000017500000000235313351443023015235 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/7.14/_types.def0000644000175000017500000006675713351443023015154 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] { // need ite as a true trinary ite a b c = if a then b else c; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = [], any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == []; } } map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } oo_unary_table op = [ [map_unary op.fn this, true] ] { // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = [], any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == []; } } map_unary fn a = map_nary (list_1ary fn) [a]; } } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ]; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ]; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ]; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ]; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.value_name colour.expr { _vislevel = 3; space = Option_enum Image_type.colour_spaces "Colour space" default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } Option_enum enum caption value_name = class Option caption enum.names (index (equal value_name) enum.names) { // corresponding thing value_thing = enum.get_thing value_name; Option_edit caption labels value = this.Option_enum enum caption (enum.names ? value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* present col x: is there an x in column col */ present col x = member (map (extract col) value) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (map (extract from) value); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = map (extract 0) value; things = map (extract 1) value; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; LUMINANCE = 2; XRAY = 3; IR = 4; YUV = 5; RED_ONLY = 6; GREEN_ONLY = 7; BLUE_ONLY = 8; POWER_SPECTRUM = 9; HISTOGRAM = 10; LUT = 11; XYZ = 12; LAB = 13; CMC = 14; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $LUMINANCE => LUMINANCE, $XRAY => XRAY, $IR => IR, $YUV => YUV, $RED_ONLY => RED_ONLY, $GREEN_ONLY => GREEN_ONLY, $BLUE_ONLY => BLUE_ONLY, $POWER_SPECTRUM => POWER_SPECTRUM, $HISTOGRAM => HISTOGRAM, $LUT => LUT, $XYZ => XYZ, $LAB => LAB, $CMC => CMC, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16 ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], // image ++ image is slightly different ... we want to // sizealike, but we must not bandalike [wrap (op.fn (get_image resized?0) (get_image resized?1)), has_image x && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], // arithmetic and reational binops between image resize // and band_alike images to match [wrap (op.fn (get_image rebanded?0) (get_image rebanded?1)), has_image x && (op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL)], // other op types don't resize [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. "Image v == // 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = []; to_image x = x, is_image x = x.value, is_Image x = clip2fmt target_format im, target_format != [] = im { im = im_black width height target_bands + x; } [if_size, then_size, else_size] = size_alike (value : formats_alike (map to_image x)); ite_result_image = image_set_type target_type (if if_size then then_size else else_size); resized = size_alike [this, x]; rebanded = bands_alike resized; } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; /* Table to map interpol numbers to descriptive strings */ names = Enum [ [_ "Nearest neighbour", NEAREST_NEIGHBOUR], [_ "Bilinear", BILINEAR], [_ "Bicubic", BICUBIC] ]; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ [_ "Perceptual", PERCEPTUAL], [_ "Relative", RELATIVE], [_ "Saturation", SATURATION], [_ "Absolute", ABSOLUTE] ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ [_ "Point", POINT], [_ "Line", LINE], [_ "Spline", SPLINE], [_ "Bar", BAR] ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ [_ "YYYY", YYYY], [_ "XYYY", XYXY], [_ "XYXY", XYXY] ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } nip2-8.7.1/share/nip2/compat/7.14/Matrix.def0000644000175000017500000002066313351443023015077 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 (converse join_tb) (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 (converse join_lr) (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 (converse join_tb) (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 (converse join_lr) (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/7.14/Tasks.def0000644000175000017500000006177613351443023014732 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linear input", "Fit intercept from chart greyscale", "Linearize input from chart greyscale" ] 2; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure 0 0 image.width image.height 6 4 image.value; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix [[0, 0], [1, 1]], mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix (map2 cons _true_grey_Y' _camera_grey') { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map the original image through the lineariser to // get linear 0-1 RGB image _image' = hist_map linearising_lut.value image.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ cast_float @ recomb M) _image'; // measure again and compute dE76 _camera'' = im_measure _result.value 0 0 image.width image.height 6 4; _dEs = map abs_vec (_camera'' - _true_Lab).value; final_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; // map the original image through the lineariser to get // linear 0-1 RGB image image' = hist_map calib.linearising_lut image; // convert linear RGB camera to Lab result = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M image')); } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum Plot_style.names "Style" "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize xfactor yfactor 1 scale_im; _offset_im = resize xfactor yfactor 1 offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.14/Makefile.am0000644000175000017500000000056513351443023015206 00000000000000startdir = $(pkgdatadir)/compat/7.14 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.14/Makefile.in0000644000175000017500000003711313417043241015217 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.14 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.14 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.14/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.14/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.14/_predicate.def0000644000175000017500000002665413351443023015740 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = error ("get_format: unable to get format from " ++ print x); has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = error ("get_bits: unable to get bits from " ++ print x); has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = error ("get_bands: unable to get bands from " ++ print x); has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = error ("get_coding: unable to get coding from " ++ print x); has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = error ("get_xres: unable to get xres from " ++ print x); has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = error ("get_yres: unable to get yres from " ++ print x); has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = error ("get_xoffset: unable to get xoffset from " ++ print x); has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = error ("get_yoffset: unable to get yoffset from " ++ print x); has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = error ("get_image: unable to get image from " ++ print x); has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = error ("get_number: unable to get number from " ++ print x); has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = error ("get_real: unable to get real from " ++ print x); has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = error ("get_width: unable to get width from " ++ print x); has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = error ("get_height: unable to get height from " ++ print x); has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = error ("get_left: unable to get left from " ++ print x); has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = error ("get_top: unable to get top from " ++ print x); // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/7.14/_list.def0000644000175000017500000002140613351443023014741 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn (tl l), fn (hd l) = l; /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); sum = foldr1 add; product = foldr1 multiply; /* Search a list for an element, returning it's index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st a) x { a:x = l; } } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/7.16/0000755000175000017500000000000013417043452013233 500000000000000nip2-8.7.1/share/nip2/compat/7.16/Image.def0000644000175000017500000012722413351443023014660 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum Image_type.type_names "Image type" "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum field_names (_ "Field") name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum Image_type.type_names "Image type" (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 32; tile_height = Number "Tile height" 32; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process in = [ in, rot90 in, rot180 in, rot270 in ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; _result = map_unary process x { process image = rotate angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = map_unary straighten x { straighten arrow = rotate angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { _interp = Option_enum Interpolate.names "Interpolation" "Bilinear"; Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = _interp; _result = map_unary process x { process image = resize xfactor yfactor interp.value_thing image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; interp = _interp; _result = map_unary process x { process image = resize fac fac interp.value_thing image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = max_pair xfac yfac; min_factor = min_pair xfac yfac; fac = [max_factor, min_factor, xfac, yfac]?which; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; interp = _interp; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize fac fac interp.value_thing x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" (map (extract 0) Interpolate.names.value) Interpolate.BILINEAR; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = class _result { _vislevel = 3; // try to find the image geometry ... don't bother trying to look // inside groups though _geo = x.rect, is_Image x = Rect 0 0 100 100; l = Expression "Crop left" ((int) (_geo.left + _geo.width / 4)); t = Expression "Crop top" ((int) (_geo.top + _geo.height / 4)); w = Expression "Crop width" (max_pair 1 ((int) (_geo.width / 2))); h = Expression "Crop height" (max_pair 1 ((int) (_geo.height / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 2; ssize = Expression "Step size" 2; _result = Image (colour_transform_to (get_type start) im) { base = colour_transform_to Image_type.LAB start; step = to_real ssize; offset = to_real nstep * step; range c = [c - offset, c - offset + step ... c + offset]; mk_patch b a = image_new 8 8 3 Image_format.FLOAT Image_coding.NOCODING Image_type.LAB (Vector [base?0, a, b]) 0 0; mk_strip b = map (mk_patch b) (range base?1); mk_grid = map mk_strip (range base?2); im = imagearray_assemble 1 1 mk_grid; } } } } nip2-8.7.1/share/nip2/compat/7.16/_convert.def0000644000175000017500000004336513351443023015460 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The innermost list objects become Group()'d. */ to_group x = Group x, is_list x && !contains_Group x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = (ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* Given a list of things, try to make them all the same size. Don't change * the format. Don't touch non-image things. */ size_alike l = map enlarge l { max_width = foldr (test_prop has_width get_width) 0 l; max_height = foldr (test_prop has_height get_height) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); enlarge x = embed 0 0 0 max_width max_height x, has_width x = x; } /* Given a list of things, look for 1 band objects and bump them to to n - * band objects, where n is the maximum number of bands. Don't change the * format. Don't touch non-image things. */ bands_alike l = map upband l { max_bands = foldr (test_prop has_bands get_bands) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); upband x = bandjoin (replicate max_bands x), has_bands x && get_bands x == 1 = x; } /* Given a list of things, try to match the formats. Don't touch non-image * objects. */ formats_alike l = map upformat l { max_format = foldr (test_prop has_format get_format) Image_format.UCHAR l; test_prop has get x best = best, !has x = max_pair best (get x); upformat x = clip2fmt max_format x, has_format x = x; } /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 == 2 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/7.16/Filter.def0000644000175000017500000011404213351443023015055 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 1.5; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 50; fs = Scale "Sharpen flat areas by" (-2) 5 1; js = Scale "Sharpen jaggy areas by" (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_convf, !separable && type == 1 = im_convsepf, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 5) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height + 1) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_greyc_item = class Menupullright "_GREYCstoration" "noise-removing filter" { Denoise_item = class Menuaction "Denoise" "Noise-removing filter" { action x = class _result { _vislevel = 3; iterations = Scale "Iterations" 1 5 1; amplitude = Scale "Amplitude" 1 100 40; sharpness = Scale "Sharpness" 0 3 0.9; anisotropy = Scale "Anisotropy" 0 1 0.15; alpha = Scale "Noise scale" 0 5 0.6; sigma = Scale "Geometry regularity" 0 2 1.1; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) x; } } Enlarge_item = class Menuaction "Enlarge" "Enlarge image" { action x = class _result { _vislevel = 3; scale = Scale "Enlarge" 1 10 3; iterations = Scale "Iterations" 1 5 3; amplitude = Scale "Amplitude" 1 100 20; sharpness = Scale "Sharpness" 0 3 0.2; anisotropy = Scale "Anisotropy" 0 1 0.9; alpha = Scale "Noise scale" 0 5 0.1; sigma = Scale "Geometry regularity" 0 2 1.5; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) (resize (to_real scale) (to_real scale) Interpolate.BILINEAR x); } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ [_ "Normal", NORMAL], [_ "If Lighter", IFLIGHTER], [_ "If Darker", IFDARKER], [_ "Multiply", MULTIPLY], [_ "Add", ADD], [_ "Subtract", SUBTRACT], [_ "Screen", SCREEN], [_ "Burn", BURN], [_ "Soft Light", SOFTLIGHT], [_ "Hard Light", HARDLIGHT], [_ "Lighten", LIGHTEN], [_ "Darken", DARKEN], [_ "Dodge", DODGE], [_ "Reflect", REFLECT], [_ "Freeze", FREEZE], [_ "Bitwise OR", OR], [_ "Bitwise AND", AND] ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum names "Blend mode" "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ] ++ super._check_args; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } nip2-8.7.1/share/nip2/compat/7.16/_joe_extra.def0000644000175000017500000003300213351443023015743 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ] ++ super._check_all; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ] ++ super._check_all; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height that * is extracted to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ] ++ super._check_all; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount color" false; ls = Expression "Lower mount section bigger by (cm)" 0; colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 6; control_selection mask im no = (if mask then im * 1.2 else im * 1), no == 0 = (if mask then im * 0.8 else im * 1), no == 1 = (if mask then 0 else im), no == 2 = (if mask then 255 else im), no == 3 = (if mask then im else 0), no == 4 = (if mask then im else 255), no == 5 = mask; Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = a.image; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = ((pt_list.value)?0).image; } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize f1 1 1 b1 {b1 = resize 1 f2 1 b;} } } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.16/Preferences.ws0000644000175000017500000007670713351443023016003 00000000000000 nip2-8.7.1/share/nip2/compat/7.16/Colour.def0000644000175000017500000003531513351443023015100 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Convert to") (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Tag as") (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Colour Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum Whitepoints (_ "Old whitepoint") "D65"; new_white = Option_enum Whitepoints (_ "New whitepoint") "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum Render_intent.names (_ "Render intent") (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; _result = map_unary chart x { chart in = measure 0 0 in.width in.height (to_real pacross) (to_real pdown) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.16/_joe_utilities.def0000644000175000017500000004705113351443023016644 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} } ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; } ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); } ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = line.image; //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = (pt_l?0).image; im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; } ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; } nip2-8.7.1/share/nip2/compat/7.16/_Object.def0000644000175000017500000002601313351443023015175 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down a bit. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/7.16/Object.def0000644000175000017500000000222013351443023015030 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list (or group) of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/7.16/Math.def0000644000175000017500000003104013351443023014515 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_And" "bitwise and of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_Or" "bitwise or of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "E_xclusive Or" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_Not" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Band_or_item = class Menuaction "Band O_r" "or the bands of an image together" { action im = map_unary (foldr1 bitwise_or @ bandsplit) im; } Band_and_item = class Menuaction "Band A_nd" "and the bands of an image together" { action im = map_unary (foldr1 bitwise_and @ bandsplit) im; } } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 2; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.16/_generate.def0000644000175000017500000000514013351443023015557 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black (to_real w) (to_real h) (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = Matrix_con mask_g_sum 0 [mask_g_line] { mask_g = im_gauss_imask (radius / 3) 0.2; mask_g_line = mask_g.value?(mask_g.height / 2); mask_g_sum = sum mask_g_line; } /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } nip2-8.7.1/share/nip2/compat/7.16/_stdenv.def0000644000175000017500000014732513351443023015304 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error "unimplemented vector operation" { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_cache x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend") { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = x, is_image x = x.value, is_Image x = black + x { black = im_black target_width target_height target_bands; } [then_image, else_image] = map (clip2fmt target_format @ to_image) [then_part, else_part]; [c, t, e] = size_alike [cond, then_image, else_image]; blend_result_image = image_set_type target_type (im_blend c t e); } } insert x y small big = oo_binary_function insert_op small big, is_class small = oo_binary'_function insert_op small big, is_class big = im_insert big' small' (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; [small', big'] = (formats_alike @ bands_alike) [small, big]; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big' small' (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; [small', big'] = (formats_alike @ bands_alike) [small, big]; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (_ "bad arguments to " ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_similarity image (cos angle) (sin angle) 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" rotate Operator_type.COMPOUND_REWRAP false; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join a b { join_lr_op = Operator "join_lr" join Operator_type.COMPOUND_REWRAP false; join a b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr"); join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join a b { join_tb_op = Operator "join_tb" join Operator_type.COMPOUND_REWRAP false; join a b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb"); join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { image = (unsigned char) im_mask2vips (Matrix m2); m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsepf image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx x = oo_unary_function greyc_op x, is_class x = greyc_im x, is_image x = error (_ "bad argument" ++ " (" ++ print x ++ ") to " ++ "greyc") { greyc_op = Operator "greyc" (greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im x = im_greyc x iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx mask x = oo_binary_function greyc_mask_op mask x, is_class mask = oo_binary'_function greyc_mask_op mask x, is_class x = greyc_im mask x, is_image mask && is_image x = error (_ "bad arguments" ++ " (" ++ print mask ++ ", " ++ print x ++ ") " ++ "to " ++ "greyc") { greyc_mask_op = Operator "greyc_mask" (greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im mask x = im_greyc_mask x mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize xfac yfac interp image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // upscale by any factor, nearest neighbour // can't really do this right ... upscale by integer part, then // bilinear to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // downscale by any factor, nearest neighbour // can't really do this right ... downscale by integer part, // then bilinear to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // upscale by any factor, bilinear = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 && interp == Interpolate.BILINEAR // downscale by any factor, bilinear // block shrink by integer factor, then bilinear resample to // exact = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.BILINEAR = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate.names.lookup 1 0 interp ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // binlinear resize scale xfac yfac im = im_affine im xfac 0 0 yfac 0 0 0 0 (rint (get_width im * xfac)) (rint (get_height im * yfac)); } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } flood_blob x y v image = oo_unary_function flood_blob_op image, is_class image = im_flood_blob_copy image (to_real x) (to_real y) v, is_image image = error (_ "bad arguments to " ++ "flood_blob") { flood_blob_op = Operator "flood_blob" (flood_blob x y v) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Image (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; } ss = len xes; sx = sum xes; sy = sum yes; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } nip2-8.7.1/share/nip2/compat/7.16/Histogram.def0000644000175000017500000001752213351443023015572 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "Histogram" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type field to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } } Hist_map_item = class Menuaction "_Map Histogram" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Cumulativise Histogram" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate Histogram" "find point-to-point differences (inverse of Cumulativise)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise Histogram" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_match_item = class Menuaction "Ma_tch Histogram" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); // extract that area area = extract_area (re p' + displace.value) (im p' - width.value / 2 + vdisplace.value) (re pv) width.value im'; // squish vertically to get an average area' = resize 1 (1 / width.value) Interpolate.BILINEAR area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = area { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); // extract that area area = extract_area (re p' + displace.value) (im p' - width.value / 2 + vdisplace.value) (re pv) width.value im'; } } } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; format = Option_enum Plot_format.names "Format" "YYYY"; style = Option_enum Plot_style.names "Style" "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; image x = image (extract_arrow x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } extract_arrow arrow = extract_area (re p') (im p') (re pv) 1 im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } } } } nip2-8.7.1/share/nip2/compat/7.16/Widgets.def0000644000175000017500000000235313351443023015237 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/7.16/_types.def0000644000175000017500000007006713351443023015143 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ] ++ super._check_args; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ] ++ super._check_args; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ] ++ super._check_args; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ] ++ super._check_args; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ] ++ super._check_args; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ] ++ super._check_args; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ] ++ super._check_args; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ] ++ super._check_args; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ] ++ super._check_args; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ] ++ super._check_args; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ] ++ super._check_args; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ] ++ super._check_args; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ] ++ super._check_args; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ] ++ super._check_args; _check_all = [ [is_list_len 3 value, "len value == 3"] ] ++ super._check_all; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.value_name colour.expr { _vislevel = 3; space = Option_enum Image_type.colour_spaces "Colour space" default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ] ++ super._check_args; _check_all = [ [from < to, "from < to"] ] ++ super._check_all; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ] ++ super._check_args; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ] ++ super._check_args; } Option_enum enum caption value_name = class Option caption enum.names (index (equal value_name) enum.names) { // corresponding thing value_thing = enum.get_thing value_name; Option_edit caption labels value = this.Option_enum enum caption (enum.names ? value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ] ++ super._check_args; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ] ++ super._check_args; /* present col x: is there an x in column col */ present col x = member (map (extract col) value) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (map (extract from) value); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] ++ super._check_args { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = map (extract 0) value; things = map (extract 1) value; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; LUMINANCE = 2; XRAY = 3; IR = 4; YUV = 5; RED_ONLY = 6; GREEN_ONLY = 7; BLUE_ONLY = 8; POWER_SPECTRUM = 9; HISTOGRAM = 10; LUT = 11; XYZ = 12; LAB = 13; CMC = 14; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $LUMINANCE => LUMINANCE, $XRAY => XRAY, $IR => IR, $YUV => YUV, $RED_ONLY => RED_ONLY, $GREEN_ONLY => GREEN_ONLY, $BLUE_ONLY => BLUE_ONLY, $POWER_SPECTRUM => POWER_SPECTRUM, $HISTOGRAM => HISTOGRAM, $LUT => LUT, $XYZ => XYZ, $LAB => LAB, $CMC => CMC, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16 ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ] ++ super._check_args; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], // image ++ image is slightly different ... we want to // sizealike, but we must not bandalike [wrap (op.fn (get_image resized?0) (get_image resized?1)), has_image x && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], // arithmetic and reational binops between image resize // and band_alike images to match [wrap (op.fn (get_image rebanded?0) (get_image rebanded?1)), has_image x && (op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL)], // other op types don't resize [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. "Image v == // 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = []; to_image x = x, is_image x = x.value, is_Image x = clip2fmt target_format im, target_format != [] = im { im = im_black width height target_bands + x; } [if_size, then_size, else_size] = size_alike (value : formats_alike (map to_image x)); ite_result_image = image_set_type target_type (if if_size then then_size else else_size); resized = size_alike [this, x]; rebanded = bands_alike resized; } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ] ++ super._check_args; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ] ++ super._check_args; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ] ++ super._check_args; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; /* Table to map interpol numbers to descriptive strings */ names = Enum [ [_ "Nearest neighbour", NEAREST_NEIGHBOUR], [_ "Bilinear", BILINEAR], [_ "Bicubic", BICUBIC] ]; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ [_ "Perceptual", PERCEPTUAL], [_ "Relative", RELATIVE], [_ "Saturation", SATURATION], [_ "Absolute", ABSOLUTE] ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ [_ "Point", POINT], [_ "Line", LINE], [_ "Spline", SPLINE], [_ "Bar", BAR] ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ [_ "YYYY", YYYY], [_ "XYYY", XYXY], [_ "XYXY", XYXY] ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/7.16/Matrix.def0000644000175000017500000002066113351443023015077 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ] ++ super._check_args; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ] ++ super._check_args; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/7.16/Tasks.def0000644000175000017500000006214713351443023014725 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linear input", "Fit intercept from chart greyscale", "Linearize input from chart greyscale" ] 2; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure 0 0 image.width image.height 6 4 image.value; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix [[0, 0], [1, 1]], mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix (map2 cons _true_grey_Y' _camera_grey') { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map the original image through the lineariser to // get linear 0-1 RGB image _image' = hist_map linearising_lut.value image.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ cast_float @ recomb M) _image'; // measure again and compute dE76 _camera'' = im_measure _result.value 0 0 image.width image.height 6 4; _dEs = map abs_vec (_camera'' - _true_Lab).value; final_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; // map the original image through the lineariser to get // linear 0-1 RGB image image' = hist_map calib.linearising_lut image; // convert linear RGB camera to Lab result = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M image')); } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum Plot_style.names "Style" "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b ++ super._check_args; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b ++ super._check_args; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d ++ super._check_args; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d ++ super._check_args; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize xfactor yfactor 1 scale_im; _offset_im = resize xfactor yfactor 1 offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.16/Makefile.am0000644000175000017500000000056513351443023015210 00000000000000startdir = $(pkgdatadir)/compat/7.16 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.16/Makefile.in0000644000175000017500000003711313417043242015222 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.16 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.16 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.16/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.16/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.16/_predicate.def0000644000175000017500000002672113351443023015735 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = error ("get_format: unable to get format from " ++ print x); has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = error ("get_bits: unable to get bits from " ++ print x); has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = error ("get_bands: unable to get bands from " ++ print x); has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = error ("get_coding: unable to get coding from " ++ print x); has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = error ("get_xres: unable to get xres from " ++ print x); has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = error ("get_yres: unable to get yres from " ++ print x); has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = error ("get_xoffset: unable to get xoffset from " ++ print x); has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = error ("get_yoffset: unable to get yoffset from " ++ print x); has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = error ("get_image: unable to get image from " ++ print x); has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = error ("get_number: unable to get number from " ++ print x); has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = error ("get_real: unable to get real from " ++ print x); has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = error ("get_width: unable to get width from " ++ print x); has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = error ("get_height: unable to get height from " ++ print x); has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = error ("get_left: unable to get left from " ++ print x); has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = error ("get_top: unable to get top from " ++ print x); // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/7.16/_list.def0000644000175000017500000002172213351443023014744 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn (tl l), fn (hd l) = l; /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); sum = foldr1 add; product = foldr1 multiply; /* Search a list for an element, returning it's index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st a) x { a:x = l; } } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/8.4/0000755000175000017500000000000013417043453013152 500000000000000nip2-8.7.1/share/nip2/compat/8.4/Image.def0000644000175000017500000014617113351443023014600 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process = [ // we can't use id here since we want to "declass" // the members of x ... consider if x is a crop class, // for example, we don't want to inherit from crop, we // want to make a new image class rot180 @ rot180, rot90, rot180, rot270 ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel h v image, aspect = resize kernel fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize kernel fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_map_item = class Menuaction "_Map" "map an image through a 2D transform image" { action a b = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_binary trans a b { trans a b = mapim interp.value in index { // get the index image first [index, in] = sortc (const is_twocomponent) [a, b]; // is a two-component image, ie. one band complex, or // two-band non-complex is_twocomponent x = is_nonc x || is_c x; is_nonc x = has_bands x && get_bands x == 2 && has_format x && !is_complex_format (get_format x); is_c x = has_bands x && get_bands x == 1 && has_format x && is_complex_format (get_format x); is_complex_format f = f == Image_format.COMPLEX || f == Image_format.DPCOMPLEX; } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; Bandand_item = class Menuaction "Bitwise Band AND" "bitwise AND of image bands" { action x = bandand x; } Bandor_item = class Menuaction "Bitwise Band OR" "bitwise OR of image bands" { action x = bandor x; } sep2 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = crop x [l, t, w, h] { fields = [ [has_left, get_left, 0], [has_top, get_top, 0], [has_width, get_width, 100], [has_height, get_height, 100] ]; [l, t, w, h] = map get_default fields { get_default line = get x, has x = default { [has, get, default] = line; } } } crop x geo = class _result { _vislevel = 3; l = Expression "Crop left" ((int) (geo?0 + geo?2 / 4)); t = Expression "Crop top" ((int) (geo?1 + geo?3 / 4)); w = Expression "Crop width" (max_pair 1 ((int) (geo?2 / 2))); h = Expression "Crop height" (max_pair 1 ((int) (geo?3 / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 100; sy = Expression "Start y" 100; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise Join" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Noise_item = class Menupullright "_Noise" "various noise generators" { Gaussian_item = class Menuaction "_Gaussian" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal noise image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Perlin_item = class Menuaction "_Perlin" "Perlin noise image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; cell_size = Expression "Cell size (pixels)" 8; eight = Toggle "Eight bit output" true; _result = 128 * im + 128, eight = im { im = perlin cell_size nwidth nheight; } } } Worley_item = class Menuaction "_Worley" "Worley noise image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 512; nheight = Expression "Image height (pixels)" 512; cell_size = Expression "Cell size (pixels)" 256; _result = worley cell_size nwidth nheight; } } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/8.4/_convert.def0000644000175000017500000004424313351443023015372 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = Image x.value, is_Plot x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The outermost list objects become Group()'d. */ to_group x = Group x, is_list x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = sign * (abs ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; sign = 1, ipart > 0 = -1; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; /* Return $PATH, reformatted as [["comp1", "comp2"], ["comp1", "comp2"] ..] */ system_search_path = [vipsbin] ++ map path_parse (split (equal path_sep) (expand "$PATH")) { /* On some platforms we ship vips with a few extra progs. Search * $VIPSHOME/bin first. */ vipsbin = path_parse (expand "$VIPSHOME") ++ ["bin"]; path_sep = ':', expand "$SEP" == "/" = ';'; } /* Search $PATH for the first occurence of name, or "". */ search_for name = hits?0, hits != [] = "" { exe_name = name ++ expand "$EXEEXT"; form_path p = path_absolute (p ++ [exe_name]); paths = map form_path system_search_path; hits = dropwhile (equal []) (map search paths); } /* Search $PATH for the first occurence of name, error on failure. */ search_for_error name = path, path != "" = error (exe_name ++ " not found on your search path. " ++ "Check you have installed the program and it is on your PATH.") { exe_name = name ++ expand "$EXEEXT"; path = search_for name; } nip2-8.7.1/share/nip2/compat/8.4/Filter.def0000644000175000017500000011730313351443023014776 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 2; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 20; fs = Scale "Sharpen flat areas by" 0 5 0.5; js = Scale "Sharpen jaggy areas by" 0 5 1; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_hough_item = class Menupullright "_Hough Transform" "transform to parameter space" { Line_item = class Menuaction "_Line" "find straight line Hough transform" { action a = class _result { _vislevel = 3; pspace_width = Expression "Parameter space width" 64; pspace_height = Expression "Parameter space height" 64; _result = map_unary line a { line a = hough_line (to_real pspace_width) (to_real pspace_height) a; } } } Circle_item = class Menuaction "_Circle" "find circle Hough transform" { action a = class _result { _vislevel = 3; scale = Expression "Scale down parameter space by" 10; min_radius = Expression "Minimum radius" 10; max_radius = Expression "Maximum radius" 30; _result = map_unary circle a { circle a = hough_circle (to_real scale) (to_real min_radius) (to_real max_radius) a; } } } } Filter_coordinate_item = class Menupullright "_Coordinate Transform" "various coordinate transforms" { // run a function which wants a complex arg on a non-complex two-band // image run_cmplx fn x = re x' ++ im x' { x' = fn (x?0, x?1); } Polar_item = class Menuaction "_Polar" "transform to polar coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_polar a { to_polar im = mapim interp.value map' im { // xy image, origin in the centre, scaled to fit image to // a circle xy = make_xy im.width im.height; xy' = xy - Vector [im.width / 2, im.height / 2]; scale = min [im.width, im.height] / im.width; xy'' = 2 * xy' / scale; // to polar, scale vertical axis to 360 degrees map = run_cmplx polar xy''; map' = map * Vector [1, im.height / 360]; } } } } Rectangular_item = class Menuaction "_Rectangular" "transform to rectangular coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_rect a { to_rect im = mapim interp.value map'' im { // xy image, vertical scaled to 360 degrees xy = make_xy im.width im.height; xy' = xy * Vector [1, 360 / im.height]; // to rect, scale to image rect map = run_cmplx rectangular xy'; scale = min [im.width, im.height] / im.width; map' = map * scale / 2; map'' = map' + Vector [im.width / 2, im.height / 2]; } } } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } Autotrace_item = class Menuaction "_Trace" "convert a bitmap to an SVG file" { action x = class _result { _vislevel = 3; despeckle = Scale "Despeckle level" 1 20 1; line = Scale "Line threshold" 1 20 1; center = Toggle "Trace centreline" false; scale = Scale "SVG scale" 0.1 10 1; command = "autotrace %s " ++ join_sep " " [ofmt, ofile, desp, lint, cent] { prog = search_for_error "autotrace"; ofmt = "-output-format svg"; ofile = "-output-file %s"; desp = "-despeckle-level " ++ print despeckle.value; lint = "-line-threshold " ++ print line.value; cent = if center then "-centerline " else ""; } _result = Image output { [output] = vips_call "system" [command] [$in => [x.value], $in_format => "%s.ppm", $out => true, $out_format => "%s.svg[scale=" ++ print scale.value ++ "]" ]; } } } nip2-8.7.1/share/nip2/compat/8.4/_joe_extra.def0000644000175000017500000003107513351443023015671 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use an Arrow or Region x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { im = x.image; mask = Image m { rx = x.region_rect, is_Region x = x; b = image_new im.width im.height 1 0 0 1 0 0 0; w = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0; m = insert_noexpand rx.nleft rx.ntop w b; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Kernel_linear f1 1 b1 {b1 = resize Kernel_linear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/8.4/Preferences.ws0000644000175000017500000010177213351443023015710 00000000000000 nip2-8.7.1/share/nip2/compat/8.4/Magick.def0000644000175000017500000014112713351443023014745 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate Magick.def 13-Apr-2014 snibgo Put "new image" items into sub-menu. New class VirtualPixlBack. 17-Apr-2014 snibgo Many small changes. A few new menu options. Created sub-menu for multi-input operations. 3-May-2014 jcupitt Put quotes around ( in shadow to help unix Last update: 17-Apr-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ // We don't need Noop. /*=== Magick_noop_item = class Menuaction "_Noop" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_testPar_item = class Menuaction "_TestPar" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "( +clone ) +append ", "\"%s\"" ]; _result = Magick.system command x; } } /* Removed Read_item and Write_item, much better to use nip2 load/save image. * Plus they can load all libMagick formats anyway. */ // Put "new image" items into sub-menu Magick_NewImageMenu_item = class Menupullright "_New image" "make a new image" { Magick_newcanvas_item = class Menuaction "_Solid colour" "make image of solid colour" { action = class _result { _vislevel = 3; size = Magick.Size_widget; colour = Magick.generalcol_widget; command = Magick.command [ size._flag, "\"canvas:" ++ colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_builtin_item = class Menuaction "_Built-in image" "create a built-in image" { action = class _result { _vislevel = 3; builtin = Magick.builtin_widget; command = Magick.command [ builtin._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_gradient_item = class Menuaction "_Gradient" "make a linear gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; topColour = Magick.generalcol_widget; bottomColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"gradient:", topColour._flag, "-", bottomColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } Magick_hald_item = class Menuaction "_Hald-clut image" "create an identity hald-clut image" { action = class _result { _vislevel = 3; order = Expression "order" 8; command = Magick.command [ "hald:" ++ print order.expr, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_pattern_item = class Menuaction "_Pattern" "create pattern" { action = class _result { _vislevel = 3; size = Magick.Size_widget; pattern = Magick.pattern_widget; command = Magick.command [ size._flag, pattern._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_plasma_item = class Menuaction "_Plasma image" "create plasma image" { action = class _result { _vislevel = 3; size = Magick.Size_widget; // FIXME? ColourA-ColourB. // FIXME? Allow plasma:fractal? command = Magick.command [ size._flag, "plasma:", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_radialgradient_item = class Menuaction "_Radial gradient" "make a radial gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; innerColour = Magick.generalcol_widget; outerColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"radial-gradient:", innerColour._flag, "-", outerColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } } // end Magick_NewImageMenu_item Magick_MultiMenu_item = class Menupullright "_Multiple inputs" "make an image from multiple images" { Magick_composite_item = class Menuaction "_Composite" "composite two images (without mask)" { action x y = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_compositeMask_item = class Menuaction "_Composite masked" "composite two images (with mask)" { action x y z = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system3 command x y z; } } // FIXME: other operations like remap that take another image as arguments are: // mask (pointless?), texture, tile (pointless?) // FIXME: operations that take a filename that isn't an image: // cdl, profile Magick_clut_item = class Menuaction "_Clut" "replace values using second image as colour look-up table" { action x y = class _result { _vislevel = 3; // FIXME: uses -intensity "when mapping greyscale CLUT image to alpha channel if set by -channels" command = Magick.command [ "\"%s\"", "\"%s\"", "-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_haldclut_item = class Menuaction "_Hald clut" "replace values using second image as Hald colour look-up table" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"", "-hald-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } // Encipher and decipher: key files can be text or image files. Magick_encipher_item = class Menuaction "_Encipher/Decipher" "encipher or decipher an image image" { action x = class _result { _vislevel = 3; pathname = Pathname "Read key file" ""; isDecipher = Toggle "Decipher" false; command = Magick.command [ "\"%s\"", if pathname.value == "" then "" else ( ( if isDecipher then "-decipher " else "-encipher ") ++ ( "\"" ++ pathname.value ++ "\"" ) ), "\"%s\"" ]; _result = Magick.system command x; } } Magick_profile_item = class Menuaction "_Profile" "assigns/applies an ICC profile" { action x = class _result { _vislevel = 3; pathname1 = Pathname "Read profile file" ""; pathname2 = Pathname "Read profile file" ""; command = Magick.command [ "\"%s\"", if pathname1.value == "" then "" else ( "-profile " ++ "\"" ++ pathname1.value ++ "\""), if pathname2.value == "" then "" else ( "-profile " ++ "\"" ++ pathname2.value ++ "\""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_remap_item = class Menuaction "_Remap" "reduce colours to those in another image" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-remap", "\"%s\"", "\"%s\"" ]; _result = Magick.system2 command x y; } } } // end Magick_MultiMenu_item Magick_image_type_item = class Menuaction "_Image Type" "change image type" { action x = class _result { _vislevel = 3; imagetype = Magick.imagetype_widget; command = Magick.command [ "\"%s\"", imagetype._flag, "\"%s\"" ]; _result = Magick.system command x; } } sep2 = Menuseparator; Magick_alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = Magick.alpha_widget; command = Magick.command [ "\"%s\"", alpha._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = Magick.text_widget; font = Magick.Font_widget; geometry = Magick.AnnotGeometry_widget; gravity = Magick.gravity_widget; foreground = Magick.foreground_widget; undercol = Magick.undercol_widget; antialias = Magick.antialias_widget; command = Magick.command [ "\"%s\"", font._flag, antialias._flag, gravity._flag, foreground._flag, undercol._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoGamma_item = class Menuaction "_AutoGamma" "automatic gamma" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-gamma", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoLevel_item = class Menuaction "_AutoLevel" "automatic level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-level", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blurSharpMenu_item = class Menupullright "_Blur/Sharpen" "blur and sharpen" { Magick_adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; // note: adaptive-blur doesn't regard VP. command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-adaptive-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_blur_item = class Menuaction "_Blur" "blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gaussianBlur_item = class Menuaction "_Gaussian Blur" "blur with a Gaussian operator" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-gaussian-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_motionBlur_item = class Menuaction "_Motion Blur" "simulate motion blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; channels = Magick.ch_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-motion-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotationalBlur_item = class Menuaction "_RotationalBlur" "blur around the centre" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; angle = Scale "angle (degrees)" (-360) 360 20; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-radial-blur", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_selectiveBlur_item = class Menuaction "_Selective Blur" "blur where contrast is less than or equal to threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; threshold = Scale "Threshold (percent)" 0 100 50; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", intensity._flag, virtpixback._flag, channels._flag, "-selective-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print threshold.value ++ "%%", "\"%s\"" ]; _result = Magick.system command x; } } sep1 = Menuseparator; Magick_adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-adaptive-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sharpen_item = class Menuaction "_Sharpen" "sharpen" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_unsharpen_item = class Menuaction "_Unsharp" "sharpen with unsharp mask" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; gain = Scale "Gain" (-10) 10 1; threshold = Scale "Threshold" 0 1 0.05; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-unsharp", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print gain.value ++ "+" ++ print threshold.value, "\"%s\"" ]; _result = Magick.system command x; } } } // end BlurSharpMenu_item Magick_border_item = class Menuaction "_Border" "add border of given colour" { action x = class _result { _vislevel = 3; compose = Magick.compose_widget; width = Expression "Width" 3; bordercol = Magick.bordercol_widget; command = Magick.command [ "\"%s\"", compose._flag, bordercol._flag, "-border", print width.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_brightCont_item = class Menuaction "_Brightness-contrast" "adjust the brightness and/or contrast" { action x = class _result { _vislevel = 3; bri = Scale "brightness" (-100) 100 0; con = Scale "contrast" (-100) 100 0; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-brightness-contrast", print bri.value ++ "x" ++ print con.value, "\"%s\"" ]; _result = Magick.system command x; } } // Note: canny requires ImageMagick 6.8.9-0 or later. Magick_canny_item = class Menuaction "_Canny" "detect a wide range of edges" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; lowPc = Scale "lower percent" 0 100 10; highPc = Scale "lower percent" 0 100 10; command = Magick.command [ "\"%s\"", "-canny", concat ["\"", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print lowPc.value ++ "%%+" ++ print highPc.value ++ "%%" ++ "\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_charcoal_item = class Menuaction "_Charcoal" "simulate a charcoal drawing" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; factor = Scale "factor" 0 50 1; command = Magick.command [ "\"%s\"", intensity._flag, "-charcoal", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_chop_item = class Menuaction "_Chop" "remove pixels from the interior" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-chop", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorize_item = class Menuaction "_Colorize" "colorize by given amount" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; val = Scale "value" 0 100 100; command = Magick.command [ "\"%s\"", foreground._flag, "-colorize", print val.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colors_item = class Menuaction "_Colors" "reduce number of colors" { action x = class _result { _vislevel = 3; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; quantize = Magick.colorspace_widget; colors = Expression "Colours" 3; command = Magick.command [ "\"%s\"", "-quantize", quantize._flag, "-treedepth", print treedepth.expr, dither._flag, "-colors", print colors.expr, "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: color-matrix? Magick_colorspace_item = class Menuaction "_Colourspace" "convert to arbitrary colourspace" { action x = class _result { _vislevel = 3; colsp = Magick.colorspace_widget; command = Magick.command [ "\"%s\"", "-colorspace", colsp._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorspaceGray_item = class Menuaction "_Colourspace gray" "convert to gray using given intensity method" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-colorspace gray", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrast_item = class Menuaction "_Contrast" "increase or reduce the contrast" { action x = class _result { _vislevel = 3; isReduce = Toggle "reduce contrast" false; command = Magick.command [ "\"%s\"", (if isReduce then "+" else "-") ++ "contrast", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrastStretch_item = class Menuaction "_Contrast stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-contrast-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: convolve (bias, kernel) Magick_crop_item = class Menuaction "_Crop" "cut out a rectangular region" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-crop", geometry._flag, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_deskew_item = class Menuaction "_Deskew" "straighten the image" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; // FIXME: toggle auto-crop? command = Magick.command [ "\"%s\"", "-deskew", "\"" ++ print threshold.value ++ "%%\"", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_despeckle_item = class Menuaction "_Despeckle" "reduce the speckles" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-despeckle", "\"%s\"" ]; _result = Magick.system command x; } } Magick_distort_item = class Menuaction "_Distort" "distort using a method and arguments" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; distort = Magick.distort_widget; args = String "Arguments" "1,0"; isPlus = Toggle "Extend to show entire image" false; command = Magick.command [ "\"%s\"", virtpixback._flag, (if isPlus then "+" else "-") ++ "distort", distort._flag, args.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_draw_item = class Menuaction "_Draw" "annotate with one or more graphic primitives" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; args = String "Arguments" "line 0,0 9,9 rectangle 10,10 20,20"; command = Magick.command [ "\"%s\"", foreground._flag, "-draw", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_edge_item = class Menuaction "_Edge" "detect edges" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-edge", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_emboss_item = class Menuaction "_Emboss" "emboss" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-emboss", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_enhance_item = class Menuaction "_Enhance" "enhance a noisy image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-enhance", "\"%s\"" ]; _result = Magick.system command x; } } Magick_equalize_item = class Menuaction "_Equalize" "equalize the histogram" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-equalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_evaluate_item = class Menuaction "_Evaluate" "evaluate an expression on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; operation = Magick.evaluate_widget; val = Expression "value" 5; isPc = Toggle "Value is percent" false; command = Magick.command [ "\"%s\"", channels._flag, operation._flag, print val.expr ++ if isPc then "%%" else "", "\"%s\"" ]; _result = Magick.system command x; } } Magick_extent_item = class Menuaction "_Extent" "set the image size and offset" { action x = class _result { _vislevel = 3; background = Magick.background_widget; compose = Magick.compose_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, background._flag, gravity._flag, "-extent", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_FlipFlopMenu_item = class Menupullright "_Flip/flop" "flip/flop/transverse/transpose" { Magick_flip_item = class Menuaction "_Flip vertically" "mirror upside-down" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flip", "\"%s\"" ]; _result = Magick.system command x; } } Magick_flop_item = class Menuaction "_Flop horizontally" "mirror left-right" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flop", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transpose_item = class Menuaction "_Transpose" "mirror along the top-left to bottom-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transpose +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transverse_item = class Menuaction "_Transverse" "mirror along the bottom-left to top-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transverse +repage", "\"%s\"" ]; _result = Magick.system command x; } } } // end Magick_FlipFlopMenu_item Magick_floodfill_item = class Menuaction "_Floodfill" "recolour neighbours that match" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; fuzz = Magick.fuzz_widget; coordinate = Magick.coordinate_widget; // -draw "color x,y floodfill" command = Magick.command [ "\"%s\"", foreground._flag, "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-draw \" color", coordinate._flag, "floodfill \"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_frame_item = class Menuaction "_Frame" "surround with border or beveled frame" { action x = class _result { _vislevel = 3; border = Magick.bordercol_widget; compose = Magick.compose_widget; matte = Magick.mattecol_widget; geometry = Magick.FrameGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, border._flag, matte._flag, "-frame", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_function_item = class Menuaction "_Function" "evaluate a function on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; function = Magick.function_widget; // FIXME: explain values; use sensible defaults. values = String "values" "0,0,0,0"; command = Magick.command [ "\"%s\"", channels._flag, "-function", function._flag, values.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_fx_item = class Menuaction "_Fx" "apply a mathematical expression" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; interpolate = Magick.interpolate_widget; virtpixback = Magick.VirtualPixelBack_widget; args = String "Expression" "u*1/2"; command = Magick.command [ "\"%s\"", channels._flag, interpolate._flag, virtpixback._flag, "-fx", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_gamma_item = class Menuaction "_Gamma" "apply a gamma correction" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; gamma = Magick.gamma_widget; command = Magick.command [ "\"%s\"", channels._flag, "-gamma", print gamma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradient_item = class Menuaction "_Gradient" "apply a linear gradient" { action x = class _result { _vislevel = 3; colourA = Magick.generalcol_widget; colourB = Magick.generalcol_widget; position = Option "colourA is at" [ "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"] 0; _baryArg = concat ["0,0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 0 = concat ["0,0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 1 = concat ["0,0,", colourA._flag, " %%[fx:w-1],0,", colourB._flag], position.value == 2 = concat ["0,0,", colourB._flag, " %%[fx:w-1],0,", colourA._flag], position.value == 3 = concat ["0,0,", colourA._flag, " %%[fx:w-1],%%[fx:h-1],", colourB._flag], position.value == 4 = concat ["%%[fx:w-1],0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 5 = concat ["%%[fx:w-1],0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 6 = concat ["0,0,", colourB._flag, " %%[fx:w-1],%%[fx:h-1],", colourA._flag], position.value == 7 = "dunno"; command = Magick.command [ "\"%s\"", "-sparse-color barycentric \"" ++ _baryArg ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradientCorn_item = class Menuaction "_Gradient corners" "apply a bilinear gradient between the corners" { action x = class _result { _vislevel = 3; colour_top_left = Magick.generalcol_widget; colour_top_right = Magick.generalcol_widget; colour_bottom_left = Magick.generalcol_widget; colour_bottom_right = Magick.generalcol_widget; command = Magick.command [ "\"%s\"", "-sparse-color bilinear \"" ++ "0,0," ++ colour_top_left._flag ++ ",%%[fx:w-1],0" ++ colour_top_right._flag ++ ",0,%%[fx:h-1]" ++ colour_bottom_left._flag ++ ",%%[fx:w-1],%%[fx:h-1]" ++ colour_bottom_right._flag ++ "\"", "+depth", "\"%s\"" ]; _result = Magick.system command x; } } Magick_histogram_item = class Menuaction "_Histogram" "make a histogram image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-define histogram:unique-colors=false histogram:" ++ "\"%s\"" ]; _result = Magick.system command x; } } Magick_implode_item = class Menuaction "_Implode" "implode pixels about the center" { action x = class _result { _vislevel = 3; factor = Scale "factor" 0 20 1; interpolate = Magick.interpolate_widget; // FIXME: virtual-pixel? command = Magick.command [ "\"%s\"", interpolate._flag, "-implode", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_level_item = class Menuaction "_Level" "adjust the level of channels" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "black point" (-100) 200 0; wht = Scale "white point" (-100) 200 100; gam = Scale "gamma" 0 30 1; isPc = Toggle "Levels are percent" true; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level", "\"" ++ print blk.value ++ "," ++ print wht.value ++ (if isPc then "%%" else "") ++ "," ++ print gam.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_levelCols_item = class Menuaction "_Level colors" "adjust levels to given colours" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; colour_black = Magick.generalcol_widget; colour_white = Magick.generalcol_widget; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level-colors", "\"" ++ colour_black._flag ++ "," ++ colour_white._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_linearStretch_item = class Menuaction "_Linear stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", channels._flag, "-linear-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_magnify_item = class Menuaction "_Magnify" "double the size of the image with pixel art scaling" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-magnify", "\"%s\"" ]; _result = Magick.system command x; } } Magick_modulate_item = class Menuaction "_Modulate" "modulate brightness, saturation and hue" { action x = class _result { _vislevel = 3; modcolsp = Magick.ModColSp_widget; bright = Scale "brightness" 0 200 100; sat = Scale "saturation" 0 200 100; hue = Scale "hue" 0 200 100; command = Magick.command [ "\"%s\"", modcolsp._flag, "-modulate", print bright.value ++ "," ++ print sat.value ++ "," ++ print hue.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_monochrome_item = class Menuaction "_Monochrome" "transform to black and white" { action x = class _result { _vislevel = 3; // FIXME: also intensity? intensity = Magick.intensity_widget; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; command = Magick.command [ "\"%s\"", intensity._flag, dither._flag, "-treedepth", print treedepth.expr, "-monochrome", "\"%s\"" ]; _result = Magick.system command x; } } Magick_morphology_item = class // See http://www.imagemagick.org/Usage/morphology/ Menuaction "_Morphology" "apply a morphological method" { action x = class _result { _vislevel = 3; method = Magick.morphmeth_widget; iter = Expression "Iterations (-1=repeat until done)" 1; kernel = Magick.kernel_widget; // FIXME: custom kernel eg "3x1+2+0:1,0,0" // width x height + offsx + offsy : {w*h values} // each value is 0.0 to 1.0 or "NaN" or "-" // kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0 // but // ring takes: radius1, radius2, scale // rectangle and comet take: width x height + offsx + offsy // blur takes: radius x sigma // FIXME: for now, simply allow any string input. kernel_arg = String "Kernel arguments" ""; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-morphology", method._flag ++ ":" ++ print iter.expr, kernel._flag ++ (if kernel_arg.value == "" then "" else ":") ++ kernel_arg.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_negate_item = class Menuaction "_Negate" "negate" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-negate", "\"%s\"" ]; _result = Magick.system command x; } } Magick_addNoise_item = class Menuaction "_add Noise" "add noise" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; attenuate = Scale "attenuate" 0 1.0 1.0; noise = Magick.noise_widget; command = Magick.command [ "\"%s\"", channels._flag, "-attenuate", print attenuate.value, noise._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_normalize_item = class Menuaction "_Normalize" "normalize" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-normalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_opaque_item = class Menuaction "_Opaque" "change this colour to the fill colour" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; fill = Magick.foreground_widget; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", fill._flag, channels._flag, "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "opaque", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_paint_item = class Menuaction "_Paint" "simulate an oil painting" { action x = class _result { _vislevel = 3; rad = Expression "radius" 10; command = Magick.command [ "\"%s\"", "-paint", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } /*=== FIXME Bug; remove for now. Polaroid_item = class Menuaction "_Polaroid" "simulate a polaroid picture" { action x = class _result { _vislevel = 3; angle = Scale "angle" (-90) 90 20; command = Magick.command [ "\"%s\"", "-polaroid", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_posterize_item = class Menuaction "_Posterize" "reduce to (n) levels per channel" { action x = class _result { _vislevel = 3; levels = Expression "levels" 3; command = Magick.command [ "\"%s\"", "-posterize", print levels.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_raise_item = class Menuaction "_Raise" "lighten or darken image edges" { action x = class _result { _vislevel = 3; thk = Expression "Thickness" 3; command = Magick.command [ "\"%s\"", "-raise", print thk.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_resize_item = class Menuaction "_Resize" "resize to given width and height" { action x = class _result { _vislevel = 3; filter = Magick.filter_widget; type = Magick.ResizeType_widget; width = Scale "Width" 1 100 10; height = Scale "Height" 1 100 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", filter._flag, "-" ++ type._flag, "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "!") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_roll_item = class Menuaction "_Roll" "roll an image horizontally or vertically" { action x = class _result { _vislevel = 3; rollx = Expression "X" 3; rolly = Expression "Y" 3; command = Magick.command [ "\"%s\"", "-roll", (if rollx.expr >= 0 then "+" else "") ++ print rollx.expr ++ (if rolly.expr >= 0 then "+" else "") ++ print rolly.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotate_item = class Menuaction "_Rotate" "rotate" { action x = class _result { _vislevel = 3; angle = Scale "angle (degrees)" (-360) 360 20; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, "+distort", "SRT", print angle.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -segment, but cluster-threshold should be percentage of image area. Magick_sepia_item = class Menuaction "_Sepia tone" "simulate a sepia-toned photo" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; command = Magick.command [ "\"%s\"", "-sepia-tone", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shade_item = class Menuaction "_Shade" "shade with a distant light source" { action x = class _result { _vislevel = 3; azimuth = Scale "Azimuth (degrees)" (-360) 360 0; elevation = Scale "Elevation (degrees)" 0 90 45; command = Magick.command [ "\"%s\"", "-shade", print azimuth.value ++ "x" ++ print elevation.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_shadow_item = class Menuaction "_Shadow" "simulate a shadow" { action x = class _result { _vislevel = 3; shadowCol = Magick.generalcol_widget; opacity = Scale "Opacity (percent)" 0 100 75; sigma = Scale "Sigma" 0 30 2; // FIXME: make offsets a single widget? offsx = Scale "X-offset" (-20) 20 4; offsy = Scale "Y-offset" (-20) 20 4; arePc = Toggle "offsets are percentages" false; // FIXME: raw operation creates page offset, which vips dislikes. // So we take this futher, compositing with source. command = Magick.command [ "\"%s\"", "\"(\" +clone", "-background", "\"" ++ shadowCol._flag ++ "\"", "-shadow", concat [ "\"", print opacity.value, "x", print sigma.value, (if offsx.value >= 0 then "+" else ""), print offsx.value, (if offsy.value >= 0 then "+" else ""), print offsy.value, (if arePc then "%%" else ""), "\"" ], "\")\" +swap -background None -layers merge", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shave_item = class Menuaction "_Shave" "shave pixels from the edges" { action x = class _result { _vislevel = 3; width = Scale "Width" 0 50 10; height = Scale "Height" 0 50 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", "-shave", "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shear_item = class Menuaction "_Shear" "shear along the x-axis and/or y-axis" { action x = class _result { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-shear", print shearX.expr ++ "x" ++ print shearY.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sigmoid_item = class Menuaction "_Sigmoid" "increase or decrease mid-tone contrast sigmoidally" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; contrast = Scale "contrast" 0 30 3; midpoint = Scale "mid-point (percent)" 0 100 50; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "sigmoidal-contrast", "\"" ++ print contrast.value ++ "x" ++ print midpoint.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_sketch_item = class Menuaction "_Sketch" "simulate a pencil sketch" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; command = Magick.command [ "\"%s\"", "-sketch", print radius.value ++ "x" ++ print sigma.value ++ (if angle >= 0 then ("+" ++ print angle.value) else ""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_solarize_item = class Menuaction "_Solarize" "negate all pixels above a threshold level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-solarize", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -sparse-color needs abitrary list of {x,y,colour}. Magick_splice_item = class Menuaction "_Splice" "splice a colour into the image" { action x = class _result { _vislevel = 3; background = Magick.background_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", background._flag, gravity._flag, "-splice", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_spread_item = class Menuaction "_Spread" "displace pixels by random amount" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; amount = Expression "Amount (pixels)" 5; command = Magick.command [ "\"%s\"", virtpixback._flag, "-spread", print amount.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_statistic_item = class Menuaction "_Statistic" "replace each pixel with statistic from neighbourhood" { action x = class _result { _vislevel = 3; width = Expression "Width" 5; height = Expression "Height" 5; statisticType = Magick.StatType_widget; command = Magick.command [ "\"%s\"", "-statistic", statisticType._flag, print width.expr ++ "x" ++ print height.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = Magick.angle_widget; command = Magick.command [ "\"%s\"", "-swirl", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_thresholdMenu_item = class Menupullright "_Threshold" "make black or white" { Magick_threshold_item = class Menuaction "_Threshold" "apply black/white threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blackThreshold_item = class Menuaction "_Black threshold" "where below threshold set to black" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-black-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_whiteThreshold_item = class Menuaction "_White threshold" "where above threshold set to white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-white-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_latThreshold_item = class Menuaction "_Local Adaptive Threshold" "where above average plus offset set to white, otherwise black" { action x = class _result { _vislevel = 3; width = Expression "Width" 10; height = Expression "Height" 10; offset = Scale "Offset (percent)" (-100) 100 0; // note: "-lat" doesn't respond to channels command = Magick.command [ "\"%s\"", "-lat", concat ["\"", print width.expr, "x", print height.expr, (if offset.value >= 0 then "+" else ""), print offset.value, "%%\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_randThreshold_item = class Menuaction "_Random Threshold" "between specified limits, apply random threshold" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; low = Scale "Low threshold" 0 100 10; high = Scale "High threshold" 0 100 90; isPc = Toggle "Thresholds are percent" true; command = Magick.command [ "\"%s\"", channels._flag, "-random-threshold", "\"" ++ print low.value ++ "x" ++ print high.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } } // end ThresholdMenu_item // Note: alternatives include: // convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif Magick_tile_item = class Menuaction "_Tile" "fill given size with tiled image" { action x = class _result { _vislevel = 3; size = Magick.Size_widget; command = Magick.command [ size._flag, "tile:" ++ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_tint_item = class Menuaction "_Tint" "apply a tint" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; amount = Scale "amount (percent)" 0 100 50; command = Magick.command [ "\"%s\"", foreground._flag, "-tint", // snibgo note: although the amount is a percentage, it doesn't need "%" character. print amount.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_transparent_item = class Menuaction "_Transparent" "make this colour transparent" { action x = class _result { _vislevel = 3; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "transparent", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_trim_item = class Menuaction "_Trim" "trims away border" { action x = class _result { _vislevel = 3; fuzz = Magick.fuzz_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-trim +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_uniqueCols_item = class Menuaction "_Unique colours" "discard all but one of any pixel color" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-unique-colors", "\"%s\"" ]; _result = Magick.system command x; } } Magick_vignette_item = class Menuaction "_Vignette" "soften the edges in vignette style" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; rx = Scale "Rolloff x (percent)" 0 100 10; ry = Scale "Rolloff y (percent)" 0 100 10; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-vignette", print radius.value ++ "x" ++ print sigma.value ++ (if rx.value >= 0 then "+" else "") ++ print rx.value ++ (if ry.value >= 0 then "+" else "") ++ print ry.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_wave_item = class Menuaction "_Wave" "shear the columns into a sine wave" { action x = class _result { _vislevel = 3; amplitude = Scale "Amplitude (pixels)" 0 100 10; wavelength = Scale "Wavelength (pixels)" 0 100 10; command = Magick.command [ "\"%s\"", "-wave", print amplitude.value ++ "x" ++ print wavelength.value, "\"%s\"" ]; _result = Magick.system command x; } } nip2-8.7.1/share/nip2/compat/8.4/Colour.def0000644000175000017500000003773013351443023015021 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } CCT_colour = class Menuaction (_ "Colour from CCT") (_ "pick colour by CCT") { action = widget 6500; widget x = class _result { _vislevel = 3; T = Scale "CCT" 1800 25000 x; _result = colour_from_temp (to_real T); Colour_edit space value = widget (temp_from_colour (Colour space value)); } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } sep1 = Menuseparator; CCT_item = class Menuaction (_ "Calculate temperature") (_ "estimate CCT using the McCamy approximation") { action z = map_unary temp_from_colour z; } Colour_item = Colour_new_item.CCT_colour; } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = print_profile, has_type image && get_type image == Image_type.CMYK && has_bands image && get_bands image >= 4 = monitor_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; measure = Scale (_ "Measure area (%)") 1 100 50; // get a representative image from an arg get_image x = get_image x.value?0, is_Group x = x; _im = get_image x; sample = measure_draw (to_real pacross) (to_real pdown) (to_real measure) _im; _result = map_unary chart x { chart in = measure_sample (to_real pacross) (to_real pdown) (to_real measure) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/8.4/_joe_utilities.def0000644000175000017500000005054513351443023016564 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/8.4/_Object.def0000644000175000017500000002600513351443023015114 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/8.4/Object.def0000644000175000017500000000220513351443023014751 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/8.4/Math.def0000644000175000017500000003162513351443023014444 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_AND" "bitwise AND of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_OR" "bitwise OR of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "_XOR" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_NOT" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Bandand_item = Image_band_item.Bandand_item; Bandor_item = Image_band_item.Bandor_item; } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Skew_item = class Menuaction "S_kew" "skew of image or list or vector" { action a = map_unary skew a; } Kurtosis_item = class Menuaction "Kurtosis" "kurtosis of image or list or vector" { action a = map_unary kurtosis a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/8.4/_generate.def0000644000175000017500000000755513351443023015511 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } mkim options x y b = Image (image_new x y b (opt $format) (opt $coding) (opt $type) (opt $pixel) (opt $xoffset) (opt $yoffset)) { opt = get_option options [ $format => Image_format.UCHAR, $coding => Image_coding.NOCODING, $type => Image_type.sRGB, $pixel => 0, $xoffset => 0, $yoffset => 0 ]; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } /* Make a colour from a temperature. */ colour_from_temp T = error (_ "T out of range"), T < 1667 || T > 25000 = Colour "Yxy" [50, x, y] { // Kim et all approximation // see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation x = -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 + 0.8776956 * 10 ** 3 / T + 0.179910, T < 4000 = -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 + 0.2226347 * 10 ** 3 / T + 0.240390; y = -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + 2.18555832 * x - 0.20219638, T < 2222 = -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867, T < 4000 = 3.0817580 * x ** 3 - 5.87338670 * x ** 2 + 3.75112997 * x - 0.37001483; } temp_from_colour z = T { c = colour_transform_to Image_type.YXY (to_colour z); x = c.value?1; y = c.value?2; // McCamy's approximation, see eg. // http://en.wikipedia.org/wiki/Color_temperature#Approximation xe = 0.332; ye = 0.1858; n = (x - xe) / (y - ye); T = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33; } nip2-8.7.1/share/nip2/compat/8.4/_stdenv.def0000644000175000017500000017741713351443023015227 00000000000000/* optional args to functions */ get_option options defaults f = error (_ "unknown parameter " ++ f), hits == [] = hits?0 { hits = [v :: [n, v] <- options ++ defaults; n == f]; } /* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } bandand x = oo_unary_function bandand_op x, is_class x = foldr1 bitwise_and (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandand") { bandand_op = Operator "bandand" bandand Operator_type.COMPOUND_REWRAP false; } bandor x = oo_unary_function bandor_op x, is_class x = foldr1 bitwise_or (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandor") { bandor_op = Operator "bandor" bandor Operator_type.COMPOUND_REWRAP false; } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } skew x = oo_unary_function skew_op x, is_class x = sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x = sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "skew") { skew_op = Operator "skew" skew Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = w * h * b, is_image x' = len x'; } kurtosis x = oo_unary_function kurtosis_op x, is_class x = sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x = sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "kurtosis") { kurtosis_op = Operator "kurtosis" kurtosis Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = len x', is_list x'; = w * h * b; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_tile_cache_random x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } decode im = oo_unary_function decode_op im, is_class im = decode_im im, is_image im = error (_ "bad arguments to " ++ "decode") { decode_op = Operator "decode" decode Operator_type.COMPOUND_REWRAP false; decode_im im = im_LabQ2Lab im, get_coding im == Image_coding.LABPACK = im_rad2float im, get_coding im == Image_coding.RAD = im; } measure_draw across down measure image = mark { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; x = map (extract 0) cods; y = map (extract 1) cods; outer = mkim [$pixel => 255] sample_width sample_height 1; inner = mkim [] (sample_width - 4) (sample_height - 4) 1; patch = insert 2 2 inner outer; bg = mkim [] image.width image.height 1; mask = Image (im_insertset bg.value patch.value x y); image' = colour_transform_to Image_type.sRGB image; mark = if mask then Vector [0, 255, 0] else image'; } measure_sample across down measure image = measures { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; image' = decode image; patches = map (\p extract_area p?0 p?1 sample_width sample_height image') cods; measures = Matrix (map (map mean) (map bandsplit patches)); } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_inv hist = oo_unary_function hist_inv_op hist, is_class hist = inv hist, is_image hist = error (_ "bad arguments to " ++ "hist_inv") { hist_inv_op = Operator "hist_inv" hist_inv Operator_type.COMPOUND_REWRAP false; inv im = im_invertlut (to_matrix im''') len { // need a vertical doublemask im' = rot90 im, get_width im > 1 && get_height im == 1 = im, get_width im == 1 && get_height im > 1 = error (_ "not a hist"); len = get_height im'; // values must be scaled to 0 - 1 im'' = im' / (max im'); // add an index column on the left // again, must be in 0-1 y = ((make_xy 1 len)?1) / len; im''' = y ++ im''; } } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } reduce kernel xshr yshr image = oo_unary_function reduce_op image, is_class image = reduce_im image, is_image image = error (_ "bad arguments to " ++ "reduce") { reduce_op = Operator "reduce" reduce_im Operator_type.COMPOUND_REWRAP false; reduce_im im = out { [out] = vips_call "reduce" [im, xshr, yshr] [$kernel => kernel.value]; } } similarity interpolate scale angle image = oo_unary_function similarity_op image, is_class image = similarity_im image, is_image image = error (_ "bad arguments to " ++ "similarity") { similarity_op = Operator "similarity" similarity_im Operator_type.COMPOUND_REWRAP false; similarity_im im = out { [out] = vips_call "similarity" [im] [ $interpolate => interpolate.value, $scale => scale, $angle => angle ]; } } resize kernel xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; is_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn // everything else ... we just pass on to vips_resize() = vips_resize kernel xfac' yfac' im { vips_resize kernel hscale vscale im = out { [out] = vips_call "resize" [im, hscale] [$vscale => vscale, $kernel => kernel.value]; } } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C * * Also calculate R2, see eg.: * https://en.wikipedia.org/wiki/Coefficient_of_determination */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } ss = len xes; sx = sum xes; sy = sum yes; my = sy / ss; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; my = sy / len xes; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* One image in, one out. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } /* Two images in, one out. */ system_image2 command x1 x2 = oo_binary_function system_image2_op x1 x2, is_class x1 = oo_binary'_function system_image2_op x1 x2, is_class x2 = system x1 x2, is_image x1 && is_image x2 = error (_ "bad arguments to " ++ "system_image2") { system_image2_op = Operator "system_image2" (system_image2 command) Operator_type.COMPOUND_REWRAP false; system x1 x2 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Three images in, one out. */ system_image3 command x1 x2 x3 = oo_binary_function system_image2_op x2 x3, is_class x2 = oo_binary'_function system_image2_op x2 x3, is_class x3 = system x1 x2 x3, is_image x1 && is_image x2 && is_image x3 = error (_ "bad arguments to " ++ "system_image3") { system_image2_op = Operator "system_image2" (system_image3 command x1) Operator_type.COMPOUND_REWRAP false; system x1 x2 x3 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2, x3], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Zero images in, one out. */ system_image0 command = Image image_out { [image_out] = vips_call "system" [command] [ $out => true, $out_format => "%s.tif" ]; } hough_line w h x = oo_unary_function hough_line_op x, is_class x = hline (to_real w) (to_real h) x, is_image x = error (_ "bad arguments to " ++ "hough_line") { hough_line_op = Operator "hough_line" (hough_line w h) Operator_type.COMPOUND_REWRAP false; hline w h x = pspace { [pspace] = vips_call "hough_line" [x] [ $width => w, $height => h ]; } } hough_circle s mn mx x = oo_unary_function hough_circle_op x, is_class x = hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x = error (_ "bad arguments to " ++ "hough_circle") { hough_circle_op = Operator "hough_circle" (hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false; hcircle s mn mx x = pspace { [pspace] = vips_call "hough_circle" [x] [ $scale => s, $min_radius => mn, $max_radius => mx ]; } } mapim interp ind in = oo_binary_function mapim_op ind in, is_class ind = oo_binary'_function mapim_op ind in, is_class in = mapim_fn ind in, is_image ind && is_image in = error (_ "bad arguments to " ++ "mapim") { mapim_op = Operator "mapim" (mapim interp) Operator_type.COMPOUND_REWRAP false; mapim_fn ind im = out { [out] = vips_call "mapim" [im, ind] [$interpolate => interp]; } } perlin cell width height = Image im { [im] = vips_call "perlin" [to_real width, to_real height] [ $cell_size => to_real cell ]; } worley cell width height = Image im { [im] = vips_call "worley" [to_real width, to_real height] [ $cell_size => to_real cell ]; } nip2-8.7.1/share/nip2/compat/8.4/Histogram.def0000644000175000017500000001620513351443023015505 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "_Identity" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_inv_item = class Menuaction "In_vert" "invert a histogram" { action x = map_unary hist_inv x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Kernel_linear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; caption = Expression "Chart caption" "none"; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; xcaption = Expression "X axis caption" "none"; ycaption = Expression "Y axis caption" "none"; series_captions = Expression "Series captions" ["Band 0"]; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range ++ captions; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; captions = concat (map test caption_options) ++ [$series_captions => series_captions.expr] { caption_options = [ $caption => caption.expr, $xcaption => xcaption.expr, $ycaption => ycaption.expr ]; test x = [], value == "none" = [option_name => value] { [option_name, value] = x; } } image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/8.4/Widgets.def0000644000175000017500000000235313351443023015155 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/8.4/_types.def0000644000175000017500000007115113351443023015054 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Kernel_type = class { NEAREST_NEIGHBOUR = 0; LINEAR = 1; CUBIC = 2; LANCZOS2 = 3; LANCZOS3 = 4; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map kernel numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Linear", _ "Cubic", _ "Lanczos, two lobes", _ "Lanczos, three lobes" ]; /* And to vips enum nicknames. */ types = [ "nearest", "linear", "cubic", "lanczos2", "lanczos3" ]; } Kernel type = class { value = Kernel_type.types?type; } Kernel_linear = Kernel Kernel_type.LINEAR; Kernel_picker default = class Kernel kernel.value { _vislevel = 2; kernel = Option "Kernel" Kernel_type.descriptions default; } Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; to_image dpi = extract_bands 0 3 (graph_export_image (to_real dpi) this); } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/8.4/Matrix.def0000644000175000017500000002573113351443023015020 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = identity (identity_matrix 5); identity v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix (identity_matrix (to_real s)), to_real s != len v; = Matrix v; Matrix_vips value scale offset filename display = identity value; } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = series (mkseries 0 1 5); mkseries s t e = transpose [[to_real s, to_real s + to_real t .. to_real e]]; series v = class _result { _vislevel = 3; _s = v?0?0; _t = v?1?0 - v?0?0; _e = (last v)?0; s = Expression "Start value" _s; t = Expression "Step by" _t; e = Expression "End value" _e; _result = Matrix (mkseries s t e), to_real s != _s || to_real t != _t || to_real e != _e = Matrix v; Matrix_vips value scale offset filename display = series value; } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = square (mksquare 5); mksquare s = replicate s (take s [1, 1 ..]); square v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix_con (sum v) 0 v, len v == to_real s = Matrix_con (sum m) 0 m { m = mksquare (to_real s); } Matrix_vips value scale offset filename display = square value; } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = circle (mkcircle 3); mkcircle r = map2 (map2 pyth) xes yes { line = [-r .. r]; xes = replicate (2 * r + 1) line; yes = transpose xes; pyth a b = 1, (a**2 + b**2) ** 0.5 <= r = 0; } circle v = class _result { _vislevel = 3; r = Expression "Radius" ((len v - 1) / 2); _result = Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1 = Matrix_con (sum m) 0 m { m = mkcircle (to_real r); } Matrix_vips value scale offset filename display = circle value; } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/8.4/Tasks.def0000644000175000017500000006407313351443023014643 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; measure = Scale (_ "Measure area (%)") 1 100 50; sample = measure_draw 6 4 (to_real measure) image; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linearize from chart greyscale", "Fit intercept from chart greyscale", "Linear input, set brightness from chart", "Linear input" ] 0; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure_sample 6 4 (to_real measure) image; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix [[0, 0], [1, 1]] { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map an image though the lineariser linear x = hist_map linearising_lut.value x, mode == 0 || mode == 1 = x; // map the chart measurements though the lineariser _camera' = (to_matrix @ linear @ to_image) _camera; // solve for RGB -> XYZ // normalise: the 2nd row is what makes Y, so divide by that to // get Y in 0-1. _pinv = (transpose _camera' * _camera') ** -1; _full_M = transpose (_pinv * (transpose _camera' * _true_XYZ)); M = _full_M / scale; scale = sum _full_M.value?1; // now turn the camera to LAB and calculate dE76 _camera'' = (to_matrix @ colour_transform Image_type.XYZ Image_type.LAB @ recomb M @ multiply scale @ to_image) _camera'; _dEs = map abs_vec (_camera'' - _true_Lab).value; avg_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } // normalise brightness ... in linear mode, we optionally don't // set the brightness from the Macbeth chart norm x = x * scale, mode != 3 = x; // convert RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ norm @ recomb M @ cast_float @ linear) image.value; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ calib.norm @ recomb calib.M @ cast_float @ calib.linear) image.value; } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Kernel_linear xfactor yfactor scale_im; _offset_im = resize Kernel_linear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/8.4/Makefile.am0000644000175000017500000000062113351443023015117 00000000000000startdir = $(pkgdatadir)/compat/8.4 start_DATA = \ Math.def \ Image.def \ Magick.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _magick.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/8.4/Makefile.in0000644000175000017500000003714413417043242015144 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/8.4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/8.4 start_DATA = \ Math.def \ Image.def \ Magick.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _magick.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/8.4/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/8.4/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/8.4/_magick.def0000644000175000017500000005322113351443023015141 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate _magick.def Add 0-ary and 2-ary system Put utility funcs into a Magick class 11-Apr-2014 snibgo Added VirtualPixelBack for cases where background is only relevant when VP=Background 17-Apr-2014 snibgo Many small changes. 2-May-2014 jcupitt Added Magick.version 30-June-2014 Put single-quotes around command exe to help win 1-July-2014 Automatically fall back to gm if we can't find convert 17-July-2014 better GM support Last update: 17-July-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ /* Put these in a class to avoid filling the main namespace with IM stuff. */ Magick = class { // first gm on path, or "" gm_path = search_for "gm"; // first convert on $PATH, or "" // we check for the convert we ship first convert_path = vips_convert, vips_convert != "" = search_for "convert" { // the convert we ship with the vips binary on some platforms, or "" vips_convert = search (path_absolute convert) { vipshome = path_parse (expand "$VIPSHOME"); convert = vipshome ++ ["bin", "convert" ++ expand "$EXEEXT"]; } } use_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK; // Are we in GM or IM mode? use_gm = true, use_gm_pref && gm_path != "" = false, !use_gm_pref && convert_path != "" = false, convert_path != "" = true, gm_path != "" = error "neither IM nor GM executable found"; command_path = gm_path, use_gm = convert_path; // try to get the version as eg. [6, 7, 7, 10] // GM versions are smaller, typically [1, 3, 18] version = map parse_int (split (member ".-") version_string) { [output] = vips_call "system" ["'" ++ command_path ++ "' -version"] [$log=>true]; version_string = (split (equal ' ') output)?1, use_gm = (split (equal ' ') output)?2; } // make a command-line ... args is a [str] we join with spaces command args = "'" ++ command_path ++ "' " ++ join_sep " " args' { args' = ["convert"] ++ args, use_gm = args; } // capabilities ... different versions support different features, we // turn features on and off based on these // would probably be better to test for caps somehow has_intensity = false, use_gm = version?0 > 6 || version?1 > 7; has_channel = false, use_gm = version?0 > 6 || version?1 > 7; system0 cmd = system_image0 cmd; system cmd x = map_unary (system_image cmd) x; system2 cmd x y = map_binary (system_image2 cmd) x y; system3 cmd x y z = map_trinary (system_image3 cmd) x y z; radius_widget = Scale "Radius" 0 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle (degrees)" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; gamma_widget = Scale "Gamma" 0 10 1; colors_widget = Scale "Colors" 1 10 3; resize_widget = Scale "Resize (percent)" 0 500 100; fuzz_widget = Scale "Fuzz (percent)" 0 100 0; blur_rad_widget = Scale "Radius (0=auto)" 0 100 0; // a colour with no enclosing quotes ... use this if we know there are // some quotes at an outer level print_colour_nq triple = concat ["#", concat (map fmt triple)] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } // we need the quotes because # is the comment character in *nix print_colour triple = "\"" ++ print_colour_nq triple ++ "\""; Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; GeneralCol triple = class Colour "sRGB" triple { _flag = print_colour_nq triple; Colour_edit space triple = this.GeneralCol triple; } generalcol_widget = GeneralCol [0, 0, 0]; Background triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" false; _flag = "-background " ++ if isNone then "None" else print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Bordercol triple = class Colour "sRGB" triple { _flag = "-bordercolor " ++ print_colour triple; Colour_edit space triple = this.Bordercol triple; } bordercol_widget = Bordercol [0, 0, 0]; Mattecol triple = class Colour "sRGB" triple { _flag = "-mattecolor " ++ print_colour triple; Colour_edit space triple = this.Mattecol triple; } mattecol_widget = Mattecol [189, 189, 189]; // FIXME: Undercolour, like many others, can have alpha channel. // How does user input this? With a slider? Undercol triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" true; _flag = if isNone then "" else ("-undercolor " ++ print_colour triple); Colour_edit space triple = this.Undercol triple; } undercol_widget = Undercol [0, 0, 0]; changeCol_widget = class { _vislevel = 3; colour = GeneralCol [0, 0, 0]; fuzz = fuzz_widget; nonMatch = Toggle "change non-matching colours" false; } Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Remove", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Builtin builtin = class Option_string "Builtin" [ // See http://www.imagemagick.org/script/formats.php "rose:", "logo:", "wizard:", "granite:", "netscape:" ] builtin { _flag = builtin; Option_edit caption labels value = this.Builtin labels?value; } builtin_widget = Builtin "rose:"; channels_widget = class { // FIXME? Can we grey-out alpha when we have no alpha channel, // show CMY(K) instead of RGB(K) etc? // Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA. ChanR valueR = class Toggle "Red" valueR { _flag = "R", valueR = ""; Toggle_edit caption valueR = this.ChanR valueR; } channelR = ChanR true; ChanG valueG = class Toggle "Green" valueG { _flag = "G", valueG = ""; Toggle_edit caption valueG = this.ChanG valueG; } channelG = ChanG true; ChanB valueB = class Toggle "Blue" valueB { _flag = "B", valueB = ""; Toggle_edit caption valueB = this.ChanB valueB; } channelB = ChanB true; ChanK valueK = class Toggle "Black" valueK { _flag = "K", valueK = ""; Toggle_edit caption valueK = this.ChanK valueK; } channelK = ChanK true; ChanA valueA = class Toggle "Alpha" valueA { _flag = "A", valueA = ""; Toggle_edit caption valueA = this.ChanA valueA; } channelA = ChanA false; ChanSy valueSy = class Toggle "Sync" valueSy { _flag = ",sync", valueSy = ""; Toggle_edit caption valueSy = this.ChanSy valueSy; } channelSy = ChanSy true; _rgbka = concat [channelR._flag, channelG._flag, channelB._flag, channelK._flag, channelA._flag ]; _flag = "", _rgbka == "" || !has_channel = concat [ "-channel ", _rgbka, channelSy._flag ]; } ch_widget = channels_widget; Colorspace colsp = class Option_string "Colorspace" [ "CIELab", "CMY", "CMYK", "Gray", "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "Lab", "LCH", "LCHab", "LCHuv", "LMS", "Log", "Luv", "OHTA", "Rec601Luma", "Rec601YCbCr", "Rec709Luma", "Rec709YCbCr", "RGB", "scRGB", "sRGB", "Transparent", "XYZ", "YCbCr", "YDbDr", "YCC", "YIQ", "YPbPr", "YUV" ] colsp { _flag = colsp; Option_edit caption labels value = this.Colorspace labels?value; } colorspace_widget = Colorspace "sRGB"; Compose comp = class Option_string "Compose method" [ "Atop", "Blend", "Blur", "Bumpmap", "ChangeMask", "Clear", "ColorBurn", "ColorDodge", "Colorize", "CopyBlack", "CopyBlue", "CopyCyan", "CopyGreen", "Copy", "CopyMagenta", "CopyOpacity", "CopyRed", "CopyYellow", "Darken", "DarkenIntensity", "DivideDst", "DivideSrc", "Dst", "Difference", "Displace", "Dissolve", "Distort", "DstAtop", "DstIn", "DstOut", "DstOver", "Exclusion", "HardLight", "Hue", "In", "Lighten", "LightenIntensity", "LinearBurn", "LinearDodge", "LinearLight", "Luminize", "Mathematics", "MinusDst", "MinusSrc", "Modulate", "ModulusAdd", "ModulusSubtract", "Multiply", "None", "Out", "Overlay", "Over", "PegtopLight", "PinLight", "Plus", "Replace", "Saturate", "Screen", "SoftLight", "Src", "SrcAtop", "SrcIn", "SrcOut", "SrcOver", "VividLight", "Xor" ] comp { _flag = "-compose " ++ comp; Option_edit caption labels value = this.Compose labels?value; } compose_widget = Compose "Over"; // FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string. // FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack coordinate_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; _flag = concat [print x.expr, ",", print y.expr]; }; Distort distort = class Option_string "Distort" [ "Affine", "AffineProjection", "ScaleRotateTranslate", "SRT", "Perspective", "PerspectiveProjection", "BilinearForward", "BilinearReverse", "Polynomial", "Arc", "Polar", "DePolar", "Barrel", "BarrelInverse", "Shepards", "Resize" ] distort { _flag = distort; Option_edit caption labels value = this.Distort labels?value; } distort_widget = Distort "SRT"; Dither dither = class Option_string "Dither" [ "None", "FloydSteinberg", "Riemersma" ] dither { _flag = "-dither " ++ dither; Option_edit caption labels value = this.Dither labels?value; } dither_widget = Dither "FloydSteinberg"; Evaluate eval = class Option_string "Evaluate operation" [ "Abs", "Add", "AddModulus", "And", "Cos", "Cosine", "Divide", "Exp", "Exponential", "GaussianNoise", "ImpulseNoise", "LaplacianNoise", "LeftShift", "Log", "Max", "Mean", "Median", "Min", "MultiplicativeNoise", "Multiply", "Or", "PoissonNoise", "Pow", "RightShift", "Set", "Sin", "Sine", "Subtract", "Sum", "Threshold", "ThresholdBlack", "ThresholdWhite", "UniformNoise", "Xor" ] eval { _flag = "-evaluate " ++ eval; Option_edit caption labels value = this.Evaluate labels?value; } evaluate_widget = Evaluate "Add"; Filter filt = class Option_string "Filter" [ "default", "Bartlett", "Blackman", "Bohman", "Box", "Catrom", "Cosine", "Cubic", "Gaussian", "Hamming", "Hann", "Hermite", "Jinc", "Kaiser", "Lagrange", "Lanczos", "Lanczos2", "Lanczos2Sharp", "LanczosRadius", "LanczosSharp", "Mitchell", "Parzen", "Point", "Quadratic", "Robidoux", "RobidouxSharp", "Sinc", "SincFast", "Spline", "Triangle", "Welch" ] filt { _flag = if filt == "default" then "" else "-filter " ++ filt; Option_edit caption labels value = this.Filter labels?value; } filter_widget = Filter "default"; Function func = class Option_string "Function" [ "Polynomial", "Sinusoid", "Arcsin", "Arctan" ] func { _flag = func; Option_edit caption labels value = this.Function labels?value; } function_widget = Function "Polynomial"; // "Polynomial (a[n], a[n-1], ... a[1], a[0])", // "Sinusoid (freq, phase, amp, bias)", // "Arcsin (width, centre, range, bias)", // "Arctan (slope, centre, range, bias)" Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; ImageType imagetype = class Option_string "Image type" [ "Bilevel", "ColorSeparation", "ColorSeparationAlpha", "ColorSeparationMatte", "Grayscale", "GrayscaleAlpha", "GrayscaleMatte", "Optimize", "Palette", "PaletteBilevelAlpha", "PaletteBilevelMatte", "PaletteAlpha", "PaletteMatte", "TrueColorAlpha", "TrueColorMatte", "TrueColor" ] imagetype { _flag = "-type " ++ imagetype; Option_edit caption labels value = this.ImageType labels?value; } imagetype_widget = ImageType "TrueColor"; Intensity intensity = class Option_string "Intensity (gray conversion)" [ "Average", "Brightness", "Lightness", "MS", "Rec601Luma", "Rec601Luminance", "Rec709Luma", "Rec709Luminance", "RMS" ] intensity { _flag = "-intensity " ++ intensity, has_intensity = ""; Option_edit caption labels value = this.Intensity labels?value; } intensity_widget = Intensity "Rec709Luminance"; Interpolate interp = class Option_string "Interpolate" [ "default", "Average", "Average4", "Average9", "Average16", "Background", "Bilinear", "Blend", "Integer", "Mesh", "Nearest", "NearestNeighbor", "Spline" ] interp { _flag = if interp == "default" then "" else "-interpolate " ++ interp; Option_edit caption labels value = this.Interpolate labels?value; } interpolate_widget = Interpolate "default"; Kernel kernel = class Option_string "Kernel" [ "Unity", "Gaussian", "DoG", "LoG", "Blur", "Comet", "Binomial", "Laplacian", "Sobel", "FreiChen", "Roberts", "Prewitt", "Compass", "Kirsch", "Diamond", "Square", "Rectangle", "Disk", "Octagon", "Plus", "Cross", "Ring", "Peaks", "Edges", "Corners", "Diagonals", "LineEnds", "LineJunctions", "Ridges", "ConvexHull", "ThinSe", "Skeleton", "Chebyshev", "Manhattan", "Octagonal", "Euclidean" // FIXME: custom kernel ] kernel { _flag = kernel; Option_edit caption labels value = this.Kernel labels?value; } kernel_widget = Kernel "Unity"; ModColSp msp = class Option_string "modulate colorspace" [ "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "LCH" ] msp { _flag = "-set option:modulate:colorspace " ++ msp; Option_edit caption labels value = this.ModColSp labels?value; } ModColSp_widget = ModColSp "HSL"; MorphMeth morph = class Option_string "Method" [ "Correlate", "Convolve", "Dilate", "Erode", "Close", "Open", "DilateIntensity", "ErodeIntensity", "CloseIntensity", "OpenIntensity", "Smooth", "EdgeOut", "EdgeIn", "Edge", "TopHat", "BottomHat", "HitAndMiss", "Thinning", "Thicken", "Distance", "IterativeDistance" ] morph { _flag = morph; Option_edit caption labels value = this.MorphMeth labels?value; } morphmeth_widget = MorphMeth "Dilate"; Noise noise = class Option_string "Noise" [ "Gaussian", "Impulse", "Laplacian", "Multiplicative", "Poisson", "Random", "Uniform" ] noise { _flag = "+noise " ++ noise; Option_edit caption labels value = this.Noise labels?value; } noise_widget = Noise "Gaussian"; Pattern pattern = class Option_string "Noise" [ // See http://www.imagemagick.org/script/formats.php "bricks", "checkerboard", "circles", "crosshatch", "crosshatch30", "crosshatch45", "gray0", "gray5", "gray10", "gray15", "gray20", "gray25", "gray30", "gray35", "gray40", "gray45", "gray50", "gray55", "gray60", "gray65", "gray70", "gray75", "gray80", "gray85", "gray90", "gray95", "gray100", "hexagons", "horizontal", "horizontal2", "horizontal3", "horizontalsaw", "hs_bdiagonal", "hs_cross", "hs_diagcross", "hs_fdiagonal", "hs_horizontal", "hs_vertical", "left30", "left45", "leftshingle", "octagons", "right30", "right45", "rightshingle", "smallfishscales", "vertical", "vertical2", "vertical3", "verticalbricks", "verticalleftshingle", "verticalrightshingle", "verticalsaw" ] pattern { _flag = "pattern:" ++ pattern; Option_edit caption labels value = this.Pattern labels?value; } pattern_widget = Pattern "bricks"; ResizeType resizet = class Option_string "Resize type" [ "resize", "scale", "sample", "adaptive-resize" ] resizet { _flag = resizet; Option_edit caption labels value = this.ResizeType labels?value; } ResizeType_widget = ResizeType "resize"; Size_widget = class { _vislevel = 3; width = Expression "Width (pixels)" 64; height = Expression "Height (pixels)" 64; _flag = "-size " ++ print width.expr ++ "x" ++ print height.expr; }; StatType statt = class Option_string "Statistic type" [ "Gradient", "Maximum", "Mean", "Median", "Minimum", "Mode", "Nonpeak", "StandardDeviation" ] statt { _flag = statt; Option_edit caption labels value = this.StatType labels?value; } StatType_widget = StatType "Mean"; VirtualPixel vp = class Option_string "Virtual pixel" [ "Background", "Black", "CheckerTile", "Dither", "Edge", "Gray", "HorizontalTile", "HorizontalTileEdge", "Mirror", "None", "Random", "Tile", "Transparent", "VerticalTile", "VerticalTileEdge", "White" ] vp { _flag = "-virtual-pixel " ++ vp; _isBackground = (vp == "Background"); Option_edit caption labels value = this.VirtualPixel labels?value; } VirtualPixel_widget = VirtualPixel "Edge"; VirtualPixelBack_widget = class { virtpix = Magick.VirtualPixel_widget; background = Magick.background_widget; _flag = (if virtpix._isBackground then (background._flag ++ " ") else "") ++ virtpix._flag; } Geometry_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; AnnotGeometry_widget = class { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print shearX.expr, "x", print shearY.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; OffsetGeometry_widget = class { _vislevel = 3; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; WhxyGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; FrameGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; outbev = Expression "Outer bevel thickness" 0; inbev = Expression "Inner bevel thickness" 0; _flag = concat [print x.expr, "x", print y.expr, format outbev, format inbev] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } } nip2-8.7.1/share/nip2/compat/8.4/_predicate.def0000644000175000017500000003252613351443023015653 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Plot x = is_instanceof "Plot" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = oo_unary_function get_type_op x, is_class x = error (_ "bad arguments to " ++ "get_type") { get_type_op = Operator "get_type" get_type Operator_type.COMPOUND false; // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = oo_unary_function get_format_op x, is_class x = error (_ "bad arguments to " ++ "get_format") { get_format_op = Operator "get_format" get_format Operator_type.COMPOUND false; } has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = oo_unary_function get_bits_op x, is_class x = error (_ "bad arguments to " ++ "get_bits") { get_bits_op = Operator "get_bits" get_format Operator_type.COMPOUND false; } has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = oo_unary_function get_bands_op x, is_class x = error (_ "bad arguments to " ++ "get_bands") { get_bands_op = Operator "get_bands" get_bands Operator_type.COMPOUND false; } has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = oo_unary_function get_coding_op x, is_class x = error (_ "bad arguments to " ++ "get_coding") { get_coding_op = Operator "get_coding" get_coding Operator_type.COMPOUND false; } has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = oo_unary_function get_xres_op x, is_class x = error (_ "bad arguments to " ++ "get_xres") { get_xres_op = Operator "get_xres" get_xres Operator_type.COMPOUND false; } has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = oo_unary_function get_yres_op x, is_class x = error (_ "bad arguments to " ++ "get_yres") { get_yres_op = Operator "get_yres" get_yres Operator_type.COMPOUND false; } has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = oo_unary_function get_xoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_xoffset") { get_xoffset_op = Operator "get_xoffset" get_xoffset Operator_type.COMPOUND false; } has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = oo_unary_function get_yoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_yoffset") { get_yoffset_op = Operator "get_yoffset" get_yoffset Operator_type.COMPOUND false; } has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = oo_unary_function get_image_op x, is_class x = error (_ "bad arguments to " ++ "get_image") { get_image_op = Operator "get_image" get_image Operator_type.COMPOUND false; } has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = oo_unary_function get_number_op x, is_class x = error (_ "bad arguments to " ++ "get_number") { get_number_op = Operator "get_number" get_number Operator_type.COMPOUND false; } has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = oo_unary_function get_real_op x, is_class x = error (_ "bad arguments to " ++ "get_real") { get_real_op = Operator "get_real" get_real Operator_type.COMPOUND false; } has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = oo_unary_function get_width_op x, is_class x = error (_ "bad arguments to " ++ "get_width") { get_width_op = Operator "get_width" get_width Operator_type.COMPOUND false; } has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = oo_unary_function get_height_op x, is_class x = error (_ "bad arguments to " ++ "get_height") { get_height_op = Operator "get_height" get_height Operator_type.COMPOUND false; } has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = oo_unary_function get_left_op x, is_class x = error (_ "bad arguments to " ++ "get_left") { get_left_op = Operator "get_left" get_left Operator_type.COMPOUND false; } has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = oo_unary_function get_top_op x, is_class x = error (_ "bad arguments to " ++ "get_top") { get_top_op = Operator "get_top" get_top Operator_type.COMPOUND false; } // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/8.4/_list.def0000644000175000017500000002310313351443023014655 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* flatten x: flatten a list of lists of things into a simple list * * flatten :: [[*]] -> [*] */ flatten x = foldr flat [] x, is_list x = x { flat x sofar = foldr flat sofar x, is_list x = x : sofar; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st x) xs { x:xs = l; } /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn x xs { x:xs = l; } /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn x (foldr fn st xs) { x:xs = l; } /* foldr1 fn l: like foldr, but use the last element as the start value * * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = x, xs == [] = fn x (foldr1 fn xs) { x:xs = l; } /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn x = search xs (n + 1) { x:xs = l; } } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = x : init xs { x:xs = l; } /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = x, xs == [] = last xs { x:xs = l; } /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scanl fn st l: apply (foldl fn r) to every initial segment of a list * * scanl add 0 [1,2,3] == [1,3,6] * scanl :: (* -> ** -> *) -> * -> [**] -> [*] */ scanl fn st l = st, l == [] = st' : scanl fn st' xs { x:xs = l; st' = fn st x; } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/7.10/0000755000175000017500000000000013417043452013225 500000000000000nip2-8.7.1/share/nip2/compat/7.10/Image.def0000644000175000017500000011132113351443023014641 00000000000000Image_new_item = class Menuaction "New _Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum Image_type.type_names "Image type" "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "New _From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "New _Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } } #separator Image_number_format_item = class Menupullright "_Number Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = class _result { _vislevel = 3; // try to find the image geometry ... don't bother trying to look // inside groups though _geo = x.rect, is_Image x = Rect 0 0 100 100; l = Expression "Crop left" ((int) (_geo.left + _geo.width / 4)); t = Expression "Crop top" ((int) (_geo.top + _geo.height / 4)); w = Expression "Crop width" (max_pair 1 ((int) (_geo.width / 2))); h = Expression "Crop height" (max_pair 1 ((int) (_geo.height / 2))); _result = map_unary extract x { extract im = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; _sorted = sortc _pred [a, b]; _a' = _sorted?0; _b' = _sorted?1; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_join_item = class Menupullright "_Join" "join images together left/right or up/down" { join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Slider 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Slider 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Slider (-100) (100) 0; vshim = Slider (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list x); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 10; voverlap = Expression "Vertical overlap" 10; _result = map_unary (Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Slider 0.001 3 1; offset = Slider (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Slider 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; shadow_adjust = Slider (-15) 15 0; mid_adjust = Slider (-30) 30 0; highlight_adjust = Slider (-15) 15 0; shadow_point = Slider 0.1 0.3 0.2; mid_point = Slider 0.4 0.6 0.5; highlight_point = Slider 0.7 0.9 0.8; black = Slider 0 100 0; white = Slider 0 100 100; curve = tone_build x.format black white shadow_point mid_point highlight_point shadow_adjust mid_adjust highlight_adjust; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process in = [ in, rot90 in, rot180 in, rot270 in ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Slider (-180) 180 0; _result = map_unary process x { process image = rotate angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = map_unary straighten x { straighten arrow = rotate angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { _interp = Option_enum Interpolate.names "Interpolation" "Bilinear"; Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = _interp; _result = map_unary process x { process image = resize xfactor yfactor interp.value_thing image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; interp = _interp; _result = map_unary process x { process image = resize fac fac interp.value_thing image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = max_pair xfac yfac; min_factor = min_pair xfac yfac; fac = [max_factor, min_factor, xfac, yfac]?which; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" (map (extract 0) Interpolate.names.value) Interpolate.BILINEAR; rubber_order = Option "order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image scale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _transform { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform _result = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image _result?0; _transform = Transform _result?1 reference.width reference.height; final_error = _result?2; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first args = sortc (const is_Transform) [a, b]; i = args?0; t = args?1; t' = t.scale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; sep2 = Menuseparator; Resize_canvas_item = class Menuaction "Resize _Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_edit_header_item = class Menuaction "Change _Header" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum Image_type.type_names "Image type" (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = ramp, orientation == 0 = rot90 ramp { fn = im_grey, foption == 0 = im_fgrey; ramp = Image (fn (to_real nwidth) (to_real nheight)); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Slider 0 255 128; deviation = Slider 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Slider 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Slider 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value frequency_cutoff.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) frequency_cutoff.value ring_width.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) frequency_cutoff_x.value frequency_cutoff_y.value radius.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) frequency_cutoff.value amplitude_cutoff.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) frequency_cutoff.value ring_width.value amplitude_cutoff.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; order = Slider 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value frequency_cutoff.value amplitude_cutoff.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; order = Slider 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value frequency_cutoff.value ring_width.value amplitude_cutoff.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; order = Slider 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Slider 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Slider 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 2; ssize = Expression "Step size" 2; _result = Image (colour_transform_to (get_type start) im) { base = colour_transform_to Image_type.LAB start; step = to_real ssize; offset = to_real nstep * step; range c = [c - offset, c - offset + step ... c + offset]; mk_patch b a = image_new 150 150 3 Image_format.FLOAT Image_coding.NOCODING Image_type.LAB (Vector [base?0, a, b]) 0 0; mk_strip b = map (mk_patch b) (range base?1); mk_grid = map mk_strip (range base?2); im = imagearray_assemble 15 15 mk_grid; } } } } nip2-8.7.1/share/nip2/compat/7.10/_convert.def0000644000175000017500000003542213351443023015445 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x, is_real x || is_image x = error (_ "bad arguments to " ++ "to_matrix") { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i && get_bands i == 1 = (im_vips2mask ((double) i'')).value, is_image i && get_bands i == 3 && get_width i == 1 = error (_ "not 1 band image, or 3 band 1 column image") { split = bandsplit i; i' = im_insert (split?0) (split?1) 1 0; i'' = im_insert i' (split?2) 2 0; } } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x, is_real x || is_image x = error (_ "bad arguments to " ++ "to_image") { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = error (_ "bad arguments to " ++ "to_colour") { colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. */ to_real x = to_real x.expr, is_Expression x = to_real x.value, is_class x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); /* Try to make a list ... ungroup, basically. Recurse for subgroups. */ to_list x = map to_list x.value, is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), len parts != 2 = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, len parts != 4 = (ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } // matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by // measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ ["D93", D93_whitepoint], ["D75", D75_whitepoint], ["D65", D65_whitepoint], ["D55", D55_whitepoint], ["D50", D50_whitepoint], ["A", A_whitepoint], ["B", B_whitepoint], ["C", C_whitepoint], ["E", E_whitepoint], ["D3250", D3250_whitepoint] ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* Convert D50 Lab to XYZ. */ im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (im_header_int "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab in = im_XYZ2Lab (im_sRGB2XYZ in); im_Lab2sRGB in = im_XYZ2sRGB (im_Lab2XYZ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* Given a list of things, try to make them all the same size. Don't change * the format. Don't touch non-image things. */ size_alike l = map enlarge l { max_width = foldr (test_prop has_width get_width) 0 l; max_height = foldr (test_prop has_height get_height) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); enlarge x = embed 0 0 0 max_width max_height x, has_width x = x; } /* Given a list of things, look for 1 band objects and bump them to to n - * band objects, where n is the maximum number of bands. Don't change the * format. Don't touch non-image things. */ bands_alike l = map upband l { max_bands = foldr (test_prop has_bands get_bands) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); upband x = bandjoin (replicate max_bands x), has_bands x && get_bands x == 1 = x; } nip2-8.7.1/share/nip2/compat/7.10/Filter.def0000644000175000017500000007216013351443023015053 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; smooth_threshold = Slider 0 5 1.5; brighten_max = Slider 1 50 10; darken_max = Slider 1 50 50; flat_sharp = Slider (-2) 5 1; jaggy_sharp = Slider (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size smooth_threshold brighten_max darken_max flat_sharp jaggy_sharp in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur" "blur with tuneable parameters" { action x = class _result { _vislevel = 3; radius = Slider 1 50 1; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; _result = map_unary process x { process in = convsep mask in { mask = matrix_blur radius.value, shape.value == 0 = matrix_gaussian_blur radius.value; } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; _result = map_unary process x { process in = Image in' { conv_fn = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_convf, !separable && type == 1 = im_convsepf, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 5) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) ((guess_size + 1) / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; width = Expression "Window width" 3; height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real width * to_real height + 1) / 2)); _result = map_unary process x { process in = rank width height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; threshold = Slider 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more threshold.value) x; } } sep1 = Menuseparator; Dilate8_item = class Menuaction "Dilate _8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "Dilate _4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } Erode8_item = class Menuaction "_Erode 8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "E_rode 4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value frequency_cutoff.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) frequency_cutoff.value ring_width.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) frequency_cutoff_x.value frequency_cutoff_y.value radius.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) frequency_cutoff.value amplitude_cutoff.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) frequency_cutoff.value ring_width.value amplitude_cutoff.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; order = Slider 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) order.value frequency_cutoff.value amplitude_cutoff.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; order = Slider 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) order.value frequency_cutoff.value ring_width.value amplitude_cutoff.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; order = Slider 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) order.value frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; offset = Slider (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + offset; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Slider 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Slider 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; width = Expression "Window width" 20; height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local width.expr height.expr in; } } } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Slider (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Slider (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Slider (-1) 1 0; shift = Slider (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Slider (-1) 1 0; shift = Slider (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Slider (-1) 1 0; hshift = Slider (-1) 1 0; vshift = Slider (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Slider_blend_item = class Menuaction "_Slider Blend" "blend two objects together with a slider" { action a b = class _result { _vislevel = 3; blend = Slider 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - blend) + im2 * blend; } } } Image_blend_item = class Menuaction "_Image Blend" "use an image to blend two objects" { action a b c = map_trinary process a b c { process a b c = blend condition in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; args' = sortc compare [a, b, c]; condition = args'?0; in1 = args'?1; in2 = args'?2; } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Slider 0 1 0.5; blend_width = Slider 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ "Green over Red", "Blue over Red", "Red over Green", "Red over Blue", "Blue over Green", "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Slider 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first args = sortc (const (is_colour_type @ get_type)) [a, b]; mono = args?0; colour = args?1; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Slider 0 (image.bands - 1) 0; display = Option "Display as" [ "Grey", "Green over Red", "Blue over Red", "Red over Green", "Red over Blue", "Blue over Green", "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider f t v = class scope.Slider f t ((int) v) { Slider = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Slider 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; radius = Slider 0 50 5; highlights = Slider 0 100 95; glow = Slider 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur radius.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; shadow_x = Slider (-50) 50 5; shadow_y = Slider (-50) 50 5; shadow_softness = Slider 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = shadow_softness.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect shadow_x.value shadow_y.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } nip2-8.7.1/share/nip2/compat/7.10/_joe_extra.def0000644000175000017500000003120113351443023015734 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Slider 0.1 1 0.5; middle_section = Slider 0.1 1 0.2; blend_fraction = Slider 0.1 0.9 0.1; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height that * is extracted to produce each of the particular regions. */ corner_section = Slider 0.1 1 0.5; middle_section = Slider 0.1 1 0.3; blend_fraction = Slider 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Slider 0.1 1 0.4; edge_section = Slider 0.1 1 0.1; middle_section = Slider 0.1 0.5 0.3; blend_fraction = Slider 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount color" false; ls = Expression "Lower mount section bigger by (cm)" 0; colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 6; control_selection mask im no = (if mask then im * 1.2 else im * 1), no == 0 = (if mask then im * 0.8 else im * 1), no == 1 = (if mask then 0 else im), no == 2 = (if mask then 255 else im), no == 3 = (if mask then im else 0), no == 4 = (if mask then im else 255), no == 5 = mask; Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Slider 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = a.image; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = ((pt_list.value)?0).image; } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize f1 1 1 b1 {b1 = resize 1 f2 1 b;} } } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.10/Format.def0000644000175000017500000000225413351443023015053 00000000000000Format_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Format_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = Group x; } Format_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = x.value; } #separator Format_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Format_assemble_item = class Menuaction "_Assemble Objects" "assemble a list (or group) of objects into a single object" { action x = ass x.value, is_Group x = ass x { ass x = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = map_unary ass x, is_list x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/7.10/Colour.def0000644000175000017500000003545013351443023015072 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; _L = default_value?0; _a = default_value?1; _b = default_value?2; lightness = Slider 0 100 _L; ab_slice = Image (lab_slice size lightness.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [lightness.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } } #separator Colour_convert_item = class Menupullright (_ "_Convert To") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Convert to") (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Tag as") (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Colour Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum Whitepoints (_ "Old whitepoint") "D65"; new_white = Option_enum Whitepoints (_ "New whitepoint") "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum Render_intent.names (_ "Render intent") (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; green_red = Slider (-20) 20 0; blue_yellow = Slider (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, green_red.value, blue_yellow.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; hue = Slider 0 360 0; saturation = Slider 0.01 5 1; brightness = Slider 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [bv, sv, 1] + Vector [0, 0, hv]; bv = brightness.value; sv = saturation.value; hv = hue.value; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; dE_threshold = Slider 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < dE_threshold { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_image_to_colour_item = class Menuaction (_ "Im_age to Colour") (_ "convert image to colour") { action x = map_unary test x { test x = to_colour x, is_Image x = to_colour (Image pixel), is_Mark x = error (_ "Colour_from_image: arg not Image or Mark: " ++ print x) { pixel = extract_area x.left x.top 1 1 x; } } } Colour_colour_to_image_item = class Menuaction (_ "C_olour to _Image") (_ "convert colour to image") { action x = class _result { _vislevel = 3; width = Expression (_ "Width of image to make") 64; height = Expression (_ "Height of image to make") 64; _result = map_unary (Image @ build) x { build in = image_new (to_real width) (to_real height) 3 Image_format.FLOAT Image_coding.NOCODING (get_type in) in 0 0; } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; _result = map_unary chart x { chart in = measure 0 0 in.width in.height (to_real pacross) (to_real pdown) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make S_ynthetic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.10/_joe_utilities.def0000644000175000017500000004710313351443023016634 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if_then_else mask im 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} } ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = im_header_int "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = im_header_int "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; } ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = im_header_int "Xsize" (get_image im), dir == 0 = im_header_int "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); } ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = line.image; //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_instanceof "Group" pt_list; pt_l = pt_list.value, group_check = pt_list; im = (pt_l?0).image; im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; } ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; } nip2-8.7.1/share/nip2/compat/7.10/Math.def0000644000175000017500000002622013351443023014513 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_And" "bitwise and of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_Or" "bitwise or of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "E_xclusive Or" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_Not" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary if_then_else a b c; } Band_or_item = class Menuaction "Band O_r" "or the bands of an image together" { action im = map_unary (foldr1 bitwise_or @ bandsplit) im; } Band_and_item = class Menuaction "Band A_nd" "and the bands of an image together" { action im = map_unary (foldr1 bitwise_and @ bandsplit) im; } } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = n ? x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = a ++ b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = a : x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Mean_item = class Menuaction "_Mean" "mean value" { action a = map_unary mean a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Stats_item = class Menuaction "_Many Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "Position of M_aximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "Position of M_inimum" "position of minimum in object" { action a = map_unary minpos a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.10/_generate.def0000644000175000017500000000515613351443023015560 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black (to_real w) (to_real h) (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = Matrix_con mask_g_sum 0 [mask_g_line] { mask_g = im_gauss_imask (radius / 3) 0.2; mask_g_line = mask_g.value?(mask_g.height / 2); mask_g_sum = foldr1 add mask_g_line; } /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (foldr1 add mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } nip2-8.7.1/share/nip2/compat/7.10/_stdenv.def0000644000175000017500000011337313351443023015272 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; join a b = a ++ b; subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; if_then_else a b c = if a then b else c; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error "unimplemented vector operation" { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } /* Macbeth chart patch names. */ _macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = im_header_int "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "mean") { mean_op = Operator "mean" mean_object Operator_type.COMPOUND false; mean_object x = im_avg x, is_image x = mean_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "mean"); mean_list l = s / n { totals = sum l; n = totals?0; s = totals?1; } // return [n, sum] for a list of numbers, or a list of list of num // etc. sum x = foldr accumulate [0, 0] x { accumulate x sofar = [n + 1, x + s], is_real x = [n + n', s + s'], is_list x = error "mean_list: not real or [real]" { n = sofar?0; s = sofar?1; sub_acc = sum x; n' = sub_acc?0; s' = sub_acc?1; } } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation_object Operator_type.COMPOUND false; deviation_object x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation"); deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { totals = sum_sum2_list l; n = totals?0; s = totals?1; s2 = totals?2; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { n = sofar?0; s = sofar?1; s2 = sofar?2; sub_acc = sum_sum2_list x; n' = sub_acc?0; s' = sub_acc?1; s2' = sub_acc?2; } } } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs_object Operator_type.COMPOUND false; abs_object x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs"); abs_list l = (foldr1 add (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec_object Operator_type.COMPOUND false; abs_vec_object x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (Vector (map abs_vec_list x)), is_matrix x = error (_ "bad arguments to " ++ "abs_vec"); abs_vec_list l = (foldr1 add (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (foldr1 add (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_matrix x, is_list x && is_list (hd x) = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose_object Operator_type.COMPOUND_REWRAP false; transpose_object x = transpose_matrix x, is_matrix x = transpose_image x, is_image x = error (_ "bad arguments to " ++ "transpose"); transpose_matrix l = [], l' == [] = (map hd l') : (transpose_matrix (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; rot90 x = oo_unary_function rot90_op x, is_class x = im_rot90 x, is_image x = error (_ "bad arguments to " ++ "rot90") { rot90_op = Operator "rot90" rot90_object Operator_type.COMPOUND_REWRAP false; rot90_object x = rot90_matrix x, is_matrix x = im_rot90 x, is_image x = error (_ "bad arguments to " ++ "rot90"); // slow, but what the heck // avoid im_rotate_dmask90(), it can only do square odd-sided matricies rot90_matrix l = apply_matrix_as_image im_rot90 l; } rot180 x = oo_unary_function rot180_op x, is_class x = im_rot180 x, is_image x = error (_ "bad arguments to " ++ "rot180") { rot180_op = Operator "rot180" rot180_object Operator_type.COMPOUND_REWRAP false; rot180_object x = rot180_matrix x, is_matrix x = im_rot180 x, is_image x = error (_ "bad arguments to " ++ "rot180"); // slow, but what the heck rot180_matrix l = apply_matrix_as_image im_rot180 l; } rot270 x = oo_unary_function rot270_op x, is_class x = im_rot270 x, is_image x = error (_ "bad arguments to " ++ "rot270") { rot270_op = Operator "rot270" rot270_object Operator_type.COMPOUND_REWRAP false; rot270_object x = rot270_matrix x, is_matrix x = im_rot270 x, is_image x = error (_ "bad arguments to " ++ "rot270"); // slow, but what the heck rot270_matrix l = apply_matrix_as_image im_rot270 l; } image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (im_header_double "Xres" x) (im_header_double "Yres" x) (im_header_int "Xoffset" x) (im_header_int "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (im_header_int "Type" x) (im_header_double "Xres" x) (im_header_double "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } rotquad x = oo_unary_function rotquad_op x, is_class x = im_rotquad x, is_image x = error (_ "bad arguments to " ++ "rotquad") { rotquad_op = Operator "rotquad" rotquad_object Operator_type.COMPOUND_REWRAP false; rotquad_object x = rotquad_matrix x, is_matrix x = im_rotquad x, is_image x = error (_ "bad arguments to " ++ "rotquad"); rotquad_matrix l = apply_matrix_as_image im_rotquad l; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_cache x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } fliptb x = oo_unary_function fliptb_op x, is_class x = im_flipver x, is_image x = error (_ "bad arguments to " ++ "fliptb") { fliptb_op = Operator "fliptb" fliptb_object Operator_type.COMPOUND_REWRAP false; fliptb_object x = fliptb_matrix x, is_matrix x = im_flipver x, is_image x = error (_ "bad arguments to " ++ "fliptb"); fliptb_matrix l = reverse l; } fliplr x = oo_unary_function fliplr_op x, is_class x = im_fliphor x, is_image x = error (_ "bad arguments to " ++ "fliplr") { fliplr_op = Operator "fliplr" fliplr_object Operator_type.COMPOUND_REWRAP false; fliplr_object x = fliplr_matrix x, is_matrix x = im_fliphor x, is_image x = error (_ "bad arguments to " ++ "fliplr"); fliplr_matrix l = map reverse l; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_real_list x || is_matrix x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_matrix x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_real_list x || is_matrix x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_matrix x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } recomb matrix image = colour_unary recomb_op image { recomb_op x = im_recomb x (to_matrix matrix), is_image x = error (_ "bad arguments to " ++ "recomb"); } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (converse cons [] @ converse subscript x') obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = im_header_int "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend") { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { then_part = x?0; else_part = x?1; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = x, is_image x = x.value, is_Image x = black + x { black = im_black target_width target_height target_bands; } then_image = to_image then_part; else_image = to_image else_part; then_image' = clip2fmt target_format then_image; else_image' = clip2fmt target_format else_image; resized = size_alike [cond, then_image', else_image']; blend_result_image = image_set_type target_type (im_blend resized?0 resized?1 resized?2); } } insert x y small big = oo_binary_function insert_op small big, is_class small = oo_binary'_function insert_op small big, is_class big = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (_ "bad arguments to " ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_similarity image (cos angle) (sin angle) 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" rotate Operator_type.COMPOUND_REWRAP false; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = im_header_int "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { image = (unsigned char) im_mask2vips (Matrix m2); m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x // work for groups too (convenient) = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } hist_find image = oo_unary_function hist_find_op image, is_class image = im_histgr image (-1), is_image image = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" hist_find Operator_type.COMPOUND_REWRAP false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { hist_map_op = Operator "hist_map" hist_map Operator_type.COMPOUND_REWRAP false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; sum = foldr1 add; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } resize xfac yfac interp image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // upscale by any factor, nearest neighbour // can't really do this right ... upscale by integer part, then // bilinear to exact size = scale (break xfac')?1 (break yfac')?1 (im_zoom im (break xfac')?0 (break yfac')?0), xfac' >= 1 && yfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // downscale by any factor, nearest neighbour // can't really do this right ... downscale by integer part, // then bilinear to exact size = scale (1 / (break rxfac')?1) (1 / (break ryfac')?1) (im_subsample im (break rxfac')?0 (break ryfac')?0), rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // upscale by any factor, bilinear = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 && interp == Interpolate.BILINEAR // downscale by any factor, bilinear // block shrink by integer factor, then bilinear resample to // exact = scale (1 / (break rxfac')?1) (1 / (break ryfac')?1) (im_shrink im (break rxfac')?0 (break ryfac')?0), rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.BILINEAR = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate.names.lookup 1 0 interp ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // binlinear resize scale xfac yfac im = im_affine im xfac 0 0 yfac 0 0 0 0 (rint (get_width im * xfac)) (rint (get_height im * yfac)); } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (tone_analyse s m h sa ma ha) Operator_type.COMPOUND_REWRAP false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Image @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (converse remainder base) (takewhile (not_equal 0) (iterate (converse idiv base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); idiv a b = (int) (a / b); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map a 3-ary function over three objects. */ map_trinary fn a b c = wrap (map3 (map_trinary fn) a' b' c'), is_list a' && is_list b' && is_list c' = wrap (map2 (map_trinary fn a') b' c'), is_list b' && is_list c' = wrap (map2 (map_trinary (converse31 fn) b') a' c'), is_list a' && is_list c' = wrap (map2 (map_trinary (converse32 fn) c') a' b'), is_list a' && is_list b' = wrap (map (map_trinary fn a' b') c'), is_list c' = wrap (map (map_trinary (converse32 fn) a' c') b'), is_list b' = wrap (map (map_trinary (converse34 fn) b' c') a'), is_list a' = fn a b c { converse31 fn a b c = fn b a c; converse32 fn a b c = fn c a b; converse33 fn a b c = fn a c b; converse34 fn a b c = fn b c a; a' = a.value, is_Group a = a; b' = b.value, is_Group b = b; c' = c.value, is_Group c = c; wrap = Group, is_Group a || is_Group b || is_Group c = id; } /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = wrap (map2 (map_binary fn) a' b'), is_list a' && is_list b' = wrap (map (map_binary fn a') b'), is_list b' = wrap (map (map_binary (converse fn) b') a'), is_list a' = fn a b { a' = a.value, is_Group a = a; b' = b.value, is_Group b = b; wrap = Group, is_Group a || is_Group b = id; } /* Map a 1-ary function over an object. */ map_unary fn a = wrap (map (map_unary fn) a'), is_list a' = fn a { a' = a.value, is_Group a = a; wrap = Group, is_Group a = id; } /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. height] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Calculate padding ... pad up to tile_size pixel boundary. */ sx = tile_width' + (width - width % hstep); sy = tile_height' + (height - height % vstep); /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. width] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } nip2-8.7.1/share/nip2/compat/7.10/Histogram.def0000644000175000017500000000555413351443023015566 00000000000000Hist_new_item = class Menuaction "_New Histogram" "make a new histogram" { action = class _result { _vislevel = 3; depth = Option "Depth" ["8 bit", "16 bit"] 0; black = Slider 0 100 0; white = Slider 0 100 100; shadow_point = Slider 0.1 0.3 0.2; mid_point = Slider 0.4 0.6 0.5; highlight_point = Slider 0.7 0.9 0.8; shadow_adjust = Slider (-15) 15 0; mid_adjust = Slider (-30) 30 0; highlight_adjust = Slider (-15) 15 0; _result = tone_build fmt black white shadow_point mid_point highlight_point shadow_adjust mid_adjust highlight_adjust { fmt = [Image_format.UCHAR, Image_format.USHORT]?depth; } } } Hist_find_item = class Menupullright "_Find Histogram" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } } Hist_map_item = class Menuaction "_Map Histogram" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { args = sortc (const is_hist) [a, b]; im = args?0; hist = args?1; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Cumulativise Histogram" "form cumulative histogram from frequency histogram" { action x = map_unary hist_cum x; } Hist_norm_item = class Menuaction "N_ormalise Histogram" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_match_item = class Menuaction "Ma_tch Histogram" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (image_set_type Image_type.HISTOGRAM @ Image) [ im_profile image.value 0, im_profile image.value 1, im_profile (fliptb image.value) 0, im_profile (fliplr image.value) 1 ]?edge; } } } Hist_graph_item = class Menuaction "_Slice Image" "slice an image along a guide" { action x = map_unary process x { process guide = image_set_type Image_type.HISTOGRAM slice { slice = extract_area 0 guide.top guide.width 1 guide.image, is_HGuide guide = extract_area guide.left 0 1 guide.height guide.image; } } } nip2-8.7.1/share/nip2/compat/7.10/Widgets.def0000644000175000017500000000215313351443023015227 00000000000000Widget_slider_item = class Menuaction "_Slider" "make a new slider widget" { icon = "nip-slider-16.png"; action = Slider 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } nip2-8.7.1/share/nip2/compat/7.10/_types.def0000644000175000017500000010575213351443023015135 00000000000000 /* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0, 1, 2 or 3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_Matrix_width w = [is_Matrix_width, _ "Matrix, " ++ print w ++ _ " columns"] { is_Matrix_width x = is_Matrix x && x.width == w; } check_colour_space = [is_colour_space, "colour_space"]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide or VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down a bit. */ check_args x = error message, badargs != [] || badalls != [] = check_args x.super, x.super != [] = x { argcheck = x._check_args; allcheck = x._check_all; // join two strings up with a separator string join_sep j a b = a ++ j ++ b; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad arguments to " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "usage" ++ "\n" ++ indent ++ usage ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make usage note usage = x.name ++ " " ++ foldr (join_sep " ") [] (map (extract 1) argcheck); // make arg type notes arg_types = foldr (join_sep "\n") [] (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = foldr (join_sep "\n") [] all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; /* Provide a fallback for class == thing ... just use pointer * equality. */ oo_binary_table op x = [ [pointer_equal this x, op.op_name == "equal" || op.op_name == "equal'"], [not_pointer_equal this x, op.op_name == "not_equal" || op.op_name == "not_equal'"] ]; oo_unary_table op = []; } /* A list of things. Do automatic iteration of unary and binary operators on us. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [this.Group (map2 (apply2 op) value x.value), is_Group x], [this.Group (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [this.Group (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [if value then x?0 else x?1, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real ... handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binary op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binary op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binary op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binary op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unary op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unary op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binary op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binary op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binary op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unary op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [len value == 3, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = im_header_int "Type" im; bands = im_header_int "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.value_name colour.expr { _vislevel = 3; space = Option_enum Image_type.colour_spaces "Colour space" default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Compat. slider type. */ Slider = Scale ""; /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } Option_enum enum caption value_name = class Option caption enum.names (index (equal value_name) enum.names) { // corresponding thing value_thing = enum.get_thing value_name; Option_edit caption labels value = this.Option_enum enum caption (enum.names ? value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NOCODING = 0; COLQUANT = 1; LABPACK = 2; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* present col x: is there an x in column col */ present col x = member (map (extract col) value) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (map (extract from) value); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = map (extract 0) value; things = map (extract 1) value; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { FOURIER = 24; YXY = 23; sRGB = 22; LABS = 21; LCH = 19; UCS = 18; RGB = 17; LABQ = 16; CMYK = 15; CMC = 14; LAB = 13; XYZ = 12; LUT = 11; HISTOGRAM = 10; POWER_SPECTRUM = 9; BLUE_ONLY = 8; GREEN_ONLY = 7; RED_ONLY = 6; YUV = 5; IR = 4; XRAY = 3; LUMINACE = 2; B_W = 1; MULTIBAND = 0; /* Table to get names <-> numbers. */ type_names = Enum [ ["FOURIER", FOURIER], ["YXY", YXY], ["sRGB", sRGB], ["LABS", LABS], ["LCH", LCH], ["UCS", UCS], ["RGB", RGB], ["LABQ", LABQ], ["CMYK", CMYK], ["CMC", CMC], ["LAB", LAB], ["XYZ", XYZ], ["LUT", LUT], ["HISTOGRAM", HISTOGRAM], ["POWER_SPECTRUM", POWER_SPECTRUM], ["BLUE_ONLY", BLUE_ONLY], ["GREEN_ONLY", GREEN_ONLY], ["RED_ONLY", RED_ONLY], ["YUV", YUV], ["IR", IR], ["XRAY", XRAY], ["LUMINACE", LUMINACE], ["B_W", B_W], ["MULTIBAND", MULTIBAND] ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ ["sRGB", sRGB], ["Lab", LAB], ["LCh", LCH], ["XYZ", XYZ], ["Yxy", YXY], ["UCS", UCS] ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ ["Mono", B_W], ["sRGB", sRGB], ["Lab", LAB], ["LabQ", LABQ], ["LabS", LABS], ["LCh", LCH], ["XYZ", XYZ], ["Yxy", YXY], ["UCS", UCS] ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = im_header_double "Xres" value; yres = im_header_double "Yres" value; xoffset = im_header_int "Xoffset" value; yoffset = im_header_int "Yoffset" value; filename = im_header_string "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], // image ++ image is slightly different ... we want to // sizealike, but we must not bandalike [wrap (op.fn (get_image resized?0) (get_image resized?1)), has_image x && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], // arithmetic and reational binops between image resize // and band_alike images to match [wrap (op.fn (get_image rebanded?0) (get_image rebanded?1)), has_image x && (op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL)], // other op types don't resize [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], [wrap (op.fn this.value x), true] ] ++ super.oo_binary_table op x { // wrap the result with this ... only skip rewrap for COMPOUND wrap = id, op.type == Operator_type.COMPOUND = this.Image; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } then_part = x?0; else_part = x?1; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = x, is_image x = x.value, is_Image x = black + x { black = im_black width height target_bands; } then_image = to_image then_part; else_image = to_image else_part; then_image' = clip2fmt target_format then_image; else_image' = clip2fmt target_format else_image; ite_resized = size_alike [value, then_image', else_image']; ite_result_image = image_set_type target_type (if ite_resized?0 then ite_resized?1 else ite_resized?2); resized = size_alike [this, x]; rebanded = bands_alike resized; } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; /* Table to map interpol numbers to descriptive strings */ names = Enum [ [_ "Nearest neighbour", NEAREST_NEIGHBOUR], [_ "Bilinear", BILINEAR], [_ "Bicubic", BICUBIC] ]; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ [_ "Perceptual", PERCEPTUAL], [_ "Relative", RELATIVE], [_ "Saturation", SATURATION], [_ "Absolute", ABSOLUTE] ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} nip2-8.7.1/share/nip2/compat/7.10/Matrix.def0000644000175000017500000002141213351443023015064 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; sigma = Slider 0.001 10 1; min_amplitude = Slider 0 1 0.2; integer = Toggle "Integer" false; _result = fn sigma.value min_amplitude.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; sigma = Slider 0.001 10 1.5; min_amplitude = Slider 0 1 0.1; integer = Toggle "Integer" false; _result = fn sigma.value min_amplitude.value { fn = im_log_imask, integer = im_log_dmask; } } } } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { extract n f = take (to_real n) @ drop (to_real f); Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process mat = mat.Matrix_base (extract number first mat.value); } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = mat.Matrix_base (map (extract number first) mat.value); } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 (extract 1) [0..] mat.value), which == 0 = mat.Matrix_base (map2 (extract 1) [mat.width - 1, mat.width - 2 .. 0] mat.value); } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // insert a thing in a list at position first insert first x l = take first l ++ x ++ drop first l; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process mat = mat.Matrix_base (insert (to_real first) rows mat.value) { row = replicate mat.width (to_real item); rows = replicate (to_real number) row; } } } } Columns_item = class Menuaction "_Columns" "remove columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process mat = mat.Matrix_base (map (insert (to_real first) cells) mat.value) { cells = replicate (to_real number) (to_real item); } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process mat = mat.Matrix_base (delete first number mat.value); } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process mat = mat.Matrix_base (map (delete first number) mat.value); } } } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_convert_to_image_item = class Menuaction "Matrix to I_mage" "convert matrix to image" { action x = class _result { _vislevel = 3; conversion = Option "Convert to" [ "Monochrome image, same size as matrix", "Multiband image, each row becomes a pixel" ] 0; _result = map_unary process x { process mat = Image im, conversion == 0 = Image joinup { im = im_mask2vips mat; joinup = bandjoin (map extract_column [0 .. mat.width - 1]); extract_column n = extract_area n 0 1 mat.height im; } } } } Matrix_from_image_item = class Menuaction "Image to M_atrix" "convert image to matrix" { action x = map_unary to_matrix x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix_width 2] ]; _vislevel = 3; gwidth = Expression "Graph size across (pixels)" 512; gheight = Expression "Graph size down (pixels)" 512; plot_colour = Colour_picker "Lab" [80, -80, 80]; xmin = Expression "X range minimum" (foldr1 min_pair (map (extract 0) x.value)); xmax = Expression "X range maximum" (foldr1 max_pair (map (extract 0) x.value)); ymin = Expression "Y range minimum" (foldr1 min_pair (map (extract 1) x.value)); ymax = Expression "Y range maximum" (foldr1 max_pair (map (extract 1) x.value)); axies = Toggle "Draw axies" true; mark = Mark this p?0 p?1 { p = _to_image x.value?0; } mark_hint = "Mark is at position:"; mark_position = _from_image [mark.left, mark.top]; // geometry _xrange = to_real xmax - to_real xmin; _yrange = to_real ymax - to_real ymin; _xscale = to_real gwidth / _xrange; _yscale = to_real gheight / _yrange; // map an [x,y] point into the image coordinates _to_image p = [(p?0 - to_real xmin) * _xscale, to_real gheight - (p?1 - to_real ymin) * _yscale]; // map an [x,y] point from image cods back to real cods _from_image p = [p?0 / _xscale + to_real xmin, (to_real gheight - p?1) / _yscale + to_real ymin]; _result = Image (foldr plot background' x.value) { // colourspace we are drawing in space = Image_type.colour_spaces.lookup 0 1 plot_colour.colour_space; plot_image_new width height pixel = image_new width height 3 Image_format.FLOAT Image_coding.NOCODING space pixel 0 0; // background background = plot_image_new (to_real gwidth) (to_real gheight) 0; // mark we plot mark_width = max_pair 1 (to_real gwidth / 100); mark_height = max_pair 1 (to_real gheight / 100); mark = plot_image_new mark_width mark_height plot_colour; // draw axies on background background' = drawxy, axies = background { // colour we draw axies in ax_col = colour_transform_to space (Colour "Lab" [100, 0, 0]); // axies xaxis = plot_image_new (to_real gwidth) 1 ax_col; yaxis = plot_image_new 1 (to_real gheight) ax_col; origin = _to_image [0, 0]; drawx = insert_noexpand 0 origin?1 xaxis background; drawxy = insert_noexpand origin?0 0 yaxis drawx; } // plot a single point on an image plot p im = insert_noexpand (x - mark_width / 2) (y - mark_height / 2) mark im { p' = _to_image p; x = p'?0; y = p'?1; } } } } nip2-8.7.1/share/nip2/compat/7.10/Tasks.def0000644000175000017500000005566313351443023014724 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; brightness = Slider 0 32767 prefs.VIDEO_BRIGHTNESS; colour = Slider 0 32767 prefs.VIDEO_COLOUR; contrast = Slider 0 32767 prefs.VIDEO_CONTRAST; hue = Slider 0 32767 prefs.VIDEO_HUE; frames_hint = "Average this many frames:"; frames = Slider 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value brightness.value colour.value contrast.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Slider 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; args = sortc larger [a, b]; image = args?0; patch = args?1; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = im_measure image.value 0 0 image.width image.height 6 4; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'); // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it linearising_lut = Image _linear_lut; // map the original image through the lineariser to // get linear 0-1 RGB image _image' = hist_map linearising_lut.value image.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ cast_float @ recomb M) _image'; // measure again and compute dE76 _camera'' = im_measure _result.value 0 0 image.width image.height 6 4; _dEs = map abs_vec (map Vector (_camera'' - _true_Lab).value); final_dE76 = mean (Vector _dEs); _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = _macbeth_names ? _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)"; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first args = sortc (const (is_instanceof calib_name)) [a, b]; calib = args?1; image = args?0; // map the original image through the lineariser to get // linear 0-1 RGB image image' = hist_map calib.linearising_lut image; // convert linear RGB camera to Lab result = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M image')); } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "building image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", len images != 2 = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = land (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Slider 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; blend_width = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 blend_width.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) blend_width.value { sorted = mosaic_sort mosaic_sort_lr [a, b]; a' = sorted?0; b' = sorted?1; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; blend_width = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 blend_width.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) blend_width.value { sorted = mosaic_sort mosaic_sort_tb [a, b]; a' = sorted?0; b' = sorted?1; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Slider 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; blend_width = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 blend_width.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top blend_width.value { sorted = mosaic_sort mosaic_sort_lr [a, b, c, d]; a' = sorted?0; b' = sorted?1; c' = sorted?2; d' = sorted?3; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; blend_width = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 blend_width.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top blend_width.value { sorted = mosaic_sort mosaic_sort_tb [a, b, c, d]; a' = sorted?0; b' = sorted?1; c' = sorted?2; d' = sorted?3; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if_then_else m_control im_in 0; _control_meanmax = so_meanmax _control_im; _group_check = is_instanceof "Group" m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Slider 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_instanceof "Group" m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize xfactor yfactor 1 scale_im; _offset_im = resize xfactor yfactor 1 offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.scale_cutoff, r1 >= Options.scale_cutoff]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. scale_cutoff = Slider 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = class Menuaction "_Adjust Tone Curve" "adjust tone curve on L*" { action x = class _result { _vislevel = 3; auto = Option "Set black and white point" [ "Manually", "Automatically from image histogram" ] 0; black = Slider 0 100 0; white = Slider 0 100 100; shadow_point = Slider 0.1 0.3 0.2; mid_point = Slider 0.4 0.6 0.5; highlight_point = Slider 0.7 0.9 0.8; shadow_adjust = Slider (-15) 15 0; mid_adjust = Slider (-30) 30 0; highlight_adjust = Slider (-15) 15 0; preview_curve = Image (im_tone_build black.value white.value shadow_point.value mid_point.value highlight_point.value shadow_adjust.value mid_adjust.value highlight_adjust.value); _result = map_unary process x { process image = tone_map curve lab { lab = colour_transform_to Image_type.LABQ image; curve = preview_curve, auto == 0 = tone_analyse shadow_point mid_point highlight_point shadow_adjust mid_adjust highlight_adjust lab; } } } } Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; // strange order forced on us by need to keep numbering backwards // compatible though 7.10 target_dpi = Option "Sharpen for print at" [ "300 dpi", "150 dpi", "75 dpi", "400 dpi" ] 0; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.10/Makefile.am0000644000175000017500000000052313351443023015174 00000000000000startdir = $(pkgdatadir)/compat/7.10 start_DATA = \ Colour.def \ _convert.def \ Filter.def \ Format.def \ _generate.def \ Histogram.def \ Image.def \ _joe_extra.def \ _joe_utilities.def \ _list.def \ Math.def \ Matrix.def \ _predicate.def \ _stdenv.def \ Tasks.def \ _types.def \ Widgets.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.10/Makefile.in0000644000175000017500000003705113417043241015214 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.10 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.10 start_DATA = \ Colour.def \ _convert.def \ Filter.def \ Format.def \ _generate.def \ Histogram.def \ Image.def \ _joe_extra.def \ _joe_utilities.def \ _list.def \ Math.def \ Matrix.def \ _predicate.def \ _stdenv.def \ Tasks.def \ _types.def \ Widgets.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.10/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.10/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.10/_predicate.def0000644000175000017500000002077713351443023015734 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true of character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && land (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, land (map is_obj l) = true, land (map is_list l) && land (map (not @ is_obj) l) && land (map is_rectangular l) && len l > 0 && land (map (equal (hd lengths)) (tl lengths)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; lengths = map len l; } /* is_matrix l: is l a list of lists of real numbers, all the same length */ is_matrix l = is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [] = is_matrix l && len l == len (hd l); /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [] = is_matrix l && (len l) % 2 == 1 && (len (l?0)) % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && (len l) % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_Image x = is_instanceof "Image" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Slider x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && land (map xy l) { xy l = is_real_list l && len l == 2; } /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.B_W, bands == 1 = type, bands == 3 && is_colorimetric = Image_type.sRGB, bands == 3 && !is_colorimetric = Image_type.MULTIBAND, bands != 3 && !is_colorimetric = type { type = im_header_int "Type" im; coding = im_header_int "Coding" im; bands = im_header_int "Bands" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = im_header_int "BandFmt" x, is_image x = error ("get_format: unable to get format from " ++ print x); has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = im_header_int "Bbits" x, is_image x = error ("get_bits: unable to get bits from " ++ print x); has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = im_header_int "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = error ("get_bands: unable to get bands from " ++ print x); has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = im_header_int "Coding" x, is_image x = Image_coding.NOCODING, is_real x = error ("get_coding: unable to get coding from " ++ print x); has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = im_header_int "Xres" x, is_image x = error ("get_xres: unable to get xres from " ++ print x); has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = im_header_int "Yres" x, is_image x = error ("get_yres: unable to get yres from " ++ print x); has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = im_header_int "Xoffset" x, is_image x = error ("get_xoffset: unable to get xoffset from " ++ print x); has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = im_header_int "Yoffset" x, is_image x = error ("get_yoffset: unable to get yoffset from " ++ print x); has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = error ("get_image: unable to get image from " ++ print x); has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = error ("get_number: unable to get number from " ++ print x); has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = error ("get_real: unable to get real from " ++ print x); has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = im_header_int "Xsize" x, is_image x = error ("get_width: unable to get width from " ++ print x); has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = im_header_int "Ysize" x, is_image x = error ("get_height: unable to get height from " ++ print x); has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = error ("get_left: unable to get left from " ++ print x); has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = error ("get_top: unable to get top from " ++ print x); // like has/get member,but first in a lst of objects has_member_list has objects = filter has objects != []; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } nip2-8.7.1/share/nip2/compat/7.10/_list.def0000644000175000017500000001743713351443023014746 00000000000000/* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn (tl l), fn (hd l) = l; /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l up from the left using function fn and start value st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold up list l, right to left, with function fn and start * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); /* Search a list for an element, returning it's index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* land l: and all the elements of list l together * * land (map (==0) list) == true, if every element of list is zero. * land :: [bool] -> bool */ land = foldr logical_and true; /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a = l?0; b = l?1; x = tl (tl l); } /* lor l: or all the elements of list l together * * lor (map (equal 0) list) == true, if any element of list is zero. * lor :: [bool] -> bool */ lor = foldr logical_or false; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map fn' (zip2 l1 l2) { fn' p = fn p?0 p?1; } /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map fn' (zip3 l1 l2 l3) { fn' p = fn p?0 p?1 p?2; } /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = lor (map (equal x) l); /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a = hd l; x = tl l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st (hd l)) (tl l); } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a = hd l1; x = tl l1; b = hd l2; y = tl l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by fn * * split is_space "hello world" == ["hello", "world"] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/8.3/0000755000175000017500000000000013417043453013151 500000000000000nip2-8.7.1/share/nip2/compat/8.3/Image.def0000644000175000017500000014437613351443023014604 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process = [ // we can't use id here since we want to "declass" // the members of x ... consider if x is a crop class, // for example, we don't want to inherit from crop, we // want to make a new image class rot180 @ rot180, rot90, rot180, rot270 ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel h v image, aspect = resize kernel fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize kernel fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_map_item = class Menuaction "_Map" "map an image through a 2D transform image" { action a b = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_binary trans a b { trans a b = mapim interp.value in index { // get the index image first [index, in] = sortc (const is_twocomponent) [a, b]; // is a two-component image, ie. one band complex, or // two-band non-complex is_twocomponent x = is_nonc x || is_c x; is_nonc x = has_bands x && get_bands x == 2 && has_format x && !is_complex_format (get_format x); is_c x = has_bands x && get_bands x == 1 && has_format x && is_complex_format (get_format x); is_complex_format f = f == Image_format.COMPLEX || f == Image_format.DPCOMPLEX; } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; Bandand_item = class Menuaction "Bitwise Band AND" "bitwise AND of image bands" { action x = bandand x; } Bandor_item = class Menuaction "Bitwise Band OR" "bitwise OR of image bands" { action x = bandor x; } sep2 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = crop x [l, t, w, h] { fields = [ [has_left, get_left, 0], [has_top, get_top, 0], [has_width, get_width, 100], [has_height, get_height, 100] ]; [l, t, w, h] = map get_default fields { get_default line = get x, has x = default { [has, get, default] = line; } } } crop x geo = class _result { _vislevel = 3; l = Expression "Crop left" ((int) (geo?0 + geo?2 / 4)); t = Expression "Crop top" ((int) (geo?1 + geo?3 / 4)); w = Expression "Crop width" (max_pair 1 ((int) (geo?2 / 2))); h = Expression "Crop height" (max_pair 1 ((int) (geo?3 / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 100; sy = Expression "Start y" 100; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise Join" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/8.3/_convert.def0000644000175000017500000004424313351443023015371 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = Image x.value, is_Plot x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The outermost list objects become Group()'d. */ to_group x = Group x, is_list x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = sign * (abs ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; sign = 1, ipart > 0 = -1; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; /* Return $PATH, reformatted as [["comp1", "comp2"], ["comp1", "comp2"] ..] */ system_search_path = [vipsbin] ++ map path_parse (split (equal path_sep) (expand "$PATH")) { /* On some platforms we ship vips with a few extra progs. Search * $VIPSHOME/bin first. */ vipsbin = path_parse (expand "$VIPSHOME") ++ ["bin"]; path_sep = ':', expand "$SEP" == "/" = ';'; } /* Search $PATH for the first occurence of name, or "". */ search_for name = hits?0, hits != [] = "" { exe_name = name ++ expand "$EXEEXT"; form_path p = path_absolute (p ++ [exe_name]); paths = map form_path system_search_path; hits = dropwhile (equal []) (map search paths); } /* Search $PATH for the first occurence of name, error on failure. */ search_for_error name = path, path != "" = error (exe_name ++ " not found on your search path. " ++ "Check you have installed the program and it is on your PATH.") { exe_name = name ++ expand "$EXEEXT"; path = search_for name; } nip2-8.7.1/share/nip2/compat/8.3/Filter.def0000644000175000017500000011730313351443023014775 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 2; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 20; fs = Scale "Sharpen flat areas by" 0 5 0.5; js = Scale "Sharpen jaggy areas by" 0 5 1; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_hough_item = class Menupullright "_Hough Transform" "transform to parameter space" { Line_item = class Menuaction "_Line" "find straight line Hough transform" { action a = class _result { _vislevel = 3; pspace_width = Expression "Parameter space width" 64; pspace_height = Expression "Parameter space height" 64; _result = map_unary line a { line a = hough_line (to_real pspace_width) (to_real pspace_height) a; } } } Circle_item = class Menuaction "_Circle" "find circle Hough transform" { action a = class _result { _vislevel = 3; scale = Expression "Scale down parameter space by" 10; min_radius = Expression "Minimum radius" 10; max_radius = Expression "Maximum radius" 30; _result = map_unary circle a { circle a = hough_circle (to_real scale) (to_real min_radius) (to_real max_radius) a; } } } } Filter_coordinate_item = class Menupullright "_Coordinate Transform" "various coordinate transforms" { // run a function which wants a complex arg on a non-complex two-band // image run_cmplx fn x = re x' ++ im x' { x' = fn (x?0, x?1); } Polar_item = class Menuaction "_Polar" "transform to polar coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_polar a { to_polar im = mapim interp.value map' im { // xy image, origin in the centre, scaled to fit image to // a circle xy = make_xy im.width im.height; xy' = xy - Vector [im.width / 2, im.height / 2]; scale = min [im.width, im.height] / im.width; xy'' = 2 * xy' / scale; // to polar, scale vertical axis to 360 degrees map = run_cmplx polar xy''; map' = map * Vector [1, im.height / 360]; } } } } Rectangular_item = class Menuaction "_Rectangular" "transform to rectangular coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_rect a { to_rect im = mapim interp.value map'' im { // xy image, vertical scaled to 360 degrees xy = make_xy im.width im.height; xy' = xy * Vector [1, 360 / im.height]; // to rect, scale to image rect map = run_cmplx rectangular xy'; scale = min [im.width, im.height] / im.width; map' = map * scale / 2; map'' = map' + Vector [im.width / 2, im.height / 2]; } } } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } Autotrace_item = class Menuaction "_Trace" "convert a bitmap to an SVG file" { action x = class _result { _vislevel = 3; despeckle = Scale "Despeckle level" 1 20 1; line = Scale "Line threshold" 1 20 1; center = Toggle "Trace centreline" false; scale = Scale "SVG scale" 0.1 10 1; command = "autotrace %s " ++ join_sep " " [ofmt, ofile, desp, lint, cent] { prog = search_for_error "autotrace"; ofmt = "-output-format svg"; ofile = "-output-file %s"; desp = "-despeckle-level " ++ print despeckle.value; lint = "-line-threshold " ++ print line.value; cent = if center then "-centerline " else ""; } _result = Image output { [output] = vips_call "system" [command] [$in => [x.value], $in_format => "%s.ppm", $out => true, $out_format => "%s.svg[scale=" ++ print scale.value ++ "]" ]; } } } nip2-8.7.1/share/nip2/compat/8.3/_joe_extra.def0000644000175000017500000003107513351443023015670 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use an Arrow or Region x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { im = x.image; mask = Image m { rx = x.region_rect, is_Region x = x; b = image_new im.width im.height 1 0 0 1 0 0 0; w = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0; m = insert_noexpand rx.nleft rx.ntop w b; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Kernel_linear f1 1 b1 {b1 = resize Kernel_linear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/8.3/Preferences.ws0000644000175000017500000010177313351443023015710 00000000000000 nip2-8.7.1/share/nip2/compat/8.3/Magick.def0000644000175000017500000014112713351443023014744 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate Magick.def 13-Apr-2014 snibgo Put "new image" items into sub-menu. New class VirtualPixlBack. 17-Apr-2014 snibgo Many small changes. A few new menu options. Created sub-menu for multi-input operations. 3-May-2014 jcupitt Put quotes around ( in shadow to help unix Last update: 17-Apr-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ // We don't need Noop. /*=== Magick_noop_item = class Menuaction "_Noop" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_testPar_item = class Menuaction "_TestPar" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "( +clone ) +append ", "\"%s\"" ]; _result = Magick.system command x; } } /* Removed Read_item and Write_item, much better to use nip2 load/save image. * Plus they can load all libMagick formats anyway. */ // Put "new image" items into sub-menu Magick_NewImageMenu_item = class Menupullright "_New image" "make a new image" { Magick_newcanvas_item = class Menuaction "_Solid colour" "make image of solid colour" { action = class _result { _vislevel = 3; size = Magick.Size_widget; colour = Magick.generalcol_widget; command = Magick.command [ size._flag, "\"canvas:" ++ colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_builtin_item = class Menuaction "_Built-in image" "create a built-in image" { action = class _result { _vislevel = 3; builtin = Magick.builtin_widget; command = Magick.command [ builtin._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_gradient_item = class Menuaction "_Gradient" "make a linear gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; topColour = Magick.generalcol_widget; bottomColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"gradient:", topColour._flag, "-", bottomColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } Magick_hald_item = class Menuaction "_Hald-clut image" "create an identity hald-clut image" { action = class _result { _vislevel = 3; order = Expression "order" 8; command = Magick.command [ "hald:" ++ print order.expr, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_pattern_item = class Menuaction "_Pattern" "create pattern" { action = class _result { _vislevel = 3; size = Magick.Size_widget; pattern = Magick.pattern_widget; command = Magick.command [ size._flag, pattern._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_plasma_item = class Menuaction "_Plasma image" "create plasma image" { action = class _result { _vislevel = 3; size = Magick.Size_widget; // FIXME? ColourA-ColourB. // FIXME? Allow plasma:fractal? command = Magick.command [ size._flag, "plasma:", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_radialgradient_item = class Menuaction "_Radial gradient" "make a radial gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; innerColour = Magick.generalcol_widget; outerColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"radial-gradient:", innerColour._flag, "-", outerColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } } // end Magick_NewImageMenu_item Magick_MultiMenu_item = class Menupullright "_Multiple inputs" "make an image from multiple images" { Magick_composite_item = class Menuaction "_Composite" "composite two images (without mask)" { action x y = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_compositeMask_item = class Menuaction "_Composite masked" "composite two images (with mask)" { action x y z = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system3 command x y z; } } // FIXME: other operations like remap that take another image as arguments are: // mask (pointless?), texture, tile (pointless?) // FIXME: operations that take a filename that isn't an image: // cdl, profile Magick_clut_item = class Menuaction "_Clut" "replace values using second image as colour look-up table" { action x y = class _result { _vislevel = 3; // FIXME: uses -intensity "when mapping greyscale CLUT image to alpha channel if set by -channels" command = Magick.command [ "\"%s\"", "\"%s\"", "-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_haldclut_item = class Menuaction "_Hald clut" "replace values using second image as Hald colour look-up table" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"", "-hald-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } // Encipher and decipher: key files can be text or image files. Magick_encipher_item = class Menuaction "_Encipher/Decipher" "encipher or decipher an image image" { action x = class _result { _vislevel = 3; pathname = Pathname "Read key file" ""; isDecipher = Toggle "Decipher" false; command = Magick.command [ "\"%s\"", if pathname.value == "" then "" else ( ( if isDecipher then "-decipher " else "-encipher ") ++ ( "\"" ++ pathname.value ++ "\"" ) ), "\"%s\"" ]; _result = Magick.system command x; } } Magick_profile_item = class Menuaction "_Profile" "assigns/applies an ICC profile" { action x = class _result { _vislevel = 3; pathname1 = Pathname "Read profile file" ""; pathname2 = Pathname "Read profile file" ""; command = Magick.command [ "\"%s\"", if pathname1.value == "" then "" else ( "-profile " ++ "\"" ++ pathname1.value ++ "\""), if pathname2.value == "" then "" else ( "-profile " ++ "\"" ++ pathname2.value ++ "\""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_remap_item = class Menuaction "_Remap" "reduce colours to those in another image" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-remap", "\"%s\"", "\"%s\"" ]; _result = Magick.system2 command x y; } } } // end Magick_MultiMenu_item Magick_image_type_item = class Menuaction "_Image Type" "change image type" { action x = class _result { _vislevel = 3; imagetype = Magick.imagetype_widget; command = Magick.command [ "\"%s\"", imagetype._flag, "\"%s\"" ]; _result = Magick.system command x; } } sep2 = Menuseparator; Magick_alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = Magick.alpha_widget; command = Magick.command [ "\"%s\"", alpha._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = Magick.text_widget; font = Magick.Font_widget; geometry = Magick.AnnotGeometry_widget; gravity = Magick.gravity_widget; foreground = Magick.foreground_widget; undercol = Magick.undercol_widget; antialias = Magick.antialias_widget; command = Magick.command [ "\"%s\"", font._flag, antialias._flag, gravity._flag, foreground._flag, undercol._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoGamma_item = class Menuaction "_AutoGamma" "automatic gamma" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-gamma", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoLevel_item = class Menuaction "_AutoLevel" "automatic level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-level", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blurSharpMenu_item = class Menupullright "_Blur/Sharpen" "blur and sharpen" { Magick_adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; // note: adaptive-blur doesn't regard VP. command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-adaptive-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_blur_item = class Menuaction "_Blur" "blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gaussianBlur_item = class Menuaction "_Gaussian Blur" "blur with a Gaussian operator" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-gaussian-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_motionBlur_item = class Menuaction "_Motion Blur" "simulate motion blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; channels = Magick.ch_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-motion-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotationalBlur_item = class Menuaction "_RotationalBlur" "blur around the centre" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; angle = Scale "angle (degrees)" (-360) 360 20; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-radial-blur", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_selectiveBlur_item = class Menuaction "_Selective Blur" "blur where contrast is less than or equal to threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; threshold = Scale "Threshold (percent)" 0 100 50; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", intensity._flag, virtpixback._flag, channels._flag, "-selective-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print threshold.value ++ "%%", "\"%s\"" ]; _result = Magick.system command x; } } sep1 = Menuseparator; Magick_adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-adaptive-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sharpen_item = class Menuaction "_Sharpen" "sharpen" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_unsharpen_item = class Menuaction "_Unsharp" "sharpen with unsharp mask" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; gain = Scale "Gain" (-10) 10 1; threshold = Scale "Threshold" 0 1 0.05; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-unsharp", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print gain.value ++ "+" ++ print threshold.value, "\"%s\"" ]; _result = Magick.system command x; } } } // end BlurSharpMenu_item Magick_border_item = class Menuaction "_Border" "add border of given colour" { action x = class _result { _vislevel = 3; compose = Magick.compose_widget; width = Expression "Width" 3; bordercol = Magick.bordercol_widget; command = Magick.command [ "\"%s\"", compose._flag, bordercol._flag, "-border", print width.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_brightCont_item = class Menuaction "_Brightness-contrast" "adjust the brightness and/or contrast" { action x = class _result { _vislevel = 3; bri = Scale "brightness" (-100) 100 0; con = Scale "contrast" (-100) 100 0; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-brightness-contrast", print bri.value ++ "x" ++ print con.value, "\"%s\"" ]; _result = Magick.system command x; } } // Note: canny requires ImageMagick 6.8.9-0 or later. Magick_canny_item = class Menuaction "_Canny" "detect a wide range of edges" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; lowPc = Scale "lower percent" 0 100 10; highPc = Scale "lower percent" 0 100 10; command = Magick.command [ "\"%s\"", "-canny", concat ["\"", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print lowPc.value ++ "%%+" ++ print highPc.value ++ "%%" ++ "\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_charcoal_item = class Menuaction "_Charcoal" "simulate a charcoal drawing" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; factor = Scale "factor" 0 50 1; command = Magick.command [ "\"%s\"", intensity._flag, "-charcoal", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_chop_item = class Menuaction "_Chop" "remove pixels from the interior" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-chop", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorize_item = class Menuaction "_Colorize" "colorize by given amount" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; val = Scale "value" 0 100 100; command = Magick.command [ "\"%s\"", foreground._flag, "-colorize", print val.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colors_item = class Menuaction "_Colors" "reduce number of colors" { action x = class _result { _vislevel = 3; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; quantize = Magick.colorspace_widget; colors = Expression "Colours" 3; command = Magick.command [ "\"%s\"", "-quantize", quantize._flag, "-treedepth", print treedepth.expr, dither._flag, "-colors", print colors.expr, "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: color-matrix? Magick_colorspace_item = class Menuaction "_Colourspace" "convert to arbitrary colourspace" { action x = class _result { _vislevel = 3; colsp = Magick.colorspace_widget; command = Magick.command [ "\"%s\"", "-colorspace", colsp._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorspaceGray_item = class Menuaction "_Colourspace gray" "convert to gray using given intensity method" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-colorspace gray", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrast_item = class Menuaction "_Contrast" "increase or reduce the contrast" { action x = class _result { _vislevel = 3; isReduce = Toggle "reduce contrast" false; command = Magick.command [ "\"%s\"", (if isReduce then "+" else "-") ++ "contrast", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrastStretch_item = class Menuaction "_Contrast stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-contrast-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: convolve (bias, kernel) Magick_crop_item = class Menuaction "_Crop" "cut out a rectangular region" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-crop", geometry._flag, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_deskew_item = class Menuaction "_Deskew" "straighten the image" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; // FIXME: toggle auto-crop? command = Magick.command [ "\"%s\"", "-deskew", "\"" ++ print threshold.value ++ "%%\"", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_despeckle_item = class Menuaction "_Despeckle" "reduce the speckles" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-despeckle", "\"%s\"" ]; _result = Magick.system command x; } } Magick_distort_item = class Menuaction "_Distort" "distort using a method and arguments" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; distort = Magick.distort_widget; args = String "Arguments" "1,0"; isPlus = Toggle "Extend to show entire image" false; command = Magick.command [ "\"%s\"", virtpixback._flag, (if isPlus then "+" else "-") ++ "distort", distort._flag, args.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_draw_item = class Menuaction "_Draw" "annotate with one or more graphic primitives" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; args = String "Arguments" "line 0,0 9,9 rectangle 10,10 20,20"; command = Magick.command [ "\"%s\"", foreground._flag, "-draw", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_edge_item = class Menuaction "_Edge" "detect edges" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-edge", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_emboss_item = class Menuaction "_Emboss" "emboss" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-emboss", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_enhance_item = class Menuaction "_Enhance" "enhance a noisy image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-enhance", "\"%s\"" ]; _result = Magick.system command x; } } Magick_equalize_item = class Menuaction "_Equalize" "equalize the histogram" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-equalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_evaluate_item = class Menuaction "_Evaluate" "evaluate an expression on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; operation = Magick.evaluate_widget; val = Expression "value" 5; isPc = Toggle "Value is percent" false; command = Magick.command [ "\"%s\"", channels._flag, operation._flag, print val.expr ++ if isPc then "%%" else "", "\"%s\"" ]; _result = Magick.system command x; } } Magick_extent_item = class Menuaction "_Extent" "set the image size and offset" { action x = class _result { _vislevel = 3; background = Magick.background_widget; compose = Magick.compose_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, background._flag, gravity._flag, "-extent", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_FlipFlopMenu_item = class Menupullright "_Flip/flop" "flip/flop/transverse/transpose" { Magick_flip_item = class Menuaction "_Flip vertically" "mirror upside-down" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flip", "\"%s\"" ]; _result = Magick.system command x; } } Magick_flop_item = class Menuaction "_Flop horizontally" "mirror left-right" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flop", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transpose_item = class Menuaction "_Transpose" "mirror along the top-left to bottom-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transpose +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transverse_item = class Menuaction "_Transverse" "mirror along the bottom-left to top-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transverse +repage", "\"%s\"" ]; _result = Magick.system command x; } } } // end Magick_FlipFlopMenu_item Magick_floodfill_item = class Menuaction "_Floodfill" "recolour neighbours that match" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; fuzz = Magick.fuzz_widget; coordinate = Magick.coordinate_widget; // -draw "color x,y floodfill" command = Magick.command [ "\"%s\"", foreground._flag, "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-draw \" color", coordinate._flag, "floodfill \"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_frame_item = class Menuaction "_Frame" "surround with border or beveled frame" { action x = class _result { _vislevel = 3; border = Magick.bordercol_widget; compose = Magick.compose_widget; matte = Magick.mattecol_widget; geometry = Magick.FrameGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, border._flag, matte._flag, "-frame", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_function_item = class Menuaction "_Function" "evaluate a function on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; function = Magick.function_widget; // FIXME: explain values; use sensible defaults. values = String "values" "0,0,0,0"; command = Magick.command [ "\"%s\"", channels._flag, "-function", function._flag, values.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_fx_item = class Menuaction "_Fx" "apply a mathematical expression" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; interpolate = Magick.interpolate_widget; virtpixback = Magick.VirtualPixelBack_widget; args = String "Expression" "u*1/2"; command = Magick.command [ "\"%s\"", channels._flag, interpolate._flag, virtpixback._flag, "-fx", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_gamma_item = class Menuaction "_Gamma" "apply a gamma correction" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; gamma = Magick.gamma_widget; command = Magick.command [ "\"%s\"", channels._flag, "-gamma", print gamma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradient_item = class Menuaction "_Gradient" "apply a linear gradient" { action x = class _result { _vislevel = 3; colourA = Magick.generalcol_widget; colourB = Magick.generalcol_widget; position = Option "colourA is at" [ "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"] 0; _baryArg = concat ["0,0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 0 = concat ["0,0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 1 = concat ["0,0,", colourA._flag, " %%[fx:w-1],0,", colourB._flag], position.value == 2 = concat ["0,0,", colourB._flag, " %%[fx:w-1],0,", colourA._flag], position.value == 3 = concat ["0,0,", colourA._flag, " %%[fx:w-1],%%[fx:h-1],", colourB._flag], position.value == 4 = concat ["%%[fx:w-1],0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 5 = concat ["%%[fx:w-1],0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 6 = concat ["0,0,", colourB._flag, " %%[fx:w-1],%%[fx:h-1],", colourA._flag], position.value == 7 = "dunno"; command = Magick.command [ "\"%s\"", "-sparse-color barycentric \"" ++ _baryArg ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradientCorn_item = class Menuaction "_Gradient corners" "apply a bilinear gradient between the corners" { action x = class _result { _vislevel = 3; colour_top_left = Magick.generalcol_widget; colour_top_right = Magick.generalcol_widget; colour_bottom_left = Magick.generalcol_widget; colour_bottom_right = Magick.generalcol_widget; command = Magick.command [ "\"%s\"", "-sparse-color bilinear \"" ++ "0,0," ++ colour_top_left._flag ++ ",%%[fx:w-1],0" ++ colour_top_right._flag ++ ",0,%%[fx:h-1]" ++ colour_bottom_left._flag ++ ",%%[fx:w-1],%%[fx:h-1]" ++ colour_bottom_right._flag ++ "\"", "+depth", "\"%s\"" ]; _result = Magick.system command x; } } Magick_histogram_item = class Menuaction "_Histogram" "make a histogram image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-define histogram:unique-colors=false histogram:" ++ "\"%s\"" ]; _result = Magick.system command x; } } Magick_implode_item = class Menuaction "_Implode" "implode pixels about the center" { action x = class _result { _vislevel = 3; factor = Scale "factor" 0 20 1; interpolate = Magick.interpolate_widget; // FIXME: virtual-pixel? command = Magick.command [ "\"%s\"", interpolate._flag, "-implode", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_level_item = class Menuaction "_Level" "adjust the level of channels" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "black point" (-100) 200 0; wht = Scale "white point" (-100) 200 100; gam = Scale "gamma" 0 30 1; isPc = Toggle "Levels are percent" true; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level", "\"" ++ print blk.value ++ "," ++ print wht.value ++ (if isPc then "%%" else "") ++ "," ++ print gam.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_levelCols_item = class Menuaction "_Level colors" "adjust levels to given colours" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; colour_black = Magick.generalcol_widget; colour_white = Magick.generalcol_widget; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level-colors", "\"" ++ colour_black._flag ++ "," ++ colour_white._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_linearStretch_item = class Menuaction "_Linear stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", channels._flag, "-linear-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_magnify_item = class Menuaction "_Magnify" "double the size of the image with pixel art scaling" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-magnify", "\"%s\"" ]; _result = Magick.system command x; } } Magick_modulate_item = class Menuaction "_Modulate" "modulate brightness, saturation and hue" { action x = class _result { _vislevel = 3; modcolsp = Magick.ModColSp_widget; bright = Scale "brightness" 0 200 100; sat = Scale "saturation" 0 200 100; hue = Scale "hue" 0 200 100; command = Magick.command [ "\"%s\"", modcolsp._flag, "-modulate", print bright.value ++ "," ++ print sat.value ++ "," ++ print hue.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_monochrome_item = class Menuaction "_Monochrome" "transform to black and white" { action x = class _result { _vislevel = 3; // FIXME: also intensity? intensity = Magick.intensity_widget; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; command = Magick.command [ "\"%s\"", intensity._flag, dither._flag, "-treedepth", print treedepth.expr, "-monochrome", "\"%s\"" ]; _result = Magick.system command x; } } Magick_morphology_item = class // See http://www.imagemagick.org/Usage/morphology/ Menuaction "_Morphology" "apply a morphological method" { action x = class _result { _vislevel = 3; method = Magick.morphmeth_widget; iter = Expression "Iterations (-1=repeat until done)" 1; kernel = Magick.kernel_widget; // FIXME: custom kernel eg "3x1+2+0:1,0,0" // width x height + offsx + offsy : {w*h values} // each value is 0.0 to 1.0 or "NaN" or "-" // kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0 // but // ring takes: radius1, radius2, scale // rectangle and comet take: width x height + offsx + offsy // blur takes: radius x sigma // FIXME: for now, simply allow any string input. kernel_arg = String "Kernel arguments" ""; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-morphology", method._flag ++ ":" ++ print iter.expr, kernel._flag ++ (if kernel_arg.value == "" then "" else ":") ++ kernel_arg.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_negate_item = class Menuaction "_Negate" "negate" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-negate", "\"%s\"" ]; _result = Magick.system command x; } } Magick_addNoise_item = class Menuaction "_add Noise" "add noise" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; attenuate = Scale "attenuate" 0 1.0 1.0; noise = Magick.noise_widget; command = Magick.command [ "\"%s\"", channels._flag, "-attenuate", print attenuate.value, noise._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_normalize_item = class Menuaction "_Normalize" "normalize" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-normalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_opaque_item = class Menuaction "_Opaque" "change this colour to the fill colour" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; fill = Magick.foreground_widget; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", fill._flag, channels._flag, "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "opaque", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_paint_item = class Menuaction "_Paint" "simulate an oil painting" { action x = class _result { _vislevel = 3; rad = Expression "radius" 10; command = Magick.command [ "\"%s\"", "-paint", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } /*=== FIXME Bug; remove for now. Polaroid_item = class Menuaction "_Polaroid" "simulate a polaroid picture" { action x = class _result { _vislevel = 3; angle = Scale "angle" (-90) 90 20; command = Magick.command [ "\"%s\"", "-polaroid", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_posterize_item = class Menuaction "_Posterize" "reduce to (n) levels per channel" { action x = class _result { _vislevel = 3; levels = Expression "levels" 3; command = Magick.command [ "\"%s\"", "-posterize", print levels.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_raise_item = class Menuaction "_Raise" "lighten or darken image edges" { action x = class _result { _vislevel = 3; thk = Expression "Thickness" 3; command = Magick.command [ "\"%s\"", "-raise", print thk.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_resize_item = class Menuaction "_Resize" "resize to given width and height" { action x = class _result { _vislevel = 3; filter = Magick.filter_widget; type = Magick.ResizeType_widget; width = Scale "Width" 1 100 10; height = Scale "Height" 1 100 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", filter._flag, "-" ++ type._flag, "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "!") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_roll_item = class Menuaction "_Roll" "roll an image horizontally or vertically" { action x = class _result { _vislevel = 3; rollx = Expression "X" 3; rolly = Expression "Y" 3; command = Magick.command [ "\"%s\"", "-roll", (if rollx.expr >= 0 then "+" else "") ++ print rollx.expr ++ (if rolly.expr >= 0 then "+" else "") ++ print rolly.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotate_item = class Menuaction "_Rotate" "rotate" { action x = class _result { _vislevel = 3; angle = Scale "angle (degrees)" (-360) 360 20; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, "+distort", "SRT", print angle.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -segment, but cluster-threshold should be percentage of image area. Magick_sepia_item = class Menuaction "_Sepia tone" "simulate a sepia-toned photo" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; command = Magick.command [ "\"%s\"", "-sepia-tone", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shade_item = class Menuaction "_Shade" "shade with a distant light source" { action x = class _result { _vislevel = 3; azimuth = Scale "Azimuth (degrees)" (-360) 360 0; elevation = Scale "Elevation (degrees)" 0 90 45; command = Magick.command [ "\"%s\"", "-shade", print azimuth.value ++ "x" ++ print elevation.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_shadow_item = class Menuaction "_Shadow" "simulate a shadow" { action x = class _result { _vislevel = 3; shadowCol = Magick.generalcol_widget; opacity = Scale "Opacity (percent)" 0 100 75; sigma = Scale "Sigma" 0 30 2; // FIXME: make offsets a single widget? offsx = Scale "X-offset" (-20) 20 4; offsy = Scale "Y-offset" (-20) 20 4; arePc = Toggle "offsets are percentages" false; // FIXME: raw operation creates page offset, which vips dislikes. // So we take this futher, compositing with source. command = Magick.command [ "\"%s\"", "\"(\" +clone", "-background", "\"" ++ shadowCol._flag ++ "\"", "-shadow", concat [ "\"", print opacity.value, "x", print sigma.value, (if offsx.value >= 0 then "+" else ""), print offsx.value, (if offsy.value >= 0 then "+" else ""), print offsy.value, (if arePc then "%%" else ""), "\"" ], "\")\" +swap -background None -layers merge", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shave_item = class Menuaction "_Shave" "shave pixels from the edges" { action x = class _result { _vislevel = 3; width = Scale "Width" 0 50 10; height = Scale "Height" 0 50 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", "-shave", "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shear_item = class Menuaction "_Shear" "shear along the x-axis and/or y-axis" { action x = class _result { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-shear", print shearX.expr ++ "x" ++ print shearY.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sigmoid_item = class Menuaction "_Sigmoid" "increase or decrease mid-tone contrast sigmoidally" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; contrast = Scale "contrast" 0 30 3; midpoint = Scale "mid-point (percent)" 0 100 50; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "sigmoidal-contrast", "\"" ++ print contrast.value ++ "x" ++ print midpoint.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_sketch_item = class Menuaction "_Sketch" "simulate a pencil sketch" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; command = Magick.command [ "\"%s\"", "-sketch", print radius.value ++ "x" ++ print sigma.value ++ (if angle >= 0 then ("+" ++ print angle.value) else ""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_solarize_item = class Menuaction "_Solarize" "negate all pixels above a threshold level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-solarize", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -sparse-color needs abitrary list of {x,y,colour}. Magick_splice_item = class Menuaction "_Splice" "splice a colour into the image" { action x = class _result { _vislevel = 3; background = Magick.background_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", background._flag, gravity._flag, "-splice", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_spread_item = class Menuaction "_Spread" "displace pixels by random amount" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; amount = Expression "Amount (pixels)" 5; command = Magick.command [ "\"%s\"", virtpixback._flag, "-spread", print amount.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_statistic_item = class Menuaction "_Statistic" "replace each pixel with statistic from neighbourhood" { action x = class _result { _vislevel = 3; width = Expression "Width" 5; height = Expression "Height" 5; statisticType = Magick.StatType_widget; command = Magick.command [ "\"%s\"", "-statistic", statisticType._flag, print width.expr ++ "x" ++ print height.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = Magick.angle_widget; command = Magick.command [ "\"%s\"", "-swirl", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_thresholdMenu_item = class Menupullright "_Threshold" "make black or white" { Magick_threshold_item = class Menuaction "_Threshold" "apply black/white threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blackThreshold_item = class Menuaction "_Black threshold" "where below threshold set to black" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-black-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_whiteThreshold_item = class Menuaction "_White threshold" "where above threshold set to white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-white-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_latThreshold_item = class Menuaction "_Local Adaptive Threshold" "where above average plus offset set to white, otherwise black" { action x = class _result { _vislevel = 3; width = Expression "Width" 10; height = Expression "Height" 10; offset = Scale "Offset (percent)" (-100) 100 0; // note: "-lat" doesn't respond to channels command = Magick.command [ "\"%s\"", "-lat", concat ["\"", print width.expr, "x", print height.expr, (if offset.value >= 0 then "+" else ""), print offset.value, "%%\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_randThreshold_item = class Menuaction "_Random Threshold" "between specified limits, apply random threshold" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; low = Scale "Low threshold" 0 100 10; high = Scale "High threshold" 0 100 90; isPc = Toggle "Thresholds are percent" true; command = Magick.command [ "\"%s\"", channels._flag, "-random-threshold", "\"" ++ print low.value ++ "x" ++ print high.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } } // end ThresholdMenu_item // Note: alternatives include: // convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif Magick_tile_item = class Menuaction "_Tile" "fill given size with tiled image" { action x = class _result { _vislevel = 3; size = Magick.Size_widget; command = Magick.command [ size._flag, "tile:" ++ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_tint_item = class Menuaction "_Tint" "apply a tint" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; amount = Scale "amount (percent)" 0 100 50; command = Magick.command [ "\"%s\"", foreground._flag, "-tint", // snibgo note: although the amount is a percentage, it doesn't need "%" character. print amount.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_transparent_item = class Menuaction "_Transparent" "make this colour transparent" { action x = class _result { _vislevel = 3; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "transparent", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_trim_item = class Menuaction "_Trim" "trims away border" { action x = class _result { _vislevel = 3; fuzz = Magick.fuzz_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-trim +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_uniqueCols_item = class Menuaction "_Unique colours" "discard all but one of any pixel color" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-unique-colors", "\"%s\"" ]; _result = Magick.system command x; } } Magick_vignette_item = class Menuaction "_Vignette" "soften the edges in vignette style" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; rx = Scale "Rolloff x (percent)" 0 100 10; ry = Scale "Rolloff y (percent)" 0 100 10; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-vignette", print radius.value ++ "x" ++ print sigma.value ++ (if rx.value >= 0 then "+" else "") ++ print rx.value ++ (if ry.value >= 0 then "+" else "") ++ print ry.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_wave_item = class Menuaction "_Wave" "shear the columns into a sine wave" { action x = class _result { _vislevel = 3; amplitude = Scale "Amplitude (pixels)" 0 100 10; wavelength = Scale "Wavelength (pixels)" 0 100 10; command = Magick.command [ "\"%s\"", "-wave", print amplitude.value ++ "x" ++ print wavelength.value, "\"%s\"" ]; _result = Magick.system command x; } } nip2-8.7.1/share/nip2/compat/8.3/Colour.def0000644000175000017500000003773013351443023015020 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } CCT_colour = class Menuaction (_ "Colour from CCT") (_ "pick colour by CCT") { action = widget 6500; widget x = class _result { _vislevel = 3; T = Scale "CCT" 1800 25000 x; _result = colour_from_temp (to_real T); Colour_edit space value = widget (temp_from_colour (Colour space value)); } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } sep1 = Menuseparator; CCT_item = class Menuaction (_ "Calculate temperature") (_ "estimate CCT using the McCamy approximation") { action z = map_unary temp_from_colour z; } Colour_item = Colour_new_item.CCT_colour; } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = print_profile, has_type image && get_type image == Image_type.CMYK && has_bands image && get_bands image >= 4 = monitor_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; measure = Scale (_ "Measure area (%)") 1 100 50; // get a representative image from an arg get_image x = get_image x.value?0, is_Group x = x; _im = get_image x; sample = measure_draw (to_real pacross) (to_real pdown) (to_real measure) _im; _result = map_unary chart x { chart in = measure_sample (to_real pacross) (to_real pdown) (to_real measure) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/8.3/_joe_utilities.def0000644000175000017500000005054513351443023016563 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/8.3/_Object.def0000644000175000017500000002600513351443023015113 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/8.3/Object.def0000644000175000017500000000220513351443023014750 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/8.3/Math.def0000644000175000017500000003162513351443023014443 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_AND" "bitwise AND of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_OR" "bitwise OR of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "_XOR" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_NOT" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Bandand_item = Image_band_item.Bandand_item; Bandor_item = Image_band_item.Bandor_item; } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Skew_item = class Menuaction "S_kew" "skew of image or list or vector" { action a = map_unary skew a; } Kurtosis_item = class Menuaction "Kurtosis" "kurtosis of image or list or vector" { action a = map_unary kurtosis a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/8.3/_generate.def0000644000175000017500000000755513351443023015510 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } mkim options x y b = Image (image_new x y b (opt $format) (opt $coding) (opt $type) (opt $pixel) (opt $xoffset) (opt $yoffset)) { opt = get_option options [ $format => Image_format.UCHAR, $coding => Image_coding.NOCODING, $type => Image_type.sRGB, $pixel => 0, $xoffset => 0, $yoffset => 0 ]; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } /* Make a colour from a temperature. */ colour_from_temp T = error (_ "T out of range"), T < 1667 || T > 25000 = Colour "Yxy" [50, x, y] { // Kim et all approximation // see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation x = -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 + 0.8776956 * 10 ** 3 / T + 0.179910, T < 4000 = -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 + 0.2226347 * 10 ** 3 / T + 0.240390; y = -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + 2.18555832 * x - 0.20219638, T < 2222 = -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867, T < 4000 = 3.0817580 * x ** 3 - 5.87338670 * x ** 2 + 3.75112997 * x - 0.37001483; } temp_from_colour z = T { c = colour_transform_to Image_type.YXY (to_colour z); x = c.value?1; y = c.value?2; // McCamy's approximation, see eg. // http://en.wikipedia.org/wiki/Color_temperature#Approximation xe = 0.332; ye = 0.1858; n = (x - xe) / (y - ye); T = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33; } nip2-8.7.1/share/nip2/compat/8.3/_stdenv.def0000644000175000017500000017677513351443023015234 00000000000000/* optional args to functions */ get_option options defaults f = error (_ "unknown parameter " ++ f), hits == [] = hits?0 { hits = [v :: [n, v] <- options ++ defaults; n == f]; } /* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } bandand x = oo_unary_function bandand_op x, is_class x = foldr1 bitwise_and (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandand") { bandand_op = Operator "bandand" bandand Operator_type.COMPOUND_REWRAP false; } bandor x = oo_unary_function bandor_op x, is_class x = foldr1 bitwise_or (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandor") { bandor_op = Operator "bandor" bandor Operator_type.COMPOUND_REWRAP false; } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } skew x = oo_unary_function skew_op x, is_class x = sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x = sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "skew") { skew_op = Operator "skew" skew Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = w * h * b, is_image x' = len x'; } kurtosis x = oo_unary_function kurtosis_op x, is_class x = sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x = sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "kurtosis") { kurtosis_op = Operator "kurtosis" kurtosis Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = len x', is_list x'; = w * h * b; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_tile_cache_random x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } decode im = oo_unary_function decode_op im, is_class im = decode_im im, is_image im = error (_ "bad arguments to " ++ "decode") { decode_op = Operator "decode" decode Operator_type.COMPOUND_REWRAP false; decode_im im = im_LabQ2Lab im, get_coding im == Image_coding.LABPACK = im_rad2float im, get_coding im == Image_coding.RAD = im; } measure_draw across down measure image = mark { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; x = map (extract 0) cods; y = map (extract 1) cods; outer = mkim [$pixel => 255] sample_width sample_height 1; inner = mkim [] (sample_width - 4) (sample_height - 4) 1; patch = insert 2 2 inner outer; bg = mkim [] image.width image.height 1; mask = Image (im_insertset bg.value patch.value x y); image' = colour_transform_to Image_type.sRGB image; mark = if mask then Vector [0, 255, 0] else image'; } measure_sample across down measure image = measures { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; image' = decode image; patches = map (\p extract_area p?0 p?1 sample_width sample_height image') cods; measures = Matrix (map (map mean) (map bandsplit patches)); } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_inv hist = oo_unary_function hist_inv_op hist, is_class hist = inv hist, is_image hist = error (_ "bad arguments to " ++ "hist_inv") { hist_inv_op = Operator "hist_inv" hist_inv Operator_type.COMPOUND_REWRAP false; inv im = im_invertlut (to_matrix im''') len { // need a vertical doublemask im' = rot90 im, get_width im > 1 && get_height im == 1 = im, get_width im == 1 && get_height im > 1 = error (_ "not a hist"); len = get_height im'; // values must be scaled to 0 - 1 im'' = im' / (max im'); // add an index column on the left // again, must be in 0-1 y = ((make_xy 1 len)?1) / len; im''' = y ++ im''; } } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } reduce kernel xshr yshr image = oo_unary_function reduce_op image, is_class image = reduce_im image, is_image image = error (_ "bad arguments to " ++ "reduce") { reduce_op = Operator "reduce" reduce_im Operator_type.COMPOUND_REWRAP false; reduce_im im = out { [out] = vips_call "reduce" [im, xshr, yshr] [$kernel => kernel.value]; } } similarity interpolate scale angle image = oo_unary_function similarity_op image, is_class image = similarity_im image, is_image image = error (_ "bad arguments to " ++ "similarity") { similarity_op = Operator "similarity" similarity_im Operator_type.COMPOUND_REWRAP false; similarity_im im = out { [out] = vips_call "similarity" [im] [ $interpolate => interpolate.value, $scale => scale, $angle => angle ]; } } resize kernel xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; is_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn // everything else ... we just pass on to vips_resize() = vips_resize kernel xfac' yfac' im { vips_resize kernel hscale vscale im = out { [out] = vips_call "resize" [im, hscale] [$vscale => vscale, $kernel => kernel.value]; } } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C * * Also calculate R2, see eg.: * https://en.wikipedia.org/wiki/Coefficient_of_determination */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } ss = len xes; sx = sum xes; sy = sum yes; my = sy / ss; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; my = sy / len xes; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* One image in, one out. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } /* Two images in, one out. */ system_image2 command x1 x2 = oo_binary_function system_image2_op x1 x2, is_class x1 = oo_binary'_function system_image2_op x1 x2, is_class x2 = system x1 x2, is_image x1 && is_image x2 = error (_ "bad arguments to " ++ "system_image2") { system_image2_op = Operator "system_image2" (system_image2 command) Operator_type.COMPOUND_REWRAP false; system x1 x2 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Three images in, one out. */ system_image3 command x1 x2 x3 = oo_binary_function system_image2_op x2 x3, is_class x2 = oo_binary'_function system_image2_op x2 x3, is_class x3 = system x1 x2 x3, is_image x1 && is_image x2 && is_image x3 = error (_ "bad arguments to " ++ "system_image3") { system_image2_op = Operator "system_image2" (system_image3 command x1) Operator_type.COMPOUND_REWRAP false; system x1 x2 x3 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2, x3], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Zero images in, one out. */ system_image0 command = Image image_out { [image_out] = vips_call "system" [command] [ $out => true, $out_format => "%s.tif" ]; } hough_line w h x = oo_unary_function hough_line_op x, is_class x = hline (to_real w) (to_real h) x, is_image x = error (_ "bad arguments to " ++ "hough_line") { hough_line_op = Operator "hough_line" (hough_line w h) Operator_type.COMPOUND_REWRAP false; hline w h x = pspace { [pspace] = vips_call "hough_line" [x] [ $width => w, $height => h ]; } } hough_circle s mn mx x = oo_unary_function hough_circle_op x, is_class x = hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x = error (_ "bad arguments to " ++ "hough_circle") { hough_circle_op = Operator "hough_circle" (hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false; hcircle s mn mx x = pspace { [pspace] = vips_call "hough_circle" [x] [ $scale => s, $min_radius => mn, $max_radius => mx ]; } } mapim interp ind in = oo_binary_function mapim_op ind in, is_class ind = oo_binary'_function mapim_op ind in, is_class in = mapim_fn ind in, is_image ind && is_image in = error (_ "bad arguments to " ++ "mapim") { mapim_op = Operator "mapim" (mapim interp) Operator_type.COMPOUND_REWRAP false; mapim_fn ind im = out { [out] = vips_call "mapim" [im, ind] [$interpolate => interp]; } } nip2-8.7.1/share/nip2/compat/8.3/Histogram.def0000644000175000017500000001620513351443023015504 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "_Identity" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_inv_item = class Menuaction "In_vert" "invert a histogram" { action x = map_unary hist_inv x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Kernel_linear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; caption = Expression "Chart caption" "none"; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; xcaption = Expression "X axis caption" "none"; ycaption = Expression "Y axis caption" "none"; series_captions = Expression "Series captions" ["Band 0"]; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range ++ captions; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; captions = concat (map test caption_options) ++ [$series_captions => series_captions.expr] { caption_options = [ $caption => caption.expr, $xcaption => xcaption.expr, $ycaption => ycaption.expr ]; test x = [], value == "none" = [option_name => value] { [option_name, value] = x; } } image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/8.3/Widgets.def0000644000175000017500000000235313351443023015154 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/8.3/_types.def0000644000175000017500000007115113351443023015053 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Kernel_type = class { NEAREST_NEIGHBOUR = 0; LINEAR = 1; CUBIC = 2; LANCZOS2 = 3; LANCZOS3 = 4; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map kernel numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Linear", _ "Cubic", _ "Lanczos, two lobes", _ "Lanczos, three lobes" ]; /* And to vips enum nicknames. */ types = [ "nearest", "linear", "cubic", "lanczos2", "lanczos3" ]; } Kernel type = class { value = Kernel_type.types?type; } Kernel_linear = Kernel Kernel_type.LINEAR; Kernel_picker default = class Kernel kernel.value { _vislevel = 2; kernel = Option "Kernel" Kernel_type.descriptions default; } Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; to_image dpi = extract_bands 0 3 (graph_export_image (to_real dpi) this); } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/8.3/Matrix.def0000644000175000017500000002573113351443023015017 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = identity (identity_matrix 5); identity v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix (identity_matrix (to_real s)), to_real s != len v; = Matrix v; Matrix_vips value scale offset filename display = identity value; } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = series (mkseries 0 1 5); mkseries s t e = transpose [[to_real s, to_real s + to_real t .. to_real e]]; series v = class _result { _vislevel = 3; _s = v?0?0; _t = v?1?0 - v?0?0; _e = (last v)?0; s = Expression "Start value" _s; t = Expression "Step by" _t; e = Expression "End value" _e; _result = Matrix (mkseries s t e), to_real s != _s || to_real t != _t || to_real e != _e = Matrix v; Matrix_vips value scale offset filename display = series value; } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = square (mksquare 5); mksquare s = replicate s (take s [1, 1 ..]); square v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix_con (sum v) 0 v, len v == to_real s = Matrix_con (sum m) 0 m { m = mksquare (to_real s); } Matrix_vips value scale offset filename display = square value; } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = circle (mkcircle 3); mkcircle r = map2 (map2 pyth) xes yes { line = [-r .. r]; xes = replicate (2 * r + 1) line; yes = transpose xes; pyth a b = 1, (a**2 + b**2) ** 0.5 <= r = 0; } circle v = class _result { _vislevel = 3; r = Expression "Radius" ((len v - 1) / 2); _result = Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1 = Matrix_con (sum m) 0 m { m = mkcircle (to_real r); } Matrix_vips value scale offset filename display = circle value; } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/8.3/Tasks.def0000644000175000017500000006407313351443023014642 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; measure = Scale (_ "Measure area (%)") 1 100 50; sample = measure_draw 6 4 (to_real measure) image; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linearize from chart greyscale", "Fit intercept from chart greyscale", "Linear input, set brightness from chart", "Linear input" ] 0; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure_sample 6 4 (to_real measure) image; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix [[0, 0], [1, 1]] { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map an image though the lineariser linear x = hist_map linearising_lut.value x, mode == 0 || mode == 1 = x; // map the chart measurements though the lineariser _camera' = (to_matrix @ linear @ to_image) _camera; // solve for RGB -> XYZ // normalise: the 2nd row is what makes Y, so divide by that to // get Y in 0-1. _pinv = (transpose _camera' * _camera') ** -1; _full_M = transpose (_pinv * (transpose _camera' * _true_XYZ)); M = _full_M / scale; scale = sum _full_M.value?1; // now turn the camera to LAB and calculate dE76 _camera'' = (to_matrix @ colour_transform Image_type.XYZ Image_type.LAB @ recomb M @ multiply scale @ to_image) _camera'; _dEs = map abs_vec (_camera'' - _true_Lab).value; avg_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } // normalise brightness ... in linear mode, we optionally don't // set the brightness from the Macbeth chart norm x = x * scale, mode != 3 = x; // convert RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ norm @ recomb M @ cast_float @ linear) image.value; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ calib.norm @ recomb calib.M @ cast_float @ calib.linear) image.value; } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Kernel_linear xfactor yfactor scale_im; _offset_im = resize Kernel_linear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/8.3/Makefile.am0000644000175000017500000000062113351443023015116 00000000000000startdir = $(pkgdatadir)/compat/8.3 start_DATA = \ Colour.def \ _convert.def \ Filter.def \ _generate.def \ Histogram.def \ Image.def \ _joe_extra.def \ _joe_utilities.def \ _list.def \ _magick.def \ Magick.def \ Math.def \ Matrix.def \ _Object.def \ Object.def \ _predicate.def \ Preferences.ws \ _stdenv.def \ Tasks.def \ _types.def \ Widgets.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/8.3/Makefile.in0000644000175000017500000003714413417043242015143 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/8.3 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/8.3 start_DATA = \ Colour.def \ _convert.def \ Filter.def \ _generate.def \ Histogram.def \ Image.def \ _joe_extra.def \ _joe_utilities.def \ _list.def \ _magick.def \ Magick.def \ Math.def \ Matrix.def \ _Object.def \ Object.def \ _predicate.def \ Preferences.ws \ _stdenv.def \ Tasks.def \ _types.def \ Widgets.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/8.3/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/8.3/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/8.3/_magick.def0000644000175000017500000005322113351443023015140 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate _magick.def Add 0-ary and 2-ary system Put utility funcs into a Magick class 11-Apr-2014 snibgo Added VirtualPixelBack for cases where background is only relevant when VP=Background 17-Apr-2014 snibgo Many small changes. 2-May-2014 jcupitt Added Magick.version 30-June-2014 Put single-quotes around command exe to help win 1-July-2014 Automatically fall back to gm if we can't find convert 17-July-2014 better GM support Last update: 17-July-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ /* Put these in a class to avoid filling the main namespace with IM stuff. */ Magick = class { // first gm on path, or "" gm_path = search_for "gm"; // first convert on $PATH, or "" // we check for the convert we ship first convert_path = vips_convert, vips_convert != "" = search_for "convert" { // the convert we ship with the vips binary on some platforms, or "" vips_convert = search (path_absolute convert) { vipshome = path_parse (expand "$VIPSHOME"); convert = vipshome ++ ["bin", "convert" ++ expand "$EXEEXT"]; } } use_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK; // Are we in GM or IM mode? use_gm = true, use_gm_pref && gm_path != "" = false, !use_gm_pref && convert_path != "" = false, convert_path != "" = true, gm_path != "" = error "neither IM nor GM executable found"; command_path = gm_path, use_gm = convert_path; // try to get the version as eg. [6, 7, 7, 10] // GM versions are smaller, typically [1, 3, 18] version = map parse_int (split (member ".-") version_string) { [output] = vips_call "system" ["'" ++ command_path ++ "' -version"] [$log=>true]; version_string = (split (equal ' ') output)?1, use_gm = (split (equal ' ') output)?2; } // make a command-line ... args is a [str] we join with spaces command args = "'" ++ command_path ++ "' " ++ join_sep " " args' { args' = ["convert"] ++ args, use_gm = args; } // capabilities ... different versions support different features, we // turn features on and off based on these // would probably be better to test for caps somehow has_intensity = false, use_gm = version?0 > 6 || version?1 > 7; has_channel = false, use_gm = version?0 > 6 || version?1 > 7; system0 cmd = system_image0 cmd; system cmd x = map_unary (system_image cmd) x; system2 cmd x y = map_binary (system_image2 cmd) x y; system3 cmd x y z = map_trinary (system_image3 cmd) x y z; radius_widget = Scale "Radius" 0 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle (degrees)" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; gamma_widget = Scale "Gamma" 0 10 1; colors_widget = Scale "Colors" 1 10 3; resize_widget = Scale "Resize (percent)" 0 500 100; fuzz_widget = Scale "Fuzz (percent)" 0 100 0; blur_rad_widget = Scale "Radius (0=auto)" 0 100 0; // a colour with no enclosing quotes ... use this if we know there are // some quotes at an outer level print_colour_nq triple = concat ["#", concat (map fmt triple)] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } // we need the quotes because # is the comment character in *nix print_colour triple = "\"" ++ print_colour_nq triple ++ "\""; Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; GeneralCol triple = class Colour "sRGB" triple { _flag = print_colour_nq triple; Colour_edit space triple = this.GeneralCol triple; } generalcol_widget = GeneralCol [0, 0, 0]; Background triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" false; _flag = "-background " ++ if isNone then "None" else print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Bordercol triple = class Colour "sRGB" triple { _flag = "-bordercolor " ++ print_colour triple; Colour_edit space triple = this.Bordercol triple; } bordercol_widget = Bordercol [0, 0, 0]; Mattecol triple = class Colour "sRGB" triple { _flag = "-mattecolor " ++ print_colour triple; Colour_edit space triple = this.Mattecol triple; } mattecol_widget = Mattecol [189, 189, 189]; // FIXME: Undercolour, like many others, can have alpha channel. // How does user input this? With a slider? Undercol triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" true; _flag = if isNone then "" else ("-undercolor " ++ print_colour triple); Colour_edit space triple = this.Undercol triple; } undercol_widget = Undercol [0, 0, 0]; changeCol_widget = class { _vislevel = 3; colour = GeneralCol [0, 0, 0]; fuzz = fuzz_widget; nonMatch = Toggle "change non-matching colours" false; } Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Remove", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Builtin builtin = class Option_string "Builtin" [ // See http://www.imagemagick.org/script/formats.php "rose:", "logo:", "wizard:", "granite:", "netscape:" ] builtin { _flag = builtin; Option_edit caption labels value = this.Builtin labels?value; } builtin_widget = Builtin "rose:"; channels_widget = class { // FIXME? Can we grey-out alpha when we have no alpha channel, // show CMY(K) instead of RGB(K) etc? // Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA. ChanR valueR = class Toggle "Red" valueR { _flag = "R", valueR = ""; Toggle_edit caption valueR = this.ChanR valueR; } channelR = ChanR true; ChanG valueG = class Toggle "Green" valueG { _flag = "G", valueG = ""; Toggle_edit caption valueG = this.ChanG valueG; } channelG = ChanG true; ChanB valueB = class Toggle "Blue" valueB { _flag = "B", valueB = ""; Toggle_edit caption valueB = this.ChanB valueB; } channelB = ChanB true; ChanK valueK = class Toggle "Black" valueK { _flag = "K", valueK = ""; Toggle_edit caption valueK = this.ChanK valueK; } channelK = ChanK true; ChanA valueA = class Toggle "Alpha" valueA { _flag = "A", valueA = ""; Toggle_edit caption valueA = this.ChanA valueA; } channelA = ChanA false; ChanSy valueSy = class Toggle "Sync" valueSy { _flag = ",sync", valueSy = ""; Toggle_edit caption valueSy = this.ChanSy valueSy; } channelSy = ChanSy true; _rgbka = concat [channelR._flag, channelG._flag, channelB._flag, channelK._flag, channelA._flag ]; _flag = "", _rgbka == "" || !has_channel = concat [ "-channel ", _rgbka, channelSy._flag ]; } ch_widget = channels_widget; Colorspace colsp = class Option_string "Colorspace" [ "CIELab", "CMY", "CMYK", "Gray", "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "Lab", "LCH", "LCHab", "LCHuv", "LMS", "Log", "Luv", "OHTA", "Rec601Luma", "Rec601YCbCr", "Rec709Luma", "Rec709YCbCr", "RGB", "scRGB", "sRGB", "Transparent", "XYZ", "YCbCr", "YDbDr", "YCC", "YIQ", "YPbPr", "YUV" ] colsp { _flag = colsp; Option_edit caption labels value = this.Colorspace labels?value; } colorspace_widget = Colorspace "sRGB"; Compose comp = class Option_string "Compose method" [ "Atop", "Blend", "Blur", "Bumpmap", "ChangeMask", "Clear", "ColorBurn", "ColorDodge", "Colorize", "CopyBlack", "CopyBlue", "CopyCyan", "CopyGreen", "Copy", "CopyMagenta", "CopyOpacity", "CopyRed", "CopyYellow", "Darken", "DarkenIntensity", "DivideDst", "DivideSrc", "Dst", "Difference", "Displace", "Dissolve", "Distort", "DstAtop", "DstIn", "DstOut", "DstOver", "Exclusion", "HardLight", "Hue", "In", "Lighten", "LightenIntensity", "LinearBurn", "LinearDodge", "LinearLight", "Luminize", "Mathematics", "MinusDst", "MinusSrc", "Modulate", "ModulusAdd", "ModulusSubtract", "Multiply", "None", "Out", "Overlay", "Over", "PegtopLight", "PinLight", "Plus", "Replace", "Saturate", "Screen", "SoftLight", "Src", "SrcAtop", "SrcIn", "SrcOut", "SrcOver", "VividLight", "Xor" ] comp { _flag = "-compose " ++ comp; Option_edit caption labels value = this.Compose labels?value; } compose_widget = Compose "Over"; // FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string. // FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack coordinate_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; _flag = concat [print x.expr, ",", print y.expr]; }; Distort distort = class Option_string "Distort" [ "Affine", "AffineProjection", "ScaleRotateTranslate", "SRT", "Perspective", "PerspectiveProjection", "BilinearForward", "BilinearReverse", "Polynomial", "Arc", "Polar", "DePolar", "Barrel", "BarrelInverse", "Shepards", "Resize" ] distort { _flag = distort; Option_edit caption labels value = this.Distort labels?value; } distort_widget = Distort "SRT"; Dither dither = class Option_string "Dither" [ "None", "FloydSteinberg", "Riemersma" ] dither { _flag = "-dither " ++ dither; Option_edit caption labels value = this.Dither labels?value; } dither_widget = Dither "FloydSteinberg"; Evaluate eval = class Option_string "Evaluate operation" [ "Abs", "Add", "AddModulus", "And", "Cos", "Cosine", "Divide", "Exp", "Exponential", "GaussianNoise", "ImpulseNoise", "LaplacianNoise", "LeftShift", "Log", "Max", "Mean", "Median", "Min", "MultiplicativeNoise", "Multiply", "Or", "PoissonNoise", "Pow", "RightShift", "Set", "Sin", "Sine", "Subtract", "Sum", "Threshold", "ThresholdBlack", "ThresholdWhite", "UniformNoise", "Xor" ] eval { _flag = "-evaluate " ++ eval; Option_edit caption labels value = this.Evaluate labels?value; } evaluate_widget = Evaluate "Add"; Filter filt = class Option_string "Filter" [ "default", "Bartlett", "Blackman", "Bohman", "Box", "Catrom", "Cosine", "Cubic", "Gaussian", "Hamming", "Hann", "Hermite", "Jinc", "Kaiser", "Lagrange", "Lanczos", "Lanczos2", "Lanczos2Sharp", "LanczosRadius", "LanczosSharp", "Mitchell", "Parzen", "Point", "Quadratic", "Robidoux", "RobidouxSharp", "Sinc", "SincFast", "Spline", "Triangle", "Welch" ] filt { _flag = if filt == "default" then "" else "-filter " ++ filt; Option_edit caption labels value = this.Filter labels?value; } filter_widget = Filter "default"; Function func = class Option_string "Function" [ "Polynomial", "Sinusoid", "Arcsin", "Arctan" ] func { _flag = func; Option_edit caption labels value = this.Function labels?value; } function_widget = Function "Polynomial"; // "Polynomial (a[n], a[n-1], ... a[1], a[0])", // "Sinusoid (freq, phase, amp, bias)", // "Arcsin (width, centre, range, bias)", // "Arctan (slope, centre, range, bias)" Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; ImageType imagetype = class Option_string "Image type" [ "Bilevel", "ColorSeparation", "ColorSeparationAlpha", "ColorSeparationMatte", "Grayscale", "GrayscaleAlpha", "GrayscaleMatte", "Optimize", "Palette", "PaletteBilevelAlpha", "PaletteBilevelMatte", "PaletteAlpha", "PaletteMatte", "TrueColorAlpha", "TrueColorMatte", "TrueColor" ] imagetype { _flag = "-type " ++ imagetype; Option_edit caption labels value = this.ImageType labels?value; } imagetype_widget = ImageType "TrueColor"; Intensity intensity = class Option_string "Intensity (gray conversion)" [ "Average", "Brightness", "Lightness", "MS", "Rec601Luma", "Rec601Luminance", "Rec709Luma", "Rec709Luminance", "RMS" ] intensity { _flag = "-intensity " ++ intensity, has_intensity = ""; Option_edit caption labels value = this.Intensity labels?value; } intensity_widget = Intensity "Rec709Luminance"; Interpolate interp = class Option_string "Interpolate" [ "default", "Average", "Average4", "Average9", "Average16", "Background", "Bilinear", "Blend", "Integer", "Mesh", "Nearest", "NearestNeighbor", "Spline" ] interp { _flag = if interp == "default" then "" else "-interpolate " ++ interp; Option_edit caption labels value = this.Interpolate labels?value; } interpolate_widget = Interpolate "default"; Kernel kernel = class Option_string "Kernel" [ "Unity", "Gaussian", "DoG", "LoG", "Blur", "Comet", "Binomial", "Laplacian", "Sobel", "FreiChen", "Roberts", "Prewitt", "Compass", "Kirsch", "Diamond", "Square", "Rectangle", "Disk", "Octagon", "Plus", "Cross", "Ring", "Peaks", "Edges", "Corners", "Diagonals", "LineEnds", "LineJunctions", "Ridges", "ConvexHull", "ThinSe", "Skeleton", "Chebyshev", "Manhattan", "Octagonal", "Euclidean" // FIXME: custom kernel ] kernel { _flag = kernel; Option_edit caption labels value = this.Kernel labels?value; } kernel_widget = Kernel "Unity"; ModColSp msp = class Option_string "modulate colorspace" [ "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "LCH" ] msp { _flag = "-set option:modulate:colorspace " ++ msp; Option_edit caption labels value = this.ModColSp labels?value; } ModColSp_widget = ModColSp "HSL"; MorphMeth morph = class Option_string "Method" [ "Correlate", "Convolve", "Dilate", "Erode", "Close", "Open", "DilateIntensity", "ErodeIntensity", "CloseIntensity", "OpenIntensity", "Smooth", "EdgeOut", "EdgeIn", "Edge", "TopHat", "BottomHat", "HitAndMiss", "Thinning", "Thicken", "Distance", "IterativeDistance" ] morph { _flag = morph; Option_edit caption labels value = this.MorphMeth labels?value; } morphmeth_widget = MorphMeth "Dilate"; Noise noise = class Option_string "Noise" [ "Gaussian", "Impulse", "Laplacian", "Multiplicative", "Poisson", "Random", "Uniform" ] noise { _flag = "+noise " ++ noise; Option_edit caption labels value = this.Noise labels?value; } noise_widget = Noise "Gaussian"; Pattern pattern = class Option_string "Noise" [ // See http://www.imagemagick.org/script/formats.php "bricks", "checkerboard", "circles", "crosshatch", "crosshatch30", "crosshatch45", "gray0", "gray5", "gray10", "gray15", "gray20", "gray25", "gray30", "gray35", "gray40", "gray45", "gray50", "gray55", "gray60", "gray65", "gray70", "gray75", "gray80", "gray85", "gray90", "gray95", "gray100", "hexagons", "horizontal", "horizontal2", "horizontal3", "horizontalsaw", "hs_bdiagonal", "hs_cross", "hs_diagcross", "hs_fdiagonal", "hs_horizontal", "hs_vertical", "left30", "left45", "leftshingle", "octagons", "right30", "right45", "rightshingle", "smallfishscales", "vertical", "vertical2", "vertical3", "verticalbricks", "verticalleftshingle", "verticalrightshingle", "verticalsaw" ] pattern { _flag = "pattern:" ++ pattern; Option_edit caption labels value = this.Pattern labels?value; } pattern_widget = Pattern "bricks"; ResizeType resizet = class Option_string "Resize type" [ "resize", "scale", "sample", "adaptive-resize" ] resizet { _flag = resizet; Option_edit caption labels value = this.ResizeType labels?value; } ResizeType_widget = ResizeType "resize"; Size_widget = class { _vislevel = 3; width = Expression "Width (pixels)" 64; height = Expression "Height (pixels)" 64; _flag = "-size " ++ print width.expr ++ "x" ++ print height.expr; }; StatType statt = class Option_string "Statistic type" [ "Gradient", "Maximum", "Mean", "Median", "Minimum", "Mode", "Nonpeak", "StandardDeviation" ] statt { _flag = statt; Option_edit caption labels value = this.StatType labels?value; } StatType_widget = StatType "Mean"; VirtualPixel vp = class Option_string "Virtual pixel" [ "Background", "Black", "CheckerTile", "Dither", "Edge", "Gray", "HorizontalTile", "HorizontalTileEdge", "Mirror", "None", "Random", "Tile", "Transparent", "VerticalTile", "VerticalTileEdge", "White" ] vp { _flag = "-virtual-pixel " ++ vp; _isBackground = (vp == "Background"); Option_edit caption labels value = this.VirtualPixel labels?value; } VirtualPixel_widget = VirtualPixel "Edge"; VirtualPixelBack_widget = class { virtpix = Magick.VirtualPixel_widget; background = Magick.background_widget; _flag = (if virtpix._isBackground then (background._flag ++ " ") else "") ++ virtpix._flag; } Geometry_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; AnnotGeometry_widget = class { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print shearX.expr, "x", print shearY.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; OffsetGeometry_widget = class { _vislevel = 3; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; WhxyGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; FrameGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; outbev = Expression "Outer bevel thickness" 0; inbev = Expression "Inner bevel thickness" 0; _flag = concat [print x.expr, "x", print y.expr, format outbev, format inbev] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } } nip2-8.7.1/share/nip2/compat/8.3/_predicate.def0000644000175000017500000003252613351443023015652 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Plot x = is_instanceof "Plot" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = oo_unary_function get_type_op x, is_class x = error (_ "bad arguments to " ++ "get_type") { get_type_op = Operator "get_type" get_type Operator_type.COMPOUND false; // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = oo_unary_function get_format_op x, is_class x = error (_ "bad arguments to " ++ "get_format") { get_format_op = Operator "get_format" get_format Operator_type.COMPOUND false; } has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = oo_unary_function get_bits_op x, is_class x = error (_ "bad arguments to " ++ "get_bits") { get_bits_op = Operator "get_bits" get_format Operator_type.COMPOUND false; } has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = oo_unary_function get_bands_op x, is_class x = error (_ "bad arguments to " ++ "get_bands") { get_bands_op = Operator "get_bands" get_bands Operator_type.COMPOUND false; } has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = oo_unary_function get_coding_op x, is_class x = error (_ "bad arguments to " ++ "get_coding") { get_coding_op = Operator "get_coding" get_coding Operator_type.COMPOUND false; } has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = oo_unary_function get_xres_op x, is_class x = error (_ "bad arguments to " ++ "get_xres") { get_xres_op = Operator "get_xres" get_xres Operator_type.COMPOUND false; } has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = oo_unary_function get_yres_op x, is_class x = error (_ "bad arguments to " ++ "get_yres") { get_yres_op = Operator "get_yres" get_yres Operator_type.COMPOUND false; } has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = oo_unary_function get_xoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_xoffset") { get_xoffset_op = Operator "get_xoffset" get_xoffset Operator_type.COMPOUND false; } has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = oo_unary_function get_yoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_yoffset") { get_yoffset_op = Operator "get_yoffset" get_yoffset Operator_type.COMPOUND false; } has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = oo_unary_function get_image_op x, is_class x = error (_ "bad arguments to " ++ "get_image") { get_image_op = Operator "get_image" get_image Operator_type.COMPOUND false; } has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = oo_unary_function get_number_op x, is_class x = error (_ "bad arguments to " ++ "get_number") { get_number_op = Operator "get_number" get_number Operator_type.COMPOUND false; } has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = oo_unary_function get_real_op x, is_class x = error (_ "bad arguments to " ++ "get_real") { get_real_op = Operator "get_real" get_real Operator_type.COMPOUND false; } has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = oo_unary_function get_width_op x, is_class x = error (_ "bad arguments to " ++ "get_width") { get_width_op = Operator "get_width" get_width Operator_type.COMPOUND false; } has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = oo_unary_function get_height_op x, is_class x = error (_ "bad arguments to " ++ "get_height") { get_height_op = Operator "get_height" get_height Operator_type.COMPOUND false; } has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = oo_unary_function get_left_op x, is_class x = error (_ "bad arguments to " ++ "get_left") { get_left_op = Operator "get_left" get_left Operator_type.COMPOUND false; } has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = oo_unary_function get_top_op x, is_class x = error (_ "bad arguments to " ++ "get_top") { get_top_op = Operator "get_top" get_top Operator_type.COMPOUND false; } // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/8.3/_list.def0000644000175000017500000002310313351443023014654 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* flatten x: flatten a list of lists of things into a simple list * * flatten :: [[*]] -> [*] */ flatten x = foldr flat [] x, is_list x = x { flat x sofar = foldr flat sofar x, is_list x = x : sofar; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st x) xs { x:xs = l; } /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn x xs { x:xs = l; } /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn x (foldr fn st xs) { x:xs = l; } /* foldr1 fn l: like foldr, but use the last element as the start value * * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = x, xs == [] = fn x (foldr1 fn xs) { x:xs = l; } /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn x = search xs (n + 1) { x:xs = l; } } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = x : init xs { x:xs = l; } /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = x, xs == [] = last xs { x:xs = l; } /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scanl fn st l: apply (foldl fn r) to every initial segment of a list * * scanl add 0 [1,2,3] == [1,3,6] * scanl :: (* -> ** -> *) -> * -> [**] -> [*] */ scanl fn st l = st, l == [] = st' : scanl fn st' xs { x:xs = l; st' = fn st x; } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/7.9/0000755000175000017500000000000013417043452013155 500000000000000nip2-8.7.1/share/nip2/compat/7.9/Image.def0000644000175000017500000002517713351443023014606 00000000000000/* take a copy of x */ Duplicate x = map_unary copy x; /* crop image x */ Crop x = map_unary build_widget x { build_widget image = widget image (image.width * 0.25 - image.xoffset) (image.height * 0.25 - image.yoffset) (image.width * 0.5) (image.height * 0.5); widget image left top width height = class Region image left top width height { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 4; Region_edit image left top width height = widget image left top width height; } } /* insert image b into image a */ Insert a b = class Image value { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _check_all = [ [a.format == b.format && a.coding == b.coding && a.bands == b.bands, "a.format == b.format && a.coding == b.coding && " ++ "a.bands == b.bands"], [a.width >= b.width && a.height >= b.height, "First image should be able to enclose second"] ]; _vislevel = 3; place = Area a ((a.width - b.width) / 2) ((a.height - b.height) / 2) b.width b.height; value = im_insert_noexpand a' b'' place.left place.top { a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; } } /* join two images left/right or up/down */ Join = class { _check_ab_args a b = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_ab_all a b = [ [a.format == b.format && a.coding == b.coding && a.bands == b.bands, "a.format == b.format && a.coding == b.coding && " ++ "a.bands == b.bands"] ]; /* join two images left-right */ Left_right a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; _check_all = _check_ab_all a b ++ super._check_all; shim = Slider 0 100 0; background_colour = 0; align = Option "Alignment" ["Top", "Centre", "Bottom"] 1; value = im2 { w = a.width + b.width + shim.value; h = max_pair a.height b.height; bg = image_new w h a.bands a.format a.coding a.type background_colour 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = im_insert_noexpand bg a.value 0 (ya?align); im2 = im_insert_noexpand im1 b.value (a.width + shim.value) (yb?align); } } /* join two images top-bottom */ Top_bottom a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; _check_all = _check_ab_all a b ++ super._check_all; shim = Slider 0 100 0; background_colour = 0; align = Option "Alignment" ["Left", "Centre", "Right"] 1; value = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim.value; bg = image_new w h a.bands a.format a.coding a.type background_colour 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = im_insert_noexpand bg a.value (xa?align) 0; im2 = im_insert_noexpand im1 b.value (xb?align) (a.height + shim.value); } } /* join a 2-D array of images */ Array x = class Image value { hspacing = Slider (-100) (100) 0; vspacing = Slider (-100) (100) 0; value = imagearray_assemble (-hspacing.value) (-vspacing.value) x' { x' = map (map getval) x; getval x = x.value, is_class x = x; } } } /* morph images to match (needs the rubbersheet plugin) */ Rubber = class { _rubber_interp = Option "Interpolation" (map (extract 0) Interpolate.names.value) Interpolate.bilinear; _rubber_order = Option "order" ["0", "1", "2", "3"] 1; _rubber_edges = Toggle "Wrap image edges" false; /* find a transform which will turn sample image into reference image */ Rubber_find reference sample = class Matrix transformation { _vislevel = 3; // controls order = _rubber_order; interp = _rubber_interp; edges = _rubber_edges; max_error = 0.3; max_iterations = 10; // transform _result = resample sample.value reference.value max_error max_iterations order.value interp.value edges.value; // results transformed_image = Image (_result?0); transformation = (_result?1).value; final_error = _result?2; } /* apply a transform to an image */ Rubber_apply transform image = class Image value { // controls interp = _rubber_interp; edges = _rubber_edges; value = im_transform image.value transform interp.value edges.value; } /* change a transformation's scale factor */ Rubber_scale transform = class Matrix scaled_transform { factor_hint = "scale transform by this factor"; factor_x = 1; factor_y = 1; // pairwise multiply scaled_transform = map2 (map2 multiply) transform.value facs { facs = [[ factor_x, factor_y ], [ 1, 1 ], [ 1, 1 ], [ 1 / factor_x, 1 / factor_y ], [ 1 / factor_x, 1 / factor_y ], [ 1 / factor_x, 1 / factor_y ]]; } } } #separator /* set pixels to 255 - x */ Photographic_negative x = map_unary invert x { invert x = oo_unary_function neg_op x, is_class x = im_invert x, is_image x = 255 - x, is_number x = error (errors.badargs ++ "invert"); neg_op = Operator "photographic_negative" invert Operator_type.ARITHMETIC false; } /* falsecolour a mono image */ Falsecolour x = map_unary falsecolour x; #separator /* adjust brightness and contrast of image x */ Adjust_scale_offset x = map_unary widget x { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; scale = Slider 0.001 255 1; offset = Slider (-128) 128 0; value = clip2fmt image.format (image * scale + offset).value; } } /* adjust gamma of image x */ Adjust_gamma x = map_unary widget x { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; gamma = Slider 0.001 4 1; image_maximum_hint = "Change image_maximum if this is " ++ "not an 8 bit image"; image_maximum = 255; value = clip2fmt image.format gammaed.value { gammaed = (image_maximum / image_maximum ** gamma) * image ** gamma; } } } /* change advisory header fields of image x */ Edit_header x = map_unary widget x { type_names = Image_type.type_names; names = sort (map (extract 0) type_names.value); widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; xres = image.xres; yres = image.yres; xoffset = image.xoffset; yoffset = image.yoffset; type_option = Option "Image type" names pos { name = type_names.lookup 1 0 image.type; pos = index (equal name) names; } value = im_copy_set image.value type xres yres xoffset yoffset { type = type_names.lookup 0 1 names?type_option; } } } #separator /* rotate and scale one image to match another */ Match a b = class Image value { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _vislevel = 3; ap1 = Point_relative a 0.5 0.25; bp1 = Point_relative b 0.5 0.25; ap2 = Point_relative a 0.5 0.75; bp2 = Point_relative b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; value = b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; ap1' = ap1.image_rect; ap2' = ap2.image_rect; bp1' = bp1.image_rect; bp2' = bp2.image_rect; b''' = im_match_linear_search a' b'' ap1'.left ap1'.top bp1'.left bp1'.top ap2'.left ap2'.top bp2'.left bp2'.top object window, refine = im_match_linear a' b'' ap1'.left ap1'.top bp1'.left bp1'.top ap2'.left ap2'.top bp2'.left bp2'.top; } } /* make a colour overlay of two mono images */ Overlay a b = class Image value { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _check_all = [ [a.bands == 1 && b.bands == 1, "a.bands == 1 && b.bands == 1"] ] ++ super._check_all; _vislevel = 3; ap1 = Point_relative a 0.5 0.25; bp1 = Point_relative b 0.5 0.25; ap2 = Point_relative a 0.5 0.75; bp2 = Point_relative b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; colour = Option "Colour overlay as" [ "Green over Red", "Blue over Red", "Red over Green", "Red over Blue", "Blue over Green", "Green over Blue" ] 0; value = [(a' ++ b''' ++ black), (a' ++ black ++ b'''), (b''' ++ a' ++ black), (b''' ++ black ++ a'), (black ++ a' ++ b'''), (black ++ b''' ++ a')]?colour { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; ap1' = ap1.image_rect; ap2' = ap2.image_rect; bp1' = bp1.image_rect; bp2' = bp2.image_rect; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1' ap2'; bp2'' = norm bp1' bp2'; b''' = im_match_linear_search a' b'' ap1'.left ap1'.top bp1'.left bp1'.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1'.left ap1'.top bp1'.left bp1'.top ap2''.left ap2''.top bp2''.left bp2''.top; black = image_new a.width a.height a.bands a.format a.coding a.type 0 0 0; } } /* browse through the bands of a multiband image with a slider */ Browse_multiband image = class Image value { _vislevel = 3; band = Slider 0 (image.bands - 1) 0; display = Option "Display as" [ "Grey", "Green over Red", "Blue over Red", "Red over Green", "Red over Blue", "Blue over Green", "Green over Blue" ] 0; value = output { down = (int) band.value; up = (int) (band.value + 1); remainder = band.value - down; a = (image.value ? up) * remainder; b = (image.value ? down) * (1 - remainder); c = image_new image.width image.height 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; output = [ a + b, a ++ b ++ c, a ++ c ++ b, b ++ a ++ c, b ++ c ++ a, c ++ a ++ b, c ++ b ++ a ] ? display; } } nip2-8.7.1/share/nip2/compat/7.9/Statistics.def0000644000175000017500000000610513351443023015704 00000000000000/* mean value of object */ Mean a = map_unary mean a; /* standard deviation of object */ Deviation a = map_unary deviation a; /* calculate a large set of stats on an object */ Stats a = map_unary stats a; #separator /* maximum of an object */ Max a = map_unary max a; /* minimum of an object */ Min a = map_unary min a; /* return complex number (max, min) */ Maxmin a = map_unary maxmin a { maxmin x = (Max x, Min x); } /* position of maximum in an image */ Maximum_position a = map_unary maxpos a; /* position of minimum in an image */ Minimum_position a = map_unary minpos a; #separator /* count the number of non-zeros in an image */ Count_set a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } /* count the number of zeros in an image */ Count_clear a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } #separator /* plot a scatter graph of a list of [x,y] coordinates */ Plot_scatter x //= map_unary widget x = widget x { widget data = class Image value { _check_args = [ [data, "data", check_xy_list] ] ++ super._check_args; width = 512; height = 512; plot_colour = Colour "Lab" [80, -80, 80]; xmin = foldr1 min_pair (map (extract 0) data); xmax = foldr1 max_pair (map (extract 0) data); ymin = foldr1 min_pair (map (extract 1) data); ymax = foldr1 max_pair (map (extract 1) data); axies = Toggle "Draw axies" true; mark = Point this x y { p = _to_image data?0; x = p?0; y = p?1; } mark_position_hint = "mark is at position:"; mark_position = _from_image [mark.left, mark.top]; // geometry _xrange = xmax - xmin; _yrange = ymax - ymin; _xscale = width / _xrange; _yscale = height / _yrange; // map an [x,y] point into the image coordinates _to_image p = [(p?0 - xmin) * _xscale, height - (p?1 - ymin) * _yscale]; // map an [x,y] point from image cods back to real cods _from_image p = [p?0 / _xscale + xmin, (height - p?1) / _yscale + ymin]; value = foldr plot background' data { plot_image_new width height pixel = image_new width height 3 Image_format.FLOAT Image_coding.NOCODING (Image_type.colour_spaces.lookup 0 1 plot_colour.colour_space) pixel 0 0; // background background = plot_image_new width height 0; // mark we plot mark_width = max_pair 1 (width / 100); mark_height = max_pair 1 (height / 100); mark = plot_image_new mark_width mark_height plot_colour; // draw axies on background background' = drawxy, axies = background { // axies xaxis = plot_image_new width 1 (Colour "Lab" [100, 0, 0]); yaxis = plot_image_new 1 height (Colour "Lab" [100, 0, 0]); origin = _to_image [0, 0]; drawx = im_insert_noexpand background xaxis 0 origin?1; drawxy = im_insert_noexpand drawx yaxis origin?0 0; } // plot a single point on an image plot p im = im_insert_noexpand im mark (x - mark_width / 2) (y - mark_height / 2) { p' = _to_image p; x = p'?0; y = p'?1; } } } } nip2-8.7.1/share/nip2/compat/7.9/_convert.def0000644000175000017500000003242113351443023015371 00000000000000 /* Convert an image ... just set the Type field. */ image_set_type type in = im_copy_set in type (im_header_double "Xres" in) (im_header_double "Yres" in) (im_header_int "Xoffset" in) (im_header_int "Yoffset" in); /* Convert an image ... just set origin */ image_set_origin xoff yoff in = im_copy_set in (im_header_int "Type" in) (im_header_double "Xres" in) (im_header_double "Yres" in) xoff yoff; /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = oo_unary_function to_matrix_op x, is_class x = tom x, is_real x || is_image x = error (errors.badargs ++ "to_matrix") { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (errors.badargs ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i && bands == 1 = (im_vips2mask ((double) i'')).value, is_image i && bands == 3 && width == 1 = error errors.not1band3band { width = im_header_int "Xsize" i; bands = im_header_int "Bands" i; split = bandsplit i; i' = im_insert (split?0) (split?1) 1 0; i'' = im_insert i' (split?2) 2 0; } } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_instanceof "Colour" x = oo_unary_function to_image_op x, is_class x = toi x, is_real x || is_image x = error (errors.badargs ++ "to_image") { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (errors.badargs ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } /* Try to make a real. */ to_real x = to_real x.value, is_class x = x, is_real x = abs x, is_complex x = error (errors.badargs ++ "to_real"); /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error "parse_c: not a digit", ! is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error "parse_number: badly formed number", len parts != 2 = sign * n { parts = splitpl [ member "+-", is_digit ] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, len parts != 4 = (ipart + fpart) * 10 ** exp { err = error "parse_float: badly formed number"; parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10**(len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Print integer as hex. */ print_hex i = "0", chars == [] = "0x" ++ reverse chars { digits = takewhile (not_equal 0) (map (bitwise_and 0xf) (iterate (converse right_shift 4) i)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'a' + (x - 10)); } /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[ 0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [ 0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { // divide by D50 white point xyz' = xyz / Vector [96.4250, 100.0, 82.4680]; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * Vector [95.0470, 100.0, 108.8827]; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { // divide by D65 white point xyz' = xyz / Vector [95.0470, 100.0, 108.8827]; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D50 xyz''' = xyz'' * Vector [96.4250, 100.0, 82.4680]; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz 96.4250 100 82.4680; /* Convert D50 Lab to XYZ. */ im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab 96.4250 100 82.4680; /* ... and mono conversions */ im_sRGB2mono in = clip2fmt (im_header_int "BandFmt" in) (im_recomb in (Matrix [[.3, .6, .1]])); im_mono2sRGB in = (unsigned char) (in ++ in ++ in); /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = fn x, is_image x = error (errors.badargs ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = fn x, is_image x = error (errors.badargs ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (errors.badargs ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (errors.badargs ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, LAB, im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, sRGB, im_mono2sRGB], [B_W, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy], [XYZ, LAB, im_XYZ2Lab], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS], [XYZ, RGB, im_XYZ2disp], [XYZ, sRGB, im_XYZ2sRGB], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ], [YXY, XYZ, im_Yxy2XYZ], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ], [LAB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ], [LAB, XYZ, im_Lab2XYZ], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ], [LAB, LAB, image_set_type LAB], [LAB, LCH, im_Lab2LCh], [LAB, UCS, im_Lab2UCS], [LAB, RGB, im_Lab2disp], [LAB, sRGB, im_XYZ2sRGB @ im_Lab2XYZ], [LAB, LABQ, im_Lab2LabQ], [LAB, LABS, im_Lab2LabS], [LCH, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab], [LCH, YXY, im_XYZ2Yxy @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab], [LCH, LAB, im_LCh2Lab], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS], [LCH, RGB, im_Lab2disp @ im_LCh2Lab], [LCH, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ], [UCS, XYZ, im_UCS2XYZ], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab], [UCS, LAB, im_UCS2Lab], [UCS, LCH, im_UCS2LCh], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab], [UCS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_UCS2Lab], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_XYZ2Lab @ im_sRGB2XYZ @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip], [LABQ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error ("unable to convert " ++ from_name ++ " to " ++ to_name) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; from_name = Image_type.type_names.lookup 1 0 from; to_name = Image_type.type_names.lookup 1 0 to; } /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_instanceof "Image" x || is_instanceof "Arrow" x || is_instanceof "Colour" x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_instanceof "Image" x = get_type_im x.image.value, is_instanceof "Arrow" x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_instanceof "Colour" x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.B_W, bands == 1 = type, bands == 3 && is_colorimetric = Image_type.MULTIBAND, bands != 3 && !is_colorimetric = type { is_colorimetric = Image_type.colour_spaces.present 1 type; type = im_header_int "Type" im; coding = im_header_int "Coding" im; bands = im_header_int "Bands" im; } } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; nip2-8.7.1/share/nip2/compat/7.9/Filter.def0000644000175000017500000003042313351443023014777 00000000000000/* Some useful masks. */ _filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; _filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; _filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; _filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; _filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; _filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; /* 3x3 blur of image */ Blur x = map_unary (conv _filter_blur) x; /* 3x3 sharpen of image */ Sharpen x = map_unary (conv _filter_sharp) x; /* 1-pixel displacement emboss */ Emboss x = map_unary (conv _filter_emboss) x; /* 3x3 median filter of image */ Median x = map_unary (rank 3 3 5) x; /* 3x3 laplacian of image */ Laplacian x = map_unary (conv _filter_laplacian) x; /* 3x3 Sobel edge detect of image */ Sobel x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv _filter_sobel im; b = conv (rot270 _filter_sobel) im; } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 _filter_lindet); images = map (converse conv im) masks; } } #separator /* custom convolution of an image */ Custom_convolution in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; border = Toggle "Output image matches input image in size" true; value = im_embed image' 0 off off image.width image.height, border = image' { conv_op = im_conv_raw, !separable && type == 0 = im_convsep_raw, separable && type == 0 = im_convf_raw, !separable && type == 1 = im_convsepf_raw, separable && type == 1 = error "boink!"; image' = conv_op image.value matrix; off = (matrix.width + 1) / 2; } } } /* blur with a radius and shape */ Custom_blur in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; radius = Slider 1 50 1; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; value = im_convsep in.value mask { /* Make a square mask. */ mask_sq_line = map (const 1) [1 .. 2 * radius.value - 1]; mask_sq_sum = foldr1 add mask_sq_line; mask_sq_sep = Matrix_con mask_sq_sum 0 [mask_sq_line]; /* Make a gaussian mask. sigma is not really related * to radius very well, sort-of bodge it. */ mask_g = im_gauss_imask (radius.value / 2) 0.2; mask_g_line = mask_g.value ? (mask_g.height / 2); mask_g_sum = foldr1 add mask_g_line; mask_g_sep = Matrix_con mask_g_sum 0 [mask_g_line]; mask = mask_sq_sep, shape.value == 0 = mask_g_sep; } } } /* cored sharpen of L only in LAB image */ Custom_sharpen in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; size = Option "Mask size" [ "3 x 3", "5 x 5", "7 x 7", "9 x 9", "11 x 11" ] 0; smooth_threshold = Slider 0 5 1.5; brighten_max = Slider 1 50 10; darken_max = Slider 1 50 50; flat_sharp = Slider (-2) 5 1; jaggy_sharp = Slider (-2) 5 2; value = im_sharpen in.value [3, 5, 7, 9, 11]?size smooth_threshold.value brighten_max.value darken_max.value flat_sharp.value jaggy_sharp.value; } } /* custom rank filter of an image */ Custom_rank in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; window_size_hint = "Length of side of window to pass " ++ "over image:"; window_size = 3; rank = (int) ((window_size * window_size + 1) / 2); border = Toggle "Output image matches input image in size" true; value = im_embed image' 0 off off image.width image.height, border = image' { image' = im_rank_raw image.value window_size window_size rank; off = (window_size + 1) / 2; } } } /* statistical difference of an image */ Statistical_difference in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; window_size_hint = "Length of side of window to pass " ++ "over image:"; window_size = 11; target_mean = 128; target_mean_weight = Slider 0 1 0.8; target_deviation = 50; target_deviation_weight = Slider 0 1 0.8; border = Toggle "Output image matches input image in size" true; value = im_embed image' 0 off off image.width image.height, border = image' { image' = im_stdif_raw image.value target_mean_weight.value target_mean target_deviation_weight.value target_deviation window_size window_size; off = (window_size + 1) / 2; } } } #separator /* various ideal fourier filters */ Ideal_filter = class { _preview_size = 64; _high_low image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff.value 0 0 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff.value 0 0 0 0; } _ring image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 6; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff.value ring_width.value 0 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff.value ring_width.value 0 0 0; } _band image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 12; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value 0 0; } /* high or low pass ideal filter */ High_low x = map_unary _high_low x; /* ring pass or reject ideal filter */ Ring x = map_unary _ring x; /* band pass or reject ideal filter */ Band x = map_unary _band x; } /* Gaussian fourier filters */ Gaussian_filter = class { _preview_size = 64; _high_low image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value + 4; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff.value amplitude_cutoff.value 0 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff.value amplitude_cutoff.value 0 0 0; } _ring image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 10; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff.value ring_width.value amplitude_cutoff.value 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff.value ring_width.value amplitude_cutoff.value 0 0; } _band image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 16; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value 0; } value = im_flt_image_freq image.value _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value 0; } /* high or low pass Gaussian filter */ High_low x = map_unary _high_low x; /* ring pass or reject Gaussian filter */ Ring x = map_unary _ring x; /* band pass or reject Gaussian filter */ Band x = map_unary _band x; } /* various Butterworth fourier filters */ Butterworth_filter = class { _preview_size = 64; _high_low image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; order = Slider 1 10 2; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value + 2; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type order.value frequency_cutoff.value amplitude_cutoff.value 0 0; } value = im_flt_image_freq image.value _type order.value frequency_cutoff.value amplitude_cutoff.value 0 0; } _ring image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; order = Slider 1 10 2; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 8; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type order.value frequency_cutoff.value ring_width.value amplitude_cutoff.value 0; } value = im_flt_image_freq image.value _type order.value frequency_cutoff.value ring_width.value amplitude_cutoff.value 0; } _band image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; order = Slider 1 10 2; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 14; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type order.value frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value; } value = im_flt_image_freq image.value _type order.value frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value; } /* high or low pass Butterworth filter */ High_low x = map_unary _high_low x; /* ring pass or reject Butterworth filter */ Ring x = map_unary _ring x; /* band pass or reject Butterworth filter */ Band x = map_unary _band x; } nip2-8.7.1/share/nip2/compat/7.9/Format.def0000644000175000017500000001125013351443023014777 00000000000000/* various operations to convert numeric precision */ Convert_format_to = class { /* convert to unsigned 8 bit [0, 255] */ unsigned_8bit x = map_unary cast_unsigned_char x; /* convert to signed 8 bit [-128, 127] */ signed_8bit x = map_unary cast_signed_char x; /* convert to unsigned 16 bit [0, 65535] */ unsigned_16bit x = map_unary cast_unsigned_short x; /* convert to signed 16 bit [-32768, 32767] */ signed_16bit x = map_unary cast_signed_short x; /* convert to unsigned 32 bit [0, 4294967295] */ unsigned_32bit x = map_unary cast_unsigned_int x; /* convert to signed 32 bit [-2147483648, 2147483647] */ signed_32bit x = map_unary cast_signed_int x; /* convert to IEEE 32 bit floating point */ float_32bit x = map_unary cast_float x; /* convert to IEEE 64 bit floating point */ float_64bit x = map_unary cast_double x; /* convert to 64 bit complex (2 x IEEE 32 bit floating point) */ complex_64bit x = map_unary cast_complex x; /* convert to 128 bit complex (2 x IEEE 64 bit floating point) */ complex_128bit x = map_unary cast_double_complex x; } /* linear scale of pixel values to fit range 0-255 */ Scale_to_byte x = map_unary scale x; #separator /* try to make a matrix out of an object */ Convert_to_matrix in = map_unary to_matrix in; /* try to make an image out of an object */ Convert_to_image in = map_unary to_image in; #separator /* measure average value of a set of patches */ Matrix_from_colour_chart x = map_unary chart x { chart image = class Matrix value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; pacross = 6; pdown = 4; value = (im_measure image.value 0 0 image.width image.height pacross pdown).value; /* Hmm, not very helpful, we throw edits away. */ Matrix_vips_edit value scale offset filename display = chart image; } } /* make a synthetic colour chart image from a matrix */ Colour_chart_from_matrix matrix = map_unary build_chart matrix { build_chart matrix = class Image value { _check_args = [ [matrix, "matrix", check_Matrix] ] ++ super._check_args; patches_across = 6; patches_down = 4; patch_width = 50; patch_height = 50; border_width = 0; value = imagearray_assemble overlap overlap patch_table { overlap = -border_width; // patch numbers for row starts rowstart = map (multiply patches_across) [0 .. patches_down - 1]; // assemble patches ... each one a pixel value patches = map (take patches_across) (map (converse drop matrix.value) rowstart); // make an n-band constant image from eg. [1,2,3] patch v = image_new patch_width patch_height (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } #separator /* make a colour from the average values in an image */ Colour_from_image image = map_unary test image { test x = build_chart x, is_instanceof "Image" x = build_chart (Image pixel), is_instanceof "Point" x = error ("Colour_from_image: arg not Image or Point: " ++ print x) { pixel = x.image.extract_area x.left x.top 1 1; } build_chart image = class Colour colour_space value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; colour_space = table.lookup 1 0 type, table.present 1 type = error ("Colour_from_image: unable to make Colour " ++ "from " ++ Image_type.type_names.lookup 1 0 type ++ " image") { table = Image_type.colour_spaces; type = im_header_int "Type" image.value; } value = map mean (bandsplit image.value); } } /* make a constant image from a colour patch */ Image_from_colour x = map_unary build x { build c = class Image value { _check_args = [ [c, "c", check_Colour] ] ++ super._check_args; width = 64; height = 64; value = image_new width height 3 Image_format.FLOAT Image_coding.NOCODING (get_type c) c 0 0; } } #separator /* try to break object in into a list of components */ Decompose in = map_unary dec in { dec x = bandsplit x, is_instanceof "Image" x = map Vector x.value, is_instanceof "Matrix_base" x = x.value, is_instanceof "Vector" x || is_instanceof "Real" x = error "Decompose: not Image/Matrix/Vector/Real"; } /* try to put a list of objects together into a large single object */ Compose x = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof (is_instanceof "Image") x = Vector (map get_value x), is_listof (is_instanceof "Real") x = Matrix (map get_value x), is_listof (is_instanceof "Vector") x = map_unary Compose x, is_list x = error "Compose: not list of Image/Vector/Real/image/real" { get_value x = x.value; } nip2-8.7.1/share/nip2/compat/7.9/Colour.def0000644000175000017500000004036613351443023015024 00000000000000/* Save a bit of typing. */ _colour_conv from to x = map_unary (colour_transform from to) x; /* convert Mono to various formats */ Mono_to = class { /* convert mono colourspace to mono colourspace */ Mono x = _colour_conv Image_type.B_W Image_type.B_W x; /* convert mono colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.B_W Image_type.XYZ x; /* convert mono colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.B_W Image_type.YXY x; /* convert mono colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.B_W Image_type.LAB x; /* convert mono colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.B_W Image_type.LCH x; /* convert mono colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.B_W Image_type.UCS x; /* convert mono colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.B_W Image_type.RGB x; /* convert mono colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.B_W Image_type.sRGB x; /* convert mono colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.B_W Image_type.LABQ x; /* convert mono colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.B_W Image_type.LABS x; } /* convert XYZ to various formats */ XYZ_to = class { /* convert XYZ colourspace to mono colourspace */ Mono x = _colour_conv Image_type.XYZ Image_type.B_W x; /* convert XYZ colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.XYZ Image_type.XYZ x; /* convert XYZ colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.XYZ Image_type.YXY x; /* convert XYZ colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.XYZ Image_type.LAB x; /* convert XYZ colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.XYZ Image_type.LCH x; /* convert XYZ colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.XYZ Image_type.UCS x; /* convert XYZ colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.XYZ Image_type.RGB x; /* convert XYZ colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.XYZ Image_type.sRGB x; /* convert XYZ colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.XYZ Image_type.LABQ x; /* convert XYZ colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.XYZ Image_type.LABS x; } /* convert Yxy to various formats */ Yxy_to = class { /* convert Yxy colourspace to mono colourspace */ Mono x = _colour_conv Image_type.YXY Image_type.B_W x; /* convert Yxy colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.YXY Image_type.XYZ x; /* convert Yxy colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.YXY Image_type.YXY x; /* convert Yxy colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.YXY Image_type.LAB x; /* convert Yxy colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.YXY Image_type.LCH x; /* convert Yxy colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.YXY Image_type.UCS x; /* convert Yxy colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.YXY Image_type.RGB x; /* convert Yxy colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.YXY Image_type.sRGB x; /* convert Yxy colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.YXY Image_type.LABQ x; /* convert Yxy colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.YXY Image_type.LABS x; } /* convert Lab to various formats */ Lab_to = class { /* convert Lab colourspace to mono colourspace */ Mono x = _colour_conv Image_type.LAB Image_type.B_W x; /* convert Lab colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.LAB Image_type.XYZ x; /* convert Lab colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.LAB Image_type.YXY x; /* convert Lab colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.LAB Image_type.LAB x; /* convert Lab colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.LAB Image_type.LCH x; /* convert Lab colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.LAB Image_type.UCS x; /* convert Lab colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.LAB Image_type.RGB x; /* convert Lab colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.LAB Image_type.sRGB x; /* convert Lab colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.LAB Image_type.LABQ x; /* convert Lab colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.LAB Image_type.LABS x; } /* convert LCh to various formats */ LCh_to = class { /* convert LCh colourspace to mono colourspace */ Mono x = _colour_conv Image_type.LCH Image_type.B_W x; /* convert LCh colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.LCH Image_type.XYZ x; /* convert LCh colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.LCH Image_type.YXY x; /* convert LCh colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.LCH Image_type.LAB x; /* convert LCh colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.LCH Image_type.LCH x; /* convert LCh colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.LCH Image_type.UCS x; /* convert LCh colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.LCH Image_type.RGB x; /* convert LCh colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.LCH Image_type.sRGB x; /* convert LCh colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.LCH Image_type.LABQ x; /* convert LCh colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.LCH Image_type.LABS x; } /* convert UCS to various formats */ UCS_to = class { /* convert UCS colourspace to mono colourspace */ Mono x = _colour_conv Image_type.UCS Image_type.B_W x; /* convert UCS colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.UCS Image_type.XYZ x; /* convert UCS colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.UCS Image_type.YXY x; /* convert UCS colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.UCS Image_type.LAB x; /* convert UCS colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.UCS Image_type.LCH x; /* convert UCS colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.UCS Image_type.UCS x; /* convert UCS colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.UCS Image_type.RGB x; /* convert UCS colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.UCS Image_type.sRGB x; /* convert UCS colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.UCS Image_type.LABQ x; /* convert UCS colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.UCS Image_type.LABS x; } /* convert RGB to various formats */ RGB_to = class { /* convert RGB colourspace to mono colourspace */ Mono x = _colour_conv Image_type.RGB Image_type.B_W x; /* convert RGB colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.RGB Image_type.XYZ x; /* convert RGB colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.RGB Image_type.YXY x; /* convert RGB colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.RGB Image_type.LAB x; /* convert RGB colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.RGB Image_type.LCH x; /* convert RGB colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.RGB Image_type.UCS x; /* convert RGB colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.RGB Image_type.RGB x; /* convert RGB colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.RGB Image_type.sRGB x; /* convert RGB colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.RGB Image_type.LABQ x; /* convert RGB colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.RGB Image_type.LABS x; } /* convert sRGB to various formats */ sRGB_to = class { /* convert sRGB colourspace to mono colourspace */ Mono x = _colour_conv Image_type.sRGB Image_type.B_W x; /* convert sRGB colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.sRGB Image_type.XYZ x; /* convert sRGB colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.sRGB Image_type.YXY x; /* convert sRGB colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.sRGB Image_type.LAB x; /* convert sRGB colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.sRGB Image_type.LCH x; /* convert sRGB colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.sRGB Image_type.UCS x; /* convert sRGB colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.sRGB Image_type.RGB x; /* convert sRGB colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.sRGB Image_type.sRGB x; /* convert sRGB colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.sRGB Image_type.LABQ x; /* convert sRGB colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.sRGB Image_type.LABS x; } /* convert LabQ to various formats */ LabQ_to = class { /* convert LabQ colourspace to mono colourspace */ Mono x = _colour_conv Image_type.LABQ Image_type.B_W x; /* convert LabQ colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.LABQ Image_type.XYZ x; /* convert LabQ colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.LABQ Image_type.YXY x; /* convert LabQ colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.LABQ Image_type.LAB x; /* convert LabQ colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.LABQ Image_type.LCH x; /* convert LabQ colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.LABQ Image_type.UCS x; /* convert LabQ colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.LABQ Image_type.RGB x; /* convert LabQ colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.LABQ Image_type.sRGB x; /* convert LabQ colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.LABQ Image_type.LABQ x; /* convert LabQ colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.LABQ Image_type.LABS x; } /* convert LabS to various formats */ LabS_to = class { /* convert LabS colourspace to mono colourspace */ Mono x = _colour_conv Image_type.LABS Image_type.B_W x; /* convert LabS colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.LABS Image_type.XYZ x; /* convert LabS colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.LABS Image_type.YXY x; /* convert LabS colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.LABS Image_type.LAB x; /* convert LabS colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.LABS Image_type.LCH x; /* convert LabS colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.LABS Image_type.UCS x; /* convert LabS colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.LABS Image_type.RGB x; /* convert LabS colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.LABS Image_type.sRGB x; /* convert LabS colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.LABS Image_type.LABQ x; /* convert LabS colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.LABS Image_type.LABS x; } #separator /* recombine image bands with an editable matrix */ Colour_recombination in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; matrix = Matrix_rec (identity_matrix image.bands); value = recomb matrix image.value; } } /* colour temperature conversions */ Colour_temperature = class { /* convert XYZ from D65 to D50 ... use the Bradford approximation */ D65XYZ_to_D50XYZ in = map_unary (colour_unary im_D652D50) in; /* convert XYZ from D50 to D65 ... use the Bradford approximation */ D50XYZ_to_D65XYZ in = map_unary (colour_unary im_D502D65) in; } /* various colour difference metrics */ dE_ = class { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ _apply_cvt cvt x = cvt x, is_instanceof "Image" x || is_instanceof "Colour" x || is_image x = x; _diff cvt in1 in2 = abs_vec (_apply_cvt cvt in1 - _apply_cvt cvt in2); /* Converter to LAB. */ _lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ _ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; /* calculate delta-E CIE76 for two objects */ CIE76 in1 in2 = map_binary (_diff _lab_cvt) in1 in2; /* calculate delta-E00 (CIEDE2000) for two objects */ CIE00 in1 in2 = map_binary (colour_binary "im_dE00_fromLab" im_dE00_fromLab) in1 in2; /* calculate delta-E CMC(1:1) for two objects */ UCS in1 in2 = map_binary (_diff _ucs_cvt) in1 in2; } #separator /* apply a coloured tint to a monochrome image */ Tint_mono_image in = map_unary apply_tint in { apply_tint in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; tint = Colour "Lab" [50, 0, 0]; value = image_set_type Image_type.LAB (fancytint inp l_tint a_tint b_tint) { // input image ... to L only inp_lab = colour_transform_to Image_type.LAB in.value; inp = inp_lab?0; // make sure tint is LAB (might be edited) lab_tint = colour_transform_to Image_type.LAB tint; // selected lab l_tint = lab_tint.value?0; a_tint = lab_tint.value?1; b_tint = lab_tint.value?2; // fancy tint function ... don't tint black and white fancytint im l a b = im ++ ima ++ imb { mod = (100 - im) / (100 - l), im > l = im / l; backgr = image_new in.width in.height 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; ima = mod * (backgr + a); imb = mod * (backgr + b); } } } } /* displace neutral axis in LAB colourspace */ Adjust_cast image = map_unary widget image { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; green_red = Slider (-20) 20 0; blue_yellow = Slider (-20) 20 0; value = (colour_transform_to (get_type image) image'').value { image' = colour_transform_to Image_type.LAB image; image'' = image' + Vector [0, green_red.value, blue_yellow.value]; } } } /* displace h, scale LC in LCh colourspace */ Adjust_hue_saturation_brightness image = map_unary widget image { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; hue = Slider 0 360 0; saturation = Slider 0.01 5 1; brightness = Slider 0.01 5 1; value = (colour_transform_to (get_type image) image'').value { image' = colour_transform_to Image_type.LCH image; image'' = image' * Vector [bv, sv, 1] + Vector [0, 0, hv]; bv = brightness.value; sv = saturation.value; hv = hue.value; } } } /* find pixels with a similar colour */ Similar_colour image = map_unary match image { match image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; target_patch = Region image (20 - image.xoffset) (20 - image.yoffset) 10 10; target_colour = Colour_from_image target_patch; dE_threshold = Slider 0 100 10; value = (dE_.CIE76 image target_colour < dE_threshold).value; } } /* plot an ab scatter histogram */ Plot_ab_scatter image = map_unary widget image { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; bins = 8; value = bg * (((90 / mx) * hist) ++ blk) { lab = colour_transform_to Image_type.LAB image.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins ab; mx = max hist; bg = lab_slice bins 1; blk = 1 + im_black bins bins 2; } } } nip2-8.7.1/share/nip2/compat/7.9/Morphology.def0000644000175000017500000000626313351443023015716 00000000000000/* Some useful masks. */ _morph_mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; _morph_mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; _morph_mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; _morph_thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; /* dilate x with 8-connected mask */ Dilate8 x = map_unary (dilate _morph_mask8) x; /* dilate x with 4-connected mask */ Dilate4 x = map_unary (dilate _morph_mask4) x; /* erode x with 8-connected mask */ Erode8 x = map_unary (erode _morph_mask8) x; /* erode x with 4-connected mask */ Erode4 x = map_unary (erode _morph_mask4) x; #separator /* open with 8-connected mask */ Open x = map_unary (dilate _morph_mask8 @ erode _morph_mask8) x; /* close with 8-connected mask */ Close x = map_unary (erode _morph_mask8 @ dilate _morph_mask8) x; /* remove single points */ Clean x = map_unary clean x { clean x = x ^ erode _morph_mask1 x; } /* thin once */ Thin x = map_unary thinall x { masks = take 8 (iterate rot45 _morph_thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } #separator /* dilate object x with mask m */ Dilate m x = map_unary (dilate m) x; /* erode object x with mask m */ Erode m x = map_unary (erode m) x; /* dilate mask m with itself n times */ Dilate_multiple m n = (iterate (dilate m) m)?n; /* erode mask m with itself n times */ Erode_multiple m n = (iterate (erode m) m)?n; #separator /* morph with a mask you can edit */ Custom_morphology in = map_unary morph in { morph image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; mask = _morph_mask8; type = Option "Operation" ["Erode", "Dilate"] 1; hint_apply_n_times = "Number of times to apply mask:"; apply_n_times = 1; border = Toggle "Output image matches input image in size" true; value = im_embed image' 0 xoff yoff image.width image.height, border = image' { fatmask = (iterate (dilate mask) mask) ? (apply_n_times - 1); image' = im_erode_raw image.value fatmask, type.value == 0 = im_dilate_raw image.value fatmask; xoff = (fatmask.width + 1) / 2; yoff = (fatmask.height + 1) / 2; } } } /* search in from the edges of an image for the first non-zero pixel */ Find_profile in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; value = image_set_type Image_type.HISTOGRAM [ im_profile image.value 0, rot270 (im_profile image.value 1), im_profile (flipud image.value) 0, rot270 (im_profile (fliplr image.value) 1) ]?edge; } } /* count the average number of black-to-white transitions across an image */ Count_lines in = map_unary widget in { widget image = class Real value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; value = im_cntlines image.value edge.value; } } nip2-8.7.1/share/nip2/compat/7.9/Resize.def0000644000175000017500000000463613351443023015022 00000000000000_resize_interp = Option "Interpolation" (map (extract 0) Interpolate.names.value) Interpolate.bilinear; /* resize image x by any scale factor */ Resize_image x = map_unary widget x { widget image = class Image value { _vislevel = 3; factor = 1; interp = _resize_interp; value = resize factor factor interp.value image.value; } } /* resize image with separate x/y factors */ Resize_xy_image x = map_unary widget x { widget image = class Image value { _vislevel = 3; xfactor = 1; yfactor = 1; interp = _resize_interp; value = resize xfactor yfactor interp.value image.value; } } /* place image x in a larger piece of image */ Resize_canvas x = map_unary widget x { widget image = class Image value { _vislevel = 3; new_image_width = image.width; new_image_height = image.height; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east" ] 4; fill = Option "Fill background with" [ "White", "Black" ] 0; value = im_insert_noexpand background image.value xp yp { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; background_colour = image_white image, fill == 0 = Vector (map (const 0) [1 .. bands]); // placement vectors ... left, centre, right xposv = [0, new_image_width / 2 - width / 2, new_image_width - width]; yposv = [0, new_image_height / 2 - height / 2, new_image_height - height]; xp = xposv?((int) (position % 3)); yp = yposv?((int) (position / 3)); background = image_new new_image_width new_image_height bands format coding type background_colour 0 0; } } } #separator /* resize image x so that the shortest axis is a certain size */ Shrink_to = class { _shrink_width default_size image = class Image value { size = default_size; interp = _resize_interp; value = resize factor factor interp.value image.value { xfac = size / image.width; yfac = size / image.height; factor = max_pair xfac yfac; } } /* shrink minimum dimension to 400 pixels */ Quicklook x = map_unary (_shrink_width 400) x; /* shrink minimum dimension to 64 pixels */ Icon x = map_unary (_shrink_width 64) x; } nip2-8.7.1/share/nip2/compat/7.9/Math.def0000644000175000017500000001325113351443023014443 00000000000000/* basic arithmetic for objects */ Arithmetic = class { /* add a and b */ Add a b = map_binary add a b; /* subtract b from a */ Subtract a b = map_binary subtract a b; /* multiply a by b */ Multiply a b = map_binary multiply a b; /* divide a by b */ Divide a b = map_binary divide a b; /* remainder after dividing a by b */ Remainder a b = map_binary remainder a b; sep1 = Separator; /* absolute value of x */ Absolute_value x = map_unary abs x; /* like Absolute_value, but treat pixels as vectors */ Absolute_value_vector x = map_unary abs_vec x; /* calculate unit vector for band elements */ Sign x = map_unary sign x; /* multiply by -1 */ Negate x = map_unary unary_minus x; } /* trigonometry operations (all in degrees) */ Trig = class { /* calculate sine x */ Sin x = map_unary sin x; /* calculate cosine x */ Cos x = map_unary cos x; /* calculate tangent x */ Tan x = map_unary tan x; sep1 = Separator; /* calculate arc sine x */ Asin x = map_unary asin x; /* calculate arc cosine x */ Acos x = map_unary acos x; /* calculate arc tangent x */ Atan x = map_unary atan x; sep2 = Separator; /* convert degrees to radians */ Rad x = map_unary rad x; /* convert radians to degrees */ Deg x = map_unary deg x; sep3 = Separator; /* is angle within t degrees of r, mod 360 */ Angle_range t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } /* logarithms and anti-logs */ Log = class { /* calculate e ** x */ Exponential x = map_unary (power e) x; /* log base e of x */ Log_natural x = map_unary log x; sep1 = Separator; /* log base 10 of x */ Log10 x = map_unary log10 x; /* calculate 10 ** x */ Exponential10 x = map_unary (power 10) x; sep2 = Separator; /* calculate x ** y */ Raise_to_power x y = map_binary power x y; } /* operations on complex numbers and images */ Complex = class { /* extract fields from complex */ Complex_extract = class { /* extract real part of complex */ Real in = map_unary re in; /* extract imaginary part of complex */ Imaginary in = map_unary im in; } /* join a and b to make a complex */ Complex_build a b = map_binary comma a b; sep1 = Separator; /* convert real and imag to amplitude and phase */ Polar a = map_unary polar a; /* convert (amplitude, phase) image to rectangular coordinates */ Rectangular x = map_unary rectangular x; sep2 = Separator; /* invert imaginary part */ Conjugate x = map_unary conj x; } /* bitwise boolean operations for integer objects */ Boolean = class { /* bitwise and of a and b */ And a b = map_binary bitwise_and a b; /* bitwise or of a and b */ Or a b = map_binary bitwise_or a b; /* bitwise exclusive or of a and b */ Eor a b = map_binary eor a b; /* invert a */ Not a = map_unary not a; sep1 = Separator; /* shift a right by b bits */ Right_shift a b = map_binary right_shift a b; /* shift a left by b bits */ Left_shift a b = map_binary left_shift a b; sep2 = Separator; /* b where a is non-zero, c elsewhere */ If_then_else a b c = map_trinary if_then_else a b c; /* or the bands of an image together */ Band_or im = foldr1 bitwise_or (bandsplit im); /* and the bands of an image together */ Band_and im = foldr1 bitwise_and (bandsplit im); } /* all comparison operations */ Relational = class { /* find points at which a is equal to b */ Equal a b = map_binary equal a b; /* find points at which a is not equal to b */ Not_equal a b = map_binary not_equal a b; /* find points at which a is greater than b */ More a b = map_binary more a b; /* find points at which a is less than b */ Less a b = map_binary less a b; /* find points at which a is greater than or equal to b */ More_equal a b = map_binary more_equal a b; /* find points at which a is less than or equal to b */ Less_equal a b = map_binary less_equal a b; } /* operations on lists */ List = class { /* take first element of list */ Head x = hd x; /* drop the first element of list */ Tail x = tl x; /* drop the last element of list */ Init x = init x; /* take the last element of list */ Last x = last x; sep1 = Separator; /* reverse order of elements in list */ Reverse x = reverse x; /* sort elements of list into ascending order */ Sort x = sort x; /* remove duplicates from list */ Make_set x = mkset equal x; /* exchange rows and columns in a list of lists */ Transpose_list x = transpose x; /* flatten a list of lists into a single list */ Concat l = concat l; sep2 = Separator; /* find the length of list */ Length x = len x; /* return element n from list (index from zero) */ Subscript n x = n ? x; /* take the first n elements of list x */ Take n x = take n x; /* drop the first n elements of list x */ Drop n x = drop n x; sep3 = Separator; /* join two lists end to end */ Join a b = a ++ b; /* put element a on the front of list x */ Cons a x = a : x; /* join two lists, pairwise */ Zip a b = zip2 a b; } /* various rounding operations */ Round = class { /* smallest integral value not less than x */ Ceil x = map_unary ceil x; /* largest integral value not greater than x */ Floor x = map_unary floor x; /* round to nearest integer */ Rint x = map_unary rint x; } /* forward and reverse fourier transforms */ Fourier = class { /* find fourier transform of image */ Forward a = map_unary (rotquad @ fwfft) a; /* find inverse fourier transform of image */ Reverse a = map_unary (invfft @ rotquad) a; /* rotate quadrants */ Rotate_quadrants a = map_unary rotquad a; } nip2-8.7.1/share/nip2/compat/7.9/Print.def0000644000175000017500000001541613351443023014653 00000000000000/* cored sharpen of L only in LAB image ... tuned for typical printers */ Sharpen_for_print in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "300 dpi", "150 dpi", "75 dpi" ] 0; // sharpen params for 300, 150 and 75 dpi // just change the size of the area we search _param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5] ]; _params = _param_table?target_dpi; value = im_sharpen (colour_transform_to Image_type.LABQ in.value) _params?0 _params?1 _params?2 _params?3 _params?4 _params?5; } } /* adjust tone curve on L* */ Tone_for_print in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; black = Slider 0 100 0; white = Slider 0 100 100; shadow_point = Slider 0.1 0.3 0.2; mid_point = Slider 0.4 0.6 0.5; highlight_point = Slider 0.7 0.9 0.8; shadow_adjust = Slider (-15) 15 0; mid_adjust = Slider (-30) 30 0; highlight_adjust = Slider (-15) 15 0; preview_curve = Image (im_tone_build black.value white.value shadow_point.value mid_point.value highlight_point.value shadow_adjust.value mid_adjust.value highlight_adjust.value); value = im_tone_map (colour_transform_to Image_type.LABQ in.value) preview_curve.value; } } /* morph image colours in LAB space ... useful for tweaking colour for print */ Morph_for_print in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; L_scale = 1.15; L_offset = -4.2; ab_scale = Slider 1 1.5 1.15; a_offset = Slider (-10) 10 0; b_offset = Slider (-10) 10 5; grey_correction = Matrix_con 1 0 [ [5, 5, -1 ], [10, 4, -1 ], [15, 2, -1 ], [20, 1, 1 ], [25, 1, 2 ], [30, 0, 1 ], [35, 0, 1 ], [40, 0, 1 ], [45, 0, 1 ], [50, 0, 1 ], [55, 0, 0 ], [99, 0, 0 ] ]; value = im_lab_morph in.value (Vector [0, a_offset.value, b_offset.value] + grey_correction) L_offset L_scale ab_scale.value ab_scale.value; } } #separator _sample_print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; _sample_monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; _render_intents = Option "Render intent" [ "Perceptual", "Relative", "Saturation", "Absolute" ] 3; /* transform from PCS to device space */ ICC_export in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; profile = Filename _sample_print_profile; intent = _render_intents; depth = Option "Output depth" ["8 bit", "16 bit"] 0; value = im_icc_export_depth in.value [8, 16]?depth (expand profile.value) intent.value; } } /* transform from device space to PCS */ ICC_import in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _check_all = [ [in.bands == 3 || in.bands == 4, "in.bands == 3 || in.bands == 4" ] ] ++ super._check_all; _vislevel = 3; profile = Filename _sample_monitor_profile, in.bands == 3 = Filename _sample_print_profile; intent = _render_intents; value = im_icc_import in.value (expand profile.value) intent.value; } } /* transform between two device spaces */ ICC_transform in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; in_profile = Filename _sample_monitor_profile; out_profile = Filename _sample_print_profile; intent = _render_intents; value = im_icc_transform in.value (expand in_profile.value) (expand out_profile.value) intent.value; } } /* transform from absolute to relative colorimetry */ ICC_ac2rc in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; profile = Filename _sample_print_profile; value = im_icc_ac2rc in.value (expand profile.value); } } #separator /* convert between XYZ and Lab for D50 */ D50XYZ_to_D50Lab in = map_unary (colour_unary im_D50XYZ2Lab) in; /* convert between XYZ and Lab for D50 */ D50Lab_to_D50XYZ in = map_unary (colour_unary im_D50Lab2XYZ) in; #separator /* add an editable drop shadow to an image */ Drop_shadow x = map_unary shadow x { shadow image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; shadow_width = Slider 0 50 5; shadow_height = Slider 0 50 5; shadow_softness = Slider 0 20 5; use_mask = Toggle "Use mask to make shadow" false; mask_image = foldr1 bitwise_and (bandsplit (image > 128)); background_colour = 255; shadow_colour = 128; value = final { blur_size = shadow_softness.value * 2 + 1; // matrix we blur with to soften shadows mask_g = im_gauss_imask (blur_size / 3) 0.2; mask_g_line = mask_g.value ? (mask_g.height / 2); mask_g_sum = foldr1 add mask_g_line; blur_matrix = Matrix_con mask_g_sum 0 [mask_g_line]; mask_size = mask_g.width; // size of final image we build final_width = image.width + 2 * mask_size + shadow_width.value; final_height = image.height + 2 * mask_size + shadow_height.value; // make a plain image mk_background colour = image_new final_width final_height image.bands image.format Image_coding.NOCODING image.type colour 0 0; // make a mask image ... place at (x,y) in the final // image mk_mask x y = im_insert black mask_image.value x y, use_mask = im_insert black white x y { black = image_new final_width final_height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 0 0 0; white = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; } // make the shadow mask image ... offset mask and // soften shadow_mask = mk_mask (mask_size + shadow_width.value) (mask_size + shadow_height.value); shadow_mask' = im_convsep shadow_mask blur_matrix; // make underlay ... use shadow mask to blend between // background colour and shadow colour background = mk_background background_colour; shadow = mk_background shadow_colour; underlay = im_blend shadow_mask' shadow background; // overlay ... place image at final position overlay = mk_background 0; overlay' = im_insert overlay image.value mask_size mask_size; // overlay mask overlay_mask = mk_mask mask_size mask_size; final = if overlay_mask then overlay' else underlay; } } } nip2-8.7.1/share/nip2/compat/7.9/Capture.def0000644000175000017500000001117413351443023015157 00000000000000/* make a new capture image */ Capture_video = class Image value { // shortcut to prefs _prefs = Workspaces.Preferences; device = _prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] _prefs.VIDEO_CHANNEL; brightness = Slider 0 32767 _prefs.VIDEO_BRIGHTNESS; colour = Slider 0 32767 _prefs.VIDEO_COLOUR; contrast = Slider 0 32767 _prefs.VIDEO_CONTRAST; hue = Slider 0 32767 _prefs.VIDEO_HUE; frames_hint = "Average this many frames:"; frames = Slider 0 100 _prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" _prefs.VIDEO_MONO; crop = Toggle "Crop image" _prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value brightness.value colour.value contrast.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = _prefs.VIDEO_CROP_LEFT; top = _prefs.VIDEO_CROP_TOP; width = min_pair _prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair _prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_hint = "Stretch vertically by this factor:"; aspect_ratio = _prefs.VIDEO_ASPECT; value = frame' { frame = edit_crop.value, crop = _raw_grab.value; frame' = colour_transform Image_type.sRGB Image_type.B_W frame, mono = frame; } } #separator /* use white image w to correct image i */ Light_correct w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } /* equalize bands in region r */ White_balance r = map_unary wb r { wb region = clip2fmt region.format (region.image * Vector facs) { target = mean region; facs = map (divide target) (map mean (bandsplit region)); } } /* remove features larger than a certain size from image x */ Smooth_image x = map_unary smooth x { smooth image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; feature = Slider 1 50 20; value = im_resize_linear (im_shrink image.value feature.value feature.value) image.width image.height; } } #separator /* calculate RGB -> LAB transform from an image of a Macbeth colour chart */ Calibrate_chart image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; // get macbeth data file to use macbeth = Filename "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = im_measure image.value 0 0 image.width image.height 6 4; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'); // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it linearising_lut = Image _linear_lut; // map the original image through the lineariser to get linear 0-1 // RGB image _image' = im_maplut image.value linearising_lut.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab value = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb M _image')); // measure again and compute dE76 _camera'' = im_measure value 0 0 image.width image.height 6 4; _dEs = map abs_vec (map Vector (_camera'' - _true_Lab).value); final_dE76 = mean (Vector _dEs); _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = _macbeth_names ? _worst ++ " (patch " ++ print (_worst + 1) ++ ")"; } /* apply RGB -> LAB transform to an image */ Calibrate_image calib image = class Image value { _check_args = [ [calib, "calib", check_instance "Calibrate_chart"], [image, "image", check_Image] ] ++ super._check_args; // map the original image through the lineariser to get linear 0-1 // RGB image _image' = im_maplut image.value calib.linearising_lut.value; // convert linear RGB camera to Lab value = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M _image')); } nip2-8.7.1/share/nip2/compat/7.9/_generate.def0000644000175000017500000000355113351443023015505 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = (unsigned int) (h ++ v) { h = (x - 1) * im_fgrey x y; v = (y - 1) * im_rot90 (im_fgrey y x); } /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12 */ image_new w h b fmt coding type pixel xoff yoff = im'''' { im = im_black w h b + pixel; im' = clip2fmt fmt im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l (size / 2) (size / 2); A1 = im_fgrey size size; /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = L ++ A2 ++ A4; } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (map (const (max_value.lookup 1 0 format)) [1 .. bands]) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } nip2-8.7.1/share/nip2/compat/7.9/X_ray.def0000644000175000017500000002501513351443023014635 00000000000000/* replace dark or light section of im1 with section from im2 */ Replace_area im1 im2 = class Image value { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ] ++ super._check_args; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.1 0.1 0.1 0.1; /* Point on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Point im2 (im2.width * 0.1 - im2.xoffset) (im2.height * 0.1 - im2.yoffset); _r2 = Region im2 p2.left p2.top r1.width r1.height; _mask = [r1 <= Options.scale_cutoff, r1 >= Options.scale_cutoff] ? Options.control; mask = _mask?0; Options = option_1, format < 4 = option_2 { format = im1.format; option_1 = class { _vislevel = 3; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ control = Option "Removing a" [ "Dark Area", "Light Area" ] 1; /* Used to select the area to be replaced. */ scale_cutoff = Slider 0.01 mx (mx / 2) { mx = Image_format.maxval im1.format; } /* Option toggle how the levels in the replacment area are calculated. * Replacement with gaussian noise uses the scale&offset balancing. */ process = Option "Use" [ "Scale&Offset Balancing", "Gaussian noise replacement", "Histogram Balancing" ] 0; /* This allows the function to be paused. */ pause = Toggle "Pause function to allow easy adjustment of region r1." true; } option_2 = class { _vislevel = 3; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ control = Option "Removing a" [ "Dark Area", "Light Area" ] 1; /* Used to select the area to be replaced. */ scale_cutoff = Slider 0.01 mx (mx / 2) { /* the below function can not cope with floats * and don't need massive range for 32-bit ints so * will just define the max as for a 16 bit unsigned. */ mx = Image_format.maxval 2; //im1.format; } /* Option toggle how the levels in the replacment area are calculated. * Replacement with gaussian noise uses the scale&offset balancing. */ process = Option "Use" [ "Scale&Offset Balancing", "Gaussian noise replacement" ] 0; /* This allows the function to be paused. */ pause = Toggle "Pause function to allow easy adjustment of region r1." true; } } value = im1.value, Options.pause = im_insert im1.value patch r1.left r1.top { patch = _so_balance mask r1.value _r2.value false, Options.process == 0; = _so_balance mask r1.value _r2.value true, Options.process == 1; = _hist_balance_2 mask r1.value _r2.value; } }; #separator /* Balance the effect of secondary structure on an X-ray image * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference * masks, where the masks are white on a black background. Then simplifys * the original X-ray to reduce interference from stretchers cradles etc. */ Balance_areas im_in m_control m_list = class Image value { _vislevel = 3; _format = im_in.format; Options = option_1, format < 4 = option_2 { format = im_in.format; option_1 = class { _vislevel = 3; pause = Toggle "Pause Process." true; blur = Slider 0 5 0; _blur = rint blur.value; option = Toggle "Use Scale&Offset Balancing rather than Histogram." true; _option = option; } option_2 = class { _vislevel = 3; pause = Toggle "Pause Process." true; blur = Slider 0 5 0; _blur = rint blur.value; _option = true; } } _control_im = _section_select2 im_in m_control; _control_values = _so_values _control_im; /* blur mask over a set number of pixels then histogram match an area * of the original image defined by m_current to the _control_im * then blend the matched area back into im_in. */ process m_current im_start = im_out { alternative = false; bl_mask = _mask_blur_2 m_current Options._blur; scaled_im = _so_convert _control_values im_start m_current, Options._option == true = _hist_convert_2 _control_im im_start m_current; fmt_im = clip2fmt im_start.format scaled_im; blended_im = im_blend bl_mask scaled_im.value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } value = im_in.value, Options.pause == true = (foldr process im_in m_list).value; }; _so_balance mask im1 im2 gauss = result { /* Extract the undamaged areas. */ im1' = if !mask then Image im1 else 0; im2' = if !mask then Image im2 else 0; /* Find the non_zero means of the undamaged areas. */ m1 = _mean_fn im1'; m2 = _mean_fn im2'; im1_mn = im1' - m1; im2_mn = im2' - m2; scale = (max im1_mn)/(max im2_mn); im2_corrected_a = ((im2 - m2) * scale) + m1; im2_corrected_b = clip2fmt im1'.format im2_corrected_a; /* Option to convert replacement image to scaled gaussian noise */ im2_corrected = im2_corrected_b, gauss == false = _gauss_noise im2_corrected_b; /* Blur mask. */ mask' = _mask_blur_2 mask 5; //mask' = _feather_mask_2 5 mask.value; /* Blend im2 into im1. */ result = im_blend mask' im2_corrected im1; }; /* make a new image of gaussian noise */ _gauss_noise im2 = value { i = Image (im2); width = i.width; height = i.height; mean = Mean i; deviation = Deviation i; noise = im_gaussnoise width height mean deviation; value = clip2fmt i.format noise; }; /* Dilate and blur a mask by a number of pixels. * *_feather_mask_2 pixels mask * = im_convsep (dilate dilate_matrix mask) blur_matrix *{ * dilate_matrix = (iterate (dilate _morph_mask8) _morph_mask8) ? pixels; * blur_matrix = Matrix_con pixels 0 [(map (const 1) [1 .. pixels])]; *}; */ /* Mask is 255 to indicate parts of im1 which are damaged: replace these bits * with the corresponding parts of im2. * * Match the histograms of the two images to hide grey-level differences, be * careful to only consider undamaged sections. * * Feather the edges of the blend to hide the join. * * mask is an Image class. im1, im2 and result are vips images. */ _hist_balance_2 mask im1 im2 = result { format = im_header_int "BandFmt" im1; bands = im_header_int "Bands" im1; /* checks for 8 or 16 bit signed and converts to unsigned */ force_unsigned i = clip2fmt Image_format.UCHAR (i + 128), format == Image_format.CHAR = clip2fmt Image_format.USHORT (i + 32768), format == Image_format.SHORT = i; /* undo any force_unsigned */ format_restore i = clip2fmt Image_format.CHAR (i - 128), format == Image_format.CHAR = clip2fmt Image_format.SHORT (i - 32768), format == Image_format.SHORT = i; /* Find histogram and then zap the zero column (0 == background). For * 16-bit images, the histogram can be smaller than 65535 .... expand * up to full size. */ build_hist i = im_insert big_black h' 0 0 { max_value = Image_format.maxval i.format; h = hist_find i.value; black_1 = image_new 1 1 i.bands Image_format.UINT Image_coding.NOCODING i.type 0 0 0; big_black = image_new max_value 1 i.bands Image_format.UINT Image_coding.NOCODING i.type 0 0 0; h' = im_insert h black_1 0 0; } /* We can't get hists of signed images :-( go unsigned if we have to. */ im1' = force_unsigned im1; im2' = force_unsigned im2; /* Extract the undamaged areas. */ reference = if !mask then Image im1' else 0; secondary = if !mask then Image im2' else 0; /* Find the hists of the undamaged areas. */ h1 = build_hist reference; h2 = build_hist secondary; /* Match greylevels of im2 to match im1. */ im2'' = hist_map (hist_match h1 h2) im2'; /* Feather mask. */ mask' = _mask_blur_2 mask 5; //mask' = _feather_mask_2 5 mask.value; /* Blend im2 into im1. */ im1'' = im_blend mask' im2'' im1'; /* Undo any signed/unsigned nonsense. */ result = format_restore im1''; }; // Blurs the edges of an 8 bit mask, over a given number of pixels. _mask_blur_2 mask pixel = value { pixels = 1, pixel == 0 = pixel; black = im_black (mask.width + (2*pixels)) (mask.height + (2*pixels)) 1; new_mask = Image (im_insert black mask.value pixels pixels); blur_matrix = Matrix_con pixels 0 [(map (const 1) [1 .. pixels])]; im_blur = im_convsep new_mask.value blur_matrix; left = pixels; top = pixels; width = mask.width; height = mask.height; value = im_extract_area im_blur left top width height; }; _so_values im = result { mean_of_im = _mean_fn im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; _so_convert con_values im mask = result { im' = _section_select2 im mask; im_values = _so_values im'; mean_of_con = con_values?0; mean_of_im = im_values?0; max_of_con = con_values?1; max_of_im = im_values?1; scale = (max_of_con)/(max_of_im); im_convert = ((im - mean_of_im) * scale) + mean_of_con; result = clip2fmt im.format im_convert; }; /* Convert the histogram of part of image im_a, depending on the mask im_m, * to match the histogram of im_c. */ _hist_convert_2 control_im im adjust_mask = im_final { max_value = Image_format.maxval im.format; adjust_im = _section_select2 im adjust_mask; hist_c = hist_fn control_im; hist_a = hist_fn adjust_im; /* Find histogram and then edit out any information related to parts * of the image with value 0. Ensure that the histogram represents * the full scale for the appropriate format. Output corrected * histograms for the correct parts of the image. */ hist_fn im_in = output { hist_1 = hist_find im_in; black_1 = clip2fmt hist_1.format (im_black 1 1 1); hist_2 = im_insert hist_1.value black_1 0 0; black_2 = clip2fmt hist_1.format (im_black max_value 1 1); output = im_insert black_2 hist_2 0 0; } im_final = hist_map (hist_match hist_a hist_c) im; }; //------------------------------------------------------------------------------- /*Returns a section of im, defined by a mask, on a black background*/ _section_select2 im_in mask = output { output = clip2fmt im_in.format (im_black im_in.width im_in.height 1), mask == 0 = im_in; }; _mean_fn im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); } nip2-8.7.1/share/nip2/compat/7.9/Mosaic.def0000644000175000017500000002121713351443023014766 00000000000000 /* Check and group a point list by image. */ _mosaic_sort_test l = error "mosaic: not all points", !is_listof (is_instanceof "Point") l = error "mosaic: points not on two images", len images != 2 = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = land (map (equal (hd l)) (tl l)); get_format x = x.image.format; get_coding x = x.image.coding; // all the different images get_image x = x.image; images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = p.image === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to get * above before below. */ _mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = (a?0).left > (b?0).left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to get * left before right. */ _mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = (a?0).top > (b?0).top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ _mosaic_sort fn = concat @ transpose @ fn @ _mosaic_sort_test; /* translate and blend two images together left/right or up/down */ Mosaic_translate = class { _check_ab_args a b = [ [a, "a", check_Point], [b, "b", check_Point] ]; // shortcut to prefs _prefs = Workspaces.Preferences; _search_area = _prefs.MOSAIC_WINDOW_SIZE; _object_size = _prefs.MOSAIC_OBJECT_SIZE; _blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH; _refine = Toggle "Refine selected tie-points" _prefs.MOSAIC_REFINE; /* translate and blend two images left/right */ Left_right a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; blend_width = _blend_width; refine = _refine; value = im_lrmosaic a'.image.value b'.image.value 0 ra'.left ra'.top rb'.left rb'.top (_object_size / 2) (_search_area / 2) 0 blend_width.value, refine = im_lrmerge a'.image.value b'.image.value (rb'.left - ra'.left) (rb'.top - ra'.top) blend_width.value { sorted = _mosaic_sort _mosaic_sort_lr [a, b]; a' = sorted?0; b' = sorted?1; ra' = a'.image_rect; rb' = b'.image_rect; } } /* translate and blend two images top/bottom */ Top_bottom a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; blend_width = _blend_width; refine = _refine; value = im_tbmosaic a'.image.value b'.image.value 0 ra'.left ra'.top rb'.left rb'.top (_object_size / 2) (_search_area / 2) 0 blend_width.value, refine = im_tbmerge a'.image.value b'.image.value (rb'.left - ra'.left) (rb'.top - ra'.top) blend_width.value { sorted = _mosaic_sort _mosaic_sort_tb [a, b]; a' = sorted?0; b' = sorted?1; ra' = a'.image_rect; rb' = b'.image_rect; } } } /* forcibly translate and blend two images together left/right or up/down */ Mosaic_force = class { _check_ab_args a b = [ [a, "a", check_Point], [b, "b", check_Point] ]; // shortcut to prefs _prefs = Workspaces.Preferences; _blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH; /* forcibly translate and blend two images left/right */ Left_right a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; blend_width = _blend_width; value = im_lrmerge a'.image.value b'.image.value (rb'.left - ra'.left) (rb'.top - ra'.top) blend_width.value { sorted = _mosaic_sort _mosaic_sort_lr [a, b]; a' = sorted?0; b' = sorted?1; ra' = a'.image_rect; rb' = b'.image_rect; } } /* forcibly translate and blend two images top/bottom */ Top_bottom a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; blend_width = _blend_width; value = im_tbmerge a'.image.value b'.image.value (rb'.left - ra'.left) (rb'.top - ra'.top) blend_width.value { sorted = _mosaic_sort _mosaic_sort_tb [a, b]; a' = sorted?0; b' = sorted?1; ra' = a'.image_rect; rb' = b'.image_rect; } } } /* translate, rotate, scale and blend two images together left/right or up/down */ Mosaic_affine = class { _check_abcd_args a b c d = [ [a, "a", check_Point], [b, "b", check_Point], [c, "c", check_Point], [d, "d", check_Point] ]; // shortcut to prefs _prefs = Workspaces.Preferences; _search_area = _prefs.MOSAIC_WINDOW_SIZE; _object_size = _prefs.MOSAIC_OBJECT_SIZE; _blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH; _refine = Toggle "Refine selected tie-points" _prefs.MOSAIC_REFINE; /* translate, rotate, scale and blend two images left/right */ Left_right a b c d = class Image value { _check_args = _check_abcd_args a b c d ++ super._check_args; blend_width = _blend_width; refine = _refine; value = im_lrmosaic1 a'.image.value b'.image.value 0 ra'.left ra'.top rb'.left rb'.top rc'.left rc'.top rd'.left rd'.top (_object_size / 2) (_search_area / 2) 0 blend_width.value, refine = im_lrmerge1 a'.image.value b'.image.value ra'.left ra'.top rb'.left rb'.top rc'.left rc'.top rd'.left rd'.top blend_width.value { sorted = _mosaic_sort _mosaic_sort_lr [a, b, c, d]; a' = sorted?0; b' = sorted?1; c' = sorted?2; d' = sorted?3; ra' = a'.image_rect; rb' = b'.image_rect; rc' = c'.image_rect; rd' = d'.image_rect; } } /* translate, rotate, scale and blend two images top/bottom */ Top_bottom a b c d = class Image value { _check_args = _check_abcd_args a b c d ++ super._check_args; blend_width = _blend_width; refine = _refine; value = im_tbmosaic1 a'.image.value b'.image.value 0 ra'.left ra'.top rb'.left rb'.top rc'.left rc'.top rd'.left rd'.top (_object_size / 2) (_search_area / 2) 0 blend_width.value, refine = im_tbmerge1 a'.image.value b'.image.value ra'.left ra'.top rb'.left rb'.top rc'.left rc'.top rd'.left rd'.top blend_width.value { sorted = _mosaic_sort _mosaic_sort_tb [a, b, c, d]; a' = sorted?0; b' = sorted?1; c' = sorted?2; d' = sorted?3; ra' = a'.image_rect; rb' = b'.image_rect; rc' = c'.image_rect; rd' = d'.image_rect; } } } #separator /* disassemble mosaic, adjust brightnesses to match, and reassemble */ Mosaic_balance x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (errors.badargs ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } /* brighten along a left/right or up/down axis */ Tilt_brightness = class { /* brighten along a left/right axis */ Left_right x = map_unary tilt_lr x { tilt_lr image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; tilt = Slider (-1) 1 0; value = final { ramp = im_fgrey image.width image.height; ramp' = bandjoin (map (const ramp) [1..image.bands]); scale = (ramp' - 0.5) * tilt + 1; final = image.value * scale; } } } /* brighten along a top/bottom axis */ Top_bottom x = map_unary tilt_tb x { tilt_tb image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; tilt = Slider (-1) 1 0; value = final { ramp = rot90 (im_fgrey image.height image.width); ramp' = bandjoin (map (const ramp) [1..image.bands]); scale = (ramp' - 0.5) * tilt + 1; final = image.value * scale; } } } } #separator /* disassemble mosaic, substitute different image files, and reassemble */ Mosaic_rebuild x = map_unary remosaic x { remosaic image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; old_hint = "For the name of each file making up the mosaic, " ++ "exchange this string:"; old = "foo"; new_hint = "for this string:"; new = "bar"; value = im_remosaic image.value old new; } } nip2-8.7.1/share/nip2/compat/7.9/_stdenv.def0000644000175000017500000007141013351443023015215 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; join a b = a ++ b; subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; if_then_else a b c = if a then b else c; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error "unimplemented vector operation" { zeros = map (const 0) [1 .. len vec]; ones = map (const 1) [1 .. len vec]; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } /* Macbeth chart patch names. */ _macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (errors.badargs ++ "bandsplit") { bands = im_header_int "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = Image (concat (map get_value l)), is_listof (is_instanceof "Image") l = concat l, is_listof is_image l = error (errors.badargs ++ "bandjoin") { get_value x = x.value; } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = error (errors.badargs ++ "mean") { mean_op = Operator "mean" mean_object Operator_type.COMPOUND false; mean_object x = im_avg x, is_image x = mean_list x, is_real_list x || is_matrix x = error (errors.badargs ++ "mean"); mean_list l = s / n { totals = sum l; n = totals?0; s = totals?1; } // return [n, sum] for a list of numbers, or a list of list of num // etc. sum x = foldr accumulate [0, 0] x { accumulate x sofar = [n + 1, x + s], is_real x = [n + n', s + s'], is_list x = error "mean_list: not real or [real]" { n = sofar?0; s = sofar?1; sub_acc = sum x; n' = sub_acc?0; s' = sub_acc?1; } } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = error (errors.badargs ++ "deviation") { deviation_op = Operator "deviation" deviation_object Operator_type.COMPOUND false; deviation_object x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (errors.badargs ++ "deviation"); deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { totals = sum_sum2_list l; n = totals?0; s = totals?1; s2 = totals?2; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { n = sofar?0; s = sofar?1; s2 = sofar?2; sub_acc = sum_sum2_list x; n' = sub_acc?0; s' = sub_acc?1; s2' = sub_acc?2; } } } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = error (errors.badargs ++ "abs") { abs_op = Operator "abs" abs_object Operator_type.COMPOUND false; abs_object x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (errors.badargs ++ "abs"); abs_list l = (foldr1 add (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = error (errors.badargs ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec_object Operator_type.COMPOUND false; abs_vec_object x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (Vector (map abs_vec_list x)), is_matrix x = error (errors.badargs ++ "abs_vec"); abs_vec_list l = (foldr1 add (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (foldr1 add (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_matrix x, is_list x && is_list (hd x) = error (errors.badargs ++ "transpose") { transpose_op = Operator "transpose" transpose_object Operator_type.COMPOUND_REWRAP false; transpose_object x = transpose_matrix x, is_matrix x = transpose_image x, is_image x = error (errors.badargs ++ "transpose"); transpose_matrix l = [], l' == [] = (map hd l') : (transpose_matrix (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (errors.badargs ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (errors.badargs ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } rot90 x = oo_unary_function rot90_op x, is_class x = im_rot90 x, is_image x = error (errors.badargs ++ "rot90") { rot90_op = Operator "rot90" rot90_object Operator_type.COMPOUND_REWRAP false; rot90_object x = rot90_matrix x, is_matrix x = im_rot90 x, is_image x = error (errors.badargs ++ "rot90"); // slow, but what the heck rot90_matrix l = (im_rotate_dmask90 (Matrix l)).value; } rot180 x = oo_unary_function rot180_op x, is_class x = im_rot180 x, is_image x = error (errors.badargs ++ "rot180") { rot180_op = Operator "rot180" rot180_object Operator_type.COMPOUND_REWRAP false; rot180_object x = rot180_matrix x, is_matrix x = im_rot180 x, is_image x = error (errors.badargs ++ "rot180"); // slow, but what the heck rot180_matrix l = (im_rotate_dmask90 (im_rotate_dmask90 (Matrix l))).value; } rot270 x = oo_unary_function rot270_op x, is_class x = im_rot270 x, is_image x = error (errors.badargs ++ "rot270") { rot270_op = Operator "rot270" rot270_object Operator_type.COMPOUND_REWRAP false; rot270_object x = rot270_matrix x, is_matrix x = im_rot270 x, is_image x = error (errors.badargs ++ "rot270"); // slow, but what the heck rot270_matrix l = (im_rotate_dmask90 (im_rotate_dmask90 (im_rotate_dmask90 (Matrix l)))).value; } rotquad x = oo_unary_function rotquad_op x, is_class x = im_rotquad x, is_image x = error (errors.badargs ++ "rotquad") { rotquad_op = Operator "rotquad" rotquad_object Operator_type.COMPOUND_REWRAP false; rotquad_object x = rotquad_matrix x, is_matrix x = im_rotquad x, is_image x = error (errors.badargs ++ "rotquad"); rotquad_matrix l = error "rotquad matrix: not implemented"; } flipud x = oo_unary_function flipud_op x, is_class x = im_flipver x, is_image x = error (errors.badargs ++ "flipud") { flipud_op = Operator "flipud" flipud_object Operator_type.COMPOUND_REWRAP false; flipud_object x = flipud_matrix x, is_matrix x = im_flipver x, is_image x = error (errors.badargs ++ "flipud"); flipud_matrix l = reverse l; } fliplr x = oo_unary_function fliplr_op x, is_class x = im_fliphor x, is_image x = error (errors.badargs ++ "fliplr") { fliplr_op = Operator "fliplr" fliplr_object Operator_type.COMPOUND_REWRAP false; fliplr_object x = fliplr_matrix x, is_matrix x = im_fliphor x, is_image x = error (errors.badargs ++ "fliplr"); fliplr_matrix l = map reverse l; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = x, is_number x = error (errors.badargs ++ "max") { max_op = Operator "max" max_list Operator_type.COMPOUND false; max_list x = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_matrix x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = x, is_number x = error (errors.badargs ++ "min") { min_op = Operator "min" min_list Operator_type.COMPOUND false; min_list x = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_matrix x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = error (errors.badargs ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos_object Operator_type.COMPOUND false; maxpos_object x = maxpos_matrix x, is_matrix x = im_maxpos x, is_image x = error (errors.badargs ++ "maxpos"); maxpos_matrix m = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = error (errors.badargs ++ "minpos") { minpos_op = Operator "minpos" minpos_object Operator_type.COMPOUND false; minpos_object x = minpos_matrix x, is_matrix x = im_minpos x, is_image x = error (errors.badargs ++ "minpos"); minpos_matrix m = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = error (errors.badargs ++ "stats") { stats_op = Operator "stats" stats_object Operator_type.COMPOUND false; stats_object x = im_stats (to_image x).value, is_matrix x = im_stats x, is_image x = error (errors.badargs ++ "stats"); } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (errors.badargs ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = rint_value x, is_image x || is_number x = error (errors.badargs ++ "rint") { rint_op = Operator "rint" rint_value Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = scale_prim x { scale_op = Operator "scale" scale_prim Operator_type.COMPOUND_REWRAP false; scale_prim x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (errors.badargs ++ "scale"); scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (errors.badargs ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (errors.badargs ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (errors.badargs ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = im_falsecolour x, is_image x = error (errors.badargs ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (errors.badargs ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (errors.badargs ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } recomb matrix image = colour_unary recomb_op image { recomb_op x = im_recomb x matrix, is_image x = error (errors.badargs ++ "recomb"); } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = extract_area_prim obj { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" extract_area_prim Operator_type.COMPOUND_REWRAP false; extract_area_prim obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (errors.badargs ++ "extract_area"); extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_row_prim obj { y' = to_real y; extract_row_op = Operator "extract_row" extract_row_prim Operator_type.COMPOUND_REWRAP false; extract_row_prim obj = im_extract_area obj 0 y' width 1, is_image obj = [obj?y'], is_matrix obj = error (errors.badargs ++ "extract_row") { width = im_header_int "Xsize" obj; } } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_column_prim obj { x' = to_real x; extract_column_op = Operator "extract_column" extract_column_prim Operator_type.COMPOUND_REWRAP false; extract_column_prim obj = im_extract_area obj x' 0 1 height, is_image obj = map (converse cons [] @ converse subscript x') obj, is_matrix obj = error (errors.badargs ++ "extract_column") { height = im_header_int "Ysize" obj; } } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_lr_prim a b { join_lr_op = Operator "join_lr" join_lr_prim Operator_type.COMPOUND_REWRAP false; join_lr_prim a b = im_extract_area (im_insert a b a_width 0) 0 0 (a_width + b_width) out_height, is_image a && is_image b = map2 join a b, is_matrix a && is_matrix b = error (errors.badargs ++ "join_lr") { a_height = im_header_int "Ysize" a; b_height = im_header_int "Ysize" b; a_width = im_header_int "Xsize" a; b_width = im_header_int "Xsize" b; out_height = min_pair a_height b_height; } } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_tb_prim a b { join_tb_op = Operator "join_tb" join_tb_prim Operator_type.COMPOUND_REWRAP false; join_tb_prim a b = im_extract_area (im_insert a b 0 a_height) 0 0 out_width (a_height + b_height), is_image a && is_image b = map (take out_matrix_width) a ++ map (take out_matrix_width) b, is_matrix a && is_matrix b = error (errors.badargs ++ "join_tb") { a_height = im_header_int "Ysize" a; b_height = im_header_int "Ysize" b; a_width = im_header_int "Xsize" a; b_width = im_header_int "Xsize" b; out_width = min_pair a_width b_width; out_matrix_width = min_pair a_matrix_width b_matrix_width { a_matrix_width = len a?0; b_matrix_width = len b?0; } } } insert x y small big = oo_binary_function insert_op small big, is_class small = oo_binary'_function insert_op small big, is_class big = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (errors.badargs ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (errors.badargs ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } rotate angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_similarity image (cos angle) (sin angle) 0 0, is_real angle && is_image image = error (errors.badargs ++ "rotate") { rotate_op = Operator "rotate" rotate Operator_type.COMPOUND_REWRAP false; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = im_header_int "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function (clip2fmt_op format) image, is_class image = im_clip2fmt image format, is_image image = error (errors.badargs ++ "clip2fmt") { clip2fmt_op format = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { image = (unsigned char) im_mask2vips (Matrix m2); m2_width = im_header_int "Xsize" image; m2_height = im_header_int "Ysize" image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = im_embed image 0 (m1.width - 1) (m1.height - 1) (m2_width + 2 * (m1.width - 1)) (m2_height + 2 * (m1.height - 1)); // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image mask, is_image image = error (errors.badargs ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image mask, is_image image = error (errors.badargs ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image mask, is_image image = error (errors.badargs ++ "conv") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image w h n, is_image image = error (errors.badargs ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } hist_find image = oo_unary_function hist_find_op image, is_class image = im_histgr image (-1), is_image image = error (errors.badargs ++ "hist_find") { hist_find_op = Operator "hist_find" hist_find Operator_type.COMPOUND_REWRAP false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image bins, is_image image = error (errors.badargs ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" hist_find_nD Operator_type.COMPOUND_REWRAP false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (errors.badargs ++ "hist_map") { hist_map_op = Operator "hist_map" hist_map Operator_type.COMPOUND_REWRAP false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (errors.badargs ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (errors.badargs ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (errors.badargs ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = im_lhisteq image w h, is_image image = error (errors.badargs ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; } resize xfac yfac interp image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (errors.badargs ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac yfac, is_int xfac && is_int yfac && xfac >= 1 && yfac >= 1 && interp == Interpolate.nearest_neighbour // downscale by integer factor, nearest neighbour = im_subsample im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && interp == Interpolate.nearest_neighbour // upscale by any factor, nearest neighbour // can't really do this right ... upscale by integer part, then // bilinear to exact size = scale (break xfac)?1 (break yfac)?1 (im_zoom im (break xfac)?0 (break yfac)?0), xfac >= 1 && yfac >= 1 && interp == Interpolate.nearest_neighbour // downscale by any factor, nearest neighbour // can't really do this right ... downscale by integer part, // then bilinear to exact size = scale (1 / (break xfac')?1) (1 / (break yfac')?1) (im_subsample im (break xfac')?0 (break yfac')?0), xfac' >= 1 && yfac' >= 1 && interp == Interpolate.nearest_neighbour // upscale by any factor, bilinear = scale xfac yfac im, xfac >= 1 && yfac >= 1 && interp == Interpolate.bilinear // downscale by any factor, bilinear // block shrink by integer factor, then bilinear resample to // exact = scale (1 / (break xfac')?1) (1 / (break yfac')?1) (im_shrink im (break xfac')?0 (break yfac')?0), xfac' >= 1 && yfac' >= 1 && interp == Interpolate.bilinear = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac ++ "\n" ++ " yfac = " ++ print yfac ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate.names.lookup 1 0 interp ++ ")") { xfac' = 1 / xfac; yfac' = 1 / yfac; // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // binlinear resize scale xfac yfac im = im_affine im xfac 0 0 yfac 0 0 0 0 (width * xfac) (height * yfac) { width = im_header_int "Xsize" im; height = im_header_int "Ysize" im; } } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map3 (map_trinary fn) a b c, is_list a && is_list b && is_list c = map2 (map_trinary fn a) b c, is_list b && is_list c = map2 (map_trinary (converse31 fn) b) a c, is_list a && is_list c = map2 (map_trinary (converse32 fn) c) a b, is_list a && is_list b = map (map_trinary fn a b) c, is_list c = map (map_trinary (converse32 fn) a c) b, is_list b = map (map_trinary (converse34 fn) b c) a, is_list a = fn a b c { converse31 fn a b c = fn b a c; converse32 fn a b c = fn c a b; converse33 fn a b c = fn a c b; converse34 fn a b c = fn b c a; } /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map2 (map_binary fn) a b, is_list a && is_list b = map (map_binary fn a) b, is_list b = map (map_binary (converse fn) b) a, is_list a = fn a b; /* Map a 1-ary function over an object. */ map_unary fn a = map (map_unary fn) a, is_list a = fn a; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop block_size overlap i = map chop' [0, step .. height] { width = im_header_int "Xsize" i; height = im_header_int "Ysize" i; bands = im_header_int "Bands" i; format = im_header_int "BandFmt" i; type = im_header_int "Type" i; /* Unique pixels per tile. */ step = block_size - overlap; /* Calculate padding ... pad up to block_size pixel boundary. */ sx = block_size + (width - width % step); sy = block_size + (height - height % step); /* Expand image with black to pad size. */ background = image_new sx sy bands format Image_coding.NOCODING type 0 0 0; pad = im_insert background i 0 0; /* Chop up a row. */ chop' y = map chop'' [0, step .. width] { chop'' x = im_extract_area pad x y block_size block_size; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = vjoin (map hjoin il) { /* Join a list of tiles horizontally. */ hjoin l = foldl1 lrj l { lrj l r = im_lrmerge l r (hoverlap - im_header_int "Xsize" l) 0 10; } /* Join a list of tiles vertically. */ vjoin l = foldl1 tbj l { tbj t b = im_tbmerge t b 0 (voverlap - im_header_int "Ysize" t) 10; } } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } nip2-8.7.1/share/nip2/compat/7.9/Histogram.def0000644000175000017500000000302113351443023015501 00000000000000/* find histogram of x */ Hist_find x = map_unary hist_find x; /* find n-dimensional histogram from n-band image */ Hist_find_nD in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; // default to something small-ish bins = 8; value = hist_find_nD bins image.value; } } /* map image x through histogram hist */ Hist_map hist x = map_binary hist_map hist x; /* find cumulative histogram of hist */ Hist_cumulative x = map_unary hist_cum x; /* find normalised histogram of hist */ Hist_normalise x = map_unary hist_norm x; /* find LUT which matches hist in to hist ref */ Hist_match in ref = map_binary hist_match in ref; #separator /* histogram equalisation */ Hist_equalise = class { /* histogram equalise x globally */ Global x = map_unary hist_equalize x; /* local histogram equalisation using region r as window */ Local r = map_unary (hist_equalize_local r.width r.height) r.image; } /* slice a line of pixels along a guide line and display as a histogram */ Guide_slice in = map_unary widget in { widget guide = class Image value { _check_args = [ [guide, "Guide", check_Guide] ] ++ super._check_args; value = image_set_type Image_type.HISTOGRAM slice { slice = guide.image.extract_area guide.image.rect.left guide.top guide.width 1, is_instanceof "HGuide" guide = guide.image.extract_area guide.left guide.image.rect.top 1 guide.height; } } } nip2-8.7.1/share/nip2/compat/7.9/_types.def0000644000175000017500000010054213351443023015055 00000000000000 /* Lots of little arg checks. Global for convenience. */ check_any = [(const true), "any"]; check_bool = [is_bool, "boolean"]; check_real = [is_real, "real"]; check_ureal = [is_ureal, "unsigned real"]; check_preal = [is_preal, "positive real"]; check_real_list = [is_real_list, "list of real"]; check_string = [is_string, "string"]; check_string_list = [is_string_list, "list of string"]; check_int = [is_int, "integer"]; check_uint = [is_uint, "unsigned integer"]; check_pint = [is_pint, "positive integer"]; check_matrix = [is_matrix, "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, "0, 1, 2 or 3"]; check_image = [is_image, "image"]; check_xy_list = [is_xy_list, "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_instanceof "Matrix_base", "Matrix"]; check_colour_space = [is_colour_space, "colour_space"]; check_rectangular = [is_rectangular, "rectangular [[*]]"]; check_Guide = [is_Guide, "HGuide or VGuide"]; check_Point = check_instance "Point"; check_Colour = check_instance "Colour"; /* Check a set of args. Grab _check_table. It's a list of two check * lists: the first checks each arg, and the second checks all args * together. * * - each line in argcheck is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in allcheck is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down a bit. */ check_args x = x, badargs == [] && badalls == [] = error message { argcheck = x._check_args; allcheck = x._check_all; // join two strings up with a separator string join_sep j a b = a ++ j ++ b; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = errors.badargs ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\nusage\n" ++ indent ++ usage ++ "\nwhere\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ "you passed " ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ "you passed\n" ++ concat (map fmt_arg argcheck) { fmt n = "condition failed: " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make usage note usage = x.name ++ " " ++ foldr (join_sep " ") [] (map (extract 1) argcheck); // make arg type notes arg_types = foldr (join_sep "\n") [] (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "and\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = foldr (join_sep "\n") [] all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error ("unknown binary operator: " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error ("unknown unary operator: " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = error ("No method found for binary operator.\n" ++ "left = " ++ print a ++ "\n" ++ "operator = " ++ op.op_name ++ "\n" ++ "right = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = error ("No method found for binary operator.\n" ++ "left = " ++ print a ++ "\n" ++ "operator = " ++ op.op_name ++ "\n" ++ "right = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error ("No method found for unary operator.\n" ++ "operator = " ++ op.op_name ++ "\n" ++ "argument = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; /* Default: no checks ... override in subclasses. */ _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; /* Provide a fallback for class == thing ... just use pointer * equality. */ oo_binary_table op x = [ [ pointer_equal this x, op.op_name == "equal" || op.op_name == "equal'" ], [ not_pointer_equal this x, op.op_name == "not_equal" || op.op_name == "not_equal'" ] ]; oo_unary_table op = []; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ] ++ super._check_args; // methods oo_binary_table op x = [ [ this.Real (op.fn this.value x.value), is_instanceof "Real" x && op.type == Operator_type.ARITHMETIC ], [ this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC ], [ op.fn this.value x.value, is_instanceof "Real" x && op.type == Operator_type.RELATIONAL ], [ op.fn this.value x, !is_class x ] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [ this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC ], [ op.fn this.value, true ] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ] ++ super._check_args; // methods oo_binary_table op x = [ [ if value then x?0 else x?1, op.op_name == "if_then_else" ], [ this.Bool (op.fn this.value x.value), is_instanceof "Bool" x ], [ this.Bool (op.fn this.value x), is_bool x ] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [ this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL ] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ] ++ super._check_args; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ] ++ super._check_args; Real value = Number caption value; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ] ++ super._check_args; } // the old name Filename = Pathname "Pick a file"; /* Vector type ... just a finite list of real ... handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ] ++ super._check_args; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [ this.Vector (op.fn this.value x.value), is_instanceof "Vector" x && (op.op_name == "join" || op.op_name == "join'") ], // extra check for lengths equal [ this.Vector (map_binary op.fn this.value x.value), is_instanceof "Vector" x && len value == len x.value && op.type == Operator_type.ARITHMETIC ], [ this.Vector (map_binary op.fn this.value x.value), is_instanceof "Real" x && op.type == Operator_type.ARITHMETIC ], [ this.Vector (map_binary op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC ], // need extra length check [ this.Vector (map bool_to_real (map_binary op.fn this.value x.value)), is_instanceof "Vector" x && len value == len x.value && op.type == Operator_type.RELATIONAL ], [ this.Vector (map bool_to_real (map_binary op.fn this.value x.value)), is_instanceof "Real" x && op.type == Operator_type.RELATIONAL ], [ this.Vector (map bool_to_real (map_binary op.fn this.value x)), is_real x && op.type == Operator_type.RELATIONAL ], [ this.Vector (op.fn this.value x.value), is_instanceof "Vector" x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP ], [ x.Image (vec op'.op_name x.value value), is_instanceof "Image" x ], [ vec op'.op_name x value, is_image x ], [ op.fn this.value x, is_real x ] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [ this.Vector (map_unary op.fn this.value), op.type == Operator_type.ARITHMETIC ], [ this.Vector (map bool_to_real (map_unary op.fn this.value)), op.type == Operator_type.RELATIONAL ], [ this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP ], [ op.fn this.value, true ] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ] ++ super._check_args; // calculate these from value width = len value?0; height = len value; // methods oo_binary_table op x = [ // mat multiply is special [ this.Matrix_base mul.value, is_instanceof "Matrix_base" x && op.op_name == "multiply" ], [ this.Matrix_base mul'.value, is_instanceof "Matrix_base" x && op.op_name == "multiply'" ], // mat divide is also special [ this.Matrix_base div.value, is_instanceof "Matrix_base" x && op.op_name == "divide" ], [ this.Matrix_base div'.value, is_instanceof "Matrix_base" x && op.op_name == "divide'" ], // power -1 means invert [ this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power" ], [ this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power" ], [ error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'" ], // matrix op vector ... treat a vector as a 1 row matrix [ this.Matrix_base (map (map_binary op'.fn x.value) this.value), is_instanceof "Vector" x && op.type == Operator_type.ARITHMETIC ], [ this.Matrix_base (map_binary op.fn this.value x.value), (is_instanceof "Matrix_base" x || is_instanceof "Real" x) && op.type == Operator_type.ARITHMETIC ], [ this.Matrix_base (map_binary op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC ], // compound ... don't do iteration [ this.Matrix_base (op.fn this.value x.value), (is_instanceof "Matrix_base" x || is_instanceof "Real" x || is_instanceof "Vector" x) && op.type == Operator_type.COMPOUND_REWRAP ] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [ this.Matrix_base (map_unary op.fn this.value), op.type == Operator_type.ARITHMETIC ], [ this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP ], [ op.fn this.value, true ] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ] ++ super._check_args; Matrix_base value = Matrix_vips value scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {}; /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = im_read_dmask (expand filename); /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ] ++ super._check_args; _check_all = [ [len value == 3, "len value == 3"] ] ++ super._check_all; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = im_header_int "Type" im; bands = im_header_int "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [ itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP ] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [ itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP ] ] ++ super.oo_unary_table op; Vector value = Colour colour_space value; } /* Base slider type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ] ++ super._check_args; _check_all = [ [from < to, "from < to"] ] ++ super._check_all; // methods oo_binary_table op x = [ [ this.Scale (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_instanceof "Scale" x && op.type == Operator_type.ARITHMETIC ], [ this.Scale (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC ] ] ++ super.oo_binary_table op x; Real value = Scale from to value; } /* Base slider type. */ Slider f t v = Scale "" f t v; /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ] ++ super._check_args; Bool value = Toggle caption value; } /* Base option type. */ Option caption labels value = class Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ] ++ super._check_args; } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ] ++ super._check_args; /* present col x: is there an x in column col */ present col x = member (map (extract col) value) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error ("item " ++ print x ++ " not in table") { n = index (equal x) (map (extract from) value); } } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ] ++ super._check_args; // derived right = left + width; bottom = top + height; // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // equal to another rect equal r = left == r.left && top == r.top && width == r.width && height == r.height; // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); // operator overloading // just define equal and not equal oo_binary_table op x = [ [ equal x, is_instanceof "Rect" x && (op.op_name == "equal" || op.op_name == "equal'") ], [ !equal x, is_instanceof "Rect" x && (op.op_name == "not_equal" || op.op_name == "not_equal'") ] ] ++ super.oo_binary_table op x; } /* Values for Compression field in image. */ Image_compression = class { NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NOCODING = 0; COLQUANT = 1; LABPACK = 2; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647 // INT ] ? fmt, fmt >= 0 && fmt <= INT = error errors.bandFmt; } /* Type field. */ Image_type = class { FOURIER = 24; YXY = 23; sRGB = 22; LABS = 21; LCH = 19; UCS = 18; RGB = 17; LABQ = 16; CMYK = 15; CMC = 14; LAB = 13; XYZ = 12; LUT = 11; HISTOGRAM = 10; POWER_SPECTRUM = 9; BLUE_ONLY = 8; GREEN_ONLY = 7; RED_ONLY = 6; YUV = 5; IR = 4; XRAY = 3; LUMINACE = 2; B_W = 1; MULTIBAND = 0; /* Table to get names <-> numbers. */ type_names = Table [ [ "FOURIER", FOURIER ], [ "YXY", YXY ], [ "sRGB", sRGB ], [ "LABS", LABS ], [ "LCH", LCH ], [ "UCS", UCS ], [ "RGB", RGB ], [ "LABQ", LABQ ], [ "CMYK", CMYK ], [ "CMC", CMC ], [ "LAB", LAB ], [ "XYZ", XYZ ], [ "LUT", LUT ], [ "HISTOGRAM", HISTOGRAM ], [ "POWER_SPECTRUM", POWER_SPECTRUM ], [ "BLUE_ONLY", BLUE_ONLY ], [ "GREEN_ONLY", GREEN_ONLY ], [ "RED_ONLY", RED_ONLY ], [ "YUV", YUV ], [ "IR", IR ], [ "XRAY", XRAY ], [ "LUMINACE", LUMINACE ], [ "B_W", B_W ], [ "MULTIBAND", MULTIBAND ] ]; /* Table relating nip's colour space names and VIPS's Type numbers. */ colour_spaces = Table [ [ "XYZ", Image_type.XYZ ], [ "Yxy", Image_type.YXY ], [ "Lab", Image_type.LAB ], [ "LCh", Image_type.LCH ], [ "UCS", Image_type.UCS ], [ "RGB", Image_type.RGB ], [ "sRGB", Image_type.sRGB ] ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ] ++ super._check_args; // fields from VIPS header width = im_header_int "Xsize" value; height = im_header_int "Ysize" value; bands = im_header_int "Bands" value; format = im_header_int "BandFmt" value; coding = im_header_int "Coding" value; type = im_header_int "Type" value; xres = im_header_double "Xres" value; yres = im_header_double "Yres" value; xoffset = im_header_int "Xoffset" value; yoffset = im_header_int "Yoffset" value; filename = im_header_string "filename" value; // convenience ... the area our pixels occupy as a rect rect = Rect (-xoffset) (-yoffset) width height; // extract an area, addressed in nip cordinates extract_area left top width height = im_extract_area value (left + xoffset) (top + yoffset) width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ [ this.Image (op.fn this.value x.value), is_instanceof "Image" x || is_instanceof "Real" x ], [ this.Image result_image, op.op_name == "if_then_else" ], [ this.Image (vec op.op_name value x.value), is_instanceof "Vector" x ], [ this.Image (op.fn this.value x), is_number x || is_image x ] ] ++ super.oo_binary_table op x { to_image x = x, is_image x = x.value, is_instanceof "Image" x = black + x { black = im_black width height target_bands; } // get a member from the first of a list of objects to have it get_property has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } // get things about our output from inputs in this order objects = [then_part, else_part, this]; then_part = x?0; else_part = x?1; // properties of our output image target_bands = get_property (has_member "bands") (get_member "bands") objects; target_format = get_property (has_member "format") (get_member "format") objects; target_type = get_property has_type get_type objects; then_image = to_image then_part; else_image = to_image else_part; then_image' = clip2fmt target_format then_image; else_image' = clip2fmt target_format else_image; result_image = image_set_type target_type (if value then then_image' else else_image'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [ this.Image result, is_image result ], [ result, true ] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file str = class Image value { _check_args = [ [str, "str", check_string] ] ++ super._check_args; file = Filename str; value = vips_image file.value; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ] ++ super._check_args; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = image.extract_area left top width height, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = Area image left top width height; } Arrow image left top width height = class Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ] ++ super._check_args; _check_all = [ [image.rect.includes_rect this, "image.rect.includes_rect this"] ] ++ super._check_all; // our rect, translated to image cods (ie. offset by origin) image_rect = Rect (left + image.xoffset) (top + image.yoffset) width height; // methods oo_binary_table op x = [ [ this.Arrow this.image left' top' width' height', is_instanceof "Arrow" x && op.type == Operator_type.ARITHMETIC ] ] ++ super.oo_binary_table op x { left' = op.fn this.left x.left; top' = op.fn this.top x.top; width' = op.fn this.width x.width; height' = op.fn this.height x.height; } oo_unary_search op = [ [ this.Arrow this.image left' top' width' height', op.type == Operator_type.ARITHMETIC ] ] ++ super.oo_unary_table op { left' = op.fn this.left; top' = op.fn this.top; width' = op.fn this.width; height' = op.fn this.height; } } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = VGuide image left; } Point image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = Point image left top; } // Mark is the name nip2 expects for Point Mark = Point; // convenience functions: make relative on an image ... subtract origin // offset, ie. make in pixel coordinates Region_relative image u v w h = Region image (image.width * u - image.xoffset) (image.height * v - image.yoffset) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u - image.xoffset) (image.height * v - image.yoffset) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u - image.xoffset) (image.height * v - image.yoffset) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v - image.yoffset); HGuide_relative image u = HGuide image (image.width * u - image.xoffset); Point_relative image u v = Point image (image.width * u - image.xoffset) (image.height * v - image.yoffset); Interpolate = class { nearest_neighbour = 0; bilinear = 1; bicubic = 2; /* Table to map interpol numbers to descriptive strings */ names = Table [ [ "Nearest neighbour", nearest_neighbour ], [ "Bilinear", bilinear ], [ "Bicubic", bicubic ] ]; } Separator = class {} // renamed in 7.9 estpar = im_estpar; resample = im_transform_search; nip2-8.7.1/share/nip2/compat/7.9/_errors.def0000644000175000017500000000273313351443023015230 00000000000000 /* Lots of error messages. */ errors = class { not1band = "not 1 band image"; not1band8bit = "not 1 band 8-bit image"; not1band3band = "not 1 band image, or 3 band 1 column image"; notodd = "not odd width|height"; notmask = "not mask"; notmaskim = "not image|mask, mask"; badcoding = "not NOCODING or LABPACK"; badlab = "unable to convert to LAB"; allreal = "not all real numbers"; allreg = "not all regions"; badargs = "bad arguments to "; badbands = "images have differing numbers of bands"; badcolour = "bad arg to colourspace function"; badmatrixmatch = "matrix arguments do not match"; badnum = "wrong number of real number arguments"; bandFmt = "bad BandFmt"; internal = "menu macro sanity failure!"; lengthdiff = "list arguments differ in length"; noimage = "no image argument"; noregion = "no region argument"; notim = "not image"; notimcmplx = "not image|complex"; notimnotreal = "non image arguments not all real numbers"; notimreg = "not image|region"; notregimreg = "not region, image|region"; notimregnum = "not image|region|number"; notimregstr = "not image|region|string"; notmatnum = "not real|matrix|mask"; notmatrix = "not matrix|mask"; notodd_square_matrix = "not odd-sided square matrix|mask"; notreal = "not real number"; notreglist = "not region|[region]"; notsquare_matrix = "not square matrix|mask"; regwrong = "regions not on two images"; sfacgt1 = "shrink factors should be >= 1"; unknownType = "unknown type"; usage = "usage: "; }; nip2-8.7.1/share/nip2/compat/7.9/New.def0000644000175000017500000003034613351443023014307 00000000000000 /* make a new blank image */ New_image = widget { type_names = Image_type.type_names; names = sort (map (extract 0) type_names.value); default_type_name = type_names.lookup 1 0 Image_type.MULTIBAND; default_type_pos = index (equal default_type_name) names; widget = class Image value { width = 64; height = 64; bands = 1; format_option = Option "Image format" [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ] 0; type_option = Option "Image type" names default_type_pos; value = image_new width height bands format Image_coding.NOCODING type 0 0 0 { format = format_option.value; type = type_names.lookup 0 1 names?type_option; } } } /* pick a colour ... any colour space */ New_colour = widget "Lab" [50,0,0] { widget default_colour value = class Colour colour_space value { _colourspaces = [ "XYZ", "Yxy", "Lab", "LCh", "UCS", "RGB", "sRGB" ]; colour_space_option = Option "Colour space" _colourspaces (index (equal default_colour) _colourspaces); colour_space = colour_space_option.labels? colour_space_option.value; Colour_edit colour_space value = widget colour_space value; } } /* make a slider */ New_slider = Slider 0 255 128; /* make a toggle widget */ New_toggle = Toggle "untitled" false; /* make an option widget */ New_option = Option "untitled" ["option0", "option1"] 0; /* make a string entry widget */ New_string = String "Enter a string" "sample text"; /* make a number entry widget */ New_number = Number "Enter a number" 42; /* make a file chooser */ New_filename = Filename "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; /* make a matrix */ New_matrix = class { /* make a plain matrix */ Plain = Matrix (identity_matrix 3); /* make a convolution matrix */ Convolution = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; /* make a recombination matrix */ Recombination = Matrix_rec (identity_matrix 3); /* make a morphology matrix */ Morphology = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } /* make a mark on an image */ New_mark = class { /* mark a region on an image */ Region image = scope.Region_relative image 0.25 0.25 0.5 0.5; /* mark a point on an image */ Point image = scope.Point_relative image 0.5 0.5; /* mark an arrow on an image */ Arrow image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; /* mark a horizontal guide on an image */ HGuide image = scope.HGuide_relative image 0.5; /* mark a vertical guide on an image */ VGuide image = scope.VGuide_relative image 0.5; } #separator /* make a spatial response pattern image */ New_eye = class Image value { width = 64; height = 64; factor = Slider 0.001 1 0.2; value = im_eye width height factor.value; } /* make a zone plate image */ New_zone_plate = class Image value { size = 64; value = im_zone size; } /* make a grey ramp image */ New_grey = class Image value { width = 64; height = 64; orientation = Option "" ["Horizontal", "Vertical"] 0; value = [im_grey width height, im_rot90 (im_grey height width)]?orientation; } /* make a two band image whose pixel values are their coordinates */ New_xy = class Image value { width = 64; height = 64; value = make_xy width height; } /* make a new image of gaussian noise */ New_gauss_noise = class Image value { size = 64; mean = Slider 0 255 128; deviation = Slider 0 128 50; value = im_gaussnoise size size mean.value deviation.value; } /* make a 2d fractal image */ New_fractal = class Image value { size = 64; dimension = Slider 2.001 2.999 2.001; value = im_fractsurf size dimension.value; } /* make a CRT calibration chart */ New_CRT_test_chart = class Image value { brightness = Slider 0 255 200; patch_size = 32; value = imagearray_assemble 0 0 [[green, red], [blue, white]] { black = image_new patch_size patch_size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } /* make a frequency test chart */ New_frequency_test_chart = class Image value { width = 64; strip_height = 10; wavelengths = [64, 32, 16, 8, 4, 2]; value = join.value { freq_slice wave = Image (sin ((im_fgrey width strip_height) * 360 * width / wave) > 0); strips = map freq_slice wavelengths; join = foldl1 Join.Top_bottom strips; } } /* make a checkerboard pattern */ New_checkerboard = class Image value { width = 64; height = 64; horizontal_patch_size = 8; vertical_patch_size = 8; horizontal_patch_offset = 0; vertical_patch_offset = 0; value = xstripes ^ ystripes { pixels = make_xy width height; xpixels = pixels?0 + horizontal_patch_offset; ypixels = pixels?1 + vertical_patch_offset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels horizontal_patch_size; ystripes = make_stripe ypixels vertical_patch_size; } } /* make a grid pattern */ New_grid = class Image value { width = 64; height = 64; horizontal_line_spacing = 8; vertical_line_spacing = 8; line_thickness = 1; horizontal_grid_offset = 0; vertical_grid_offset = 0; value = xstripes | ystripes { pixels = make_xy width height; xpixels = pixels?0 + horizontal_grid_offset; ypixels = pixels?1 + vertical_grid_offset; make_stripe pix swidth = pix % swidth < line_thickness; xstripes = make_stripe xpixels horizontal_line_spacing; ystripes = make_stripe ypixels vertical_line_spacing; } } #separator /* make a gaussian matrix */ New_gauss_matrix = class Matrix_vips _mask.value _mask.scale _mask.offset _mask.filename _mask.display { sigma = Slider 0.001 10 1; min_amplitude = Slider 0 1 0.2; integer = Toggle "Integer" false; _mask = fn sigma.value min_amplitude.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } /* make a laplacian of a gaussian mask */ New_log_matrix = class Matrix_vips _mask.value _mask.scale _mask.offset _mask.filename _mask.display { sigma = Slider 0.001 10 1.5; min_amplitude = Slider 0 1 0.1; integer = Toggle "Integer" false; _mask = fn sigma.value min_amplitude.value { fn = im_log_imask, integer = im_log_dmask; } } #separator /* make the mask images for various ideal fourier filters */ New_ideal = class { /* make a mask image for an ideal highpass/lowpass fourier filter */ High_low = class Image value { size = 64; frequency_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff.value 0 0 0 0; } } /* make a mask image for an ideal ring pass/reject fourier filter */ Ring = class Image value { size = 64; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 6; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff.value ring_width.value 0 0 0; } } /* make a mask image for an ideal band pass/reject fourier filter */ Band = class Image value { size = 64; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 12; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value 0 0; } } } /* various Gaussian fourier filters */ New_gaussian = class { /* make a mask image for a gaussian highpass/lowpass fourier filter */ High_low = class Image value { size = 64; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value + 4; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff.value amplitude_cutoff.value 0 0 0; } } /* make a mask image for a gaussian ring pass/reject fourier filter */ Ring = class Image value { size = 64; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 10; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff.value ring_width.value amplitude_cutoff.value 0 0; } } /* make a mask image for a gaussian band pass/reject fourier filter */ Band = class Image value { size = 64; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 16; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value 0; } } } /* various Butterworth fourier filters */ New_butterworth = class { /* make a mask image for a Butterworth highpass/lowpass fourier filter */ High_low = class Image value { size = 64; order = Slider 1 10 2; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value + 2; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type order.value frequency_cutoff.value amplitude_cutoff.value 0 0; } } /* make a mask image for a Butterworth ring pass/reject fourier filter */ Ring = class Image value { size = 64; order = Slider 1 10 2; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 8; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type order.value frequency_cutoff.value ring_width.value amplitude_cutoff.value 0; } } /* make a mask image for a Butterworth band pass/reject fourier filter */ Band = class Image value { size = 64; order = Slider 1 10 2; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 14; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type order.value frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value; } } } #separator /* make a slice through CIELAB space */ New_CIELAB_slice = class Image value { size = 64; L = Slider 0 100 50; value = lab_slice size L.value; } /* pick a colour in LAB space */ New_LAB_colour = widget "Lab" [50, 0, 0] { // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range); ab2xy a = (a * (size / range)); widget space default_value = class Colour space value { L = default_value?0; a = default_value?1; b = default_value?2; lightness = Slider 0 100 L; ab_slice = Image (lab_slice size lightness.value); point = Point ab_slice (ab2xy a) (ab2xy b); value = [lightness.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } nip2-8.7.1/share/nip2/compat/7.9/Makefile.am0000644000175000017500000000062213351443023015124 00000000000000startdir = $(pkgdatadir)/compat/7.9 start_DATA = \ Math.def \ Image.def \ Mosaic.def \ Colour.def \ Resize.def \ Capture.def \ Format.def \ Filter.def \ Morphology.def \ New.def \ Histogram.def \ Print.def \ Rotate.def \ Statistics.def \ X_ray.def \ _convert.def \ _errors.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.9/Rotate.def0000644000175000017500000000460713351443023015015 00000000000000/* rotate images and matricies by fixed angles */ Rotate_fixed = class { /* rotate image clockwise in 90 degree increments */ _rotate_widget default a = map_unary widget a { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; value = [ image.value, rot90 image.value, rot180 image.value, rot270 image.value ] ? angle; } } /* clockwise rotate by 90 degrees */ R90 x = _rotate_widget 1 x; /* rotate by 180 degrees */ R180 x = _rotate_widget 2 x; /* clockwise rotate by 270 degrees */ R270 x = _rotate_widget 3 x; /* rotate by 45 degrees ... square, odd-length-sides, matrices only */ R45 x = map_unary rot45 x; } /* rotate image anticlockwise by any angle */ Rotate_free a = map_unary widget a { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; angle = Slider 0 360 0; value = rotate angle image.value; } } #separator /* mirror left/right or up/down */ Flip = class { /* mirror object up/down */ Up_down x = map_unary flipud x; /* mirror object left/right */ Left_right x = map_unary fliplr x; } /* swap rows and columns */ Transpose x = map_unary transpose x; #separator /* smallest rotate that gets arrow vertical or horizontal */ Straighten_arrow x = map_unary straighten x { straighten arrow = rotate angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } nip2-8.7.1/share/nip2/compat/7.9/Makefile.in0000644000175000017500000003714513417043242015151 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.9 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.9 start_DATA = \ Math.def \ Image.def \ Mosaic.def \ Colour.def \ Resize.def \ Capture.def \ Format.def \ Filter.def \ Morphology.def \ New.def \ Histogram.def \ Print.def \ Rotate.def \ Statistics.def \ X_ray.def \ _convert.def \ _errors.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.9/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.9/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.9/_predicate.def0000644000175000017500000000551013351443023015650 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true of character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && land (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, land (map is_obj l) = true, land (map is_list l) && land (map (not @ is_obj) l) && land (map is_rectangular l) && len l > 0 && land (map (equal (hd lengths)) (tl lengths)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; lengths = map len l; } /* is_matrix l: is l a list of lists of real numbers, all the same length */ is_matrix l = is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [] = is_matrix l && len l == len (hd l); /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [] = is_matrix l && (len l) % 2 == 1 && (len (l?0)) % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && (len l) % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_Guide x = is_instanceof "HGuide" x || is_instanceof "VGuide" x; is_Point x = is_instanceof "Point" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && land (map xy l) { xy l = is_real_list l && len l == 2; } nip2-8.7.1/share/nip2/compat/7.9/_list.def0000644000175000017500000001743713351443023014676 00000000000000/* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn (tl l), fn (hd l) = l; /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l up from the left using function fn and start value st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold up list l, right to left, with function fn and start * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); /* Search a list for an element, returning it's index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* land l: and all the elements of list l together * * land (map (==0) list) == true, if every element of list is zero. * land :: [bool] -> bool */ land = foldr logical_and true; /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a = l?0; b = l?1; x = tl (tl l); } /* lor l: or all the elements of list l together * * lor (map (equal 0) list) == true, if any element of list is zero. * lor :: [bool] -> bool */ lor = foldr logical_or false; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map fn' (zip2 l1 l2) { fn' p = fn p?0 p?1; } /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map fn' (zip3 l1 l2 l3) { fn' p = fn p?0 p?1 p?2; } /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = lor (map (equal x) l); /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a = hd l; x = tl l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st (hd l)) (tl l); } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a = hd l1; x = tl l1; b = hd l2; y = tl l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by fn * * split is_space "hello world" == ["hello", "world"] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/7.24/0000755000175000017500000000000013417043452013232 500000000000000nip2-8.7.1/share/nip2/compat/7.24/Image.def0000644000175000017500000013201513351443023014651 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum Image_type.type_names "Image type" "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum field_names (_ "Field") name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum Image_type.type_names "Image type" (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process in = [ in, rot90 in, rot180 in, rot270 in ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp h v image, aspect = resize interp fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize interp fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = class _result { _vislevel = 3; // try to find the image geometry ... don't bother trying to look // inside groups though _geo = x.rect, is_Image x = Rect 0 0 100 100; l = Expression "Crop left" ((int) (_geo.left + _geo.width / 4)); t = Expression "Crop top" ((int) (_geo.top + _geo.height / 4)); w = Expression "Crop width" (max_pair 1 ((int) (_geo.width / 2))); h = Expression "Crop height" (max_pair 1 ((int) (_geo.height / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/7.24/_convert.def0000644000175000017500000004437013351443023015454 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The innermost list objects become Group()'d. */ to_group x = Group x, is_list x && !contains_Group x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = (ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* Given a list of things, try to make them all the same size. Don't change * the format. Don't touch non-image things. */ size_alike l = map enlarge l { max_width = foldr (test_prop has_width get_width) 0 l; max_height = foldr (test_prop has_height get_height) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); enlarge x = embed 0 0 0 max_width max_height x, has_width x = x; } /* Given a list of things, look for 1 band objects and bump them to to n - * band objects, where n is the maximum number of bands. Don't change the * format. Don't touch non-image things. */ bands_alike l = map upband l { max_bands = foldr (test_prop has_bands get_bands) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); upband x = bandjoin (replicate max_bands x), has_bands x && get_bands x == 1 = x; } /* Given a list of things, try to match the formats. Don't touch non-image * objects. */ formats_alike l = map upformat l { max_format = foldr (test_prop has_format get_format) Image_format.UCHAR l; test_prop has get x best = best, !has x = max_pair best (get x); upformat x = clip2fmt max_format x, has_format x = x; } /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 == 2 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/7.24/Filter.def0000644000175000017500000011516513351443023015063 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 1.5; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 50; fs = Scale "Sharpen flat areas by" (-2) 5 1; js = Scale "Sharpen jaggy areas by" (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees"] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } sep3 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_greyc_item = class Menupullright "_GREYCstoration" "noise-removing filter" { Denoise_item = class Menuaction "Denoise" "Noise-removing filter" { action x = class _result { _vislevel = 3; iterations = Scale "Iterations" 1 5 1; amplitude = Scale "Amplitude" 1 100 40; sharpness = Scale "Sharpness" 0 3 0.9; anisotropy = Scale "Anisotropy" 0 1 0.15; alpha = Scale "Noise scale" 0 5 0.6; sigma = Scale "Geometry regularity" 0 2 1.1; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) x; } } Enlarge_item = class Menuaction "Enlarge" "Enlarge image" { action x = class _result { _vislevel = 3; scale = Scale "Enlarge" 1 10 3; iterations = Scale "Iterations" 1 5 3; amplitude = Scale "Amplitude" 1 100 20; sharpness = Scale "Sharpness" 0 3 0.2; anisotropy = Scale "Anisotropy" 0 1 0.9; alpha = Scale "Noise scale" 0 5 0.1; sigma = Scale "Geometry regularity" 0 2 1.5; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) (resize Interpolate_bilinear (to_real scale) (to_real scale) x); } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ [_ "Normal", NORMAL], [_ "If Lighter", IFLIGHTER], [_ "If Darker", IFDARKER], [_ "Multiply", MULTIPLY], [_ "Add", ADD], [_ "Subtract", SUBTRACT], [_ "Screen", SCREEN], [_ "Burn", BURN], [_ "Soft Light", SOFTLIGHT], [_ "Hard Light", HARDLIGHT], [_ "Lighten", LIGHTEN], [_ "Darken", DARKEN], [_ "Dodge", DODGE], [_ "Reflect", REFLECT], [_ "Freeze", FREEZE], [_ "Bitwise OR", OR], [_ "Bitwise AND", AND] ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum names "Blend mode" "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } nip2-8.7.1/share/nip2/compat/7.24/_joe_extra.def0000644000175000017500000002725013351443023015752 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = (if mask then im * 1.2 else im * 1), no == 0 = (if mask then im * 0.8 else im * 1), no == 1 = (if mask then 0 else im), no == 2 = (if mask then 255 else im), no == 3 = (if mask then im else 0), no == 4 = (if mask then im else 255), no == 5 = mask; Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Interpolate_bilinear f1 1 b1 {b1 = resize Interpolate_bilinear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.24/Colour.def0000644000175000017500000003610013351443023015070 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Convert to") (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Tag as") (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Colour Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum Whitepoints (_ "Old whitepoint") "D65"; new_white = Option_enum Whitepoints (_ "New whitepoint") "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum Render_intent.names (_ "Render intent") (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; _result = map_unary chart x { chart in = measure 0 0 in.width in.height (to_real pacross) (to_real pdown) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.24/_joe_utilities.def0000644000175000017500000005054713351443023016647 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/7.24/_Object.def0000644000175000017500000002600513351443023015175 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/7.24/Object.def0000644000175000017500000000222013351443023015027 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list (or group) of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/7.24/Math.def0000644000175000017500000003157713351443023014533 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_And" "bitwise and of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_Or" "bitwise or of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "E_xclusive Or" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_Not" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Band_or_item = class Menuaction "Band O_r" "or the bands of an image together" { action im = map_unary (foldr1 bitwise_or @ bandsplit) im; } Band_and_item = class Menuaction "Band A_nd" "and the bands of an image together" { action im = map_unary (foldr1 bitwise_and @ bandsplit) im; } } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.24/_generate.def0000644000175000017500000000470713351443023015566 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } nip2-8.7.1/share/nip2/compat/7.24/_stdenv.def0000644000175000017500000015754513351443023015310 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_cache x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend") { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; [c, t, e] = size_alike [cond, then_image, else_image]; blend_result_image = image_set_type target_type (im_blend c t e); } } insert x y small big = oo_binary_function insert_op small big, is_class small = oo_binary'_function insert_op small big, is_class big = im_insert big' small' (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; [small', big'] = (formats_alike @ bands_alike) [small, big]; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big' small' (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; [small', big'] = (formats_alike @ bands_alike) [small, big]; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (_ "bad arguments to " ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx x = oo_unary_function greyc_op x, is_class x = greyc_im x, is_image x = error (_ "bad argument" ++ " (" ++ print x ++ ") to " ++ "greyc") { greyc_op = Operator "greyc" (greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im x = im_greyc x iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx mask x = oo_binary_function greyc_mask_op mask x, is_class mask = oo_binary'_function greyc_mask_op mask x, is_class x = greyc_im mask x, is_image mask && is_image x = error (_ "bad arguments" ++ " (" ++ print mask ++ ", " ++ print x ++ ") " ++ "to " ++ "greyc") { greyc_mask_op = Operator "greyc_mask" (greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im mask x = im_greyc_mask x mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize interp xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; // is this interpolation nearest-neighbour? is_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor, nearest neighbour // upscale by integer part, then affine to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by any factor, nearest neighbour // downscale by integer part, then affine to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor with affine = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 // downscale by any factor, bilinear // block shrink by integer factor, then resample to // exact with affine = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate_type.descriptions?interp.type ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // resize scale xfac yfac im = im_affinei_all im interp.value xfac 0 0 yfac 0 0; } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } flood_blob x y v image = oo_unary_function flood_blob_op image, is_class image = im_flood_blob_copy image (to_real x) (to_real y) v, is_image image = error (_ "bad arguments to " ++ "flood_blob") { flood_blob_op = Operator "flood_blob" (flood_blob x y v) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; } ss = len xes; sx = sum xes; sy = sum yes; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } nip2-8.7.1/share/nip2/compat/7.24/Histogram.def0000644000175000017500000001452513351443023015571 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "Histogram" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Cumulativise" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Cumulativise)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Interpolate_bilinear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; format = Option_enum Plot_format.names "Format" "YYYY"; style = Option_enum Plot_style.names "Style" "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/7.24/Widgets.def0000644000175000017500000000235313351443023015236 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/7.24/_types.def0000644000175000017500000007073213351443023015141 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.value_name colour.expr { _vislevel = 3; space = Option_enum Image_type.colour_spaces "Colour space" default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } Option_enum enum caption value_name = class Option caption enum.names (index (equal value_name) enum.names) { // corresponding thing value_thing = enum.get_thing value_name; Option_edit caption labels value = this.Option_enum enum caption (enum.names ? value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; LUMINANCE = 2; XRAY = 3; IR = 4; YUV = 5; RED_ONLY = 6; GREEN_ONLY = 7; BLUE_ONLY = 8; POWER_SPECTRUM = 9; HISTOGRAM = 10; LUT = 11; XYZ = 12; LAB = 13; CMC = 14; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $LUMINANCE => LUMINANCE, $XRAY => XRAY, $IR => IR, $YUV => YUV, $RED_ONLY => RED_ONLY, $GREEN_ONLY => GREEN_ONLY, $BLUE_ONLY => BLUE_ONLY, $POWER_SPECTRUM => POWER_SPECTRUM, $HISTOGRAM => HISTOGRAM, $LUT => LUT, $XYZ => XYZ, $LAB => LAB, $CMC => CMC, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16 ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], // image ++ image is slightly different ... we want to // sizealike, but we must not bandalike [wrap (op.fn (get_image resized?0) (get_image resized?1)), has_image x && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], // arithmetic and reational binops between image resize // and band_alike images to match [wrap (op.fn (get_image rebanded?0) (get_image rebanded?1)), has_image x && (op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL)], // other op types don't resize [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [if_size, then_size, else_size] = size_alike (value : formats_alike (map to_image x)); ite_result_image = image_set_type target_type (if if_size then then_size else else_size); resized = size_alike [this, x]; rebanded = bands_alike resized; } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ [_ "Perceptual", PERCEPTUAL], [_ "Relative", RELATIVE], [_ "Saturation", SATURATION], [_ "Absolute", ABSOLUTE] ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ [_ "Point", POINT], [_ "Line", LINE], [_ "Spline", SPLINE], [_ "Bar", BAR] ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ [_ "YYYY", YYYY], [_ "XYYY", XYXY], [_ "XYXY", XYXY] ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/7.24/Matrix.def0000644000175000017500000002060713351443023015076 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/7.24/Tasks.def0000644000175000017500000006321313351443023014717 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linear input", "Fit intercept from chart greyscale", "Linearize input from chart greyscale" ] 2; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure 0 0 image.width image.height 6 4 image.value; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix [[0, 0], [1, 1]], mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix (map2 cons _true_grey_Y' _camera_grey') { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map the original image through the lineariser to // get linear 0-1 RGB image _image' = hist_map linearising_lut.value image.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ cast_float @ recomb M) _image'; // measure again and compute dE76 _camera'' = im_measure _result.value 0 0 image.width image.height 6 4; _dEs = map abs_vec (_camera'' - _true_Lab).value; final_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; // map the original image through the lineariser to get // linear 0-1 RGB image image' = hist_map calib.linearising_lut image; // convert linear RGB camera to Lab result = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M image')); } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum Plot_style.names "Style" "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Interpolate_bilinear xfactor yfactor scale_im; _offset_im = resize Interpolate_bilinear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.24/Makefile.am0000644000175000017500000000054313351443023015203 00000000000000startdir = $(pkgdatadir)/compat/7.24 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.24/Makefile.in0000644000175000017500000003707113417043242015224 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.24 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.24 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.24/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.24/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.24/_predicate.def0000644000175000017500000002672113351443023015734 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = error ("get_format: unable to get format from " ++ print x); has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = error ("get_bits: unable to get bits from " ++ print x); has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = error ("get_bands: unable to get bands from " ++ print x); has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = error ("get_coding: unable to get coding from " ++ print x); has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = error ("get_xres: unable to get xres from " ++ print x); has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = error ("get_yres: unable to get yres from " ++ print x); has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = error ("get_xoffset: unable to get xoffset from " ++ print x); has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = error ("get_yoffset: unable to get yoffset from " ++ print x); has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = error ("get_image: unable to get image from " ++ print x); has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = error ("get_number: unable to get number from " ++ print x); has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = error ("get_real: unable to get real from " ++ print x); has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = error ("get_width: unable to get width from " ++ print x); has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = error ("get_height: unable to get height from " ++ print x); has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = error ("get_left: unable to get left from " ++ print x); has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = error ("get_top: unable to get top from " ++ print x); // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/7.24/_list.def0000644000175000017500000002245013351443023014742 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st a) x { a:x = l; } } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/8.6/0000755000175000017500000000000013417043453013154 500000000000000nip2-8.7.1/share/nip2/compat/8.6/Image.def0000644000175000017500000015333713351443023014604 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process = [ // we can't use id here since we want to "declass" // the members of x ... consider if x is a crop class, // for example, we don't want to inherit from crop, we // want to make a new image class rot180 @ rot180, rot90, rot180, rot270 ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel h v image, aspect = resize kernel fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize kernel fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_map_item = class Menuaction "_Map" "map an image through a 2D transform image" { action a b = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_binary trans a b { trans a b = mapim interp.value in index { // get the index image first [index, in] = sortc (const is_twocomponent) [a, b]; // is a two-component image, ie. one band complex, or // two-band non-complex is_twocomponent x = is_nonc x || is_c x; is_nonc x = has_bands x && get_bands x == 2 && has_format x && !is_complex_format (get_format x); is_c x = has_bands x && get_bands x == 1 && has_format x && is_complex_format (get_format x); is_complex_format f = f == Image_format.COMPLEX || f == Image_format.DPCOMPLEX; } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1a = Menuseparator; Bandand_item = class Menuaction "Bitwise Band AND" "bitwise AND of image bands" { action x = bandand x; } Bandor_item = class Menuaction "Bitwise Band OR" "bitwise OR of image bands" { action x = bandor x; } sep2 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_alpha_item = class Menupullright "_Alpha" "manipulate image alpha" { Add_item = class Menuaction "_Add" "add alpha" { action x = class _result { _vislevel = 3; opacity = Expression "Opacity (255 == solid)" 255; _result = x ++ to_real opacity; } } Flatten_item = class Menuaction "_Flatten" "flatten alpha out of image" { action x = class _result { _vislevel = 3; bg = Expression "Background" 0; _result = map_unary (flattenimage bg) x; } } Extract_item = class Menuaction "_Extract" "extract alpha" { action x = map_unary exb x { exb x = extract_bands (x.bands - 1) 1 x; } } Drop_item = class Menuaction "_Drop" "drop alpha" { action x = map_unary exb x { exb x = extract_bands 0 (x.bands - 1) x; } } sep1 = Menuseparator; Premultiply_item = class Menuaction "_Premultiply" "premultiply alpha" { action x = premultiply x; } Unpremultiply_item = class Menuaction "_Unpremultiply" "unpremultiply alpha" { action x = unpremultiply x; } sep2 = Menuseparator; Composite2_item = class Menuaction "_Composite two" "composite a pair of images" { action x y = class _result { _vislevel = 3; blend = Option_enum (_ "Blend mode") modes "over" { modes = Blend_type.types; } compositing_space = Option_enum (_ "Compositing space") spaces "sRGB" { spaces = Image_type.image_colour_spaces; } premultiplied = Toggle (_ "Premultiplied") false; _result = Image output { [output] = vips_call "composite" [[y.value, x.value], blend.value] [$compositing_space => compositing_space.value_thing, $premultiplied => premultiplied.value ]; } } } Composite3_item = class Menuaction "_Composite three" "composite three images" { action x y z = class _result { _vislevel = 3; blend1 = Option_enum (_ "Blend mode") modes "over" { modes = Blend_type.types; } blend2 = Option_enum (_ "Blend mode") modes "over" { modes = Blend_type.types; } compositing_space = Option_enum (_ "Compositing space") spaces "sRGB" { spaces = Image_type.image_colour_spaces; } premultiplied = Toggle (_ "Premultiplied") false; _result = Image output { [output] = vips_call "composite" [[z.value, y.value, x.value], [blend1.value, blend2.value]] [$compositing_space => compositing_space.value_thing, $premultiplied => premultiplied.value ]; } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = crop x [l, t, w, h] { fields = [ [has_left, get_left, 0], [has_top, get_top, 0], [has_width, get_width, 100], [has_height, get_height, 100] ]; [l, t, w, h] = map get_default fields { get_default line = get x, has x = default { [has, get, default] = line; } } } crop x geo = class _result { _vislevel = 3; l = Expression "Crop left" ((int) (geo?0 + geo?2 / 4)); t = Expression "Crop top" ((int) (geo?1 + geo?3 / 4)); w = Expression "Crop width" (max_pair 1 ((int) (geo?2 / 2))); h = Expression "Crop height" (max_pair 1 ((int) (geo?3 / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 0; sy = Expression "Start y" 0; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise Join" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; snake = Toggle "Reverse the order of every other row" false; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _l' = map2 reverse_if_odd [0..] _l, snake = _l { reverse_if_odd n x = reverse x, n % 2 == 1 = x; } _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l')); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Noise_item = class Menupullright "_Noise" "various noise generators" { Gaussian_item = class Menuaction "_Gaussian" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (gaussnoise nwidth nheight mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal noise image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Perlin_item = class Menuaction "_Perlin" "Perlin noise image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; cell_size = Expression "Cell size (pixels)" 8; eight = Toggle "Eight bit output" true; _result = 128 * im + 128, eight = im { im = perlin cell_size nwidth nheight; } } } Worley_item = class Menuaction "_Worley" "Worley noise image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 512; nheight = Expression "Image height (pixels)" 512; cell_size = Expression "Cell size (pixels)" 256; _result = worley cell_size nwidth nheight; } } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/8.6/_convert.def0000644000175000017500000005063113351443023015372 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make a Vector ... works for Vector/Image/Real, plus image/real */ to_vector x = to_vector x.expr, is_Expression x = x, is_Vector x = oo_unary_function to_vector_op x, is_class x = tov x { to_vector_op = Operator "to_vector" tov Operator_type.COMPOUND false; tov x = Vector (itov x), is_image x = Vector [x], is_real x = Vector x, is_real_list x = Vector x?0, is_matrix x && len x == 1 = Vector (transpose x)?0, is_matrix x && len x?0 == 1 = error (_ "bad arguments to " ++ "to_vector"); itov i = v, is_image i = error (_ "not image") { m = im_vips2mask ((double) i); v = m.value?0, m.height == 1 = (transpose m.value)?0, m.width == 1 = error (_ "image is not 1xN or Nx1"); } } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = Image x.value, is_Plot x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The outermost list objects become Group()'d. */ to_group x = Group x, is_list x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = sign * (abs ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; sign = 1, ipart >= 0 = -1; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* The vips8 scRGB functions. */ im_sRGB2scRGB in = out { [out] = vips_call "sRGB2scRGB" [in] []; } im_scRGB2sRGB in = out { [out] = vips_call "scRGB2sRGB" [in] []; } im_scRGB2XYZ in = out { [out] = vips_call "scRGB2XYZ" [in] []; } im_XYZ2scRGB in = out { [out] = vips_call "XYZ2scRGB" [in] []; } /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, scRGB, im_sRGB2scRGB @ im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, scRGB, im_XYZ2scRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, scRGB, im_XYZ2scRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, scRGB, im_XYZ2scRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, scRGB, im_sRGB2scRGB @ im_clip], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_Lab2LabS @ im_sRGB2Lab @ im_clip], [scRGB, B_W, im_sRGB2mono @ im_scRGB2sRGB], [scRGB, XYZ, im_scRGB2XYZ], [scRGB, YXY, im_XYZ2Yxy @ im_scRGB2XYZ], [scRGB, LAB, im_XYZ2Lab @ im_scRGB2XYZ], [scRGB, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_scRGB2XYZ], [scRGB, UCS, im_XYZ2UCS @ im_scRGB2XYZ], [scRGB, RGB, im_XYZ2disp @ im_scRGB2XYZ], [scRGB, sRGB, im_scRGB2sRGB], [scRGB, scRGB, image_set_type scRGB], [scRGB, RGB16, image_set_type RGB16 @ im_8216 @ im_scRGB2sRGB], [scRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono @ im_scRGB2sRGB], [scRGB, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_scRGB2XYZ], [scRGB, LABS, im_Lab2LabS @ im_XYZ2Lab @ im_scRGB2XYZ], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, scRGB, im_sRGB2scRGB], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, scRGB, im_sRGB2scRGB @ im_mono2sRGB], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabS2Lab @ im_clip2s], [LABS, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LabS2Lab @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; scRGB = 28; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; /* Return $PATH, reformatted as [["comp1", "comp2"], ["comp1", "comp2"] ..] */ system_search_path = [vipsbin] ++ map path_parse (split (equal path_sep) (expand "$PATH")) { /* On some platforms we ship vips with a few extra progs. Search * $VIPSHOME/bin first. */ vipsbin = path_parse (expand "$VIPSHOME") ++ ["bin"]; path_sep = ':', expand "$SEP" == "/" = ';'; } /* Search $PATH for the first occurence of name, or "". */ search_for name = hits?0, hits != [] = "" { exe_name = name ++ expand "$EXEEXT"; form_path p = path_absolute (p ++ [exe_name]); paths = map form_path system_search_path; hits = dropwhile (equal []) (map search paths); } /* Search $PATH for the first occurence of name, error on failure. */ search_for_error name = path, path != "" = error (exe_name ++ " not found on your search path. " ++ "Check you have installed the program and it is on your PATH.") { exe_name = name ++ expand "$EXEEXT"; path = search_for name; } nip2-8.7.1/share/nip2/compat/8.6/Filter.def0000644000175000017500000011740613351443023015004 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 2; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 20; fs = Scale "Sharpen flat areas by" 0 5 0.5; js = Scale "Sharpen jaggy areas by" 0 5 1; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; max_slope = Scale "Maxium slope" 0 10 0; _result = map_unary process x { process in = hist_equalize_local window_width window_height max_slope in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_hough_item = class Menupullright "_Hough Transform" "transform to parameter space" { Line_item = class Menuaction "_Line" "find straight line Hough transform" { action a = class _result { _vislevel = 3; pspace_width = Expression "Parameter space width" 64; pspace_height = Expression "Parameter space height" 64; _result = map_unary line a { line a = hough_line (to_real pspace_width) (to_real pspace_height) a; } } } Circle_item = class Menuaction "_Circle" "find circle Hough transform" { action a = class _result { _vislevel = 3; scale = Expression "Scale down parameter space by" 10; min_radius = Expression "Minimum radius" 10; max_radius = Expression "Maximum radius" 30; _result = map_unary circle a { circle a = hough_circle (to_real scale) (to_real min_radius) (to_real max_radius) a; } } } } Filter_coordinate_item = class Menupullright "_Coordinate Transform" "various coordinate transforms" { // run a function which wants a complex arg on a non-complex two-band // image run_cmplx fn x = re x' ++ im x' { x' = fn (x?0, x?1); } Polar_item = class Menuaction "_Polar" "transform to polar coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_polar a { to_polar im = mapim interp.value map' im { // xy image, origin in the centre, scaled to fit image to // a circle xy = make_xy im.width im.height; xy' = xy - Vector [im.width / 2, im.height / 2]; scale = min [im.width, im.height] / im.width; xy'' = 2 * xy' / scale; // to polar, scale vertical axis to 360 degrees map = run_cmplx polar xy''; map' = map * Vector [1, im.height / 360]; } } } } Rectangular_item = class Menuaction "_Rectangular" "transform to rectangular coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_rect a { to_rect im = mapim interp.value map'' im { // xy image, vertical scaled to 360 degrees xy = make_xy im.width im.height; xy' = xy * Vector [1, 360 / im.height]; // to rect, scale to image rect map = run_cmplx rectangular xy'; scale = min [im.width, im.height] / im.width; map' = map * scale / 2; map'' = map' + Vector [im.width / 2, im.height / 2]; } } } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "Blend _Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } Autotrace_item = class Menuaction "_Trace" "convert a bitmap to an SVG file" { action x = class _result { _vislevel = 3; despeckle = Scale "Despeckle level" 1 20 1; line = Scale "Line threshold" 1 20 1; center = Toggle "Trace centreline" false; scale = Scale "SVG scale" 0.1 10 1; command = "autotrace %s " ++ join_sep " " [ofmt, ofile, desp, lint, cent] { prog = search_for_error "autotrace"; ofmt = "-output-format svg"; ofile = "-output-file %s"; desp = "-despeckle-level " ++ print despeckle.value; lint = "-line-threshold " ++ print line.value; cent = if center then "-centerline " else ""; } _result = Image output { [output] = vips_call "system" [command] [$in => [x.value], $in_format => "%s.ppm", $out => true, $out_format => "%s.svg[scale=" ++ print scale.value ++ "]" ]; } } } nip2-8.7.1/share/nip2/compat/8.6/_joe_extra.def0000644000175000017500000003225713351443023015676 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use an Arrow or Region x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { im = x.image; mask = Image m { rx = x.region_rect, is_Region x = x; b = image_new im.width im.height 1 0 0 1 0 0 0; w = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0; m = insert_noexpand rx.nleft rx.ntop w b; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } Fill_item = class Menuaction "_Fill" "fill zero pixels with the nearest non-zero" { action x = class Image _result { _vislevel = 3; distance = Image _distance; [_result, _distance] = vips_call "fill_nearest" [x.value] [ "distance" => true ]; } } fill_nearest x = oo_unary_function nearest_op x, is_class x = near x, is_image x = error (_ "bad arguments to " ++ "fill_nearest") { nearest_op = Operator "fill_nearest" fill_nearest Operator_type.COMPOUND_REWRAP false; near x = [out, distance] { [out, distance] = vips_call "fill_nearest" [x] [ "distance" => true ]; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Kernel_linear f1 1 b1 {b1 = resize Kernel_linear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/8.6/Magick.def0000644000175000017500000014112713351443023014747 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate Magick.def 13-Apr-2014 snibgo Put "new image" items into sub-menu. New class VirtualPixlBack. 17-Apr-2014 snibgo Many small changes. A few new menu options. Created sub-menu for multi-input operations. 3-May-2014 jcupitt Put quotes around ( in shadow to help unix Last update: 17-Apr-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ // We don't need Noop. /*=== Magick_noop_item = class Menuaction "_Noop" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_testPar_item = class Menuaction "_TestPar" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "( +clone ) +append ", "\"%s\"" ]; _result = Magick.system command x; } } /* Removed Read_item and Write_item, much better to use nip2 load/save image. * Plus they can load all libMagick formats anyway. */ // Put "new image" items into sub-menu Magick_NewImageMenu_item = class Menupullright "_New image" "make a new image" { Magick_newcanvas_item = class Menuaction "_Solid colour" "make image of solid colour" { action = class _result { _vislevel = 3; size = Magick.Size_widget; colour = Magick.generalcol_widget; command = Magick.command [ size._flag, "\"canvas:" ++ colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_builtin_item = class Menuaction "_Built-in image" "create a built-in image" { action = class _result { _vislevel = 3; builtin = Magick.builtin_widget; command = Magick.command [ builtin._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_gradient_item = class Menuaction "_Gradient" "make a linear gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; topColour = Magick.generalcol_widget; bottomColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"gradient:", topColour._flag, "-", bottomColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } Magick_hald_item = class Menuaction "_Hald-clut image" "create an identity hald-clut image" { action = class _result { _vislevel = 3; order = Expression "order" 8; command = Magick.command [ "hald:" ++ print order.expr, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_pattern_item = class Menuaction "_Pattern" "create pattern" { action = class _result { _vislevel = 3; size = Magick.Size_widget; pattern = Magick.pattern_widget; command = Magick.command [ size._flag, pattern._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_plasma_item = class Menuaction "_Plasma image" "create plasma image" { action = class _result { _vislevel = 3; size = Magick.Size_widget; // FIXME? ColourA-ColourB. // FIXME? Allow plasma:fractal? command = Magick.command [ size._flag, "plasma:", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_radialgradient_item = class Menuaction "_Radial gradient" "make a radial gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; innerColour = Magick.generalcol_widget; outerColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"radial-gradient:", innerColour._flag, "-", outerColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } } // end Magick_NewImageMenu_item Magick_MultiMenu_item = class Menupullright "_Multiple inputs" "make an image from multiple images" { Magick_composite_item = class Menuaction "_Composite" "composite two images (without mask)" { action x y = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_compositeMask_item = class Menuaction "_Composite masked" "composite two images (with mask)" { action x y z = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system3 command x y z; } } // FIXME: other operations like remap that take another image as arguments are: // mask (pointless?), texture, tile (pointless?) // FIXME: operations that take a filename that isn't an image: // cdl, profile Magick_clut_item = class Menuaction "_Clut" "replace values using second image as colour look-up table" { action x y = class _result { _vislevel = 3; // FIXME: uses -intensity "when mapping greyscale CLUT image to alpha channel if set by -channels" command = Magick.command [ "\"%s\"", "\"%s\"", "-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_haldclut_item = class Menuaction "_Hald clut" "replace values using second image as Hald colour look-up table" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"", "-hald-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } // Encipher and decipher: key files can be text or image files. Magick_encipher_item = class Menuaction "_Encipher/Decipher" "encipher or decipher an image image" { action x = class _result { _vislevel = 3; pathname = Pathname "Read key file" ""; isDecipher = Toggle "Decipher" false; command = Magick.command [ "\"%s\"", if pathname.value == "" then "" else ( ( if isDecipher then "-decipher " else "-encipher ") ++ ( "\"" ++ pathname.value ++ "\"" ) ), "\"%s\"" ]; _result = Magick.system command x; } } Magick_profile_item = class Menuaction "_Profile" "assigns/applies an ICC profile" { action x = class _result { _vislevel = 3; pathname1 = Pathname "Read profile file" ""; pathname2 = Pathname "Read profile file" ""; command = Magick.command [ "\"%s\"", if pathname1.value == "" then "" else ( "-profile " ++ "\"" ++ pathname1.value ++ "\""), if pathname2.value == "" then "" else ( "-profile " ++ "\"" ++ pathname2.value ++ "\""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_remap_item = class Menuaction "_Remap" "reduce colours to those in another image" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-remap", "\"%s\"", "\"%s\"" ]; _result = Magick.system2 command x y; } } } // end Magick_MultiMenu_item Magick_image_type_item = class Menuaction "_Image Type" "change image type" { action x = class _result { _vislevel = 3; imagetype = Magick.imagetype_widget; command = Magick.command [ "\"%s\"", imagetype._flag, "\"%s\"" ]; _result = Magick.system command x; } } sep2 = Menuseparator; Magick_alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = Magick.alpha_widget; command = Magick.command [ "\"%s\"", alpha._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = Magick.text_widget; font = Magick.Font_widget; geometry = Magick.AnnotGeometry_widget; gravity = Magick.gravity_widget; foreground = Magick.foreground_widget; undercol = Magick.undercol_widget; antialias = Magick.antialias_widget; command = Magick.command [ "\"%s\"", font._flag, antialias._flag, gravity._flag, foreground._flag, undercol._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoGamma_item = class Menuaction "_AutoGamma" "automatic gamma" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-gamma", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoLevel_item = class Menuaction "_AutoLevel" "automatic level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-level", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blurSharpMenu_item = class Menupullright "_Blur/Sharpen" "blur and sharpen" { Magick_adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; // note: adaptive-blur doesn't regard VP. command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-adaptive-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_blur_item = class Menuaction "_Blur" "blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gaussianBlur_item = class Menuaction "_Gaussian Blur" "blur with a Gaussian operator" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-gaussian-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_motionBlur_item = class Menuaction "_Motion Blur" "simulate motion blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; channels = Magick.ch_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-motion-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotationalBlur_item = class Menuaction "_RotationalBlur" "blur around the centre" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; angle = Scale "angle (degrees)" (-360) 360 20; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-radial-blur", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_selectiveBlur_item = class Menuaction "_Selective Blur" "blur where contrast is less than or equal to threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; threshold = Scale "Threshold (percent)" 0 100 50; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", intensity._flag, virtpixback._flag, channels._flag, "-selective-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print threshold.value ++ "%%", "\"%s\"" ]; _result = Magick.system command x; } } sep1 = Menuseparator; Magick_adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-adaptive-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sharpen_item = class Menuaction "_Sharpen" "sharpen" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_unsharpen_item = class Menuaction "_Unsharp" "sharpen with unsharp mask" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; gain = Scale "Gain" (-10) 10 1; threshold = Scale "Threshold" 0 1 0.05; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-unsharp", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print gain.value ++ "+" ++ print threshold.value, "\"%s\"" ]; _result = Magick.system command x; } } } // end BlurSharpMenu_item Magick_border_item = class Menuaction "_Border" "add border of given colour" { action x = class _result { _vislevel = 3; compose = Magick.compose_widget; width = Expression "Width" 3; bordercol = Magick.bordercol_widget; command = Magick.command [ "\"%s\"", compose._flag, bordercol._flag, "-border", print width.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_brightCont_item = class Menuaction "_Brightness-contrast" "adjust the brightness and/or contrast" { action x = class _result { _vislevel = 3; bri = Scale "brightness" (-100) 100 0; con = Scale "contrast" (-100) 100 0; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-brightness-contrast", print bri.value ++ "x" ++ print con.value, "\"%s\"" ]; _result = Magick.system command x; } } // Note: canny requires ImageMagick 6.8.9-0 or later. Magick_canny_item = class Menuaction "_Canny" "detect a wide range of edges" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; lowPc = Scale "lower percent" 0 100 10; highPc = Scale "lower percent" 0 100 10; command = Magick.command [ "\"%s\"", "-canny", concat ["\"", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print lowPc.value ++ "%%+" ++ print highPc.value ++ "%%" ++ "\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_charcoal_item = class Menuaction "_Charcoal" "simulate a charcoal drawing" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; factor = Scale "factor" 0 50 1; command = Magick.command [ "\"%s\"", intensity._flag, "-charcoal", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_chop_item = class Menuaction "_Chop" "remove pixels from the interior" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-chop", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorize_item = class Menuaction "_Colorize" "colorize by given amount" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; val = Scale "value" 0 100 100; command = Magick.command [ "\"%s\"", foreground._flag, "-colorize", print val.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colors_item = class Menuaction "_Colors" "reduce number of colors" { action x = class _result { _vislevel = 3; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; quantize = Magick.colorspace_widget; colors = Expression "Colours" 3; command = Magick.command [ "\"%s\"", "-quantize", quantize._flag, "-treedepth", print treedepth.expr, dither._flag, "-colors", print colors.expr, "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: color-matrix? Magick_colorspace_item = class Menuaction "_Colourspace" "convert to arbitrary colourspace" { action x = class _result { _vislevel = 3; colsp = Magick.colorspace_widget; command = Magick.command [ "\"%s\"", "-colorspace", colsp._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorspaceGray_item = class Menuaction "_Colourspace gray" "convert to gray using given intensity method" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-colorspace gray", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrast_item = class Menuaction "_Contrast" "increase or reduce the contrast" { action x = class _result { _vislevel = 3; isReduce = Toggle "reduce contrast" false; command = Magick.command [ "\"%s\"", (if isReduce then "+" else "-") ++ "contrast", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrastStretch_item = class Menuaction "_Contrast stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-contrast-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: convolve (bias, kernel) Magick_crop_item = class Menuaction "_Crop" "cut out a rectangular region" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-crop", geometry._flag, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_deskew_item = class Menuaction "_Deskew" "straighten the image" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; // FIXME: toggle auto-crop? command = Magick.command [ "\"%s\"", "-deskew", "\"" ++ print threshold.value ++ "%%\"", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_despeckle_item = class Menuaction "_Despeckle" "reduce the speckles" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-despeckle", "\"%s\"" ]; _result = Magick.system command x; } } Magick_distort_item = class Menuaction "_Distort" "distort using a method and arguments" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; distort = Magick.distort_widget; args = String "Arguments" "1,0"; isPlus = Toggle "Extend to show entire image" false; command = Magick.command [ "\"%s\"", virtpixback._flag, (if isPlus then "+" else "-") ++ "distort", distort._flag, args.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_draw_item = class Menuaction "_Draw" "annotate with one or more graphic primitives" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; args = String "Arguments" "line 0,0 9,9 rectangle 10,10 20,20"; command = Magick.command [ "\"%s\"", foreground._flag, "-draw", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_edge_item = class Menuaction "_Edge" "detect edges" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-edge", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_emboss_item = class Menuaction "_Emboss" "emboss" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-emboss", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_enhance_item = class Menuaction "_Enhance" "enhance a noisy image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-enhance", "\"%s\"" ]; _result = Magick.system command x; } } Magick_equalize_item = class Menuaction "_Equalize" "equalize the histogram" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-equalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_evaluate_item = class Menuaction "_Evaluate" "evaluate an expression on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; operation = Magick.evaluate_widget; val = Expression "value" 5; isPc = Toggle "Value is percent" false; command = Magick.command [ "\"%s\"", channels._flag, operation._flag, print val.expr ++ if isPc then "%%" else "", "\"%s\"" ]; _result = Magick.system command x; } } Magick_extent_item = class Menuaction "_Extent" "set the image size and offset" { action x = class _result { _vislevel = 3; background = Magick.background_widget; compose = Magick.compose_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, background._flag, gravity._flag, "-extent", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_FlipFlopMenu_item = class Menupullright "_Flip/flop" "flip/flop/transverse/transpose" { Magick_flip_item = class Menuaction "_Flip vertically" "mirror upside-down" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flip", "\"%s\"" ]; _result = Magick.system command x; } } Magick_flop_item = class Menuaction "_Flop horizontally" "mirror left-right" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flop", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transpose_item = class Menuaction "_Transpose" "mirror along the top-left to bottom-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transpose +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transverse_item = class Menuaction "_Transverse" "mirror along the bottom-left to top-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transverse +repage", "\"%s\"" ]; _result = Magick.system command x; } } } // end Magick_FlipFlopMenu_item Magick_floodfill_item = class Menuaction "_Floodfill" "recolour neighbours that match" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; fuzz = Magick.fuzz_widget; coordinate = Magick.coordinate_widget; // -draw "color x,y floodfill" command = Magick.command [ "\"%s\"", foreground._flag, "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-draw \" color", coordinate._flag, "floodfill \"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_frame_item = class Menuaction "_Frame" "surround with border or beveled frame" { action x = class _result { _vislevel = 3; border = Magick.bordercol_widget; compose = Magick.compose_widget; matte = Magick.mattecol_widget; geometry = Magick.FrameGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, border._flag, matte._flag, "-frame", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_function_item = class Menuaction "_Function" "evaluate a function on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; function = Magick.function_widget; // FIXME: explain values; use sensible defaults. values = String "values" "0,0,0,0"; command = Magick.command [ "\"%s\"", channels._flag, "-function", function._flag, values.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_fx_item = class Menuaction "_Fx" "apply a mathematical expression" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; interpolate = Magick.interpolate_widget; virtpixback = Magick.VirtualPixelBack_widget; args = String "Expression" "u*1/2"; command = Magick.command [ "\"%s\"", channels._flag, interpolate._flag, virtpixback._flag, "-fx", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_gamma_item = class Menuaction "_Gamma" "apply a gamma correction" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; gamma = Magick.gamma_widget; command = Magick.command [ "\"%s\"", channels._flag, "-gamma", print gamma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradient_item = class Menuaction "_Gradient" "apply a linear gradient" { action x = class _result { _vislevel = 3; colourA = Magick.generalcol_widget; colourB = Magick.generalcol_widget; position = Option "colourA is at" [ "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"] 0; _baryArg = concat ["0,0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 0 = concat ["0,0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 1 = concat ["0,0,", colourA._flag, " %%[fx:w-1],0,", colourB._flag], position.value == 2 = concat ["0,0,", colourB._flag, " %%[fx:w-1],0,", colourA._flag], position.value == 3 = concat ["0,0,", colourA._flag, " %%[fx:w-1],%%[fx:h-1],", colourB._flag], position.value == 4 = concat ["%%[fx:w-1],0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 5 = concat ["%%[fx:w-1],0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 6 = concat ["0,0,", colourB._flag, " %%[fx:w-1],%%[fx:h-1],", colourA._flag], position.value == 7 = "dunno"; command = Magick.command [ "\"%s\"", "-sparse-color barycentric \"" ++ _baryArg ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradientCorn_item = class Menuaction "_Gradient corners" "apply a bilinear gradient between the corners" { action x = class _result { _vislevel = 3; colour_top_left = Magick.generalcol_widget; colour_top_right = Magick.generalcol_widget; colour_bottom_left = Magick.generalcol_widget; colour_bottom_right = Magick.generalcol_widget; command = Magick.command [ "\"%s\"", "-sparse-color bilinear \"" ++ "0,0," ++ colour_top_left._flag ++ ",%%[fx:w-1],0" ++ colour_top_right._flag ++ ",0,%%[fx:h-1]" ++ colour_bottom_left._flag ++ ",%%[fx:w-1],%%[fx:h-1]" ++ colour_bottom_right._flag ++ "\"", "+depth", "\"%s\"" ]; _result = Magick.system command x; } } Magick_histogram_item = class Menuaction "_Histogram" "make a histogram image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-define histogram:unique-colors=false histogram:" ++ "\"%s\"" ]; _result = Magick.system command x; } } Magick_implode_item = class Menuaction "_Implode" "implode pixels about the center" { action x = class _result { _vislevel = 3; factor = Scale "factor" 0 20 1; interpolate = Magick.interpolate_widget; // FIXME: virtual-pixel? command = Magick.command [ "\"%s\"", interpolate._flag, "-implode", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_level_item = class Menuaction "_Level" "adjust the level of channels" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "black point" (-100) 200 0; wht = Scale "white point" (-100) 200 100; gam = Scale "gamma" 0 30 1; isPc = Toggle "Levels are percent" true; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level", "\"" ++ print blk.value ++ "," ++ print wht.value ++ (if isPc then "%%" else "") ++ "," ++ print gam.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_levelCols_item = class Menuaction "_Level colors" "adjust levels to given colours" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; colour_black = Magick.generalcol_widget; colour_white = Magick.generalcol_widget; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level-colors", "\"" ++ colour_black._flag ++ "," ++ colour_white._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_linearStretch_item = class Menuaction "_Linear stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", channels._flag, "-linear-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_magnify_item = class Menuaction "_Magnify" "double the size of the image with pixel art scaling" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-magnify", "\"%s\"" ]; _result = Magick.system command x; } } Magick_modulate_item = class Menuaction "_Modulate" "modulate brightness, saturation and hue" { action x = class _result { _vislevel = 3; modcolsp = Magick.ModColSp_widget; bright = Scale "brightness" 0 200 100; sat = Scale "saturation" 0 200 100; hue = Scale "hue" 0 200 100; command = Magick.command [ "\"%s\"", modcolsp._flag, "-modulate", print bright.value ++ "," ++ print sat.value ++ "," ++ print hue.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_monochrome_item = class Menuaction "_Monochrome" "transform to black and white" { action x = class _result { _vislevel = 3; // FIXME: also intensity? intensity = Magick.intensity_widget; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; command = Magick.command [ "\"%s\"", intensity._flag, dither._flag, "-treedepth", print treedepth.expr, "-monochrome", "\"%s\"" ]; _result = Magick.system command x; } } Magick_morphology_item = class // See http://www.imagemagick.org/Usage/morphology/ Menuaction "_Morphology" "apply a morphological method" { action x = class _result { _vislevel = 3; method = Magick.morphmeth_widget; iter = Expression "Iterations (-1=repeat until done)" 1; kernel = Magick.kernel_widget; // FIXME: custom kernel eg "3x1+2+0:1,0,0" // width x height + offsx + offsy : {w*h values} // each value is 0.0 to 1.0 or "NaN" or "-" // kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0 // but // ring takes: radius1, radius2, scale // rectangle and comet take: width x height + offsx + offsy // blur takes: radius x sigma // FIXME: for now, simply allow any string input. kernel_arg = String "Kernel arguments" ""; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-morphology", method._flag ++ ":" ++ print iter.expr, kernel._flag ++ (if kernel_arg.value == "" then "" else ":") ++ kernel_arg.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_negate_item = class Menuaction "_Negate" "negate" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-negate", "\"%s\"" ]; _result = Magick.system command x; } } Magick_addNoise_item = class Menuaction "_add Noise" "add noise" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; attenuate = Scale "attenuate" 0 1.0 1.0; noise = Magick.noise_widget; command = Magick.command [ "\"%s\"", channels._flag, "-attenuate", print attenuate.value, noise._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_normalize_item = class Menuaction "_Normalize" "normalize" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-normalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_opaque_item = class Menuaction "_Opaque" "change this colour to the fill colour" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; fill = Magick.foreground_widget; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", fill._flag, channels._flag, "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "opaque", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_paint_item = class Menuaction "_Paint" "simulate an oil painting" { action x = class _result { _vislevel = 3; rad = Expression "radius" 10; command = Magick.command [ "\"%s\"", "-paint", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } /*=== FIXME Bug; remove for now. Polaroid_item = class Menuaction "_Polaroid" "simulate a polaroid picture" { action x = class _result { _vislevel = 3; angle = Scale "angle" (-90) 90 20; command = Magick.command [ "\"%s\"", "-polaroid", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_posterize_item = class Menuaction "_Posterize" "reduce to (n) levels per channel" { action x = class _result { _vislevel = 3; levels = Expression "levels" 3; command = Magick.command [ "\"%s\"", "-posterize", print levels.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_raise_item = class Menuaction "_Raise" "lighten or darken image edges" { action x = class _result { _vislevel = 3; thk = Expression "Thickness" 3; command = Magick.command [ "\"%s\"", "-raise", print thk.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_resize_item = class Menuaction "_Resize" "resize to given width and height" { action x = class _result { _vislevel = 3; filter = Magick.filter_widget; type = Magick.ResizeType_widget; width = Scale "Width" 1 100 10; height = Scale "Height" 1 100 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", filter._flag, "-" ++ type._flag, "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "!") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_roll_item = class Menuaction "_Roll" "roll an image horizontally or vertically" { action x = class _result { _vislevel = 3; rollx = Expression "X" 3; rolly = Expression "Y" 3; command = Magick.command [ "\"%s\"", "-roll", (if rollx.expr >= 0 then "+" else "") ++ print rollx.expr ++ (if rolly.expr >= 0 then "+" else "") ++ print rolly.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotate_item = class Menuaction "_Rotate" "rotate" { action x = class _result { _vislevel = 3; angle = Scale "angle (degrees)" (-360) 360 20; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, "+distort", "SRT", print angle.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -segment, but cluster-threshold should be percentage of image area. Magick_sepia_item = class Menuaction "_Sepia tone" "simulate a sepia-toned photo" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; command = Magick.command [ "\"%s\"", "-sepia-tone", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shade_item = class Menuaction "_Shade" "shade with a distant light source" { action x = class _result { _vislevel = 3; azimuth = Scale "Azimuth (degrees)" (-360) 360 0; elevation = Scale "Elevation (degrees)" 0 90 45; command = Magick.command [ "\"%s\"", "-shade", print azimuth.value ++ "x" ++ print elevation.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_shadow_item = class Menuaction "_Shadow" "simulate a shadow" { action x = class _result { _vislevel = 3; shadowCol = Magick.generalcol_widget; opacity = Scale "Opacity (percent)" 0 100 75; sigma = Scale "Sigma" 0 30 2; // FIXME: make offsets a single widget? offsx = Scale "X-offset" (-20) 20 4; offsy = Scale "Y-offset" (-20) 20 4; arePc = Toggle "offsets are percentages" false; // FIXME: raw operation creates page offset, which vips dislikes. // So we take this futher, compositing with source. command = Magick.command [ "\"%s\"", "\"(\" +clone", "-background", "\"" ++ shadowCol._flag ++ "\"", "-shadow", concat [ "\"", print opacity.value, "x", print sigma.value, (if offsx.value >= 0 then "+" else ""), print offsx.value, (if offsy.value >= 0 then "+" else ""), print offsy.value, (if arePc then "%%" else ""), "\"" ], "\")\" +swap -background None -layers merge", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shave_item = class Menuaction "_Shave" "shave pixels from the edges" { action x = class _result { _vislevel = 3; width = Scale "Width" 0 50 10; height = Scale "Height" 0 50 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", "-shave", "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shear_item = class Menuaction "_Shear" "shear along the x-axis and/or y-axis" { action x = class _result { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-shear", print shearX.expr ++ "x" ++ print shearY.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sigmoid_item = class Menuaction "_Sigmoid" "increase or decrease mid-tone contrast sigmoidally" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; contrast = Scale "contrast" 0 30 3; midpoint = Scale "mid-point (percent)" 0 100 50; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "sigmoidal-contrast", "\"" ++ print contrast.value ++ "x" ++ print midpoint.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_sketch_item = class Menuaction "_Sketch" "simulate a pencil sketch" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; command = Magick.command [ "\"%s\"", "-sketch", print radius.value ++ "x" ++ print sigma.value ++ (if angle >= 0 then ("+" ++ print angle.value) else ""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_solarize_item = class Menuaction "_Solarize" "negate all pixels above a threshold level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-solarize", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -sparse-color needs abitrary list of {x,y,colour}. Magick_splice_item = class Menuaction "_Splice" "splice a colour into the image" { action x = class _result { _vislevel = 3; background = Magick.background_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", background._flag, gravity._flag, "-splice", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_spread_item = class Menuaction "_Spread" "displace pixels by random amount" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; amount = Expression "Amount (pixels)" 5; command = Magick.command [ "\"%s\"", virtpixback._flag, "-spread", print amount.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_statistic_item = class Menuaction "_Statistic" "replace each pixel with statistic from neighbourhood" { action x = class _result { _vislevel = 3; width = Expression "Width" 5; height = Expression "Height" 5; statisticType = Magick.StatType_widget; command = Magick.command [ "\"%s\"", "-statistic", statisticType._flag, print width.expr ++ "x" ++ print height.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = Magick.angle_widget; command = Magick.command [ "\"%s\"", "-swirl", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_thresholdMenu_item = class Menupullright "_Threshold" "make black or white" { Magick_threshold_item = class Menuaction "_Threshold" "apply black/white threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blackThreshold_item = class Menuaction "_Black threshold" "where below threshold set to black" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-black-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_whiteThreshold_item = class Menuaction "_White threshold" "where above threshold set to white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-white-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_latThreshold_item = class Menuaction "_Local Adaptive Threshold" "where above average plus offset set to white, otherwise black" { action x = class _result { _vislevel = 3; width = Expression "Width" 10; height = Expression "Height" 10; offset = Scale "Offset (percent)" (-100) 100 0; // note: "-lat" doesn't respond to channels command = Magick.command [ "\"%s\"", "-lat", concat ["\"", print width.expr, "x", print height.expr, (if offset.value >= 0 then "+" else ""), print offset.value, "%%\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_randThreshold_item = class Menuaction "_Random Threshold" "between specified limits, apply random threshold" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; low = Scale "Low threshold" 0 100 10; high = Scale "High threshold" 0 100 90; isPc = Toggle "Thresholds are percent" true; command = Magick.command [ "\"%s\"", channels._flag, "-random-threshold", "\"" ++ print low.value ++ "x" ++ print high.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } } // end ThresholdMenu_item // Note: alternatives include: // convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif Magick_tile_item = class Menuaction "_Tile" "fill given size with tiled image" { action x = class _result { _vislevel = 3; size = Magick.Size_widget; command = Magick.command [ size._flag, "tile:" ++ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_tint_item = class Menuaction "_Tint" "apply a tint" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; amount = Scale "amount (percent)" 0 100 50; command = Magick.command [ "\"%s\"", foreground._flag, "-tint", // snibgo note: although the amount is a percentage, it doesn't need "%" character. print amount.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_transparent_item = class Menuaction "_Transparent" "make this colour transparent" { action x = class _result { _vislevel = 3; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "transparent", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_trim_item = class Menuaction "_Trim" "trims away border" { action x = class _result { _vislevel = 3; fuzz = Magick.fuzz_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-trim +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_uniqueCols_item = class Menuaction "_Unique colours" "discard all but one of any pixel color" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-unique-colors", "\"%s\"" ]; _result = Magick.system command x; } } Magick_vignette_item = class Menuaction "_Vignette" "soften the edges in vignette style" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; rx = Scale "Rolloff x (percent)" 0 100 10; ry = Scale "Rolloff y (percent)" 0 100 10; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-vignette", print radius.value ++ "x" ++ print sigma.value ++ (if rx.value >= 0 then "+" else "") ++ print rx.value ++ (if ry.value >= 0 then "+" else "") ++ print ry.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_wave_item = class Menuaction "_Wave" "shear the columns into a sine wave" { action x = class _result { _vislevel = 3; amplitude = Scale "Amplitude (pixels)" 0 100 10; wavelength = Scale "Wavelength (pixels)" 0 100 10; command = Magick.command [ "\"%s\"", "-wave", print amplitude.value ++ "x" ++ print wavelength.value, "\"%s\"" ]; _result = Magick.system command x; } } nip2-8.7.1/share/nip2/compat/8.6/Colour.def0000644000175000017500000004032613351443023015016 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } CCT_colour = class Menuaction (_ "Colour from CCT") (_ "pick colour by CCT") { action = widget 6500; widget x = class _result { _vislevel = 3; T = Scale "CCT" 1800 25000 x; _result = colour_from_temp (to_real T); Colour_edit space value = widget (temp_from_colour (Colour space value)); } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } scRGB_item = class Menuaction (_ "_scRGB") (_ "convert to scRGB colourspace") { action x = conv Image_type.scRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } scRGB_item = class Menuaction (_ "_scRGB") (_ "tag as being in scRGB colourspace") { action x = tag Image_type.scRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } sep1 = Menuseparator; CCT_item = class Menuaction (_ "Calculate temperature") (_ "estimate CCT using the McCamy approximation") { action z = map_unary temp_from_colour z; } Colour_item = Colour_new_item.CCT_colour; } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = print_profile, has_type image && get_type image == Image_type.CMYK && has_bands image && get_bands image >= 4 = monitor_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; measure = Scale (_ "Measure area (%)") 1 100 50; // get a representative image from an arg get_image x = get_image x.value?0, is_Group x = x; _im = get_image x; sample = measure_draw (to_real pacross) (to_real pdown) (to_real measure) _im; _result = map_unary chart x { chart in = measure_sample (to_real pacross) (to_real pdown) (to_real measure) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/8.6/_joe_utilities.def0000644000175000017500000005054213351443023016563 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/8.6/_Object.def0000644000175000017500000002600513351443023015116 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/8.6/Object.def0000644000175000017500000000220513351443023014753 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/8.6/Math.def0000644000175000017500000003162513351443023014446 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_AND" "bitwise AND of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_OR" "bitwise OR of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "_XOR" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_NOT" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Bandand_item = Image_band_item.Bandand_item; Bandor_item = Image_band_item.Bandor_item; } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Skew_item = class Menuaction "S_kew" "skew of image or list or vector" { action a = map_unary skew a; } Kurtosis_item = class Menuaction "Kurtosis" "kurtosis of image or list or vector" { action a = map_unary kurtosis a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/8.6/_generate.def0000644000175000017500000000755513351443023015513 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } mkim options x y b = Image (image_new x y b (opt $format) (opt $coding) (opt $type) (opt $pixel) (opt $xoffset) (opt $yoffset)) { opt = get_option options [ $format => Image_format.UCHAR, $coding => Image_coding.NOCODING, $type => Image_type.sRGB, $pixel => 0, $xoffset => 0, $yoffset => 0 ]; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } /* Make a colour from a temperature. */ colour_from_temp T = error (_ "T out of range"), T < 1667 || T > 25000 = Colour "Yxy" [50, x, y] { // Kim et all approximation // see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation x = -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 + 0.8776956 * 10 ** 3 / T + 0.179910, T < 4000 = -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 + 0.2226347 * 10 ** 3 / T + 0.240390; y = -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + 2.18555832 * x - 0.20219638, T < 2222 = -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867, T < 4000 = 3.0817580 * x ** 3 - 5.87338670 * x ** 2 + 3.75112997 * x - 0.37001483; } temp_from_colour z = T { c = colour_transform_to Image_type.YXY (to_colour z); x = c.value?1; y = c.value?2; // McCamy's approximation, see eg. // http://en.wikipedia.org/wiki/Color_temperature#Approximation xe = 0.332; ye = 0.1858; n = (x - xe) / (y - ye); T = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33; } nip2-8.7.1/share/nip2/compat/8.6/_stdenv.def0000644000175000017500000020305613351443023015216 00000000000000/* optional args to functions */ get_option options defaults f = error (_ "unknown parameter " ++ f), hits == [] = hits?0 { hits = [v :: [n, v] <- options ++ defaults; n == f]; } /* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } bandand x = oo_unary_function bandand_op x, is_class x = foldr1 bitwise_and (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandand") { bandand_op = Operator "bandand" bandand Operator_type.COMPOUND_REWRAP false; } bandor x = oo_unary_function bandor_op x, is_class x = foldr1 bitwise_or (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandor") { bandor_op = Operator "bandor" bandor Operator_type.COMPOUND_REWRAP false; } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } skew x = oo_unary_function skew_op x, is_class x = sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x = sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "skew") { skew_op = Operator "skew" skew Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = w * h * b, is_image x' = len x'; } kurtosis x = oo_unary_function kurtosis_op x, is_class x = sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x = sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "kurtosis") { kurtosis_op = Operator "kurtosis" kurtosis Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = len x', is_list x'; = w * h * b; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_tile_cache_random x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } decode im = oo_unary_function decode_op im, is_class im = decode_im im, is_image im = error (_ "bad arguments to " ++ "decode") { decode_op = Operator "decode" decode Operator_type.COMPOUND_REWRAP false; decode_im im = im_LabQ2Lab im, get_coding im == Image_coding.LABPACK = im_rad2float im, get_coding im == Image_coding.RAD = im; } measure_draw across down measure image = mark { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; x = map (extract 0) cods; y = map (extract 1) cods; outer = mkim [$pixel => 255] sample_width sample_height 1; inner = mkim [] (sample_width - 4) (sample_height - 4) 1; patch = insert 2 2 inner outer; bg = mkim [] image.width image.height 1; mask = Image (im_insertset bg.value patch.value x y); image' = colour_transform_to Image_type.sRGB image; mark = if mask then Vector [0, 255, 0] else image'; } measure_sample across down measure image = measures { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; image' = decode image; patches = map (\p extract_area p?0 p?1 sample_width sample_height image') cods; measures = Matrix (map (map mean) (map bandsplit patches)); } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed mode index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) (hist_find_indexed mode)) Operator_type.COMPOUND false; indexed index value = out { [out] = vips_call "hist_find_indexed" [value, index] [ "combine" => mode ]; } } hist_entropy x = oo_unary_function hist_entropy_op x, is_class x = entropy x, is_image x = error (_ "bad arguments to " ++ "hist_entropy") { hist_entropy_op = Operator "hist_entropy" hist_entropy Operator_type.COMPOUND_REWRAP false; entropy x = out { [out] = vips_call "hist_entropy" [x] [ ]; } } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_inv hist = oo_unary_function hist_inv_op hist, is_class hist = inv hist, is_image hist = error (_ "bad arguments to " ++ "hist_inv") { hist_inv_op = Operator "hist_inv" hist_inv Operator_type.COMPOUND_REWRAP false; inv im = im_invertlut (to_matrix im''') len { // need a vertical doublemask im' = rot90 im, get_width im > 1 && get_height im == 1 = im, get_width im == 1 && get_height im > 1 = error (_ "not a hist"); len = get_height im'; // values must be scaled to 0 - 1 im'' = im' / (max im'); // add an index column on the left // again, must be in 0-1 y = ((make_xy 1 len)?1) / len; im''' = y ++ im''; } } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h l image = oo_unary_function hist_equalize_local_op image, is_class image = out, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h l) Operator_type.COMPOUND_REWRAP false; [out] = vips_call "hist_local" [image, to_real w, to_real h] [$max_slope => to_real l]; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } reduce kernel xshr yshr image = oo_unary_function reduce_op image, is_class image = reduce_im image, is_image image = error (_ "bad arguments to " ++ "reduce") { reduce_op = Operator "reduce" reduce_im Operator_type.COMPOUND_REWRAP false; reduce_im im = out { [out] = vips_call "reduce" [im, xshr, yshr] [$kernel => kernel.value]; } } similarity interpolate scale angle image = oo_unary_function similarity_op image, is_class image = similarity_im image, is_image image = error (_ "bad arguments to " ++ "similarity") { similarity_op = Operator "similarity" similarity_im Operator_type.COMPOUND_REWRAP false; similarity_im im = out { [out] = vips_call "similarity" [im] [ $interpolate => interpolate.value, $scale => scale, $angle => angle ]; } } resize kernel xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; is_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn // everything else ... we just pass on to vips_resize() = vips_resize kernel xfac' yfac' im { vips_resize kernel hscale vscale im = out { [out] = vips_call "resize" [im, hscale] [$vscale => vscale, $kernel => kernel.value]; } } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C * * Also calculate R2, see eg.: * https://en.wikipedia.org/wiki/Coefficient_of_determination */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } ss = len xes; sx = sum xes; sy = sum yes; my = sy / ss; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; my = sy / len xes; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* One image in, one out. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } /* Two images in, one out. */ system_image2 command x1 x2 = oo_binary_function system_image2_op x1 x2, is_class x1 = oo_binary'_function system_image2_op x1 x2, is_class x2 = system x1 x2, is_image x1 && is_image x2 = error (_ "bad arguments to " ++ "system_image2") { system_image2_op = Operator "system_image2" (system_image2 command) Operator_type.COMPOUND_REWRAP false; system x1 x2 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Three images in, one out. */ system_image3 command x1 x2 x3 = oo_binary_function system_image2_op x2 x3, is_class x2 = oo_binary'_function system_image2_op x2 x3, is_class x3 = system x1 x2 x3, is_image x1 && is_image x2 && is_image x3 = error (_ "bad arguments to " ++ "system_image3") { system_image2_op = Operator "system_image2" (system_image3 command x1) Operator_type.COMPOUND_REWRAP false; system x1 x2 x3 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2, x3], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Zero images in, one out. */ system_image0 command = Image image_out { [image_out] = vips_call "system" [command] [ $out => true, $out_format => "%s.tif" ]; } hough_line w h x = oo_unary_function hough_line_op x, is_class x = hline (to_real w) (to_real h) x, is_image x = error (_ "bad arguments to " ++ "hough_line") { hough_line_op = Operator "hough_line" (hough_line w h) Operator_type.COMPOUND_REWRAP false; hline w h x = pspace { [pspace] = vips_call "hough_line" [x] [ $width => w, $height => h ]; } } hough_circle s mn mx x = oo_unary_function hough_circle_op x, is_class x = hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x = error (_ "bad arguments to " ++ "hough_circle") { hough_circle_op = Operator "hough_circle" (hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false; hcircle s mn mx x = pspace { [pspace] = vips_call "hough_circle" [x] [ $scale => s, $min_radius => mn, $max_radius => mx ]; } } mapim interp ind in = oo_binary_function mapim_op ind in, is_class ind = oo_binary'_function mapim_op ind in, is_class in = mapim_fn ind in, is_image ind && is_image in = error (_ "bad arguments to " ++ "mapim") { mapim_op = Operator "mapim" (mapim interp) Operator_type.COMPOUND_REWRAP false; mapim_fn ind im = out { [out] = vips_call "mapim" [im, ind] [$interpolate => interp]; } } perlin cell width height = Image im { [im] = vips_call "perlin" [to_real width, to_real height] [ $cell_size => to_real cell ]; } worley cell width height = Image im { [im] = vips_call "worley" [to_real width, to_real height] [ $cell_size => to_real cell ]; } gaussnoise width height mean sigma = im { [im] = vips_call "gaussnoise" [to_real width, to_real height] [ $mean => to_real mean, $sigma => to_real sigma ]; } flattenimage bg x = oo_unary_function flatten_op x, is_class x = flt (to_vector bg) x, is_image x = error (_ "bad arguments to " ++ "flattenimage") { flatten_op = Operator "flatten" (flattenimage bg) Operator_type.COMPOUND_REWRAP false; flt bg x = out { [out] = vips_call "flatten" [x] [ $background => bg.value ]; } } premultiply x = oo_unary_function premultiply_op x, is_class x = prem x, is_image x = error (_ "bad arguments to " ++ "premultiply") { premultiply_op = Operator "premultiply" premultiply Operator_type.COMPOUND_REWRAP false; prem x = out { [out] = vips_call "premultiply" [x] [ ]; } } unpremultiply x = oo_unary_function unpremultiply_op x, is_class x = unprem x, is_image x = error (_ "bad arguments to " ++ "unpremultiply") { unpremultiply_op = Operator "unpremultiply" unpremultiply Operator_type.COMPOUND_REWRAP false; unprem x = out { [out] = vips_call "unpremultiply" [x] [ ]; } } hist_entropy x = oo_unary_function hist_entropy_op x, is_class x = entropy x, is_image x = error (_ "bad arguments to " ++ "hist_entropy") { hist_entropy_op = Operator "hist_entropy" hist_entropy Operator_type.COMPOUND_REWRAP false; entropy x = out { [out] = vips_call "hist_entropy" [x] [ ]; } } nip2-8.7.1/share/nip2/compat/8.6/Histogram.def0000644000175000017500000001656713351443023015522 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "_Identity" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = class _result { _vislevel = 3; combine = Combine_picker Combine_type.SUM; _result = map_binary map x y { map a b = hist_find_indexed combine.value index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_inv_item = class Menuaction "In_vert" "invert a histogram" { action x = map_unary hist_inv x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } Hist_entropy_item = class Menuaction "Entropy" "calculate histogram entropy" { action x = hist_entropy x; } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Kernel_linear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; caption = Expression "Chart caption" "none"; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; xcaption = Expression "X axis caption" "none"; ycaption = Expression "Y axis caption" "none"; series_captions = Expression "Series captions" ["Band 0"]; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range ++ captions; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; captions = concat (map test caption_options) ++ [$series_captions => series_captions.expr] { caption_options = [ $caption => caption.expr, $xcaption => xcaption.expr, $ycaption => ycaption.expr ]; test x = [], value == "none" = [option_name => value] { [option_name, value] = x; } } image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/8.6/Widgets.def0000644000175000017500000000235313351443023015157 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/8.6/_types.def0000644000175000017500000007526713351443023015072 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; scRGB = 28; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY, $scRGB => scRGB ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options are generated from this, so match the order to the order in * the Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $scRGB => scRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $scRGB => scRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Kernel_type = class { NEAREST_NEIGHBOUR = 0; LINEAR = 1; CUBIC = 2; LANCZOS2 = 3; LANCZOS3 = 4; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map kernel numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Linear", _ "Cubic", _ "Lanczos, two lobes", _ "Lanczos, three lobes" ]; /* And to vips enum nicknames. */ types = [ "nearest", "linear", "cubic", "lanczos2", "lanczos3" ]; } Kernel type = class { value = Kernel_type.types?type; } Kernel_linear = Kernel Kernel_type.LINEAR; Kernel_picker default = class Kernel kernel.value { _vislevel = 2; kernel = Option "Kernel" Kernel_type.descriptions default; } Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; to_image dpi = extract_bands 0 3 (graph_export_image (to_real dpi) this); } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } Blend_type = class { CLEAR = 0; SOURCE = 1; OVER = 2; IN = 3; OUT = 4; ATOP = 5; DEST = 6; DEST_OVER = 7; DEST_IN = 8; DEST_OUT = 9; DEST_ATOP = 10; XOR = 11; ADD = 12; SATURATE = 13; MULTIPLY = 14; SCREEN = 15; OVERLAY = 16; DARKEN = 17; LIGHTEN = 18; COLOUR_DODGE = 19; COLOUR_BURN = 20; HARD_LIGHT = 21; SOFT_LIGHT = 22; DIFFERENCE = 23; EXCLUSION = 24; /* Table to map blend numbers to descriptive strings */ descriptions = [ _ "Clear", _ "Source", _ "Over", _ "In", _ "Out", _ "Atop", _ "Dest", _ "Dest over", _ "Dest in", _ "Dest out", _ "Dest atop", _ "Xor", _ "Add", _ "Saturate", _ "Multiply", _ "Screen", _ "Overlay", _ "Darken", _ "Lighten", _ "Colour dodge", _ "Colour burn", _ "Hard light", _ "Soft light", _ "Difference", _ "Exclusion" ]; /* And to vips enum nicknames. */ types = Enum [ $clear => "clear", $source => "source", $over => "over", $in => "in", $out => "out", $atop => "atop", $dest => "dest", $dest_over => "dest_over", $dest_in => "dest_in", $dest_out => "dest_out", $dest_atop => "dest_atop", $xor => "xor", $add => "add", $saturate => "saturate", $multiply => "multiply", $screen => "screen", $overlay => "overlay", $darken => "darken", $lighten => "lighten", $colour_dodge => "colour_dodge", $colour_burn => "colour_burn", $hard_light => "hard_light", $soft_light => "soft_light", $difference => "difference", $exclusion => "exclusion" ]; } Blend type = class { value = Blend_type.types?type; } Blend_over = Blend Blend_type.OVER; Blend_picker default = class Blend blend.value { _vislevel = 2; blend = Option "Blend" Blend_type.descriptions default; } Combine_type = class { MAX = 0; SUM = 1; MIN = 2; enum = Enum [ _ "Maximum" => MAX, _ "Sum" => SUM, _ "Minimum" => MIN ]; } Combine type = class { value = Combine_type.enum.names?type; } Combine_sum = Combine Combine_type.SUM; Combine_picker default = Option "Combine" Combine_type.enum.names default; nip2-8.7.1/share/nip2/compat/8.6/Matrix.def0000644000175000017500000002573113351443023015022 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = identity (identity_matrix 5); identity v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix (identity_matrix (to_real s)), to_real s != len v; = Matrix v; Matrix_vips value scale offset filename display = identity value; } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = series (mkseries 0 1 5); mkseries s t e = transpose [[to_real s, to_real s + to_real t .. to_real e]]; series v = class _result { _vislevel = 3; _s = v?0?0; _t = v?1?0 - v?0?0; _e = (last v)?0; s = Expression "Start value" _s; t = Expression "Step by" _t; e = Expression "End value" _e; _result = Matrix (mkseries s t e), to_real s != _s || to_real t != _t || to_real e != _e = Matrix v; Matrix_vips value scale offset filename display = series value; } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = square (mksquare 5); mksquare s = replicate s (take s [1, 1 ..]); square v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix_con (sum v) 0 v, len v == to_real s = Matrix_con (sum m) 0 m { m = mksquare (to_real s); } Matrix_vips value scale offset filename display = square value; } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = circle (mkcircle 3); mkcircle r = map2 (map2 pyth) xes yes { line = [-r .. r]; xes = replicate (2 * r + 1) line; yes = transpose xes; pyth a b = 1, (a**2 + b**2) ** 0.5 <= r = 0; } circle v = class _result { _vislevel = 3; r = Expression "Radius" ((len v - 1) / 2); _result = Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1 = Matrix_con (sum m) 0 m { m = mkcircle (to_real r); } Matrix_vips value scale offset filename display = circle value; } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/8.6/Tasks.def0000644000175000017500000006407313351443023014645 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; measure = Scale (_ "Measure area (%)") 1 100 50; sample = measure_draw 6 4 (to_real measure) image; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linearize from chart greyscale", "Fit intercept from chart greyscale", "Linear input, set brightness from chart", "Linear input" ] 0; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure_sample 6 4 (to_real measure) image; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix [[0, 0], [1, 1]] { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map an image though the lineariser linear x = hist_map linearising_lut.value x, mode == 0 || mode == 1 = x; // map the chart measurements though the lineariser _camera' = (to_matrix @ linear @ to_image) _camera; // solve for RGB -> XYZ // normalise: the 2nd row is what makes Y, so divide by that to // get Y in 0-1. _pinv = (transpose _camera' * _camera') ** -1; _full_M = transpose (_pinv * (transpose _camera' * _true_XYZ)); M = _full_M / scale; scale = sum _full_M.value?1; // now turn the camera to LAB and calculate dE76 _camera'' = (to_matrix @ colour_transform Image_type.XYZ Image_type.LAB @ recomb M @ multiply scale @ to_image) _camera'; _dEs = map abs_vec (_camera'' - _true_Lab).value; avg_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } // normalise brightness ... in linear mode, we optionally don't // set the brightness from the Macbeth chart norm x = x * scale, mode != 3 = x; // convert RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ norm @ recomb M @ cast_float @ linear) image.value; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ calib.norm @ recomb calib.M @ cast_float @ calib.linear) image.value; } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Kernel_linear xfactor yfactor scale_im; _offset_im = resize Kernel_linear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/8.6/Makefile.am0000644000175000017500000000057713351443023015133 00000000000000startdir = $(pkgdatadir)/compat/8.6 start_DATA = \ Colour.def \ _convert.def \ Filter.def \ _generate.def \ Histogram.def \ Image.def \ _joe_extra.def \ _joe_utilities.def \ _list.def \ _magick.def \ Magick.def \ Math.def \ Matrix.def \ _Object.def \ Object.def \ _predicate.def \ _stdenv.def \ Tasks.def \ _types.def \ Widgets.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/8.6/Makefile.in0000644000175000017500000003712213417043242015142 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/8.6 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/8.6 start_DATA = \ Colour.def \ _convert.def \ Filter.def \ _generate.def \ Histogram.def \ Image.def \ _joe_extra.def \ _joe_utilities.def \ _list.def \ _magick.def \ Magick.def \ Math.def \ Matrix.def \ _Object.def \ Object.def \ _predicate.def \ _stdenv.def \ Tasks.def \ _types.def \ Widgets.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/8.6/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/8.6/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/8.6/_magick.def0000644000175000017500000005322113351443023015143 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate _magick.def Add 0-ary and 2-ary system Put utility funcs into a Magick class 11-Apr-2014 snibgo Added VirtualPixelBack for cases where background is only relevant when VP=Background 17-Apr-2014 snibgo Many small changes. 2-May-2014 jcupitt Added Magick.version 30-June-2014 Put single-quotes around command exe to help win 1-July-2014 Automatically fall back to gm if we can't find convert 17-July-2014 better GM support Last update: 17-July-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ /* Put these in a class to avoid filling the main namespace with IM stuff. */ Magick = class { // first gm on path, or "" gm_path = search_for "gm"; // first convert on $PATH, or "" // we check for the convert we ship first convert_path = vips_convert, vips_convert != "" = search_for "convert" { // the convert we ship with the vips binary on some platforms, or "" vips_convert = search (path_absolute convert) { vipshome = path_parse (expand "$VIPSHOME"); convert = vipshome ++ ["bin", "convert" ++ expand "$EXEEXT"]; } } use_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK; // Are we in GM or IM mode? use_gm = true, use_gm_pref && gm_path != "" = false, !use_gm_pref && convert_path != "" = false, convert_path != "" = true, gm_path != "" = error "neither IM nor GM executable found"; command_path = gm_path, use_gm = convert_path; // try to get the version as eg. [6, 7, 7, 10] // GM versions are smaller, typically [1, 3, 18] version = map parse_int (split (member ".-") version_string) { [output] = vips_call "system" ["'" ++ command_path ++ "' -version"] [$log=>true]; version_string = (split (equal ' ') output)?1, use_gm = (split (equal ' ') output)?2; } // make a command-line ... args is a [str] we join with spaces command args = "'" ++ command_path ++ "' " ++ join_sep " " args' { args' = ["convert"] ++ args, use_gm = args; } // capabilities ... different versions support different features, we // turn features on and off based on these // would probably be better to test for caps somehow has_intensity = false, use_gm = version?0 > 6 || version?1 > 7; has_channel = false, use_gm = version?0 > 6 || version?1 > 7; system0 cmd = system_image0 cmd; system cmd x = map_unary (system_image cmd) x; system2 cmd x y = map_binary (system_image2 cmd) x y; system3 cmd x y z = map_trinary (system_image3 cmd) x y z; radius_widget = Scale "Radius" 0 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle (degrees)" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; gamma_widget = Scale "Gamma" 0 10 1; colors_widget = Scale "Colors" 1 10 3; resize_widget = Scale "Resize (percent)" 0 500 100; fuzz_widget = Scale "Fuzz (percent)" 0 100 0; blur_rad_widget = Scale "Radius (0=auto)" 0 100 0; // a colour with no enclosing quotes ... use this if we know there are // some quotes at an outer level print_colour_nq triple = concat ["#", concat (map fmt triple)] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } // we need the quotes because # is the comment character in *nix print_colour triple = "\"" ++ print_colour_nq triple ++ "\""; Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; GeneralCol triple = class Colour "sRGB" triple { _flag = print_colour_nq triple; Colour_edit space triple = this.GeneralCol triple; } generalcol_widget = GeneralCol [0, 0, 0]; Background triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" false; _flag = "-background " ++ if isNone then "None" else print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Bordercol triple = class Colour "sRGB" triple { _flag = "-bordercolor " ++ print_colour triple; Colour_edit space triple = this.Bordercol triple; } bordercol_widget = Bordercol [0, 0, 0]; Mattecol triple = class Colour "sRGB" triple { _flag = "-mattecolor " ++ print_colour triple; Colour_edit space triple = this.Mattecol triple; } mattecol_widget = Mattecol [189, 189, 189]; // FIXME: Undercolour, like many others, can have alpha channel. // How does user input this? With a slider? Undercol triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" true; _flag = if isNone then "" else ("-undercolor " ++ print_colour triple); Colour_edit space triple = this.Undercol triple; } undercol_widget = Undercol [0, 0, 0]; changeCol_widget = class { _vislevel = 3; colour = GeneralCol [0, 0, 0]; fuzz = fuzz_widget; nonMatch = Toggle "change non-matching colours" false; } Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Remove", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Builtin builtin = class Option_string "Builtin" [ // See http://www.imagemagick.org/script/formats.php "rose:", "logo:", "wizard:", "granite:", "netscape:" ] builtin { _flag = builtin; Option_edit caption labels value = this.Builtin labels?value; } builtin_widget = Builtin "rose:"; channels_widget = class { // FIXME? Can we grey-out alpha when we have no alpha channel, // show CMY(K) instead of RGB(K) etc? // Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA. ChanR valueR = class Toggle "Red" valueR { _flag = "R", valueR = ""; Toggle_edit caption valueR = this.ChanR valueR; } channelR = ChanR true; ChanG valueG = class Toggle "Green" valueG { _flag = "G", valueG = ""; Toggle_edit caption valueG = this.ChanG valueG; } channelG = ChanG true; ChanB valueB = class Toggle "Blue" valueB { _flag = "B", valueB = ""; Toggle_edit caption valueB = this.ChanB valueB; } channelB = ChanB true; ChanK valueK = class Toggle "Black" valueK { _flag = "K", valueK = ""; Toggle_edit caption valueK = this.ChanK valueK; } channelK = ChanK true; ChanA valueA = class Toggle "Alpha" valueA { _flag = "A", valueA = ""; Toggle_edit caption valueA = this.ChanA valueA; } channelA = ChanA false; ChanSy valueSy = class Toggle "Sync" valueSy { _flag = ",sync", valueSy = ""; Toggle_edit caption valueSy = this.ChanSy valueSy; } channelSy = ChanSy true; _rgbka = concat [channelR._flag, channelG._flag, channelB._flag, channelK._flag, channelA._flag ]; _flag = "", _rgbka == "" || !has_channel = concat [ "-channel ", _rgbka, channelSy._flag ]; } ch_widget = channels_widget; Colorspace colsp = class Option_string "Colorspace" [ "CIELab", "CMY", "CMYK", "Gray", "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "Lab", "LCH", "LCHab", "LCHuv", "LMS", "Log", "Luv", "OHTA", "Rec601Luma", "Rec601YCbCr", "Rec709Luma", "Rec709YCbCr", "RGB", "scRGB", "sRGB", "Transparent", "XYZ", "YCbCr", "YDbDr", "YCC", "YIQ", "YPbPr", "YUV" ] colsp { _flag = colsp; Option_edit caption labels value = this.Colorspace labels?value; } colorspace_widget = Colorspace "sRGB"; Compose comp = class Option_string "Compose method" [ "Atop", "Blend", "Blur", "Bumpmap", "ChangeMask", "Clear", "ColorBurn", "ColorDodge", "Colorize", "CopyBlack", "CopyBlue", "CopyCyan", "CopyGreen", "Copy", "CopyMagenta", "CopyOpacity", "CopyRed", "CopyYellow", "Darken", "DarkenIntensity", "DivideDst", "DivideSrc", "Dst", "Difference", "Displace", "Dissolve", "Distort", "DstAtop", "DstIn", "DstOut", "DstOver", "Exclusion", "HardLight", "Hue", "In", "Lighten", "LightenIntensity", "LinearBurn", "LinearDodge", "LinearLight", "Luminize", "Mathematics", "MinusDst", "MinusSrc", "Modulate", "ModulusAdd", "ModulusSubtract", "Multiply", "None", "Out", "Overlay", "Over", "PegtopLight", "PinLight", "Plus", "Replace", "Saturate", "Screen", "SoftLight", "Src", "SrcAtop", "SrcIn", "SrcOut", "SrcOver", "VividLight", "Xor" ] comp { _flag = "-compose " ++ comp; Option_edit caption labels value = this.Compose labels?value; } compose_widget = Compose "Over"; // FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string. // FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack coordinate_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; _flag = concat [print x.expr, ",", print y.expr]; }; Distort distort = class Option_string "Distort" [ "Affine", "AffineProjection", "ScaleRotateTranslate", "SRT", "Perspective", "PerspectiveProjection", "BilinearForward", "BilinearReverse", "Polynomial", "Arc", "Polar", "DePolar", "Barrel", "BarrelInverse", "Shepards", "Resize" ] distort { _flag = distort; Option_edit caption labels value = this.Distort labels?value; } distort_widget = Distort "SRT"; Dither dither = class Option_string "Dither" [ "None", "FloydSteinberg", "Riemersma" ] dither { _flag = "-dither " ++ dither; Option_edit caption labels value = this.Dither labels?value; } dither_widget = Dither "FloydSteinberg"; Evaluate eval = class Option_string "Evaluate operation" [ "Abs", "Add", "AddModulus", "And", "Cos", "Cosine", "Divide", "Exp", "Exponential", "GaussianNoise", "ImpulseNoise", "LaplacianNoise", "LeftShift", "Log", "Max", "Mean", "Median", "Min", "MultiplicativeNoise", "Multiply", "Or", "PoissonNoise", "Pow", "RightShift", "Set", "Sin", "Sine", "Subtract", "Sum", "Threshold", "ThresholdBlack", "ThresholdWhite", "UniformNoise", "Xor" ] eval { _flag = "-evaluate " ++ eval; Option_edit caption labels value = this.Evaluate labels?value; } evaluate_widget = Evaluate "Add"; Filter filt = class Option_string "Filter" [ "default", "Bartlett", "Blackman", "Bohman", "Box", "Catrom", "Cosine", "Cubic", "Gaussian", "Hamming", "Hann", "Hermite", "Jinc", "Kaiser", "Lagrange", "Lanczos", "Lanczos2", "Lanczos2Sharp", "LanczosRadius", "LanczosSharp", "Mitchell", "Parzen", "Point", "Quadratic", "Robidoux", "RobidouxSharp", "Sinc", "SincFast", "Spline", "Triangle", "Welch" ] filt { _flag = if filt == "default" then "" else "-filter " ++ filt; Option_edit caption labels value = this.Filter labels?value; } filter_widget = Filter "default"; Function func = class Option_string "Function" [ "Polynomial", "Sinusoid", "Arcsin", "Arctan" ] func { _flag = func; Option_edit caption labels value = this.Function labels?value; } function_widget = Function "Polynomial"; // "Polynomial (a[n], a[n-1], ... a[1], a[0])", // "Sinusoid (freq, phase, amp, bias)", // "Arcsin (width, centre, range, bias)", // "Arctan (slope, centre, range, bias)" Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; ImageType imagetype = class Option_string "Image type" [ "Bilevel", "ColorSeparation", "ColorSeparationAlpha", "ColorSeparationMatte", "Grayscale", "GrayscaleAlpha", "GrayscaleMatte", "Optimize", "Palette", "PaletteBilevelAlpha", "PaletteBilevelMatte", "PaletteAlpha", "PaletteMatte", "TrueColorAlpha", "TrueColorMatte", "TrueColor" ] imagetype { _flag = "-type " ++ imagetype; Option_edit caption labels value = this.ImageType labels?value; } imagetype_widget = ImageType "TrueColor"; Intensity intensity = class Option_string "Intensity (gray conversion)" [ "Average", "Brightness", "Lightness", "MS", "Rec601Luma", "Rec601Luminance", "Rec709Luma", "Rec709Luminance", "RMS" ] intensity { _flag = "-intensity " ++ intensity, has_intensity = ""; Option_edit caption labels value = this.Intensity labels?value; } intensity_widget = Intensity "Rec709Luminance"; Interpolate interp = class Option_string "Interpolate" [ "default", "Average", "Average4", "Average9", "Average16", "Background", "Bilinear", "Blend", "Integer", "Mesh", "Nearest", "NearestNeighbor", "Spline" ] interp { _flag = if interp == "default" then "" else "-interpolate " ++ interp; Option_edit caption labels value = this.Interpolate labels?value; } interpolate_widget = Interpolate "default"; Kernel kernel = class Option_string "Kernel" [ "Unity", "Gaussian", "DoG", "LoG", "Blur", "Comet", "Binomial", "Laplacian", "Sobel", "FreiChen", "Roberts", "Prewitt", "Compass", "Kirsch", "Diamond", "Square", "Rectangle", "Disk", "Octagon", "Plus", "Cross", "Ring", "Peaks", "Edges", "Corners", "Diagonals", "LineEnds", "LineJunctions", "Ridges", "ConvexHull", "ThinSe", "Skeleton", "Chebyshev", "Manhattan", "Octagonal", "Euclidean" // FIXME: custom kernel ] kernel { _flag = kernel; Option_edit caption labels value = this.Kernel labels?value; } kernel_widget = Kernel "Unity"; ModColSp msp = class Option_string "modulate colorspace" [ "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "LCH" ] msp { _flag = "-set option:modulate:colorspace " ++ msp; Option_edit caption labels value = this.ModColSp labels?value; } ModColSp_widget = ModColSp "HSL"; MorphMeth morph = class Option_string "Method" [ "Correlate", "Convolve", "Dilate", "Erode", "Close", "Open", "DilateIntensity", "ErodeIntensity", "CloseIntensity", "OpenIntensity", "Smooth", "EdgeOut", "EdgeIn", "Edge", "TopHat", "BottomHat", "HitAndMiss", "Thinning", "Thicken", "Distance", "IterativeDistance" ] morph { _flag = morph; Option_edit caption labels value = this.MorphMeth labels?value; } morphmeth_widget = MorphMeth "Dilate"; Noise noise = class Option_string "Noise" [ "Gaussian", "Impulse", "Laplacian", "Multiplicative", "Poisson", "Random", "Uniform" ] noise { _flag = "+noise " ++ noise; Option_edit caption labels value = this.Noise labels?value; } noise_widget = Noise "Gaussian"; Pattern pattern = class Option_string "Noise" [ // See http://www.imagemagick.org/script/formats.php "bricks", "checkerboard", "circles", "crosshatch", "crosshatch30", "crosshatch45", "gray0", "gray5", "gray10", "gray15", "gray20", "gray25", "gray30", "gray35", "gray40", "gray45", "gray50", "gray55", "gray60", "gray65", "gray70", "gray75", "gray80", "gray85", "gray90", "gray95", "gray100", "hexagons", "horizontal", "horizontal2", "horizontal3", "horizontalsaw", "hs_bdiagonal", "hs_cross", "hs_diagcross", "hs_fdiagonal", "hs_horizontal", "hs_vertical", "left30", "left45", "leftshingle", "octagons", "right30", "right45", "rightshingle", "smallfishscales", "vertical", "vertical2", "vertical3", "verticalbricks", "verticalleftshingle", "verticalrightshingle", "verticalsaw" ] pattern { _flag = "pattern:" ++ pattern; Option_edit caption labels value = this.Pattern labels?value; } pattern_widget = Pattern "bricks"; ResizeType resizet = class Option_string "Resize type" [ "resize", "scale", "sample", "adaptive-resize" ] resizet { _flag = resizet; Option_edit caption labels value = this.ResizeType labels?value; } ResizeType_widget = ResizeType "resize"; Size_widget = class { _vislevel = 3; width = Expression "Width (pixels)" 64; height = Expression "Height (pixels)" 64; _flag = "-size " ++ print width.expr ++ "x" ++ print height.expr; }; StatType statt = class Option_string "Statistic type" [ "Gradient", "Maximum", "Mean", "Median", "Minimum", "Mode", "Nonpeak", "StandardDeviation" ] statt { _flag = statt; Option_edit caption labels value = this.StatType labels?value; } StatType_widget = StatType "Mean"; VirtualPixel vp = class Option_string "Virtual pixel" [ "Background", "Black", "CheckerTile", "Dither", "Edge", "Gray", "HorizontalTile", "HorizontalTileEdge", "Mirror", "None", "Random", "Tile", "Transparent", "VerticalTile", "VerticalTileEdge", "White" ] vp { _flag = "-virtual-pixel " ++ vp; _isBackground = (vp == "Background"); Option_edit caption labels value = this.VirtualPixel labels?value; } VirtualPixel_widget = VirtualPixel "Edge"; VirtualPixelBack_widget = class { virtpix = Magick.VirtualPixel_widget; background = Magick.background_widget; _flag = (if virtpix._isBackground then (background._flag ++ " ") else "") ++ virtpix._flag; } Geometry_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; AnnotGeometry_widget = class { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print shearX.expr, "x", print shearY.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; OffsetGeometry_widget = class { _vislevel = 3; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; WhxyGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; FrameGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; outbev = Expression "Outer bevel thickness" 0; inbev = Expression "Inner bevel thickness" 0; _flag = concat [print x.expr, "x", print y.expr, format outbev, format inbev] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } } nip2-8.7.1/share/nip2/compat/8.6/_predicate.def0000644000175000017500000003263513351443023015656 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Plot x = is_instanceof "Plot" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = oo_unary_function get_type_op x, is_class x = error (_ "bad arguments to " ++ "get_type") { get_type_op = Operator "get_type" get_type Operator_type.COMPOUND false; // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.scRGB, coding == Image_coding.RAD = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.scRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = oo_unary_function get_format_op x, is_class x = error (_ "bad arguments to " ++ "get_format") { get_format_op = Operator "get_format" get_format Operator_type.COMPOUND false; } has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = oo_unary_function get_bits_op x, is_class x = error (_ "bad arguments to " ++ "get_bits") { get_bits_op = Operator "get_bits" get_format Operator_type.COMPOUND false; } has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = oo_unary_function get_bands_op x, is_class x = error (_ "bad arguments to " ++ "get_bands") { get_bands_op = Operator "get_bands" get_bands Operator_type.COMPOUND false; } has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = oo_unary_function get_coding_op x, is_class x = error (_ "bad arguments to " ++ "get_coding") { get_coding_op = Operator "get_coding" get_coding Operator_type.COMPOUND false; } has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = oo_unary_function get_xres_op x, is_class x = error (_ "bad arguments to " ++ "get_xres") { get_xres_op = Operator "get_xres" get_xres Operator_type.COMPOUND false; } has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = oo_unary_function get_yres_op x, is_class x = error (_ "bad arguments to " ++ "get_yres") { get_yres_op = Operator "get_yres" get_yres Operator_type.COMPOUND false; } has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = oo_unary_function get_xoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_xoffset") { get_xoffset_op = Operator "get_xoffset" get_xoffset Operator_type.COMPOUND false; } has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = oo_unary_function get_yoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_yoffset") { get_yoffset_op = Operator "get_yoffset" get_yoffset Operator_type.COMPOUND false; } has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = oo_unary_function get_image_op x, is_class x = error (_ "bad arguments to " ++ "get_image") { get_image_op = Operator "get_image" get_image Operator_type.COMPOUND false; } has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = oo_unary_function get_number_op x, is_class x = error (_ "bad arguments to " ++ "get_number") { get_number_op = Operator "get_number" get_number Operator_type.COMPOUND false; } has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = oo_unary_function get_real_op x, is_class x = error (_ "bad arguments to " ++ "get_real") { get_real_op = Operator "get_real" get_real Operator_type.COMPOUND false; } has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = oo_unary_function get_width_op x, is_class x = error (_ "bad arguments to " ++ "get_width") { get_width_op = Operator "get_width" get_width Operator_type.COMPOUND false; } has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = oo_unary_function get_height_op x, is_class x = error (_ "bad arguments to " ++ "get_height") { get_height_op = Operator "get_height" get_height Operator_type.COMPOUND false; } has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = oo_unary_function get_left_op x, is_class x = error (_ "bad arguments to " ++ "get_left") { get_left_op = Operator "get_left" get_left Operator_type.COMPOUND false; } has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = oo_unary_function get_top_op x, is_class x = error (_ "bad arguments to " ++ "get_top") { get_top_op = Operator "get_top" get_top Operator_type.COMPOUND false; } // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/8.6/_list.def0000644000175000017500000002310313351443023014657 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* flatten x: flatten a list of lists of things into a simple list * * flatten :: [[*]] -> [*] */ flatten x = foldr flat [] x, is_list x = x { flat x sofar = foldr flat sofar x, is_list x = x : sofar; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st x) xs { x:xs = l; } /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn x xs { x:xs = l; } /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn x (foldr fn st xs) { x:xs = l; } /* foldr1 fn l: like foldr, but use the last element as the start value * * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = x, xs == [] = fn x (foldr1 fn xs) { x:xs = l; } /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn x = search xs (n + 1) { x:xs = l; } } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = x : init xs { x:xs = l; } /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = x, xs == [] = last xs { x:xs = l; } /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scanl fn st l: apply (foldl fn r) to every initial segment of a list * * scanl add 0 [1,2,3] == [1,3,6] * scanl :: (* -> ** -> *) -> * -> [**] -> [*] */ scanl fn st l = st, l == [] = st' : scanl fn st' xs { x:xs = l; st' = fn st x; } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/7.12/0000755000175000017500000000000013417043452013227 500000000000000nip2-8.7.1/share/nip2/compat/7.12/Image.def0000644000175000017500000012232313351443023014647 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum Image_type.type_names "Image type" "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; args' = sortc compare [a, b]; target = args'?0; x = args'?1; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } #separator Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ ["width", width], ["height", height], ["bands", bands], ["format", format], ["type", type], ["xres", xres], ["yres", yres], ["xoffset", xoffset], ["yoffset", yoffset], ["coding", coding] ]; field_option name = Option_enum field_names (_ "Field") name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum Image_type.type_names "Image type" (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_number_format_item = class Menupullright "Set _Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process in = [ in, rot90 in, rot180 in, rot270 in ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; _result = map_unary process x { process image = rotate angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = map_unary straighten x { straighten arrow = rotate angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { _interp = Option_enum Interpolate.names "Interpolation" "Bilinear"; Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = _interp; _result = map_unary process x { process image = resize xfactor yfactor interp.value_thing image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; interp = _interp; _result = map_unary process x { process image = resize fac fac interp.value_thing image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = max_pair xfac yfac; min_factor = min_pair xfac yfac; fac = [max_factor, min_factor, xfac, yfac]?which; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" (map (extract 0) Interpolate.names.value) Interpolate.BILINEAR; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _transform { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform _result = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image _result?0; _transform = Transform _result?1 reference.width reference.height; final_error = _result?2; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first args = sortc (const is_Transform) [a, b]; i = args?0; t = args?1; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } sep1 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldr1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = class _result { _vislevel = 3; // try to find the image geometry ... don't bother trying to look // inside groups though _geo = x.rect, is_Image x = Rect 0 0 100 100; l = Expression "Crop left" ((int) (_geo.left + _geo.width / 4)); t = Expression "Crop top" ((int) (_geo.top + _geo.height / 4)); w = Expression "Crop width" (max_pair 1 ((int) (_geo.width / 2))); h = Expression "Crop height" (max_pair 1 ((int) (_geo.height / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; _sorted = sortc _pred [a, b]; _a' = _sorted?0; _b' = _sorted?1; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 2; ssize = Expression "Step size" 2; _result = Image (colour_transform_to (get_type start) im) { base = colour_transform_to Image_type.LAB start; step = to_real ssize; offset = to_real nstep * step; range c = [c - offset, c - offset + step ... c + offset]; mk_patch b a = image_new 150 150 3 Image_format.FLOAT Image_coding.NOCODING Image_type.LAB (Vector [base?0, a, b]) 0 0; mk_strip b = map (mk_patch b) (range base?1); mk_grid = map mk_strip (range base?2); im = imagearray_assemble 15 15 mk_grid; } } } } nip2-8.7.1/share/nip2/compat/7.12/_convert.def0000644000175000017500000004243513351443023015451 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && len x == 3 = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The innermost list objects become Group()'d. */ to_group x = Group x, is_list x && !contains_Group x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), len parts != 2 = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, len parts != 4 = (ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), len parts != 5 = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ ["D93", D93_whitepoint], ["D75", D75_whitepoint], ["D65", D65_whitepoint], ["D55", D55_whitepoint], ["D50", D50_whitepoint], ["A", A_whitepoint], ["B", B_whitepoint], ["C", C_whitepoint], ["E", E_whitepoint], ["D3250", D3250_whitepoint] ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, im_8216 @ im_mono2sRGB], [B_W, GREY16, im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, im_8216], [RGB, GREY16, im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, im_8216], [sRGB, GREY16, im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* Given a list of things, try to make them all the same size. Don't change * the format. Don't touch non-image things. */ size_alike l = map enlarge l { max_width = foldr (test_prop has_width get_width) 0 l; max_height = foldr (test_prop has_height get_height) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); enlarge x = embed 0 0 0 max_width max_height x, has_width x = x; } /* Given a list of things, look for 1 band objects and bump them to to n - * band objects, where n is the maximum number of bands. Don't change the * format. Don't touch non-image things. */ bands_alike l = map upband l { max_bands = foldr (test_prop has_bands get_bands) 0 l; test_prop has get x best = best, !has x = max_pair best (get x); upband x = bandjoin (replicate max_bands x), has_bands x && get_bands x == 1 = x; } /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = foldl1 fn l { fn a b = a ++ path_separator ++ b; } /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 == 2 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/7.12/Filter.def0000644000175000017500000010771613351443023015063 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 1.5; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 50; fs = Scale "Sharpen flat areas by" (-2) 5 1; js = Scale "Sharpen jaggy areas by" (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_convf, !separable && type == 1 = im_convsepf, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 5) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height + 1) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale Blend" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image Blend" "use an image to blend two objects" { action a b c = map_trinary process a b c { process a b c = blend condition in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; args' = sortc compare [a, b, c]; condition = args'?0; in1 = args'?1; in2 = args'?2; } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha Blend" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ ["Normal", NORMAL], ["If Lighter", IFLIGHTER], ["If Darker", IFDARKER], ["Multiply", MULTIPLY], ["Add", ADD], ["Subtract", SUBTRACT], ["Screen", SCREEN], ["Burn", BURN], ["Soft Light", SOFTLIGHT], ["Hard Light", HARDLIGHT], ["Lighten", LIGHTEN], ["Darken", DARKEN], ["Dodge", DODGE], ["Reflect", REFLECT], ["Freeze", FREEZE], ["Bitwise OR", OR], ["Bitwise AND", AND] ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum names "Blend mode" "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ "Green over Red", "Blue over Red", "Red over Green", "Red over Blue", "Blue over Green", "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first args = sortc (const (is_colour_type @ get_type)) [a, b]; mono = args?0; colour = args?1; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ "Grey", "Green over Red", "Blue over Red", "Red over Green", "Red over Blue", "Blue over Green", "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } Filter_draw_line_item = class Menuaction "Draw _Line" "draw a line using an arrow as a guide" { } nip2-8.7.1/share/nip2/compat/7.12/_joe_extra.def0000644000175000017500000003260713351443023015751 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height that * is extracted to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = class { scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; } _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = class { apply = Toggle "Apply mount color" false; ls = Expression "Lower mount section bigger by (cm)" 0; colour = Colour _type [0, 0, 0]; _los = ls.expr * ppcm.expr; } _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize _sf _sf Interpolate.BILINEAR a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 6; control_selection mask im no = (if mask then im * 1.2 else im * 1), no == 0 = (if mask then im * 0.8 else im * 1), no == 1 = (if mask then 0 else im), no == 2 = (if mask then 255 else im), no == 3 = (if mask then im else 0), no == 4 = (if mask then im else 255), no == 5 = mask; Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = a.image; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = ((pt_list.value)?0).image; } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize f1 1 1 b1 {b1 = resize 1 f2 1 b;} } } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.12/Preferences.ws0000644000175000017500000007760213351443023015772 00000000000000 nip2-8.7.1/share/nip2/compat/7.12/Format.def0000644000175000017500000000630713351443023015060 00000000000000Format_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Format_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Format_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Format_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Format_assemble_item = class Menuaction "_Assemble Objects" "assemble a list (or group) of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } #separator Format_csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Interpret_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } nip2-8.7.1/share/nip2/compat/7.12/Colour.def0000644000175000017500000003537013351443023015075 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; _L = default_value?0; _a = default_value?1; _b = default_value?2; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Convert to") (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum spaces (_ "Tag as") (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Colour Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum Whitepoints (_ "Old whitepoint") "D65"; new_white = Option_enum Whitepoints (_ "New whitepoint") "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum Render_intent.names (_ "Render intent") (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; _result = map_unary chart x { chart in = measure 0 0 in.width in.height (to_real pacross) (to_real pdown) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.12/_joe_utilities.def0000644000175000017500000004705113351443023016640 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} } ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; } ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); } ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = line.image; //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = (pt_l?0).image; im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; } ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; } ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; } nip2-8.7.1/share/nip2/compat/7.12/Math.def0000644000175000017500000003355513351443023014526 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_And" "bitwise and of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_Or" "bitwise or of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "E_xclusive Or" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_Not" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Band_or_item = class Menuaction "Band O_r" "or the bands of an image together" { action im = map_unary (foldr1 bitwise_or @ bandsplit) im; } Band_and_item = class Menuaction "Band A_nd" "and the bands of an image together" { action im = map_unary (foldr1 bitwise_and @ bandsplit) im; } } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; // from s15.2, p 665 NR in C Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = class { _vislevel = 3; /* Hide these by default. */ details = class { ss = len xes; sx = sum xes; sy = sum yes; sxoss = sx / ss; t = map (converse subtract sxoss) xes; st2 = sum (map (converse power 2) t); } slope = sum (map2 multiply details.t yes) / details.st2; intercept = (details.sy - details.sx * slope) / details.ss; chi2 = sum (map (converse power 2) (map2 subtract (map (converse subtract intercept) yes) (map (multiply slope) xes))); siga = (chi2 / (details.ss - 2)) ** 0.5 * ((1 + details.sx ** 2 / (details.ss * details.st2)) / details.ss) ** 0.5; sigb = (chi2 / (details.ss - 2)) ** 0.5 * (1 / details.st2) ** 0.5; q = 1.0; } } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = class { _vislevel = 3; /* Hide these by default. */ details = class { wt = map (converse power (-0.5)) devs; ss = sum wt; sx = sum (map2 multiply xes wt); sy = sum (map2 multiply yes wt); sxoss = sx / ss; t = map2 divide (map (converse subtract sxoss) xes) devs; st2 = sum (map (converse power 2) t); } slope = sum (map2 divide (map2 multiply details.t yes) devs) / details.st2; intercept = (details.sy - details.sx * slope) / details.ss; siga = ((1 + details.sx * details.sx / (details.ss * details.st2)) / details.ss) ** 0.5; sigb = (1 / details.st2) ** 0.5; chi2 = sum (map (converse power 2) (map2 divide (map2 subtract (map (converse subtract intercept) yes) (map (multiply slope) xes)) devs)); q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.12/_generate.def0000644000175000017500000000514013351443023015553 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black (to_real w) (to_real h) (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = Matrix_con mask_g_sum 0 [mask_g_line] { mask_g = im_gauss_imask (radius / 3) 0.2; mask_g_line = mask_g.value?(mask_g.height / 2); mask_g_sum = sum mask_g_line; } /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } nip2-8.7.1/share/nip2/compat/7.12/_stdenv.def0000644000175000017500000013523113351443023015271 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error "unimplemented vector operation" { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { totals = sum_sum2_list l; n = totals?0; s = totals?1; s2 = totals?2; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { n = sofar?0; s = sofar?1; s2 = sofar?2; sub_acc = sum_sum2_list x; n' = sub_acc?0; s' = sub_acc?1; s2' = sub_acc?2; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { totals = sum_sum2_list l; n = totals?0; s = totals?1; s2 = totals?2; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { n = sofar?0; s = sofar?1; s2 = sofar?2; sub_acc = sum_sum2_list x; n' = sub_acc?0; s' = sub_acc?1; s2' = sub_acc?2; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_cache x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (converse cons [] @ converse subscript x') obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend") { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { then_part = x?0; else_part = x?1; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = x, is_image x = x.value, is_Image x = black + x { black = im_black target_width target_height target_bands; } then_image = to_image then_part; else_image = to_image else_part; then_image' = clip2fmt target_format then_image; else_image' = clip2fmt target_format else_image; resized = size_alike [cond, then_image', else_image']; blend_result_image = image_set_type target_type (im_blend resized?0 resized?1 resized?2); } } insert x y small big = oo_binary_function insert_op small big, is_class small = oo_binary'_function insert_op small big, is_class big = im_insert rebanded?1 rebanded?0 (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; rebanded = bands_alike [small, big]; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand rebanded?1 rebanded?0 (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; rebanded = bands_alike [small, big]; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (_ "bad arguments to " ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_similarity image (cos angle) (sin angle) 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" rotate Operator_type.COMPOUND_REWRAP false; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join a b { join_lr_op = Operator "join_lr" join Operator_type.COMPOUND_REWRAP false; join a b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr"); join_im a b = insert (get_width b) 0 a b; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join a b { join_tb_op = Operator "join_tb" join Operator_type.COMPOUND_REWRAP false; join a b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb"); join_im a b = insert 0 (get_height b) a b; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { image = (unsigned char) im_mask2vips (Matrix m2); m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsepf image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = conv (Matrix [[-1, 1]]) h; } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize xfac yfac interp image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // upscale by any factor, nearest neighbour // can't really do this right ... upscale by integer part, then // bilinear to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // downscale by any factor, nearest neighbour // can't really do this right ... downscale by integer part, // then bilinear to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.NEAREST_NEIGHBOUR // upscale by any factor, bilinear = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 && interp == Interpolate.BILINEAR // downscale by any factor, bilinear // block shrink by integer factor, then bilinear resample to // exact = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && interp == Interpolate.BILINEAR = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate.names.lookup 1 0 interp ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // binlinear resize scale xfac yfac im = im_affine im xfac 0 0 yfac 0 0 0 0 (rint (get_width im * xfac)) (rint (get_height im * yfac)); } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } flood_blob x y v image = oo_unary_function flood_blob_op image, is_class image = im_flood_blob_copy image (to_real x) (to_real y) v, is_image image = error (_ "bad arguments to " ++ "flood_blob") { flood_blob_op = Operator "flood_blob" (flood_blob x y v) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (converse remainder base) (takewhile (not_equal 0) (iterate (converse idiv base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); idiv a b = (int) (a / b); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = [], lor (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == []; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Image (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && len x?0 > 1 = error (_ "bad arguments to " ++ "buildlut"); nip2-8.7.1/share/nip2/compat/7.12/Histogram.def0000644000175000017500000001706513351443023015570 00000000000000Hist_new_item = class Menuaction "_New Histogram" "make a new histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type field to Histogram" { action x = hist_tag x; } #separator Hist_find_item = class Menupullright "_Find Histogram" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } } Hist_map_item = class Menuaction "_Map Histogram" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { args = sortc (const is_hist) [a, b]; im = args?0; hist = args?1; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Cumulativise Histogram" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate Histogram" "find point-to-point differences (inverse of Cumulativise)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise Histogram" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_match_item = class Menuaction "Ma_tch Histogram" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); // extract that area area = extract_area (re p' + displace.value) (im p' - width.value / 2 + vdisplace.value) (re pv) width.value im'; // squish vertically to get an average area' = resize 1 (1 / width.value) Interpolate.BILINEAR area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = area { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); // extract that area area = extract_area (re p' + displace.value) (im p' - width.value / 2 + vdisplace.value) (re pv) width.value im'; } } } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; format = Option_enum Plot_format.names "Format" "YYYY"; style = Option_enum Plot_style.names "Style" "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (image x) { options = [["style", style.value], ["format", format.value]] ++ range; range = [], auto = [["xmin", xmin.expr], ["xmax", xmax.expr], ["ymin", ymin.expr], ["ymax", ymax.expr]]; image x = image (extract_arrow x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } extract_arrow arrow = extract_area (re p') (im p') (re pv) 1 im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } } } } nip2-8.7.1/share/nip2/compat/7.12/Widgets.def0000644000175000017500000000235313351443023015233 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/7.12/_types.def0000644000175000017500000011500513351443023015127 00000000000000 /* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0, 1, 2 or 3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, "colour_space"]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide or VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down a bit. */ check_args x = error message, badargs != [] || badalls != [] = check_args x.super, x.super != [] = x { argcheck = x._check_args; allcheck = x._check_all; // join two strings up with a separator string join_sep j a b = a ++ j ++ b; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad arguments to " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "usage" ++ "\n" ++ indent ++ usage ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make usage note usage = x.name ++ " " ++ foldr (join_sep " ") [] (map (extract 1) argcheck); // make arg type notes arg_types = foldr (join_sep "\n") [] (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = foldr (join_sep "\n") [] all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; /* Provide a fallback for class == thing ... just use pointer * equality. */ oo_binary_table op x = [ [pointer_equal this x, op.op_name == "equal" || op.op_name == "equal'"], [not_pointer_equal this x, op.op_name == "not_equal" || op.op_name == "not_equal'"] ]; oo_unary_table op = []; } /* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary ((converse op.fn) x) this, true] ] { // need ite as a true trinary ite a b c = if a then b else c; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = [], lor (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == []; } } map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } oo_unary_table op = [ [map_unary op.fn this, true] ] { // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = [], lor (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == []; } } map_unary fn a = map_nary (list_1ary fn) [a]; } } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ]; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ]; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ]; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ]; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [len value == 3, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.value_name colour.expr { _vislevel = 3; space = Option_enum Image_type.colour_spaces "Colour space" default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } Option_enum enum caption value_name = class Option caption enum.names (index (equal value_name) enum.names) { // corresponding thing value_thing = enum.get_thing value_name; Option_edit caption labels value = this.Option_enum enum caption (enum.names ? value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NOCODING = 0; COLQUANT = 1; LABPACK = 2; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* present col x: is there an x in column col */ present col x = member (map (extract col) value) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (map (extract from) value); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = map (extract 0) value; things = map (extract 1) value; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; LUMINANCE = 2; XRAY = 3; IR = 4; YUV = 5; RED_ONLY = 6; GREEN_ONLY = 7; BLUE_ONLY = 8; POWER_SPECTRUM = 9; HISTOGRAM = 10; LUT = 11; XYZ = 12; LAB = 13; CMC = 14; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; /* Table to get names <-> numbers. */ type_names = Enum [ ["MULTIBAND", MULTIBAND], ["B_W", B_W], ["LUMINANCE", LUMINANCE], ["XRAY", XRAY], ["IR", IR], ["YUV", YUV], ["RED_ONLY", RED_ONLY], ["GREEN_ONLY", GREEN_ONLY], ["BLUE_ONLY", BLUE_ONLY], ["POWER_SPECTRUM", POWER_SPECTRUM], ["HISTOGRAM", HISTOGRAM], ["LUT", LUT], ["XYZ", XYZ], ["LAB", LAB], ["CMC", CMC], ["CMYK", CMYK], ["LABQ", LABQ], ["RGB", RGB], ["UCS", UCS], ["LCH", LCH], ["LABS", LABS], ["sRGB", sRGB], ["YXY", YXY], ["FOURIER", FOURIER], ["RGB16", RGB16], ["GREY16", GREY16] ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ ["sRGB", sRGB], ["Lab", LAB], ["LCh", LCH], ["XYZ", XYZ], ["Yxy", YXY], ["UCS", UCS] ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ ["Mono", B_W], ["sRGB", sRGB], ["RGB16", RGB16], ["GREY16", GREY16], ["Lab", LAB], ["LabQ", LABQ], ["LabS", LABS], ["LCh", LCH], ["XYZ", XYZ], ["Yxy", YXY], ["UCS", UCS] ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], // image ++ image is slightly different ... we want to // sizealike, but we must not bandalike [wrap (op.fn (get_image resized?0) (get_image resized?1)), has_image x && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], // arithmetic and reational binops between image resize // and band_alike images to match [wrap (op.fn (get_image rebanded?0) (get_image rebanded?1)), has_image x && (op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL)], // other op types don't resize [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. "Image v == // 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } then_part = x?0; else_part = x?1; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = x, is_image x = x.value, is_Image x = black + x { black = im_black width height target_bands; } then_image = to_image then_part; else_image = to_image else_part; then_image' = clip2fmt target_format then_image; else_image' = clip2fmt target_format else_image; ite_resized = size_alike [value, then_image', else_image']; ite_result_image = image_set_type target_type (if ite_resized?0 then ite_resized?1 else ite_resized?2); resized = size_alike [this, x]; rebanded = bands_alike resized; } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; /* Table to map interpol numbers to descriptive strings */ names = Enum [ [_ "Nearest neighbour", NEAREST_NEIGHBOUR], [_ "Bilinear", BILINEAR], [_ "Bicubic", BICUBIC] ]; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ [_ "Perceptual", PERCEPTUAL], [_ "Relative", RELATIVE], [_ "Saturation", SATURATION], [_ "Absolute", ABSOLUTE] ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ [_ "Point", POINT], [_ "Line", LINE], [_ "Spline", SPLINE], [_ "Bar", BAR] ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ [_ "YYYY", YYYY], [_ "XYYY", XYXY], [_ "XYXY", XYXY] ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [["format", Plot_format.XYYY]] value { } nip2-8.7.1/share/nip2/compat/7.12/Matrix.def0000644000175000017500000002067113351443023015074 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 (converse join_tb) (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 (converse join_lr) (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 (converse join_tb) (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 (converse join_lr) (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [["style", Plot_style.POINT], ["format", Plot_format.XYYY]] ++ range; range = [], auto = [["xmin", xmin.expr], ["xmax", xmax.expr], ["ymin", ymin.expr], ["ymax", ymax.expr]]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/7.12/Tasks.def0000644000175000017500000005514013351443023014714 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; args = sortc larger [a, b]; image = args?0; patch = args?1; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = im_measure image.value 0 0 image.width image.height 6 4; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'); // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it linearising_lut = Image _linear_lut; // map the original image through the lineariser to // get linear 0-1 RGB image _image' = hist_map linearising_lut.value image.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ cast_float @ recomb M) _image'; // measure again and compute dE76 _camera'' = im_measure _result.value 0 0 image.width image.height 6 4; _dEs = map abs_vec (_camera'' - _true_Lab).value; final_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 = "Unknown"; } } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first args = sortc (const (is_instanceof calib_name)) [a, b]; calib = args?1; image = args?0; // map the original image through the lineariser to get // linear 0-1 RGB image image' = hist_map calib.linearising_lut image; // convert linear RGB camera to Lab result = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M image')); } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum Plot_style.names "Style" "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [["style", style.value]] ++ if auto then [] else [["ymin", ymin.expr], ["ymax", ymax.expr]]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", len images != 2 = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = land (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { sorted = mosaic_sort mosaic_sort_lr [a, b]; a' = sorted?0; b' = sorted?1; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { sorted = mosaic_sort mosaic_sort_tb [a, b]; a' = sorted?0; b' = sorted?1; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { sorted = mosaic_sort mosaic_sort_lr [a, b, c, d]; a' = sorted?0; b' = sorted?1; c' = sorted?2; d' = sorted?3; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { sorted = mosaic_sort mosaic_sort_tb [a, b, c, d]; a' = sorted?0; b' = sorted?1; c' = sorted?2; d' = sorted?3; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize xfactor yfactor 1 scale_im; _offset_im = resize xfactor yfactor 1 offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.12/Makefile.am0000644000175000017500000000054613351443023015203 00000000000000startdir = $(pkgdatadir)/compat/7.12 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Format.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.12/Makefile.in0000644000175000017500000003707413417043241015223 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.12 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.12 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Format.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.12/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.12/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.12/_predicate.def0000644000175000017500000002542713351443023015733 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = lor (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && land (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, land (map is_obj l) = true, land (map is_list l) && land (map (not @ is_obj) l) && land (map is_rectangular l) && len l > 0 && land (map (equal (hd lengths)) (tl lengths)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; lengths = map len l; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && len l == len (hd l); /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && land (map xy l) { xy l = is_real_list l && len l == 2; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && lor (map is_Group l) = lor (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = type, bands == 1 && type == Image_type.GREY16 = type, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, bands == 1 = type, bands == 3 && is_colorimetric = Image_type.sRGB, bands == 3 && !is_colorimetric = Image_type.MULTIBAND, bands != 3 && !is_colorimetric = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = error ("get_format: unable to get format from " ++ print x); has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = error ("get_bits: unable to get bits from " ++ print x); has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = error ("get_bands: unable to get bands from " ++ print x); has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = error ("get_coding: unable to get coding from " ++ print x); has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = error ("get_xres: unable to get xres from " ++ print x); has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = error ("get_yres: unable to get yres from " ++ print x); has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = error ("get_xoffset: unable to get xoffset from " ++ print x); has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = error ("get_yoffset: unable to get yoffset from " ++ print x); has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = error ("get_image: unable to get image from " ++ print x); has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = error ("get_number: unable to get number from " ++ print x); has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = error ("get_real: unable to get real from " ++ print x); has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = error ("get_width: unable to get width from " ++ print x); has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = error ("get_height: unable to get height from " ++ print x); has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = error ("get_left: unable to get left from " ++ print x); has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = error ("get_top: unable to get top from " ++ print x); // like has/get member,but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/7.12/_list.def0000644000175000017500000002142313351443023014736 00000000000000/* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn (tl l), fn (hd l) = l; /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); sum = foldr1 add; product = foldr1 multiply; /* Search a list for an element, returning it's index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* land l: and all the elements of list l together * * land (map (==0) list) == true, if every element of list is zero. * land :: [bool] -> bool */ land = foldr logical_and true; /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a = l?0; b = l?1; x = tl (tl l); } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* lor l: or all the elements of list l together * * lor (map (equal 0) list) == true, if any element of list is zero. * lor :: [bool] -> bool */ lor = foldr logical_or false; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = lor (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge b l r = [], b == [] || l == [] || r == [] = hd l : merge (tl b) (tl l) (tl r), hd b = hd r : merge (tl b) (tl l) (tl r); /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a = hd l; x = tl l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st (hd l)) (tl l); } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a = hd l1; x = tl l1; b = hd l2; y = tl l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/7.28/0000755000175000017500000000000013417043453013237 500000000000000nip2-8.7.1/share/nip2/compat/7.28/Image.def0000644000175000017500000014150213351443023014656 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process in = [ in, rot90 in, rot180 in, rot270 in ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp h v image, aspect = resize interp fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize interp fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = class _result { _vislevel = 3; // try to find the image geometry ... don't bother trying to look // inside groups though _geo = x.rect, is_Image x = Rect 0 0 100 100; l = Expression "Crop left" ((int) (_geo.left + _geo.width / 4)); t = Expression "Crop top" ((int) (_geo.top + _geo.height / 4)); w = Expression "Crop width" (max_pair 1 ((int) (_geo.width / 2))); h = Expression "Crop height" (max_pair 1 ((int) (_geo.height / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 100; sy = Expression "Start y" 100; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/7.28/_convert.def0000644000175000017500000004214013351443023015451 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The innermost list objects become Group()'d. */ to_group x = Group x, is_list x && !contains_Group x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = (ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/7.28/Filter.def0000644000175000017500000012653013351443023015065 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 1.5; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 50; fs = Scale "Sharpen flat areas by" (-2) 5 1; js = Scale "Sharpen jaggy areas by" (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_greyc_item = class Menupullright "_GREYCstoration" "noise-removing filter" { Denoise_item = class Menuaction "Denoise" "Noise-removing filter" { action x = class _result { _vislevel = 3; iterations = Scale "Iterations" 1 5 1; amplitude = Scale "Amplitude" 1 100 40; sharpness = Scale "Sharpness" 0 3 0.9; anisotropy = Scale "Anisotropy" 0 1 0.15; alpha = Scale "Noise scale" 0 5 0.6; sigma = Scale "Geometry regularity" 0 2 1.1; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) x; } } Enlarge_item = class Menuaction "Enlarge" "Enlarge image" { action x = class _result { _vislevel = 3; scale = Scale "Enlarge" 1 10 3; iterations = Scale "Iterations" 1 5 3; amplitude = Scale "Amplitude" 1 100 20; sharpness = Scale "Sharpness" 0 3 0.2; anisotropy = Scale "Anisotropy" 0 1 0.9; alpha = Scale "Noise scale" 0 5 0.1; sigma = Scale "Geometry regularity" 0 2 1.5; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) (resize Interpolate_bilinear (to_real scale) (to_real scale) x); } } } Filter_magick_item = class Menupullright "Magic_k" "various Image/Graphics Magick filters" { system command x = map_unary (system_image command) x; radius_widget = Scale "Radius" 1 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; print_colour triple = concat ["\"#", concat (map fmt triple), "\""] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; Background triple = class Colour "sRGB" triple { _flag = "-background " ++ print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Geometry_widget = class { _vislevel = 3; x = Expression "Y" 0; y = Expression "X" 0; hoffset = Expression "Horizontal offset" 10; voffset = Expression "Vertical offset" 10; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } Adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; radius = radius_widget; sigma = sigma_widget; command = magick_command (concat ["-adaptive-blur ", print radius.value, "x", print sigma.value]); _result = system command x; } } Adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; radius = radius_widget; sigma = sigma_widget; command = magick_command (concat ["-adaptive-sharpen ", print radius.value, "x", print sigma.value]); _result = system command x; } } Alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = alpha_widget; command = magick_command alpha._flag; _result = system command x; } } Annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = text_widget; font = Font_widget; geometry = Geometry_widget; gravity = gravity_widget; foreground = foreground_widget; antialias = antialias_widget; command = magick_command (join_sep " " [ font._flag, antialias._flag, gravity._flag, foreground._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\""]); _result = system command x; } } Swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = angle_widget; command = magick_command ("-swirl " ++ print angle.value); _result = system command x; } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } nip2-8.7.1/share/nip2/compat/7.28/_joe_extra.def0000644000175000017500000003066713351443023015764 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use line/arrow/rect x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_rect x; im = get_image x; select_rect x = Image mask { im = Image (get_image x); imc = make_xy im.width im.height; mask = imc?0 >= x.nleft & imc?0 < x.nright & imc?1 >= x.ntop & imc?1 < x.nbottom; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Interpolate_bilinear f1 1 b1 {b1 = resize Interpolate_bilinear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.28/Colour.def0000644000175000017500000003607713351443023015111 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Colour Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; _result = map_unary chart x { chart in = measure 0 0 in.width in.height (to_real pacross) (to_real pdown) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.28/_joe_utilities.def0000644000175000017500000005054513351443023016651 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/7.28/_Object.def0000644000175000017500000002600513351443023015201 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/7.28/Object.def0000644000175000017500000000222013351443023015033 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list (or group) of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/7.28/Math.def0000644000175000017500000003157713351443023014537 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_And" "bitwise and of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_Or" "bitwise or of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "E_xclusive Or" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_Not" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Band_or_item = class Menuaction "Band O_r" "or the bands of an image together" { action im = map_unary (foldr1 bitwise_or @ bandsplit) im; } Band_and_item = class Menuaction "Band A_nd" "and the bands of an image together" { action im = map_unary (foldr1 bitwise_and @ bandsplit) im; } } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.28/_generate.def0000644000175000017500000000470713351443023015572 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } nip2-8.7.1/share/nip2/compat/7.28/_stdenv.def0000644000175000017500000016766513351443023015320 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_cache x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (_ "bad arguments to " ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx x = oo_unary_function greyc_op x, is_class x = greyc_im x, is_image x = error (_ "bad argument" ++ " (" ++ print x ++ ") to " ++ "greyc") { greyc_op = Operator "greyc" (greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im x = im_greyc x iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx mask x = oo_binary_function greyc_mask_op mask x, is_class mask = oo_binary'_function greyc_mask_op mask x, is_class x = greyc_im mask x, is_image mask && is_image x = error (_ "bad arguments" ++ " (" ++ print mask ++ ", " ++ print x ++ ") " ++ "to " ++ "greyc") { greyc_mask_op = Operator "greyc_mask" (greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im mask x = im_greyc_mask x mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize interp xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; // is this interpolation nearest-neighbour? is_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor, nearest neighbour // upscale by integer part, then affine to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by any factor, nearest neighbour // downscale by integer part, then affine to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor with affine = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 // downscale by any factor, bilinear // block shrink by integer factor, then resample to // exact with affine = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate_type.descriptions?interp.type ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // resize scale xfac yfac im = im_affinei_all im interp.value xfac 0 0 yfac 0 0; } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; } ss = len xes; sx = sum xes; sy = sum yes; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* Generate an ImageMagick (or GraphicsMagick) command suitable for * im_system_image. Use convert.exe in $VIPSHOME/bin, if it exists, otherwise * assume it's on the path somewhere. */ magick_command switch = join_sep " " [convert, "\"%s\"", switch, "\"%s\""] { prefs = Workspaces.Preferences; use_gm = prefs.USE_GRAPHICSMAGICK; name = if use_gm then "gm" else "convert"; exe = concat [name, expand "$EXEEXT"]; vipsexe = path_absolute [expand "$VIPSHOME", "bin", exe]; final_exe = vipsexe, search vipsexe != [] = exe; convert = join_sep " " [final_exe, "convert"], use_gm = final_exe; } /* Run a command on an image. See magick_command, for example. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } nip2-8.7.1/share/nip2/compat/7.28/Histogram.def0000644000175000017500000001474013351443023015574 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "Histogram" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Interpolate_bilinear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/7.28/Widgets.def0000644000175000017500000000235313351443023015242 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/7.28/_types.def0000644000175000017500000006732313351443023015147 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/7.28/Matrix.def0000644000175000017500000002433413351443023015103 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = class _result { _vislevel = 3; s = Expression "Size" 5; _result = Matrix (identity_matrix s.expr); } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = class _result { _vislevel = 3; s = Expression "Start value" 0; t = Expression "Step by" 1; e = Expression "End value" 5; _result = Matrix (transpose [series]) { series = [to_real s, to_real t.. to_real e]; } } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = class _result { _vislevel = 3; s = Expression "Size" 5; _result = Matrix_con (s.expr ** 2) 0 square { line = take s.expr [1, 1 ..]; square = replicate s.expr line; } } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = class _result { _vislevel = 3; r = Expression "Radius" 5; _result = Matrix_con (sum circle) 0 circle { line = [-r.expr .. r.expr]; xes = replicate (2 * r.expr + 1) line; yes = transpose xes; circle = map2 (map2 pyth) xes yes { pyth a b = 1, (a**2 + b**2) ** 0.5 <= r.expr = 0; } } } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/7.28/Tasks.def0000644000175000017500000006321313351443023014723 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linear input", "Fit intercept from chart greyscale", "Linearize input from chart greyscale" ] 2; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure 0 0 image.width image.height 6 4 image.value; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix [[0, 0], [1, 1]], mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix (map2 cons _true_grey_Y' _camera_grey') { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map the original image through the lineariser to // get linear 0-1 RGB image _image' = hist_map linearising_lut.value image.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ cast_float @ recomb M) _image'; // measure again and compute dE76 _camera'' = im_measure _result.value 0 0 image.width image.height 6 4; _dEs = map abs_vec (_camera'' - _true_Lab).value; final_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; // map the original image through the lineariser to get // linear 0-1 RGB image image' = hist_map calib.linearising_lut image; // convert linear RGB camera to Lab result = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M image')); } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Interpolate_bilinear xfactor yfactor scale_im; _offset_im = resize Interpolate_bilinear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.28/Makefile.am0000644000175000017500000000054313351443023015207 00000000000000startdir = $(pkgdatadir)/compat/7.28 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.28/Makefile.in0000644000175000017500000003707113417043242015230 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.28 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.28 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.28/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.28/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.28/_predicate.def0000644000175000017500000002672113351443023015740 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = error ("get_format: unable to get format from " ++ print x); has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = error ("get_bits: unable to get bits from " ++ print x); has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = error ("get_bands: unable to get bands from " ++ print x); has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = error ("get_coding: unable to get coding from " ++ print x); has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = error ("get_xres: unable to get xres from " ++ print x); has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = error ("get_yres: unable to get yres from " ++ print x); has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = error ("get_xoffset: unable to get xoffset from " ++ print x); has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = error ("get_yoffset: unable to get yoffset from " ++ print x); has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = error ("get_image: unable to get image from " ++ print x); has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = error ("get_number: unable to get number from " ++ print x); has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = error ("get_real: unable to get real from " ++ print x); has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = error ("get_width: unable to get width from " ++ print x); has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = error ("get_height: unable to get height from " ++ print x); has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = error ("get_left: unable to get left from " ++ print x); has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = error ("get_top: unable to get top from " ++ print x); // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/7.28/_list.def0000644000175000017500000002245013351443023014746 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st a) x { a:x = l; } } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/8.5/0000755000175000017500000000000013417043453013153 500000000000000nip2-8.7.1/share/nip2/compat/8.5/Image.def0000644000175000017500000015060413351443023014575 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process = [ // we can't use id here since we want to "declass" // the members of x ... consider if x is a crop class, // for example, we don't want to inherit from crop, we // want to make a new image class rot180 @ rot180, rot90, rot180, rot270 ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { process image = resize kernel h v image, aspect = resize kernel fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; kernel = Kernel_picker Kernel_type.LINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize kernel fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_map_item = class Menuaction "_Map" "map an image through a 2D transform image" { action a b = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_binary trans a b { trans a b = mapim interp.value in index { // get the index image first [index, in] = sortc (const is_twocomponent) [a, b]; // is a two-component image, ie. one band complex, or // two-band non-complex is_twocomponent x = is_nonc x || is_c x; is_nonc x = has_bands x && get_bands x == 2 && has_format x && !is_complex_format (get_format x); is_c x = has_bands x && get_bands x == 1 && has_format x && is_complex_format (get_format x); is_complex_format f = f == Image_format.COMPLEX || f == Image_format.DPCOMPLEX; } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1a = Menuseparator; Bandand_item = class Menuaction "Bitwise Band AND" "bitwise AND of image bands" { action x = bandand x; } Bandor_item = class Menuaction "Bitwise Band OR" "bitwise OR of image bands" { action x = bandor x; } sep2 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_alpha_item = class Menupullright "_Alpha" "manipulate image alpha" { Add_item = class Menuaction "_Add" "add alpha" { action x = class _result { _vislevel = 3; opacity = Expression "Opacity (255 == solid)" 255; _result = x ++ to_real opacity; } } Flatten_item = class Menuaction "_Flatten" "flatten alpha out of image" { action x = class _result { _vislevel = 3; bg = Expression "Background" 0; _result = map_unary (flattenimage bg) x; } } Extract_item = class Menuaction "_Extract" "extract alpha" { action x = map_unary exb x { exb x = extract_bands (x.bands - 1) 1 x; } } Drop_item = class Menuaction "_Drop" "drop alpha" { action x = map_unary exb x { exb x = extract_bands 0 (x.bands - 1) x; } } sep1 = Menuseparator; Premultiply_item = class Menuaction "_Premultiply" "premultiply alpha" { action x = premultiply x; } Unpremultiply_item = class Menuaction "_Unpremultiply" "unpremultiply alpha" { action x = unpremultiply x; } sep2 = Menuseparator; Blend_alpha_item = Filter_blend_item.Blend_alpha_item; } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = crop x [l, t, w, h] { fields = [ [has_left, get_left, 0], [has_top, get_top, 0], [has_width, get_width, 100], [has_height, get_height, 100] ]; [l, t, w, h] = map get_default fields { get_default line = get x, has x = default { [has, get, default] = line; } } } crop x geo = class _result { _vislevel = 3; l = Expression "Crop left" ((int) (geo?0 + geo?2 / 4)); t = Expression "Crop top" ((int) (geo?1 + geo?3 / 4)); w = Expression "Crop width" (max_pair 1 ((int) (geo?2 / 2))); h = Expression "Crop height" (max_pair 1 ((int) (geo?3 / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 0; sy = Expression "Start y" 0; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise Join" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; snake = Toggle "Reverse the order of every other row" false; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _l' = map2 reverse_if_odd [0..] _l, snake = _l { reverse_if_odd n x = reverse x, n % 2 == 1 = x; } _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l')); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Noise_item = class Menupullright "_Noise" "various noise generators" { Gaussian_item = class Menuaction "_Gaussian" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (gaussnoise nwidth nheight mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal noise image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Perlin_item = class Menuaction "_Perlin" "Perlin noise image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; cell_size = Expression "Cell size (pixels)" 8; eight = Toggle "Eight bit output" true; _result = 128 * im + 128, eight = im { im = perlin cell_size nwidth nheight; } } } Worley_item = class Menuaction "_Worley" "Worley noise image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 512; nheight = Expression "Image height (pixels)" 512; cell_size = Expression "Cell size (pixels)" 256; _result = worley cell_size nwidth nheight; } } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/8.5/_convert.def0000644000175000017500000004557713351443023015406 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make a Vector ... works for Vector/Image/Real, plus image/real */ to_vector x = to_vector x.expr, is_Expression x = x, is_Vector x = oo_unary_function to_vector_op x, is_class x = tov x { to_vector_op = Operator "to_vector" tov Operator_type.COMPOUND false; tov x = Vector (itov x), is_image x = Vector [x], is_real x = Vector x, is_real_list x = Vector x?0, is_matrix x && len x == 1 = Vector (transpose x)?0, is_matrix x && len x?0 == 1 = error (_ "bad arguments to " ++ "to_vector"); itov i = v, is_image i = error (_ "not image") { m = im_vips2mask ((double) i); v = m.value?0, m.height == 1 = (transpose m.value)?0, m.width == 1 = error (_ "image is not 1xN or Nx1"); } } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = Image x.value, is_Plot x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The outermost list objects become Group()'d. */ to_group x = Group x, is_list x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = sign * (abs ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; sign = 1, ipart >= 0 = -1; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; /* Return $PATH, reformatted as [["comp1", "comp2"], ["comp1", "comp2"] ..] */ system_search_path = [vipsbin] ++ map path_parse (split (equal path_sep) (expand "$PATH")) { /* On some platforms we ship vips with a few extra progs. Search * $VIPSHOME/bin first. */ vipsbin = path_parse (expand "$VIPSHOME") ++ ["bin"]; path_sep = ':', expand "$SEP" == "/" = ';'; } /* Search $PATH for the first occurence of name, or "". */ search_for name = hits?0, hits != [] = "" { exe_name = name ++ expand "$EXEEXT"; form_path p = path_absolute (p ++ [exe_name]); paths = map form_path system_search_path; hits = dropwhile (equal []) (map search paths); } /* Search $PATH for the first occurence of name, error on failure. */ search_for_error name = path, path != "" = error (exe_name ++ " not found on your search path. " ++ "Check you have installed the program and it is on your PATH.") { exe_name = name ++ expand "$EXEEXT"; path = search_for name; } nip2-8.7.1/share/nip2/compat/8.5/Filter.def0000644000175000017500000011740613351443023015003 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 2; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 20; fs = Scale "Sharpen flat areas by" 0 5 0.5; js = Scale "Sharpen jaggy areas by" 0 5 1; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; max_slope = Scale "Maxium slope" 0 10 0; _result = map_unary process x { process in = hist_equalize_local window_width window_height max_slope in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_hough_item = class Menupullright "_Hough Transform" "transform to parameter space" { Line_item = class Menuaction "_Line" "find straight line Hough transform" { action a = class _result { _vislevel = 3; pspace_width = Expression "Parameter space width" 64; pspace_height = Expression "Parameter space height" 64; _result = map_unary line a { line a = hough_line (to_real pspace_width) (to_real pspace_height) a; } } } Circle_item = class Menuaction "_Circle" "find circle Hough transform" { action a = class _result { _vislevel = 3; scale = Expression "Scale down parameter space by" 10; min_radius = Expression "Minimum radius" 10; max_radius = Expression "Maximum radius" 30; _result = map_unary circle a { circle a = hough_circle (to_real scale) (to_real min_radius) (to_real max_radius) a; } } } } Filter_coordinate_item = class Menupullright "_Coordinate Transform" "various coordinate transforms" { // run a function which wants a complex arg on a non-complex two-band // image run_cmplx fn x = re x' ++ im x' { x' = fn (x?0, x?1); } Polar_item = class Menuaction "_Polar" "transform to polar coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_polar a { to_polar im = mapim interp.value map' im { // xy image, origin in the centre, scaled to fit image to // a circle xy = make_xy im.width im.height; xy' = xy - Vector [im.width / 2, im.height / 2]; scale = min [im.width, im.height] / im.width; xy'' = 2 * xy' / scale; // to polar, scale vertical axis to 360 degrees map = run_cmplx polar xy''; map' = map * Vector [1, im.height / 360]; } } } } Rectangular_item = class Menuaction "_Rectangular" "transform to rectangular coordinates" { action a = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary to_rect a { to_rect im = mapim interp.value map'' im { // xy image, vertical scaled to 360 degrees xy = make_xy im.width im.height; xy' = xy * Vector [1, 360 / im.height]; // to rect, scale to image rect map = run_cmplx rectangular xy'; scale = min [im.width, im.height] / im.width; map' = map * scale / 2; map'' = map' + Vector [im.width / 2, im.height / 2]; } } } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "Blend _Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } Autotrace_item = class Menuaction "_Trace" "convert a bitmap to an SVG file" { action x = class _result { _vislevel = 3; despeckle = Scale "Despeckle level" 1 20 1; line = Scale "Line threshold" 1 20 1; center = Toggle "Trace centreline" false; scale = Scale "SVG scale" 0.1 10 1; command = "autotrace %s " ++ join_sep " " [ofmt, ofile, desp, lint, cent] { prog = search_for_error "autotrace"; ofmt = "-output-format svg"; ofile = "-output-file %s"; desp = "-despeckle-level " ++ print despeckle.value; lint = "-line-threshold " ++ print line.value; cent = if center then "-centerline " else ""; } _result = Image output { [output] = vips_call "system" [command] [$in => [x.value], $in_format => "%s.ppm", $out => true, $out_format => "%s.svg[scale=" ++ print scale.value ++ "]" ]; } } } nip2-8.7.1/share/nip2/compat/8.5/_joe_extra.def0000644000175000017500000003107513351443023015672 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Kernel_linear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use an Arrow or Region x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { im = x.image; mask = Image m { rx = x.region_rect, is_Region x = x; b = image_new im.width im.height 1 0 0 1 0 0 0; w = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0; m = insert_noexpand rx.nleft rx.ntop w b; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Kernel_linear f1 1 b1 {b1 = resize Kernel_linear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/8.5/Preferences.ws0000644000175000017500000010177213351443023015711 00000000000000 nip2-8.7.1/share/nip2/compat/8.5/Magick.def0000644000175000017500000014112713351443023014746 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate Magick.def 13-Apr-2014 snibgo Put "new image" items into sub-menu. New class VirtualPixlBack. 17-Apr-2014 snibgo Many small changes. A few new menu options. Created sub-menu for multi-input operations. 3-May-2014 jcupitt Put quotes around ( in shadow to help unix Last update: 17-Apr-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ // We don't need Noop. /*=== Magick_noop_item = class Menuaction "_Noop" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_testPar_item = class Menuaction "_TestPar" "no operation" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "( +clone ) +append ", "\"%s\"" ]; _result = Magick.system command x; } } /* Removed Read_item and Write_item, much better to use nip2 load/save image. * Plus they can load all libMagick formats anyway. */ // Put "new image" items into sub-menu Magick_NewImageMenu_item = class Menupullright "_New image" "make a new image" { Magick_newcanvas_item = class Menuaction "_Solid colour" "make image of solid colour" { action = class _result { _vislevel = 3; size = Magick.Size_widget; colour = Magick.generalcol_widget; command = Magick.command [ size._flag, "\"canvas:" ++ colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_builtin_item = class Menuaction "_Built-in image" "create a built-in image" { action = class _result { _vislevel = 3; builtin = Magick.builtin_widget; command = Magick.command [ builtin._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_gradient_item = class Menuaction "_Gradient" "make a linear gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; topColour = Magick.generalcol_widget; bottomColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"gradient:", topColour._flag, "-", bottomColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } Magick_hald_item = class Menuaction "_Hald-clut image" "create an identity hald-clut image" { action = class _result { _vislevel = 3; order = Expression "order" 8; command = Magick.command [ "hald:" ++ print order.expr, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_pattern_item = class Menuaction "_Pattern" "create pattern" { action = class _result { _vislevel = 3; size = Magick.Size_widget; pattern = Magick.pattern_widget; command = Magick.command [ size._flag, pattern._flag, "\"%s\"" ]; _result = Magick.system0 command; } } Magick_plasma_item = class Menuaction "_Plasma image" "create plasma image" { action = class _result { _vislevel = 3; size = Magick.Size_widget; // FIXME? ColourA-ColourB. // FIXME? Allow plasma:fractal? command = Magick.command [ size._flag, "plasma:", "\"%s\"" ]; _result = Magick.system0 command; } } Magick_radialgradient_item = class Menuaction "_Radial gradient" "make a radial gradient between two colours" { action = class _result { _vislevel = 3; size = Magick.Size_widget; innerColour = Magick.generalcol_widget; outerColour = Magick.generalcol_widget; command = Magick.command [ size._flag, concat ["\"radial-gradient:", innerColour._flag, "-", outerColour._flag, "\""], "\"%s\"" ]; _result = Magick.system0 command; } } } // end Magick_NewImageMenu_item Magick_MultiMenu_item = class Menupullright "_Multiple inputs" "make an image from multiple images" { Magick_composite_item = class Menuaction "_Composite" "composite two images (without mask)" { action x y = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_compositeMask_item = class Menuaction "_Composite masked" "composite two images (with mask)" { action x y z = class _result { _vislevel = 3; method = Magick.compose_widget; offsets = Magick.OffsetGeometry_widget; gravity = Magick.gravity_widget; command = Magick.command [ "\"%s\"", "\"%s\"", "\"%s\"", "-geometry", offsets._flag, gravity._flag, method._flag, "-composite", "\"%s\"" ]; _result = Magick.system3 command x y z; } } // FIXME: other operations like remap that take another image as arguments are: // mask (pointless?), texture, tile (pointless?) // FIXME: operations that take a filename that isn't an image: // cdl, profile Magick_clut_item = class Menuaction "_Clut" "replace values using second image as colour look-up table" { action x y = class _result { _vislevel = 3; // FIXME: uses -intensity "when mapping greyscale CLUT image to alpha channel if set by -channels" command = Magick.command [ "\"%s\"", "\"%s\"", "-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } Magick_haldclut_item = class Menuaction "_Hald clut" "replace values using second image as Hald colour look-up table" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "\"%s\"", "-hald-clut", "\"%s\"" ]; _result = Magick.system2 command x y; } } // Encipher and decipher: key files can be text or image files. Magick_encipher_item = class Menuaction "_Encipher/Decipher" "encipher or decipher an image image" { action x = class _result { _vislevel = 3; pathname = Pathname "Read key file" ""; isDecipher = Toggle "Decipher" false; command = Magick.command [ "\"%s\"", if pathname.value == "" then "" else ( ( if isDecipher then "-decipher " else "-encipher ") ++ ( "\"" ++ pathname.value ++ "\"" ) ), "\"%s\"" ]; _result = Magick.system command x; } } Magick_profile_item = class Menuaction "_Profile" "assigns/applies an ICC profile" { action x = class _result { _vislevel = 3; pathname1 = Pathname "Read profile file" ""; pathname2 = Pathname "Read profile file" ""; command = Magick.command [ "\"%s\"", if pathname1.value == "" then "" else ( "-profile " ++ "\"" ++ pathname1.value ++ "\""), if pathname2.value == "" then "" else ( "-profile " ++ "\"" ++ pathname2.value ++ "\""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_remap_item = class Menuaction "_Remap" "reduce colours to those in another image" { action x y = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-remap", "\"%s\"", "\"%s\"" ]; _result = Magick.system2 command x y; } } } // end Magick_MultiMenu_item Magick_image_type_item = class Menuaction "_Image Type" "change image type" { action x = class _result { _vislevel = 3; imagetype = Magick.imagetype_widget; command = Magick.command [ "\"%s\"", imagetype._flag, "\"%s\"" ]; _result = Magick.system command x; } } sep2 = Menuseparator; Magick_alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = Magick.alpha_widget; command = Magick.command [ "\"%s\"", alpha._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = Magick.text_widget; font = Magick.Font_widget; geometry = Magick.AnnotGeometry_widget; gravity = Magick.gravity_widget; foreground = Magick.foreground_widget; undercol = Magick.undercol_widget; antialias = Magick.antialias_widget; command = Magick.command [ "\"%s\"", font._flag, antialias._flag, gravity._flag, foreground._flag, undercol._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoGamma_item = class Menuaction "_AutoGamma" "automatic gamma" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-gamma", "\"%s\"" ]; _result = Magick.system command x; } } Magick_autoLevel_item = class Menuaction "_AutoLevel" "automatic level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-auto-level", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blurSharpMenu_item = class Menupullright "_Blur/Sharpen" "blur and sharpen" { Magick_adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; // note: adaptive-blur doesn't regard VP. command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-adaptive-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_blur_item = class Menuaction "_Blur" "blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gaussianBlur_item = class Menuaction "_Gaussian Blur" "blur with a Gaussian operator" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-gaussian-blur", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_motionBlur_item = class Menuaction "_Motion Blur" "simulate motion blur" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; channels = Magick.ch_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-motion-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotationalBlur_item = class Menuaction "_RotationalBlur" "blur around the centre" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; angle = Scale "angle (degrees)" (-360) 360 20; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-radial-blur", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_selectiveBlur_item = class Menuaction "_Selective Blur" "blur where contrast is less than or equal to threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; threshold = Scale "Threshold (percent)" 0 100 50; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", intensity._flag, virtpixback._flag, channels._flag, "-selective-blur", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print threshold.value ++ "%%", "\"%s\"" ]; _result = Magick.system command x; } } sep1 = Menuseparator; Magick_adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-adaptive-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sharpen_item = class Menuaction "_Sharpen" "sharpen" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-sharpen", print radius.value ++ "x" ++ print sigma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_unsharpen_item = class Menuaction "_Unsharp" "sharpen with unsharp mask" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; channels = Magick.channels_widget; gain = Scale "Gain" (-10) 10 1; threshold = Scale "Threshold" 0 1 0.05; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, channels._flag, "-unsharp", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print gain.value ++ "+" ++ print threshold.value, "\"%s\"" ]; _result = Magick.system command x; } } } // end BlurSharpMenu_item Magick_border_item = class Menuaction "_Border" "add border of given colour" { action x = class _result { _vislevel = 3; compose = Magick.compose_widget; width = Expression "Width" 3; bordercol = Magick.bordercol_widget; command = Magick.command [ "\"%s\"", compose._flag, bordercol._flag, "-border", print width.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_brightCont_item = class Menuaction "_Brightness-contrast" "adjust the brightness and/or contrast" { action x = class _result { _vislevel = 3; bri = Scale "brightness" (-100) 100 0; con = Scale "contrast" (-100) 100 0; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-brightness-contrast", print bri.value ++ "x" ++ print con.value, "\"%s\"" ]; _result = Magick.system command x; } } // Note: canny requires ImageMagick 6.8.9-0 or later. Magick_canny_item = class Menuaction "_Canny" "detect a wide range of edges" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; lowPc = Scale "lower percent" 0 100 10; highPc = Scale "lower percent" 0 100 10; command = Magick.command [ "\"%s\"", "-canny", concat ["\"", print radius.value ++ "x" ++ print sigma.value ++ "+" ++ print lowPc.value ++ "%%+" ++ print highPc.value ++ "%%" ++ "\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_charcoal_item = class Menuaction "_Charcoal" "simulate a charcoal drawing" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; factor = Scale "factor" 0 50 1; command = Magick.command [ "\"%s\"", intensity._flag, "-charcoal", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_chop_item = class Menuaction "_Chop" "remove pixels from the interior" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-chop", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorize_item = class Menuaction "_Colorize" "colorize by given amount" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; val = Scale "value" 0 100 100; command = Magick.command [ "\"%s\"", foreground._flag, "-colorize", print val.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colors_item = class Menuaction "_Colors" "reduce number of colors" { action x = class _result { _vislevel = 3; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; quantize = Magick.colorspace_widget; colors = Expression "Colours" 3; command = Magick.command [ "\"%s\"", "-quantize", quantize._flag, "-treedepth", print treedepth.expr, dither._flag, "-colors", print colors.expr, "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: color-matrix? Magick_colorspace_item = class Menuaction "_Colourspace" "convert to arbitrary colourspace" { action x = class _result { _vislevel = 3; colsp = Magick.colorspace_widget; command = Magick.command [ "\"%s\"", "-colorspace", colsp._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_colorspaceGray_item = class Menuaction "_Colourspace gray" "convert to gray using given intensity method" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; command = Magick.command [ "\"%s\"", intensity._flag, "-colorspace gray", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrast_item = class Menuaction "_Contrast" "increase or reduce the contrast" { action x = class _result { _vislevel = 3; isReduce = Toggle "reduce contrast" false; command = Magick.command [ "\"%s\"", (if isReduce then "+" else "-") ++ "contrast", "\"%s\"" ]; _result = Magick.system command x; } } Magick_contrastStretch_item = class Menuaction "_Contrast stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-contrast-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: convolve (bias, kernel) Magick_crop_item = class Menuaction "_Crop" "cut out a rectangular region" { action x = class _result { _vislevel = 3; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", gravity._flag, "-crop", geometry._flag, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_deskew_item = class Menuaction "_Deskew" "straighten the image" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; // FIXME: toggle auto-crop? command = Magick.command [ "\"%s\"", "-deskew", "\"" ++ print threshold.value ++ "%%\"", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_despeckle_item = class Menuaction "_Despeckle" "reduce the speckles" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-despeckle", "\"%s\"" ]; _result = Magick.system command x; } } Magick_distort_item = class Menuaction "_Distort" "distort using a method and arguments" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; distort = Magick.distort_widget; args = String "Arguments" "1,0"; isPlus = Toggle "Extend to show entire image" false; command = Magick.command [ "\"%s\"", virtpixback._flag, (if isPlus then "+" else "-") ++ "distort", distort._flag, args.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_draw_item = class Menuaction "_Draw" "annotate with one or more graphic primitives" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; args = String "Arguments" "line 0,0 9,9 rectangle 10,10 20,20"; command = Magick.command [ "\"%s\"", foreground._flag, "-draw", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_edge_item = class Menuaction "_Edge" "detect edges" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-edge", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_emboss_item = class Menuaction "_Emboss" "emboss" { action x = class _result { _vislevel = 3; rad = Expression "Radius" 3; command = Magick.command [ "\"%s\"", "-emboss", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_enhance_item = class Menuaction "_Enhance" "enhance a noisy image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-enhance", "\"%s\"" ]; _result = Magick.system command x; } } Magick_equalize_item = class Menuaction "_Equalize" "equalize the histogram" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-equalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_evaluate_item = class Menuaction "_Evaluate" "evaluate an expression on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; operation = Magick.evaluate_widget; val = Expression "value" 5; isPc = Toggle "Value is percent" false; command = Magick.command [ "\"%s\"", channels._flag, operation._flag, print val.expr ++ if isPc then "%%" else "", "\"%s\"" ]; _result = Magick.system command x; } } Magick_extent_item = class Menuaction "_Extent" "set the image size and offset" { action x = class _result { _vislevel = 3; background = Magick.background_widget; compose = Magick.compose_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, background._flag, gravity._flag, "-extent", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_FlipFlopMenu_item = class Menupullright "_Flip/flop" "flip/flop/transverse/transpose" { Magick_flip_item = class Menuaction "_Flip vertically" "mirror upside-down" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flip", "\"%s\"" ]; _result = Magick.system command x; } } Magick_flop_item = class Menuaction "_Flop horizontally" "mirror left-right" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-flop", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transpose_item = class Menuaction "_Transpose" "mirror along the top-left to bottom-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transpose +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_transverse_item = class Menuaction "_Transverse" "mirror along the bottom-left to top-right diagonal" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-transverse +repage", "\"%s\"" ]; _result = Magick.system command x; } } } // end Magick_FlipFlopMenu_item Magick_floodfill_item = class Menuaction "_Floodfill" "recolour neighbours that match" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; fuzz = Magick.fuzz_widget; coordinate = Magick.coordinate_widget; // -draw "color x,y floodfill" command = Magick.command [ "\"%s\"", foreground._flag, "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-draw \" color", coordinate._flag, "floodfill \"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_frame_item = class Menuaction "_Frame" "surround with border or beveled frame" { action x = class _result { _vislevel = 3; border = Magick.bordercol_widget; compose = Magick.compose_widget; matte = Magick.mattecol_widget; geometry = Magick.FrameGeometry_widget; command = Magick.command [ "\"%s\"", compose._flag, border._flag, matte._flag, "-frame", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_function_item = class Menuaction "_Function" "evaluate a function on each pixel channel" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; function = Magick.function_widget; // FIXME: explain values; use sensible defaults. values = String "values" "0,0,0,0"; command = Magick.command [ "\"%s\"", channels._flag, "-function", function._flag, values.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_fx_item = class Menuaction "_Fx" "apply a mathematical expression" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; interpolate = Magick.interpolate_widget; virtpixback = Magick.VirtualPixelBack_widget; args = String "Expression" "u*1/2"; command = Magick.command [ "\"%s\"", channels._flag, interpolate._flag, virtpixback._flag, "-fx", concat ["\"", args.value, "\""], "\"%s\"" ]; _result = Magick.system command x; } } Magick_gamma_item = class Menuaction "_Gamma" "apply a gamma correction" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; gamma = Magick.gamma_widget; command = Magick.command [ "\"%s\"", channels._flag, "-gamma", print gamma.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradient_item = class Menuaction "_Gradient" "apply a linear gradient" { action x = class _result { _vislevel = 3; colourA = Magick.generalcol_widget; colourB = Magick.generalcol_widget; position = Option "colourA is at" [ "top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"] 0; _baryArg = concat ["0,0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 0 = concat ["0,0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 1 = concat ["0,0,", colourA._flag, " %%[fx:w-1],0,", colourB._flag], position.value == 2 = concat ["0,0,", colourB._flag, " %%[fx:w-1],0,", colourA._flag], position.value == 3 = concat ["0,0,", colourA._flag, " %%[fx:w-1],%%[fx:h-1],", colourB._flag], position.value == 4 = concat ["%%[fx:w-1],0,", colourA._flag, " 0,%%[fx:h-1],", colourB._flag], position.value == 5 = concat ["%%[fx:w-1],0,", colourB._flag, " 0,%%[fx:h-1],", colourA._flag], position.value == 6 = concat ["0,0,", colourB._flag, " %%[fx:w-1],%%[fx:h-1],", colourA._flag], position.value == 7 = "dunno"; command = Magick.command [ "\"%s\"", "-sparse-color barycentric \"" ++ _baryArg ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_gradientCorn_item = class Menuaction "_Gradient corners" "apply a bilinear gradient between the corners" { action x = class _result { _vislevel = 3; colour_top_left = Magick.generalcol_widget; colour_top_right = Magick.generalcol_widget; colour_bottom_left = Magick.generalcol_widget; colour_bottom_right = Magick.generalcol_widget; command = Magick.command [ "\"%s\"", "-sparse-color bilinear \"" ++ "0,0," ++ colour_top_left._flag ++ ",%%[fx:w-1],0" ++ colour_top_right._flag ++ ",0,%%[fx:h-1]" ++ colour_bottom_left._flag ++ ",%%[fx:w-1],%%[fx:h-1]" ++ colour_bottom_right._flag ++ "\"", "+depth", "\"%s\"" ]; _result = Magick.system command x; } } Magick_histogram_item = class Menuaction "_Histogram" "make a histogram image" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-define histogram:unique-colors=false histogram:" ++ "\"%s\"" ]; _result = Magick.system command x; } } Magick_implode_item = class Menuaction "_Implode" "implode pixels about the center" { action x = class _result { _vislevel = 3; factor = Scale "factor" 0 20 1; interpolate = Magick.interpolate_widget; // FIXME: virtual-pixel? command = Magick.command [ "\"%s\"", interpolate._flag, "-implode", print factor.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_level_item = class Menuaction "_Level" "adjust the level of channels" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "black point" (-100) 200 0; wht = Scale "white point" (-100) 200 100; gam = Scale "gamma" 0 30 1; isPc = Toggle "Levels are percent" true; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level", "\"" ++ print blk.value ++ "," ++ print wht.value ++ (if isPc then "%%" else "") ++ "," ++ print gam.value ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_levelCols_item = class Menuaction "_Level colors" "adjust levels to given colours" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; colour_black = Magick.generalcol_widget; colour_white = Magick.generalcol_widget; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "level-colors", "\"" ++ colour_black._flag ++ "," ++ colour_white._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_linearStretch_item = class Menuaction "_Linear stretch" "stretches tones, making some black/white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; blk = Scale "percent to make black" 0 100 0; wht = Scale "percent to make white" 0 100 0; command = Magick.command [ "\"%s\"", channels._flag, "-linear-stretch", "\"" ++ print blk.value ++ "x" ++ print wht.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_magnify_item = class Menuaction "_Magnify" "double the size of the image with pixel art scaling" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-magnify", "\"%s\"" ]; _result = Magick.system command x; } } Magick_modulate_item = class Menuaction "_Modulate" "modulate brightness, saturation and hue" { action x = class _result { _vislevel = 3; modcolsp = Magick.ModColSp_widget; bright = Scale "brightness" 0 200 100; sat = Scale "saturation" 0 200 100; hue = Scale "hue" 0 200 100; command = Magick.command [ "\"%s\"", modcolsp._flag, "-modulate", print bright.value ++ "," ++ print sat.value ++ "," ++ print hue.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_monochrome_item = class Menuaction "_Monochrome" "transform to black and white" { action x = class _result { _vislevel = 3; // FIXME: also intensity? intensity = Magick.intensity_widget; treedepth = Expression "Treedepth" 8; dither = Magick.dither_widget; command = Magick.command [ "\"%s\"", intensity._flag, dither._flag, "-treedepth", print treedepth.expr, "-monochrome", "\"%s\"" ]; _result = Magick.system command x; } } Magick_morphology_item = class // See http://www.imagemagick.org/Usage/morphology/ Menuaction "_Morphology" "apply a morphological method" { action x = class _result { _vislevel = 3; method = Magick.morphmeth_widget; iter = Expression "Iterations (-1=repeat until done)" 1; kernel = Magick.kernel_widget; // FIXME: custom kernel eg "3x1+2+0:1,0,0" // width x height + offsx + offsy : {w*h values} // each value is 0.0 to 1.0 or "NaN" or "-" // kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0 // but // ring takes: radius1, radius2, scale // rectangle and comet take: width x height + offsx + offsy // blur takes: radius x sigma // FIXME: for now, simply allow any string input. kernel_arg = String "Kernel arguments" ""; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-morphology", method._flag ++ ":" ++ print iter.expr, kernel._flag ++ (if kernel_arg.value == "" then "" else ":") ++ kernel_arg.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_negate_item = class Menuaction "_Negate" "negate" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", channels._flag, "-negate", "\"%s\"" ]; _result = Magick.system command x; } } Magick_addNoise_item = class Menuaction "_add Noise" "add noise" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; attenuate = Scale "attenuate" 0 1.0 1.0; noise = Magick.noise_widget; command = Magick.command [ "\"%s\"", channels._flag, "-attenuate", print attenuate.value, noise._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_normalize_item = class Menuaction "_Normalize" "normalize" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-normalize", "\"%s\"" ]; _result = Magick.system command x; } } Magick_opaque_item = class Menuaction "_Opaque" "change this colour to the fill colour" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; fill = Magick.foreground_widget; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", fill._flag, channels._flag, "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "opaque", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_paint_item = class Menuaction "_Paint" "simulate an oil painting" { action x = class _result { _vislevel = 3; rad = Expression "radius" 10; command = Magick.command [ "\"%s\"", "-paint", print rad.expr, "\"%s\"" ]; _result = Magick.system command x; } } /*=== FIXME Bug; remove for now. Polaroid_item = class Menuaction "_Polaroid" "simulate a polaroid picture" { action x = class _result { _vislevel = 3; angle = Scale "angle" (-90) 90 20; command = Magick.command [ "\"%s\"", "-polaroid", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } ===*/ Magick_posterize_item = class Menuaction "_Posterize" "reduce to (n) levels per channel" { action x = class _result { _vislevel = 3; levels = Expression "levels" 3; command = Magick.command [ "\"%s\"", "-posterize", print levels.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_raise_item = class Menuaction "_Raise" "lighten or darken image edges" { action x = class _result { _vislevel = 3; thk = Expression "Thickness" 3; command = Magick.command [ "\"%s\"", "-raise", print thk.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_resize_item = class Menuaction "_Resize" "resize to given width and height" { action x = class _result { _vislevel = 3; filter = Magick.filter_widget; type = Magick.ResizeType_widget; width = Scale "Width" 1 100 10; height = Scale "Height" 1 100 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", filter._flag, "-" ++ type._flag, "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "!") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_roll_item = class Menuaction "_Roll" "roll an image horizontally or vertically" { action x = class _result { _vislevel = 3; rollx = Expression "X" 3; rolly = Expression "Y" 3; command = Magick.command [ "\"%s\"", "-roll", (if rollx.expr >= 0 then "+" else "") ++ print rollx.expr ++ (if rolly.expr >= 0 then "+" else "") ++ print rolly.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_rotate_item = class Menuaction "_Rotate" "rotate" { action x = class _result { _vislevel = 3; angle = Scale "angle (degrees)" (-360) 360 20; virtpixback = Magick.VirtualPixelBack_widget; command = Magick.command [ "\"%s\"", virtpixback._flag, "+distort", "SRT", print angle.value, "+repage", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -segment, but cluster-threshold should be percentage of image area. Magick_sepia_item = class Menuaction "_Sepia tone" "simulate a sepia-toned photo" { action x = class _result { _vislevel = 3; threshold = Scale "Threshold (percent)" 0 100 80; command = Magick.command [ "\"%s\"", "-sepia-tone", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shade_item = class Menuaction "_Shade" "shade with a distant light source" { action x = class _result { _vislevel = 3; azimuth = Scale "Azimuth (degrees)" (-360) 360 0; elevation = Scale "Elevation (degrees)" 0 90 45; command = Magick.command [ "\"%s\"", "-shade", print azimuth.value ++ "x" ++ print elevation.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_shadow_item = class Menuaction "_Shadow" "simulate a shadow" { action x = class _result { _vislevel = 3; shadowCol = Magick.generalcol_widget; opacity = Scale "Opacity (percent)" 0 100 75; sigma = Scale "Sigma" 0 30 2; // FIXME: make offsets a single widget? offsx = Scale "X-offset" (-20) 20 4; offsy = Scale "Y-offset" (-20) 20 4; arePc = Toggle "offsets are percentages" false; // FIXME: raw operation creates page offset, which vips dislikes. // So we take this futher, compositing with source. command = Magick.command [ "\"%s\"", "\"(\" +clone", "-background", "\"" ++ shadowCol._flag ++ "\"", "-shadow", concat [ "\"", print opacity.value, "x", print sigma.value, (if offsx.value >= 0 then "+" else ""), print offsx.value, (if offsy.value >= 0 then "+" else ""), print offsy.value, (if arePc then "%%" else ""), "\"" ], "\")\" +swap -background None -layers merge", "+repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shave_item = class Menuaction "_Shave" "shave pixels from the edges" { action x = class _result { _vislevel = 3; width = Scale "Width" 0 50 10; height = Scale "Height" 0 50 10; isPc = Toggle "Width and height are percent" false; command = Magick.command [ "\"%s\"", "-shave", "\"" ++ print width.value ++ "x" ++ print height.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_shear_item = class Menuaction "_Shear" "shear along the x-axis and/or y-axis" { action x = class _result { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-shear", print shearX.expr ++ "x" ++ print shearY.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_sigmoid_item = class Menuaction "_Sigmoid" "increase or decrease mid-tone contrast sigmoidally" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; contrast = Scale "contrast" 0 30 3; midpoint = Scale "mid-point (percent)" 0 100 50; isInv = Toggle "Invert effect" false; command = Magick.command [ "\"%s\"", channels._flag, (if isInv then "+" else "-") ++ "sigmoidal-contrast", "\"" ++ print contrast.value ++ "x" ++ print midpoint.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_sketch_item = class Menuaction "_Sketch" "simulate a pencil sketch" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; angle = Scale "angle" (-360) 360 0; command = Magick.command [ "\"%s\"", "-sketch", print radius.value ++ "x" ++ print sigma.value ++ (if angle >= 0 then ("+" ++ print angle.value) else ""), "\"%s\"" ]; _result = Magick.system command x; } } Magick_solarize_item = class Menuaction "_Solarize" "negate all pixels above a threshold level" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-solarize", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } // FIXME: -sparse-color needs abitrary list of {x,y,colour}. Magick_splice_item = class Menuaction "_Splice" "splice a colour into the image" { action x = class _result { _vislevel = 3; background = Magick.background_widget; gravity = Magick.gravity_widget; geometry = Magick.WhxyGeometry_widget; command = Magick.command [ "\"%s\"", background._flag, gravity._flag, "-splice", geometry._flag, "\"%s\"" ]; _result = Magick.system command x; } } Magick_spread_item = class Menuaction "_Spread" "displace pixels by random amount" { action x = class _result { _vislevel = 3; virtpixback = Magick.VirtualPixelBack_widget; amount = Expression "Amount (pixels)" 5; command = Magick.command [ "\"%s\"", virtpixback._flag, "-spread", print amount.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_statistic_item = class Menuaction "_Statistic" "replace each pixel with statistic from neighbourhood" { action x = class _result { _vislevel = 3; width = Expression "Width" 5; height = Expression "Height" 5; statisticType = Magick.StatType_widget; command = Magick.command [ "\"%s\"", "-statistic", statisticType._flag, print width.expr ++ "x" ++ print height.expr, "\"%s\"" ]; _result = Magick.system command x; } } Magick_swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = Magick.angle_widget; command = Magick.command [ "\"%s\"", "-swirl", print angle.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_thresholdMenu_item = class Menupullright "_Threshold" "make black or white" { Magick_threshold_item = class Menuaction "_Threshold" "apply black/white threshold" { action x = class _result { _vislevel = 3; intensity = Magick.intensity_widget; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", intensity._flag, channels._flag, "-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_blackThreshold_item = class Menuaction "_Black threshold" "where below threshold set to black" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-black-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_whiteThreshold_item = class Menuaction "_White threshold" "where above threshold set to white" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; threshold = Scale "Threshold (percent)" 0 100 50; command = Magick.command [ "\"%s\"", channels._flag, "-white-threshold", "\"" ++ print threshold.value ++ "%%\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_latThreshold_item = class Menuaction "_Local Adaptive Threshold" "where above average plus offset set to white, otherwise black" { action x = class _result { _vislevel = 3; width = Expression "Width" 10; height = Expression "Height" 10; offset = Scale "Offset (percent)" (-100) 100 0; // note: "-lat" doesn't respond to channels command = Magick.command [ "\"%s\"", "-lat", concat ["\"", print width.expr, "x", print height.expr, (if offset.value >= 0 then "+" else ""), print offset.value, "%%\"" ], "\"%s\"" ]; _result = Magick.system command x; } } Magick_randThreshold_item = class Menuaction "_Random Threshold" "between specified limits, apply random threshold" { action x = class _result { _vislevel = 3; channels = Magick.channels_widget; low = Scale "Low threshold" 0 100 10; high = Scale "High threshold" 0 100 90; isPc = Toggle "Thresholds are percent" true; command = Magick.command [ "\"%s\"", channels._flag, "-random-threshold", "\"" ++ print low.value ++ "x" ++ print high.value ++ (if isPc then "%%" else "") ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } } // end ThresholdMenu_item // Note: alternatives include: // convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif Magick_tile_item = class Menuaction "_Tile" "fill given size with tiled image" { action x = class _result { _vislevel = 3; size = Magick.Size_widget; command = Magick.command [ size._flag, "tile:" ++ "\"%s\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_tint_item = class Menuaction "_Tint" "apply a tint" { action x = class _result { _vislevel = 3; foreground = Magick.foreground_widget; amount = Scale "amount (percent)" 0 100 50; command = Magick.command [ "\"%s\"", foreground._flag, "-tint", // snibgo note: although the amount is a percentage, it doesn't need "%" character. print amount.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_transparent_item = class Menuaction "_Transparent" "make this colour transparent" { action x = class _result { _vislevel = 3; changeColour = Magick.changeCol_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print changeColour.fuzz.value ++ "%%\"", (if changeColour.nonMatch then "+" else "-") ++ "transparent", "\"" ++ changeColour.colour._flag ++ "\"", "\"%s\"" ]; _result = Magick.system command x; } } Magick_trim_item = class Menuaction "_Trim" "trims away border" { action x = class _result { _vislevel = 3; fuzz = Magick.fuzz_widget; command = Magick.command [ "\"%s\"", "-fuzz", "\"" ++ print fuzz.value ++ "%%\"", "-trim +repage", "\"%s\"" ]; _result = Magick.system command x; } } Magick_uniqueCols_item = class Menuaction "_Unique colours" "discard all but one of any pixel color" { action x = class _result { _vislevel = 3; command = Magick.command [ "\"%s\"", "-unique-colors", "\"%s\"" ]; _result = Magick.system command x; } } Magick_vignette_item = class Menuaction "_Vignette" "soften the edges in vignette style" { action x = class _result { _vislevel = 3; radius = Magick.blur_rad_widget; sigma = Magick.sigma_widget; rx = Scale "Rolloff x (percent)" 0 100 10; ry = Scale "Rolloff y (percent)" 0 100 10; background = Magick.background_widget; command = Magick.command [ "\"%s\"", background._flag, "-vignette", print radius.value ++ "x" ++ print sigma.value ++ (if rx.value >= 0 then "+" else "") ++ print rx.value ++ (if ry.value >= 0 then "+" else "") ++ print ry.value, "\"%s\"" ]; _result = Magick.system command x; } } Magick_wave_item = class Menuaction "_Wave" "shear the columns into a sine wave" { action x = class _result { _vislevel = 3; amplitude = Scale "Amplitude (pixels)" 0 100 10; wavelength = Scale "Wavelength (pixels)" 0 100 10; command = Magick.command [ "\"%s\"", "-wave", print amplitude.value ++ "x" ++ print wavelength.value, "\"%s\"" ]; _result = Magick.system command x; } } nip2-8.7.1/share/nip2/compat/8.5/Colour.def0000644000175000017500000003773013351443023015022 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } CCT_colour = class Menuaction (_ "Colour from CCT") (_ "pick colour by CCT") { action = widget 6500; widget x = class _result { _vislevel = 3; T = Scale "CCT" 1800 25000 x; _result = colour_from_temp (to_real T); Colour_edit space value = widget (temp_from_colour (Colour space value)); } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } sep1 = Menuseparator; CCT_item = class Menuaction (_ "Calculate temperature") (_ "estimate CCT using the McCamy approximation") { action z = map_unary temp_from_colour z; } Colour_item = Colour_new_item.CCT_colour; } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = print_profile, has_type image && get_type image == Image_type.CMYK && has_bands image && get_bands image >= 4 = monitor_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; measure = Scale (_ "Measure area (%)") 1 100 50; // get a representative image from an arg get_image x = get_image x.value?0, is_Group x = x; _im = get_image x; sample = measure_draw (to_real pacross) (to_real pdown) (to_real measure) _im; _result = map_unary chart x { chart in = measure_sample (to_real pacross) (to_real pdown) (to_real measure) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/8.5/_joe_utilities.def0000644000175000017500000005054213351443023016562 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/8.5/_Object.def0000644000175000017500000002600513351443023015115 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/8.5/Object.def0000644000175000017500000000220513351443023014752 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/8.5/Math.def0000644000175000017500000003162513351443023014445 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_AND" "bitwise AND of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_OR" "bitwise OR of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "_XOR" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_NOT" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Bandand_item = Image_band_item.Bandand_item; Bandor_item = Image_band_item.Bandor_item; } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Skew_item = class Menuaction "S_kew" "skew of image or list or vector" { action a = map_unary skew a; } Kurtosis_item = class Menuaction "Kurtosis" "kurtosis of image or list or vector" { action a = map_unary kurtosis a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/8.5/_generate.def0000644000175000017500000000755513351443023015512 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } mkim options x y b = Image (image_new x y b (opt $format) (opt $coding) (opt $type) (opt $pixel) (opt $xoffset) (opt $yoffset)) { opt = get_option options [ $format => Image_format.UCHAR, $coding => Image_coding.NOCODING, $type => Image_type.sRGB, $pixel => 0, $xoffset => 0, $yoffset => 0 ]; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } /* Make a colour from a temperature. */ colour_from_temp T = error (_ "T out of range"), T < 1667 || T > 25000 = Colour "Yxy" [50, x, y] { // Kim et all approximation // see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation x = -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 + 0.8776956 * 10 ** 3 / T + 0.179910, T < 4000 = -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 + 0.2226347 * 10 ** 3 / T + 0.240390; y = -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + 2.18555832 * x - 0.20219638, T < 2222 = -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867, T < 4000 = 3.0817580 * x ** 3 - 5.87338670 * x ** 2 + 3.75112997 * x - 0.37001483; } temp_from_colour z = T { c = colour_transform_to Image_type.YXY (to_colour z); x = c.value?1; y = c.value?2; // McCamy's approximation, see eg. // http://en.wikipedia.org/wiki/Color_temperature#Approximation xe = 0.332; ye = 0.1858; n = (x - xe) / (y - ye); T = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33; } nip2-8.7.1/share/nip2/compat/8.5/_stdenv.def0000644000175000017500000020217013351443023015211 00000000000000/* optional args to functions */ get_option options defaults f = error (_ "unknown parameter " ++ f), hits == [] = hits?0 { hits = [v :: [n, v] <- options ++ defaults; n == f]; } /* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } bandand x = oo_unary_function bandand_op x, is_class x = foldr1 bitwise_and (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandand") { bandand_op = Operator "bandand" bandand Operator_type.COMPOUND_REWRAP false; } bandor x = oo_unary_function bandor_op x, is_class x = foldr1 bitwise_or (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandor") { bandor_op = Operator "bandor" bandor Operator_type.COMPOUND_REWRAP false; } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } skew x = oo_unary_function skew_op x, is_class x = sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x = sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "skew") { skew_op = Operator "skew" skew Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = w * h * b, is_image x' = len x'; } kurtosis x = oo_unary_function kurtosis_op x, is_class x = sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x = sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "kurtosis") { kurtosis_op = Operator "kurtosis" kurtosis Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = len x', is_list x'; = w * h * b; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_tile_cache_random x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } decode im = oo_unary_function decode_op im, is_class im = decode_im im, is_image im = error (_ "bad arguments to " ++ "decode") { decode_op = Operator "decode" decode Operator_type.COMPOUND_REWRAP false; decode_im im = im_LabQ2Lab im, get_coding im == Image_coding.LABPACK = im_rad2float im, get_coding im == Image_coding.RAD = im; } measure_draw across down measure image = mark { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; x = map (extract 0) cods; y = map (extract 1) cods; outer = mkim [$pixel => 255] sample_width sample_height 1; inner = mkim [] (sample_width - 4) (sample_height - 4) 1; patch = insert 2 2 inner outer; bg = mkim [] image.width image.height 1; mask = Image (im_insertset bg.value patch.value x y); image' = colour_transform_to Image_type.sRGB image; mark = if mask then Vector [0, 255, 0] else image'; } measure_sample across down measure image = measures { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; image' = decode image; patches = map (\p extract_area p?0 p?1 sample_width sample_height image') cods; measures = Matrix (map (map mean) (map bandsplit patches)); } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_inv hist = oo_unary_function hist_inv_op hist, is_class hist = inv hist, is_image hist = error (_ "bad arguments to " ++ "hist_inv") { hist_inv_op = Operator "hist_inv" hist_inv Operator_type.COMPOUND_REWRAP false; inv im = im_invertlut (to_matrix im''') len { // need a vertical doublemask im' = rot90 im, get_width im > 1 && get_height im == 1 = im, get_width im == 1 && get_height im > 1 = error (_ "not a hist"); len = get_height im'; // values must be scaled to 0 - 1 im'' = im' / (max im'); // add an index column on the left // again, must be in 0-1 y = ((make_xy 1 len)?1) / len; im''' = y ++ im''; } } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h l image = oo_unary_function hist_equalize_local_op image, is_class image = out, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h l) Operator_type.COMPOUND_REWRAP false; [out] = vips_call "hist_local" [image, to_real w, to_real h] [$max_slope => to_real l]; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } reduce kernel xshr yshr image = oo_unary_function reduce_op image, is_class image = reduce_im image, is_image image = error (_ "bad arguments to " ++ "reduce") { reduce_op = Operator "reduce" reduce_im Operator_type.COMPOUND_REWRAP false; reduce_im im = out { [out] = vips_call "reduce" [im, xshr, yshr] [$kernel => kernel.value]; } } similarity interpolate scale angle image = oo_unary_function similarity_op image, is_class image = similarity_im image, is_image image = error (_ "bad arguments to " ++ "similarity") { similarity_op = Operator "similarity" similarity_im Operator_type.COMPOUND_REWRAP false; similarity_im im = out { [out] = vips_call "similarity" [im] [ $interpolate => interpolate.value, $scale => scale, $angle => angle ]; } } resize kernel xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; is_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn // everything else ... we just pass on to vips_resize() = vips_resize kernel xfac' yfac' im { vips_resize kernel hscale vscale im = out { [out] = vips_call "resize" [im, hscale] [$vscale => vscale, $kernel => kernel.value]; } } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C * * Also calculate R2, see eg.: * https://en.wikipedia.org/wiki/Coefficient_of_determination */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } ss = len xes; sx = sum xes; sy = sum yes; my = sy / ss; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); R2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes]; } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; my = sy / len xes; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* One image in, one out. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } /* Two images in, one out. */ system_image2 command x1 x2 = oo_binary_function system_image2_op x1 x2, is_class x1 = oo_binary'_function system_image2_op x1 x2, is_class x2 = system x1 x2, is_image x1 && is_image x2 = error (_ "bad arguments to " ++ "system_image2") { system_image2_op = Operator "system_image2" (system_image2 command) Operator_type.COMPOUND_REWRAP false; system x1 x2 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Three images in, one out. */ system_image3 command x1 x2 x3 = oo_binary_function system_image2_op x2 x3, is_class x2 = oo_binary'_function system_image2_op x2 x3, is_class x3 = system x1 x2 x3, is_image x1 && is_image x2 && is_image x3 = error (_ "bad arguments to " ++ "system_image3") { system_image2_op = Operator "system_image2" (system_image3 command x1) Operator_type.COMPOUND_REWRAP false; system x1 x2 x3 = image_out { [image_out] = vips_call "system" [command] [ $in => [x1, x2, x3], $out => true, $out_format => "%s.tif", $in_format => "%s.tif" ]; } } /* Zero images in, one out. */ system_image0 command = Image image_out { [image_out] = vips_call "system" [command] [ $out => true, $out_format => "%s.tif" ]; } hough_line w h x = oo_unary_function hough_line_op x, is_class x = hline (to_real w) (to_real h) x, is_image x = error (_ "bad arguments to " ++ "hough_line") { hough_line_op = Operator "hough_line" (hough_line w h) Operator_type.COMPOUND_REWRAP false; hline w h x = pspace { [pspace] = vips_call "hough_line" [x] [ $width => w, $height => h ]; } } hough_circle s mn mx x = oo_unary_function hough_circle_op x, is_class x = hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x = error (_ "bad arguments to " ++ "hough_circle") { hough_circle_op = Operator "hough_circle" (hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false; hcircle s mn mx x = pspace { [pspace] = vips_call "hough_circle" [x] [ $scale => s, $min_radius => mn, $max_radius => mx ]; } } mapim interp ind in = oo_binary_function mapim_op ind in, is_class ind = oo_binary'_function mapim_op ind in, is_class in = mapim_fn ind in, is_image ind && is_image in = error (_ "bad arguments to " ++ "mapim") { mapim_op = Operator "mapim" (mapim interp) Operator_type.COMPOUND_REWRAP false; mapim_fn ind im = out { [out] = vips_call "mapim" [im, ind] [$interpolate => interp]; } } perlin cell width height = Image im { [im] = vips_call "perlin" [to_real width, to_real height] [ $cell_size => to_real cell ]; } worley cell width height = Image im { [im] = vips_call "worley" [to_real width, to_real height] [ $cell_size => to_real cell ]; } gaussnoise width height mean sigma = im { [im] = vips_call "gaussnoise" [to_real width, to_real height] [ $mean => to_real mean, $sigma => to_real sigma ]; } flattenimage bg x = oo_unary_function flatten_op x, is_class x = flt (to_vector bg) x, is_image x = error (_ "bad arguments to " ++ "flattenimage") { flatten_op = Operator "flatten" (flattenimage bg) Operator_type.COMPOUND_REWRAP false; flt bg x = out { [out] = vips_call "flatten" [x] [ $background => bg.value ]; } } premultiply x = oo_unary_function premultiply_op x, is_class x = prem x, is_image x = error (_ "bad arguments to " ++ "premultiply") { premultiply_op = Operator "premultiply" premultiply Operator_type.COMPOUND_REWRAP false; prem x = out { [out] = vips_call "premultiply" [x] [ ]; } } unpremultiply x = oo_unary_function unpremultiply_op x, is_class x = unprem x, is_image x = error (_ "bad arguments to " ++ "unpremultiply") { unpremultiply_op = Operator "unpremultiply" unpremultiply Operator_type.COMPOUND_REWRAP false; unprem x = out { [out] = vips_call "unpremultiply" [x] [ ]; } } hist_entropy x = oo_unary_function hist_entropy_op x, is_class x = entropy x, is_image x = error (_ "bad arguments to " ++ "hist_entropy") { hist_entropy_op = Operator "hist_entropy" hist_entropy Operator_type.COMPOUND_REWRAP false; entropy x = out { [out] = vips_call "hist_entropy" [x] [ ]; } } nip2-8.7.1/share/nip2/compat/8.5/Histogram.def0000644000175000017500000001636313351443023015513 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "_Identity" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_inv_item = class Menuaction "In_vert" "invert a histogram" { action x = map_unary hist_inv x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } Hist_entropy_item = class Menuaction "Entropy" "calculate histogram entropy" { action x = hist_entropy x; } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Kernel_linear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; caption = Expression "Chart caption" "none"; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; xcaption = Expression "X axis caption" "none"; ycaption = Expression "Y axis caption" "none"; series_captions = Expression "Series captions" ["Band 0"]; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range ++ captions; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; captions = concat (map test caption_options) ++ [$series_captions => series_captions.expr] { caption_options = [ $caption => caption.expr, $xcaption => xcaption.expr, $ycaption => ycaption.expr ]; test x = [], value == "none" = [option_name => value] { [option_name, value] = x; } } image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/8.5/Widgets.def0000644000175000017500000000235313351443023015156 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/8.5/_types.def0000644000175000017500000007115113351443023015055 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Kernel_type = class { NEAREST_NEIGHBOUR = 0; LINEAR = 1; CUBIC = 2; LANCZOS2 = 3; LANCZOS3 = 4; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map kernel numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Linear", _ "Cubic", _ "Lanczos, two lobes", _ "Lanczos, three lobes" ]; /* And to vips enum nicknames. */ types = [ "nearest", "linear", "cubic", "lanczos2", "lanczos3" ]; } Kernel type = class { value = Kernel_type.types?type; } Kernel_linear = Kernel Kernel_type.LINEAR; Kernel_picker default = class Kernel kernel.value { _vislevel = 2; kernel = Option "Kernel" Kernel_type.descriptions default; } Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; to_image dpi = extract_bands 0 3 (graph_export_image (to_real dpi) this); } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/8.5/Matrix.def0000644000175000017500000002573113351443023015021 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = identity (identity_matrix 5); identity v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix (identity_matrix (to_real s)), to_real s != len v; = Matrix v; Matrix_vips value scale offset filename display = identity value; } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = series (mkseries 0 1 5); mkseries s t e = transpose [[to_real s, to_real s + to_real t .. to_real e]]; series v = class _result { _vislevel = 3; _s = v?0?0; _t = v?1?0 - v?0?0; _e = (last v)?0; s = Expression "Start value" _s; t = Expression "Step by" _t; e = Expression "End value" _e; _result = Matrix (mkseries s t e), to_real s != _s || to_real t != _t || to_real e != _e = Matrix v; Matrix_vips value scale offset filename display = series value; } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = square (mksquare 5); mksquare s = replicate s (take s [1, 1 ..]); square v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix_con (sum v) 0 v, len v == to_real s = Matrix_con (sum m) 0 m { m = mksquare (to_real s); } Matrix_vips value scale offset filename display = square value; } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = circle (mkcircle 3); mkcircle r = map2 (map2 pyth) xes yes { line = [-r .. r]; xes = replicate (2 * r + 1) line; yes = transpose xes; pyth a b = 1, (a**2 + b**2) ** 0.5 <= r = 0; } circle v = class _result { _vislevel = 3; r = Expression "Radius" ((len v - 1) / 2); _result = Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1 = Matrix_con (sum m) 0 m { m = mkcircle (to_real r); } Matrix_vips value scale offset filename display = circle value; } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/8.5/Tasks.def0000644000175000017500000006407313351443023014644 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; measure = Scale (_ "Measure area (%)") 1 100 50; sample = measure_draw 6 4 (to_real measure) image; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linearize from chart greyscale", "Fit intercept from chart greyscale", "Linear input, set brightness from chart", "Linear input" ] 0; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure_sample 6 4 (to_real measure) image; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix [[0, 0], [1, 1]] { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map an image though the lineariser linear x = hist_map linearising_lut.value x, mode == 0 || mode == 1 = x; // map the chart measurements though the lineariser _camera' = (to_matrix @ linear @ to_image) _camera; // solve for RGB -> XYZ // normalise: the 2nd row is what makes Y, so divide by that to // get Y in 0-1. _pinv = (transpose _camera' * _camera') ** -1; _full_M = transpose (_pinv * (transpose _camera' * _true_XYZ)); M = _full_M / scale; scale = sum _full_M.value?1; // now turn the camera to LAB and calculate dE76 _camera'' = (to_matrix @ colour_transform Image_type.XYZ Image_type.LAB @ recomb M @ multiply scale @ to_image) _camera'; _dEs = map abs_vec (_camera'' - _true_Lab).value; avg_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } // normalise brightness ... in linear mode, we optionally don't // set the brightness from the Macbeth chart norm x = x * scale, mode != 3 = x; // convert RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ norm @ recomb M @ cast_float @ linear) image.value; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ calib.norm @ recomb calib.M @ cast_float @ calib.linear) image.value; } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Kernel_linear xfactor yfactor scale_im; _offset_im = resize Kernel_linear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/8.5/Makefile.am0000644000175000017500000000062113351443023015120 00000000000000startdir = $(pkgdatadir)/compat/8.5 start_DATA = \ Math.def \ Image.def \ Magick.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _magick.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/8.5/Makefile.in0000644000175000017500000003714413417043242015145 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/8.5 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/8.5 start_DATA = \ Math.def \ Image.def \ Magick.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ Preferences.ws \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _magick.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/8.5/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/8.5/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/8.5/_magick.def0000644000175000017500000005322113351443023015142 00000000000000/* ImageMagick operations edited by Alan Gibson (aka "snibgo"; snibgo at earthling dot net). 1-Apr-2014 Minor corrections to Geometry_widget and Alpha. Added loads of widgets and Menuactions. Not fully tested. 5-Apr-2014 Many more menu actions. Reorganised Magick menu. 10-Apr-2014 Many more menu actions. 11-Apr-2014 jcupitt Split to separate _magick.def Add 0-ary and 2-ary system Put utility funcs into a Magick class 11-Apr-2014 snibgo Added VirtualPixelBack for cases where background is only relevant when VP=Background 17-Apr-2014 snibgo Many small changes. 2-May-2014 jcupitt Added Magick.version 30-June-2014 Put single-quotes around command exe to help win 1-July-2014 Automatically fall back to gm if we can't find convert 17-July-2014 better GM support Last update: 17-July-2014. For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc. */ /* Put these in a class to avoid filling the main namespace with IM stuff. */ Magick = class { // first gm on path, or "" gm_path = search_for "gm"; // first convert on $PATH, or "" // we check for the convert we ship first convert_path = vips_convert, vips_convert != "" = search_for "convert" { // the convert we ship with the vips binary on some platforms, or "" vips_convert = search (path_absolute convert) { vipshome = path_parse (expand "$VIPSHOME"); convert = vipshome ++ ["bin", "convert" ++ expand "$EXEEXT"]; } } use_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK; // Are we in GM or IM mode? use_gm = true, use_gm_pref && gm_path != "" = false, !use_gm_pref && convert_path != "" = false, convert_path != "" = true, gm_path != "" = error "neither IM nor GM executable found"; command_path = gm_path, use_gm = convert_path; // try to get the version as eg. [6, 7, 7, 10] // GM versions are smaller, typically [1, 3, 18] version = map parse_int (split (member ".-") version_string) { [output] = vips_call "system" ["'" ++ command_path ++ "' -version"] [$log=>true]; version_string = (split (equal ' ') output)?1, use_gm = (split (equal ' ') output)?2; } // make a command-line ... args is a [str] we join with spaces command args = "'" ++ command_path ++ "' " ++ join_sep " " args' { args' = ["convert"] ++ args, use_gm = args; } // capabilities ... different versions support different features, we // turn features on and off based on these // would probably be better to test for caps somehow has_intensity = false, use_gm = version?0 > 6 || version?1 > 7; has_channel = false, use_gm = version?0 > 6 || version?1 > 7; system0 cmd = system_image0 cmd; system cmd x = map_unary (system_image cmd) x; system2 cmd x y = map_binary (system_image2 cmd) x y; system3 cmd x y z = map_trinary (system_image3 cmd) x y z; radius_widget = Scale "Radius" 0 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle (degrees)" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; gamma_widget = Scale "Gamma" 0 10 1; colors_widget = Scale "Colors" 1 10 3; resize_widget = Scale "Resize (percent)" 0 500 100; fuzz_widget = Scale "Fuzz (percent)" 0 100 0; blur_rad_widget = Scale "Radius (0=auto)" 0 100 0; // a colour with no enclosing quotes ... use this if we know there are // some quotes at an outer level print_colour_nq triple = concat ["#", concat (map fmt triple)] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } // we need the quotes because # is the comment character in *nix print_colour triple = "\"" ++ print_colour_nq triple ++ "\""; Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; GeneralCol triple = class Colour "sRGB" triple { _flag = print_colour_nq triple; Colour_edit space triple = this.GeneralCol triple; } generalcol_widget = GeneralCol [0, 0, 0]; Background triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" false; _flag = "-background " ++ if isNone then "None" else print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Bordercol triple = class Colour "sRGB" triple { _flag = "-bordercolor " ++ print_colour triple; Colour_edit space triple = this.Bordercol triple; } bordercol_widget = Bordercol [0, 0, 0]; Mattecol triple = class Colour "sRGB" triple { _flag = "-mattecolor " ++ print_colour triple; Colour_edit space triple = this.Mattecol triple; } mattecol_widget = Mattecol [189, 189, 189]; // FIXME: Undercolour, like many others, can have alpha channel. // How does user input this? With a slider? Undercol triple = class Colour "sRGB" triple { isNone = Toggle "None (transparent black)" true; _flag = if isNone then "" else ("-undercolor " ++ print_colour triple); Colour_edit space triple = this.Undercol triple; } undercol_widget = Undercol [0, 0, 0]; changeCol_widget = class { _vislevel = 3; colour = GeneralCol [0, 0, 0]; fuzz = fuzz_widget; nonMatch = Toggle "change non-matching colours" false; } Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Remove", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Builtin builtin = class Option_string "Builtin" [ // See http://www.imagemagick.org/script/formats.php "rose:", "logo:", "wizard:", "granite:", "netscape:" ] builtin { _flag = builtin; Option_edit caption labels value = this.Builtin labels?value; } builtin_widget = Builtin "rose:"; channels_widget = class { // FIXME? Can we grey-out alpha when we have no alpha channel, // show CMY(K) instead of RGB(K) etc? // Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA. ChanR valueR = class Toggle "Red" valueR { _flag = "R", valueR = ""; Toggle_edit caption valueR = this.ChanR valueR; } channelR = ChanR true; ChanG valueG = class Toggle "Green" valueG { _flag = "G", valueG = ""; Toggle_edit caption valueG = this.ChanG valueG; } channelG = ChanG true; ChanB valueB = class Toggle "Blue" valueB { _flag = "B", valueB = ""; Toggle_edit caption valueB = this.ChanB valueB; } channelB = ChanB true; ChanK valueK = class Toggle "Black" valueK { _flag = "K", valueK = ""; Toggle_edit caption valueK = this.ChanK valueK; } channelK = ChanK true; ChanA valueA = class Toggle "Alpha" valueA { _flag = "A", valueA = ""; Toggle_edit caption valueA = this.ChanA valueA; } channelA = ChanA false; ChanSy valueSy = class Toggle "Sync" valueSy { _flag = ",sync", valueSy = ""; Toggle_edit caption valueSy = this.ChanSy valueSy; } channelSy = ChanSy true; _rgbka = concat [channelR._flag, channelG._flag, channelB._flag, channelK._flag, channelA._flag ]; _flag = "", _rgbka == "" || !has_channel = concat [ "-channel ", _rgbka, channelSy._flag ]; } ch_widget = channels_widget; Colorspace colsp = class Option_string "Colorspace" [ "CIELab", "CMY", "CMYK", "Gray", "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "Lab", "LCH", "LCHab", "LCHuv", "LMS", "Log", "Luv", "OHTA", "Rec601Luma", "Rec601YCbCr", "Rec709Luma", "Rec709YCbCr", "RGB", "scRGB", "sRGB", "Transparent", "XYZ", "YCbCr", "YDbDr", "YCC", "YIQ", "YPbPr", "YUV" ] colsp { _flag = colsp; Option_edit caption labels value = this.Colorspace labels?value; } colorspace_widget = Colorspace "sRGB"; Compose comp = class Option_string "Compose method" [ "Atop", "Blend", "Blur", "Bumpmap", "ChangeMask", "Clear", "ColorBurn", "ColorDodge", "Colorize", "CopyBlack", "CopyBlue", "CopyCyan", "CopyGreen", "Copy", "CopyMagenta", "CopyOpacity", "CopyRed", "CopyYellow", "Darken", "DarkenIntensity", "DivideDst", "DivideSrc", "Dst", "Difference", "Displace", "Dissolve", "Distort", "DstAtop", "DstIn", "DstOut", "DstOver", "Exclusion", "HardLight", "Hue", "In", "Lighten", "LightenIntensity", "LinearBurn", "LinearDodge", "LinearLight", "Luminize", "Mathematics", "MinusDst", "MinusSrc", "Modulate", "ModulusAdd", "ModulusSubtract", "Multiply", "None", "Out", "Overlay", "Over", "PegtopLight", "PinLight", "Plus", "Replace", "Saturate", "Screen", "SoftLight", "Src", "SrcAtop", "SrcIn", "SrcOut", "SrcOver", "VividLight", "Xor" ] comp { _flag = "-compose " ++ comp; Option_edit caption labels value = this.Compose labels?value; } compose_widget = Compose "Over"; // FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string. // FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack coordinate_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; _flag = concat [print x.expr, ",", print y.expr]; }; Distort distort = class Option_string "Distort" [ "Affine", "AffineProjection", "ScaleRotateTranslate", "SRT", "Perspective", "PerspectiveProjection", "BilinearForward", "BilinearReverse", "Polynomial", "Arc", "Polar", "DePolar", "Barrel", "BarrelInverse", "Shepards", "Resize" ] distort { _flag = distort; Option_edit caption labels value = this.Distort labels?value; } distort_widget = Distort "SRT"; Dither dither = class Option_string "Dither" [ "None", "FloydSteinberg", "Riemersma" ] dither { _flag = "-dither " ++ dither; Option_edit caption labels value = this.Dither labels?value; } dither_widget = Dither "FloydSteinberg"; Evaluate eval = class Option_string "Evaluate operation" [ "Abs", "Add", "AddModulus", "And", "Cos", "Cosine", "Divide", "Exp", "Exponential", "GaussianNoise", "ImpulseNoise", "LaplacianNoise", "LeftShift", "Log", "Max", "Mean", "Median", "Min", "MultiplicativeNoise", "Multiply", "Or", "PoissonNoise", "Pow", "RightShift", "Set", "Sin", "Sine", "Subtract", "Sum", "Threshold", "ThresholdBlack", "ThresholdWhite", "UniformNoise", "Xor" ] eval { _flag = "-evaluate " ++ eval; Option_edit caption labels value = this.Evaluate labels?value; } evaluate_widget = Evaluate "Add"; Filter filt = class Option_string "Filter" [ "default", "Bartlett", "Blackman", "Bohman", "Box", "Catrom", "Cosine", "Cubic", "Gaussian", "Hamming", "Hann", "Hermite", "Jinc", "Kaiser", "Lagrange", "Lanczos", "Lanczos2", "Lanczos2Sharp", "LanczosRadius", "LanczosSharp", "Mitchell", "Parzen", "Point", "Quadratic", "Robidoux", "RobidouxSharp", "Sinc", "SincFast", "Spline", "Triangle", "Welch" ] filt { _flag = if filt == "default" then "" else "-filter " ++ filt; Option_edit caption labels value = this.Filter labels?value; } filter_widget = Filter "default"; Function func = class Option_string "Function" [ "Polynomial", "Sinusoid", "Arcsin", "Arctan" ] func { _flag = func; Option_edit caption labels value = this.Function labels?value; } function_widget = Function "Polynomial"; // "Polynomial (a[n], a[n-1], ... a[1], a[0])", // "Sinusoid (freq, phase, amp, bias)", // "Arcsin (width, centre, range, bias)", // "Arctan (slope, centre, range, bias)" Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; ImageType imagetype = class Option_string "Image type" [ "Bilevel", "ColorSeparation", "ColorSeparationAlpha", "ColorSeparationMatte", "Grayscale", "GrayscaleAlpha", "GrayscaleMatte", "Optimize", "Palette", "PaletteBilevelAlpha", "PaletteBilevelMatte", "PaletteAlpha", "PaletteMatte", "TrueColorAlpha", "TrueColorMatte", "TrueColor" ] imagetype { _flag = "-type " ++ imagetype; Option_edit caption labels value = this.ImageType labels?value; } imagetype_widget = ImageType "TrueColor"; Intensity intensity = class Option_string "Intensity (gray conversion)" [ "Average", "Brightness", "Lightness", "MS", "Rec601Luma", "Rec601Luminance", "Rec709Luma", "Rec709Luminance", "RMS" ] intensity { _flag = "-intensity " ++ intensity, has_intensity = ""; Option_edit caption labels value = this.Intensity labels?value; } intensity_widget = Intensity "Rec709Luminance"; Interpolate interp = class Option_string "Interpolate" [ "default", "Average", "Average4", "Average9", "Average16", "Background", "Bilinear", "Blend", "Integer", "Mesh", "Nearest", "NearestNeighbor", "Spline" ] interp { _flag = if interp == "default" then "" else "-interpolate " ++ interp; Option_edit caption labels value = this.Interpolate labels?value; } interpolate_widget = Interpolate "default"; Kernel kernel = class Option_string "Kernel" [ "Unity", "Gaussian", "DoG", "LoG", "Blur", "Comet", "Binomial", "Laplacian", "Sobel", "FreiChen", "Roberts", "Prewitt", "Compass", "Kirsch", "Diamond", "Square", "Rectangle", "Disk", "Octagon", "Plus", "Cross", "Ring", "Peaks", "Edges", "Corners", "Diagonals", "LineEnds", "LineJunctions", "Ridges", "ConvexHull", "ThinSe", "Skeleton", "Chebyshev", "Manhattan", "Octagonal", "Euclidean" // FIXME: custom kernel ] kernel { _flag = kernel; Option_edit caption labels value = this.Kernel labels?value; } kernel_widget = Kernel "Unity"; ModColSp msp = class Option_string "modulate colorspace" [ "HCL", "HCLp", "HSB", "HSI", "HSL", "HSV", "HWB", "LCH" ] msp { _flag = "-set option:modulate:colorspace " ++ msp; Option_edit caption labels value = this.ModColSp labels?value; } ModColSp_widget = ModColSp "HSL"; MorphMeth morph = class Option_string "Method" [ "Correlate", "Convolve", "Dilate", "Erode", "Close", "Open", "DilateIntensity", "ErodeIntensity", "CloseIntensity", "OpenIntensity", "Smooth", "EdgeOut", "EdgeIn", "Edge", "TopHat", "BottomHat", "HitAndMiss", "Thinning", "Thicken", "Distance", "IterativeDistance" ] morph { _flag = morph; Option_edit caption labels value = this.MorphMeth labels?value; } morphmeth_widget = MorphMeth "Dilate"; Noise noise = class Option_string "Noise" [ "Gaussian", "Impulse", "Laplacian", "Multiplicative", "Poisson", "Random", "Uniform" ] noise { _flag = "+noise " ++ noise; Option_edit caption labels value = this.Noise labels?value; } noise_widget = Noise "Gaussian"; Pattern pattern = class Option_string "Noise" [ // See http://www.imagemagick.org/script/formats.php "bricks", "checkerboard", "circles", "crosshatch", "crosshatch30", "crosshatch45", "gray0", "gray5", "gray10", "gray15", "gray20", "gray25", "gray30", "gray35", "gray40", "gray45", "gray50", "gray55", "gray60", "gray65", "gray70", "gray75", "gray80", "gray85", "gray90", "gray95", "gray100", "hexagons", "horizontal", "horizontal2", "horizontal3", "horizontalsaw", "hs_bdiagonal", "hs_cross", "hs_diagcross", "hs_fdiagonal", "hs_horizontal", "hs_vertical", "left30", "left45", "leftshingle", "octagons", "right30", "right45", "rightshingle", "smallfishscales", "vertical", "vertical2", "vertical3", "verticalbricks", "verticalleftshingle", "verticalrightshingle", "verticalsaw" ] pattern { _flag = "pattern:" ++ pattern; Option_edit caption labels value = this.Pattern labels?value; } pattern_widget = Pattern "bricks"; ResizeType resizet = class Option_string "Resize type" [ "resize", "scale", "sample", "adaptive-resize" ] resizet { _flag = resizet; Option_edit caption labels value = this.ResizeType labels?value; } ResizeType_widget = ResizeType "resize"; Size_widget = class { _vislevel = 3; width = Expression "Width (pixels)" 64; height = Expression "Height (pixels)" 64; _flag = "-size " ++ print width.expr ++ "x" ++ print height.expr; }; StatType statt = class Option_string "Statistic type" [ "Gradient", "Maximum", "Mean", "Median", "Minimum", "Mode", "Nonpeak", "StandardDeviation" ] statt { _flag = statt; Option_edit caption labels value = this.StatType labels?value; } StatType_widget = StatType "Mean"; VirtualPixel vp = class Option_string "Virtual pixel" [ "Background", "Black", "CheckerTile", "Dither", "Edge", "Gray", "HorizontalTile", "HorizontalTileEdge", "Mirror", "None", "Random", "Tile", "Transparent", "VerticalTile", "VerticalTileEdge", "White" ] vp { _flag = "-virtual-pixel " ++ vp; _isBackground = (vp == "Background"); Option_edit caption labels value = this.VirtualPixel labels?value; } VirtualPixel_widget = VirtualPixel "Edge"; VirtualPixelBack_widget = class { virtpix = Magick.VirtualPixel_widget; background = Magick.background_widget; _flag = (if virtpix._isBackground then (background._flag ++ " ") else "") ++ virtpix._flag; } Geometry_widget = class { _vislevel = 3; x = Expression "X" 0; y = Expression "Y" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; AnnotGeometry_widget = class { _vislevel = 3; shearX = Expression "shear X (degrees)" 0; shearY = Expression "shear Y (degrees)" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print shearX.expr, "x", print shearY.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; OffsetGeometry_widget = class { _vislevel = 3; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; WhxyGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; hoffset = Expression "Horizontal offset" 0; voffset = Expression "Vertical offset" 0; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; FrameGeometry_widget = class { _vislevel = 3; x = Expression "Width" 0; y = Expression "Height" 0; outbev = Expression "Outer bevel thickness" 0; inbev = Expression "Inner bevel thickness" 0; _flag = concat [print x.expr, "x", print y.expr, format outbev, format inbev] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } } nip2-8.7.1/share/nip2/compat/8.5/_predicate.def0000644000175000017500000003252613351443023015654 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Plot x = is_instanceof "Plot" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = oo_unary_function get_type_op x, is_class x = error (_ "bad arguments to " ++ "get_type") { get_type_op = Operator "get_type" get_type Operator_type.COMPOUND false; // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = oo_unary_function get_format_op x, is_class x = error (_ "bad arguments to " ++ "get_format") { get_format_op = Operator "get_format" get_format Operator_type.COMPOUND false; } has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = oo_unary_function get_bits_op x, is_class x = error (_ "bad arguments to " ++ "get_bits") { get_bits_op = Operator "get_bits" get_format Operator_type.COMPOUND false; } has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = oo_unary_function get_bands_op x, is_class x = error (_ "bad arguments to " ++ "get_bands") { get_bands_op = Operator "get_bands" get_bands Operator_type.COMPOUND false; } has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = oo_unary_function get_coding_op x, is_class x = error (_ "bad arguments to " ++ "get_coding") { get_coding_op = Operator "get_coding" get_coding Operator_type.COMPOUND false; } has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = oo_unary_function get_xres_op x, is_class x = error (_ "bad arguments to " ++ "get_xres") { get_xres_op = Operator "get_xres" get_xres Operator_type.COMPOUND false; } has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = oo_unary_function get_yres_op x, is_class x = error (_ "bad arguments to " ++ "get_yres") { get_yres_op = Operator "get_yres" get_yres Operator_type.COMPOUND false; } has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = oo_unary_function get_xoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_xoffset") { get_xoffset_op = Operator "get_xoffset" get_xoffset Operator_type.COMPOUND false; } has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = oo_unary_function get_yoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_yoffset") { get_yoffset_op = Operator "get_yoffset" get_yoffset Operator_type.COMPOUND false; } has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = oo_unary_function get_image_op x, is_class x = error (_ "bad arguments to " ++ "get_image") { get_image_op = Operator "get_image" get_image Operator_type.COMPOUND false; } has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = oo_unary_function get_number_op x, is_class x = error (_ "bad arguments to " ++ "get_number") { get_number_op = Operator "get_number" get_number Operator_type.COMPOUND false; } has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = oo_unary_function get_real_op x, is_class x = error (_ "bad arguments to " ++ "get_real") { get_real_op = Operator "get_real" get_real Operator_type.COMPOUND false; } has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = oo_unary_function get_width_op x, is_class x = error (_ "bad arguments to " ++ "get_width") { get_width_op = Operator "get_width" get_width Operator_type.COMPOUND false; } has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = oo_unary_function get_height_op x, is_class x = error (_ "bad arguments to " ++ "get_height") { get_height_op = Operator "get_height" get_height Operator_type.COMPOUND false; } has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = oo_unary_function get_left_op x, is_class x = error (_ "bad arguments to " ++ "get_left") { get_left_op = Operator "get_left" get_left Operator_type.COMPOUND false; } has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = oo_unary_function get_top_op x, is_class x = error (_ "bad arguments to " ++ "get_top") { get_top_op = Operator "get_top" get_top Operator_type.COMPOUND false; } // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/8.5/_list.def0000644000175000017500000002310313351443023014656 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* flatten x: flatten a list of lists of things into a simple list * * flatten :: [[*]] -> [*] */ flatten x = foldr flat [] x, is_list x = x { flat x sofar = foldr flat sofar x, is_list x = x : sofar; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st x) xs { x:xs = l; } /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn x xs { x:xs = l; } /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn x (foldr fn st xs) { x:xs = l; } /* foldr1 fn l: like foldr, but use the last element as the start value * * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = x, xs == [] = fn x (foldr1 fn xs) { x:xs = l; } /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn x = search xs (n + 1) { x:xs = l; } } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = x : init xs { x:xs = l; } /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = x, xs == [] = last xs { x:xs = l; } /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scanl fn st l: apply (foldl fn r) to every initial segment of a list * * scanl add 0 [1,2,3] == [1,3,6] * scanl :: (* -> ** -> *) -> * -> [**] -> [*] */ scanl fn st l = st, l == [] = st' : scanl fn st' xs { x:xs = l; st' = fn st x; } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/Makefile.am0000644000175000017500000000013013351443023014601 00000000000000SUBDIRS = 7.8 7.9 7.10 7.12 7.14 7.16 7.24 7.26 7.28 7.38 7.40 8.2 8.3 \ 8.4 8.5 8.6 nip2-8.7.1/share/nip2/compat/7.38/0000755000175000017500000000000013417043453013240 500000000000000nip2-8.7.1/share/nip2/compat/7.38/Image.def0000644000175000017500000014266213351443023014667 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process = [ // we can't use id here since we want to "declass" // the members of x ... consider if x is a crop class, // for example, we don't want to inherit from crop, we // want to make a new image class rot180 @ rot180, rot90, rot180, rot270 ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp h v image, aspect = resize interp fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize interp fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; Bandand_item = class Menuaction "Bitwise Band AND" "bitwise AND of image bands" { action x = bandand x; } Bandor_item = class Menuaction "Bitwise Band OR" "bitwise OR of image bands" { action x = bandor x; } sep2 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = crop x [l, t, w, h] { fields = [ [has_left, get_left, 0], [has_top, get_top, 0], [has_width, get_width, 100], [has_height, get_height, 100] ]; [l, t, w, h] = map get_default fields { get_default line = get x, has x = default { [has, get, default] = line; } } } crop x geo = class _result { _vislevel = 3; l = Expression "Crop left" ((int) (geo?0 + geo?2 / 4)); t = Expression "Crop top" ((int) (geo?1 + geo?3 / 4)); w = Expression "Crop width" (max_pair 1 ((int) (geo?2 / 2))); h = Expression "Crop height" (max_pair 1 ((int) (geo?3 / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; i = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1 y1 x2 y2 i.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; rx = Expression "Left" 50; ry = Expression "Top" 50; rw = Expression "Width" 100; rh = Expression "Height" 100; f = Toggle "Fill" true; t = Scale "Line thickness" 1 50 3; i = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect_width rx ry rw rh f t i.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; f = Toggle "Fill" true; i = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx cy r f i.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; sx = Expression "Start x" 100; sy = Expression "Start y" 100; e = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can i = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area sx sy 1 1 im)); im = get_image x; } _result = map_unary flood x { flood im = draw_flood sx sy i.expr im, e == 0 = draw_flood_blob sx sy i.expr im; } } } Draw_scalebar_item = class Menuaction "_Scale" "draw scale bar" { action x = class _result { _vislevel = 3; px = Expression "Left" 50; py = Expression "Top" 50; wid = Expression "Width" 100; thick = Scale "Line thickness" 1 50 3; text = String "Dimension text" "50μm"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; pos = Option "Position Text" ["Above", "Below"] 1; vp = Option "Dimension by" [ "Inner Vertical Edge", "Centre of Vertical", "Outer Vertical Edge" ] 1; dpi = Expression "DPI" 100; ink = Colour "Lab" [50,0,0]; _result = map_unary process x { process im = blend (Image scale) ink' im { // make an ink compatible with the image ink' = colour_transform_to (get_type im) ink; x = to_real px; y = to_real py; w = to_real wid; d = to_real dpi; t = floor thick; bg = image_new (get_width im) (get_height im) (get_bands im) (get_format im) (get_coding im) (get_type im) 0 0 0; draw_block x y w t im = draw_rect_width x y w t true 1 [255] im; label = im_text text.value font.value w 1 d; lw = get_width label; lh = get_height label; ly = [y - lh - t, y + 2 * t]?pos; vx = [ [x - t, x + w], [x - t / 2, x + w - t / 2], [x, x + w - t] ]?vp; scale = (draw_block x y w t @ draw_block vx?0 (y - 2 * t) t (t * 5) @ draw_block vx?1 (y - 2 * t) t (t * 5) @ insert_noexpand (x + w / 2 - lw / 2) ly label) bg; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise Join" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/7.38/_convert.def0000644000175000017500000004223113351443023015453 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = Image x.value, is_Plot x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } to_int x = (int) (to_real x); /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The outermost list objects become Group()'d. */ to_group x = Group x, is_list x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = sign * (abs ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; sign = 1, ipart > 0 = -1; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/7.38/Filter.def0000644000175000017500000012653013351443023015066 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 1.5; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 50; fs = Scale "Sharpen flat areas by" (-2) 5 1; js = Scale "Sharpen jaggy areas by" (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_greyc_item = class Menupullright "_GREYCstoration" "noise-removing filter" { Denoise_item = class Menuaction "Denoise" "Noise-removing filter" { action x = class _result { _vislevel = 3; iterations = Scale "Iterations" 1 5 1; amplitude = Scale "Amplitude" 1 100 40; sharpness = Scale "Sharpness" 0 3 0.9; anisotropy = Scale "Anisotropy" 0 1 0.15; alpha = Scale "Noise scale" 0 5 0.6; sigma = Scale "Geometry regularity" 0 2 1.1; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) x; } } Enlarge_item = class Menuaction "Enlarge" "Enlarge image" { action x = class _result { _vislevel = 3; scale = Scale "Enlarge" 1 10 3; iterations = Scale "Iterations" 1 5 3; amplitude = Scale "Amplitude" 1 100 20; sharpness = Scale "Sharpness" 0 3 0.2; anisotropy = Scale "Anisotropy" 0 1 0.9; alpha = Scale "Noise scale" 0 5 0.1; sigma = Scale "Geometry regularity" 0 2 1.5; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) (resize Interpolate_bilinear (to_real scale) (to_real scale) x); } } } Filter_magick_item = class Menupullright "Magic_k" "various Image/Graphics Magick filters" { system command x = map_unary (system_image command) x; radius_widget = Scale "Radius" 1 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; print_colour triple = concat ["\"#", concat (map fmt triple), "\""] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; Background triple = class Colour "sRGB" triple { _flag = "-background " ++ print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Geometry_widget = class { _vislevel = 3; x = Expression "Y" 0; y = Expression "X" 0; hoffset = Expression "Horizontal offset" 10; voffset = Expression "Vertical offset" 10; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } Adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; radius = radius_widget; sigma = sigma_widget; command = magick_command (concat ["-adaptive-blur ", print radius.value, "x", print sigma.value]); _result = system command x; } } Adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; radius = radius_widget; sigma = sigma_widget; command = magick_command (concat ["-adaptive-sharpen ", print radius.value, "x", print sigma.value]); _result = system command x; } } Alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = alpha_widget; command = magick_command alpha._flag; _result = system command x; } } Annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = text_widget; font = Font_widget; geometry = Geometry_widget; gravity = gravity_widget; foreground = foreground_widget; antialias = antialias_widget; command = magick_command (join_sep " " [ font._flag, antialias._flag, gravity._flag, foreground._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\""]); _result = system command x; } } Swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = angle_widget; command = magick_command ("-swirl " ++ print angle.value); _result = system command x; } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } nip2-8.7.1/share/nip2/compat/7.38/_joe_extra.def0000644000175000017500000003114713351443023015757 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use an Arrow or Region x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { im = x.image; mask = Image m { rx = x.region_rect, is_Region x = x; b = image_new im.width im.height 1 0 0 1 0 0 0; w = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0; m = insert_noexpand rx.nleft rx.ntop w b; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } sep2 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Interpolate_bilinear f1 1 b1 {b1 = resize Interpolate_bilinear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.38/Colour.def0000644000175000017500000003762213351443023015107 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } CCT_colour = class Menuaction (_ "Colour from CCT") (_ "pick colour by CCT") { action = widget 6500; widget x = class _result { _vislevel = 3; T = Scale "CCT" 1800 25000 x; _result = colour_from_temp (to_real T); Colour_edit space value = widget (temp_from_colour (Colour space value)); } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } sep1 = Menuseparator; CCT_item = class Menuaction (_ "Calculate temperature") (_ "estimate CCT using the McCamy approximation") { action z = map_unary temp_from_colour z; } Colour_item = Colour_new_item.CCT_colour; } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; measure = Scale (_ "Measure area (%)") 1 100 50; // get a representative image from an arg get_image x = get_image x.value?0, is_Group x = x; _im = get_image x; sample = measure_draw (to_real pacross) (to_real pdown) (to_real measure) _im; _result = map_unary chart x { chart in = measure_sample (to_real pacross) (to_real pdown) (to_real measure) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.38/_joe_utilities.def0000644000175000017500000005054513351443023016652 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/7.38/_Object.def0000644000175000017500000002600513351443023015202 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/7.38/Object.def0000644000175000017500000000220513351443023015037 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/7.38/Math.def0000644000175000017500000003162513351443023014532 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_AND" "bitwise AND of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_OR" "bitwise OR of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "_XOR" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_NOT" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Bandand_item = Image_band_item.Bandand_item; Bandor_item = Image_band_item.Bandor_item; } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Skew_item = class Menuaction "S_kew" "skew of image or list or vector" { action a = map_unary skew a; } Kurtosis_item = class Menuaction "Kurtosis" "kurtosis of image or list or vector" { action a = map_unary kurtosis a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.38/_generate.def0000644000175000017500000000755513351443023015577 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } mkim options x y b = Image (image_new x y b (opt $format) (opt $coding) (opt $type) (opt $pixel) (opt $xoffset) (opt $yoffset)) { opt = get_option options [ $format => Image_format.UCHAR, $coding => Image_coding.NOCODING, $type => Image_type.sRGB, $pixel => 0, $xoffset => 0, $yoffset => 0 ]; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } /* Make a colour from a temperature. */ colour_from_temp T = error (_ "T out of range"), T < 1667 || T > 25000 = Colour "Yxy" [50, x, y] { // Kim et all approximation // see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation x = -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 + 0.8776956 * 10 ** 3 / T + 0.179910, T < 4000 = -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 + 0.2226347 * 10 ** 3 / T + 0.240390; y = -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + 2.18555832 * x - 0.20219638, T < 2222 = -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + 2.09137015 * x - 0.16748867, T < 4000 = 3.0817580 * x ** 3 - 5.87338670 * x ** 2 + 3.75112997 * x - 0.37001483; } temp_from_colour z = T { c = colour_transform_to Image_type.YXY (to_colour z); x = c.value?1; y = c.value?2; // McCamy's approximation, see eg. // http://en.wikipedia.org/wiki/Color_temperature#Approximation xe = 0.332; ye = 0.1858; n = (x - xe) / (y - ye); T = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33; } nip2-8.7.1/share/nip2/compat/7.38/_stdenv.def0000644000175000017500000017677113351443023015317 00000000000000/* optional args to functions */ get_option options defaults f = error (_ "unknown parameter " ++ f), hits == [] = hits?0 { hits = [v :: [n, v] <- options ++ defaults; n == f]; } /* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } bandand x = oo_unary_function bandand_op x, is_class x = foldr1 bitwise_and (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandand") { bandand_op = Operator "bandand" bandand Operator_type.COMPOUND_REWRAP false; } bandor x = oo_unary_function bandor_op x, is_class x = foldr1 bitwise_or (bandsplit x), is_image x = error (_ "bad arguments to " ++ "bandor") { bandor_op = Operator "bandor" bandor Operator_type.COMPOUND_REWRAP false; } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } skew x = oo_unary_function skew_op x, is_class x = sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x = sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "skew") { skew_op = Operator "skew" skew Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = w * h * b, is_image x' = len x'; } kurtosis x = oo_unary_function kurtosis_op x, is_class x = sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x = sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "kurtosis") { kurtosis_op = Operator "kurtosis" kurtosis Operator_type.COMPOUND false; // squash any large matrix down to a flat list ... much simpler x' = x, is_image x; = flatten x; m = mean x'; s = deviation x'; w = get_width x'; h = get_height x'; b = get_bands x'; N = len x', is_list x'; = w * h * b; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_cache x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend" ++ ": " ++ join_sep ", " (map print [cond, in1, in2])) { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } measure_draw across down measure image = mark { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; x = map (extract 0) cods; y = map (extract 1) cods; outer = mkim [$pixel => 255] sample_width sample_height 1; inner = mkim [] (sample_width - 4) (sample_height - 4) 1; patch = insert 2 2 inner outer; bg = mkim [] image.width image.height 1; mask = Image (im_insertset bg.value patch.value x y); image' = colour_transform_to Image_type.sRGB image; mark = if mask then Vector [0, 255, 0] else image'; } measure_sample across down measure image = measures { patch_width = image.width / across; sample_width = patch_width * (measure / 100); left_margin = (patch_width - sample_width) / 2; patch_height = image.height / down; sample_height = patch_height * (measure / 100); top_margin = (patch_height - sample_height) / 2; cods = [[x * patch_width + left_margin, y * patch_height + top_margin] :: y <- [0 .. down - 1]; x <- [0 .. across - 1]]; patches = map (\p extract_area p?0 p?1 sample_width sample_height image) cods; measures = Matrix (map (map mean) (map bandsplit patches)); } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx x = oo_unary_function greyc_op x, is_class x = greyc_im x, is_image x = error (_ "bad argument" ++ " (" ++ print x ++ ") to " ++ "greyc") { greyc_op = Operator "greyc" (greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im x = im_greyc x iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx mask x = oo_binary_function greyc_mask_op mask x, is_class mask = oo_binary'_function greyc_mask_op mask x, is_class x = greyc_im mask x, is_image mask && is_image x = error (_ "bad arguments" ++ " (" ++ print mask ++ ", " ++ print x ++ ") " ++ "to " ++ "greyc") { greyc_mask_op = Operator "greyc_mask" (greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im mask x = im_greyc_mask x mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_inv hist = oo_unary_function hist_inv_op hist, is_class hist = inv hist, is_image hist = error (_ "bad arguments to " ++ "hist_inv") { hist_inv_op = Operator "hist_inv" hist_inv Operator_type.COMPOUND_REWRAP false; inv im = im_invertlut (to_matrix im''') len { // need a vertical doublemask im' = rot90 im, get_width im > 1 && get_height im == 1 = im, get_width im == 1 && get_height im > 1 = error (_ "not a hist"); len = get_height im'; // values must be scaled to 0 - 1 im'' = im' / (max im'); // add an index column on the left // again, must be in 0-1 y = ((make_xy 1 len)?1) / len; im''' = y ++ im''; } } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize interp xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; // is this interpolation nearest-neighbour? is_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor, nearest neighbour // upscale by integer part, then affine to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by any factor, nearest neighbour // downscale by integer part, then affine to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor with affine = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 // downscale by any factor, bilinear // block shrink by integer factor, then resample to // exact with affine = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate_type.descriptions?interp.type ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // resize scale xfac yfac im = im_affinei_all im interp.value xfac 0 0 yfac 0 0; } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } // Given a xywh rect, flip it around so wh are always positive rect_normalise x y w h = [x', y', w', h'] { x' = x + w, w < 0 = x; y' = y + h, h < 0 = y; w' = abs w; h' = abs h; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } /* This version of draw_rect uses insert_noexpand and will be fast, even for * huge images. */ draw_rect_width x y w h f t ink image = oo_unary_function draw_rect_width_op image, is_class image = my_draw_rect_width image (to_int x) (to_int y) (to_int w) (to_int h) (to_int f) (to_int t) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_width") { draw_rect_width_op = Operator "draw_rect_width" (draw_rect_width x y w h f t ink) Operator_type.COMPOUND_REWRAP false; my_draw_rect_width image x y w h f t ink = insert x' y' (block w' h') image, f == 1 = (insert x' y' (block w' t) @ insert (x' + w' - t) y' (block t h') @ insert x' (y' + h' - t) (block w' t) @ insert x' y' (block t h')) image { insert = insert_noexpand; block w h = image_new w h (get_bands image) (get_format image) (get_coding image) (get_type image) ink' 0 0; ink' = Vector ink, is_list ink = ink; [x', y', w', h'] = rect_normalise x y w h; } } /* Default to 1 pixel wide edges. */ draw_rect x y w h f ink image = draw_rect_width x y w h f 1 ink image; /* This version of draw_rect uses the paintbox rect draw operation. It is an * inplace operation and will use bucketloads of memory. */ draw_rect_paintbox x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect_paintbox") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; } ss = len xes; sx = sum xes; sy = sum yes; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* Generate an ImageMagick (or GraphicsMagick) command suitable for * im_system_image. Use convert.exe in $VIPSHOME/bin, if it exists, otherwise * assume it's on the path somewhere. */ magick_command switch = join_sep " " [convert, "\"%s\"", switch, "\"%s\""] { prefs = Workspaces.Preferences; use_gm = prefs.USE_GRAPHICSMAGICK; name = if use_gm then "gm" else "convert"; exe = concat [name, expand "$EXEEXT"]; vipsexe = path_absolute [expand "$VIPSHOME", "bin", exe]; final_exe = vipsexe, search vipsexe != [] = exe; convert = join_sep " " [final_exe, "convert"], use_gm = final_exe; } /* Run a command on an image. See magick_command, for example. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } nip2-8.7.1/share/nip2/compat/7.38/Histogram.def0000644000175000017500000001511113351443023015566 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "_Identity" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_inv_item = class Menuaction "In_vert" "invert a histogram" { action x = map_unary hist_inv x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Interpolate_bilinear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/7.38/Widgets.def0000644000175000017500000000235313351443023015243 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/7.38/_types.def0000644000175000017500000006732313351443023015150 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; HISTOGRAM = 10; XYZ = 12; LAB = 13; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; ARRAY = 27; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $HISTOGRAM => HISTOGRAM, $XYZ => XYZ, $LAB => LAB, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16, $ARRAY => ARRAY ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/7.38/Matrix.def0000644000175000017500000002573113351443023015106 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = identity (identity_matrix 5); identity v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix (identity_matrix (to_real s)), to_real s != len v; = Matrix v; Matrix_vips value scale offset filename display = identity value; } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = series (mkseries 0 1 5); mkseries s t e = transpose [[to_real s, to_real s + to_real t .. to_real e]]; series v = class _result { _vislevel = 3; _s = v?0?0; _t = v?1?0 - v?0?0; _e = (last v)?0; s = Expression "Start value" _s; t = Expression "Step by" _t; e = Expression "End value" _e; _result = Matrix (mkseries s t e), to_real s != _s || to_real t != _t || to_real e != _e = Matrix v; Matrix_vips value scale offset filename display = series value; } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = square (mksquare 5); mksquare s = replicate s (take s [1, 1 ..]); square v = class _result { _vislevel = 3; s = Expression "Size" (len v); _result = Matrix_con (sum v) 0 v, len v == to_real s = Matrix_con (sum m) 0 m { m = mksquare (to_real s); } Matrix_vips value scale offset filename display = square value; } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = circle (mkcircle 3); mkcircle r = map2 (map2 pyth) xes yes { line = [-r .. r]; xes = replicate (2 * r + 1) line; yes = transpose xes; pyth a b = 1, (a**2 + b**2) ** 0.5 <= r = 0; } circle v = class _result { _vislevel = 3; r = Expression "Radius" ((len v - 1) / 2); _result = Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1 = Matrix_con (sum m) 0 m { m = mkcircle (to_real r); } Matrix_vips value scale offset filename display = circle value; } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/7.38/Tasks.def0000644000175000017500000006411113351443023014722 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; measure = Scale (_ "Measure area (%)") 1 100 50; sample = measure_draw 6 4 (to_real measure) image; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linearize from chart greyscale", "Fit intercept from chart greyscale", "Linear input, set brightness from chart", "Linear input" ] 0; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure_sample 6 4 (to_real measure) image; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix [[0, 0], [1, 1]] { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map an image though the lineariser linear x = hist_map linearising_lut.value x, mode == 0 || mode == 1 = x; // map the chart measurements though the lineariser _camera' = (to_matrix @ linear @ to_image) _camera; // solve for RGB -> XYZ // normalise: the 2nd row is what makes Y, so divide by that to // get Y in 0-1. _pinv = (transpose _camera' * _camera') ** -1; _full_M = transpose (_pinv * (transpose _camera' * _true_XYZ)); M = _full_M / scale; scale = sum _full_M.value?1; // now turn the camera to LAB and calculate dE76 _camera'' = (to_matrix @ colour_transform Image_type.XYZ Image_type.LAB @ recomb M @ multiply scale @ to_image) _camera'; _dEs = map abs_vec (_camera'' - _true_Lab).value; avg_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } // normalise brightness ... in linear mode, we optionally don't // set the brightness from the Macbeth chart norm x = x * scale, mode != 3 = x; // convert RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ norm @ recomb M @ cast_float @ linear) image.value; } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ calib.norm @ recomb calib.M @ cast_float @ calib.linear) image.value; } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Interpolate_bilinear xfactor yfactor scale_im; _offset_im = resize Interpolate_bilinear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.38/Makefile.am0000644000175000017500000000054313351443023015210 00000000000000startdir = $(pkgdatadir)/compat/7.38 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.38/Makefile.in0000644000175000017500000003707113417043242015231 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.38 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.38 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.38/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.38/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.38/_predicate.def0000644000175000017500000003252613351443023015741 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Plot x = is_instanceof "Plot" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = oo_unary_function get_type_op x, is_class x = error (_ "bad arguments to " ++ "get_type") { get_type_op = Operator "get_type" get_type Operator_type.COMPOUND false; // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = oo_unary_function get_format_op x, is_class x = error (_ "bad arguments to " ++ "get_format") { get_format_op = Operator "get_format" get_format Operator_type.COMPOUND false; } has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = oo_unary_function get_bits_op x, is_class x = error (_ "bad arguments to " ++ "get_bits") { get_bits_op = Operator "get_bits" get_format Operator_type.COMPOUND false; } has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = oo_unary_function get_bands_op x, is_class x = error (_ "bad arguments to " ++ "get_bands") { get_bands_op = Operator "get_bands" get_bands Operator_type.COMPOUND false; } has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = oo_unary_function get_coding_op x, is_class x = error (_ "bad arguments to " ++ "get_coding") { get_coding_op = Operator "get_coding" get_coding Operator_type.COMPOUND false; } has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = oo_unary_function get_xres_op x, is_class x = error (_ "bad arguments to " ++ "get_xres") { get_xres_op = Operator "get_xres" get_xres Operator_type.COMPOUND false; } has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = oo_unary_function get_yres_op x, is_class x = error (_ "bad arguments to " ++ "get_yres") { get_yres_op = Operator "get_yres" get_yres Operator_type.COMPOUND false; } has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = oo_unary_function get_xoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_xoffset") { get_xoffset_op = Operator "get_xoffset" get_xoffset Operator_type.COMPOUND false; } has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = oo_unary_function get_yoffset_op x, is_class x = error (_ "bad arguments to " ++ "get_yoffset") { get_yoffset_op = Operator "get_yoffset" get_yoffset Operator_type.COMPOUND false; } has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = oo_unary_function get_image_op x, is_class x = error (_ "bad arguments to " ++ "get_image") { get_image_op = Operator "get_image" get_image Operator_type.COMPOUND false; } has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = oo_unary_function get_number_op x, is_class x = error (_ "bad arguments to " ++ "get_number") { get_number_op = Operator "get_number" get_number Operator_type.COMPOUND false; } has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = oo_unary_function get_real_op x, is_class x = error (_ "bad arguments to " ++ "get_real") { get_real_op = Operator "get_real" get_real Operator_type.COMPOUND false; } has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = oo_unary_function get_width_op x, is_class x = error (_ "bad arguments to " ++ "get_width") { get_width_op = Operator "get_width" get_width Operator_type.COMPOUND false; } has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = oo_unary_function get_height_op x, is_class x = error (_ "bad arguments to " ++ "get_height") { get_height_op = Operator "get_height" get_height Operator_type.COMPOUND false; } has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = oo_unary_function get_left_op x, is_class x = error (_ "bad arguments to " ++ "get_left") { get_left_op = Operator "get_left" get_left Operator_type.COMPOUND false; } has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = oo_unary_function get_top_op x, is_class x = error (_ "bad arguments to " ++ "get_top") { get_top_op = Operator "get_top" get_top Operator_type.COMPOUND false; } // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/7.38/_list.def0000644000175000017500000002310313351443023014743 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* flatten x: flatten a list of lists of things into a simple list * * flatten :: [[*]] -> [*] */ flatten x = foldr flat [] x, is_list x = x { flat x sofar = foldr flat sofar x, is_list x = x : sofar; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st x) xs { x:xs = l; } /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn x xs { x:xs = l; } /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn x (foldr fn st xs) { x:xs = l; } /* foldr1 fn l: like foldr, but use the last element as the start value * * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = x, xs == [] = fn x (foldr1 fn xs) { x:xs = l; } /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn x = search xs (n + 1) { x:xs = l; } } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = x : init xs { x:xs = l; } /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = x, xs == [] = last xs { x:xs = l; } /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scanl fn st l: apply (foldl fn r) to every initial segment of a list * * scanl add 0 [1,2,3] == [1,3,6] * scanl :: (* -> ** -> *) -> * -> [**] -> [*] */ scanl fn st l = st, l == [] = st' : scanl fn st' xs { x:xs = l; st' = fn st x; } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/Makefile.in0000644000175000017500000004660113417043242014631 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ SUBDIRS = 7.8 7.9 7.10 7.12 7.14 7.16 7.24 7.26 7.28 7.38 7.40 8.2 8.3 \ 8.4 8.5 8.6 all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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: 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-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.8/0000755000175000017500000000000013417043452013154 500000000000000nip2-8.7.1/share/nip2/compat/7.8/Image.def0000644000175000017500000002517713351443023014605 00000000000000/* take a copy of x */ Duplicate x = map_unary copy x; /* crop image x */ Crop x = map_unary build_widget x { build_widget image = widget image (image.width * 0.25 - image.xoffset) (image.height * 0.25 - image.yoffset) (image.width * 0.5) (image.height * 0.5); widget image left top width height = class Region image left top width height { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 4; Region_edit image left top width height = widget image left top width height; } } /* insert image b into image a */ Insert a b = class Image value { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _check_all = [ [a.format == b.format && a.coding == b.coding && a.bands == b.bands, "a.format == b.format && a.coding == b.coding && " ++ "a.bands == b.bands"], [a.width >= b.width && a.height >= b.height, "First image should be able to enclose second"] ]; _vislevel = 3; place = Area a ((a.width - b.width) / 2) ((a.height - b.height) / 2) b.width b.height; value = im_insert_noexpand a' b'' place.left place.top { a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; } } /* join two images left/right or up/down */ Join = class { _check_ab_args a b = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_ab_all a b = [ [a.format == b.format && a.coding == b.coding && a.bands == b.bands, "a.format == b.format && a.coding == b.coding && " ++ "a.bands == b.bands"] ]; /* join two images left-right */ Left_right a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; _check_all = _check_ab_all a b ++ super._check_all; shim = Slider 0 100 0; background_colour = 0; align = Option "Alignment" ["Top", "Centre", "Bottom"] 1; value = im2 { w = a.width + b.width + shim.value; h = max_pair a.height b.height; bg = image_new w h a.bands a.format a.coding a.type background_colour 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = im_insert_noexpand bg a.value 0 (ya?align); im2 = im_insert_noexpand im1 b.value (a.width + shim.value) (yb?align); } } /* join two images top-bottom */ Top_bottom a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; _check_all = _check_ab_all a b ++ super._check_all; shim = Slider 0 100 0; background_colour = 0; align = Option "Alignment" ["Left", "Centre", "Right"] 1; value = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim.value; bg = image_new w h a.bands a.format a.coding a.type background_colour 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = im_insert_noexpand bg a.value (xa?align) 0; im2 = im_insert_noexpand im1 b.value (xb?align) (a.height + shim.value); } } /* join a 2-D array of images */ Array x = class Image value { hspacing = Slider (-100) (100) 0; vspacing = Slider (-100) (100) 0; value = imagearray_assemble (-hspacing.value) (-vspacing.value) x' { x' = map (map getval) x; getval x = x.value, is_class x = x; } } } /* morph images to match (needs the rubbersheet plugin) */ Rubber = class { _rubber_interp = Option "Interpolation" (map (extract 0) Interpolate.names.value) Interpolate.bilinear; _rubber_order = Option "order" ["0", "1", "2", "3"] 1; _rubber_edges = Toggle "Wrap image edges" false; /* find a transform which will turn sample image into reference image */ Rubber_find reference sample = class Matrix transformation { _vislevel = 3; // controls order = _rubber_order; interp = _rubber_interp; edges = _rubber_edges; max_error = 0.3; max_iterations = 10; // transform _result = resample sample.value reference.value max_error max_iterations order.value interp.value edges.value; // results transformed_image = Image (_result?0); transformation = (_result?1).value; final_error = _result?2; } /* apply a transform to an image */ Rubber_apply transform image = class Image value { // controls interp = _rubber_interp; edges = _rubber_edges; value = im_transform image.value transform interp.value edges.value; } /* change a transformation's scale factor */ Rubber_scale transform = class Matrix scaled_transform { factor_hint = "scale transform by this factor"; factor_x = 1; factor_y = 1; // pairwise multiply scaled_transform = map2 (map2 multiply) transform.value facs { facs = [[ factor_x, factor_y ], [ 1, 1 ], [ 1, 1 ], [ 1 / factor_x, 1 / factor_y ], [ 1 / factor_x, 1 / factor_y ], [ 1 / factor_x, 1 / factor_y ]]; } } } #separator /* set pixels to 255 - x */ Photographic_negative x = map_unary invert x { invert x = oo_unary_function neg_op x, is_class x = im_invert x, is_image x = 255 - x, is_number x = error (errors.badargs ++ "invert"); neg_op = Operator "photographic_negative" invert Operator_type.ARITHMETIC false; } /* falsecolour a mono image */ Falsecolour x = map_unary falsecolour x; #separator /* adjust brightness and contrast of image x */ Adjust_scale_offset x = map_unary widget x { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; scale = Slider 0.001 255 1; offset = Slider (-128) 128 0; value = clip2fmt image.format (image * scale + offset).value; } } /* adjust gamma of image x */ Adjust_gamma x = map_unary widget x { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; gamma = Slider 0.001 4 1; image_maximum_hint = "Change image_maximum if this is " ++ "not an 8 bit image"; image_maximum = 255; value = clip2fmt image.format gammaed.value { gammaed = (image_maximum / image_maximum ** gamma) * image ** gamma; } } } /* change advisory header fields of image x */ Edit_header x = map_unary widget x { type_names = Image_type.type_names; names = sort (map (extract 0) type_names.value); widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; xres = image.xres; yres = image.yres; xoffset = image.xoffset; yoffset = image.yoffset; type_option = Option "Image type" names pos { name = type_names.lookup 1 0 image.type; pos = index (equal name) names; } value = im_copy_set image.value type xres yres xoffset yoffset { type = type_names.lookup 0 1 names?type_option; } } } #separator /* rotate and scale one image to match another */ Match a b = class Image value { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _vislevel = 3; ap1 = Point_relative a 0.5 0.25; bp1 = Point_relative b 0.5 0.25; ap2 = Point_relative a 0.5 0.75; bp2 = Point_relative b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; value = b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; ap1' = ap1.image_rect; ap2' = ap2.image_rect; bp1' = bp1.image_rect; bp2' = bp2.image_rect; b''' = im_match_linear_search a' b'' ap1'.left ap1'.top bp1'.left bp1'.top ap2'.left ap2'.top bp2'.left bp2'.top object window, refine = im_match_linear a' b'' ap1'.left ap1'.top bp1'.left bp1'.top ap2'.left ap2'.top bp2'.left bp2'.top; } } /* make a colour overlay of two mono images */ Overlay a b = class Image value { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ] ++ super._check_args; _check_all = [ [a.bands == 1 && b.bands == 1, "a.bands == 1 && b.bands == 1"] ] ++ super._check_all; _vislevel = 3; ap1 = Point_relative a 0.5 0.25; bp1 = Point_relative b 0.5 0.25; ap2 = Point_relative a 0.5 0.75; bp2 = Point_relative b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; colour = Option "Colour overlay as" [ "Green over Red", "Blue over Red", "Red over Green", "Red over Blue", "Blue over Green", "Green over Blue" ] 0; value = [(a' ++ b''' ++ black), (a' ++ black ++ b'''), (b''' ++ a' ++ black), (b''' ++ black ++ a'), (black ++ a' ++ b'''), (black ++ b''' ++ a')]?colour { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; ap1' = ap1.image_rect; ap2' = ap2.image_rect; bp1' = bp1.image_rect; bp2' = bp2.image_rect; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1' ap2'; bp2'' = norm bp1' bp2'; b''' = im_match_linear_search a' b'' ap1'.left ap1'.top bp1'.left bp1'.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1'.left ap1'.top bp1'.left bp1'.top ap2''.left ap2''.top bp2''.left bp2''.top; black = image_new a.width a.height a.bands a.format a.coding a.type 0 0 0; } } /* browse through the bands of a multiband image with a slider */ Browse_multiband image = class Image value { _vislevel = 3; band = Slider 0 (image.bands - 1) 0; display = Option "Display as" [ "Grey", "Green over Red", "Blue over Red", "Red over Green", "Red over Blue", "Blue over Green", "Green over Blue" ] 0; value = output { down = (int) band.value; up = (int) (band.value + 1); remainder = band.value - down; a = (image.value ? up) * remainder; b = (image.value ? down) * (1 - remainder); c = image_new image.width image.height 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; output = [ a + b, a ++ b ++ c, a ++ c ++ b, b ++ a ++ c, b ++ c ++ a, c ++ a ++ b, c ++ b ++ a ] ? display; } } nip2-8.7.1/share/nip2/compat/7.8/Statistics.def0000644000175000017500000000610513351443023015703 00000000000000/* mean value of object */ Mean a = map_unary mean a; /* standard deviation of object */ Deviation a = map_unary deviation a; /* calculate a large set of stats on an object */ Stats a = map_unary stats a; #separator /* maximum of an object */ Max a = map_unary max a; /* minimum of an object */ Min a = map_unary min a; /* return complex number (max, min) */ Maxmin a = map_unary maxmin a { maxmin x = (Max x, Min x); } /* position of maximum in an image */ Maximum_position a = map_unary maxpos a; /* position of minimum in an image */ Minimum_position a = map_unary minpos a; #separator /* count the number of non-zeros in an image */ Count_set a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } /* count the number of zeros in an image */ Count_clear a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } #separator /* plot a scatter graph of a list of [x,y] coordinates */ Plot_scatter x //= map_unary widget x = widget x { widget data = class Image value { _check_args = [ [data, "data", check_xy_list] ] ++ super._check_args; width = 512; height = 512; plot_colour = Colour "Lab" [80, -80, 80]; xmin = foldr1 min_pair (map (extract 0) data); xmax = foldr1 max_pair (map (extract 0) data); ymin = foldr1 min_pair (map (extract 1) data); ymax = foldr1 max_pair (map (extract 1) data); axies = Toggle "Draw axies" true; mark = Point this x y { p = _to_image data?0; x = p?0; y = p?1; } mark_position_hint = "mark is at position:"; mark_position = _from_image [mark.left, mark.top]; // geometry _xrange = xmax - xmin; _yrange = ymax - ymin; _xscale = width / _xrange; _yscale = height / _yrange; // map an [x,y] point into the image coordinates _to_image p = [(p?0 - xmin) * _xscale, height - (p?1 - ymin) * _yscale]; // map an [x,y] point from image cods back to real cods _from_image p = [p?0 / _xscale + xmin, (height - p?1) / _yscale + ymin]; value = foldr plot background' data { plot_image_new width height pixel = image_new width height 3 Image_format.FLOAT Image_coding.NOCODING (Image_type.colour_spaces.lookup 0 1 plot_colour.colour_space) pixel 0 0; // background background = plot_image_new width height 0; // mark we plot mark_width = max_pair 1 (width / 100); mark_height = max_pair 1 (height / 100); mark = plot_image_new mark_width mark_height plot_colour; // draw axies on background background' = drawxy, axies = background { // axies xaxis = plot_image_new width 1 (Colour "Lab" [100, 0, 0]); yaxis = plot_image_new 1 height (Colour "Lab" [100, 0, 0]); origin = _to_image [0, 0]; drawx = im_insert_noexpand background xaxis 0 origin?1; drawxy = im_insert_noexpand drawx yaxis origin?0 0; } // plot a single point on an image plot p im = im_insert_noexpand im mark (x - mark_width / 2) (y - mark_height / 2) { p' = _to_image p; x = p'?0; y = p'?1; } } } } nip2-8.7.1/share/nip2/compat/7.8/_convert.def0000644000175000017500000003242113351443023015370 00000000000000 /* Convert an image ... just set the Type field. */ image_set_type type in = im_copy_set in type (im_header_double "Xres" in) (im_header_double "Yres" in) (im_header_int "Xoffset" in) (im_header_int "Yoffset" in); /* Convert an image ... just set origin */ image_set_origin xoff yoff in = im_copy_set in (im_header_int "Type" in) (im_header_double "Xres" in) (im_header_double "Yres" in) xoff yoff; /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = oo_unary_function to_matrix_op x, is_class x = tom x, is_real x || is_image x = error (errors.badargs ++ "to_matrix") { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (errors.badargs ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i && bands == 1 = (im_vips2mask ((double) i'')).value, is_image i && bands == 3 && width == 1 = error errors.not1band3band { width = im_header_int "Xsize" i; bands = im_header_int "Bands" i; split = bandsplit i; i' = im_insert (split?0) (split?1) 1 0; i'' = im_insert i' (split?2) 2 0; } } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_instanceof "Colour" x = oo_unary_function to_image_op x, is_class x = toi x, is_real x || is_image x = error (errors.badargs ++ "to_image") { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (errors.badargs ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } /* Try to make a real. */ to_real x = to_real x.value, is_class x = x, is_real x = abs x, is_complex x = error (errors.badargs ++ "to_real"); /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error "parse_c: not a digit", ! is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error "parse_number: badly formed number", len parts != 2 = sign * n { parts = splitpl [ member "+-", is_digit ] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, len parts != 4 = (ipart + fpart) * 10 ** exp { err = error "parse_float: badly formed number"; parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10**(len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Print integer as hex. */ print_hex i = "0", chars == [] = "0x" ++ reverse chars { digits = takewhile (not_equal 0) (map (bitwise_and 0xf) (iterate (converse right_shift 4) i)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'a' + (x - 10)); } /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[ 0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [ 0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { // divide by D50 white point xyz' = xyz / Vector [96.4250, 100.0, 82.4680]; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * Vector [95.0470, 100.0, 108.8827]; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { // divide by D65 white point xyz' = xyz / Vector [95.0470, 100.0, 108.8827]; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D50 xyz''' = xyz'' * Vector [96.4250, 100.0, 82.4680]; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz 96.4250 100 82.4680; /* Convert D50 Lab to XYZ. */ im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab 96.4250 100 82.4680; /* ... and mono conversions */ im_sRGB2mono in = clip2fmt (im_header_int "BandFmt" in) (im_recomb in (Matrix [[.3, .6, .1]])); im_mono2sRGB in = (unsigned char) (in ++ in ++ in); /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = fn x, is_image x = error (errors.badargs ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = fn x, is_image x = error (errors.badargs ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (errors.badargs ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (errors.badargs ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, LAB, im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, sRGB, im_mono2sRGB], [B_W, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy], [XYZ, LAB, im_XYZ2Lab], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS], [XYZ, RGB, im_XYZ2disp], [XYZ, sRGB, im_XYZ2sRGB], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ], [YXY, XYZ, im_Yxy2XYZ], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ], [LAB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ], [LAB, XYZ, im_Lab2XYZ], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ], [LAB, LAB, image_set_type LAB], [LAB, LCH, im_Lab2LCh], [LAB, UCS, im_Lab2UCS], [LAB, RGB, im_Lab2disp], [LAB, sRGB, im_XYZ2sRGB @ im_Lab2XYZ], [LAB, LABQ, im_Lab2LabQ], [LAB, LABS, im_Lab2LabS], [LCH, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab], [LCH, YXY, im_XYZ2Yxy @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab], [LCH, LAB, im_LCh2Lab], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS], [LCH, RGB, im_Lab2disp @ im_LCh2Lab], [LCH, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ], [UCS, XYZ, im_UCS2XYZ], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab], [UCS, LAB, im_UCS2Lab], [UCS, LCH, im_UCS2LCh], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab], [UCS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_UCS2Lab], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_XYZ2Lab @ im_sRGB2XYZ @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip], [LABQ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error ("unable to convert " ++ from_name ++ " to " ++ to_name) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; from_name = Image_type.type_names.lookup 1 0 from; to_name = Image_type.type_names.lookup 1 0 to; } /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_instanceof "Image" x || is_instanceof "Arrow" x || is_instanceof "Colour" x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_instanceof "Image" x = get_type_im x.image.value, is_instanceof "Arrow" x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_instanceof "Colour" x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.B_W, bands == 1 = type, bands == 3 && is_colorimetric = Image_type.MULTIBAND, bands != 3 && !is_colorimetric = type { is_colorimetric = Image_type.colour_spaces.present 1 type; type = im_header_int "Type" im; coding = im_header_int "Coding" im; bands = im_header_int "Bands" im; } } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; nip2-8.7.1/share/nip2/compat/7.8/Filter.def0000644000175000017500000003042313351443023014776 00000000000000/* Some useful masks. */ _filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; _filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; _filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; _filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; _filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; _filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; /* 3x3 blur of image */ Blur x = map_unary (conv _filter_blur) x; /* 3x3 sharpen of image */ Sharpen x = map_unary (conv _filter_sharp) x; /* 1-pixel displacement emboss */ Emboss x = map_unary (conv _filter_emboss) x; /* 3x3 median filter of image */ Median x = map_unary (rank 3 3 5) x; /* 3x3 laplacian of image */ Laplacian x = map_unary (conv _filter_laplacian) x; /* 3x3 Sobel edge detect of image */ Sobel x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv _filter_sobel im; b = conv (rot270 _filter_sobel) im; } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 _filter_lindet); images = map (converse conv im) masks; } } #separator /* custom convolution of an image */ Custom_convolution in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; border = Toggle "Output image matches input image in size" true; value = im_embed image' 0 off off image.width image.height, border = image' { conv_op = im_conv_raw, !separable && type == 0 = im_convsep_raw, separable && type == 0 = im_convf_raw, !separable && type == 1 = im_convsepf_raw, separable && type == 1 = error "boink!"; image' = conv_op image.value matrix; off = (matrix.width + 1) / 2; } } } /* blur with a radius and shape */ Custom_blur in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; radius = Slider 1 50 1; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; value = im_convsep in.value mask { /* Make a square mask. */ mask_sq_line = map (const 1) [1 .. 2 * radius.value - 1]; mask_sq_sum = foldr1 add mask_sq_line; mask_sq_sep = Matrix_con mask_sq_sum 0 [mask_sq_line]; /* Make a gaussian mask. sigma is not really related * to radius very well, sort-of bodge it. */ mask_g = im_gauss_imask (radius.value / 2) 0.2; mask_g_line = mask_g.value ? (mask_g.height / 2); mask_g_sum = foldr1 add mask_g_line; mask_g_sep = Matrix_con mask_g_sum 0 [mask_g_line]; mask = mask_sq_sep, shape.value == 0 = mask_g_sep; } } } /* cored sharpen of L only in LAB image */ Custom_sharpen in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; size = Option "Mask size" [ "3 x 3", "5 x 5", "7 x 7", "9 x 9", "11 x 11" ] 0; smooth_threshold = Slider 0 5 1.5; brighten_max = Slider 1 50 10; darken_max = Slider 1 50 50; flat_sharp = Slider (-2) 5 1; jaggy_sharp = Slider (-2) 5 2; value = im_sharpen in.value [3, 5, 7, 9, 11]?size smooth_threshold.value brighten_max.value darken_max.value flat_sharp.value jaggy_sharp.value; } } /* custom rank filter of an image */ Custom_rank in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; window_size_hint = "Length of side of window to pass " ++ "over image:"; window_size = 3; rank = (int) ((window_size * window_size + 1) / 2); border = Toggle "Output image matches input image in size" true; value = im_embed image' 0 off off image.width image.height, border = image' { image' = im_rank_raw image.value window_size window_size rank; off = (window_size + 1) / 2; } } } /* statistical difference of an image */ Statistical_difference in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; window_size_hint = "Length of side of window to pass " ++ "over image:"; window_size = 11; target_mean = 128; target_mean_weight = Slider 0 1 0.8; target_deviation = 50; target_deviation_weight = Slider 0 1 0.8; border = Toggle "Output image matches input image in size" true; value = im_embed image' 0 off off image.width image.height, border = image' { image' = im_stdif_raw image.value target_mean_weight.value target_mean target_deviation_weight.value target_deviation window_size window_size; off = (window_size + 1) / 2; } } } #separator /* various ideal fourier filters */ Ideal_filter = class { _preview_size = 64; _high_low image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff.value 0 0 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff.value 0 0 0 0; } _ring image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 6; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff.value ring_width.value 0 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff.value ring_width.value 0 0 0; } _band image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 12; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value 0 0; } /* high or low pass ideal filter */ High_low x = map_unary _high_low x; /* ring pass or reject ideal filter */ Ring x = map_unary _ring x; /* band pass or reject ideal filter */ Band x = map_unary _band x; } /* Gaussian fourier filters */ Gaussian_filter = class { _preview_size = 64; _high_low image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value + 4; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff.value amplitude_cutoff.value 0 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff.value amplitude_cutoff.value 0 0 0; } _ring image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 10; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff.value ring_width.value amplitude_cutoff.value 0 0; } value = im_flt_image_freq image.value _type frequency_cutoff.value ring_width.value amplitude_cutoff.value 0 0; } _band image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 16; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value 0; } value = im_flt_image_freq image.value _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value 0; } /* high or low pass Gaussian filter */ High_low x = map_unary _high_low x; /* ring pass or reject Gaussian filter */ Ring x = map_unary _ring x; /* band pass or reject Gaussian filter */ Band x = map_unary _band x; } /* various Butterworth fourier filters */ Butterworth_filter = class { _preview_size = 64; _high_low image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; order = Slider 1 10 2; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value + 2; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type order.value frequency_cutoff.value amplitude_cutoff.value 0 0; } value = im_flt_image_freq image.value _type order.value frequency_cutoff.value amplitude_cutoff.value 0 0; } _ring image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; order = Slider 1 10 2; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 8; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type order.value frequency_cutoff.value ring_width.value amplitude_cutoff.value 0; } value = im_flt_image_freq image.value _type order.value frequency_cutoff.value ring_width.value amplitude_cutoff.value 0; } _band image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; order = Slider 1 10 2; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 14; visualize_mask = Image vis { vis = image_set_type Image_type.FOURIER (rotquad mask); mask = im_create_fmask _preview_size _preview_size _type order.value frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value; } value = im_flt_image_freq image.value _type order.value frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value; } /* high or low pass Butterworth filter */ High_low x = map_unary _high_low x; /* ring pass or reject Butterworth filter */ Ring x = map_unary _ring x; /* band pass or reject Butterworth filter */ Band x = map_unary _band x; } nip2-8.7.1/share/nip2/compat/7.8/Format.def0000644000175000017500000001125013351443023014776 00000000000000/* various operations to convert numeric precision */ Convert_format_to = class { /* convert to unsigned 8 bit [0, 255] */ unsigned_8bit x = map_unary cast_unsigned_char x; /* convert to signed 8 bit [-128, 127] */ signed_8bit x = map_unary cast_signed_char x; /* convert to unsigned 16 bit [0, 65535] */ unsigned_16bit x = map_unary cast_unsigned_short x; /* convert to signed 16 bit [-32768, 32767] */ signed_16bit x = map_unary cast_signed_short x; /* convert to unsigned 32 bit [0, 4294967295] */ unsigned_32bit x = map_unary cast_unsigned_int x; /* convert to signed 32 bit [-2147483648, 2147483647] */ signed_32bit x = map_unary cast_signed_int x; /* convert to IEEE 32 bit floating point */ float_32bit x = map_unary cast_float x; /* convert to IEEE 64 bit floating point */ float_64bit x = map_unary cast_double x; /* convert to 64 bit complex (2 x IEEE 32 bit floating point) */ complex_64bit x = map_unary cast_complex x; /* convert to 128 bit complex (2 x IEEE 64 bit floating point) */ complex_128bit x = map_unary cast_double_complex x; } /* linear scale of pixel values to fit range 0-255 */ Scale_to_byte x = map_unary scale x; #separator /* try to make a matrix out of an object */ Convert_to_matrix in = map_unary to_matrix in; /* try to make an image out of an object */ Convert_to_image in = map_unary to_image in; #separator /* measure average value of a set of patches */ Matrix_from_colour_chart x = map_unary chart x { chart image = class Matrix value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; pacross = 6; pdown = 4; value = (im_measure image.value 0 0 image.width image.height pacross pdown).value; /* Hmm, not very helpful, we throw edits away. */ Matrix_vips_edit value scale offset filename display = chart image; } } /* make a synthetic colour chart image from a matrix */ Colour_chart_from_matrix matrix = map_unary build_chart matrix { build_chart matrix = class Image value { _check_args = [ [matrix, "matrix", check_Matrix] ] ++ super._check_args; patches_across = 6; patches_down = 4; patch_width = 50; patch_height = 50; border_width = 0; value = imagearray_assemble overlap overlap patch_table { overlap = -border_width; // patch numbers for row starts rowstart = map (multiply patches_across) [0 .. patches_down - 1]; // assemble patches ... each one a pixel value patches = map (take patches_across) (map (converse drop matrix.value) rowstart); // make an n-band constant image from eg. [1,2,3] patch v = image_new patch_width patch_height (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } #separator /* make a colour from the average values in an image */ Colour_from_image image = map_unary test image { test x = build_chart x, is_instanceof "Image" x = build_chart (Image pixel), is_instanceof "Point" x = error ("Colour_from_image: arg not Image or Point: " ++ print x) { pixel = x.image.extract_area x.left x.top 1 1; } build_chart image = class Colour colour_space value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; colour_space = table.lookup 1 0 type, table.present 1 type = error ("Colour_from_image: unable to make Colour " ++ "from " ++ Image_type.type_names.lookup 1 0 type ++ " image") { table = Image_type.colour_spaces; type = im_header_int "Type" image.value; } value = map mean (bandsplit image.value); } } /* make a constant image from a colour patch */ Image_from_colour x = map_unary build x { build c = class Image value { _check_args = [ [c, "c", check_Colour] ] ++ super._check_args; width = 64; height = 64; value = image_new width height 3 Image_format.FLOAT Image_coding.NOCODING (get_type c) c 0 0; } } #separator /* try to break object in into a list of components */ Decompose in = map_unary dec in { dec x = bandsplit x, is_instanceof "Image" x = map Vector x.value, is_instanceof "Matrix_base" x = x.value, is_instanceof "Vector" x || is_instanceof "Real" x = error "Decompose: not Image/Matrix/Vector/Real"; } /* try to put a list of objects together into a large single object */ Compose x = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof (is_instanceof "Image") x = Vector (map get_value x), is_listof (is_instanceof "Real") x = Matrix (map get_value x), is_listof (is_instanceof "Vector") x = map_unary Compose x, is_list x = error "Compose: not list of Image/Vector/Real/image/real" { get_value x = x.value; } nip2-8.7.1/share/nip2/compat/7.8/Colour.def0000644000175000017500000004036613351443023015023 00000000000000/* Save a bit of typing. */ _colour_conv from to x = map_unary (colour_transform from to) x; /* convert Mono to various formats */ Mono_to = class { /* convert mono colourspace to mono colourspace */ Mono x = _colour_conv Image_type.B_W Image_type.B_W x; /* convert mono colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.B_W Image_type.XYZ x; /* convert mono colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.B_W Image_type.YXY x; /* convert mono colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.B_W Image_type.LAB x; /* convert mono colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.B_W Image_type.LCH x; /* convert mono colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.B_W Image_type.UCS x; /* convert mono colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.B_W Image_type.RGB x; /* convert mono colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.B_W Image_type.sRGB x; /* convert mono colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.B_W Image_type.LABQ x; /* convert mono colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.B_W Image_type.LABS x; } /* convert XYZ to various formats */ XYZ_to = class { /* convert XYZ colourspace to mono colourspace */ Mono x = _colour_conv Image_type.XYZ Image_type.B_W x; /* convert XYZ colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.XYZ Image_type.XYZ x; /* convert XYZ colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.XYZ Image_type.YXY x; /* convert XYZ colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.XYZ Image_type.LAB x; /* convert XYZ colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.XYZ Image_type.LCH x; /* convert XYZ colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.XYZ Image_type.UCS x; /* convert XYZ colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.XYZ Image_type.RGB x; /* convert XYZ colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.XYZ Image_type.sRGB x; /* convert XYZ colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.XYZ Image_type.LABQ x; /* convert XYZ colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.XYZ Image_type.LABS x; } /* convert Yxy to various formats */ Yxy_to = class { /* convert Yxy colourspace to mono colourspace */ Mono x = _colour_conv Image_type.YXY Image_type.B_W x; /* convert Yxy colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.YXY Image_type.XYZ x; /* convert Yxy colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.YXY Image_type.YXY x; /* convert Yxy colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.YXY Image_type.LAB x; /* convert Yxy colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.YXY Image_type.LCH x; /* convert Yxy colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.YXY Image_type.UCS x; /* convert Yxy colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.YXY Image_type.RGB x; /* convert Yxy colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.YXY Image_type.sRGB x; /* convert Yxy colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.YXY Image_type.LABQ x; /* convert Yxy colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.YXY Image_type.LABS x; } /* convert Lab to various formats */ Lab_to = class { /* convert Lab colourspace to mono colourspace */ Mono x = _colour_conv Image_type.LAB Image_type.B_W x; /* convert Lab colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.LAB Image_type.XYZ x; /* convert Lab colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.LAB Image_type.YXY x; /* convert Lab colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.LAB Image_type.LAB x; /* convert Lab colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.LAB Image_type.LCH x; /* convert Lab colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.LAB Image_type.UCS x; /* convert Lab colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.LAB Image_type.RGB x; /* convert Lab colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.LAB Image_type.sRGB x; /* convert Lab colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.LAB Image_type.LABQ x; /* convert Lab colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.LAB Image_type.LABS x; } /* convert LCh to various formats */ LCh_to = class { /* convert LCh colourspace to mono colourspace */ Mono x = _colour_conv Image_type.LCH Image_type.B_W x; /* convert LCh colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.LCH Image_type.XYZ x; /* convert LCh colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.LCH Image_type.YXY x; /* convert LCh colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.LCH Image_type.LAB x; /* convert LCh colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.LCH Image_type.LCH x; /* convert LCh colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.LCH Image_type.UCS x; /* convert LCh colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.LCH Image_type.RGB x; /* convert LCh colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.LCH Image_type.sRGB x; /* convert LCh colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.LCH Image_type.LABQ x; /* convert LCh colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.LCH Image_type.LABS x; } /* convert UCS to various formats */ UCS_to = class { /* convert UCS colourspace to mono colourspace */ Mono x = _colour_conv Image_type.UCS Image_type.B_W x; /* convert UCS colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.UCS Image_type.XYZ x; /* convert UCS colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.UCS Image_type.YXY x; /* convert UCS colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.UCS Image_type.LAB x; /* convert UCS colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.UCS Image_type.LCH x; /* convert UCS colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.UCS Image_type.UCS x; /* convert UCS colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.UCS Image_type.RGB x; /* convert UCS colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.UCS Image_type.sRGB x; /* convert UCS colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.UCS Image_type.LABQ x; /* convert UCS colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.UCS Image_type.LABS x; } /* convert RGB to various formats */ RGB_to = class { /* convert RGB colourspace to mono colourspace */ Mono x = _colour_conv Image_type.RGB Image_type.B_W x; /* convert RGB colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.RGB Image_type.XYZ x; /* convert RGB colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.RGB Image_type.YXY x; /* convert RGB colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.RGB Image_type.LAB x; /* convert RGB colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.RGB Image_type.LCH x; /* convert RGB colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.RGB Image_type.UCS x; /* convert RGB colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.RGB Image_type.RGB x; /* convert RGB colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.RGB Image_type.sRGB x; /* convert RGB colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.RGB Image_type.LABQ x; /* convert RGB colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.RGB Image_type.LABS x; } /* convert sRGB to various formats */ sRGB_to = class { /* convert sRGB colourspace to mono colourspace */ Mono x = _colour_conv Image_type.sRGB Image_type.B_W x; /* convert sRGB colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.sRGB Image_type.XYZ x; /* convert sRGB colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.sRGB Image_type.YXY x; /* convert sRGB colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.sRGB Image_type.LAB x; /* convert sRGB colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.sRGB Image_type.LCH x; /* convert sRGB colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.sRGB Image_type.UCS x; /* convert sRGB colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.sRGB Image_type.RGB x; /* convert sRGB colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.sRGB Image_type.sRGB x; /* convert sRGB colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.sRGB Image_type.LABQ x; /* convert sRGB colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.sRGB Image_type.LABS x; } /* convert LabQ to various formats */ LabQ_to = class { /* convert LabQ colourspace to mono colourspace */ Mono x = _colour_conv Image_type.LABQ Image_type.B_W x; /* convert LabQ colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.LABQ Image_type.XYZ x; /* convert LabQ colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.LABQ Image_type.YXY x; /* convert LabQ colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.LABQ Image_type.LAB x; /* convert LabQ colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.LABQ Image_type.LCH x; /* convert LabQ colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.LABQ Image_type.UCS x; /* convert LabQ colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.LABQ Image_type.RGB x; /* convert LabQ colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.LABQ Image_type.sRGB x; /* convert LabQ colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.LABQ Image_type.LABQ x; /* convert LabQ colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.LABQ Image_type.LABS x; } /* convert LabS to various formats */ LabS_to = class { /* convert LabS colourspace to mono colourspace */ Mono x = _colour_conv Image_type.LABS Image_type.B_W x; /* convert LabS colourspace to XYZ colourspace */ XYZ x = _colour_conv Image_type.LABS Image_type.XYZ x; /* convert LabS colourspace to Yxy colourspace */ Yxy x = _colour_conv Image_type.LABS Image_type.YXY x; /* convert LabS colourspace to Lab colourspace */ Lab x = _colour_conv Image_type.LABS Image_type.LAB x; /* convert LabS colourspace to LCh colourspace */ LCh x = _colour_conv Image_type.LABS Image_type.LCH x; /* convert LabS colourspace to UCS colourspace */ UCS x = _colour_conv Image_type.LABS Image_type.UCS x; /* convert LabS colourspace to RGB colourspace */ RGB x = _colour_conv Image_type.LABS Image_type.RGB x; /* convert LabS colourspace to sRGB colourspace */ sRGB x = _colour_conv Image_type.LABS Image_type.sRGB x; /* convert LabS colourspace to LabQ colourspace */ LabQ x = _colour_conv Image_type.LABS Image_type.LABQ x; /* convert LabS colourspace to LabS colourspace */ LabS x = _colour_conv Image_type.LABS Image_type.LABS x; } #separator /* recombine image bands with an editable matrix */ Colour_recombination in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; matrix = Matrix_rec (identity_matrix image.bands); value = recomb matrix image.value; } } /* colour temperature conversions */ Colour_temperature = class { /* convert XYZ from D65 to D50 ... use the Bradford approximation */ D65XYZ_to_D50XYZ in = map_unary (colour_unary im_D652D50) in; /* convert XYZ from D50 to D65 ... use the Bradford approximation */ D50XYZ_to_D65XYZ in = map_unary (colour_unary im_D502D65) in; } /* various colour difference metrics */ dE_ = class { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ _apply_cvt cvt x = cvt x, is_instanceof "Image" x || is_instanceof "Colour" x || is_image x = x; _diff cvt in1 in2 = abs_vec (_apply_cvt cvt in1 - _apply_cvt cvt in2); /* Converter to LAB. */ _lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ _ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; /* calculate delta-E CIE76 for two objects */ CIE76 in1 in2 = map_binary (_diff _lab_cvt) in1 in2; /* calculate delta-E00 (CIEDE2000) for two objects */ CIE00 in1 in2 = map_binary (colour_binary "im_dE00_fromLab" im_dE00_fromLab) in1 in2; /* calculate delta-E CMC(1:1) for two objects */ UCS in1 in2 = map_binary (_diff _ucs_cvt) in1 in2; } #separator /* apply a coloured tint to a monochrome image */ Tint_mono_image in = map_unary apply_tint in { apply_tint in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; tint = Colour "Lab" [50, 0, 0]; value = image_set_type Image_type.LAB (fancytint inp l_tint a_tint b_tint) { // input image ... to L only inp_lab = colour_transform_to Image_type.LAB in.value; inp = inp_lab?0; // make sure tint is LAB (might be edited) lab_tint = colour_transform_to Image_type.LAB tint; // selected lab l_tint = lab_tint.value?0; a_tint = lab_tint.value?1; b_tint = lab_tint.value?2; // fancy tint function ... don't tint black and white fancytint im l a b = im ++ ima ++ imb { mod = (100 - im) / (100 - l), im > l = im / l; backgr = image_new in.width in.height 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; ima = mod * (backgr + a); imb = mod * (backgr + b); } } } } /* displace neutral axis in LAB colourspace */ Adjust_cast image = map_unary widget image { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; green_red = Slider (-20) 20 0; blue_yellow = Slider (-20) 20 0; value = (colour_transform_to (get_type image) image'').value { image' = colour_transform_to Image_type.LAB image; image'' = image' + Vector [0, green_red.value, blue_yellow.value]; } } } /* displace h, scale LC in LCh colourspace */ Adjust_hue_saturation_brightness image = map_unary widget image { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; hue = Slider 0 360 0; saturation = Slider 0.01 5 1; brightness = Slider 0.01 5 1; value = (colour_transform_to (get_type image) image'').value { image' = colour_transform_to Image_type.LCH image; image'' = image' * Vector [bv, sv, 1] + Vector [0, 0, hv]; bv = brightness.value; sv = saturation.value; hv = hue.value; } } } /* find pixels with a similar colour */ Similar_colour image = map_unary match image { match image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; target_patch = Region image (20 - image.xoffset) (20 - image.yoffset) 10 10; target_colour = Colour_from_image target_patch; dE_threshold = Slider 0 100 10; value = (dE_.CIE76 image target_colour < dE_threshold).value; } } /* plot an ab scatter histogram */ Plot_ab_scatter image = map_unary widget image { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; bins = 8; value = bg * (((90 / mx) * hist) ++ blk) { lab = colour_transform_to Image_type.LAB image.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins ab; mx = max hist; bg = lab_slice bins 1; blk = 1 + im_black bins bins 2; } } } nip2-8.7.1/share/nip2/compat/7.8/Morphology.def0000644000175000017500000000626313351443023015715 00000000000000/* Some useful masks. */ _morph_mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; _morph_mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; _morph_mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; _morph_thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; /* dilate x with 8-connected mask */ Dilate8 x = map_unary (dilate _morph_mask8) x; /* dilate x with 4-connected mask */ Dilate4 x = map_unary (dilate _morph_mask4) x; /* erode x with 8-connected mask */ Erode8 x = map_unary (erode _morph_mask8) x; /* erode x with 4-connected mask */ Erode4 x = map_unary (erode _morph_mask4) x; #separator /* open with 8-connected mask */ Open x = map_unary (dilate _morph_mask8 @ erode _morph_mask8) x; /* close with 8-connected mask */ Close x = map_unary (erode _morph_mask8 @ dilate _morph_mask8) x; /* remove single points */ Clean x = map_unary clean x { clean x = x ^ erode _morph_mask1 x; } /* thin once */ Thin x = map_unary thinall x { masks = take 8 (iterate rot45 _morph_thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } #separator /* dilate object x with mask m */ Dilate m x = map_unary (dilate m) x; /* erode object x with mask m */ Erode m x = map_unary (erode m) x; /* dilate mask m with itself n times */ Dilate_multiple m n = (iterate (dilate m) m)?n; /* erode mask m with itself n times */ Erode_multiple m n = (iterate (erode m) m)?n; #separator /* morph with a mask you can edit */ Custom_morphology in = map_unary morph in { morph image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; mask = _morph_mask8; type = Option "Operation" ["Erode", "Dilate"] 1; hint_apply_n_times = "Number of times to apply mask:"; apply_n_times = 1; border = Toggle "Output image matches input image in size" true; value = im_embed image' 0 xoff yoff image.width image.height, border = image' { fatmask = (iterate (dilate mask) mask) ? (apply_n_times - 1); image' = im_erode_raw image.value fatmask, type.value == 0 = im_dilate_raw image.value fatmask; xoff = (fatmask.width + 1) / 2; yoff = (fatmask.height + 1) / 2; } } } /* search in from the edges of an image for the first non-zero pixel */ Find_profile in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; value = image_set_type Image_type.HISTOGRAM [ im_profile image.value 0, rot270 (im_profile image.value 1), im_profile (flipud image.value) 0, rot270 (im_profile (fliplr image.value) 1) ]?edge; } } /* count the average number of black-to-white transitions across an image */ Count_lines in = map_unary widget in { widget image = class Real value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; value = im_cntlines image.value edge.value; } } nip2-8.7.1/share/nip2/compat/7.8/Resize.def0000644000175000017500000000463613351443023015021 00000000000000_resize_interp = Option "Interpolation" (map (extract 0) Interpolate.names.value) Interpolate.bilinear; /* resize image x by any scale factor */ Resize_image x = map_unary widget x { widget image = class Image value { _vislevel = 3; factor = 1; interp = _resize_interp; value = resize factor factor interp.value image.value; } } /* resize image with separate x/y factors */ Resize_xy_image x = map_unary widget x { widget image = class Image value { _vislevel = 3; xfactor = 1; yfactor = 1; interp = _resize_interp; value = resize xfactor yfactor interp.value image.value; } } /* place image x in a larger piece of image */ Resize_canvas x = map_unary widget x { widget image = class Image value { _vislevel = 3; new_image_width = image.width; new_image_height = image.height; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east" ] 4; fill = Option "Fill background with" [ "White", "Black" ] 0; value = im_insert_noexpand background image.value xp yp { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; background_colour = image_white image, fill == 0 = Vector (map (const 0) [1 .. bands]); // placement vectors ... left, centre, right xposv = [0, new_image_width / 2 - width / 2, new_image_width - width]; yposv = [0, new_image_height / 2 - height / 2, new_image_height - height]; xp = xposv?((int) (position % 3)); yp = yposv?((int) (position / 3)); background = image_new new_image_width new_image_height bands format coding type background_colour 0 0; } } } #separator /* resize image x so that the shortest axis is a certain size */ Shrink_to = class { _shrink_width default_size image = class Image value { size = default_size; interp = _resize_interp; value = resize factor factor interp.value image.value { xfac = size / image.width; yfac = size / image.height; factor = max_pair xfac yfac; } } /* shrink minimum dimension to 400 pixels */ Quicklook x = map_unary (_shrink_width 400) x; /* shrink minimum dimension to 64 pixels */ Icon x = map_unary (_shrink_width 64) x; } nip2-8.7.1/share/nip2/compat/7.8/Math.def0000644000175000017500000001325113351443023014442 00000000000000/* basic arithmetic for objects */ Arithmetic = class { /* add a and b */ Add a b = map_binary add a b; /* subtract b from a */ Subtract a b = map_binary subtract a b; /* multiply a by b */ Multiply a b = map_binary multiply a b; /* divide a by b */ Divide a b = map_binary divide a b; /* remainder after dividing a by b */ Remainder a b = map_binary remainder a b; sep1 = Separator; /* absolute value of x */ Absolute_value x = map_unary abs x; /* like Absolute_value, but treat pixels as vectors */ Absolute_value_vector x = map_unary abs_vec x; /* calculate unit vector for band elements */ Sign x = map_unary sign x; /* multiply by -1 */ Negate x = map_unary unary_minus x; } /* trigonometry operations (all in degrees) */ Trig = class { /* calculate sine x */ Sin x = map_unary sin x; /* calculate cosine x */ Cos x = map_unary cos x; /* calculate tangent x */ Tan x = map_unary tan x; sep1 = Separator; /* calculate arc sine x */ Asin x = map_unary asin x; /* calculate arc cosine x */ Acos x = map_unary acos x; /* calculate arc tangent x */ Atan x = map_unary atan x; sep2 = Separator; /* convert degrees to radians */ Rad x = map_unary rad x; /* convert radians to degrees */ Deg x = map_unary deg x; sep3 = Separator; /* is angle within t degrees of r, mod 360 */ Angle_range t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } /* logarithms and anti-logs */ Log = class { /* calculate e ** x */ Exponential x = map_unary (power e) x; /* log base e of x */ Log_natural x = map_unary log x; sep1 = Separator; /* log base 10 of x */ Log10 x = map_unary log10 x; /* calculate 10 ** x */ Exponential10 x = map_unary (power 10) x; sep2 = Separator; /* calculate x ** y */ Raise_to_power x y = map_binary power x y; } /* operations on complex numbers and images */ Complex = class { /* extract fields from complex */ Complex_extract = class { /* extract real part of complex */ Real in = map_unary re in; /* extract imaginary part of complex */ Imaginary in = map_unary im in; } /* join a and b to make a complex */ Complex_build a b = map_binary comma a b; sep1 = Separator; /* convert real and imag to amplitude and phase */ Polar a = map_unary polar a; /* convert (amplitude, phase) image to rectangular coordinates */ Rectangular x = map_unary rectangular x; sep2 = Separator; /* invert imaginary part */ Conjugate x = map_unary conj x; } /* bitwise boolean operations for integer objects */ Boolean = class { /* bitwise and of a and b */ And a b = map_binary bitwise_and a b; /* bitwise or of a and b */ Or a b = map_binary bitwise_or a b; /* bitwise exclusive or of a and b */ Eor a b = map_binary eor a b; /* invert a */ Not a = map_unary not a; sep1 = Separator; /* shift a right by b bits */ Right_shift a b = map_binary right_shift a b; /* shift a left by b bits */ Left_shift a b = map_binary left_shift a b; sep2 = Separator; /* b where a is non-zero, c elsewhere */ If_then_else a b c = map_trinary if_then_else a b c; /* or the bands of an image together */ Band_or im = foldr1 bitwise_or (bandsplit im); /* and the bands of an image together */ Band_and im = foldr1 bitwise_and (bandsplit im); } /* all comparison operations */ Relational = class { /* find points at which a is equal to b */ Equal a b = map_binary equal a b; /* find points at which a is not equal to b */ Not_equal a b = map_binary not_equal a b; /* find points at which a is greater than b */ More a b = map_binary more a b; /* find points at which a is less than b */ Less a b = map_binary less a b; /* find points at which a is greater than or equal to b */ More_equal a b = map_binary more_equal a b; /* find points at which a is less than or equal to b */ Less_equal a b = map_binary less_equal a b; } /* operations on lists */ List = class { /* take first element of list */ Head x = hd x; /* drop the first element of list */ Tail x = tl x; /* drop the last element of list */ Init x = init x; /* take the last element of list */ Last x = last x; sep1 = Separator; /* reverse order of elements in list */ Reverse x = reverse x; /* sort elements of list into ascending order */ Sort x = sort x; /* remove duplicates from list */ Make_set x = mkset equal x; /* exchange rows and columns in a list of lists */ Transpose_list x = transpose x; /* flatten a list of lists into a single list */ Concat l = concat l; sep2 = Separator; /* find the length of list */ Length x = len x; /* return element n from list (index from zero) */ Subscript n x = n ? x; /* take the first n elements of list x */ Take n x = take n x; /* drop the first n elements of list x */ Drop n x = drop n x; sep3 = Separator; /* join two lists end to end */ Join a b = a ++ b; /* put element a on the front of list x */ Cons a x = a : x; /* join two lists, pairwise */ Zip a b = zip2 a b; } /* various rounding operations */ Round = class { /* smallest integral value not less than x */ Ceil x = map_unary ceil x; /* largest integral value not greater than x */ Floor x = map_unary floor x; /* round to nearest integer */ Rint x = map_unary rint x; } /* forward and reverse fourier transforms */ Fourier = class { /* find fourier transform of image */ Forward a = map_unary (rotquad @ fwfft) a; /* find inverse fourier transform of image */ Reverse a = map_unary (invfft @ rotquad) a; /* rotate quadrants */ Rotate_quadrants a = map_unary rotquad a; } nip2-8.7.1/share/nip2/compat/7.8/Print.def0000644000175000017500000001541613351443023014652 00000000000000/* cored sharpen of L only in LAB image ... tuned for typical printers */ Sharpen_for_print in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "300 dpi", "150 dpi", "75 dpi" ] 0; // sharpen params for 300, 150 and 75 dpi // just change the size of the area we search _param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5] ]; _params = _param_table?target_dpi; value = im_sharpen (colour_transform_to Image_type.LABQ in.value) _params?0 _params?1 _params?2 _params?3 _params?4 _params?5; } } /* adjust tone curve on L* */ Tone_for_print in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; black = Slider 0 100 0; white = Slider 0 100 100; shadow_point = Slider 0.1 0.3 0.2; mid_point = Slider 0.4 0.6 0.5; highlight_point = Slider 0.7 0.9 0.8; shadow_adjust = Slider (-15) 15 0; mid_adjust = Slider (-30) 30 0; highlight_adjust = Slider (-15) 15 0; preview_curve = Image (im_tone_build black.value white.value shadow_point.value mid_point.value highlight_point.value shadow_adjust.value mid_adjust.value highlight_adjust.value); value = im_tone_map (colour_transform_to Image_type.LABQ in.value) preview_curve.value; } } /* morph image colours in LAB space ... useful for tweaking colour for print */ Morph_for_print in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; L_scale = 1.15; L_offset = -4.2; ab_scale = Slider 1 1.5 1.15; a_offset = Slider (-10) 10 0; b_offset = Slider (-10) 10 5; grey_correction = Matrix_con 1 0 [ [5, 5, -1 ], [10, 4, -1 ], [15, 2, -1 ], [20, 1, 1 ], [25, 1, 2 ], [30, 0, 1 ], [35, 0, 1 ], [40, 0, 1 ], [45, 0, 1 ], [50, 0, 1 ], [55, 0, 0 ], [99, 0, 0 ] ]; value = im_lab_morph in.value (Vector [0, a_offset.value, b_offset.value] + grey_correction) L_offset L_scale ab_scale.value ab_scale.value; } } #separator _sample_print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; _sample_monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; _render_intents = Option "Render intent" [ "Perceptual", "Relative", "Saturation", "Absolute" ] 3; /* transform from PCS to device space */ ICC_export in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; profile = Filename _sample_print_profile; intent = _render_intents; depth = Option "Output depth" ["8 bit", "16 bit"] 0; value = im_icc_export_depth in.value [8, 16]?depth (expand profile.value) intent.value; } } /* transform from device space to PCS */ ICC_import in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _check_all = [ [in.bands == 3 || in.bands == 4, "in.bands == 3 || in.bands == 4" ] ] ++ super._check_all; _vislevel = 3; profile = Filename _sample_monitor_profile, in.bands == 3 = Filename _sample_print_profile; intent = _render_intents; value = im_icc_import in.value (expand profile.value) intent.value; } } /* transform between two device spaces */ ICC_transform in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; in_profile = Filename _sample_monitor_profile; out_profile = Filename _sample_print_profile; intent = _render_intents; value = im_icc_transform in.value (expand in_profile.value) (expand out_profile.value) intent.value; } } /* transform from absolute to relative colorimetry */ ICC_ac2rc in = map_unary widget in { widget in = class Image value { _check_args = [ [in, "in", check_Image] ] ++ super._check_args; _vislevel = 3; profile = Filename _sample_print_profile; value = im_icc_ac2rc in.value (expand profile.value); } } #separator /* convert between XYZ and Lab for D50 */ D50XYZ_to_D50Lab in = map_unary (colour_unary im_D50XYZ2Lab) in; /* convert between XYZ and Lab for D50 */ D50Lab_to_D50XYZ in = map_unary (colour_unary im_D50Lab2XYZ) in; #separator /* add an editable drop shadow to an image */ Drop_shadow x = map_unary shadow x { shadow image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; shadow_width = Slider 0 50 5; shadow_height = Slider 0 50 5; shadow_softness = Slider 0 20 5; use_mask = Toggle "Use mask to make shadow" false; mask_image = foldr1 bitwise_and (bandsplit (image > 128)); background_colour = 255; shadow_colour = 128; value = final { blur_size = shadow_softness.value * 2 + 1; // matrix we blur with to soften shadows mask_g = im_gauss_imask (blur_size / 3) 0.2; mask_g_line = mask_g.value ? (mask_g.height / 2); mask_g_sum = foldr1 add mask_g_line; blur_matrix = Matrix_con mask_g_sum 0 [mask_g_line]; mask_size = mask_g.width; // size of final image we build final_width = image.width + 2 * mask_size + shadow_width.value; final_height = image.height + 2 * mask_size + shadow_height.value; // make a plain image mk_background colour = image_new final_width final_height image.bands image.format Image_coding.NOCODING image.type colour 0 0; // make a mask image ... place at (x,y) in the final // image mk_mask x y = im_insert black mask_image.value x y, use_mask = im_insert black white x y { black = image_new final_width final_height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 0 0 0; white = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; } // make the shadow mask image ... offset mask and // soften shadow_mask = mk_mask (mask_size + shadow_width.value) (mask_size + shadow_height.value); shadow_mask' = im_convsep shadow_mask blur_matrix; // make underlay ... use shadow mask to blend between // background colour and shadow colour background = mk_background background_colour; shadow = mk_background shadow_colour; underlay = im_blend shadow_mask' shadow background; // overlay ... place image at final position overlay = mk_background 0; overlay' = im_insert overlay image.value mask_size mask_size; // overlay mask overlay_mask = mk_mask mask_size mask_size; final = if overlay_mask then overlay' else underlay; } } } nip2-8.7.1/share/nip2/compat/7.8/Capture.def0000644000175000017500000001117413351443023015156 00000000000000/* make a new capture image */ Capture_video = class Image value { // shortcut to prefs _prefs = Workspaces.Preferences; device = _prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] _prefs.VIDEO_CHANNEL; brightness = Slider 0 32767 _prefs.VIDEO_BRIGHTNESS; colour = Slider 0 32767 _prefs.VIDEO_COLOUR; contrast = Slider 0 32767 _prefs.VIDEO_CONTRAST; hue = Slider 0 32767 _prefs.VIDEO_HUE; frames_hint = "Average this many frames:"; frames = Slider 0 100 _prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" _prefs.VIDEO_MONO; crop = Toggle "Crop image" _prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value brightness.value colour.value contrast.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = _prefs.VIDEO_CROP_LEFT; top = _prefs.VIDEO_CROP_TOP; width = min_pair _prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair _prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_hint = "Stretch vertically by this factor:"; aspect_ratio = _prefs.VIDEO_ASPECT; value = frame' { frame = edit_crop.value, crop = _raw_grab.value; frame' = colour_transform Image_type.sRGB Image_type.B_W frame, mono = frame; } } #separator /* use white image w to correct image i */ Light_correct w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } /* equalize bands in region r */ White_balance r = map_unary wb r { wb region = clip2fmt region.format (region.image * Vector facs) { target = mean region; facs = map (divide target) (map mean (bandsplit region)); } } /* remove features larger than a certain size from image x */ Smooth_image x = map_unary smooth x { smooth image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; feature = Slider 1 50 20; value = im_resize_linear (im_shrink image.value feature.value feature.value) image.width image.height; } } #separator /* calculate RGB -> LAB transform from an image of a Macbeth colour chart */ Calibrate_chart image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; // get macbeth data file to use macbeth = Filename "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = im_measure image.value 0 0 image.width image.height 6 4; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'); // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it linearising_lut = Image _linear_lut; // map the original image through the lineariser to get linear 0-1 // RGB image _image' = im_maplut image.value linearising_lut.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab value = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb M _image')); // measure again and compute dE76 _camera'' = im_measure value 0 0 image.width image.height 6 4; _dEs = map abs_vec (map Vector (_camera'' - _true_Lab).value); final_dE76 = mean (Vector _dEs); _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = _macbeth_names ? _worst ++ " (patch " ++ print (_worst + 1) ++ ")"; } /* apply RGB -> LAB transform to an image */ Calibrate_image calib image = class Image value { _check_args = [ [calib, "calib", check_instance "Calibrate_chart"], [image, "image", check_Image] ] ++ super._check_args; // map the original image through the lineariser to get linear 0-1 // RGB image _image' = im_maplut image.value calib.linearising_lut.value; // convert linear RGB camera to Lab value = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M _image')); } nip2-8.7.1/share/nip2/compat/7.8/_generate.def0000644000175000017500000000360113351443023015500 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = (unsigned int) (h ++ v) { h = (x - 1) * im_fgrey x y; v = (y - 1) * im_rot90 (im_fgrey y x); } /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12 */ image_new w h b fmt coding type pixel xoff yoff = im'''' { im = im_black w h b + pixel; im' = clip2fmt fmt im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_origin (size / 2) (size / 2) (image_set_type Image_type.LAB im) { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey size size; /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = L ++ A2 ++ A4; } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (map (const (max_value.lookup 1 0 format)) [1 .. bands]) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } nip2-8.7.1/share/nip2/compat/7.8/X_ray.def0000644000175000017500000002501513351443023014634 00000000000000/* replace dark or light section of im1 with section from im2 */ Replace_area im1 im2 = class Image value { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ] ++ super._check_args; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.1 0.1 0.1 0.1; /* Point on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Point im2 (im2.width * 0.1 - im2.xoffset) (im2.height * 0.1 - im2.yoffset); _r2 = Region im2 p2.left p2.top r1.width r1.height; _mask = [r1 <= Options.scale_cutoff, r1 >= Options.scale_cutoff] ? Options.control; mask = _mask?0; Options = option_1, format < 4 = option_2 { format = im1.format; option_1 = class { _vislevel = 3; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ control = Option "Removing a" [ "Dark Area", "Light Area" ] 1; /* Used to select the area to be replaced. */ scale_cutoff = Slider 0.01 mx (mx / 2) { mx = Image_format.maxval im1.format; } /* Option toggle how the levels in the replacment area are calculated. * Replacement with gaussian noise uses the scale&offset balancing. */ process = Option "Use" [ "Scale&Offset Balancing", "Gaussian noise replacement", "Histogram Balancing" ] 0; /* This allows the function to be paused. */ pause = Toggle "Pause function to allow easy adjustment of region r1." true; } option_2 = class { _vislevel = 3; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ control = Option "Removing a" [ "Dark Area", "Light Area" ] 1; /* Used to select the area to be replaced. */ scale_cutoff = Slider 0.01 mx (mx / 2) { /* the below function can not cope with floats * and don't need massive range for 32-bit ints so * will just define the max as for a 16 bit unsigned. */ mx = Image_format.maxval 2; //im1.format; } /* Option toggle how the levels in the replacment area are calculated. * Replacement with gaussian noise uses the scale&offset balancing. */ process = Option "Use" [ "Scale&Offset Balancing", "Gaussian noise replacement" ] 0; /* This allows the function to be paused. */ pause = Toggle "Pause function to allow easy adjustment of region r1." true; } } value = im1.value, Options.pause = im_insert im1.value patch r1.left r1.top { patch = _so_balance mask r1.value _r2.value false, Options.process == 0; = _so_balance mask r1.value _r2.value true, Options.process == 1; = _hist_balance_2 mask r1.value _r2.value; } }; #separator /* Balance the effect of secondary structure on an X-ray image * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference * masks, where the masks are white on a black background. Then simplifys * the original X-ray to reduce interference from stretchers cradles etc. */ Balance_areas im_in m_control m_list = class Image value { _vislevel = 3; _format = im_in.format; Options = option_1, format < 4 = option_2 { format = im_in.format; option_1 = class { _vislevel = 3; pause = Toggle "Pause Process." true; blur = Slider 0 5 0; _blur = rint blur.value; option = Toggle "Use Scale&Offset Balancing rather than Histogram." true; _option = option; } option_2 = class { _vislevel = 3; pause = Toggle "Pause Process." true; blur = Slider 0 5 0; _blur = rint blur.value; _option = true; } } _control_im = _section_select2 im_in m_control; _control_values = _so_values _control_im; /* blur mask over a set number of pixels then histogram match an area * of the original image defined by m_current to the _control_im * then blend the matched area back into im_in. */ process m_current im_start = im_out { alternative = false; bl_mask = _mask_blur_2 m_current Options._blur; scaled_im = _so_convert _control_values im_start m_current, Options._option == true = _hist_convert_2 _control_im im_start m_current; fmt_im = clip2fmt im_start.format scaled_im; blended_im = im_blend bl_mask scaled_im.value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } value = im_in.value, Options.pause == true = (foldr process im_in m_list).value; }; _so_balance mask im1 im2 gauss = result { /* Extract the undamaged areas. */ im1' = if !mask then Image im1 else 0; im2' = if !mask then Image im2 else 0; /* Find the non_zero means of the undamaged areas. */ m1 = _mean_fn im1'; m2 = _mean_fn im2'; im1_mn = im1' - m1; im2_mn = im2' - m2; scale = (max im1_mn)/(max im2_mn); im2_corrected_a = ((im2 - m2) * scale) + m1; im2_corrected_b = clip2fmt im1'.format im2_corrected_a; /* Option to convert replacement image to scaled gaussian noise */ im2_corrected = im2_corrected_b, gauss == false = _gauss_noise im2_corrected_b; /* Blur mask. */ mask' = _mask_blur_2 mask 5; //mask' = _feather_mask_2 5 mask.value; /* Blend im2 into im1. */ result = im_blend mask' im2_corrected im1; }; /* make a new image of gaussian noise */ _gauss_noise im2 = value { i = Image (im2); width = i.width; height = i.height; mean = Mean i; deviation = Deviation i; noise = im_gaussnoise width height mean deviation; value = clip2fmt i.format noise; }; /* Dilate and blur a mask by a number of pixels. * *_feather_mask_2 pixels mask * = im_convsep (dilate dilate_matrix mask) blur_matrix *{ * dilate_matrix = (iterate (dilate _morph_mask8) _morph_mask8) ? pixels; * blur_matrix = Matrix_con pixels 0 [(map (const 1) [1 .. pixels])]; *}; */ /* Mask is 255 to indicate parts of im1 which are damaged: replace these bits * with the corresponding parts of im2. * * Match the histograms of the two images to hide grey-level differences, be * careful to only consider undamaged sections. * * Feather the edges of the blend to hide the join. * * mask is an Image class. im1, im2 and result are vips images. */ _hist_balance_2 mask im1 im2 = result { format = im_header_int "BandFmt" im1; bands = im_header_int "Bands" im1; /* checks for 8 or 16 bit signed and converts to unsigned */ force_unsigned i = clip2fmt Image_format.UCHAR (i + 128), format == Image_format.CHAR = clip2fmt Image_format.USHORT (i + 32768), format == Image_format.SHORT = i; /* undo any force_unsigned */ format_restore i = clip2fmt Image_format.CHAR (i - 128), format == Image_format.CHAR = clip2fmt Image_format.SHORT (i - 32768), format == Image_format.SHORT = i; /* Find histogram and then zap the zero column (0 == background). For * 16-bit images, the histogram can be smaller than 65535 .... expand * up to full size. */ build_hist i = im_insert big_black h' 0 0 { max_value = Image_format.maxval i.format; h = hist_find i.value; black_1 = image_new 1 1 i.bands Image_format.UINT Image_coding.NOCODING i.type 0 0 0; big_black = image_new max_value 1 i.bands Image_format.UINT Image_coding.NOCODING i.type 0 0 0; h' = im_insert h black_1 0 0; } /* We can't get hists of signed images :-( go unsigned if we have to. */ im1' = force_unsigned im1; im2' = force_unsigned im2; /* Extract the undamaged areas. */ reference = if !mask then Image im1' else 0; secondary = if !mask then Image im2' else 0; /* Find the hists of the undamaged areas. */ h1 = build_hist reference; h2 = build_hist secondary; /* Match greylevels of im2 to match im1. */ im2'' = hist_map (hist_match h1 h2) im2'; /* Feather mask. */ mask' = _mask_blur_2 mask 5; //mask' = _feather_mask_2 5 mask.value; /* Blend im2 into im1. */ im1'' = im_blend mask' im2'' im1'; /* Undo any signed/unsigned nonsense. */ result = format_restore im1''; }; // Blurs the edges of an 8 bit mask, over a given number of pixels. _mask_blur_2 mask pixel = value { pixels = 1, pixel == 0 = pixel; black = im_black (mask.width + (2*pixels)) (mask.height + (2*pixels)) 1; new_mask = Image (im_insert black mask.value pixels pixels); blur_matrix = Matrix_con pixels 0 [(map (const 1) [1 .. pixels])]; im_blur = im_convsep new_mask.value blur_matrix; left = pixels; top = pixels; width = mask.width; height = mask.height; value = im_extract_area im_blur left top width height; }; _so_values im = result { mean_of_im = _mean_fn im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; _so_convert con_values im mask = result { im' = _section_select2 im mask; im_values = _so_values im'; mean_of_con = con_values?0; mean_of_im = im_values?0; max_of_con = con_values?1; max_of_im = im_values?1; scale = (max_of_con)/(max_of_im); im_convert = ((im - mean_of_im) * scale) + mean_of_con; result = clip2fmt im.format im_convert; }; /* Convert the histogram of part of image im_a, depending on the mask im_m, * to match the histogram of im_c. */ _hist_convert_2 control_im im adjust_mask = im_final { max_value = Image_format.maxval im.format; adjust_im = _section_select2 im adjust_mask; hist_c = hist_fn control_im; hist_a = hist_fn adjust_im; /* Find histogram and then edit out any information related to parts * of the image with value 0. Ensure that the histogram represents * the full scale for the appropriate format. Output corrected * histograms for the correct parts of the image. */ hist_fn im_in = output { hist_1 = hist_find im_in; black_1 = clip2fmt hist_1.format (im_black 1 1 1); hist_2 = im_insert hist_1.value black_1 0 0; black_2 = clip2fmt hist_1.format (im_black max_value 1 1); output = im_insert black_2 hist_2 0 0; } im_final = hist_map (hist_match hist_a hist_c) im; }; //------------------------------------------------------------------------------- /*Returns a section of im, defined by a mask, on a black background*/ _section_select2 im_in mask = output { output = clip2fmt im_in.format (im_black im_in.width im_in.height 1), mask == 0 = im_in; }; _mean_fn im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); } nip2-8.7.1/share/nip2/compat/7.8/Mosaic.def0000644000175000017500000002121713351443023014765 00000000000000 /* Check and group a point list by image. */ _mosaic_sort_test l = error "mosaic: not all points", !is_listof (is_instanceof "Point") l = error "mosaic: points not on two images", len images != 2 = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = land (map (equal (hd l)) (tl l)); get_format x = x.image.format; get_coding x = x.image.coding; // all the different images get_image x = x.image; images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = p.image === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to get * above before below. */ _mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = (a?0).left > (b?0).left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to get * left before right. */ _mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = (a?0).top > (b?0).top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ _mosaic_sort fn = concat @ transpose @ fn @ _mosaic_sort_test; /* translate and blend two images together left/right or up/down */ Mosaic_translate = class { _check_ab_args a b = [ [a, "a", check_Point], [b, "b", check_Point] ]; // shortcut to prefs _prefs = Workspaces.Preferences; _search_area = _prefs.MOSAIC_WINDOW_SIZE; _object_size = _prefs.MOSAIC_OBJECT_SIZE; _blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH; _refine = Toggle "Refine selected tie-points" _prefs.MOSAIC_REFINE; /* translate and blend two images left/right */ Left_right a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; blend_width = _blend_width; refine = _refine; value = im_lrmosaic a'.image.value b'.image.value 0 ra'.left ra'.top rb'.left rb'.top (_object_size / 2) (_search_area / 2) 0 blend_width.value, refine = im_lrmerge a'.image.value b'.image.value (rb'.left - ra'.left) (rb'.top - ra'.top) blend_width.value { sorted = _mosaic_sort _mosaic_sort_lr [a, b]; a' = sorted?0; b' = sorted?1; ra' = a'.image_rect; rb' = b'.image_rect; } } /* translate and blend two images top/bottom */ Top_bottom a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; blend_width = _blend_width; refine = _refine; value = im_tbmosaic a'.image.value b'.image.value 0 ra'.left ra'.top rb'.left rb'.top (_object_size / 2) (_search_area / 2) 0 blend_width.value, refine = im_tbmerge a'.image.value b'.image.value (rb'.left - ra'.left) (rb'.top - ra'.top) blend_width.value { sorted = _mosaic_sort _mosaic_sort_tb [a, b]; a' = sorted?0; b' = sorted?1; ra' = a'.image_rect; rb' = b'.image_rect; } } } /* forcibly translate and blend two images together left/right or up/down */ Mosaic_force = class { _check_ab_args a b = [ [a, "a", check_Point], [b, "b", check_Point] ]; // shortcut to prefs _prefs = Workspaces.Preferences; _blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH; /* forcibly translate and blend two images left/right */ Left_right a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; blend_width = _blend_width; value = im_lrmerge a'.image.value b'.image.value (rb'.left - ra'.left) (rb'.top - ra'.top) blend_width.value { sorted = _mosaic_sort _mosaic_sort_lr [a, b]; a' = sorted?0; b' = sorted?1; ra' = a'.image_rect; rb' = b'.image_rect; } } /* forcibly translate and blend two images top/bottom */ Top_bottom a b = class Image value { _check_args = _check_ab_args a b ++ super._check_args; blend_width = _blend_width; value = im_tbmerge a'.image.value b'.image.value (rb'.left - ra'.left) (rb'.top - ra'.top) blend_width.value { sorted = _mosaic_sort _mosaic_sort_tb [a, b]; a' = sorted?0; b' = sorted?1; ra' = a'.image_rect; rb' = b'.image_rect; } } } /* translate, rotate, scale and blend two images together left/right or up/down */ Mosaic_affine = class { _check_abcd_args a b c d = [ [a, "a", check_Point], [b, "b", check_Point], [c, "c", check_Point], [d, "d", check_Point] ]; // shortcut to prefs _prefs = Workspaces.Preferences; _search_area = _prefs.MOSAIC_WINDOW_SIZE; _object_size = _prefs.MOSAIC_OBJECT_SIZE; _blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH; _refine = Toggle "Refine selected tie-points" _prefs.MOSAIC_REFINE; /* translate, rotate, scale and blend two images left/right */ Left_right a b c d = class Image value { _check_args = _check_abcd_args a b c d ++ super._check_args; blend_width = _blend_width; refine = _refine; value = im_lrmosaic1 a'.image.value b'.image.value 0 ra'.left ra'.top rb'.left rb'.top rc'.left rc'.top rd'.left rd'.top (_object_size / 2) (_search_area / 2) 0 blend_width.value, refine = im_lrmerge1 a'.image.value b'.image.value ra'.left ra'.top rb'.left rb'.top rc'.left rc'.top rd'.left rd'.top blend_width.value { sorted = _mosaic_sort _mosaic_sort_lr [a, b, c, d]; a' = sorted?0; b' = sorted?1; c' = sorted?2; d' = sorted?3; ra' = a'.image_rect; rb' = b'.image_rect; rc' = c'.image_rect; rd' = d'.image_rect; } } /* translate, rotate, scale and blend two images top/bottom */ Top_bottom a b c d = class Image value { _check_args = _check_abcd_args a b c d ++ super._check_args; blend_width = _blend_width; refine = _refine; value = im_tbmosaic1 a'.image.value b'.image.value 0 ra'.left ra'.top rb'.left rb'.top rc'.left rc'.top rd'.left rd'.top (_object_size / 2) (_search_area / 2) 0 blend_width.value, refine = im_tbmerge1 a'.image.value b'.image.value ra'.left ra'.top rb'.left rb'.top rc'.left rc'.top rd'.left rd'.top blend_width.value { sorted = _mosaic_sort _mosaic_sort_tb [a, b, c, d]; a' = sorted?0; b' = sorted?1; c' = sorted?2; d' = sorted?3; ra' = a'.image_rect; rb' = b'.image_rect; rc' = c'.image_rect; rd' = d'.image_rect; } } } #separator /* disassemble mosaic, adjust brightnesses to match, and reassemble */ Mosaic_balance x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (errors.badargs ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } /* brighten along a left/right or up/down axis */ Tilt_brightness = class { /* brighten along a left/right axis */ Left_right x = map_unary tilt_lr x { tilt_lr image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; tilt = Slider (-1) 1 0; value = final { ramp = im_fgrey image.width image.height; ramp' = bandjoin (map (const ramp) [1..image.bands]); scale = (ramp' - 0.5) * tilt + 1; final = image.value * scale; } } } /* brighten along a top/bottom axis */ Top_bottom x = map_unary tilt_tb x { tilt_tb image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; tilt = Slider (-1) 1 0; value = final { ramp = rot90 (im_fgrey image.height image.width); ramp' = bandjoin (map (const ramp) [1..image.bands]); scale = (ramp' - 0.5) * tilt + 1; final = image.value * scale; } } } } #separator /* disassemble mosaic, substitute different image files, and reassemble */ Mosaic_rebuild x = map_unary remosaic x { remosaic image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; old_hint = "For the name of each file making up the mosaic, " ++ "exchange this string:"; old = "foo"; new_hint = "for this string:"; new = "bar"; value = im_remosaic image.value old new; } } nip2-8.7.1/share/nip2/compat/7.8/_stdenv.def0000644000175000017500000007141013351443023015214 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; join a b = a ++ b; subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; if_then_else a b c = if a then b else c; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error "unimplemented vector operation" { zeros = map (const 0) [1 .. len vec]; ones = map (const 1) [1 .. len vec]; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } /* Macbeth chart patch names. */ _macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (errors.badargs ++ "bandsplit") { bands = im_header_int "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = Image (concat (map get_value l)), is_listof (is_instanceof "Image") l = concat l, is_listof is_image l = error (errors.badargs ++ "bandjoin") { get_value x = x.value; } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = error (errors.badargs ++ "mean") { mean_op = Operator "mean" mean_object Operator_type.COMPOUND false; mean_object x = im_avg x, is_image x = mean_list x, is_real_list x || is_matrix x = error (errors.badargs ++ "mean"); mean_list l = s / n { totals = sum l; n = totals?0; s = totals?1; } // return [n, sum] for a list of numbers, or a list of list of num // etc. sum x = foldr accumulate [0, 0] x { accumulate x sofar = [n + 1, x + s], is_real x = [n + n', s + s'], is_list x = error "mean_list: not real or [real]" { n = sofar?0; s = sofar?1; sub_acc = sum x; n' = sub_acc?0; s' = sub_acc?1; } } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = error (errors.badargs ++ "deviation") { deviation_op = Operator "deviation" deviation_object Operator_type.COMPOUND false; deviation_object x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (errors.badargs ++ "deviation"); deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { totals = sum_sum2_list l; n = totals?0; s = totals?1; s2 = totals?2; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { n = sofar?0; s = sofar?1; s2 = sofar?2; sub_acc = sum_sum2_list x; n' = sub_acc?0; s' = sub_acc?1; s2' = sub_acc?2; } } } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = error (errors.badargs ++ "abs") { abs_op = Operator "abs" abs_object Operator_type.COMPOUND false; abs_object x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (errors.badargs ++ "abs"); abs_list l = (foldr1 add (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = error (errors.badargs ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec_object Operator_type.COMPOUND false; abs_vec_object x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (Vector (map abs_vec_list x)), is_matrix x = error (errors.badargs ++ "abs_vec"); abs_vec_list l = (foldr1 add (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (foldr1 add (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_matrix x, is_list x && is_list (hd x) = error (errors.badargs ++ "transpose") { transpose_op = Operator "transpose" transpose_object Operator_type.COMPOUND_REWRAP false; transpose_object x = transpose_matrix x, is_matrix x = transpose_image x, is_image x = error (errors.badargs ++ "transpose"); transpose_matrix l = [], l' == [] = (map hd l') : (transpose_matrix (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (errors.badargs ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (errors.badargs ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } rot90 x = oo_unary_function rot90_op x, is_class x = im_rot90 x, is_image x = error (errors.badargs ++ "rot90") { rot90_op = Operator "rot90" rot90_object Operator_type.COMPOUND_REWRAP false; rot90_object x = rot90_matrix x, is_matrix x = im_rot90 x, is_image x = error (errors.badargs ++ "rot90"); // slow, but what the heck rot90_matrix l = (im_rotate_dmask90 (Matrix l)).value; } rot180 x = oo_unary_function rot180_op x, is_class x = im_rot180 x, is_image x = error (errors.badargs ++ "rot180") { rot180_op = Operator "rot180" rot180_object Operator_type.COMPOUND_REWRAP false; rot180_object x = rot180_matrix x, is_matrix x = im_rot180 x, is_image x = error (errors.badargs ++ "rot180"); // slow, but what the heck rot180_matrix l = (im_rotate_dmask90 (im_rotate_dmask90 (Matrix l))).value; } rot270 x = oo_unary_function rot270_op x, is_class x = im_rot270 x, is_image x = error (errors.badargs ++ "rot270") { rot270_op = Operator "rot270" rot270_object Operator_type.COMPOUND_REWRAP false; rot270_object x = rot270_matrix x, is_matrix x = im_rot270 x, is_image x = error (errors.badargs ++ "rot270"); // slow, but what the heck rot270_matrix l = (im_rotate_dmask90 (im_rotate_dmask90 (im_rotate_dmask90 (Matrix l)))).value; } rotquad x = oo_unary_function rotquad_op x, is_class x = im_rotquad x, is_image x = error (errors.badargs ++ "rotquad") { rotquad_op = Operator "rotquad" rotquad_object Operator_type.COMPOUND_REWRAP false; rotquad_object x = rotquad_matrix x, is_matrix x = im_rotquad x, is_image x = error (errors.badargs ++ "rotquad"); rotquad_matrix l = error "rotquad matrix: not implemented"; } flipud x = oo_unary_function flipud_op x, is_class x = im_flipver x, is_image x = error (errors.badargs ++ "flipud") { flipud_op = Operator "flipud" flipud_object Operator_type.COMPOUND_REWRAP false; flipud_object x = flipud_matrix x, is_matrix x = im_flipver x, is_image x = error (errors.badargs ++ "flipud"); flipud_matrix l = reverse l; } fliplr x = oo_unary_function fliplr_op x, is_class x = im_fliphor x, is_image x = error (errors.badargs ++ "fliplr") { fliplr_op = Operator "fliplr" fliplr_object Operator_type.COMPOUND_REWRAP false; fliplr_object x = fliplr_matrix x, is_matrix x = im_fliphor x, is_image x = error (errors.badargs ++ "fliplr"); fliplr_matrix l = map reverse l; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = x, is_number x = error (errors.badargs ++ "max") { max_op = Operator "max" max_list Operator_type.COMPOUND false; max_list x = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_matrix x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = x, is_number x = error (errors.badargs ++ "min") { min_op = Operator "min" min_list Operator_type.COMPOUND false; min_list x = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_matrix x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = error (errors.badargs ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos_object Operator_type.COMPOUND false; maxpos_object x = maxpos_matrix x, is_matrix x = im_maxpos x, is_image x = error (errors.badargs ++ "maxpos"); maxpos_matrix m = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = error (errors.badargs ++ "minpos") { minpos_op = Operator "minpos" minpos_object Operator_type.COMPOUND false; minpos_object x = minpos_matrix x, is_matrix x = im_minpos x, is_image x = error (errors.badargs ++ "minpos"); minpos_matrix m = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = error (errors.badargs ++ "stats") { stats_op = Operator "stats" stats_object Operator_type.COMPOUND false; stats_object x = im_stats (to_image x).value, is_matrix x = im_stats x, is_image x = error (errors.badargs ++ "stats"); } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (errors.badargs ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = rint_value x, is_image x || is_number x = error (errors.badargs ++ "rint") { rint_op = Operator "rint" rint_value Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = scale_prim x { scale_op = Operator "scale" scale_prim Operator_type.COMPOUND_REWRAP false; scale_prim x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (errors.badargs ++ "scale"); scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (errors.badargs ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (errors.badargs ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (errors.badargs ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = im_falsecolour x, is_image x = error (errors.badargs ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (errors.badargs ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (errors.badargs ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } recomb matrix image = colour_unary recomb_op image { recomb_op x = im_recomb x matrix, is_image x = error (errors.badargs ++ "recomb"); } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = extract_area_prim obj { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" extract_area_prim Operator_type.COMPOUND_REWRAP false; extract_area_prim obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (errors.badargs ++ "extract_area"); extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_row_prim obj { y' = to_real y; extract_row_op = Operator "extract_row" extract_row_prim Operator_type.COMPOUND_REWRAP false; extract_row_prim obj = im_extract_area obj 0 y' width 1, is_image obj = [obj?y'], is_matrix obj = error (errors.badargs ++ "extract_row") { width = im_header_int "Xsize" obj; } } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_column_prim obj { x' = to_real x; extract_column_op = Operator "extract_column" extract_column_prim Operator_type.COMPOUND_REWRAP false; extract_column_prim obj = im_extract_area obj x' 0 1 height, is_image obj = map (converse cons [] @ converse subscript x') obj, is_matrix obj = error (errors.badargs ++ "extract_column") { height = im_header_int "Ysize" obj; } } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_lr_prim a b { join_lr_op = Operator "join_lr" join_lr_prim Operator_type.COMPOUND_REWRAP false; join_lr_prim a b = im_extract_area (im_insert a b a_width 0) 0 0 (a_width + b_width) out_height, is_image a && is_image b = map2 join a b, is_matrix a && is_matrix b = error (errors.badargs ++ "join_lr") { a_height = im_header_int "Ysize" a; b_height = im_header_int "Ysize" b; a_width = im_header_int "Xsize" a; b_width = im_header_int "Xsize" b; out_height = min_pair a_height b_height; } } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_tb_prim a b { join_tb_op = Operator "join_tb" join_tb_prim Operator_type.COMPOUND_REWRAP false; join_tb_prim a b = im_extract_area (im_insert a b 0 a_height) 0 0 out_width (a_height + b_height), is_image a && is_image b = map (take out_matrix_width) a ++ map (take out_matrix_width) b, is_matrix a && is_matrix b = error (errors.badargs ++ "join_tb") { a_height = im_header_int "Ysize" a; b_height = im_header_int "Ysize" b; a_width = im_header_int "Xsize" a; b_width = im_header_int "Xsize" b; out_width = min_pair a_width b_width; out_matrix_width = min_pair a_matrix_width b_matrix_width { a_matrix_width = len a?0; b_matrix_width = len b?0; } } } insert x y small big = oo_binary_function insert_op small big, is_class small = oo_binary'_function insert_op small big, is_class big = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (errors.badargs ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (errors.badargs ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } rotate angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_similarity image (cos angle) (sin angle) 0 0, is_real angle && is_image image = error (errors.badargs ++ "rotate") { rotate_op = Operator "rotate" rotate Operator_type.COMPOUND_REWRAP false; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = im_header_int "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function (clip2fmt_op format) image, is_class image = im_clip2fmt image format, is_image image = error (errors.badargs ++ "clip2fmt") { clip2fmt_op format = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { image = (unsigned char) im_mask2vips (Matrix m2); m2_width = im_header_int "Xsize" image; m2_height = im_header_int "Ysize" image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = im_embed image 0 (m1.width - 1) (m1.height - 1) (m2_width + 2 * (m1.width - 1)) (m2_height + 2 * (m1.height - 1)); // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image mask, is_image image = error (errors.badargs ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image mask, is_image image = error (errors.badargs ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image mask, is_image image = error (errors.badargs ++ "conv") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image w h n, is_image image = error (errors.badargs ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } hist_find image = oo_unary_function hist_find_op image, is_class image = im_histgr image (-1), is_image image = error (errors.badargs ++ "hist_find") { hist_find_op = Operator "hist_find" hist_find Operator_type.COMPOUND_REWRAP false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image bins, is_image image = error (errors.badargs ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" hist_find_nD Operator_type.COMPOUND_REWRAP false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (errors.badargs ++ "hist_map") { hist_map_op = Operator "hist_map" hist_map Operator_type.COMPOUND_REWRAP false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (errors.badargs ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (errors.badargs ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (errors.badargs ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = im_lhisteq image w h, is_image image = error (errors.badargs ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; } resize xfac yfac interp image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (errors.badargs ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac yfac, is_int xfac && is_int yfac && xfac >= 1 && yfac >= 1 && interp == Interpolate.nearest_neighbour // downscale by integer factor, nearest neighbour = im_subsample im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && interp == Interpolate.nearest_neighbour // upscale by any factor, nearest neighbour // can't really do this right ... upscale by integer part, then // bilinear to exact size = scale (break xfac)?1 (break yfac)?1 (im_zoom im (break xfac)?0 (break yfac)?0), xfac >= 1 && yfac >= 1 && interp == Interpolate.nearest_neighbour // downscale by any factor, nearest neighbour // can't really do this right ... downscale by integer part, // then bilinear to exact size = scale (1 / (break xfac')?1) (1 / (break yfac')?1) (im_subsample im (break xfac')?0 (break yfac')?0), xfac' >= 1 && yfac' >= 1 && interp == Interpolate.nearest_neighbour // upscale by any factor, bilinear = scale xfac yfac im, xfac >= 1 && yfac >= 1 && interp == Interpolate.bilinear // downscale by any factor, bilinear // block shrink by integer factor, then bilinear resample to // exact = scale (1 / (break xfac')?1) (1 / (break yfac')?1) (im_shrink im (break xfac')?0 (break yfac')?0), xfac' >= 1 && yfac' >= 1 && interp == Interpolate.bilinear = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac ++ "\n" ++ " yfac = " ++ print yfac ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate.names.lookup 1 0 interp ++ ")") { xfac' = 1 / xfac; yfac' = 1 / yfac; // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // binlinear resize scale xfac yfac im = im_affine im xfac 0 0 yfac 0 0 0 0 (width * xfac) (height * yfac) { width = im_header_int "Xsize" im; height = im_header_int "Ysize" im; } } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map3 (map_trinary fn) a b c, is_list a && is_list b && is_list c = map2 (map_trinary fn a) b c, is_list b && is_list c = map2 (map_trinary (converse31 fn) b) a c, is_list a && is_list c = map2 (map_trinary (converse32 fn) c) a b, is_list a && is_list b = map (map_trinary fn a b) c, is_list c = map (map_trinary (converse32 fn) a c) b, is_list b = map (map_trinary (converse34 fn) b c) a, is_list a = fn a b c { converse31 fn a b c = fn b a c; converse32 fn a b c = fn c a b; converse33 fn a b c = fn a c b; converse34 fn a b c = fn b c a; } /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map2 (map_binary fn) a b, is_list a && is_list b = map (map_binary fn a) b, is_list b = map (map_binary (converse fn) b) a, is_list a = fn a b; /* Map a 1-ary function over an object. */ map_unary fn a = map (map_unary fn) a, is_list a = fn a; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop block_size overlap i = map chop' [0, step .. height] { width = im_header_int "Xsize" i; height = im_header_int "Ysize" i; bands = im_header_int "Bands" i; format = im_header_int "BandFmt" i; type = im_header_int "Type" i; /* Unique pixels per tile. */ step = block_size - overlap; /* Calculate padding ... pad up to block_size pixel boundary. */ sx = block_size + (width - width % step); sy = block_size + (height - height % step); /* Expand image with black to pad size. */ background = image_new sx sy bands format Image_coding.NOCODING type 0 0 0; pad = im_insert background i 0 0; /* Chop up a row. */ chop' y = map chop'' [0, step .. width] { chop'' x = im_extract_area pad x y block_size block_size; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = vjoin (map hjoin il) { /* Join a list of tiles horizontally. */ hjoin l = foldl1 lrj l { lrj l r = im_lrmerge l r (hoverlap - im_header_int "Xsize" l) 0 10; } /* Join a list of tiles vertically. */ vjoin l = foldl1 tbj l { tbj t b = im_tbmerge t b 0 (voverlap - im_header_int "Ysize" t) 10; } } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } nip2-8.7.1/share/nip2/compat/7.8/Histogram.def0000644000175000017500000000302113351443023015500 00000000000000/* find histogram of x */ Hist_find x = map_unary hist_find x; /* find n-dimensional histogram from n-band image */ Hist_find_nD in = map_unary widget in { widget image = class Image value { _check_args = [ [image, "Image", check_Image] ] ++ super._check_args; _vislevel = 3; // default to something small-ish bins = 8; value = hist_find_nD bins image.value; } } /* map image x through histogram hist */ Hist_map hist x = map_binary hist_map hist x; /* find cumulative histogram of hist */ Hist_cumulative x = map_unary hist_cum x; /* find normalised histogram of hist */ Hist_normalise x = map_unary hist_norm x; /* find LUT which matches hist in to hist ref */ Hist_match in ref = map_binary hist_match in ref; #separator /* histogram equalisation */ Hist_equalise = class { /* histogram equalise x globally */ Global x = map_unary hist_equalize x; /* local histogram equalisation using region r as window */ Local r = map_unary (hist_equalize_local r.width r.height) r.image; } /* slice a line of pixels along a guide line and display as a histogram */ Guide_slice in = map_unary widget in { widget guide = class Image value { _check_args = [ [guide, "Guide", check_Guide] ] ++ super._check_args; value = image_set_type Image_type.HISTOGRAM slice { slice = guide.image.extract_area guide.image.rect.left guide.top guide.width 1, is_instanceof "HGuide" guide = guide.image.extract_area guide.left guide.image.rect.top 1 guide.height; } } } nip2-8.7.1/share/nip2/compat/7.8/_types.def0000644000175000017500000010045713351443023015061 00000000000000 /* Lots of little arg checks. Global for convenience. */ check_any = [(const true), "any"]; check_bool = [is_bool, "boolean"]; check_real = [is_real, "real"]; check_ureal = [is_ureal, "unsigned real"]; check_preal = [is_preal, "positive real"]; check_real_list = [is_real_list, "list of real"]; check_string = [is_string, "string"]; check_string_list = [is_string_list, "list of string"]; check_int = [is_int, "integer"]; check_uint = [is_uint, "unsigned integer"]; check_pint = [is_pint, "positive integer"]; check_matrix = [is_matrix, "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, "0, 1, 2 or 3"]; check_image = [is_image, "image"]; check_xy_list = [is_xy_list, "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_instanceof "Matrix_base", "Matrix"]; check_colour_space = [is_colour_space, "colour_space"]; check_rectangular = [is_rectangular, "rectangular [[*]]"]; check_Guide = [is_Guide, "HGuide or VGuide"]; check_Point = check_instance "Point"; check_Colour = check_instance "Colour"; /* Check a set of args. Grab _check_table. It's a list of two check * lists: the first checks each arg, and the second checks all args * together. * * - each line in argcheck is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in allcheck is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down a bit. */ check_args x = x, badargs == [] && badalls == [] = error message { argcheck = x._check_args; allcheck = x._check_all; // join two strings up with a separator string join_sep j a b = a ++ j ++ b; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = errors.badargs ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\nusage\n" ++ indent ++ usage ++ "\nwhere\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ "you passed " ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ "you passed\n" ++ concat (map fmt_arg argcheck) { fmt n = "condition failed: " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make usage note usage = x.name ++ " " ++ foldr (join_sep " ") [] (map (extract 1) argcheck); // make arg type notes arg_types = foldr (join_sep "\n") [] (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "and\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = foldr (join_sep "\n") [] all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error ("unknown binary operator: " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error ("unknown unary operator: " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = error ("No method found for binary operator.\n" ++ "left = " ++ print a ++ "\n" ++ "operator = " ++ op.op_name ++ "\n" ++ "right = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = error ("No method found for binary operator.\n" ++ "left = " ++ print a ++ "\n" ++ "operator = " ++ op.op_name ++ "\n" ++ "right = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error ("No method found for unary operator.\n" ++ "operator = " ++ op.op_name ++ "\n" ++ "argument = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; /* Default: no checks ... override in subclasses. */ _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; /* Provide a fallback for class == thing ... just use pointer * equality. */ oo_binary_table op x = [ [ pointer_equal this x, op.op_name == "equal" || op.op_name == "equal'" ], [ not_pointer_equal this x, op.op_name == "not_equal" || op.op_name == "not_equal'" ] ]; oo_unary_table op = []; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ] ++ super._check_args; // methods oo_binary_table op x = [ [ this.Real (op.fn this.value x.value), is_instanceof "Real" x && op.type == Operator_type.ARITHMETIC ], [ this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC ], [ op.fn this.value x.value, is_instanceof "Real" x && op.type == Operator_type.RELATIONAL ], [ op.fn this.value x, !is_class x ] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [ this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC ], [ op.fn this.value, true ] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ] ++ super._check_args; // methods oo_binary_table op x = [ [ if value then x?0 else x?1, op.op_name == "if_then_else" ], [ this.Bool (op.fn this.value x.value), is_instanceof "Bool" x ], [ this.Bool (op.fn this.value x), is_bool x ] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [ this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL ] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ] ++ super._check_args; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ] ++ super._check_args; Real value = Number caption value; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ] ++ super._check_args; } // the old name Filename = Pathname "Pick a file"; /* Vector type ... just a finite list of real ... handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ] ++ super._check_args; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [ this.Vector (op.fn this.value x.value), is_instanceof "Vector" x && (op.op_name == "join" || op.op_name == "join'") ], // extra check for lengths equal [ this.Vector (map_binary op.fn this.value x.value), is_instanceof "Vector" x && len value == len x.value && op.type == Operator_type.ARITHMETIC ], [ this.Vector (map_binary op.fn this.value x.value), is_instanceof "Real" x && op.type == Operator_type.ARITHMETIC ], [ this.Vector (map_binary op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC ], // need extra length check [ this.Vector (map bool_to_real (map_binary op.fn this.value x.value)), is_instanceof "Vector" x && len value == len x.value && op.type == Operator_type.RELATIONAL ], [ this.Vector (map bool_to_real (map_binary op.fn this.value x.value)), is_instanceof "Real" x && op.type == Operator_type.RELATIONAL ], [ this.Vector (map bool_to_real (map_binary op.fn this.value x)), is_real x && op.type == Operator_type.RELATIONAL ], [ this.Vector (op.fn this.value x.value), is_instanceof "Vector" x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP ], [ x.Image (vec op'.op_name x.value value), is_instanceof "Image" x ], [ vec op'.op_name x value, is_image x ], [ op.fn this.value x, is_real x ] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [ this.Vector (map_unary op.fn this.value), op.type == Operator_type.ARITHMETIC ], [ this.Vector (map bool_to_real (map_unary op.fn this.value)), op.type == Operator_type.RELATIONAL ], [ this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP ], [ op.fn this.value, true ] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ] ++ super._check_args; // calculate these from value width = len value?0; height = len value; // methods oo_binary_table op x = [ // mat multiply is special [ this.Matrix_base mul.value, is_instanceof "Matrix_base" x && op.op_name == "multiply" ], [ this.Matrix_base mul'.value, is_instanceof "Matrix_base" x && op.op_name == "multiply'" ], // mat divide is also special [ this.Matrix_base div.value, is_instanceof "Matrix_base" x && op.op_name == "divide" ], [ this.Matrix_base div'.value, is_instanceof "Matrix_base" x && op.op_name == "divide'" ], // power -1 means invert [ this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power" ], [ this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power" ], [ error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'" ], // matrix op vector ... treat a vector as a 1 row matrix [ this.Matrix_base (map (map_binary op'.fn x.value) this.value), is_instanceof "Vector" x && op.type == Operator_type.ARITHMETIC ], [ this.Matrix_base (map_binary op.fn this.value x.value), (is_instanceof "Matrix_base" x || is_instanceof "Real" x) && op.type == Operator_type.ARITHMETIC ], [ this.Matrix_base (map_binary op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC ], // compound ... don't do iteration [ this.Matrix_base (op.fn this.value x.value), (is_instanceof "Matrix_base" x || is_instanceof "Real" x || is_instanceof "Vector" x) && op.type == Operator_type.COMPOUND_REWRAP ] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [ this.Matrix_base (map_unary op.fn this.value), op.type == Operator_type.ARITHMETIC ], [ this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP ], [ op.fn this.value, true ] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ] ++ super._check_args; Matrix_base value = Matrix_vips value scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {}; /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = im_read_dmask (expand filename); /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ] ++ super._check_args; _check_all = [ [len value == 3, "len value == 3"] ] ++ super._check_all; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = im_header_int "Type" im; bands = im_header_int "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [ itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP ] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [ itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP ] ] ++ super.oo_unary_table op; Vector value = Colour colour_space value; } /* Base slider type. */ Scale caption from to value = class scope.Real value { _check_args = [ [from, "from", check_real], [to, "to", check_real] ] ++ super._check_args; _check_all = [ [from < to, "from < to"] ] ++ super._check_all; // methods oo_binary_table op x = [ [ this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_instanceof "Scale" x && op.type == Operator_type.ARITHMETIC ], [ this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC ] ] ++ super.oo_binary_table op x; Real value = Scale caption from to value; } Slider = Scale ""; /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ] ++ super._check_args; Bool value = Toggle caption value; } /* Base option type. */ Option caption labels value = class Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ] ++ super._check_args; } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ] ++ super._check_args; /* present col x: is there an x in column col */ present col x = member (map (extract col) value) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error ("item " ++ print x ++ " not in table") { n = index (equal x) (map (extract from) value); } } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ] ++ super._check_args; // derived right = left + width; bottom = top + height; // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // equal to another rect equal r = left == r.left && top == r.top && width == r.width && height == r.height; // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); // operator overloading // just define equal and not equal oo_binary_table op x = [ [ equal x, is_instanceof "Rect" x && (op.op_name == "equal" || op.op_name == "equal'") ], [ !equal x, is_instanceof "Rect" x && (op.op_name == "not_equal" || op.op_name == "not_equal'") ] ] ++ super.oo_binary_table op x; } /* Values for Compression field in image. */ Image_compression = class { NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NOCODING = 0; COLQUANT = 1; LABPACK = 2; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647 // INT ] ? fmt, fmt >= 0 && fmt <= INT = error errors.bandFmt; } /* Type field. */ Image_type = class { FOURIER = 24; YXY = 23; sRGB = 22; LABS = 21; LCH = 19; UCS = 18; RGB = 17; LABQ = 16; CMYK = 15; CMC = 14; LAB = 13; XYZ = 12; LUT = 11; HISTOGRAM = 10; POWER_SPECTRUM = 9; BLUE_ONLY = 8; GREEN_ONLY = 7; RED_ONLY = 6; YUV = 5; IR = 4; XRAY = 3; LUMINACE = 2; B_W = 1; MULTIBAND = 0; /* Table to get names <-> numbers. */ type_names = Table [ [ "FOURIER", FOURIER ], [ "YXY", YXY ], [ "sRGB", sRGB ], [ "LABS", LABS ], [ "LCH", LCH ], [ "UCS", UCS ], [ "RGB", RGB ], [ "LABQ", LABQ ], [ "CMYK", CMYK ], [ "CMC", CMC ], [ "LAB", LAB ], [ "XYZ", XYZ ], [ "LUT", LUT ], [ "HISTOGRAM", HISTOGRAM ], [ "POWER_SPECTRUM", POWER_SPECTRUM ], [ "BLUE_ONLY", BLUE_ONLY ], [ "GREEN_ONLY", GREEN_ONLY ], [ "RED_ONLY", RED_ONLY ], [ "YUV", YUV ], [ "IR", IR ], [ "XRAY", XRAY ], [ "LUMINACE", LUMINACE ], [ "B_W", B_W ], [ "MULTIBAND", MULTIBAND ] ]; /* Table relating nip's colour space names and VIPS's Type numbers. */ colour_spaces = Table [ [ "XYZ", Image_type.XYZ ], [ "Yxy", Image_type.YXY ], [ "Lab", Image_type.LAB ], [ "LCh", Image_type.LCH ], [ "UCS", Image_type.UCS ], [ "RGB", Image_type.RGB ], [ "sRGB", Image_type.sRGB ] ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ] ++ super._check_args; // fields from VIPS header width = im_header_int "Xsize" value; height = im_header_int "Ysize" value; bands = im_header_int "Bands" value; format = im_header_int "BandFmt" value; coding = im_header_int "Coding" value; type = im_header_int "Type" value; xres = im_header_double "Xres" value; yres = im_header_double "Yres" value; xoffset = im_header_int "Xoffset" value; yoffset = im_header_int "Yoffset" value; filename = im_header_string "filename" value; // convenience ... the area our pixels occupy as a rect rect = Rect (-xoffset) (-yoffset) width height; // extract an area, addressed in nip cordinates extract_area left top width height = im_extract_area value (left + xoffset) (top + yoffset) width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ [ this.Image (op.fn this.value x.value), is_instanceof "Image" x || is_instanceof "Real" x ], [ this.Image result_image, op.op_name == "if_then_else" ], [ this.Image (vec op.op_name value x.value), is_instanceof "Vector" x ], [ this.Image (op.fn this.value x), is_number x || is_image x ] ] ++ super.oo_binary_table op x { to_image x = x, is_image x = x.value, is_instanceof "Image" x = black + x { black = im_black width height target_bands; } // get a member from the first of a list of objects to have it get_property has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } // get things about our output from inputs in this order objects = [then_part, else_part, this]; then_part = x?0; else_part = x?1; // properties of our output image target_bands = get_property (has_member "bands") (get_member "bands") objects; target_format = get_property (has_member "format") (get_member "format") objects; target_type = get_property has_type get_type objects; then_image = to_image then_part; else_image = to_image else_part; then_image' = clip2fmt target_format then_image; else_image' = clip2fmt target_format else_image; result_image = image_set_type target_type (if value then then_image' else else_image'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [ this.Image result, is_image result ], [ result, true ] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file str = class Image value { _check_args = [ [str, "str", check_string] ] ++ super._check_args; file = Filename str; value = vips_image file.value; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ] ++ super._check_args; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = image.extract_area left top width height, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = Area image left top width height; } Arrow image left top width height = class Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ] ++ super._check_args; _check_all = [ [image.rect.includes_rect this, "image.rect.includes_rect this"] ] ++ super._check_all; // our rect, translated to image cods (ie. offset by origin) image_rect = Rect (left + image.xoffset) (top + image.yoffset) width height; // methods oo_binary_table op x = [ [ this.Arrow this.image left' top' width' height', is_instanceof "Arrow" x && op.type == Operator_type.ARITHMETIC ] ] ++ super.oo_binary_table op x { left' = op.fn this.left x.left; top' = op.fn this.top x.top; width' = op.fn this.width x.width; height' = op.fn this.height x.height; } oo_unary_search op = [ [ this.Arrow this.image left' top' width' height', op.type == Operator_type.ARITHMETIC ] ] ++ super.oo_unary_table op { left' = op.fn this.left; top' = op.fn this.top; width' = op.fn this.width; height' = op.fn this.height; } } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = VGuide image left; } Point image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = Point image left top; } // Mark is the name nip2 expects for Point Mark = Point; // convenience functions: make relative on an image ... subtract origin // offset, ie. make in pixel coordinates Region_relative image u v w h = Region image (image.width * u - image.xoffset) (image.height * v - image.yoffset) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u - image.xoffset) (image.height * v - image.yoffset) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u - image.xoffset) (image.height * v - image.yoffset) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v - image.yoffset); HGuide_relative image u = HGuide image (image.width * u - image.xoffset); Point_relative image u v = Point image (image.width * u - image.xoffset) (image.height * v - image.yoffset); Interpolate = class { nearest_neighbour = 0; bilinear = 1; bicubic = 2; /* Table to map interpol numbers to descriptive strings */ names = Table [ [ "Nearest neighbour", nearest_neighbour ], [ "Bilinear", bilinear ], [ "Bicubic", bicubic ] ]; } Separator = class {} // renamed in 7.9 estpar = im_estpar; resample = im_transform_search; nip2-8.7.1/share/nip2/compat/7.8/_errors.def0000644000175000017500000000273313351443023015227 00000000000000 /* Lots of error messages. */ errors = class { not1band = "not 1 band image"; not1band8bit = "not 1 band 8-bit image"; not1band3band = "not 1 band image, or 3 band 1 column image"; notodd = "not odd width|height"; notmask = "not mask"; notmaskim = "not image|mask, mask"; badcoding = "not NOCODING or LABPACK"; badlab = "unable to convert to LAB"; allreal = "not all real numbers"; allreg = "not all regions"; badargs = "bad arguments to "; badbands = "images have differing numbers of bands"; badcolour = "bad arg to colourspace function"; badmatrixmatch = "matrix arguments do not match"; badnum = "wrong number of real number arguments"; bandFmt = "bad BandFmt"; internal = "menu macro sanity failure!"; lengthdiff = "list arguments differ in length"; noimage = "no image argument"; noregion = "no region argument"; notim = "not image"; notimcmplx = "not image|complex"; notimnotreal = "non image arguments not all real numbers"; notimreg = "not image|region"; notregimreg = "not region, image|region"; notimregnum = "not image|region|number"; notimregstr = "not image|region|string"; notmatnum = "not real|matrix|mask"; notmatrix = "not matrix|mask"; notodd_square_matrix = "not odd-sided square matrix|mask"; notreal = "not real number"; notreglist = "not region|[region]"; notsquare_matrix = "not square matrix|mask"; regwrong = "regions not on two images"; sfacgt1 = "shrink factors should be >= 1"; unknownType = "unknown type"; usage = "usage: "; }; nip2-8.7.1/share/nip2/compat/7.8/New.def0000644000175000017500000003034613351443023014306 00000000000000 /* make a new blank image */ New_image = widget { type_names = Image_type.type_names; names = sort (map (extract 0) type_names.value); default_type_name = type_names.lookup 1 0 Image_type.MULTIBAND; default_type_pos = index (equal default_type_name) names; widget = class Image value { width = 64; height = 64; bands = 1; format_option = Option "Image format" [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ] 0; type_option = Option "Image type" names default_type_pos; value = image_new width height bands format Image_coding.NOCODING type 0 0 0 { format = format_option.value; type = type_names.lookup 0 1 names?type_option; } } } /* pick a colour ... any colour space */ New_colour = widget "Lab" [50,0,0] { widget default_colour value = class Colour colour_space value { _colourspaces = [ "XYZ", "Yxy", "Lab", "LCh", "UCS", "RGB", "sRGB" ]; colour_space_option = Option "Colour space" _colourspaces (index (equal default_colour) _colourspaces); colour_space = colour_space_option.labels? colour_space_option.value; Colour_edit colour_space value = widget colour_space value; } } /* make a slider */ New_slider = Slider 0 255 128; /* make a toggle widget */ New_toggle = Toggle "untitled" false; /* make an option widget */ New_option = Option "untitled" ["option0", "option1"] 0; /* make a string entry widget */ New_string = String "Enter a string" "sample text"; /* make a number entry widget */ New_number = Number "Enter a number" 42; /* make a file chooser */ New_filename = Filename "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; /* make a matrix */ New_matrix = class { /* make a plain matrix */ Plain = Matrix (identity_matrix 3); /* make a convolution matrix */ Convolution = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; /* make a recombination matrix */ Recombination = Matrix_rec (identity_matrix 3); /* make a morphology matrix */ Morphology = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } /* make a mark on an image */ New_mark = class { /* mark a region on an image */ Region image = scope.Region_relative image 0.25 0.25 0.5 0.5; /* mark a point on an image */ Point image = scope.Point_relative image 0.5 0.5; /* mark an arrow on an image */ Arrow image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; /* mark a horizontal guide on an image */ HGuide image = scope.HGuide_relative image 0.5; /* mark a vertical guide on an image */ VGuide image = scope.VGuide_relative image 0.5; } #separator /* make a spatial response pattern image */ New_eye = class Image value { width = 64; height = 64; factor = Slider 0.001 1 0.2; value = im_eye width height factor.value; } /* make a zone plate image */ New_zone_plate = class Image value { size = 64; value = im_zone size; } /* make a grey ramp image */ New_grey = class Image value { width = 64; height = 64; orientation = Option "" ["Horizontal", "Vertical"] 0; value = [im_grey width height, im_rot90 (im_grey height width)]?orientation; } /* make a two band image whose pixel values are their coordinates */ New_xy = class Image value { width = 64; height = 64; value = make_xy width height; } /* make a new image of gaussian noise */ New_gauss_noise = class Image value { size = 64; mean = Slider 0 255 128; deviation = Slider 0 128 50; value = im_gaussnoise size size mean.value deviation.value; } /* make a 2d fractal image */ New_fractal = class Image value { size = 64; dimension = Slider 2.001 2.999 2.001; value = im_fractsurf size dimension.value; } /* make a CRT calibration chart */ New_CRT_test_chart = class Image value { brightness = Slider 0 255 200; patch_size = 32; value = imagearray_assemble 0 0 [[green, red], [blue, white]] { black = image_new patch_size patch_size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } /* make a frequency test chart */ New_frequency_test_chart = class Image value { width = 64; strip_height = 10; wavelengths = [64, 32, 16, 8, 4, 2]; value = join.value { freq_slice wave = Image (sin ((im_fgrey width strip_height) * 360 * width / wave) > 0); strips = map freq_slice wavelengths; join = foldl1 Join.Top_bottom strips; } } /* make a checkerboard pattern */ New_checkerboard = class Image value { width = 64; height = 64; horizontal_patch_size = 8; vertical_patch_size = 8; horizontal_patch_offset = 0; vertical_patch_offset = 0; value = xstripes ^ ystripes { pixels = make_xy width height; xpixels = pixels?0 + horizontal_patch_offset; ypixels = pixels?1 + vertical_patch_offset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels horizontal_patch_size; ystripes = make_stripe ypixels vertical_patch_size; } } /* make a grid pattern */ New_grid = class Image value { width = 64; height = 64; horizontal_line_spacing = 8; vertical_line_spacing = 8; line_thickness = 1; horizontal_grid_offset = 0; vertical_grid_offset = 0; value = xstripes | ystripes { pixels = make_xy width height; xpixels = pixels?0 + horizontal_grid_offset; ypixels = pixels?1 + vertical_grid_offset; make_stripe pix swidth = pix % swidth < line_thickness; xstripes = make_stripe xpixels horizontal_line_spacing; ystripes = make_stripe ypixels vertical_line_spacing; } } #separator /* make a gaussian matrix */ New_gauss_matrix = class Matrix_vips _mask.value _mask.scale _mask.offset _mask.filename _mask.display { sigma = Slider 0.001 10 1; min_amplitude = Slider 0 1 0.2; integer = Toggle "Integer" false; _mask = fn sigma.value min_amplitude.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } /* make a laplacian of a gaussian mask */ New_log_matrix = class Matrix_vips _mask.value _mask.scale _mask.offset _mask.filename _mask.display { sigma = Slider 0.001 10 1.5; min_amplitude = Slider 0 1 0.1; integer = Toggle "Integer" false; _mask = fn sigma.value min_amplitude.value { fn = im_log_imask, integer = im_log_dmask; } } #separator /* make the mask images for various ideal fourier filters */ New_ideal = class { /* make a mask image for an ideal highpass/lowpass fourier filter */ High_low = class Image value { size = 64; frequency_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff.value 0 0 0 0; } } /* make a mask image for an ideal ring pass/reject fourier filter */ Ring = class Image value { size = 64; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 6; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff.value ring_width.value 0 0 0; } } /* make a mask image for an ideal band pass/reject fourier filter */ Band = class Image value { size = 64; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 12; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value 0 0; } } } /* various Gaussian fourier filters */ New_gaussian = class { /* make a mask image for a gaussian highpass/lowpass fourier filter */ High_low = class Image value { size = 64; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value + 4; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff.value amplitude_cutoff.value 0 0 0; } } /* make a mask image for a gaussian ring pass/reject fourier filter */ Ring = class Image value { size = 64; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 10; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff.value ring_width.value amplitude_cutoff.value 0 0; } } /* make a mask image for a gaussian band pass/reject fourier filter */ Band = class Image value { size = 64; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 16; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value 0; } } } /* various Butterworth fourier filters */ New_butterworth = class { /* make a mask image for a Butterworth highpass/lowpass fourier filter */ High_low = class Image value { size = 64; order = Slider 1 10 2; frequency_cutoff = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "High or low" ["High pass", "Low pass"] 0; _type = type.value + 2; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type order.value frequency_cutoff.value amplitude_cutoff.value 0 0; } } /* make a mask image for a Butterworth ring pass/reject fourier filter */ Ring = class Image value { size = 64; order = Slider 1 10 2; frequency_cutoff = Slider 0.01 0.99 0.5; ring_width = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Ring pass", "Ring reject"] 0; _type = type.value + 8; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type order.value frequency_cutoff.value ring_width.value amplitude_cutoff.value 0; } } /* make a mask image for a Butterworth band pass/reject fourier filter */ Band = class Image value { size = 64; order = Slider 1 10 2; frequency_cutoff_x = Slider 0.01 0.99 0.5; frequency_cutoff_y = Slider 0.01 0.99 0.5; radius = Slider 0.01 0.99 0.5; amplitude_cutoff = Slider 0.01 0.99 0.5; type = Option "Pass or reject" ["Band pass", "Band reject"] 0; _type = type.value + 14; value = image_set_type Image_type.FOURIER (rotquad mask) { mask = im_create_fmask size size _type order.value frequency_cutoff_x.value frequency_cutoff_y.value radius.value amplitude_cutoff.value; } } } #separator /* make a slice through CIELAB space */ New_CIELAB_slice = class Image value { size = 64; L = Slider 0 100 50; value = lab_slice size L.value; } /* pick a colour in LAB space */ New_LAB_colour = widget "Lab" [50, 0, 0] { // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range); ab2xy a = (a * (size / range)); widget space default_value = class Colour space value { L = default_value?0; a = default_value?1; b = default_value?2; lightness = Slider 0 100 L; ab_slice = Image (lab_slice size lightness.value); point = Point ab_slice (ab2xy a) (ab2xy b); value = [lightness.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } nip2-8.7.1/share/nip2/compat/7.8/Makefile.am0000644000175000017500000000062213351443023015123 00000000000000startdir = $(pkgdatadir)/compat/7.8 start_DATA = \ Math.def \ Image.def \ Mosaic.def \ Colour.def \ Resize.def \ Capture.def \ Format.def \ Filter.def \ Morphology.def \ New.def \ Histogram.def \ Print.def \ Rotate.def \ Statistics.def \ X_ray.def \ _convert.def \ _errors.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.8/Rotate.def0000644000175000017500000000460713351443023015014 00000000000000/* rotate images and matricies by fixed angles */ Rotate_fixed = class { /* rotate image clockwise in 90 degree increments */ _rotate_widget default a = map_unary widget a { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; value = [ image.value, rot90 image.value, rot180 image.value, rot270 image.value ] ? angle; } } /* clockwise rotate by 90 degrees */ R90 x = _rotate_widget 1 x; /* rotate by 180 degrees */ R180 x = _rotate_widget 2 x; /* clockwise rotate by 270 degrees */ R270 x = _rotate_widget 3 x; /* rotate by 45 degrees ... square, odd-length-sides, matrices only */ R45 x = map_unary rot45 x; } /* rotate image anticlockwise by any angle */ Rotate_free a = map_unary widget a { widget image = class Image value { _check_args = [ [image, "image", check_Image] ] ++ super._check_args; _vislevel = 3; angle = Slider 0 360 0; value = rotate angle image.value; } } #separator /* mirror left/right or up/down */ Flip = class { /* mirror object up/down */ Up_down x = map_unary flipud x; /* mirror object left/right */ Left_right x = map_unary fliplr x; } /* swap rows and columns */ Transpose x = map_unary transpose x; #separator /* smallest rotate that gets arrow vertical or horizontal */ Straighten_arrow x = map_unary straighten x { straighten arrow = rotate angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } nip2-8.7.1/share/nip2/compat/7.8/Makefile.in0000644000175000017500000003714513417043242015150 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.8 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.8 start_DATA = \ Math.def \ Image.def \ Mosaic.def \ Colour.def \ Resize.def \ Capture.def \ Format.def \ Filter.def \ Morphology.def \ New.def \ Histogram.def \ Print.def \ Rotate.def \ Statistics.def \ X_ray.def \ _convert.def \ _errors.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.8/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.8/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.8/_predicate.def0000644000175000017500000000551013351443023015647 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true of character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && land (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, land (map is_obj l) = true, land (map is_list l) && land (map (not @ is_obj) l) && land (map is_rectangular l) && len l > 0 && land (map (equal (hd lengths)) (tl lengths)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; lengths = map len l; } /* is_matrix l: is l a list of lists of real numbers, all the same length */ is_matrix l = is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [] = is_matrix l && len l == len (hd l); /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [] = is_matrix l && (len l) % 2 == 1 && (len (l?0)) % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && (len l) % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_Guide x = is_instanceof "HGuide" x || is_instanceof "VGuide" x; is_Point x = is_instanceof "Point" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && land (map xy l) { xy l = is_real_list l && len l == 2; } nip2-8.7.1/share/nip2/compat/7.8/_list.def0000644000175000017500000001743713351443023014675 00000000000000/* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn (tl l), fn (hd l) = l; /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l up from the left using function fn and start value st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold up list l, right to left, with function fn and start * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); /* Search a list for an element, returning it's index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* land l: and all the elements of list l together * * land (map (==0) list) == true, if every element of list is zero. * land :: [bool] -> bool */ land = foldr logical_and true; /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a = l?0; b = l?1; x = tl (tl l); } /* lor l: or all the elements of list l together * * lor (map (equal 0) list) == true, if any element of list is zero. * lor :: [bool] -> bool */ lor = foldr logical_or false; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map fn' (zip2 l1 l2) { fn' p = fn p?0 p?1; } /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map fn' (zip3 l1 l2 l3) { fn' p = fn p?0 p?1 p?2; } /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = lor (map (equal x) l); /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a = hd l; x = tl l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st (hd l)) (tl l); } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a = hd l1; x = tl l1; b = hd l2; y = tl l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by fn * * split is_space "hello world" == ["hello", "world"] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/compat/7.26/0000755000175000017500000000000013417043452013234 500000000000000nip2-8.7.1/share/nip2/compat/7.26/Image.def0000644000175000017500000013626213351443023014663 00000000000000Image_new_item = class Menupullright "_New" "make new things" { Image_black_item = class Menuaction "_Image" "make a new image" { format_names = [ "8-bit unsigned int - UCHAR", // 0 "8-bit signed int - CHAR", // 1 "16-bit unsigned int - USHORT", // 2 "16-bit signed int - SHORT", // 3 "32-bit unsigned int - UINT", // 4 "32-bit signed int - INT", // 5 "32-bit float - FLOAT", // 6 "64-bit complex - COMPLEX", // 7 "64-bit float - DOUBLE", // 8 "128-bit complex - DPCOMPLEX" // 9 ]; action = class Image _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; nbands = Expression "Image bands" 1; format_option = Option "Image format" format_names 0; type_option = Option_enum "Image type" Image_type.type_names "B_W"; pixel = Expression "Pixel value" 0; _result = image_new (to_real nwidth) (to_real nheight) (to_real nbands) (to_real format_option) Image_coding.NOCODING type_option.value_thing pixel.expr 0 0; } } Image_new_from_image_item = class Menuaction "_From Image" "make a new image based on image x" { action x = class Image _result { _vislevel = 3; pixel = Expression "Pixel value" 0; _result = image_new x.width x.height x.bands x.format x.coding x.type pixel.expr x.xoffset x.yoffset; } } Image_region_item = class Menupullright "_Region on Image" "make a new region on an image" { Region_item = class Menuaction "_Region" "make a region on an image" { action image = scope.Region_relative image 0.25 0.25 0.5 0.5; } Mark_item = class Menuaction "_Point" "make a point on an image" { action image = scope.Mark_relative image 0.5 0.5; } Arrow_item = class Menuaction "_Arrow" "make an arrow on an image" { action image = scope.Arrow_relative image 0.25 0.25 0.5 0.5; } HGuide_item = class Menuaction "_Horizontal Guide" "make a horizontal guide on an image" { action image = scope.HGuide image 0.5; } VGuide_item = class Menuaction "_Vertical Guide" "make a vertical guide on an image" { action image = scope.VGuide image 0.5; } sep1 = Menuseparator; Move_item = class Menuaction "From Region" "new region on image using existing region as a guide" { action a b = map_binary process a b { process a b = x.Region target x.left x.top x.width x.height, is_Region x = x.Arrow target x.left x.top x.width x.height, is_Arrow x = error "bad arguments to region-from-region" { // prefer image then region compare a b = false, !is_Image a && is_Image b = false, is_Region a && !is_Region b = true; [target, x] = sortc compare [a, b]; } } } } } Image_convert_to_image_item = class Menuaction "Con_vert to Image" "convert anything to an image" { action x = to_image x; } Image_number_format_item = class Menupullright "_Format" "convert numeric format" { U8_item = class Menuaction "_8 bit unsigned" "convert to unsigned 8 bit [0, 255]" { action x = map_unary cast_unsigned_char x; } U16_item = class Menuaction "1_6 bit unsigned" "convert to unsigned 16 bit [0, 65535]" { action x = map_unary cast_unsigned_short x; } U32_item = class Menuaction "_32 bit unsigned" "convert to unsigned 32 bit [0, 4294967295]" { action x = map_unary cast_unsigned_int x; } sep1 = Menuseparator; S8_item = class Menuaction "8 _bit signed" "convert to signed 8 bit [-128, 127]" { action x = map_unary cast_signed_char x; } S16_item = class Menuaction "16 b_it signed" "convert to signed 16 bit [-32768, 32767]" { action x = map_unary cast_signed_short x; } S32_item = class Menuaction "32 bi_t signed" "convert to signed 32 bit [-2147483648, 2147483647]" { action x = map_unary cast_signed_int x; } sep2 = Menuseparator; Float_item = class Menuaction "_Single precision float" "convert to IEEE 32 bit float" { action x = map_unary cast_float x; } Double_item = class Menuaction "_Double precision float" "convert to IEEE 64 bit float" { action x = map_unary cast_double x; } sep3 = Menuseparator; Scmplxitem = class Menuaction "Single _precision complex" "convert to 2 x IEEE 32 bit float" { action x = map_unary cast_complex x; } Dcmplx_item = class Menuaction "Double p_recision complex" "convert to 2 x IEEE 64 bit float" { action x = map_unary cast_double_complex x; } } Image_header_item = class Menupullright "_Header" "do stuff to the image header" { Image_get_item = class Menupullright "_Get" "get header fields" { // the header fields we can get fields = class { type = 0; width = 1; height = 2; format = 3; bands = 4; xres = 5; yres = 6; xoffset = 7; yoffset = 8; coding = 9; field_names = Enum [ $width => width, $height => height, $bands => bands, $format => format, $type => type, $xres => xres, $yres => yres, $xoffset => xoffset, $yoffset => yoffset, $coding => coding ]; field_option name = Option_enum (_ "Field") field_names name; field_funcs = Table [ [type, get_type], [width, get_width], [height, get_height], [format, get_format], [bands, get_bands], [xres, get_xres], [yres, get_yres], [xoffset, get_xoffset], [yoffset, get_yoffset], [coding, get_coding] ]; } get_field field_name x = class _result { _vislevel = 3; field = fields.field_option field_name; _result = map_unary (Real @ fields.field_funcs.lookup 0 1 field.value_thing) x; } Width_item = class Menuaction "_Width" "get width" { action x = get_field "width" x; } Height_item = class Menuaction "_Height" "get height" { action x = get_field "height" x; } Bands_item = class Menuaction "_Bands" "get bands" { action x = get_field "bands" x; } Format_item = class Menuaction "_Format" "get format" { action x = get_field "format" x; } Type_item = class Menuaction "_Type" "get type" { action x = get_field "type" x; } Xres_item = class Menuaction "_Xres" "get X resolution" { action x = get_field "xres" x; } Yres_item = class Menuaction "_Yres" "get Y resolution" { action x = get_field "yres" x; } Xoffset_item = class Menuaction "X_offset" "get X offset" { action x = get_field "xoffset" x; } Yoffset_item = class Menuaction "Yo_ffset" "get Y offset" { action x = get_field "yoffset" x; } Coding_item = class Menuaction "_Coding" "get coding" { action x = get_field "coding" x; } sep1 = Menuseparator; Custom_item = class Menuaction "C_ustom" "get any header field" { action x = class _result { _vislevel = 3; field = String "Field" "Xsize"; parse = Option "Parse" [ "No parsing", "Parse string as integer", "Parse string as real", "Parse string as hh:mm:ss" ] 0; _result = map_unary (wrap @ process @ get_header field.value) x { parse_str parse str = parse (split is_space str)?0; parse_field name cast parse x = cast x, is_number x = parse_str parse x, is_string x = error ("not " ++ name); get_int = parse_field "int" cast_signed_int parse_int; get_float = parse_field "float" cast_float parse_float; get_time = parse_field "hh:mm:ss" cast_signed_int parse_time; wrap x = Real x, is_real x = Vector x, is_real_list x = Image x, is_image x = Bool x, is_bool x = Matrix x, is_matrix x = String "String" x, is_string x = List x, is_list x = x; process = [ id, get_int, get_float, get_time ]?parse; } } } } sep1 = Menuseparator; Image_set_meta_item = class Menuaction "_Set" "set image metadata" { action x = class _result { _vislevel = 3; fname = String "Field" "field-name"; val = Expression "Value" 42; _result = map_unary process x { process image = set_header fname.value val.expr image; } } } Image_edit_header_item = class Menuaction "_Edit" "change advisory header fields of image" { type_names = Image_type.type_names; all_names = sort (map (extract 0) type_names.value); get_prop has get def x = get x, has x = def; action x = class _result { _vislevel = 3; nxres = Expression "Xres" (get_prop has_xres get_xres 1 x); nyres = Expression "Yres" (get_prop has_yres get_yres 1 x); nxoff = Expression "Xoffset" (get_prop has_xoffset get_xoffset 0 x); nyoff = Expression "Yoffset" (get_prop has_yoffset get_yoffset 0 x); type_option = Option_enum "Image type" Image_type.type_names (Image_type.type_names.get_name type) { type = x.type, is_Image x = Image_type.MULTIBAND; } _result = map_unary process x { process image = Image (im_copy_set image.value type_option.value_thing (to_real nxres) (to_real nyres) (to_real nxoff) (to_real nyoff)); } } } } Image_cache_item = class Menuaction "C_ache" "cache calculated image pixels" { action x = class _result { _vislevel = 3; tile_width = Number "Tile width" 128; tile_height = Number "Tile height" 128; max_tiles = Number "Maximum number of tiles to cache" (-1); _result = map_unary process x { process image = cache (to_real tile_width) (to_real tile_height) (to_real max_tiles) image; } } } #separator Image_levels_item = class Menupullright "_Levels" "change image levels" { Scale_item = class Menuaction "_Scale to 0 - 255" "linear transform to fit 0 - 255 range" { action x = map_unary scale x; } Linear_item = class Menuaction "_Linear" "linear transform of image levels" { action x = class _result { _vislevel = 3; scale = Scale "Scale" 0.001 3 1; offset = Scale "Offset" (-128) 128 0; _result = map_unary adj x { adj x // only force back to input type if this is a thing // with a type ... so we work for Colour / Matrix etc. = clip2fmt x.format x', has_member "format" x = x' { x' = x * scale + offset; } } } } Gamma_item = class Menuaction "_Power" "power transform of image levels (gamma)" { action x = class _result { _vislevel = 3; gamma = Scale "Gamma" 0.001 4 1; image_maximum_hint = "You may need to change image_maximum if " ++ "this is not an 8 bit image"; im_mx = Expression "Image maximum" mx { mx = Image_format.maxval x.format, has_format x = 255; } _result = map_unary gam x { gam x = clip2fmt (get_format x) x', has_format x = x' { x' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma; } } } } Tone_item = class Menuaction "_Tone Curve" "adjust tone curve" { action x = class _result { _vislevel = 3; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; curve = tone_build x.format b w sp mp hp sa ma ha; _result = map_unary (hist_map curve) x; } } } Image_transform_item = class Menupullright "_Transform" "transform images" { Rotate_item = class Menupullright "Ro_tate" "rotate image" { Fixed_item = class Menupullright "_Fixed" "clockwise rotation by fixed angles" { rotate_widget default x = class _result { _vislevel = 3; angle = Option "Rotate by" [ "Don't rotate", "90 degrees clockwise", "180 degrees", "90 degrees anticlockwise" ] default; _result = map_unary process x { process in = [ in, rot90 in, rot180 in, rot270 in ] ? angle; } } Rot90_item = class Menuaction "_90 Degrees" "clockwise rotation by 90 degrees" { action x = rotate_widget 1 x; } Rot180_item = class Menuaction "_180 Degrees" "clockwise rotation by 180 degrees" { action x = rotate_widget 2 x; } Rot270_item = class Menuaction "_270 Degrees" "clockwise rotation by 270 degrees" { action x = rotate_widget 3 x; } } Free_item = class Menuaction "_Free" "clockwise rotation by any angle" { action x = class _result { _vislevel = 3; angle = Scale "Angle" (-180) 180 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = rotate interp angle image; } } } Straighten_item = class Menuaction "_Straighten" ("smallest rotation that makes an arrow either horizontal " ++ "or vertical") { action x = class _result { _vislevel = 3; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary straighten x { straighten arrow = rotate interp angle'' arrow.image { x = arrow.width; y = arrow.height; angle = im (polar (x, y)); angle' = angle - 360, angle > 315 = angle - 180, angle > 135 = angle; angle'' = -angle', angle' >= (-45) && angle' < 45 = 90 - angle'; } } } } } Flip_item = class Menupullright "_Flip" "mirror left/right or up/down" { Left_right_item = class Menuaction "_Left Right" "mirror object left/right" { action x = map_unary fliplr x; } Top_bottom_item = class Menuaction "_Top Bottom" "mirror object top/bottom" { action x = map_unary fliptb x; } } Resize_item = class Menupullright "_Resize" "change image size" { Scale_item = class Menuaction "_Scale" "scale image size by a factor" { action x = class _result { _vislevel = 3; xfactor = Expression "Horizontal scale factor" 1; yfactor = Expression "Vertical scale factor" 1; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp xfactor yfactor image; } } } Size_item = class Menuaction "_Size To" "resize to a fixed size" { action x = class _result { _vislevel = 3; which = Option "Resize axis" [ "Shortest", "Longest", "Horizontal", "Vertical" ] 0; size = Expression "Resize to (pixels)" 128; aspect = Toggle "Break aspect ratio" false; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { process image = resize interp h v image, aspect = resize interp fac fac image { xfac = to_real size / image.width; yfac = to_real size / image.height; max_factor = [xfac, 1], xfac > yfac = [1, yfac]; min_factor = [xfac, 1], xfac < yfac = [1, yfac]; [h, v] = [ max_factor, min_factor, [xfac, 1], [1, yfac]]?which; fac = h, v == 1 = v; } } } } Size_within_item = class Menuaction "Size _Within" "size to fit within a rectangle" { action x = class _result { _vislevel = 3; // the rects we size to fit within _rects = [ [2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], [1280, 1024], [1024, 768], [800, 600], [640, 480] ]; within = Option "Fit within (pixels)" ( [print w ++ " x " ++ print h :: [w, h] <- _rects] ++ ["Custom"] ) 4; custom_width = Expression "Custom width" 1000; custom_height = Expression "Custom height" 1000; size = Option "Page size" [ "Full page", "Half page", "Quarter page" ] 0; interp = Interpolate_picker Interpolate_type.BILINEAR; _result = map_unary process x { xdiv = [1, 2, 2]?size; ydiv = [1, 1, 2]?size; allrect = _rects ++ [ [custom_width.expr, custom_height.expr] ]; [width, height] = allrect?within; process x = resize interp fac fac x, fac < 1 = x { xfac = (width / xdiv) / x.width; yfac = (height / ydiv) / x.height; fac = min_pair xfac yfac; } } } } Resize_canvas_item = class Menuaction "_Canvas" "change size of surrounding image" { action x = class _result { _vislevel = 3; // try to guess a sensible size for the new image _guess_size = x.rect, is_Image x = Rect 0 0 100 100; nwidth = Expression "New width (pixels)" _guess_size.width; nheight = Expression "New height (pixels)" _guess_size.height; bgcolour = Expression "Background colour" 0; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary process x { process image = insert_noexpand xp yp image background { width = image.width; height = image.height; coding = image.coding; bands = 3, coding == Image_coding.LABPACK = image.bands; format = Image_format.FLOAT, coding == Image_coding.LABPACK = image.format; type = image.type; // placement vectors ... left, centre, right xposv = [0, to_real nwidth / 2 - width / 2, to_real nwidth - width]; yposv = [0, to_real nheight / 2 - height / 2, to_real nheight - height]; xp = left, position == 9 = xposv?((int) (position % 3)); yp = top, position == 9 = yposv?((int) (position / 3)); background = image_new nwidth nheight bands format coding type bgcolour.expr 0 0; } } } } } Image_perspective_item = Perspective_item; Image_rubber_item = class Menupullright "Ru_bber Sheet" "automatically warp images to superposition" { rubber_interp = Option "Interpolation" ["Nearest", "Bilinear"] 1; rubber_order = Option "Order" ["0", "1", "2", "3"] 1; rubber_wrap = Toggle "Wrap image edges" false; // a transform ... a matrix, plus the size of the image the // matrix was made for Transform matrix image_width image_height = class matrix { // scale a transform ... if it worked for a m by n image, make // it work for a (m * xfac) by (y * yfac) image rescale xfac yfac = Transform (Matrix (map2 (map2 multiply) matrix.value facs)) (image_width * xfac) (image_height * yfac) { facs = [ [xfac, yfac], [1, 1], [1, 1], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac], [1 / xfac, 1 / yfac] ]; } } // yuk!!!! fix is_instanceof to not need absolute names is_Transform = is_instanceof "Image_transform_item.Image_rubber_item.Transform"; Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _trn { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [sample', trn, err] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image sample'; _trn = Transform trn reference.width reference.height; final_error = err; } } Apply_item = class Menuaction "_Apply" "apply a transform to an image" { action a b = class _result { _vislevel = 3; // controls interp = rubber_interp; wrap = rubber_wrap; _result = map_binary trans a b { trans a b = transform interp wrap t' i { // get the transform arg first [i, t] = sortc (const is_Transform) [a, b]; t' = t.rescale (i.width / t.image_width) (i.height / t.image_height); } } } } } sep1 = Menuseparator; Match_item = class Menuaction "_Linear Match" "rotate and scale one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.5 0.25; bp1 = Mark_relative _b 0.5 0.25; ap2 = Mark_relative _a 0.5 0.75; bp2 = Mark_relative _b 0.5 0.75; refine = Toggle "Refine selected tie-points" false; lock = Toggle "No resize" false; _result = map_binary process x y { process a b = Image b''' { _prefs = Workspaces.Preferences; window = _prefs.MOSAIC_WINDOW_SIZE; object = _prefs.MOSAIC_OBJECT_SIZE; a' = a.value; b' = b.value; b'' = clip2fmt a.format b'; // return p2 ... if lock is set, return a p2 a standard // distance along the vector joining p1 and p2 norm p1 p2 = Rect left' top' 0 0, lock = p2 { v = (p2.left - p1.left, p2.top - p1.top); // 100000 to give precision since we pass points as // ints to match n = 100000 * sign v; left' = p1.left + re n; top' = p1.top + im n; } ap2'' = norm ap1 ap2; bp2'' = norm bp1 bp2; b''' = im_match_linear_search a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top object window, // we can't search if lock is on refine && !lock = im_match_linear a' b'' ap1.left ap1.top bp1.left bp1.top ap2''.left ap2''.top bp2''.left bp2''.top; } } } } Image_perspective_match_item = Perspective_match_item; } Image_band_item = class Menupullright "_Band" "manipulate image bands" { // like extract_bands, but return [] for zero band image // makes compose a bit simpler exb b n x = [], to_real n == 0 = extract_bands b n x; Extract_item = class Menuaction "_Extract" "extract bands from image" { action x = class _result { _vislevel = 3; first = Expression "Extract from band" 0; number = Expression "Extract this many bands" 1; _result = map_unary (exb first number) x; } } Insert_item = class Menuaction "_Insert" "insert bands into image" { action x y = class _result { _vislevel = 3; first = Expression "Insert at position" 0; _result = map_binary process x y { process im1 im2 = exb 0 f im1 ++ im2 ++ exb f (b - f) im1 { f = to_real first; b = im1.bands; } } } } Delete_item = class Menuaction "_Delete" "delete bands from image" { action x = class _result { _vislevel = 3; first = Expression "Delete from band" 0; number = Expression "Delete this many bands" 1; _result = map_unary process x { process im = exb 0 f im ++ exb (f + n) (b - (f + n)) im { f = to_real first; n = to_real number; b = im.bands; } } } } Bandwise_item = Image_join_item.Bandwise_item; sep1 = Menuseparator; To_dimension_item = class Menuaction "To D_imension" "convert bands to width or height" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = foldl1 [join_lr, join_tb]?orientation (bandsplit im); } } } To_bands_item = class Menuaction "To B_ands" "turn width or height to bands" { action x = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; _result = map_unary process x { process im = bandjoin (map extract_column [0 .. im.width - 1]), orientation == 0 = bandjoin (map extract_row [0 .. im.height - 1]) { extract_column n = extract_area n 0 1 im.height im; extract_row n = extract_area 0 n im.width 1 im; } } } } } Image_crop_item = class Menuaction "_Crop" "extract a rectangular area from an image" { action x = class _result { _vislevel = 3; // try to find the image geometry ... don't bother trying to look // inside groups though _geo = x.rect, is_Image x = Rect 0 0 100 100; l = Expression "Crop left" ((int) (_geo.left + _geo.width / 4)); t = Expression "Crop top" ((int) (_geo.top + _geo.height / 4)); w = Expression "Crop width" (max_pair 1 ((int) (_geo.width / 2))); h = Expression "Crop height" (max_pair 1 ((int) (_geo.height / 2))); _result = map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr] { extract im l t w h = extract_area left' top' width' height' im { width' = min_pair (to_real w) im.width; height' = min_pair (to_real h) im.height; left' = range 0 (to_real l) (im.width - width'); top' = range 0 (to_real t) (im.height - height'); } } } } Image_insert_item = class Menuaction "_Insert" "insert a small image into a large image" { action a b = insert_position, is_Group a || is_Group b = insert_area { insert_area = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _vislevel = 3; // sort to get smallest first _pred x y = x.width * x.height < y.width * y.height; [_a', _b'] = sortc _pred [a, b]; place = Area _b' left top width height { // be careful in case b is smaller than a left = max_pair 0 ((_b'.width - _a'.width) / 2); top = max_pair 0 ((_b'.height - _a'.height) / 2); width = min_pair _a'.width _b'.width; height = min_pair _a'.height _b'.height; } _result = insert_noexpand place.left place.top (clip2fmt _b'.format a'') _b' { a'' = extract_area 0 0 place.width place.height _a'; } } insert_position = class _result { _vislevel = 3; position = Option "Position" [ "North-west", "North", "North-east", "West", "Centre", "East", "South-west", "South", "South-east", "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_binary insert a b { insert a b = insert_noexpand left top (clip2fmt b.format a) b, position == 9 = insert_noexpand xp yp (clip2fmt b.format a) b { xr = b.width - a.width; yr = b.height - a.height; xp = [0, xr / 2, xr]?((int) (position % 3)); yp = [0, yr / 2, yr]?((int) (position / 3)); } } } } } Image_select_item = Select_item; Image_draw_item = class Menupullright "_Draw" "draw lines, circles, rectangles, floods" { Line_item = class Menuaction "_Line" "draw line on image" { action x = class _result { _vislevel = 3; x1 = Expression "Start x" 0; y1 = Expression "Start y" 0; x2 = Expression "End x" 100; y2 = Expression "End y" 100; ink = Expression "Ink" [0]; _result = map_unary line x { line im = draw_line x1.expr y1.expr x2.expr y2.expr ink.expr im; } } } Rect_item = class Menuaction "_Rectangle" "draw rectangle on image" { action x = class _result { _vislevel = 3; left = Expression "Left" 50; top = Expression "Top" 50; width = Expression "Width" 100; height = Expression "Height" 100; fill = Toggle "Fill" true; ink = Expression "Ink" [0]; _result = map_unary rect x { rect im = draw_rect left.expr top.expr width.expr height.expr fill.value ink.expr im; } } } Circle_item = class Menuaction "_Circle" "draw circle on image" { action x = class _result { _vislevel = 3; cx = Expression "Centre x" 100; cy = Expression "Centre y" 100; r = Expression "Radius" 50; fill = Toggle "Fill" true; ink = Expression "Ink" [0]; _result = map_unary circle x { circle im = draw_circle cx.expr cy.expr r.expr fill.value ink.expr im; } } } Flood_item = class Menuaction "_Flood" "flood bounded area of image" { action x = class _result { _vislevel = 3; startx = Expression "Start x" 100; starty = Expression "Start y" 100; edge = Option "Flood while" [ "Not equal to ink", "Equal to start point" ] 0; // pick a default ink that won't flood, if we can ink = Expression "Ink" default_ink { default_ink = [0], ! has_image x = pixel; pixel = map mean (bandsplit (extract_area left top 1 1 im)); left = startx.expr; top = starty.expr; im = get_image x; } _result = map_unary flood x { flood im = draw_flood left top ink.expr im, edge == 0 = draw_flood_blob left top ink.expr im { left = startx.expr; top = starty.expr; } } } } } Image_join_item = class Menupullright "_Join" "join two or more images together" { Bandwise_item = class Menuaction "_Bandwise" "join two images bandwise" { action a b = join a b; } sep1 = Menuseparator; join_lr shim bg align a b = im2 { w = a.width + b.width + shim; h = max_pair a.height b.height; back = image_new w h a.bands a.format a.coding a.type bg 0 0; ya = [0, max_pair 0 ((b.height - a.height)/2), max_pair 0 (b.height - a.height)]; yb = [0, max_pair 0 ((a.height - b.height)/2), max_pair 0 (a.height - b.height)]; im1 = insert_noexpand 0 ya?align a back; im2 = insert_noexpand (a.width + shim) yb?align b im1; } join_tb shim bg align a b = im2 { w = max_pair a.width b.width; h = a.height + b.height + shim; back = image_new w h a.bands a.format a.coding a.type bg 0 0; xa = [0, max_pair 0 ((b.width - a.width)/2), max_pair 0 (b.width - a.width)]; xb = [0, max_pair 0 ((a.width - b.width)/2), max_pair 0 (a.width - b.width)]; im1 = insert_noexpand xa?align 0 a back; im2 = insert_noexpand xb?align (a.height + shim) b im1; } halign_names = ["Top", "Centre", "Bottom"]; valign_names = ["Left", "Centre", "Right"]; Left_right_item = class Menuaction "_Left to Right" "join two images left-right" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" halign_names 1; _result = map_binary (join_lr shim.value bg_colour.expr align.value) a b; } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom" { action a b = class _result { _vislevel = 3; shim = Scale "Spacing" 0 100 0; bg_colour = Expression "Background colour" 0; align = Option "Alignment" valign_names 1; _result = map_binary (join_tb shim.value bg_colour.expr align.value) a b; } } sep2 = Menuseparator; Array_item = class Menuaction "_Array" "join a list of lists of images into a single image" { action x = class _result { _vislevel = 3; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; // we can't use map_unary since chop-into-tiles returns a group of // groups and we want to be able to reassemble that // TODO: chop-into-tiles should return an array class which // displays as group but does not have the looping behaviour? _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list x)); } } ArrayFL_item = class Menuaction "_Array from List" "join a list of images into a single image" { action x = class _result { _vislevel = 3; ncol = Number "Max. Number of Columns" 1; hshim = Scale "Horizontal spacing" (-100) (100) 0; vshim = Scale "Vertical spacing" (-100) (100) 0; bg_colour = Expression "Background colour" 0; halign = Option "Horizontal alignment" valign_names 1; valign = Option "Vertical alignment" halign_names 1; _l = split_lines ncol.value x.value, is_Group x = split_lines ncol.value x; _result = (image_set_origin 0 0 @ foldl1 (join_tb vshim.value bg_colour.expr halign.value) @ map (foldl1 (join_lr hshim.value bg_colour.expr valign.value))) (to_list (to_list _l)); } } } Image_tile_item = class Menupullright "Til_e" "tile an image across and down" { tile_widget default_type x = class _result { _vislevel = 3; across = Expression "Tiles across" 2; down = Expression "Tiles down" 2; repeat = Option "Tile type" ["Replicate", "Four-way mirror"] default_type; _result = map_unary process x { process image = tile across down image, repeat == 0 = tile across down image'' { image' = insert image.width 0 (fliplr image) image; image'' = insert 0 image.height (fliptb image') image'; } } } Replicate_item = class Menuaction "_Replicate" "replicate image across and down" { action x = tile_widget 0 x; } Fourway_item = class Menuaction "_Four-way Mirror" "four-way mirror across and down" { action x = tile_widget 1 x; } Chop_item = class Menuaction "_Chop Into Tiles" "slice an image into tiles" { action x = class _result { _vislevel = 3; tile_width = Expression "Tile width" 100; tile_height = Expression "Tile height" 100; hoverlap = Expression "Horizontal overlap" 0; voverlap = Expression "Vertical overlap" 0; _result = map_unary (Group @ map Group @ process) x { process x = imagearray_chop tile_width tile_height hoverlap voverlap x; } } } } #separator Pattern_images_item = class Menupullright "_Patterns" "make a variety of useful patterns" { Grey_item = class Menuaction "Grey _Ramp" "make a smooth grey ramp" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; orientation = Option "Orientation" [ "Horizontal", "Vertical" ] 0; foption = Option "Format" ["8 bit", "float"] 0; _result = Image im { gen = im_grey, foption == 0 = im_fgrey; w = to_real nwidth; h = to_real nheight; im = gen w h, orientation == 0 = rot90 (gen h w); } } } Xy_item = class Menuaction "_XY Image" "make a two band image whose pixel values are their coordinates" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; _result = Image (make_xy nwidth nheight); } } Gaussian_item = class Menuaction "Gaussian _Noise" "make an image of gaussian noise" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; mean = Scale "Mean" 0 255 128; deviation = Scale "Deviation" 0 128 50; _result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) mean.value deviation.value); } } Fractal_item = class Menuaction "_Fractal" "make a fractal image" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; dimension = Scale "Dimension" 2.001 2.999 2.001; _result = Image (im_fractsurf (to_real nsize) dimension.value); } } Checkerboard_item = class Menuaction "_Checkerboard" "make a checkerboard image" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hpsize = Expression "Horizontal patch size" 8; vpsize = Expression "Vertical patch size" 8; hpoffset = Expression "Horizontal patch offset" 0; vpoffset = Expression "Vertical patch offset" 0; _result = Image (xstripes ^ ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hpoffset; ypixels = pixels?1 + to_real vpoffset; make_stripe pix swidth = pix % (swidth * 2) >= swidth; xstripes = make_stripe xpixels (to_real hpsize); ystripes = make_stripe ypixels (to_real vpsize); } } } Grid_item = class Menuaction "Gri_d" "make a grid" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; hspace = Expression "Horizontal line spacing" 8; vspace = Expression "Vertical line spacing" 8; thick = Expression "Line thickness" 1; hoff = Expression "Horizontal grid offset" 4; voff = Expression "Vertical grid offset" 4; _result = Image (xstripes | ystripes) { pixels = make_xy nwidth nheight; xpixels = pixels?0 + to_real hoff; ypixels = pixels?1 + to_real voff; make_stripe pix swidth = pix % swidth < to_real thick; xstripes = make_stripe xpixels (to_real hspace); ystripes = make_stripe ypixels (to_real vspace); } } } Text_item = class Menuaction "_Text" "make a bitmap of some text" { action = class _result { _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; wrap = Expression "Wrap text at" 500; align = Option "Alignment" [ "Left", "Centre", "Right" ] 0; dpi = Expression "DPI" 300; _result = Image (im_text text.value font.value (to_real wrap) align.value (to_real dpi)); } } New_CIELAB_slice_item = class Menuaction "CIELAB _Slice" "make a slice through CIELAB space" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; L = Scale "L value" 0 100 50; _result = Image (lab_slice (to_real nsize) L.value); } } sense_option = Option "Sense" [ "Pass", "Reject" ] 0; build fn size = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask size size); New_ideal_item = class Menupullright "_Ideal Fourier Mask" "make various ideal Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f sense.value fc.value 0 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 6) fc.value rw.value 0 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "ideal Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; } } } } New_gaussian_item = class Menupullright "_Gaussian Fourier Mask" "make various Gaussian Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 4) fc.value ac.value 0 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 10) fc.value rw.value ac.value 0 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Gaussian Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; _result = build param (to_real nsize) { param f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; } } } } New_butterworth_item = class Menupullright "_Butterworth Fourier Mask" "make various Butterworth Fourier filter masks" { High_low_item = class Menuaction "_High or Low Pass" ("make a mask image for a highpass/lowpass " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 2) order.value fc.value ac.value 0 0; } } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" ("make a mask image for an ring pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 8) order.value fc.value rw.value ac.value 0; } } } Band_item = class Menuaction "_Band Pass or Band Reject" ("make a mask image for a band pass/reject " ++ "Butterworth Fourier filter") { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; order = Scale "Order" 1 10 2; _result = build param (to_real nsize) { param f = f (sense.value + 14) order.value fcx.value fcy.value r.value ac.value; } } } } } Test_images_item = class Menupullright "Test I_mages" "make a variety of test images" { Eye_item = class Menuaction "_Spatial Response" "image for testing the eye's spatial response" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; nheight = Expression "Image height (pixels)" 64; factor = Scale "Factor" 0.001 1 0.2; _result = Image (im_eye (to_real nwidth) (to_real nheight) factor.value); } } Zone_plate = class Menuaction "_Zone Plate" "make a zone plate" { action = class _result { _vislevel = 3; nsize = Expression "Image size (pixels)" 64; _result = Image (im_zone (to_real nsize)); } } Frequency_test_chart_item = class Menuaction "_Frequency Testchart" "make a black/white frequency test pattern" { action = class _result { _vislevel = 3; nwidth = Expression "Image width (pixels)" 64; sheight = Expression "Strip height (pixels)" 10; waves = Expression "Wavelengths" [64, 32, 16, 8, 4, 2]; _result = imagearray_assemble 0 0 (transpose [strips]) { freq_slice wave = Image (sin (grey / wave) > 0); strips = map freq_slice waves.expr; grey = im_fgrey (to_real nwidth) (to_real sheight) * 360 * (to_real nwidth); } } } CRT_test_chart_item = class Menuaction "CRT _Phosphor Chart" "make an image for measuring phosphor colours" { action = class _result { _vislevel = 3; brightness = Scale "Brightness" 0 255 200; psize = Expression "Patch size (pixels)" 32; _result = Image (imagearray_assemble 0 0 [[green, red], [blue, white]]) { black = image_new (to_real psize) (to_real psize) 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W 0 0 0; notblack = black + brightness; green = black ++ notblack ++ black; red = notblack ++ black ++ black; blue = black ++ black ++ notblack; white = notblack ++ notblack ++ notblack; } } } Greyscale_chart_item = class Menuaction "_Greyscale" "make a greyscale" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.B_W (clip2fmt Image_format.UCHAR wedge)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } } } } CMYK_test_chart_item = class Menuaction "_CMYK Wedges" "make a set of CMYK wedges" { action = class _result { _vislevel = 3; pwidth = Expression "Patch width" 8; pheight = Expression "Patch height" 8; npatches = Expression "Number of patches" 16; _result = Image (image_set_type Image_type.CMYK (clip2fmt Image_format.UCHAR strips)) { wedge = 255 / (to_real npatches - 1) * (int) (strip?0 / to_real pwidth) { strip = make_xy (to_real pwidth * to_real npatches) pheight; } black = wedge * 0; C = wedge ++ black ++ black ++ black; M = black ++ wedge ++ black ++ black; Y = black ++ black ++ wedge ++ black; K = black ++ black ++ black ++ wedge; strips = imagearray_assemble 0 0 [[C],[M],[Y],[K]]; } } } Colour_atlas_item = class Menuaction "_Colour Atlas" "make a grid of patches grouped around a colour" { action = class _result { _vislevel = 3; start = Colour_picker "Lab" [50,0,0]; nstep = Expression "Number of steps" 9; ssize = Expression "Step size" 10; psize = Expression "Patch size" 32; sepsize = Expression "Separator size" 4; _result = colour_transform_to (get_type start) blocks''' { size = (to_real nstep * 2 + 1) * to_real psize - to_real sepsize; xy = make_xy size size; xy_grid = (xy % to_real psize) < (to_real psize - to_real sepsize); grid = xy_grid?0 & xy_grid?1; blocks = (int) (to_real ssize * ((int) (xy / to_real psize))); lab_start = colour_transform_to Image_type.LAB start; blocks' = blocks - to_real nstep * to_real ssize + Vector (tl lab_start.value); blocks'' = hd lab_start.value ++ Image blocks'; blocks''' = image_set_type Image_type.LAB blocks'', Image grid = 0; } } } } nip2-8.7.1/share/nip2/compat/7.26/_convert.def0000644000175000017500000004210113351443023015444 00000000000000 /* Try to make a Matrix ... works for Vector/Image/Real, plus image/real */ to_matrix x = to_matrix x.expr, is_Expression x = x, is_Matrix x = oo_unary_function to_matrix_op x, is_class x = tom x { to_matrix_op = Operator "to_matrix" tom Operator_type.COMPOUND false; tom x = Matrix (itom x), is_image x = Matrix [[x]], is_real x = Matrix [x], is_real_list x = Matrix x, is_matrix x = error (_ "bad arguments to " ++ "to_matrix"); itom i = (im_vips2mask ((double) i)).value, is_image i = error (_ "not image"); } /* Try to make an Image ... works for Vector/Matrix/Real, plus image/real * Special case for Colour ... pull out the colour_space and set Type in the * image. */ to_image x = to_image x.expr, is_Expression x = x, is_Image x = Image (image_set_type (Image_type.colour_spaces.lookup 0 1 x.colour_space) (mtoi [x.value])), is_Colour x = oo_unary_function to_image_op x, is_class x = toi x { to_image_op = Operator "to_image" toi Operator_type.COMPOUND false; toi x = Image x, is_image x = Image (mtoi [[x]]), is_real x = Image (mtoi [x]), is_real_list x = Image (mtoi x), is_matrix x = error (_ "bad arguments to " ++ "to_image"); // [[real]] -> image mtoi m = im_mask2vips (Matrix m), width != 3 = joinup (im_mask2vips (Matrix m)) { width = len m?0; height = len m; joinup i = b1 ++ b2 ++ b3 { b1 = extract_area 0 0 1 height i; b2 = extract_area 1 0 1 height i; b3 = extract_area 2 0 1 height i; } } } // like to_image, but we do 1x1 pixel + x, then embed it up // always make an unwrapped image for speed ... this gets used by ifthenelse // and stuff like that // format can be NULL, meaning set format from x to_image_size width height bands format x = x, is_image x = x.value, is_Image x = im'' { // we want x to set the target format if we don't have one, so we // can't use image_new im = im_black 1 1 bands + x; im' = clip2fmt format im, format != NULL = im; im'' = embed 1 0 0 width height im'; } /* Try to make a Colour. */ to_colour x = to_colour x.expr, is_Expression x = x, is_Colour x = to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x = oo_unary_function to_colour_op x, is_class x = toc x { to_colour_op = Operator "to_colour" toc Operator_type.COMPOUND false; toc x = Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))), has_image x && has_type x = Colour "sRGB" [x, x, x], is_real x // since Colour can't do mono = Colour "sRGB" x, is_real_list x && is_list_len 3 x = map toc x, is_matrix x = error (_ "bad arguments to " ++ "to_colour"); colour_space type = table.get_name type, table.has_name type = error (_ "unable to make Colour from " ++ table.get_name type ++ _ " image") { table = Image_type.colour_spaces; } } /* Try to make a real. (not a Real!) */ to_real x = to_real x.expr, is_Expression x = oo_unary_function to_real_op x, is_class x = tor x { to_real_op = Operator "to_real" tor Operator_type.COMPOUND false; tor x = x, is_real x = abs x, is_complex x = 1, is_bool x && x = 0, is_bool x && !x = error (_ "bad arguments to " ++ "to_real"); } /* Try to make a list ... ungroup, basically. We remove the innermost layer of * Groups. */ to_list x = x.value, is_Group x && !contains_Group x.value = Group (map to_list x.value), is_Group x = x; /* Try to make a group. The innermost list objects become Group()'d. */ to_group x = Group x, is_list x && !contains_Group x = Group (map to_group x.value), is_Group x = x; /* Parse a positive integer. */ parse_pint l = foldl acc 0 l { acc sofar ch = sofar * 10 + parse_c ch; /* Turn a char digit to a number. */ parse_c ch = error (_ "not a digit"), !is_digit ch = (int) ch - (int) '0'; } /* Parse an integer, with an optional sign character. */ parse_int l = error (_ "badly formed number"), !is_list_len 2 parts = sign * n { parts = splitpl [member "+-", is_digit] l; n = parse_pint parts?1; sign = 1, parts?0 == [] || parts?0 == "+" = -1; } /* Parse a float. * [+-]?[0-9]*([.][0-9]*)?(e[0-9]+)? */ parse_float l = err, !is_list_len 4 parts = (ipart + fpart) * 10 ** exp { err = error (_ "badly formed number"); parts = splitpl [ member "+-0123456789", member ".0123456789", member "eE", member "+-0123456789" ] l; ipart = parse_int parts?0; fpart = 0, parts?1 == []; = err, parts?1?0 != '.' = parse_pint (tl parts?1) / 10 ** (len parts?1 - 1); exp = 0, parts?2 == [] && parts?3 == [] = err, parts?2 == [] = parse_int parts?3; } /* Parse a time in "hh:mm:ss" into seconds. We could do this in one line :) = (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map parse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l))) [0,2,4]; but it's totally unreadable. */ parse_time l = error (_ "badly formed time"), !is_list_len 5 parts = s + 60 * m + 60 * 60 * h { parts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l; h = parse_int parts?0; m = parse_int parts?2; s = parse_int parts?4; } /* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix */ D652D50_direct = Matrix [[ 1.13529, -0.0604663, -0.0606321 ], [ 0.0975399, 0.935024, -0.0256156 ], [ -0.0336428, 0.0414702, 0.994135 ]]; D502D65_direct = D652D50_direct ** -1; /* Convert normalised XYZ to bradford RGB. */ XYZ2RGBbrad = Matrix [[0.8951, 0.2664, -0.1614], [-0.7502, 1.7135, 0.0367], [0.0389, -0.0685, 1.0296]]; /* Convert bradford RGB to normalised XYZ. */ RGBbrad2XYZ = XYZ2RGBbrad ** -1; D93_whitepoint = Vector [89.7400, 100, 130.7700]; D75_whitepoint = Vector [94.9682, 100, 122.5710]; D65_whitepoint = Vector [95.0470, 100, 108.8827]; D55_whitepoint = Vector [95.6831, 100, 92.0871]; D50_whitepoint = Vector [96.4250, 100, 82.4680]; A_whitepoint = Vector [109.8503, 100, 35.5849]; // 2856K B_whitepoint = Vector [99.0720, 100, 85.2230]; // 4874K C_whitepoint = Vector [98.0700, 100, 118.2300]; // 6774K E_whitepoint = Vector [100, 100, 100]; // ill. free D3250_whitepoint = Vector [105.6590, 100, 45.8501]; Whitepoints = Enum [ $D93 => D93_whitepoint, $D75 => D75_whitepoint, $D65 => D65_whitepoint, $D55 => D55_whitepoint, $D50 => D50_whitepoint, $A => A_whitepoint, $B => B_whitepoint, $C => C_whitepoint, $E => E_whitepoint, $D3250 => D3250_whitepoint ]; /* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx. */ im_D502D65 xyz = xyz''' { xyz' = xyz / D50_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb / Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; // back to D65 xyz''' = xyz'' * D65_whitepoint; } /* Convert D65 XYZ to D50 using the bradford approx. */ im_D652D50 xyz = xyz''' { xyz' = xyz / D65_whitepoint; rgb = recomb XYZ2RGBbrad xyz'; // move white in bradford RGB rgb' = rgb * Vector [0.94, 1.02, 1.33]; xyz'' = recomb RGBbrad2XYZ rgb'; xyz''' = xyz'' * D50_whitepoint; } /* Convert D50 XYZ to Lab. */ im_D50XYZ2Lab xyz = im_XYZ2Lab_temp xyz D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; im_D50Lab2XYZ lab = im_Lab2XYZ_temp lab D50_whitepoint.value?0 D50_whitepoint.value?1 D50_whitepoint.value?2; /* ... and mono conversions */ im_sRGB2mono in = (image_set_type Image_type.B_W @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_mono2sRGB in = image_set_type Image_type.sRGB (in ++ in ++ in); im_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ; im_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ; // from the 16 bit RGB and GREY formats im_1628 x = im_clip (x >> 8); im_162f x = x / 256; im_8216 x = (im_clip2us x) << 8; im_f216 x = im_clip2us (x * 256); im_RGB162GREY16 in = (image_set_type Image_type.GREY16 @ clip2fmt (get_header "BandFmt" in) @ recomb (Matrix [[.3, .6, .1]])) in; im_GREY162RGB16 in = image_set_type Image_type.RGB16 (in ++ in ++ in); /* apply a func to an image ... make it 1 or 3 bands, and reapply other bands * on the way out. Except if it's LABPACK. */ colour_apply fn x = fn x, b == 1 || b == 3 || c == Image_coding.LABPACK = x'' { b = get_bands x; c = get_coding x; first = extract_bands 0 3 x, b > 3 = extract_bands 0 1 x; tail = extract_bands 3 (b - 3) x, b > 3 = extract_bands 1 (b - 1) x; x' = fn first; x'' = x' ++ clip2fmt (get_format x') tail; } /* Any 1-ary colour op, applied to Vector/Image/Matrix or image */ colour_unary fn x = oo_unary_function colour_op x, is_class x = colour_apply fn x, is_image x = colour_apply fn [x], is_real x = error (_ "bad arguments to " ++ "colour_unary") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back colour_op = Operator "colour_unary" colour_object Operator_type.COMPOUND_REWRAP false; colour_object x = colour_real_list x, is_real_list x = map colour_real_list x, is_matrix x = colour_apply fn x, is_image x = error (_ "bad arguments to " ++ "colour_unary"); colour_real_list l = (to_matrix (fn (float) (to_image (Vector l)).value)).value?0; } /* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ... * name is op name for error messages etc. */ colour_binary name fn x y = oo_binary_function colour_op x y, is_class x = oo_binary'_function colour_op x y, is_class y = fn x y, is_image x && is_image y = error (_ "bad arguments to " ++ name) { colour_op = Operator name colour_object Operator_type.COMPOUND_REWRAP true; colour_object x y = fn x y, is_image x && is_image y = colour_real_list fn x y, is_real_list x && is_real_list y = map (colour_real_list fn x) y, is_real_list x && is_matrix y = map (colour_real_list (converse fn) y) x, is_matrix x && is_real_list y = map2 (colour_real_list fn) x y, is_matrix x && is_matrix y = error (_ "bad arguments to " ++ name); colour_real_list fn l1 l2 = (to_matrix (fn i1 i2)).value?0 { i1 = (float) (to_image (Vector l1)).value; i2 = (float) (to_image (Vector l2)).value; } } _colour_conversion_table = [ /* Lines are [space-from, space-to, conversion function]. Could do * this as a big array, but table lookup feels safer. */ [B_W, B_W, image_set_type B_W], [B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip], [B_W, sRGB, im_mono2sRGB @ im_clip], [B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB], [B_W, GREY16, image_set_type GREY16 @ im_8216], [B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip], [XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f], [XYZ, XYZ, image_set_type XYZ], [XYZ, YXY, im_XYZ2Yxy @ im_clip2f], [XYZ, LAB, im_XYZ2Lab @ im_clip2f], [XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab], [XYZ, UCS, im_XYZ2UCS @ im_clip2f], [XYZ, RGB, im_XYZ2disp @ im_clip2f], [XYZ, sRGB, im_XYZ2sRGB @ im_clip2f], [XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f], [YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, XYZ, im_Yxy2XYZ @ im_clip2f], [YXY, YXY, image_set_type YXY], [YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f], [YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f], [YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f], [YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f], [LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f], [LAB, XYZ, im_Lab2XYZ @ im_clip2f], [LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f], [LAB, LAB, image_set_type LAB @ im_clip2f], [LAB, LCH, im_Lab2LCh @ im_clip2f], [LAB, UCS, im_Lab2UCS @ im_clip2f], [LAB, RGB, im_Lab2disp @ im_clip2f], [LAB, sRGB, im_Lab2sRGB @ im_clip2f], [LAB, LABQ, im_Lab2LabQ @ im_clip2f], [LAB, LABS, im_Lab2LabS @ im_clip2f], [LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f], [LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LAB, im_LCh2Lab @ im_clip2f], [LCH, LCH, image_set_type LCH], [LCH, UCS, im_LCh2UCS @ im_clip2f], [LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f], [LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f], [LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f], [UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f], [UCS, XYZ, im_UCS2XYZ @ im_clip2f], [UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f], [UCS, LAB, im_UCS2Lab @ im_clip2f], [UCS, LCH, im_UCS2LCh @ im_clip2f], [UCS, UCS, image_set_type UCS], [UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f], [UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f], [UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f], [RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, XYZ, im_disp2XYZ @ im_clip], [RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip], [RGB, LAB, im_disp2Lab @ im_clip], [RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip], [RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip], [RGB, RGB, image_set_type RGB], [RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip], [RGB, RGB16, image_set_type RGB16 @ im_8216], [RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip], [RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip], [sRGB, B_W, im_sRGB2mono], [sRGB, XYZ, im_sRGB2XYZ @ im_clip], [sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip], [sRGB, LAB, im_sRGB2Lab @ im_clip], [sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip], [sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip], [sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip], [sRGB, sRGB, image_set_type sRGB], [sRGB, RGB16, image_set_type RGB16 @ im_8216], [sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono], [sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip], [RGB16, B_W, im_1628 @ im_sRGB2mono], [RGB16, RGB, image_set_type RGB @ im_1628], [RGB16, sRGB, image_set_type sRGB @ im_1628], [RGB16, RGB16, image_set_type RGB16], [RGB16, GREY16, im_RGB162GREY16], [GREY16, B_W, image_set_type B_W @ im_1628], [GREY16, RGB, im_mono2sRGB @ im_1628], [GREY16, sRGB, im_mono2sRGB @ im_1628], [GREY16, RGB16, im_GREY162RGB16], [GREY16, GREY16, image_set_type GREY16], [LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab], [LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab], [LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab], [LABQ, LAB, im_LabQ2Lab], [LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab], [LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab], [LABQ, RGB, im_LabQ2disp], [LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab], [LABQ, LABQ, image_set_type LABQ], [LABQ, LABS, im_LabQ2LabS], [LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LAB, im_LabS2Lab], [LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s], [LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s], [LABS, LABQ, im_LabS2LabQ @ im_clip2s], [LABS, LABS, image_set_type LABS] ] { /* From Image_type ... repeat here for brevity. Use same ordering as * in Colour menu for consistency. */ B_W = 1; XYZ = 12; YXY = 23; LAB = 13; LCH = 19; UCS = 18; RGB = 17; sRGB = 22; RGB16 = 25; GREY16 = 26; LABQ = 16; LABS = 21; } /* Transform between two colour spaces. */ colour_transform from to in = colour_unary _colour_conversion_table?i?2 in, i >= 0 = error (_ "unable to convert " ++ Image_type.type_names.get_name from ++ _ " to " ++ Image_type.type_names.get_name to) { match x = x?0 == from && x?1 == to; i = index match _colour_conversion_table; } /* Transform to a colour space, assuming the type field in the input is * correct */ colour_transform_to to in = colour_transform (get_type in) to in; /* String for path separator on this platform. */ path_separator = expand "$SEP"; /* Form a relative pathname. * path_relative ["home", "john"] == "home/john" * path_relative [] == "" */ path_relative l = join_sep path_separator l; /* Form an absolute pathname. * path_absolute ["home", "john"] == "/home/john" * path_absolute [] == "/" * If the first component looks like 'A:', don't add an initial separator. */ path_absolute l = path_relative l, len l?0 > 1 && is_letter l?0?0 && l?0?1 == ':' = path_separator ++ path_relative l; /* Parse a pathname. * path_parse "/home/john" == ["home", "john"] * path_parse "home/john" == ["home", "john"] */ path_parse str = split (equal path_separator?0) str; nip2-8.7.1/share/nip2/compat/7.26/Filter.def0000644000175000017500000012722113351443023015061 00000000000000Filter_conv_item = class Menupullright "_Convolution" "various spatial convolution filters" { /* Some useful masks. */ filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]]; filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]]; filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]; filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]; filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]]; Blur_item = class Menuaction "_Blur" "3x3 blur of image" { action x = map_unary (conv filter_blur) x; } Sharpen_item = class Menuaction "_Sharpen" "3x3 sharpen of image" { action x = map_unary (conv filter_sharp) x; } Emboss_item = class Menuaction "_Emboss" "1 pixel displace emboss" { action x = map_unary (conv filter_emboss) x; } Laplacian_item = class Menuaction "_Laplacian" "3x3 laplacian edge detect" { action x = map_unary (conv filter_laplacian) x; } Sobel_item = class Menuaction "So_bel" "3x3 Sobel edge detect" { action x = map_unary sobel x { sobel im = abs (a - 128) + abs (b - 128) { a = conv filter_sobel im; b = conv (rot270 filter_sobel) im; } } } /* 3x3 line detect of image diagonals should be scaled down by root(2) I guess Kirk */ Linedet_item = class Menuaction "Li_ne Detect" "3x3 line detect" { action x = map_unary lindet x { lindet im = foldr1 max_pair images { masks = take 4 (iterate rot45 filter_lindet); images = map (converse conv im) masks; } } } Usharp_item = class Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" { action x = class _result { _vislevel = 3; size = Option "Radius" [ "3 pixels", "5 pixels", "7 pixels", "9 pixels", "11 pixels", "51 pixels" ] 0; st = Scale "Smoothness threshold" 0 5 1.5; bm = Scale "Brighten by at most" 1 50 10; dm = Scale "Darken by at most" 1 50 50; fs = Scale "Sharpen flat areas by" (-2) 5 1; js = Scale "Sharpen jaggy areas by" (-2) 5 2; _result = map_unary process x { process in = Image in''' { in' = colour_transform_to Image_type.LABS in.value; in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in'; in''' = colour_transform_to (get_type in) in''; } } } } sep1 = Menuseparator; Custom_blur_item = class Menuaction "Custom B_lur / Sharpen" "blur or sharpen with tuneable parameters" { action x = class _result { _vislevel = 3; type = Option "Type" ["Blur", "Sharpen"] 0; r = Scale "Radius" 1 100 1; fac = Scale "Amount" 0 1 1; layers = Scale "Layers" 1 100 10; shape = Option "Mask shape" [ "Square", "Gaussian" ] 0; prec = Option "Precision" ["Int", "Float", "Approximate"] 0; _result = map_unary process x { process in = clip2fmt blur.format proc { mask = matrix_blur r.value, shape.value == 0 = matrix_gaussian_blur r.value; blur = [convsep, convsepf, aconvsep layers]?prec mask in; proc = in + fac * (in - blur), type == 1 = blur * fac + in * (1 - fac); } } } } Custom_conv_item = class Menuaction "Custom C_onvolution" "convolution filter with tuneable parameters" { action x = class _result { _vislevel = 3; matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; separable = Toggle "Seperable convolution" false, matrix.width == 1 || matrix.height == 1 = false; type = Option "Convolution type" ["Int", "Float"] 0; rotate = Option "Rotate" [ "Don't rotate", "4 x 45 degrees", "8 x 45 degrees", "2 x 90 degrees" ] 0; _result = map_unary process x { process in = in.Image in' { conv_fn = im_lindetect, !separable && type == 0 && rotate == 1 = im_compass, !separable && type == 0 && rotate == 2 = im_gradient, !separable && type == 0 && rotate == 3 = im_conv, !separable && type == 0 = im_convsep, separable && type == 0 = im_conv_f, !separable && type == 1 = im_convsep_f, separable && type == 1 = error "boink!"; in' = conv_fn in.value matrix; } } } } } Filter_rank_item = class Menupullright "_Rank" "various rank filters" { Median_item = class Menuaction "_Median" "3x3 median rank filter" { action x = map_unary (rank 3 3 4) x; } Image_rank_item = class Menuaction "_Image Rank" "pixelwise rank a list or group of images" { action x = class _result { _vislevel = 3; select = Expression "Rank" ((int) (guess_size / 2)) { guess_size = len x, is_list x = len x.value, is_Group x = 0; } // can't really iterate over groups ... since we allow a group // argument _result = rank_image select x; } } Custom_rank_item = class Menuaction "Custom _Rank" "rank filter with tuneable parameters" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 3; window_height = Expression "Window height" 3; select = Expression "Rank" ((int) ((to_real window_width * to_real window_height) / 2)); _result = map_unary process x { process in = rank window_width window_height select in; } } } } Filter_morphology_item = class Menupullright "_Morphology" "various morphological filters" { /* Some useful masks. */ mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]]; mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]]; Threshold_item = Select_item.Threshold_item; sep1 = Menuseparator; Dilate_item = class Menupullright "_Dilate" "morphological dilate" { Dilate8_item = class Menuaction "_8-connected" "dilate with an 8-connected mask" { action x = map_unary (dilate mask8) x; } Dilate4_item = class Menuaction "_4-connected" "dilate with a 4-connected mask" { action x = map_unary (dilate mask4) x; } } Erode_item = class Menupullright "_Erode" "morphological erode" { Erode8_item = class Menuaction "_8-connected" "erode with an 8-connected mask" { action x = map_unary (erode mask8) x; } Erode4_item = class Menuaction "_4-connected" "erode with a 4-connected mask" { action x = map_unary (erode mask4) x; } } Custom_morph_item = class Menuaction "Custom _Morphology" "convolution morphological operator" { action x = class _result { _vislevel = 3; mask = mask4; type = Option "Operation" ["Erode", "Dilate"] 1; apply = Expression "Number of times to apply mask" 1; _result = map_unary morph x { morph image = Image value' { fatmask = (iterate (dilate mask) mask)?(to_real apply - 1); value' = im_erode image.value fatmask, type.value == 0 = im_dilate image.value fatmask; } } } } sep2 = Menuseparator; Open_item = class Menuaction "_Open" "open with an 8-connected mask" { action x = map_unary (dilate mask8 @ erode mask8) x; } Close_item = class Menuaction "_Close" "close with an 8-connected mask" { action x = map_unary (erode mask8 @ dilate mask8) x; } Clean_item = class Menuaction "C_lean" "remove 8-connected isolated points" { action x = map_unary clean x { clean x = x ^ erode mask1 x; } } Thin_item = class Menuaction "_Thin" "thin once" { action x = map_unary thinall x { masks = take 8 (iterate rot45 thin); thin1 m x = x ^ erode m x; thinall x = foldr thin1 x masks; } } sep3 = Menuseparator; Segment_item = class Menuaction "_Segment" "break image into disjoint regions" { action x = class _result { _vislevel = 3; segments = Expression "Number of disjoint regions" (map_unary (get_header "n-segments") _result); _result = map_unary segment x; } } } Filter_fourier_item = class Menupullright "_Fourier" "various Fourier filters" { preview_size = 64; sense_option = Option "Sense" [ "Pass", "Reject" ] 0; // make a visualisation image make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn) (im_create_fmask preview_size preview_size); // make the process function process fn in = (Image @ fn) (im_flt_image_freq in.value); New_ideal_item = class Menupullright "_Ideal" "various ideal Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f sense.value fc.value 0 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 6) fc.value rw.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject ideal Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 12) fcx.value fcy.value r.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_gaussian_item = class Menupullright "_Gaussian" "various Gaussian Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 4) fc.value ac.value 0 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 10) fc.value rw.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Gaussian Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; // call a freq func with our parameters _params f = f (sense.value + 16) fcx.value fcy.value r.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } New_butterworth_item = class Menupullright "_Butterworth" "various Butterworth Fourier filters" { High_low_item = class Menuaction "_High or Low Pass" "highpass/lowpass Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 2) o.value fc.value ac.value 0 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Ring_item = class Menuaction "_Ring Pass or Ring Reject" "ring pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fc = Scale "Frequency cutoff" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; rw = Scale "Ring width" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 8) o.value fc.value rw.value ac.value 0; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } Band_item = class Menuaction "_Band Pass or Band Reject" "band pass/reject Butterworth Fourier filter" { action x = class _result { _vislevel = 3; sense = sense_option; fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5; fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5; r = Scale "Radius" 0.01 0.99 0.5; ac = Scale "Amplitude cutoff" 0.01 0.99 0.5; o = Scale "Order" 1 10 2; // call a freq func with our parameters _params f = f (sense.value + 14) o.value fcx.value fcy.value r.value ac.value; visualize_mask = make_vis _params; _result = map_unary (process _params) x; } } } } Filter_enhance_item = class Menupullright "_Enhance" "various enhancement filters" { Falsecolour_item = class Menuaction "_False Colour" "false colour a mono image" { action x = class _result { _vislevel = 3; o = Scale "Offset" (-255) 255 0; clip = Toggle "Clip colour range" false; _result = map_unary process x { process im = falsecolour mono'' { mono = colour_transform_to Image_type.B_W im; mono' = mono + o; mono'' = (unsigned char) mono', clip = (unsigned char) (mono' & 0xff); } } } } Statistical_diff_item = class Menuaction "_Statistical Difference" "statistical difference of an image" { action x = class _result { _vislevel = 3; wsize = Expression "Window size" 11; tmean = Expression "Target mean" 128; mean_weight = Scale "Mean weight" 0 1 0.8; tdev = Expression "Target deviation" 50; dev_weight = Scale "Deviation weight" 0 1 0.8; border = Toggle "Output image matches input image in size" true; _result = map_unary process x { process in = Image in'' { in' = colour_transform_to Image_type.B_W in.value; fn = im_stdif, border = im_stdif_raw; in'' = fn in' mean_weight.value tmean.expr dev_weight.value tdev.expr wsize.expr wsize.expr; } } } } Hist_equal_item = class Menupullright "_Equalise Histogram" "equalise contrast" { Global_item = class Menuaction "_Global" "equalise contrast globally" { action x = map_unary hist_equalize x; } Local_item = class Menuaction "_Local" "equalise contrast within a roving window" { action x = class _result { _vislevel = 3; window_width = Expression "Window width" 20; window_height = Expression "Window height" 20; _result = map_unary process x { process in = hist_equalize_local window_width.expr window_height.expr in; } } } } } Filter_correlate_item = class Menupullright "Spatial _Correlation" "calculate correlation surfaces" { Correlate_item = class Menuaction "_Correlate" "calculate correlation coefficient" { action a b = map_binary corr a b { corr a b = correlate a b, a.width <= b.width && a.height <= b.height = correlate b a; } } Correlate_fast_item = class Menuaction "_Simple Difference" "calculate sum of squares of differences" { action a b = map_binary corr a b { corr a b = correlate_fast a b, a.width <= b.width && a.height <= b.height = correlate_fast b a; } } } Filter_greyc_item = class Menupullright "_GREYCstoration" "noise-removing filter" { Denoise_item = class Menuaction "Denoise" "Noise-removing filter" { action x = class _result { _vislevel = 3; iterations = Scale "Iterations" 1 5 1; amplitude = Scale "Amplitude" 1 100 40; sharpness = Scale "Sharpness" 0 3 0.9; anisotropy = Scale "Anisotropy" 0 1 0.15; alpha = Scale "Noise scale" 0 5 0.6; sigma = Scale "Geometry regularity" 0 2 1.1; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) x; } } Enlarge_item = class Menuaction "Enlarge" "Enlarge image" { action x = class _result { _vislevel = 3; scale = Scale "Enlarge" 1 10 3; iterations = Scale "Iterations" 1 5 3; amplitude = Scale "Amplitude" 1 100 20; sharpness = Scale "Sharpness" 0 3 0.2; anisotropy = Scale "Anisotropy" 0 1 0.9; alpha = Scale "Noise scale" 0 5 0.1; sigma = Scale "Geometry regularity" 0 2 1.5; dl = Scale "Spatial integration step" 0 1 0.8; da = Scale "Angular integration step" 0 90 30; gauss_prec = Scale "Precision" 1 10 2; interpolation = Option "Interpolation" ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0; fast_approx = Toggle "Fast approximation" true; _result = greyc (to_real iterations) (to_real amplitude) (to_real sharpness) (to_real anisotropy) (to_real alpha) (to_real sigma) (to_real dl) (to_real da) (to_real gauss_prec) (to_real interpolation) (to_real fast_approx) (resize Interpolate_bilinear (to_real scale) (to_real scale) x); } } } Filter_magick_item = class Menupullright "Magic_k" "various Image/Graphics Magick filters" { system command x = map_unary (system_image command) x; radius_widget = Scale "Radius" 1 100 10; sigma_widget = Scale "Sigma" 0.1 10 1; angle_widget = Scale "Angle" (-360) 360 0; text_widget = String "Text to draw" "AaBbCcDdEe"; print_colour triple = concat ["\"#", concat (map fmt triple), "\""] { fmt x = reverse (take 2 (reverse (print_base 16 (x + 256)))); } Foreground triple = class Colour "sRGB" triple { _flag = "-fill " ++ print_colour triple; Colour_edit space triple = this.Foreground triple; } foreground_widget = Foreground [0, 0, 0]; Background triple = class Colour "sRGB" triple { _flag = "-background " ++ print_colour triple; Colour_edit space triple = this.Background triple; } background_widget = Background [255, 255, 255]; Antialias value = class Toggle "Antialias" value { _flag = "-antialias", value = "+antialias"; Toggle_edit caption value = this.Antialias value; } antialias_widget = Antialias true; Gravity gravity = class Option_string "Gravity" [ "None", "Center", "East", "Forget", "NorthEast", "North", "NorthWest", "SouthEast", "South", "SouthWest", "West", "Static" ] gravity { _flag = "-gravity " ++ gravity; Option_edit caption labels value = this.Gravity labels?value; } gravity_widget = Gravity "Center"; Alpha alpha = class Option_string "Alpha" [ "On", "Off", "Set", "Opaque", "Transparent", "Extract", "Copy", "Shape", "Background" ] alpha { _flag = "-alpha " ++ alpha; Option_edit caption labels value = this.Alpha labels?value; } alpha_widget = Alpha "On"; Geometry_widget = class { _vislevel = 3; x = Expression "Y" 0; y = Expression "X" 0; hoffset = Expression "Horizontal offset" 10; voffset = Expression "Vertical offset" 10; _flag = concat [print x.expr, "x", print y.expr, format hoffset, format voffset] { // print an offset ... we want '+' in front of +ve strings format offset = concat ["+", print offset.expr], offset.expr >= 0 = print offset.expr; } }; Font_widget = class { _vislevel = 3; family = Option_string "Family" [ "Arial", "ArialBlack", "AvantGarde", "BitstreamCharter", "Bookman", "CenturySchoolbook", "ComicSansMS", "Courier", "CourierNew", "DejaVuSans", "DejaVuSansMono", "DejaVuSerif", "Dingbats", "FreeMono", "FreeSans", "FreeSerif", "Garuda", "Georgia", "Helvetica", "HelveticaNarrow", "Impact", "LiberationMono", "LiberationSans", "LiberationSerif", "NewCenturySchlbk", "Palatino", "Purisa", "Symbol", "Times", "TimesNewRoman", "Ubuntu", "Verdana", "Webdings" ] "Arial"; style = Option_string "Style" [ "Any", "Italic", "Normal", "Oblique" ] "Normal"; weight = Scale "Weight" 1 800 400; size = Scale "Point size" 1 100 12; stretch = Option_string "Stretch" [ "Any", "Condensed", "Expanded", "ExtraCondensed", "ExtraExpanded", "Normal", "SemiCondensed", "SemiExpanded", "UltraCondensed", "UltraExpanded" ] "Normal"; _flag = join_sep " " [ "-family", family.item, "-weight", print weight.value, "-pointsize", print size.value, "-style", style.item, "-stretch", stretch.item]; } Adaptive_blur_item = class Menuaction "_Adaptive Blur" "blur less near edges" { action x = class _result { _vislevel = 3; radius = radius_widget; sigma = sigma_widget; command = magick_command (concat ["-adaptive-blur ", print radius.value, "x", print sigma.value]); _result = system command x; } } Adaptive_sharpen_item = class Menuaction "_Adaptive Sharpen" "sharpen more near edges" { action x = class _result { _vislevel = 3; radius = radius_widget; sigma = sigma_widget; command = magick_command (concat ["-adaptive-sharpen ", print radius.value, "x", print sigma.value]); _result = system command x; } } Alpha_item = class Menuaction "_Alpha" "add/remove alpha channel" { action x = class _result { _vislevel = 3; alpha = alpha_widget; command = magick_command alpha._flag; _result = system command x; } } Annotate_item = class Menuaction "_Annotate" "add text annotation" { action x = class _result { _vislevel = 3; text = text_widget; font = Font_widget; geometry = Geometry_widget; gravity = gravity_widget; foreground = foreground_widget; antialias = antialias_widget; command = magick_command (join_sep " " [ font._flag, antialias._flag, gravity._flag, foreground._flag, "-annotate", geometry._flag, "\"" ++ text.value ++ "\""]); _result = system command x; } } Swirl_item = class Menuaction "_Swirl" "swirl around the centre" { action x = class _result { _vislevel = 3; angle = angle_widget; command = magick_command ("-swirl " ++ print angle.value); _result = system command x; } } } #separator Filter_tilt_item = class Menupullright "Ti_lt Brightness" "tilt brightness" { Left_right_item = class Menuaction "_Left to Right" "linear left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height; scale = (ramp - 0.5) * tilt + 1; } } } } Top_bottom_item = class Menuaction "_Top to Bottom" "linear top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width); scale = (ramp - 0.5) * tilt + 1; } } } } sep1 = Menuseparator; Left_right_cos_item = class Menuaction "Cosine Left-_right" "cosine left-right brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Left-right tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_lr x { tilt_lr image = image * scale { ramp = im_fgrey image.width image.height - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } Top_bottom_cos_item = class Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Top-bottom tilt" (-1) 1 0; shift = Scale "Shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { ramp = rot90 (im_fgrey image.height image.width) - 0.5 - shift.value; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } sep2 = Menuseparator; Circular_item = class Menuaction "_Circular" "circular brighten" { action x = class _result { _vislevel = 3; tilt = Scale "Tilt" (-1) 1 0; hshift = Scale "Horizontal shift by" (-1) 1 0; vshift = Scale "Vertical shift by" (-1) 1 0; _result = map_unary tilt_tb x { tilt_tb image = image * scale { hramp = im_fgrey image.width image.height - 0.5 - hshift.value; vramp = rot90 (im_fgrey image.height image.width) - 0.5 - vshift.value; ramp = (hramp ** 2 + vramp ** 2) ** 0.5; scale = 0.5 * tilt.value * cos (ramp * 180) + 1; } } } } } Filter_blend_item = class Menupullright "_Blend" "blend objects together" { Scale_blend_item = class Menuaction "_Scale" "blend two objects together with a scale" { action a b = class _result { _vislevel = 3; p = Scale "Blend position" 0 1 0.5; _result = map_binary process a b { process im1 im2 = im1 * (1 - p.value) + im2 * p.value; } } } Image_blend_item = class Menuaction "_Image" "use an image to blend two objects" { action a b c = class _result { _vislevel = 3; i = Toggle "Invert mask" false; _result = map_trinary process a b c { process a b c = blend condition in1 in2, !i = blend (invert condition) in1 in2 { compare a b // prefer image as the condition = false, !has_image a && has_image b // prefer mono images as the condition = false, has_bands a && has_bands b && get_bands a > 1 && get_bands b == 1 // prefer uchar as the condition = false, has_format a && has_format b && get_format a > Image_format.UCHAR && get_format b == Image_format.UCHAR = true; [condition, in1, in2] = sortc compare [a, b, c]; } } } } Line_blend_item = class Menuaction "_Along Line" "blend between image a and image b along a line" { action a b = class _result { _vislevel = 3; orientation = Option "Orientation" [ "Left to Right", "Top to Bottom" ] 0; blend_position = Scale "Blend position" 0 1 0.5; blend_width = Scale "Blend width" 0 1 0.05; _result = map_binary process a b { process a b = blend (Image condition) b a { output_width = max_pair a.width b.width; output_height = max_pair a.height b.height; range = output_width, orientation == 0 = output_height; blend_position' = floor (range * blend_position.value); blend_width' = 1, blend_width.value == 0 = floor (range * blend_width.value); start = blend_position' - blend_width' / 2; background = (make_xy output_width output_height) >= blend_position'; ramp = im_grey blend_width' output_height, orientation == 0 = rot90 (im_grey blend_width' output_width); condition = insert_noexpand start 0 ramp background?0, orientation == 0 = insert_noexpand 0 start ramp background?1; } } } } Blend_alpha_item = class Menuaction "_Alpha" "blend images with optional alpha channels" { // usage: layerit foreground background // input images must be either 1 or 3 bands, optionally + 1 band // which is used as the alpha channel // rich lott scale_mask im opacity = (unsigned char) (to_real opacity / 255 * im); // to mono intensity = colour_transform_to Image_type.B_W; // All the blend functions // I am grateful to this page // http://www.pegtop.net/delphi/blendmodes/ // for most of the formulae. blend_normal mask opacity fg bg = blend (scale_mask mask opacity) fg bg; blend_iflighter mask opacity fg bg = blend (if fg' > bg' then mask' else 0) fg bg { fg' = intensity fg; bg' = intensity bg; mask' = scale_mask mask opacity ; } blend_ifdarker mask opacity fg bg = blend (if fg' < bg' then mask' else 0) fg bg { fg' = intensity fg ; bg' = intensity bg ; mask' = scale_mask mask opacity ; } blend_multiply mask opacity fg bg = blend (scale_mask mask opacity) fg' bg { fg' = fg / 255 * bg; } blend_add mask opacity fg bg = blend mask fg' bg { fg' = opacity / 255 * fg + bg; } blend_subtract mask opacity fg bg = blend mask fg' bg { fg' = bg - opacity / 255 * fg; } blend_screen mask opacity fg bg = blend mask fg' bg { fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255; } blend_burn mask opacity fg bg = blend mask fg'' bg { // fades to white which has no effect. fg' = (255 - opacity) + opacity * fg / 255; fg'' = 255 - 255 * (255 - bg) / fg'; } blend_softlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255; } blend_hardlight mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 2 / 255 * fg * bg, bg < 129 = 255 - 2 * (255 - bg) * (255 - fg) / 255; } blend_lighten mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg < fg then fg else bg; } blend_darken mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = if bg > fg then fg else bg; } blend_dodge mask opacity fg bg = blend mask fg'' bg { // one added to avoid divide by zero fg' = 1 + 255 - (opacity / 255 * fg); fg'' = bg * 255 / fg'; } blend_reflect mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = bg * bg / (255 - fg); } blend_freeze mask opacity fg bg = blend mask' fg' bg { mask' = scale_mask mask opacity; fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg); } blend_or mask opacity fg bg = bg | (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } blend_and mask opacity fg bg = bg & (unsigned char) fg' { mask' = scale_mask mask opacity; fg' = fg * mask' / 255; } // blend types NORMAL = 0; IFLIGHTER = 1; IFDARKER = 2; MULTIPLY = 3; ADD = 4; SUBTRACT = 5; SCREEN = 6; BURN = 7; DODGE = 8; HARDLIGHT = 9; SOFTLIGHT = 10; LIGHTEN = 11; DARKEN = 12; REFLECT = 13; FREEZE = 14; OR = 15; AND = 16; // names we show the user for blend types names = Enum [ _ "Normal" => NORMAL, _ "If Lighter" => IFLIGHTER, _ "If Darker" => IFDARKER, _ "Multiply" => MULTIPLY, _ "Add" => ADD, _ "Subtract" => SUBTRACT, _ "Screen" => SCREEN, _ "Burn" => BURN, _ "Soft Light" => SOFTLIGHT, _ "Hard Light" => HARDLIGHT, _ "Lighten" => LIGHTEN, _ "Darken" => DARKEN, _ "Dodge" => DODGE, _ "Reflect" => REFLECT, _ "Freeze" => FREEZE, _ "Bitwise OR" => OR, _ "Bitwise AND" => AND ]; // functions we call for each blend type actions = Table [ [NORMAL, blend_normal], [IFLIGHTER, blend_iflighter], [IFDARKER, blend_ifdarker], [MULTIPLY, blend_multiply], [ADD, blend_add], [SUBTRACT, blend_subtract], [SCREEN, blend_screen], [BURN, blend_burn], [SOFTLIGHT, blend_softlight], [HARDLIGHT, blend_hardlight], [LIGHTEN, blend_lighten], [DARKEN, blend_darken], [DODGE, blend_dodge], [REFLECT, blend_reflect], [FREEZE, blend_freeze], [OR, blend_or], [AND, blend_and] ]; // make sure im has an alpha channel (set opaque if it hasn't) put_alpha im = im, im.bands == 4 || im.bands == 2 = im ++ 255; // make sure im has no alpha channel lose_alpha im = extract_bands 0 3 im, im.bands == 4 = im?0, im.bands == 2 = im; // does im have al alpha channel? has_alpha im = im.bands == 2 || im.bands == 4; // get the alpha (set opaque if no alpha) get_alpha img = img'?3, img.bands == 4 = img'?1 { img' = put_alpha img; } // add an alpha ... cast the alpha image to match the main image append_alpha im alpha = im ++ clip2fmt im.format alpha; // makes fg the same size as bg, displaced with u, v pixel offset moveit fg bg u v = insert_noexpand u v fg bg' { bg' = image_new bg.width bg.height fg.bands fg.format fg.coding fg.type 0 0 0; } action bg fg = class _value { _vislevel = 3; method = Option_enum "Blend mode" names "Normal"; opacity = Scale "Opacity" 0 255 255; hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0; _value = append_alpha blended merged_alpha, has_alpha bg = blended { // displace and resize fg (need to displace alpha too) fg' = moveit (put_alpha fg) bg hmove vmove; // transform to sRGB fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg'); bg' = colour_transform_to Image_type.sRGB (lose_alpha bg); // alphas merged merged_alpha = get_alpha bg | get_alpha fg'; // blend together blended = (actions.lookup 0 1 method.value_thing) (get_alpha fg') opacity.value fg'' bg'; } } } } Filter_overlay_header_item = class Menuaction "_Overlay" "make a colour overlay of two monochrome images" { action a b = class _result { _vislevel = 3; colour = Option "Colour overlay as" [ _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = map_binary overlay a b { overlay a b = image_set_type Image_type.sRGB [(a' ++ b' ++ 0), (a' ++ 0 ++ b'), (b' ++ a' ++ 0), (b' ++ 0 ++ a'), (0 ++ a' ++ b'), (0 ++ b' ++ a')]?colour { a' = colour_transform_to Image_type.B_W a; b' = colour_transform_to Image_type.B_W b; } } } } Filter_colourize_item = class Menuaction "_Colourize" "use a colour image or patch to tint a mono image" { action a b = class _result { _vislevel = 3; tint = Scale "Tint" 0 1 0.6; _result = map_binary tintit a b { tintit a b = colour_transform_to (get_type colour) colourized' { // get the mono thing first [mono, colour] = sortc (const (is_colour_type @ get_type)) [a, b]; colour' = tint * colour_transform_to Image_type.LAB colour; mono' = colour_transform_to Image_type.B_W mono; colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2; colourized' = image_set_type Image_type.LAB colourized; } } } } Filter_browse_multiband_item = class Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" { Bandwise_item = class Menuaction "B_andwise" "browse through the bands of a multiband image" { action image = class _result { _vislevel = 3; band = Scale "Band" 0 (image.bands - 1) 0; display = Option "Display as" [ _ "Grey", _ "Green over Red", _ "Blue over Red", _ "Red over Green", _ "Red over Blue", _ "Blue over Green", _ "Green over Blue" ] 0; _result = output { down = (int) band.value; up = down + 1; remainder = band.value - down; fade x a = Vector [0], x == 0 = a * x; a = fade remainder image?up; b = fade (1 - remainder) image?down; output = [ a + b, a ++ b ++ 0, a ++ 0 ++ b, b ++ a ++ 0, b ++ 0 ++ a, 0 ++ a ++ b, 0 ++ b ++ a ] ? display; } } } Bitwise_item = class Menuaction "Bi_twise" "browse through the bits of an image" { action x = class _result { _vislevel = 3; bit = Islider "Bit" 0 (nbits - 1) (nbits - 1) { nbits = x.bits, is_Image x = 8; Islider c f t v = class scope.Scale c f t ((int) v) { Scale = Islider; } } _result = map_unary process x { process im = (im & (0x1 << bit.value)) != 0; } } } } #separator Filter_negative_item = class Menuaction "Photographic _Negative" "swap black and white" { action x = map_unary invert x { invert in = clip2fmt in.format (colour_transform_to (get_type in) rgb') { rgb = colour_transform_to Image_type.sRGB in; rgb' = 255 - rgb; } } } Filter_solarize_item = class Menuaction "_Solarise" "invert colours above a threshold" { action x = class _result { _vislevel = 3; kink = Scale "Kink" 0 1 0.5; _result = map_unary process x { process image = hist_map tab'''' image { // max pixel value for this format mx = Image_format.maxval image.format; // make a LUT ... just 8 and 16 bit tab = im_identity_ushort image.bands mx, image.format == Image_format.USHORT = im_identity image.bands; tab' = Image tab; // make basic ^ shape tab'' = tab' * (1 / kink), tab' < mx * kink = (mx - tab') / (1 - kink); tab''' = clip2fmt image.format tab''; // smooth a bit mask = matrix_blur (tab'''.width / 8); tab'''' = convsep mask tab'''; } } } } Filter_diffuse_glow_item = class Menuaction "_Diffuse Glow" "add a halo to highlights" { action x = class _result { _vislevel = 3; r = Scale "Radius" 0 50 5; highlights = Scale "Highlights" 0 100 95; glow = Scale "Glow" 0 1 0.5; colour = Colour_new_item.Widget_colour_item.action; _result = map_unary process x { process image = image' { mono = (unsigned char) (colour_transform_to Image_type.B_W image); thresh = hist_thresh (highlights.value / 100) mono; mask = mono > thresh; blur = convsep (matrix_gaussian_blur r.value) mask; colour' = colour_transform_to image.type colour; image' = image + colour' * glow * (blur / 255); } } } } Filter_drop_shadow_item = class Menuaction "Drop S_hadow" "add a drop shadow to an image" { action x = class _result { _vislevel = 3; sx = Scale "Horizontal shadow" (-50) 50 5; sy = Scale "Vertical shadow" (-50) 50 5; ss = Scale "Shadow softness" 0 20 5; bg_colour = Expression "Background colour" 255; sd_colour = Expression "Shadow colour" 128; alpha = Toggle "Shadow in alpha channel" false; transparent = Toggle "Zero pixels are transparent" false; _result = map_unary shadow x { shadow image = Image final { blur_size = ss.value * 2 + 1; // matrix we blur with to soften shadows blur_matrix = matrix_gaussian_blur blur_size; matrix_size = blur_matrix.width; matrix_radius = (int) (matrix_size / 2) + 1; // position and size of shadow image in input cods // before and after fuzzing shadow_rect = Rect sx.value sy.value image.width image.height; fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius; // size and pos of final image, in input cods final_rect = image.rect.union fuzzy_shadow_rect; // hard part of shadow in output cods shadow_rect' = Rect (shadow_rect.left - final_rect.left) (shadow_rect.top - final_rect.top) shadow_rect.width shadow_rect.height; // make the shadow mask ... true for parts which cast // a shadow mask = (foldr1 bitwise_and @ bandsplit) (image.value != 0), transparent = image_new image.width image.height 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W 255 0 0; mask' = embed 0 shadow_rect'.left shadow_rect'.top final_rect.width final_rect.height mask; mask'' = convsep blur_matrix mask'; // use mask to fade between bg and shadow colour mk_background colour = image_new final_rect.width final_rect.height image.bands image.format image.coding image.type colour 0 0; bg_image = mk_background bg_colour.expr; shadow_image = mk_background sd_colour.expr; bg = blend mask'' shadow_image bg_image; // make a full size mask fg_mask = embed 0 (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) final_rect.width final_rect.height mask; // wrap up the input image ... put the shadow colour // around it, so if we are outputting a separate // alpha the shadow colour will be set correctly fg = insert (image.rect.left - final_rect.left) (image.rect.top - final_rect.top) image.value shadow_image; final // make a separate alpha = fg ++ mask'', alpha // paste image over shadow = if fg_mask then fg else bg; } } } } Filter_paint_text_item = class Menuaction "_Paint Text" "paint text into an image" { action x = paint_position, is_Group x = paint_area { paint_area = class _result { _check_args = [ [x, "x", check_Image] ]; _vislevel = 3; text = String "Text to paint" "Hello world!"; font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT; align = Option "Alignment" ["Left", "Centre", "Right"] 0; dpi = Expression "DPI" 300; colour = Expression "Text colour" 255; place = Region x (x.width / 4) (x.height / 4) (x.width / 2) (x.height / 2); _result = insert_noexpand place.left place.top (blend txt' fg place) x { fg = image_new place.width place.height x.bands x.format x.coding x.type colour.expr 0 0; txt = Image (im_text text.value font.value place.width align.value (to_real dpi)); bg = im_black place.width place.height 1; txt' = insert_noexpand 0 0 txt bg; } } paint_position = class _result { _vislevel = 3; text = Pattern_images_item.Text_item.action; colour = Expression "Text colour" 255; position = Option "Position" [ _ "North-west", _ "North", _ "North-east", _ "West", _ "Centre", _ "East", _ "South-west", _ "South", _ "South-east", _ "Specify in pixels" ] 4; left = Expression "Pixels from left" 0; top = Expression "Pixels from top" 0; _result = map_unary paint x { paint image = insert_noexpand x' y' place' image { xr = image.width - text.width; yr = image.height - text.height; x = left.expr, position == 9 = [0, xr / 2, xr]?(position % 3); y = top.expr, position == 9 = [0, yr / 2, yr]?(position / 3); x' = range 0 x (image.width - 1); y' = range 0 y (image.height - 1); w' = range 1 text.width (image.width - x'); h' = range 1 text.height (image.height - y'); place = extract_area x' y' w' h' image; text' = insert_noexpand 0 0 text (im_black w' h' 1); fg = image_new w' h' image.bands image.format image.coding image.type colour.expr 0 0; place' = blend text' fg place; } } } } } nip2-8.7.1/share/nip2/compat/7.26/_joe_extra.def0000644000175000017500000003017513351443023015754 00000000000000//////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Frame_item = class Menupullright "Picture _Frame" "working with images of frames" { //////////////////////////////////////////////////////////////////////////////////// Build_frame_item = class Menupullright "_Build Frame From" "builds a new frame from image a and places it around image b" { //////////////////////////////////////////////////////////////////////////////////// Frame_corner_item = class Menuaction "_Frame Corner" "copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = corner_frame _a _im_w _im_h _ov _cs _ms _bf; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Simple_frame_item = class Menuaction "_Simple Frame" "extends or shortens the central sections of a simple frame, a, to fit round a given image, b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 0; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; //Scale frame image if required. _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.mount_colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } //////////////////////////////////////////////////////////////////////////////////// Complex_frame_item = class Menuaction "_Complex Frame" "extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b" { prefs = Workspaces.Preferences; action a b = class _result { _check_args = [ [a, "a", check_Image], [b, "b", check_Image] ]; _check_all = [ [a.coding == b.coding && a.bands == b.bands, "a.coding == b.coding && a.bands == b.bands"] ]; _vislevel = 3; ppcm = Expression "Number of pixels per cm" 25; /* Given the value of ppcm, distance between the inner edge of the frame * and the outer edge of the image. +ve values mean the frame overlaps * the image. */ overlap = Expression "Size of frame overlap in cm" 0; variables = Frame_variables 1; _type = Image_type.colour_spaces.get_name b.type; //If applied the count colour be seen for -ve values of overlap mount_options = Mount_options _type ppcm.expr; _cs = variables.corner_section.value; _es = variables.edge_section.value; _ms = variables.middle_section.value; _ov = ppcm.expr * overlap.expr; _sf = variables.scale_factor.expr; _bf = variables.blend_fraction.value; _a = a, _sf == 1; = a, _sf == 0; = Image (resize Interpolate_bilinear _sf _sf a.value); _im_w = b.width; _im_h = b.height + mount_options._los, mount_options.apply = b.height; _os = mount_options._los, mount_options.apply = 0; _cl = Vector mount_options.colour.value, mount_options.apply = 0; //Produce scaled and resized frame. frame = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option; //Resize image canvas and applied mount colour as required. _pos_im = frame_position_image b frame _os _cl; //Wrap frame round image. _result = if (frame == 0) then _pos_im else frame; } } } //////////////////////////////////////////////////////////////////////////////////// Straighten_frame_item = class Menuaction "_Straighten Frame" "uses four points to square up distorted images of frames" { action a = Perspective_item.action a; } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Select_item = class Menupullright "_Select" "select user defined areas of an image" { prefs = Workspaces.Preferences; /* Option toggle used to define whether the user is replacing a * dark or a light area. */ _control = Option "Make" [ "Selection Brighter", "Selection Darker", "Selection Black", "Selection White", "Background Black", "Background White", "Mask" ] 4; control_selection mask im no = [ if mask then im * 1.2 else im * 1, if mask then im * 0.8 else im * 1, if mask then 0 else im, if mask then 255 else im, if mask then im else 0, if mask then im else 255, mask ]?no; Rectangle = class Menuaction "_Rectangle" "use line/arrow/rect x to define a rectangle" { action x = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_rect x; im = get_image x; select_rect x = Image mask { im = Image (get_image x); imc = make_xy im.width im.height; mask = imc?0 >= x.nleft & imc?0 < x.nright & imc?1 >= x.ntop & imc?1 < x.nbottom; } } } } Elipse = class Menuaction "_Ellipse" "use a line/arrow x to define the center point radius and direction of an ellipse" { action x = class _result { _vislevel = 3; control = _control; width = Scale "Width" 0.01 1 0.5; _result = control_selection mask im control { mask = select_ellipse x width.value; im = x.image; } } } Tetragon = class Menuaction "_Tetragon" "selects the convex area defined by four points" { action a b c d = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_tetragon a b c d; im = get_image a; } } } Polygon = class Menuaction "_Polygon" "selects a polygon from an ordered group of points" { action pt_list = class _result { _vislevel = 3; control = _control; _result = control_selection mask im control { mask = select_polygon pt_list; im = get_image ((pt_list.value)?0); } } } sep1 = Menuseparator; Threshold_item = class Menuaction "Thres_hold" "simple image threshold" { action x = class _result { _vislevel = 3; t = Scale "Threshold" 0 mx (mx / 2) { mx = Image_format.maxval x.format, is_Image x = 255; } _result = map_unary (more t.value) x; } } Threshold_percent_item = class Menuaction "Per_cent Threshold" "threshold at a percentage of pixels" { action x = class _result { _vislevel = 3; t = Scale "Percentage of pixels" 0 100 50; _result = map_unary (more (hist_thresh (t.value / 100) x)) x; } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_match_item = class Menuaction "_Perspective Match" "rotate, scale and skew one image to match another" { action x y = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; _b = find_image y; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.1 0.9; ap4 = Mark_relative _a 0.9 0.9; bp1 = Mark_relative _b 0.1 0.1; bp2 = Mark_relative _b 0.9 0.1; bp3 = Mark_relative _b 0.1 0.9; bp4 = Mark_relative _b 0.9 0.9; _result = map_binary process x y { f1 = _a.width / _b.width; f2 = _a.height / _b.height; rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; pl = sort_pts_clockwise [bp1, bp2, bp3, bp4]; to = [ rl?0.left, rl?0.top, rl?1.left, rl?1.top, rl?2.left, rl?2.top, rl?3.left, rl?3.top ]; from = [ pl?0.left * f1, pl?0.top * f2, pl?1.left * f1, pl?1.top * f2, pl?2.left * f1, pl?2.top * f2, pl?3.left * f1, pl?3.top * f2 ]; trans = perspective_transform to from; process a b = transform 1 0 trans b2 { b2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1) = resize Interpolate_bilinear f1 1 b1 {b1 = resize Interpolate_bilinear 1 f2 b;} } } } }; //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Perspective_item = class Menuaction "Pe_rspective Distort" "rotate, scale and skew an image with respect to defined points" { action x = class _result { _vislevel = 3; // try to find an image ... for a group, get the first item find_image x = x, is_Image x = find_image x?0, is_list x = find_image x.value, is_class x && has_value x = error "unable to find image"; _a = find_image x; dir = Option "Select distort direction" [ "Distort to points", "Distort to corners" ] 1; ap1 = Mark_relative _a 0.1 0.1; ap2 = Mark_relative _a 0.9 0.1; ap3 = Mark_relative _a 0.9 0.9; ap4 = Mark_relative _a 0.1 0.9; _result = map_unary process x { trans = [perspective_transform to from, perspective_transform from to]?(dir.value) { rl = sort_pts_clockwise [ap1, ap2, ap3, ap4]; to = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top, (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top]; from=[0, 0, (_a.width - 1), 0, (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)]; } process a = transform 1 0 trans a; } } }; nip2-8.7.1/share/nip2/compat/7.26/Colour.def0000644000175000017500000003607713351443023015107 00000000000000 Colour_new_item = class Menupullright (_ "_New") (_ "make a patch of colour") { Widget_colour_item = class Menuaction (_ "_Colour") (_ "make a patch of colour") { action = Colour_picker "Lab" [50,0,0]; } LAB_colour = class Menuaction (_ "CIE Lab _Picker") (_ "pick colour in CIE Lab space") { action = widget "Lab" [50, 0, 0]; // ab_slice size size = 512; // range of values ... +/- 128 for ab range = 256; // map xy in slice image to ab and back xy2ab x = x / (size / range) - 128; ab2xy a = (a + 128) * (size / range); widget space default_value = class Colour space _result { _vislevel = 3; [_L, _a, _b] = default_value; L = Scale "Lightness" 0 100 _L; ab_slice = Image (lab_slice size L.value); point = Mark ab_slice (ab2xy _a) (ab2xy _b); _result = [L.value, xy2ab point.left, xy2ab point.top]; Colour_edit colour_space value = widget colour_space value; } } } Colour_to_colour_item = class Menuaction (_ "Con_vert to Colour") (_ "convert anything to a colour") { action x = to_colour x; } #separator Colour_convert_item = class Menupullright (_ "_Colourspace") (_ "convert to various colour spaces") { spaces = Image_type.image_colour_spaces; conv dest x = class _result { _vislevel = 3; to = Option_enum (_ "Convert to") spaces (spaces.get_name dest); _result = map_unary (colour_transform_to to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "convert to mono colourspace") { action x = conv Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "convert to sRGB colourspace") { action x = conv Image_type.sRGB x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "convert to GREY16 colourspace") { action x = conv Image_type.GREY16 x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "convert to RGB16 colourspace") { action x = conv Image_type.RGB16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "convert to Lab colourspace (float Lab)") { action x = conv Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "convert to LabQ colourspace (32-bit Lab)") { action x = conv Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "convert to LabS colourspace (48-bit Lab)") { action x = conv Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "convert to LCh colourspace") { action x = conv Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "convert to XYZ colourspace") { action x = conv Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "convert to Yxy colourspace") { action x = conv Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "convert to UCS colourspace") { action x = conv Image_type.UCS x; } } /* mark objects as being in various colourspaces */ Colour_tag_item = class Menupullright (_ "_Tag As") (_ "tag object as being in various colour spaces") { spaces = Image_type.image_colour_spaces; tag dest x = class _result { _vislevel = 3; to = Option_enum (_ "Tag as") spaces (spaces.get_name dest); _result = map_unary (image_set_type to.value_thing) x; } Mono_item = class Menuaction (_ "_Monochrome") (_ "tag as being in mono colourspace") { action x = tag Image_type.B_W x; } sRGB_item = class Menuaction (_ "_sRGB") (_ "tag as being in sRGB colourspace") { action x = tag Image_type.sRGB x; } RGB16_item = class Menuaction (_ "_RGB16") (_ "tag as being in RGB16 colourspace") { action x = tag Image_type.RGB16 x; } GREY16_item = class Menuaction (_ "_GREY16") (_ "tag as being in GREY16 colourspace") { action x = tag Image_type.GREY16 x; } Lab_item = class Menuaction (_ "_Lab") (_ "tag as being in Lab colourspace (float Lab)") { action x = tag Image_type.LAB x; } LabQ_item = class Menuaction (_ "Lab_Q") (_ "tag as being in LabQ colourspace (32-bit Lab)") { action x = tag Image_type.LABQ x; } LabS_item = class Menuaction (_ "Lab_S") (_ "tag as being in LabS colourspace (48-bit Lab)") { action x = tag Image_type.LABS x; } LCh_item = class Menuaction (_ "L_Ch") (_ "tag as being in LCh colourspace") { action x = tag Image_type.LCH x; } XYZ_item = class Menuaction (_ "_XYZ") (_ "tag as being in XYZ colourspace") { action x = tag Image_type.XYZ x; } Yxy_item = class Menuaction (_ "_Yxy") (_ "tag as being in Yxy colourspace") { action x = tag Image_type.YXY x; } UCS_item = class Menuaction (_ "_UCS") (_ "tag as being in UCS colourspace") { action x = tag Image_type.UCS x; } } Colour_temperature_item = class Menupullright (_ "Colour Te_mperature") (_ "colour temperature conversions") { Whitepoint_item = class Menuaction (_ "_Move Whitepoint") (_ "change whitepoint") { action x = class _result { _vislevel = 3; old_white = Option_enum (_ "Old whitepoint") Whitepoints "D65"; new_white = Option_enum (_ "New whitepoint") Whitepoints "D50"; _result = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im' * (new_white.value_thing / old_white.value_thing); im''' = colour_transform_to (get_type im) im''; } } } } D65_to_D50_item = class Menupullright (_ "D_65 to D50") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D65 to D50 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D652D50_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D65 to D50 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D652D50 im'; im''' = colour_transform_to (get_type im) im''; } } } } D50_to_D65_item = class Menupullright (_ "D_50 to D65") (_ "complex conversion") { XYZ_minimal_item = class Menuaction (_ "_Minimal") (_ "D50 to D65 using the minimal 3x3 matrix in XYZ") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = recomb D502D65_direct im'; im''' = colour_transform_to (get_type im) im''; } } } Bradford_item = class Menuaction (_ "_Bradford") (_ "D60 to D65 in Bradford cone space") { action x = map_unary process x { process im = im''' { im' = colour_transform_to Image_type.XYZ im; im'' = im_D502D65 im'; im''' = colour_transform_to (get_type im) im''; } } } } Lab_to_D50XYZ_item = class Menuaction (_ "_Lab to D50 XYZ") (_ "Lab to XYZ with a D50 whitepoint") { action x = map_unary (colour_unary im_D50Lab2XYZ) x; } D50XYZ_to_Lab_item = class Menuaction (_ "D50 _XYZ to Lab") (_ "XYZ to Lab with a D50 whitepoint") { action x = map_unary (colour_unary im_D50XYZ2Lab) x; } } Colour_icc_item = class Menupullright (_ "_ICC") (_ "transform with ICC profiles") { print_profile = "$VIPSHOME/share/$PACKAGE/data/cmyk.icm"; monitor_profile = "$VIPSHOME/share/$PACKAGE/data/sRGB.icm"; guess_profile image = monitor_profile, has_bands image && get_bands image == 3 = print_profile; render_intents = Option_enum (_ "Render intent") Render_intent.names (_ "Absolute"); Export_item = class Menuaction (_ "_Export") (_ "export from PCS to device space") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Output profile") print_profile; intent = render_intents; depth = Option (_ "Output depth") [_ "8 bit", _ "16 bit"] 0; _result = map_unary process x { process image = icc_export [8, 16]?depth profile.value intent.value_thing lab { lab = colour_transform_to Image_type.LABQ image; } } } } Import_item = class Menuaction (_ "_Import") (_ "import from device space to PCS") { action x = class _result { _vislevel = 3; embedded = Toggle (_ "Use embedded profile if possible") false; profile = Pathname (_ "Default input profile") (guess_profile x); intent = render_intents; _result = map_unary process x { process image = icc_import_embedded intent.value_thing image, get_header_type "icc-profile-data" image != 0 && embedded = icc_import profile.value intent.value_thing image; } } } Transform_item = class Menuaction (_ "_Transform") (_ "transform between two device spaces") { action x = class _result { _vislevel = 3; in_profile = Pathname (_ "Input profile") (guess_profile x); out_profile = Pathname (_ "Output profile") print_profile; intent = render_intents; _result = map_unary process x { process image = icc_transform in_profile.value out_profile.value intent.value_thing image; } } } AC2RC_item = class Menuaction (_ "_Absolute to Relative") (_ "absolute to relative colorimetry using device profile") { action x = class _result { _vislevel = 3; profile = Pathname (_ "Pick a profile") (guess_profile x); _result = map_unary process x { process image = icc_ac2rc profile.value lab { lab = colour_transform_to Image_type.LAB image; } } } } } Colour_rad_item = class Menupullright (_ "_Radiance") (_ "convert to and from Radiance packed format") { Unpack_item = class Menuaction (_ "Unpack") (_ "unpack Radiance format to float") { action x = map_unary rad2float x; } Pack_item = class Menuaction (_ "Pack") (_ "pack 3-band float to Radiance format") { action x = map_unary float2rad x; } } #separator Colour_dE_item = class Menupullright (_ "_Difference") (_ "calculate colour difference") { /* Apply a converter to an object ... convert image or colour (since * we can guess the colour space we're converting from), don't convert * matrix or vector (since we can't tell ... assume it's in the right * space already). */ apply_cvt cvt x = cvt x, is_Image x || is_Colour x || is_image x = x; diff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2); /* Converter to LAB. */ lab_cvt = colour_transform_to Image_type.LAB; /* Converter to UCS ... plain UCS is Ch form, so we go LAB again after * to make sure we get a rectangular coord system. */ ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @ colour_transform_to Image_type.UCS; CIEdE76_item = class Menuaction (_ "CIE dE _76") (_ "calculate CIE dE 1976 for two objects") { action a b = map_binary (diff lab_cvt) a b; } CIEdE00_item = class Menuaction (_ "CIE dE _00") (_ "calculate CIE dE 2000 for two objects") { action a b = map_binary (colour_binary (_ "im_dE00_fromLab") im_dE00_fromLab) a b; } UCS_item = class Menuaction (_ "_CMC(l:l)") (_ "calculate CMC(l:l) for two objects") { action a b = map_binary (diff ucs_cvt) a b; } } Colour_adjust_item = class Menupullright (_ "_Adjust") (_ "alter colours in various ways") { Recombination_item = class Menuaction (_ "_Recombination") (_ "recombine colour with an editable matrix") { action x = class _result { _vislevel = 3; matrix = Matrix_rec (identity_matrix (bands x)) { // try to guess a sensible value for the size of the // matrix bands x = x.bands, is_Image x || is_Colour x = x.width, is_Matrix x = bands x.value?0, is_Group x = x.bands, has_member "bands" x = 3; } _result = map_unary (recomb matrix) x; } } Cast_item = class Menuaction (_ "_Cast") (_ "displace neutral axis in CIE Lab") { action x = class _result { _vislevel = 3; gr = Scale "Green-red" (-20) 20 0; by = Scale "Blue-yellow" (-20) 20 0; _result = map_unary adjust_cast x { adjust_cast in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LAB in; in'' = in' + Vector [0, gr.value, by.value]; } } } } HSB_item = class Menuaction (_ "_HSB") (_ "adjust hue-saturation-brightness in LCh") { action x = class _result { _vislevel = 3; h = Scale "Hue" 0 360 0; s = Scale "Saturation" 0.01 5 1; b = Scale "Brightness" 0.01 5 1; _result = map_unary adjust_hsb x { adjust_hsb in = colour_transform_to (get_type in) in'' { in' = colour_transform_to Image_type.LCH in; in'' = in' * Vector [b.value, s.value, 1] + Vector [0, 0, h.value]; } } } } } Colour_similar_item = class Menuaction (_ "_Similar Colour") (_ "find pixels with a similar colour") { action x = class _result { _vislevel = 3; target_colour = Colour_picker "Lab" [50, 0, 0]; t = Scale "dE threshold" 0 100 10; _result = map_unary match x { match in = abs_vec (in' - target) < t { target = colour_transform_to Image_type.LAB target_colour; in' = colour_transform_to Image_type.LAB in; } } } } #separator Colour_chart_to_matrix_item = class Menuaction (_ "_Measure Colour Chart") (_ "measure average pixel values for a colour chart image") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; _result = map_unary chart x { chart in = measure 0 0 in.width in.height (to_real pacross) (to_real pdown) in; } } } Colour_matrix_to_chart_item = class Menuaction (_ "Make Synth_etic Colour Chart") (_ "make a colour chart image from a matrix of measurements") { action x = class _result { _vislevel = 3; pacross = Expression (_ "Patches across chart") 6; pdown = Expression (_ "Patches down chart") 4; pwidth = Expression (_ "Patch width in pixels") 50; pheight = Expression (_ "Patch height in pixels") 50; bwidth = Expression (_ "Border between patches") 0; _result = map_unary build_chart x { build_chart in = Image (imagearray_assemble (to_real bwidth) (to_real bwidth) patch_table) { // patch numbers for row starts rowstart = map (multiply (to_real pacross)) [0 .. to_real pdown - 1]; // assemble patches ... each one a pixel value patches = map (take (to_real pacross)) (map (converse drop in.value) rowstart); // make an n-band constant image from eg. [1,2,3] // we don't know the format .. use sRGB (well, why not?) patch v = image_new (to_real pwidth) (to_real pheight) (len v) Image_format.FLOAT Image_coding.NOCODING Image_type.sRGB (Vector v) 0 0; // make an image for each patch patch_table = map (map patch) patches; } } } } Colour_plot_ab_scatter_item = class Menuaction (_ "_Plot ab Scatter") (_ "plot an ab scatter histogram") { action x = class _result { _vislevel = 3; bins = Expression (_ "Number of bins on each axis") 8; _result = map_unary plot_scatter x { plot_scatter in = Image (bg * (((90 / mx) * hist) ++ blk)) { lab = colour_transform_to Image_type.LAB in.value; ab = (unsigned char) ((lab?1 ++ lab?2) + 128); hist = hist_find_nD bins.expr ab; mx = max hist; bg = lab_slice bins.expr 1; blk = 1 + im_black (to_real bins) (to_real bins) 2; } } } } nip2-8.7.1/share/nip2/compat/7.26/_joe_utilities.def0000644000175000017500000005054513351443023016647 00000000000000/* ******Functions included in start/_NG_utilities.def:****** * * so_balance ref_meanmax im1 im2 mask blur gauss * * nonzero_mean im = no_out * * so_meanmax im = result * * so_calculate ref_meanmax im mask = result * * simple_frame frame im_w im_h ov cs ms bf option = result * * corner_frame frame im_w im_h ov cs ms bf = result * * build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result * * complex_frame frame im_w im_h ov cs es ms bf option= result * * complex_edge ra rb t bl d = rc * * frame_lr_min r_l r_r target bw = result * * frame_tb_min r_t r_b target bw = result * * frame_position_image im ref os colour= result * * merge_array bw arr = result * * merge_to_scale im target blend dir = result * * select_ellipse line width = mask * * select_tetragon p1 p2 p3 p4 = mask * * select_polygon pt_list = mask * * perspective_transform to from = trans'' * * sort_pts_clockwise l = l'' * */ /* Called from: * _NG_Extra.def Clone_area_item */ so_balance ref_meanmax im1 im2 mask gauss = result { //ref_meanmax = so_meanmax im1; so_values = so_calculate ref_meanmax im2 mask; im2_cor_a = clip2fmt im2.format im2'', has_member "format" im2 = im2'' {im2'' = im2 * (so_values?0) + (so_values?1);} // Option to convert replacement image to scaled gaussian noise im2_cor = im2_cor_a, gauss == false = clip2fmt im2_cor_a.format gauss_im {gauss_im = im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0 (deviation im2_cor_a);} result = im_blend (get_image mask) (get_image im2_cor) (get_image im1); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the mean of the non zero pixels. * * Called from: * _NG_utilities so_meanmax */ nonzero_mean im = no_out { zero_im = (im == 0); zero_mean = mean zero_im; no_mean = mean im; no_out = no_mean/(1 - (zero_mean/255)); }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the max and nonzero mean of an image * * Called from: * _NG_utilities so_balance * _NG_utilities so_calculate * _NG_Extra.def Clone_area_item * _NG_Extra.def Balance_item.Balance_find_item */ so_meanmax im = result { mean_of_im = nonzero_mean im; adjusted_im = im - mean_of_im; max_of_im = max adjusted_im; result = [mean_of_im, max_of_im]; }; //////////////////////////////////////////////////////////////////////////////// /* Calculates the scale and offset required to match a reference mean and max * * Called from: * _NG_utilities so_balance * _NG_Extra.def Balance_item.Balance_find_item */ so_calculate ref_meanmax im mask = result { im' = if mask then im else 0; im_values = so_meanmax im'; mean_of_ref = ref_meanmax?0; mean_of_im = im_values?0; max_of_ref = ref_meanmax?1; max_of_im = im_values?1; scale = (max_of_ref)/(max_of_im); offset = mean_of_ref - (mean_of_im * scale); result = [ scale, offset ]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a simple frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Simple_frame_item */ simple_frame frame im_w im_h ov cs ms bf option = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); ms'' = (1 - cs); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' ms'' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame ms'' ms' cs ms; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Copies and extends a simple frame corner to produce a complete frame to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item */ corner_frame frame im_w im_h ov cs ms bf = result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); //Regions r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl; r_bl = fliptb r_tl; r_br = fliplr r_bl; r_mt = Region_relative frame ms' 0 ms cs; r_mb = fliptb r_mt; r_ml = Region_relative frame 0 ms' cs ms;; r_mr = fliplr r_ml; result = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf; }; //////////////////////////////////////////////////////////////////////////////// /* Completes the frame building process for simple_frame and corner_frame. * * _NG_utilities simple_frame * _NG_utilities corner_frame */ build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result { //Find pixel thickness of frames section s_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1); s_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); blend = bf * r_tl.width; cw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width) = w_target; ch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height) = h_target; //Use regions to produce sections top = merge_to_scale r_mt cw_target blend 0; bottom = merge_to_scale r_mb cw_target blend 0; left = merge_to_scale r_ml ch_target blend 1; right = merge_to_scale r_mr ch_target blend 1; middle = Image (image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0); //Build sections into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Extends or shortens the central sections of a frame, preserving any central details on each * edge, to fit round a given image. * * Called from: * _NG_Extra.def Frame_item.Complex_frame_item */ complex_frame frame im_w im_h ov cs es ms bf option= result { cs' = (1 - cs); ms' = (0.5 - (ms/2)); es' = (0.25 - (es/2)); r_tl = Region_relative frame 0 0 cs cs; r_tr = fliplr r_tl, option == true = Region_relative frame cs' 0 cs cs; r_bl = Region_relative frame 0 cs' cs cs; r_br = fliplr r_bl, option == true = Region_relative frame cs' cs' cs cs; r_mt = Region_relative frame ms' 0 ms cs; r_mb = Region_relative frame ms' cs' ms cs; r_ml = Region_relative frame 0 ms' cs ms; r_mr = fliplr r_ml, option == true = Region_relative frame cs' ms' cs ms; r_et = Region_relative frame es' 0 es cs; r_eb = Region_relative frame es' cs' es cs; r_el = Region_relative frame 0 es' cs es; r_er = fliplr r_el, option == true = Region_relative frame cs' es' cs es; //Find pixel thickness of frames section s_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1); s_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0); w_target = im_w + (2 * (s_width - ov)); h_target = im_h + (2 * (s_height - ov)); min_size = foldr1 min_pair [r_tl.width, r_tl.height, r_mt.width, r_mt.height, r_et.width, r_et.height]; blend = bf * min_size; cw_target = w_target - (2 * r_tl.width) + (2 * blend); ch_target = h_target - (2 * r_tl.height) + (2 * blend); top = complex_edge r_mt r_et cw_target blend 0; bottom = complex_edge r_mb r_eb cw_target blend 0; left = complex_edge r_ml r_el ch_target blend 1; right = complex_edge r_mr r_er ch_target blend 1; middle = Image (image_new top.width left.height left.bands left.format left.coding left.type 0 0 0); //Build regions into full frame. row_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_tl, top, r_tr]]; row_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[left, middle, right]]; row_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2)) = merge_array blend [[r_bl, bottom, r_br]]; result = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2)) = merge_array blend [[row_1], [row_2], [row_3]]; }; //////////////////////////////////////////////////////////////////////////////// /* Function called by complex frame, used to produce section * * Called from: * _NG_utilities.def complex_frame */ complex_edge ra rb t bl d = rc { e1 = ceil (ra.width - t)/2, d == 0 = 0; e2 = 0, d == 0 = ceil (ra.height - t)/2; e3 = t, d == 0 = ra.width; e4 = ra.height, d == 0 = t; check = ra.width, d == 0; = ra.height; rai = get_image ra; t2 = (t - ra.width + (2 * bl))/2, d == 0 = (t - ra.height + (2 * bl))/2; rc = ra , t <= 0 = Image (im_extract_area rai e1 e2 e3 e4), t <= check = merge_array bl [[rb',ra,rb']], d == 0 = merge_array bl [[rb'],[ra],[rb']] {rb' = merge_to_scale rb t2 bl d;} }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images left/right to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_lr_min r_l r_r target bw = result { //Calculating the new widh required for each image. no = (target/2 + bw); n_w = no, (r_l.width > no) = r_l.width; //Removing excess from what will be the middle of the final image. n_l = im_extract_area r_l.value 0 0 n_w r_l.height; n_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height; //Merge the two image together with a bw*2 pixel overlap. result = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw); }; ////////////////////////////////////////////////////////////////////////////// /* Blends two images top/bottom to produce an image a specific width. * * _NG_utilities build_frame * _NG_utilities complex_frame */ frame_tb_min r_t r_b target bw = result { //Calculating the new height required for each image. no = (target/2 + bw); n_h = no, (r_t.height > no) = r_t.height; //Removing excess from what will be the middle of the final image. n_t = im_extract_area r_t.value 0 0 r_t.width n_h; n_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h; //Merge the two image together with a 50 pixel overlap. result = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw); }; ////////////////////////////////////////////////////////////////////////////// /* Resixe canvas of an image to accomodate a frame and possible mount * * Called from: * _NG_Extra.def Frame_item.Frame_corner_item * _NG_Extra.def Frame_item.Simple_frame_item * _NG_Extra.def Frame_item.Complex_frame_item */ frame_position_image im ref os colour= result { background = image_new ref.width ref.height im.bands im.format im.coding im.type colour 0 0; result = insert_noexpand xp yp im background { xp = (ref.width - im.width)/2; yp = (ref.height - im.height - os)/2; } }; ////////////////////////////////////////////////////////////////////////////// /* Merges an array of images together according to blend width bw * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_frame * _NG_Utilites.def complex_edge */ merge_array bw arr = result { merge_lr bw im1 im2 = im3 { bw' = get_header "Xsize" (get_image im1); bw'' = -(bw' - bw); im3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw; } merge_tb bw im1 im2 = im3 { bw' = get_header "Ysize" (get_image im1); bw'' = -(bw' - bw); im3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw; } im_out = (image_set_origin 0 0 @ foldl1 (merge_tb bw) @ map (foldl1 (merge_lr bw))) arr; result = Image im_out; }; ////////////////////////////////////////////////////////////////////////////// /* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target * * Called from: * _NG_Utilites.def build_frame * _NG_Utilites.def complex_edge */ merge_to_scale im target blend dir = result { blend' = floor blend; //allow fir lr or tb process var_a = im.width, dir == 0 = im.height; var_w = im.width, dir == 1 = target, target > blend' = blend'; var_h = im.height, dir == 0 = target, target > blend' = blend'; //total numner of copies of im requires, taking overlap into account. no_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2)); process im no = result { pr_a = get_header "Xsize" (get_image im), dir == 0 = get_header "Ysize" (get_image im); pr_b = -(pr_a - blend' + 1); im' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0 = im_tbmerge (get_image im) (get_image im) 0 pr_b blend'; no' = no - 1; result = im', no' < 1 = process im' no'; } im_tmp = im.value, var_a > target = process im no_loops; result = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h); }; ////////////////////////////////////////////////////////////////////////////// /* Selects an elispe based on a line and a width * * Called from: * _NG_Extra.def Select_item.Elipse */ select_ellipse line width = mask { im = Image (get_image line); //Make a 2 band image whose value equals its coordinates. im_coor = Image (make_xy im.width im.height); //Adjust the values to center tham on (line.left, line.top) im_cent = im_coor - Vector [line.left,line.top]; w = line.width; h = line.height; angle = 270, w == 0 && h < 0 = 90, w == 0 && h >= 0 = 360 + atan (h/w), w > 0 && h < 0 = atan (h/w), w > 0 && h >= 0 = 180 + atan (h/w); a = ( (h ** 2) + (w ** 2) )**0.5; b = a * width; x' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1); y' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0); mask = ( (b**2) * (x'**2) ) + ( (a**2) * (y'**2) ) <= (a * b)**2; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Tetragon * _NG_Extra.def Perspective_item */ select_tetragon p1 p2 p3 p4 = mask { //Put points in clockwise order starting at the top left. pt_list = sort_pts_clockwise [p1, p2, p3, p4]; pair_list = [ [ pt_list?0, pt_list?1 ], [ pt_list?1, pt_list?2 ], [ pt_list?2, pt_list?3 ], [ pt_list?3, pt_list?0 ] ]; //Make xy image the same size as p1.image; im_xy = Image (make_xy p1.image.width p1.image.height); white = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0); mask = foldl process white pair_list; /* Treat each pair of point as a vector going from p1 to p2, * then select all to right of line. This is done for each pair, * the results are all combined to select the area defined by * the four points. */ process im_in pair = im_out { x = (pair?0).left; y = (pair?0).top; x'= (pair?1).left; y'= (pair?1).top; w = x' - x; h = y' - y; m = 0, x == x' = (y-y')/(x-x'); c = 0, x == x' = ((y*x') - (y'*x))/(x' - x); mask= im_xy?1 - (im_xy?0 * m) >= c, w > 0 = im_xy?1 - (im_xy?0 * m) <= c, w < 0 = im_xy?0 <= x, w == 0 && h > 0 = im_xy?0 >= x; im_out = im_in & mask; } }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Select_item.Polygon */ select_polygon pt_list = mask { group_check = is_Group pt_list; pt_l = pt_list.value, group_check = pt_list; im = Image (get_image (pt_l?0)); im_xy = Image (make_xy im.width im.height); black = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0); x = im_xy?0; y = im_xy?1; pt_l' = grp_trip pt_l; mask = foldl process black pt_l'; /*Takes a group adds the first two the end and then creates a lists of *lists [[a, b, c], [b, c, d] .... [x, a, b]] */ grp_trip l = l'' { px = take 2 l; l' = join l px; start = [(take 3 l')]; rest = drop 3 l'; process a b = c { x = (last a)?1; x'= (last a)?2; x'' = [[x, x', b]]; c = join a x''; } l'' = foldl process start rest; }; process im_in triplet = im_out { p1 = triplet?0; p2 = triplet?1; p3 = triplet?2; //check for change in x direction between p1-p2 and p2 -p3 dir_1 = sign (p2.left - p1.left); dir_2 = sign (p3.left - p2.left); dir = dir_1 + dir_2; //define min x limit. min_x = p1.left, p1.left < p2.left = p2.left + 1, dir != 0 = p2.left; //define max x limit. max_x = p1.left, p1.left > p2.left = p2.left - 1, dir != 0 = p2.left; //equation of line defined by p1 and p2 m = line_m p1 p2; c = line_c p1 p2; //Every thing below the line im_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x)); im_out = im_in ^ im_test; } line_c p1 p2 = c {m = line_m p1 p2; c = p1.top - (m * p1.left);}; line_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left = 0; }; ////////////////////////////////////////////////////////////////////////////// /* Selects a tetragon based on four points. * * Called from: * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ perspective_transform to from = trans'' { /* * Tramsformation matrix is calculated on the bases of the following functions: * x' = c0x + c1y + c2xy + c3 * y' = c4x + c5y + c6xy + c7 * * The functions used in vips im_transform works based on the functions: * x = x' + b0 + b2x' + b4y' + b6x'y' * y = y' + b1 + b3x' + b5y' + b7x'y' * * and is applied in the form of the matrix: * * [[b0, b1], * [b2, b3], * [b4, b5], * [b6, b7]] * * Therefore our required calculated matrix will be * * [[ c3 , c7], * [(c0 - 1) , c4], * [ c1 , (c5 - 1)], * [ c2 , c6]] * * to = [x1, y1, x2, y2, x3, y3, x4, y4] * from = [x1', y1', x2', y2', x3', y3', x4', y4'] * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]] * */ to' = Matrix [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1], [to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1], [to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1], [to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0], [0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]]; from' = Matrix (transpose [from]); to'' = to' ** (-1); trans = to'' * from'; trans' = trans.value; trans''= Matrix [[(trans'?3)?0, (trans'?7)?0 ], [((trans'?0)?0 - 1), (trans'?4)?0 ], [(trans'?1)?0, ((trans'?5)?0 - 1)], [(trans'?2)?0, (trans'?6)?0 ]]; }; ////////////////////////////////////////////////////////////////////////////// /* Sort a list of points into clockwise order. * * Called from: * _NG_utilities.def select_tetragon * _NG_Extra.def Perspective_match_item * _NG_Extra.def Perspective_item */ sort_pts_clockwise l = l'' { // sort functions: f_top a b = a.top < b.top; f_left a b = a.left < b.left; f_right a b = a.left > b.left; l' = sortc f_top l; l'_a = take 2 l'; l'_b = drop 2 l'; l''_a = sortc f_left l'_a; l''_b = sortc f_right l'_b; l'' = join l''_a l''_b; }; Mount_options _ctype _ppcm = class { _vislevel = 3; apply = Toggle "Apply mount options" false; ls = Expression "Lower mount section bigger by (cm)" 0; mount_colour = Colour _ctype [0, 0, 0]; _los = ls.expr * _ppcm; }; Frame_variables comp = class { _vislevel = 3; scale_factor = Expression "scale the size of the frame by" 1; /* These sliders define the fraction of the frames width or height is extracted * to produce each of the particular regions. */ corner_section = Scale "Corner section" 0.1 1 0.5; edge_section = Scale "Edge section" 0.1 1 0.2, comp > 0 = "Only required for complex frames"; middle_section = Scale "Middle section" 0.1 1 0.2; blend_fraction = Scale "Blend fraction" 0.1 0.9 0.1; option = Toggle "Use mirror of left-side to make right" true; }; nip2-8.7.1/share/nip2/compat/7.26/_Object.def0000644000175000017500000002600513351443023015177 00000000000000/* Lots of little arg checks. Global for convenience. */ check_any = [(const true), _ "any"]; check_bool = [is_bool, _ "boolean"]; check_real = [is_real, _ "real"]; check_ureal = [is_ureal, _ "unsigned real"]; check_preal = [is_preal, _ "positive real"]; check_list = [is_list, _ "list"]; check_real_list = [is_real_list, _ "list of real"]; check_string = [is_string, _ "string"]; check_string_list = [is_string_list, _ "list of string"]; check_int = [is_int, _ "integer"]; check_uint = [is_uint, _ "unsigned integer"]; check_pint = [is_pint, _ "positive integer"]; check_matrix = [is_matrix, _ "rectangular array of real"]; check_matrix_display = [Matrix_display.is_display, _ "0|1|2|3"]; check_image = [is_image, _ "image"]; check_xy_list = [is_xy_list, _ "list of form [[1, 2], [3, 4], [5, 6], ...]"]; check_instance name = [is_instanceof name, name]; check_Image = check_instance "Image"; check_Matrix = [is_Matrix, _ "Matrix"]; check_colour_space = [is_colour_space, join_sep "|" Image_type.colour_spaces.names]; check_rectangular = [is_rectangular, _ "rectangular [[*]]"]; check_Guide = [is_Guide, _ "HGuide|VGuide"]; check_Colour = check_instance (_ "Colour"); check_Mark = check_instance (_ "Mark"); /* Check a set of args to a class. Two members to look at: _check_args and * _check_all. * * - each line in _check_args is [arg, "arg name", [test_fn, "arg type"]] * same number of lines as there are args * * stuff like "arg 2 must be real" * * - each line in _check_all is [test, "description"] * any number of lines * * stuff like "to must be greater than from" * * generate an error dialog with a helpful message on failure. * * Have as a separate function to try to keep the size of _Object down. */ check_args x = error message, badargs != [] || badalls != [] = x { argcheck = x._check_args; allcheck = x._check_all; // indent string indent = " "; // test for a condition in a check line fails test_fail x = ! x?0; // set of failed argcheck indexes badargs = map (extract 1) (filter test_fail (zip2 (map testarg argcheck) [0..])) { testarg x = x?2?0 x?0; } // set of failed allcheck indexes badalls = map (extract 1) (filter test_fail (zip2 (map hd allcheck) [0..])); // the error message message = _ "bad properties for " ++ "\"" ++ x.name ++ "\"\n" ++ argmsg ++ allmsg ++ "\n" ++ _ "where" ++ "\n" ++ arg_types ++ extra; // make the failed argcheck messages ... eg. ""value" should be // real, you passed " etc. argmsg = concat (map fmt badargs) { fmt n = indent ++ "\"" ++ argcheck?n?1 ++ "\"" ++ _ " should be of type " ++ argcheck?n?2?1 ++ ", " ++ _ "you passed" ++ ":\n" ++ indent ++ indent ++ print argcheck?n?0 ++ "\n"; } // make the failed allcheck messages ... eg "condition failed: // x < y" ... don't make a message if any typechecks have // failed, as we'll probably error horribly allmsg = [], badargs != [] = concat (map fmt badalls) ++ _ "you passed" ++ "\n" ++ concat (map fmt_arg argcheck) { fmt n = _ "condition failed" ++ ": " ++ allcheck?n?1 ++ "\n"; fmt_arg l = indent ++ l?1 ++ " = " ++ print l?0 ++ "\n"; } // make arg type notes arg_types = join_sep "\n" (map fmt argcheck) { fmt l = indent ++ l?1 ++ " is of type " ++ l?2?1; } // extra bit at the bottom, if we have any conditions extra = [], allcheck == [] = "\n" ++ _ "and" ++ "\n" ++ all_desc; // make a list of all the allcheck descriptions, with a few // spaces in front all_desc_list = map (join indent @ extract 1) allcheck; // join em up to make a set of condition notes all_desc = join_sep "\n" all_desc_list; } /* Operator overloading stuff. */ Operator_type = class { ARITHMETIC = 1; // eg. add RELATIONAL = 2; // eg. less COMPOUND = 3; // eg. max/mean/etc. COMPOUND_REWRAP = 4; // eg. transpose } Operator op_name fn type symmetric = class { } /* Form the converse of an Operator. */ oo_converse op = Operator (converse_name op.op_name) (converse op.fn) op.type op.symmetric { converse_name x = init x, last x == last "'" = x ++ "'"; } /* Given an operator name, look up the definition. */ oo_binary_lookup op_name = matches?0, matches != [] = error (_ "unknown binary operator" ++ ": " ++ print op_name) { operator_table = [ Operator "add" add Operator_type.ARITHMETIC true, Operator "subtract" subtract Operator_type.ARITHMETIC false, Operator "remainder" remainder Operator_type.ARITHMETIC false, Operator "power" power Operator_type.ARITHMETIC false, Operator "subscript" subscript Operator_type.ARITHMETIC false, Operator "left_shift" left_shift Operator_type.ARITHMETIC false, Operator "right_shift" right_shift Operator_type.ARITHMETIC false, Operator "divide" divide Operator_type.ARITHMETIC false, Operator "join" join Operator_type.ARITHMETIC false, Operator "multiply" multiply Operator_type.ARITHMETIC true, Operator "logical_and" logical_and Operator_type.ARITHMETIC true, Operator "logical_or" logical_or Operator_type.ARITHMETIC true, Operator "bitwise_and" bitwise_and Operator_type.ARITHMETIC true, Operator "bitwise_or" bitwise_or Operator_type.ARITHMETIC true, Operator "eor" eor Operator_type.ARITHMETIC true, Operator "comma" comma Operator_type.ARITHMETIC false, Operator "if_then_else" if_then_else Operator_type.ARITHMETIC false, Operator "equal" equal Operator_type.RELATIONAL true, Operator "not_equal" not_equal Operator_type.RELATIONAL true, Operator "less" less Operator_type.RELATIONAL false, Operator "less_equal" less_equal Operator_type.RELATIONAL false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Given an operator name, look up a function that implements that * operator. */ oo_unary_lookup op_name = matches?0, matches != [] = error (_ "unknown unary operator" ++ ": " ++ print op_name) { operator_table = [ /* Operators. */ Operator "cast_signed_char" cast_signed_char Operator_type.ARITHMETIC false, Operator "cast_unsigned_char" cast_unsigned_char Operator_type.ARITHMETIC false, Operator "cast_signed_short" cast_signed_short Operator_type.ARITHMETIC false, Operator "cast_unsigned_short" cast_unsigned_short Operator_type.ARITHMETIC false, Operator "cast_signed_int" cast_signed_int Operator_type.ARITHMETIC false, Operator "cast_unsigned_int" cast_unsigned_int Operator_type.ARITHMETIC false, Operator "cast_float" cast_float Operator_type.ARITHMETIC false, Operator "cast_double" cast_double Operator_type.ARITHMETIC false, Operator "cast_complex" cast_complex Operator_type.ARITHMETIC false, Operator "cast_double_complex" cast_double_complex Operator_type.ARITHMETIC false, Operator "unary_minus" unary_minus Operator_type.ARITHMETIC false, Operator "negate" negate Operator_type.RELATIONAL false, Operator "complement" complement Operator_type.ARITHMETIC false, Operator "unary_plus" unary_plus Operator_type.ARITHMETIC false, /* Built in projections. */ Operator "re" re Operator_type.ARITHMETIC false, Operator "im" im Operator_type.ARITHMETIC false, Operator "hd" hd Operator_type.ARITHMETIC false, Operator "tl" tl Operator_type.ARITHMETIC false, /* Maths builtins. */ Operator "sin" sin Operator_type.ARITHMETIC false, Operator "cos" cos Operator_type.ARITHMETIC false, Operator "tan" tan Operator_type.ARITHMETIC false, Operator "asin" asin Operator_type.ARITHMETIC false, Operator "acos" acos Operator_type.ARITHMETIC false, Operator "atan" atan Operator_type.ARITHMETIC false, Operator "log" log Operator_type.ARITHMETIC false, Operator "log10" log10 Operator_type.ARITHMETIC false, Operator "exp" exp Operator_type.ARITHMETIC false, Operator "exp10" exp10 Operator_type.ARITHMETIC false, Operator "ceil" ceil Operator_type.ARITHMETIC false, Operator "floor" floor Operator_type.ARITHMETIC false ]; matches = filter test_name operator_table; test_name x = x.op_name == op_name; } /* Find the matching methods in a method table. */ oo_method_lookup table = map (extract 0) (filter (extract 1) table); /* A binary op: a is a class, b may be a class ... eg. "add" a b two obvious ways to find a method: - a.oo_binary_search "add" (+) b - b.oo_binary_search "add'" (converse (+)) a, is_class b if these fail but op is a symmetric operator (eg. a + b == b + a), we can also try reversing the args - a.oo_binary_search "add'" (converse (+)) b - b.oo_binary_search "add" (+) a, is_class b if those fail as well, but this is ==, do pointer equals as a fallback */ oo_binary_function op a b = matches1?0, matches1 != [] = matches2?0, is_class b && matches2 != [] = matches3?0, op.symmetric && matches3 != [] = matches4?0, op.symmetric && is_class b && matches4 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (a.oo_binary_table op b); matches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b); matches4 = oo_method_lookup (b.oo_binary_table op a); } /* A binary op: a is not a class, b is a class ... eg. "subtract" a b only one way to find a method: - b.oo_binary_search "subtract'" (converse (-)) a if this fails but op is a symmetric operator (eg. a + b == b + a), we can try reversing the args - b.oo_binary_search "add" (+) a, is_class b if that fails as well, but this is ==, do pointer equals as a fallback */ oo_binary'_function op a b = matches1?0, matches1 != [] = matches2?0, op.symmetric && matches2 != [] = pointer_equal a b, op.op_name == "equal" || op.op_name == "equal'" = not_pointer_equal a b, op.op_name == "not_equal" || op.op_name == "not_equal'" = error (_ "No method found for binary operator." ++ "\n" ++ _ "left" ++ " = " ++ print a ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "right" ++ " = " ++ print b) { matches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a); matches2 = oo_method_lookup (b.oo_binary_table op a); } oo_unary_function op x = matches?0, matches != [] = error (_ "No method found for unary operator." ++ "\n" ++ _ "operator" ++ " = " ++ op.op_name ++ "\n" ++ _ "argument" ++ " = " ++ print x) { matches = oo_method_lookup (x.oo_unary_table op); } /* Base class for nip's built-in classes ... base check function, base * operator overload functions. */ _Object = class { check = check_args this; // these should always be defined _check_args = []; _check_all = []; /* Operator overloading stuff. */ oo_binary op x = oo_binary_function (oo_binary_lookup op) this x; oo_binary' op x = oo_binary'_function (oo_binary_lookup op) x this; oo_unary op = oo_unary_function (oo_unary_lookup op) this; oo_binary_table op x = []; oo_unary_table op = []; } nip2-8.7.1/share/nip2/compat/7.26/Object.def0000644000175000017500000000222013351443023015031 00000000000000Object_duplicate_item = class Menuaction "_Duplicate" "take a copy of an object" { action x = map_unary copy x; } #separator Object_list_to_group_item = class Menuaction "_List to Group" "turn a list of objects into a group" { action x = to_group x; } Object_group_to_list_item = class Menuaction "_Group to List" "turn a group into a list of objects" { action x = to_list x; } #separator Object_break_item = class Menuaction "_Break Up Object" "break an object into a list of components" { action x = map_unary break x { break x = bandsplit x, is_Image x = map Vector x.value, is_Matrix x = x.value, is_Vector x || is_Real x = error "Breakup: not Image/Matrix/Vector/Real"; } } Object_assemble_item = class Menuaction "_Assemble Objects" "assemble a list (or group) of objects into a single object" { action x = map_unary ass x { ass x = [], x == [] = Vector x, is_real_list x = Matrix x, is_matrix x = bandjoin x, is_listof is_Image x = Vector (map get_value x), is_listof is_Real x = Matrix (map get_value x), is_listof is_Vector x = error "Assemble: not list of Image/Vector/Real/image/real"; } } nip2-8.7.1/share/nip2/compat/7.26/Math.def0000644000175000017500000003157713351443023014535 00000000000000Math_arithmetic_item = class Menupullright "_Arithmetic" "basic arithmetic for objects" { Add_item = class Menuaction "_Add" "add a and b" { action a b = map_binary add a b; } Subtract_item = class Menuaction "_Subtract" "subtract b from a" { action a b = map_binary subtract a b; } Multiply_item = class Menuaction "_Multiply" "multiply a by b" { action a b = map_binary multiply a b; } Divide_item = class Menuaction "_Divide" "divide a by b" { action a b = map_binary divide a b; } Remainder_item = class Menuaction "_Remainder" "remainder after integer division of a by b" { action a b = map_binary remainder a b; } sep1 = Menuseparator; Absolute_value_item = class Menuaction "A_bsolute Value" "absolute value of x" { action x = map_unary abs x; } Absolute_value_vector_item = class Menuaction "Absolute Value _Vector" "like Absolute Value, but treat pixels as vectors" { action x = map_unary abs_vec x; } Sign_item = class Menuaction "S_ign" "unit vector" { action x = map_unary sign x; } Negate_item = class Menuaction "_Negate" "multiply by -1" { action x = map_unary unary_minus x; } } Math_trig_item = class Menupullright "_Trigonometry" "trigonometry operations (all in degrees)" { Sin_item = class Menuaction "_Sine" "calculate sine x" { action x = map_unary sin x; } Cos_item = class Menuaction "_Cosine" "calculate cosine x" { action x = map_unary cos x; } Tan_item = class Menuaction "_Tangent" "calculate tangent x" { action x = map_unary tan x; } sep1 = Menuseparator; Asin_item = class Menuaction "Arc S_ine" "calculate arc sine x" { action x = map_unary asin x; } Acos_item = class Menuaction "Arc C_osine" "calculate arc cosine x" { action x = map_unary acos x; } Atan_item = class Menuaction "Arc T_angent" "calculate arc tangent x" { action x = map_unary atan x; } sep2 = Menuseparator; Rad_item = class Menuaction "_Degrees to Radians" "convert degrees to radians" { action x = map_unary rad x; } Deg_item = class Menuaction "_Radians to Degrees" "convert radians to degrees" { action x = map_unary deg x; } sep3 = Menuseparator; Angle_range_item = class Menuaction "Angle i_n Range" "is angle within t degrees of r, mod 360" { action t r angle = clock (max - angle) < 2*r { max = clock (t + r); clock a = a + 360, a < 0; = a - 360, a >= 360; = a; } } } Math_log_item = class Menupullright "_Log" "logarithms and anti-logs" { Exponential_item = class Menuaction "_Exponential" "calculate e ** x" { action x = map_unary (power e) x; } Log_natural_item = class Menuaction "Natural _Log" "log base e of x" { action x = map_unary log x; } sep1 = Menuseparator; Exponential10_item = class Menuaction "E_xponential base 10" "calculate 10 ** x" { action x = map_unary (power 10) x; } Log10_item = class Menuaction "L_og Base 10" "log base 10 of x" { action x = map_unary log10 x; } sep2 = Menuseparator; Raise_to_power_item = class Menuaction "_Raise to Power" "calculate x ** y" { action x y = map_binary power x y; } } Math_complex_item = class Menupullright "_Complex" "operations on complex numbers and images" { Complex_extract = class Menupullright "_Extract" "extract fields from complex" { Real_item = class Menuaction "_Real" "extract real part of complex" { action in = map_unary re in; } Imaginary_item = class Menuaction "_Imaginary" "extract imaginary part of complex" { action in = map_unary im in; } } Complex_build_item = class Menuaction "_Build" "join a and b to make a complex" { action a b = map_binary comma a b; } sep1 = Menuseparator; Polar_item = class Menuaction "_Polar" "convert real and imag to amplitude and phase" { action a = map_unary polar a; } Rectangular_item = class Menuaction "_Rectagular" ("convert (amplitude, phase) image to rectangular " ++ "coordinates") { action x = map_unary rectangular x; } sep2 = Menuseparator; Conjugate_item = class Menuaction "_Conjugate" "invert imaginary part" { action x = map_unary conj x; } } Math_boolean_item = class Menupullright "_Boolean" "bitwise boolean operations for integer objects" { And_item = class Menuaction "_And" "bitwise and of a and b" { action a b = map_binary bitwise_and a b; } Or_item = class Menuaction "_Or" "bitwise or of a and b" { action a b = map_binary bitwise_or a b; } Eor_item = class Menuaction "E_xclusive Or" "bitwise exclusive or of a and b" { action a b = map_binary eor a b; } Not_item = class Menuaction "_Not" "invert a" { action a = map_unary not a; } sep1 = Menuseparator; Right_shift_item = class Menuaction "Shift _Right" "shift a right by b bits" { action a b = map_binary right_shift a b; } Left_shift_item = class Menuaction "Shift _Left" "shift a left by b bits" { action a b = map_binary left_shift a b; } sep2 = Menuseparator; If_then_else_item = class Menuaction "_If Then Else" "b where a is non-zero, c elsewhere" { action a b c = map_trinary ite a b c { // can't use if_then_else, we need a true trinary ite a b c = if a then b else c; } } Band_or_item = class Menuaction "Band O_r" "or the bands of an image together" { action im = map_unary (foldr1 bitwise_or @ bandsplit) im; } Band_and_item = class Menuaction "Band A_nd" "and the bands of an image together" { action im = map_unary (foldr1 bitwise_and @ bandsplit) im; } } Math_relational_item = class Menupullright "R_elational" "comparison operations" { Equal_item = class Menuaction "_Equal to" "test a equal to b" { action a b = map_binary equal a b; } Not_equal_item = class Menuaction "_Not Equal to" "test a not equal to b" { action a b = map_binary not_equal a b; } sep1 = Menuseparator; More_item = class Menuaction "_More Than" "test a strictly greater than b" { action a b = map_binary more a b; } Less_item = class Menuaction "_Less Than" "test a strictly less than b" { action a b = map_binary less a b; } sep2 = Menuseparator; More_equal_item = class Menuaction "M_ore Than or Equal to" "test a greater than or equal to b" { action a b = map_binary more_equal a b; } Less_equal_item = class Menuaction "L_ess Than or Equal to" "test a less than or equal to b" { action a b = map_binary less_equal a b; } } Math_list_item = class Menupullright "L_ist" "operations on lists" { Head_item = class Menuaction "_Head" "first element in list" { action x = map_unary hd x; } Tail_item = class Menuaction "_Tail" "list without the first element" { action x = map_unary tl x; } Last_item = class Menuaction "_Last" "last element in list" { action x = map_unary last x; } Init_item = class Menuaction "_Init" "list without the last element" { action x = map_unary init x; } sep1 = Menuseparator; Reverse_item = class Menuaction "_Reverse" "reverse order of elements in list" { action x = map_unary reverse x; } Sort_item = class Menuaction "_Sort" "sort list into ascending order" { action x = map_unary sort x; } Make_set_item = class Menuaction "_Make Set" "remove duplicates from list" { action x = map_unary mkset equal x; } Transpose_list_item = class Menuaction "Tr_anspose" "exchange rows and columns in a list of lists" { action x = map_unary transpose x; } Concat_item = class Menuaction "_Concat" "flatten a list of lists into a single list" { action l = map_unary concat l; } sep2 = Menuseparator; Length_item = class Menuaction "L_ength" "find the length of list" { action x = map_unary len x; } Subscript_item = class Menuaction "S_ubscript" "return element n from list (index from zero)" { action n x = map_binary subscript n x; } Take_item = class Menuaction "_Take" "take the first n elements of list x" { action n x = map_binary take n x; } Drop_item = class Menuaction "_Drop" "drop the first n elements of list x" { action n x = map_binary drop n x; } sep3 = Menuseparator; Join_item = class Menuaction "_Join" "join two lists end to end" { action a b = map_binary join a b; } Difference_item = class Menuaction "_Difference" "difference of two lists" { action a b = map_binary difference a b; } Cons_item = class Menuaction "C_ons" "put element a on the front of list x" { action a x = map_binary cons a x; } Zip_item = class Menuaction "_Zip" "join two lists, pairwise" { action a b = map_binary zip2 a b; } } Math_round_item = class Menupullright "_Round" "various rounding operations" { /* smallest integral value not less than x */ Ceil_item = class Menuaction "_Ceil" "smallest integral value not less than x" { action x = map_unary ceil x; } Floor_item = class Menuaction "_Floor" "largest integral value not greater than x" { action x = map_unary floor x; } Rint_item = class Menuaction "_Round to Nearest" "round to nearest integer" { action x = map_unary rint x; } } Math_fourier_item = class Menupullright "_Fourier" "Fourier transform" { Forward_item = class Menuaction "_Forward" "fourier transform of image" { action a = map_unary (rotquad @ fwfft) a; } Reverse_item = class Menuaction "_Reverse" "inverse fourier transform of image" { action a = map_unary (invfft @ rotquad) a; } Rotate_quadrants_item = class Menuaction "Rotate _Quadrants" "rotate quadrants" { action a = map_unary rotquad a; } } Math_stats_item = class Menupullright "_Statistics" "measure various statistics of objects" { Value_item = class Menuaction "_Value" "value of point in object" { action a = class _result { _vislevel = 3; position = Expression "Coordinate" (0, 0); _result = map_binary point position.expr a; } } Mean_item = class Menuaction "_Mean" "arithmetic mean value" { action a = map_unary mean a; } Gmean_item = class Menuaction "_Geometric Mean" "geometric mean value" { action a = map_unary meang a; } Zmean_item = class Menuaction "_Zero-excluding Mean" "mean value of non-zero elements" { action a = map_unary meanze a; } Deviation_item = class Menuaction "_Standard Deviation" "standard deviation of object" { action a = map_unary deviation a; } Zdeviation_item = class Menuaction "Z_ero-excluding Standard Deviation" "standard deviation of non-zero elements" { action a = map_unary deviationze a; } Stats_item = class Menuaction "Ma_ny Stats" "calculate many stats in a single pass" { action a = map_unary stats a; } sep1 = Menuseparator; Max_item = class Menuaction "M_aximum" "maximum of object" { action a = map_unary max a; } Min_item = class Menuaction "M_inimum" "minimum of object" { action a = map_unary min a; } Maxpos_item = class Menuaction "_Position of Maximum" "position of maximum in object" { action a = map_unary maxpos a; } Minpos_item = class Menuaction "P_osition of Minimum" "position of minimum in object" { action a = map_unary minpos a; } Gravity_item = class Menuaction "Centre of _Gravity" "position of centre of gravity of histogram" { action a = map_unary gravity a; } sep2 = Menuseparator; Count_set_item = class Menuaction "_Non-zeros" "number of non-zero elements in object" { action a = map_unary cset a { cset i = (mean (i != 0) * i.width * i.height) / 255; } } Count_clear_item = class Menuaction "_Zeros" "number of zero elements in object" { action a = map_unary cclear a { cclear i = (mean (i == 0) * i.width * i.height) / 255; } } Count_edges_item = class Menuaction "_Edges" "count average edges across or down image" { action x = class _result { _vislevel = 3; edge = Option "Count" [ "Horizontal lines", "Vertical lines" ] 0; _result = map_unary process x { process image = Number (edge.labels?edge) (im_cntlines image.value edge.value); } } } sep3 = Menuseparator; Linear_regression_item = class Menuaction "_Linear Regression" "fit a line to a set of points" { action xes yes = linreg xes yes; } Weighted_linear_regression_item = class Menuaction "_Weighted Linear Regression" "fit a line to a set of points and deviations" { action xes yes devs = linregw xes yes devs; } Cluster_item = class Menuaction "_Cluster" "cluster a list of numbers" { action l = class { _vislevel = 3; thresh = Expression "Threshold" 10; [_r, _w] = cluster thresh.expr l; result = _r; weights = _w; } } } Math_base_item = class Menupullright "Bas_e" "convert number bases" { Hexadecimal_item = class Menuaction "_Hexadecimal" "convert to hexadecimal (base 16)" { action a = map_unary (print_base 16) a; } Binary_item = class Menuaction "_Binary" "convert to binary (base 2)" { action a = map_unary (print_base 2) a; } Octal_item = class Menuaction "_Octal" "convert to octal (base 8)" { action a = map_unary (print_base 8) a; } } nip2-8.7.1/share/nip2/compat/7.26/_generate.def0000644000175000017500000000470713351443023015570 00000000000000 /* make an image of size x by y whose pixels are their coordinates. */ make_xy x y = im_make_xy (to_real x) (to_real y); /* make an image with the specified properties ... pixel is (eg.) * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and * type, generate a 3 band float image, and lab2labq it before handing it * back. */ image_new w h b fmt coding type pixel xoff yoff = embed 1 0 0 w h im'''' { b' = 3, coding == Image_coding.LABPACK = b; fmt' = Image_format.FLOAT, coding == Image_coding.LABPACK = fmt; type' = Image_type.LAB, coding == Image_coding.LABPACK = type; im = im_black 1 1 (to_real b') + pixel; im' = clip2fmt fmt' im; im'' = im_Lab2LabQ im', coding == Image_coding.LABPACK; = im'; im''' = image_set_type type' im''; im'''' = image_set_origin xoff yoff im'''; } /* generate a slice of LAB space size x size pixels for L* == l */ lab_slice size l = image_set_type Image_type.LAB im { L = image_new size size 1 Image_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0; A1 = im_fgrey (to_real size) (to_real size); /* im_fgrey always makes 0-1, so these ranges can be wired in. */ A2 = A1 * 256 - 128; A4 = im_rot90 A2; im = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4); } /* Look at Image, try to make a Colour (failing that, a Vector) which is white * for that image type. */ image_white im = colour_transform_to type white_lab, bands == 3 && coding == Image_coding.NOCODING && colour_spaces.present 1 type = white_lab, coding == Image_coding.LABPACK = Vector (replicate bands (max_value.lookup 1 0 format)) { bands = im.bands; type = im.type; format = im.format; coding = im.coding; colour_spaces = Image_type.colour_spaces; // white as LAB white_lab = Colour "Lab" [100, 0, 0]; // maximum value for this numeric type max_value = Table [ [255, Image_format.DPCOMPLEX], [255, Image_format.DOUBLE], [255, Image_format.COMPLEX], [255, Image_format.FLOAT], [2 ** 31 - 1, Image_format.INT], [2 ** 32 - 1, Image_format.UINT], [2 ** 15 - 1, Image_format.SHORT], [2 ** 16 - 1, Image_format.USHORT], [2 ** 7 - 1, Image_format.CHAR], [2 ** 8 - 1, Image_format.UCHAR] ]; } /* Make a seperable gaussian mask. */ matrix_gaussian_blur radius = im_gauss_imask_sep (radius / 3) 0.2; /* Make a seperable square mask. */ matrix_blur radius = Matrix_con (sum mask_sq_line) 0 [mask_sq_line] { mask_sq_line = replicate (2 * radius - 1) 1; } nip2-8.7.1/share/nip2/compat/7.26/_stdenv.def0000644000175000017500000016472513351443023015310 00000000000000/* Various operators as functions. */ logical_and a b = a && b; logical_or a b = a || b; bitwise_and a b = a & b; bitwise_or a b = a | b; eor a b = a ^ b; left_shift a b = a << b; right_shift a b = a >> b; not a = !a; less a b = a < b; more a b = a > b; less_equal a b = a <= b; more_equal a b = a >= b; equal a b = a == b; not_equal a b = a != b; pointer_equal a b = a === b; not_pointer_equal a b = a !== b; add a b = a + b; subtract a b = a - b; multiply a b = a * b; divide a b = a / b; idivide a b = (int) ((int) a / (int) b); power a b = a ** b; square x = x * x; remainder a b = a % b; cons a b = a : b; dot a b = a . ( b ); join a b = a ++ b; // 'difference' is defined in _list subscript a b = a ? b; generate s n f = [s, n .. f]; comma r i = (r, i); compose f g = f @ g; // our only trinary operator is actually a binary operator if_then_else a x = if a then x?0 else x?1; cast_unsigned_char x = (unsigned char) x; cast_signed_char x = (signed char) x; cast_unsigned_short x = (unsigned short) x; cast_signed_short x = (signed short) x; cast_unsigned_int x = (unsigned int) x; cast_signed_int x = (signed int) x; cast_float x = (float) x; cast_double x = (double) x; cast_complex x = (complex) x; cast_double_complex x = (double complex) x; unary_minus x = -x; negate x = !x; complement x = ~x; unary_plus x = +x; // the function we call for "a -> v" expressions mksvpair s v = [s, v], is_string s = error "not str on lhs of ->"; // the vector ops ... im is an image, vec is a real_list vec op_name im vec = im_lintra_vec ones im vec, op_name == "add" || op_name == "add'" = im_lintra_vec ones (-1 * im) vec, op_name == "subtract'" = im_lintra_vec ones im inv, op_name == "subtract" = im_lintra_vec vec im zeros, op_name == "multiply" || op_name == "multiply'" = im_lintra_vec vec (1 / im) zeros, op_name == "divide'" = im_lintra_vec recip im zeros, op_name == "divide" = im_expntra_vec im vec, op_name == "power'" = im_powtra_vec im vec, op_name == "power" = im_remainderconst_vec im vec, op_name == "remainder" = im_andimage_vec im vec, op_name == "bitwise_and" || op_name == "bitwise_and'" = im_orimage_vec im vec, op_name == "bitwise_or" || op_name == "bitwise_or'" = im_eorimage_vec im vec, op_name == "eor" || op_name == "eor'" = im_equal_vec im vec, op_name == "equal" || op_name == "equal'" = im_notequal_vec im vec, op_name == "not_equal" || op_name == "not_equal'" = im_less_vec im vec, op_name == "less" = im_moreeq_vec im vec, op_name == "less'" = im_lesseq_vec im vec, op_name == "less_equal" = im_more_vec im vec, op_name == "less_equal'" = error ("unimplemented vector operation: " ++ op_name) { zeros = replicate (len vec) 0; ones = replicate (len vec) 1; recip = map (divide 1) vec; inv = map (multiply (-1)) vec; } // make a name value pair mknvpair n v = [n, v], is_string n = error "not [char] on LHS of =>"; /* Macbeth chart patch names. */ macbeth_names = [ "Dark skin", "Light skin", "Blue sky", "Foliage", "Blue flower", "Bluish green", "Orange", "Purplish blue", "Moderate red", "Purple", "Yellow green", "Orange yellow", "Blue", "Green", "Red", "Yellow", "Magenta", "Cyan", "White (density 0.05)", "Neutral 8 (density 0.23)", "Neutral 6.5 (density 0.44)", "Neutral 5 (density 0.70)", "Neutral 3.5 (density 1.05)", "Black (density 1.50)" ]; bandsplit x = oo_unary_function bandsplit_op x, is_class x = map (subscript x) [0 .. bands - 1], is_image x = error (_ "bad arguments to " ++ "bandsplit") { bands = get_header "Bands" x; bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) Operator_type.COMPOUND false; } bandjoin l = wrapper joined, has_wrapper = joined, is_listof has_image l = error (_ "bad arguments to " ++ "bandjoin") { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; joined = im_gbandjoin (map get_image l); } sum x = oo_unary_function sum_op x, is_class x = im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x = sum_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "sum") { sum_op = Operator "sum" sum Operator_type.COMPOUND false; // add elements in a nested-list thing sum_list l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } } product x = oo_unary_function product_op x, is_class x = product_list x, is_list x // (product image) doesn't make much sense :( = error (_ "bad arguments (" ++ print x ++ ") to " ++ "product") { product_op = Operator "product" product Operator_type.COMPOUND false; product_list l = foldr prod 1 l { prod x total = total * product x, is_list x = total * x; } } mean x = oo_unary_function mean_op x, is_class x = im_avg x, is_image x = mean_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "mean") { mean_op = Operator "mean" mean Operator_type.COMPOUND false; mean_list l = sum l / size l; // number of elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1; } } meang x = (appl (power e) @ mean @ appl log) x { appl fn x = map fn x, is_list x = fn x; } // zero-excluding mean meanze x = oo_unary_function meanze_op x, is_class x = meanze_image_hist x, is_image x && (fmt == Image_format.UCHAR || fmt == Image_format.USHORT) = meanze_image x, is_image x = meanze_list x, is_list x = error (_ "bad arguments (" ++ print x ++ ") to " ++ "meanze") { fmt = get_format x; meanze_op = Operator "meanze" meanze Operator_type.COMPOUND false; meanze_list l = sum l / size l; // number of non-zero elements in some sort of nested-list thing size l = foldr acc 0 l { acc x total = total + size x, is_list x = total + 1, x != 0; = total; } // add elements in a nested-list thing sum l = foldr acc 0 l { acc x total = total + sum x, is_list x = total + x; } // image mean, for any image type meanze_image i = sum / N { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } // image mean for 8 and 16-bit unsigned images // we can use a histogram, yay, and save a pass through the image meanze_image_hist i = sum / N { // histogram, knock out zeros hist = hist_find i; black = image_new 1 1 (get_bands hist) (get_format hist) (get_coding hist) (get_type hist) 0 0 0; histze = insert 0 0 black hist; // matching identity iden = im_identity_ushort (get_bands hist) (get_width hist), (get_width hist) > 256 = im_identity (get_bands hist); // number of non-zero pixels N = mean histze * 256; // sum of pixels sum = mean (hist * iden) * 256; } } deviation x = oo_unary_function deviation_op x, is_class x = im_deviate x, is_image x = deviation_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviation") { deviation_op = Operator "deviation" deviation Operator_type.COMPOUND false; deviation_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return n, sum, sum of squares for a list of reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } } deviationze x = oo_unary_function deviationze_op x, is_class x = deviationze_image x, is_image x = deviationze_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "deviationze") { deviationze_op = Operator "deviationze" deviationze Operator_type.COMPOUND false; deviationze_list l = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 { [n, s, s2] = sum_sum2_list l; } // return number of non-zero elements, sum, sum of squares for a list of // reals sum_sum2_list x = foldr accumulate [0, 0, 0] x { accumulate x sofar = sofar, is_real x && x == 0 = [n + 1, x + s, x * x + s2], is_real x = [n + n', s + s', s2 + s2'], is_list x = error "sum_sum2_list: not real or [real]" { [n, s, s2] = sofar; [n', s', s2'] = sum_sum2_list x; } } deviationze_image i = ((sum2 - sum * sum / N) / (N - 1)) ** 0.5 { w = get_width i; h = get_height i; b = get_bands i; st = stats i; sum = st.value?0?2; sum2 = st.value?0?3; // find non-zero pixels (not zero in all bands) zp = im_notequal_vec i (replicate b 0); // number of non-zero pixels N = b * (mean zp * w * h) / 255; } } // find the centre of gravity of a histogram gravity x = oo_unary_function gravity_op x, is_class x = im_hist_gravity x, is_hist x = gravity_list x, is_list x = error (_ "bad arguments to " ++ "gravity") { gravity_op = Operator "gravity" gravity Operator_type.COMPOUND false; // centre of gravity of a histogram... use the histogram to weight an // identity, then sum, then find the mean element im_hist_gravity h = m { // make horizontal h' = rot270 h, get_width h == 1 = h, get_height h == 1 = error "width or height not 1"; // number of elements w = get_width h'; // matching identity i = im_identity_ushort 1 w, w <= 2 ** 16 - 1 = make_xy w 1 ? 0; // weight identity and sum s = mean (i * h') * w; // sum of original histogram s' = mean h * w; // weighted mean m = s / s'; } gravity_list l = m { w = len l; // matching identity i = [0, 1 .. w - 1]; // weight identity and sum s = sum (map2 multiply i l); // sum of original histogram s' = sum l; // weighted mean m = s / s'; } } project x = oo_unary_function project_op x, is_class x = im_project x, is_image x = error (_ "bad arguments to " ++ "project") { project_op = Operator "project" project Operator_type.COMPOUND false; } abs x = oo_unary_function abs_op x, is_class x = im_abs x, is_image x = abs_cmplx x, is_complex x = abs_num x, is_real x = abs_list x, is_real_list x = abs_list (map abs_list x), is_matrix x = error (_ "bad arguments to " ++ "abs") { abs_op = Operator "abs" abs Operator_type.COMPOUND false; abs_list l = (sum (map square l)) ** 0.5; abs_num n = n, n >= 0 = -n; abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; } copy x = oo_unary_function copy_op x, is_class x = im_copy x, is_image x = x { copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; } // like abs, but treat pixels as vectors ... ie. always get a 1-band image // back ... also treat matricies as lists of vectors // handy for dE from object difference abs_vec x = oo_unary_function abs_vec_op x, is_class x = abs_vec_image x, is_image x = abs_vec_cmplx x, is_complex x = abs_vec_num x, is_real x = abs_vec_list x, is_real_list x = mean (map abs_vec_list x), is_matrix x = error (_ "bad arguments to " ++ "abs_vec") { abs_vec_op = Operator "abs_vec" abs_vec Operator_type.COMPOUND false; abs_vec_list l = (sum (map square l)) ** 0.5; abs_vec_num n = n, n >= 0 = -n; abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; abs_vec_image im = (sum (map square (bandsplit im))) ** 0.5; } transpose x = oo_unary_function transpose_op x, is_class x = transpose_image x, is_image x = transpose_list x, is_listof is_list x = error (_ "bad arguments to " ++ "transpose") { transpose_op = Operator "transpose" transpose Operator_type.COMPOUND_REWRAP false; transpose_list l = [], l' == [] = (map hd l') : (transpose_list (map tl l')) { l' = takewhile (not_equal []) l; } transpose_image = im_flipver @ im_rot270; } rot45 x = oo_unary_function rot45_op x, is_class x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45") { rot45_op = Operator "rot45" rot45_object Operator_type.COMPOUND_REWRAP false; rot45_object x = rot45_matrix x, is_odd_square_matrix x = error "rot45 image: not implemented", is_image x = error (_ "bad arguments to " ++ "rot45"); // slow, but what the heck rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; } // apply an image function to a [[real]] ... matrix is converted to a 1 band // image for processing apply_matrix_as_image fn m = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; // a general image/matrix operation where the mat version is most easily done // by converting mat->image->mat apply_matim_operation name fn x = oo_unary_function class_op x, is_class x = fn x, is_image x = apply_matrix_as_image fn x, is_matrix x = error (_ "bad arguments to " ++ name) { class_op = Operator name (apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false; } rot90 = apply_matim_operation "rot90" im_rot90; rot180 = apply_matim_operation "rot180" im_rot180; rot270 = apply_matim_operation "rot270" im_rot270; rotquad = apply_matim_operation "rotquad" im_rotquad; fliplr = apply_matim_operation "fliplr" im_fliphor; fliptb = apply_matim_operation "flipud" im_flipver; image_set_type type x = oo_unary_function image_set_type_op x, is_class x = im_copy_set x (to_real type) (get_header "Xres" x) (get_header "Yres" x) (get_header "Xoffset" x) (get_header "Yoffset" x), is_image x = error (_ "bad arguments to " ++ "image_set_type:" ++ print type ++ " " ++ print x) { image_set_type_op = Operator "image_set_type" (image_set_type type) Operator_type.COMPOUND_REWRAP false; } image_set_origin xoff yoff x = oo_unary_function image_set_origin_op x, is_class x = im_copy_set x (get_header "Type" x) (get_header "Xres" x) (get_header "Yres" x) (to_real xoff) (to_real yoff), is_image x = error (_ "bad arguments to " ++ "image_set_origin") { image_set_origin_op = Operator "image_set_origin" (image_set_origin xoff yoff) Operator_type.COMPOUND_REWRAP false; } cache tile_width tile_height max_tiles x = oo_unary_function cache_op x, is_class x = im_cache x (to_real tile_width) (to_real tile_height) (to_real max_tiles), is_image x = error (_ "bad arguments to " ++ "cache") { cache_op = Operator "cache" (cache tile_width tile_height max_tiles) Operator_type.COMPOUND_REWRAP false; } tile across down x = oo_unary_function tile_op x, is_class x = im_replicate x (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "tile") { tile_op = Operator "tile" (tile across down) Operator_type.COMPOUND_REWRAP false; } grid tile_height across down x = oo_unary_function grid_op x, is_class x = im_grid x (to_real tile_height) (to_real across) (to_real down), is_image x = error (_ "bad arguments to " ++ "grid") { grid_op = Operator "grid" (grid tile_height across down) Operator_type.COMPOUND_REWRAP false; } max_pair a b = a, a > b = b; min_pair a b = a, a < b = b; range min value max = min_pair max (max_pair min value); max x = oo_unary_function max_op x, is_class x = im_max x, is_image x = max_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "max") { max_op = Operator "max" max Operator_type.COMPOUND false; max_list x = error "max []", x == [] = foldr1 max_pair x, is_real_list x = foldr1 max_pair (map max_list x), is_list x = max x; } min x = oo_unary_function min_op x, is_class x = im_min x, is_image x = min_list x, is_list x = x, is_number x = error (_ "bad arguments to " ++ "min") { min_op = Operator "min" min Operator_type.COMPOUND false; min_list x = error "min []", x == [] = foldr1 min_pair x, is_real_list x = foldr1 min_pair (map min_list x), is_list x = min x; } maxpos x = oo_unary_function maxpos_op x, is_class x = im_maxpos x, is_image x = maxpos_matrix x, is_matrix x = maxpos_list x, is_list x = error (_ "bad arguments to " ++ "maxpos") { maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; maxpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { max_value = max (Matrix m); indexes = map (index (equal max_value)) m; row = index (not_equal (-1)) indexes; } maxpos_list l = -1, l == [] = index (equal (max l)) l; } minpos x = oo_unary_function minpos_op x, is_class x = im_minpos x, is_image x = minpos_matrix x, is_matrix x = minpos_list x, is_list x = error (_ "bad arguments to " ++ "minpos") { minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; minpos_matrix m = (-1, -1), m == [[]] = (indexes?row, row) { min_value = min (Matrix m); indexes = map (index (equal min_value)) m; row = index (not_equal (-1)) indexes; } minpos_list l = -1, l == [] = index (equal (min l)) l; } stats x = oo_unary_function stats_op x, is_class x = im_stats x, is_image x = im_stats (to_image x).value, is_matrix x = error (_ "bad arguments to " ++ "stats") { stats_op = Operator "stats" stats Operator_type.COMPOUND false; } e = 2.7182818284590452354; pi = 3.14159265358979323846; rad d = 2 * pi * (d / 360); deg r = 360 * r / (2 * pi); sign x = oo_unary_function sign_op x, is_class x = im_sign x, is_image x = sign_cmplx x, is_complex x = sign_num x, is_real x = error (_ "bad arguments to " ++ "sign") { sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; sign_num n = 0, n == 0 = 1, n > 0 = -1; sign_cmplx c = (0, 0), mod == 0 = (re c / mod, im c / mod) { mod = abs c; } } rint x = oo_unary_function rint_op x, is_class x = im_rint x, is_image x = rint_value x, is_number x = error (_ "bad arguments to " ++ "rint") { rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; rint_value x = (int) (x + 0.5), x > 0 = (int) (x - 0.5); } scale x = oo_unary_function scale_op x, is_class x = (unsigned char) x, is_number x = im_scale x, is_image x = scale_list x, is_real_list x || is_matrix x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; scale_list l = apply_scale s o l { mn = find_limit min_pair l; mx = find_limit max_pair l; s = 255.0 / (mx - mn); o = -(mn * s); } find_limit fn l = find_limit fn (map (find_limit fn) l), is_listof is_list l = foldr1 fn l; apply_scale s o x = x * s + o, is_number x = map (apply_scale s o) x; } scaleps x = oo_unary_function scale_op x, is_class x = im_scaleps x, is_image x = error (_ "bad arguments to " ++ "scale") { scale_op = Operator "scaleps" scaleps Operator_type.COMPOUND_REWRAP false; } fwfft x = oo_unary_function fwfft_op x, is_class x = im_fwfft x, is_image x = error (_ "bad arguments to " ++ "fwfft") { fwfft_op = Operator "fwfft" fwfft Operator_type.COMPOUND_REWRAP false; } invfft x = oo_unary_function invfft_op x, is_class x = im_invfftr x, is_image x = error (_ "bad arguments to " ++ "invfft") { invfft_op = Operator "invfft" invfft Operator_type.COMPOUND_REWRAP false; } falsecolour x = oo_unary_function falsecolour_op x, is_class x = image_set_type Image_type.sRGB (im_falsecolour x), is_image x = error (_ "bad arguments to " ++ "falsecolour") { falsecolour_op = Operator "falsecolour" falsecolour Operator_type.COMPOUND_REWRAP false; } polar x = oo_unary_function polar_op x, is_class x = im_c2amph x, is_image x = polar_cmplx x, is_complex x = error (_ "bad arguments to " ++ "polar") { polar_op = Operator "polar" polar Operator_type.COMPOUND false; polar_cmplx r = (l, a) { a = 270, x == 0 && y < 0 = 90, x == 0 && y >= 0 = 360 + atan (y / x), x > 0 && y < 0 = atan (y / x), x > 0 && y >= 0 = 180 + atan (y / x); l = (x ** 2 + y ** 2) ** 0.5; x = re r; y = im r; } } rectangular x = oo_unary_function rectangular_op x, is_class x = im_c2rect x, is_image x = rectangular_cmplx x, is_complex x = error (_ "bad arguments to " ++ "rectangular") { rectangular_op = Operator "rectangular" rectangular Operator_type.COMPOUND false; rectangular_cmplx p = (x, y) { l = re p; a = im p; x = l * cos a; y = l * sin a; } } // we can't use colour_unary: that likes 3 band only recomb matrix x = oo_unary_function recomb_op x, is_class x = im_recomb x matrix, is_image x = recomb_real_list x, is_real_list x = map recomb_real_list x, is_matrix x = error (_ "bad arguments to " ++ "recomb") { // COMPOUND_REWRAP ... signal to the colour class to go to image and // back recomb_op = Operator "recomb" (recomb matrix) Operator_type.COMPOUND_REWRAP false; // process [1,2,3 ..] as an image recomb_real_list l = (to_matrix im').value?0 { im = (float) (to_image (Vector l)).value; im' = recomb matrix im; } } extract_area x y w h obj = oo_unary_function extract_area_op obj, is_class obj = im_extract_area obj x' y' w' h', is_image obj = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj = error (_ "bad arguments to " ++ "extract_area") { x' = to_real x; y' = to_real y; w' = to_real w; h' = to_real h; extract_area_op = Operator "extract_area" (extract_area x y w h) Operator_type.COMPOUND_REWRAP false; extract_range from length list = (take length @ drop from) list; } extract_band b obj = subscript obj b; extract_row y obj = oo_unary_function extract_row_op obj, is_class obj = extract_area 0 y' (get_width obj) 1 obj, is_image obj = [obj?y'], is_matrix obj = error (_ "bad arguments to " ++ "extract_row") { y' = to_real y; extract_row_op = Operator "extract_row" (extract_row y) Operator_type.COMPOUND_REWRAP false; } extract_column x obj = oo_unary_function extract_column_op obj, is_class obj = extract_area x' 0 1 height obj, is_image obj = map (\row [row?x']) obj, is_matrix obj = error (_ "bad arguments to " ++ "extract_column") { x' = to_real x; height = get_header "Ysize" obj; extract_column_op = Operator "extract_column" (extract_column x) Operator_type.COMPOUND_REWRAP false; } blend cond in1 in2 = oo_binary_function blend_op cond [in1,in2], is_class cond = im_blend (get_image cond) (get_image in1) (get_image in2), has_image cond && has_image in1 && has_image in2 = error (_ "bad arguments to " ++ "blend") { blend_op = Operator "blend" blend_obj Operator_type.COMPOUND_REWRAP false; blend_obj cond x = blend_result_image { [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, cond]; // properties of our output image target_width = get_member_list has_width get_width objects; target_height = get_member_list has_height get_height objects; target_bands = get_member_list has_bands get_bands objects; target_format = get_member_list has_format get_format objects; target_type = get_member_list has_type get_type objects; to_image x = to_image_size target_width target_height target_bands target_format x; [then_image, else_image] = map to_image [then_part, else_part]; blend_result_image = image_set_type target_type (im_blend cond then_image else_image); } } // do big first: we want to keep big's class, if possible // eg. big is a Plot, small is a 1x1 Image insert x y small big = oo_binary'_function insert_op small big, is_class big = oo_binary_function insert_op small big, is_class small = im_insert big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert") { insert_op = Operator "insert" (insert x y) Operator_type.COMPOUND_REWRAP false; } insert_noexpand x y small big = oo_binary_function insert_noexpand_op small big, is_class small = oo_binary'_function insert_noexpand_op small big, is_class big = im_insert_noexpand big small (to_real x) (to_real y), is_image small && is_image big = error (_ "bad arguments to " ++ "insert_noexpand") { insert_noexpand_op = Operator "insert_noexpand" (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; } measure x y w h u v image = oo_unary_function measure_op image, is_class image = im_measure image (to_real x) (to_real y) (to_real w) (to_real h) (to_real u) (to_real v), is_image image = error (_ "bad arguments to " ++ "measure") { measure_op = Operator "measure" (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; } extract_bands b n obj = oo_unary_function extract_bands_op obj, is_class obj = im_extract_bands obj (to_real b) (to_real n), is_image obj = error (_ "bad arguments to " ++ "extract_bands") { extract_bands_op = Operator "extract_bands" (extract_bands b n) Operator_type.COMPOUND_REWRAP false; } invert x = oo_unary_function invert_op x, is_class x = im_invert x, is_image x = 255 - x, is_real x = error (_ "bad arguments to " ++ "invert") { invert_op = Operator "invert" invert Operator_type.COMPOUND false; } transform ipol wrap params image = oo_unary_function transform_op image, is_class image = im_transform image (to_matrix params) (to_real ipol) (to_real wrap), is_image image = error (_ "bad arguments to " ++ "transform") { transform_op = Operator "transform" (transform ipol wrap params) Operator_type.COMPOUND_REWRAP false; } transform_search max_error max_iterations order ipol wrap sample reference = oo_binary_function transform_search_op sample reference, is_class sample = oo_binary'_function transform_search_op sample reference, is_class reference = im_transform_search sample reference (to_real max_error) (to_real max_iterations) (to_real order) (to_real ipol) (to_real wrap), is_image sample && is_image reference = error (_ "bad arguments to " ++ "transform_search") { transform_search_op = Operator "transform_search" (transform_search max_error max_iterations order ipol wrap) Operator_type.COMPOUND false; } rotate interp angle image = oo_binary_function rotate_op angle image, is_class angle = oo_binary'_function rotate_op angle image, is_class image = im_affinei_all image interp.value a (-b) b a 0 0, is_real angle && is_image image = error (_ "bad arguments to " ++ "rotate") { rotate_op = Operator "rotate" (rotate interp) Operator_type.COMPOUND_REWRAP false; a = cos angle; b = sin angle; } matrix_binary fn a b = itom (fn (mtoi a) (mtoi b)) { mtoi x = im_mask2vips (Matrix x); itom x = (im_vips2mask x).value; } join_lr a b = oo_binary_function join_lr_op a b, is_class a = oo_binary'_function join_lr_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_lr") { join_lr_op = Operator "join_lr" join_lr Operator_type.COMPOUND_REWRAP false; join_im a b = insert (get_width a) 0 b a; } join_tb a b = oo_binary_function join_tb_op a b, is_class a = oo_binary'_function join_tb_op a b, is_class b = join_im a b, is_image a && is_image b = matrix_binary join_im a b, is_matrix a && is_matrix b = error (_ "bad arguments to " ++ "join_tb") { join_tb_op = Operator "join_tb" join_tb Operator_type.COMPOUND_REWRAP false; join_im a b = insert 0 (get_height a) b a; } conj x = oo_unary_function conj_op x, is_class x = (re x, -im x), is_complex x || (is_image x && format == Image_format.COMPLEX) || (is_image x && format == Image_format.DPCOMPLEX) // assume it's some sort of real = x { format = get_header "BandFmt" x; conj_op = Operator "conj" conj Operator_type.COMPOUND false; } clip2fmt format image = oo_unary_function clip2fmt_op image, is_class image = im_clip2fmt image (to_real format), is_image image = error (_ "bad arguments to " ++ "clip2fmt") { clip2fmt_op = Operator "clip2fmt" (clip2fmt format) Operator_type.COMPOUND_REWRAP false; } embed type x y w h im = oo_unary_function embed_op im, is_class im = im_embed im (to_real type) (to_real x) (to_real y) (to_real w) (to_real h), is_image im = error (_ "bad arguments to " ++ "embed") { embed_op = Operator "embed" (embed type x y w h) Operator_type.COMPOUND_REWRAP false; } /* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it * with m1, turn it back to a matrix again. */ _morph_2_masks fn m1 m2 = m'' { // The [[real]] can contain 128 values ... squeeze them out! image = im_mask2vips (Matrix m2) == 255; m2_width = get_width image; m2_height = get_height image; // need to embed m2 in an image large enough for us to be able to // position m1 all around the edges, with a 1 pixel overlap image' = embed 0 (m1.width / 2) (m1.height / 2) (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) image; // morph! image'' = fn m1 image'; // back to mask m' = im_vips2mask ((double) image''); // Turn 0 in output to 128 (don't care). m'' = map (map fn) m'.value { fn a = 128, a == 0; = a; } } dilate mask image = oo_unary_function dilate_op image, is_class image = im_dilate image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "dilate") { dilate_op = Operator "dilate" dilate_object Operator_type.COMPOUND_REWRAP false; dilate_object x = _morph_2_masks dilate mask x, is_matrix x = dilate mask x; } erode mask image = oo_unary_function erode_op image, is_class image = im_erode image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "erode") { erode_op = Operator "erode" erode_object Operator_type.COMPOUND_REWRAP false; erode_object x = _morph_2_masks erode mask x, is_matrix x = erode mask x; } conv mask image = oo_unary_function conv_op image, is_class image = im_conv image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "conv" ++ ": " ++ "conv (" ++ print mask ++ ") (" ++ print image ++ ")") { conv_op = Operator "conv" (conv mask) Operator_type.COMPOUND_REWRAP false; } convf mask image = oo_unary_function convf_op image, is_class image = im_conv_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convf" ++ ": " ++ "convf (" ++ print mask ++ ") (" ++ print image ++ ")") { convf_op = Operator "convf" (convf mask) Operator_type.COMPOUND_REWRAP false; } convsep mask image = oo_unary_function convsep_op image, is_class image = im_convsep image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsep") { convsep_op = Operator "convsep" (convsep mask) Operator_type.COMPOUND_REWRAP false; } aconvsep layers mask image = oo_unary_function aconvsep_op image, is_class image = im_aconvsep image (to_matrix mask) (to_real layers), is_image image = error (_ "bad arguments to " ++ "aconvsep") { aconvsep_op = Operator "aconvsep" (aconvsep layers mask) Operator_type.COMPOUND_REWRAP false; } convsepf mask image = oo_unary_function convsepf_op image, is_class image = im_convsep_f image (to_matrix mask), is_image image = error (_ "bad arguments to " ++ "convsepf") { convsepf_op = Operator "convsepf" (convsepf mask) Operator_type.COMPOUND_REWRAP false; } rank w h n image = oo_unary_function rank_op image, is_class image = im_rank image (to_real w) (to_real h) (to_real n), is_image image = error (_ "bad arguments to " ++ "rank") { rank_op = Operator "rank" (rank w h n) Operator_type.COMPOUND_REWRAP false; } rank_image n x = rlist x.value, is_Group x = rlist x, is_list x = error (_ "bad arguments to " ++ "rank_image") { rlist l = wrapper ranked, has_wrapper = ranked { has_wrapper = has_member_list (has_member "Image") l; wrapper = get_member_list (has_member "Image") (get_member "Image") l; ranked = im_rank_image (map get_image l) (to_real n); } } greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx x = oo_unary_function greyc_op x, is_class x = greyc_im x, is_image x = error (_ "bad argument" ++ " (" ++ print x ++ ") to " ++ "greyc") { greyc_op = Operator "greyc" (greyc iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im x = im_greyc x iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx mask x = oo_binary_function greyc_mask_op mask x, is_class mask = oo_binary'_function greyc_mask_op mask x, is_class x = greyc_im mask x, is_image mask && is_image x = error (_ "bad arguments" ++ " (" ++ print mask ++ ", " ++ print x ++ ") " ++ "to " ++ "greyc") { greyc_mask_op = Operator "greyc_mask" (greyc_mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx) Operator_type.COMPOUND_REWRAP false; greyc_im mask x = im_greyc_mask x mask iterations amplitude sharpness anisotropy alpha sigma dl da gauss_prec interpolation fast_approx; } // find the correlation surface for a small image within a big one correlate small big = oo_binary_function correlate_op small big, is_class small = oo_binary'_function correlate_op small big, is_class big = im_spcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate") { correlate_op = Operator "correlate" correlate Operator_type.COMPOUND_REWRAP false; } // just sum-of-squares-of-differences correlate_fast small big = oo_binary_function correlate_fast_op small big, is_class small = oo_binary'_function correlate_fast_op small big, is_class big = im_fastcor big small, is_image small && is_image big = error (_ "bad arguments to " ++ "correlate_fast") { correlate_fast_op = Operator "correlate_fast" correlate_fast Operator_type.COMPOUND_REWRAP false; } // set Type, wrap as Plot_hist if it's a class hist_tag x = oo_unary_function hist_tag_op x, is_class x = image_set_type Image_type.HISTOGRAM x, is_image x = error (_ "bad arguments to " ++ "hist_tag") { hist_tag_op = Operator "hist_tag" (Plot_histogram @ hist_tag) Operator_type.COMPOUND false; } hist_find x = oo_unary_function hist_find_op x, is_class x = im_histgr x (-1), is_image x = error (_ "bad arguments to " ++ "hist_find") { hist_find_op = Operator "hist_find" (Plot_histogram @ hist_find) Operator_type.COMPOUND false; } hist_find_nD bins image = oo_unary_function hist_find_nD_op image, is_class image = im_histnD image (to_real bins), is_image image = error (_ "bad arguments to " ++ "hist_find_nD") { hist_find_nD_op = Operator "hist_find_nD" (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; } hist_find_indexed index value = oo_binary_function hist_find_indexed_op index value, is_class index = oo_binary'_function hist_find_indexed_op index value, is_class value = im_hist_indexed index value, is_image index && is_image value = error (_ "bad arguments to " ++ "hist_find_indexed") { hist_find_indexed_op = Operator "hist_find_indexed" (compose (compose Plot_histogram) hist_find_indexed) Operator_type.COMPOUND false; } hist_map hist image = oo_binary_function hist_map_op hist image, is_class hist = oo_binary'_function hist_map_op hist image, is_class image = im_maplut image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "hist_map") { // can't use rewrap, as we want to always wrap as image hist_map_op = Operator "hist_map" (compose (compose Image) hist_map) Operator_type.COMPOUND false; } hist_cum hist = oo_unary_function hist_cum_op hist, is_class hist = im_histcum hist, is_image hist = error (_ "bad arguments to " ++ "hist_cum") { hist_cum_op = Operator "hist_cum" hist_cum Operator_type.COMPOUND_REWRAP false; } hist_diff hist = oo_unary_function hist_diff_op hist, is_class hist = im_histdiff hist, is_image hist = error (_ "bad arguments to " ++ "hist_diff") { hist_diff_op = Operator "hist_diff" hist_diff Operator_type.COMPOUND_REWRAP false; im_histdiff h = (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h { // up the format so it can represent the whole range of // possible values from this mask fmt x = Image_format.SHORT, x == Image_format.UCHAR || x == Image_format.CHAR = Image_format.INT, x == Image_format.USHORT || x == Image_format.SHORT || x == Image_format.UINT = x; } } hist_norm hist = oo_unary_function hist_norm_op hist, is_class hist = im_histnorm hist, is_image hist = error (_ "bad arguments to " ++ "hist_norm") { hist_norm_op = Operator "hist_norm" hist_norm Operator_type.COMPOUND_REWRAP false; } hist_match in ref = oo_binary_function hist_match_op in ref, is_class in = oo_binary'_function hist_match_op in ref, is_class ref = im_histspec in ref, is_image in && is_image ref = error (_ "bad arguments to " ++ "hist_match") { hist_match_op = Operator "hist_match" hist_match Operator_type.COMPOUND_REWRAP false; } hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; hist_equalize_local w h image = oo_unary_function hist_equalize_local_op image, is_class image = lhisteq image, is_image image = error (_ "bad arguments to " ++ "hist_equalize_local") { hist_equalize_local_op = Operator "hist_equalize_local" (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; // loop over bands, if necessary lhisteq im = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 = (foldl1 join @ map lhisteq @ bandsplit) im; } // find the threshold below which are percent of the image (percent in [0,1]) // eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels hist_thresh percent image = x { // our own normaliser ... we don't want to norm channels separately // norm to [0,1] my_hist_norm h = h / max h; // normalised cumulative hist // we sum the channels before we normalise, because we want to treat them // all the same h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) image.value; // threshold that, then use im_profile to search for the x position in the // histogram x = mean (im_profile (h > percent) 1); } /* Sometimes useful, despite plotting now being built in, for making * diagnostic images. */ hist_plot hist = oo_unary_function hist_plot_op hist, is_class hist = im_histplot hist, is_image hist = error (_ "bad arguments to " ++ "hist_plot") { hist_plot_op = Operator "hist_plot" (Image @ hist_plot) Operator_type.COMPOUND false; } zerox d x = oo_unary_function zerox_op x, is_class x = im_zerox x (to_real d), is_image x = error (_ "bad arguments to " ++ "zerox") { zerox_op = Operator "zerox" (zerox d) Operator_type.COMPOUND_REWRAP false; } resize interp xfac yfac image = oo_unary_function resize_op image, is_class image = resize_im image, is_image image = error (_ "bad arguments to " ++ "resize") { resize_op = Operator "resize" resize_im Operator_type.COMPOUND_REWRAP false; xfac' = to_real xfac; yfac' = to_real yfac; rxfac' = 1 / xfac'; ryfac' = 1 / yfac'; // is this interpolation nearest-neighbour? is_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR; resize_im im // upscale by integer factor, nearest neighbour = im_zoom im xfac' yfac', is_int xfac' && is_int yfac' && xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by integer factor, nearest neighbour = im_subsample im rxfac' ryfac', is_int rxfac' && is_int ryfac' && rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor, nearest neighbour // upscale by integer part, then affine to exact size = scale xg?1 yg?1 (im_zoom im xg?0 yg?0), xfac' >= 1 && yfac' >= 1 && is_nn interp // downscale by any factor, nearest neighbour // downscale by integer part, then affine to exact size = scale xs?1 ys?1 (im_subsample im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 && is_nn interp // upscale by any factor with affine = scale xfac' yfac' im, xfac' >= 1 && yfac' >= 1 // downscale by any factor, bilinear // block shrink by integer factor, then resample to // exact with affine = scale xs?1 ys?1 (im_shrink im xs?0 ys?0), rxfac' >= 1 && ryfac' >= 1 = error ("resize: unimplemented argument combination:\n" ++ " xfac = " ++ print xfac' ++ "\n" ++ " yfac = " ++ print yfac' ++ "\n" ++ " interp = " ++ print interp ++ " (" ++ Interpolate_type.descriptions?interp.type ++ ")") { // convert a float scale to integer plus fraction // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) break f = [floor f, f / floor f]; // same, but for downsizing ... turn a float scale which is less than // 1 into an int shrink and a float scale // complicated: the int shrink may round the size down (eg. imagine // subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide // image, not a 3.666 pixel wide image), so pass in the size of image // we are operating on and adjust for any rounding // so ... x is (eg.) 467, f is (eg. 128/467, about 0.274) rbreak x f = [int_shrink, float_resample] { // the size of image we are aiming for after the combined int and // float resample x' = x * f; // int part int_shrink = floor (1 / f); // size after int shrink x'' = floor (x / int_shrink); // therefore what we need for the float part float_resample = x' / x''; } width = get_width im; height = get_height im; // grow and shrink factors xg = break xfac'; yg = break yfac'; xs = rbreak width xfac'; ys = rbreak height yfac'; // resize scale xfac yfac im = im_affinei_all im interp.value xfac 0 0 yfac 0 0; } } sharpen radius x1 y2 y3 m1 m2 in = oo_unary_function sharpen_op in, is_class in = im_sharpen in (to_real radius) (to_real x1) (to_real y2) (to_real y3) (to_real m1) (to_real m2), is_image in = error (_ "bad arguments to " ++ "sharpen") { sharpen_op = Operator "sharpen" (sharpen radius x1 y2 y3 m1 m2) Operator_type.COMPOUND_REWRAP false; } tone_analyse s m h sa ma ha in = oo_unary_function tone_analyse_op in, is_class in = im_tone_analyse in (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha), is_image in = error (_ "bad arguments to " ++ "tone_analyse") { tone_analyse_op = Operator "tone_analyse" (Plot_histogram @ tone_analyse s m h sa ma ha) Operator_type.COMPOUND false; } tone_map hist image = oo_binary_function tone_map_op hist image, is_class hist = oo_binary'_function tone_map_op hist image, is_class image = im_tone_map image hist, is_image hist && is_image image = error (_ "bad arguments to " ++ "tone_map") { tone_map_op = Operator "tone_map" tone_map Operator_type.COMPOUND_REWRAP false; } tone_build fmt b w s m h sa ma ha = (Plot_histogram @ clip2fmt fmt) (im_tone_build_range mx mx (to_real b) (to_real w) (to_real s) (to_real m) (to_real h) (to_real sa) (to_real ma) (to_real ha)) { mx = Image_format.maxval fmt; } icc_export depth profile intent in = oo_unary_function icc_export_op in, is_class in = im_icc_export_depth in (to_real depth) (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_export") { icc_export_op = Operator "icc_export" (icc_export depth profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import profile intent in = oo_unary_function icc_import_op in, is_class in = im_icc_import in (expand profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import") { icc_import_op = Operator "icc_import" (icc_import profile intent) Operator_type.COMPOUND_REWRAP false; } icc_import_embedded intent in = oo_unary_function icc_import_embedded_op in, is_class in = im_icc_import_embedded in (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_import_embedded") { icc_import_embedded_op = Operator "icc_import_embedded" (icc_import_embedded intent) Operator_type.COMPOUND_REWRAP false; } icc_transform in_profile out_profile intent in = oo_unary_function icc_transform_op in, is_class in = im_icc_transform in (expand in_profile) (expand out_profile) (to_real intent), is_image in = error (_ "bad arguments to " ++ "icc_transform") { icc_transform_op = Operator "icc_transform" (icc_transform in_profile out_profile intent) Operator_type.COMPOUND_REWRAP false; } icc_ac2rc profile in = oo_unary_function icc_ac2rc_op in, is_class in = im_icc_ac2rc in (expand profile), is_image in = error (_ "bad arguments to " ++ "icc_ac2rc") { icc_ac2rc_op = Operator "icc_ac2rc" (icc_ac2rc profile) Operator_type.COMPOUND_REWRAP false; } draw_flood_blob x y ink image = oo_unary_function draw_flood_blob_op image, is_class image = im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood_blob") { draw_flood_blob_op = Operator "draw_flood_blob" (draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false; } draw_flood x y ink image = oo_unary_function draw_flood_op image, is_class image = im_draw_flood image (to_real x) (to_real y) ink, is_image image = error (_ "bad arguments to " ++ "draw_flood") { draw_flood_op = Operator "draw_flood" (draw_flood x y ink) Operator_type.COMPOUND_REWRAP false; } draw_rect x y w h f ink image = oo_unary_function draw_rect_op image, is_class image = im_draw_rect image (to_real x) (to_real y) (to_real w) (to_real h) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_rect") { draw_rect_op = Operator "draw_rect" (draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false; } draw_circle x y r f ink image = oo_unary_function draw_circle_op image, is_class image = im_draw_circle image (to_real x) (to_real y) (to_real r) (to_real f) ink, is_image image = error (_ "bad arguments to " ++ "draw_circle") { draw_circle_op = Operator "draw_circle" (draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false; } draw_line x1 y1 x2 y2 ink image = oo_unary_function draw_line_op image, is_class image = im_draw_line image (to_real x1) (to_real y1) (to_real x2) (to_real y2) ink, is_image image = error (_ "bad arguments to " ++ "draw_line") { draw_line_op = Operator "draw_line" (draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false; } print_base base in = oo_unary_function print_base_op in, is_class in = map (print_base base) in, is_list in = print_base_real, is_real in = error (_ "bad arguments to " ++ "print_base") { print_base_op = Operator "print_base" (print_base base) Operator_type.COMPOUND false; print_base_real = error "print_base: bad base", base < 2 || base > 16 = "0", in < 0 || chars == [] = reverse chars { digits = map (\x x % base) (takewhile (not_equal 0) (iterate (\x idivide x base) in)); chars = map tohd digits; tohd x = (char) ((int) '0' + x), x < 10 = (char) ((int) 'A' + (x - 10)); } } /* id x: the identity function * * id :: * -> * */ id x = x; /* const x y: junk y, return x * * (const 3) is the function that always returns 3. * const :: * -> ** -> * */ const x y = x; /* converse fn a b: swap order of args to fn * * converse fn a b == fn b a * converse :: (* -> ** -> ***) -> ** -> * -> *** */ converse fn a b = fn b a; /* fix fn x: find the fixed point of a function */ fix fn x = limit (iterate fn x); /* until pred fn n: apply fn to n until pred succeeds; return that value * * until (more 1000) (multiply 2) 1 = 1024 * until :: (* -> bool) -> (* -> *) -> * -> * */ until pred fn n = n, pred n = until pred fn (fn n); /* Infinite list of primes. */ primes = 1 : (sieve [2 ..]) { sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); nmultiple n x = x / n != (int) (x / n); } /* Map an n-ary function (pass the args as a list) over groups of objects. * The objects can be single objects or groups. If more than one * object is a group, we iterate for the length of the smallest group. * Don't loop over plain lists, since we want (eg.) "mean [1, 2, 3]" to work. * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the * output and don't apply the function. copy-pasted into _types, keep in sync */ map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { // find all the group arguments groups = filter is_Group args; // what's the length of the shortest group arg? shortest = foldr1 min_pair (map (len @ get_value) groups); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested groups too process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } /* Map a 1-ary function over an object. */ map_unary fn a = map_nary (list_1ary fn) [a]; /* Map a 2-ary function over a pair of objects. */ map_binary fn a b = map_nary (list_2ary fn) [a, b]; /* Map a 3-ary function over three objects. */ map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; /* Map a 4-ary function over three objects. */ map_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d]; /* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on * vectors and matricies. */ map_nary_list fn args = fn args, lists == [] = map process [0, 1 .. shortest - 1] { // find all the list arguments lists = filter is_list args; // what's the length of the shortest list arg? shortest = foldr1 min_pair (map len lists); // process index n ... pull that member from each argument // recurse to handle application, so we work for nested lists too process n = map_nary_list fn (map (extract n) args) { extract n arg = arg?n, is_list arg = arg; } } map_unaryl fn a = map_nary_list (list_1ary fn) [a]; map_binaryl fn a b = map_nary_list (list_2ary fn) [a, b]; /* Remove features smaller than x pixels across from an image. This used to be * rather complex ... convsep is now good enough to use. */ smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; /* Chop up an image into a list of lists of smaller images. Pad edges with * black. */ imagearray_chop tile_width tile_height hoverlap voverlap i = map chop' [0, vstep .. last_y] { width = get_width i; height = get_height i; bands = get_bands i; format = get_format i; type = get_type i; tile_width' = to_real tile_width; tile_height' = to_real tile_height; hoverlap' = to_real hoverlap; voverlap' = to_real voverlap; /* Unique pixels per tile. */ hstep = tile_width' - hoverlap'; vstep = tile_height' - voverlap'; /* Number of tiles across and down. Remember the case where width == * hstep. */ across = (int) ((width - 1) / hstep) + 1; down = (int) ((height - 1) / vstep) + 1; /* top/left of final tile. */ last_x = hstep * (across - 1); last_y = vstep * (down - 1); /* How much do we need to pad by? */ sx = last_x + tile_width'; sy = last_y + tile_height'; /* Expand image with black to pad size. */ pad = embed 0 0 0 sx sy i; /* Chop up a row. */ chop' y = map chop'' [0, hstep .. last_x] { chop'' x = extract_area x y tile_width' tile_height' pad; } } /* Reassemble image. */ imagearray_assemble hoverlap voverlap il = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il { lrj l r = insert (get_width l + hoverlap) 0 r l; tbj t b = insert 0 (get_height t + voverlap) b t; } /* Generate an nxn identity matrix. */ identity_matrix n = error "identity_matrix: n > 0", n < 1 = map line [0 .. n - 1] { line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; } /* Incomplete gamma function Q(a, x) == 1 - P(a, x) FIXME ... this is now a builtin, until we can get a nice List class (requires overloadable ':') gammq a x = error "bad args", x < 0 || a <= 0 = 1 - gamser, x < a + 1 = gammcf { gamser = (gser a x)?0; gammcf = (gcf a x)?0; } */ /* Incomplete gamma function P(a, x) evaluated as series representation. Also * return ln(gamma(a)) ... nr in c, pp 218 */ gser a x = [gamser, gln] { gln = gammln a; gamser = error "bad args", x < 0 = 0, x == 0 = 1 // fix this { // maximum iterations maxit = 100; ap = List [a + 1, a + 2 ...]; xoap = x / ap; del = map product (prefixes xoap.value); /* del = map (multiply (1 / a)) (map product (prefixes xoap)) del = xap = iterate (multiply */ /* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2, * 3], [1, 2, 3, 4] ...] */ prefixes l = map (converse take l) [1..]; } } /* ln(gamma(xx)) ... nr in c, pp 214 */ gammln xx = gln { cof = [76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5]; y = take 6 (iterate (add 1) (xx + 1)); ser = 1.000000000190015 + sum (map2 divide cof y); tmp = xx + 0.5; tmp' = tmp - ((xx + 0.5) * log tmp); gln = -tmp + log (2.5066282746310005 * ser / xx); } /* make a LUT from a scatter */ buildlut x = Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1 = im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0 = error (_ "bad arguments to " ++ "buildlut"); /* Linear regression. Return a class with the stuff we need in. * from s15.2, p 665 NR in C */ linreg xes yes = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes]; siga = (chi2 / (ss - 2)) ** 0.5 * ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5; sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5; // for compat with linregw, see below q = 1.0; } ss = len xes; sx = sum xes; sy = sum yes; sxoss = sx / ss; tes = [x - sxoss :: x <- xes]; st2 = sum [t ** 2 :: t <- tes]; } /* Weighted linear regression. Xes, yes and a list of deviations. */ linregw xes yes devs = obj { obj = class { // in case we ever get shown in the workspace _vislevel = 2; slope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2; intercept = (sy - sx * slope) / ss; chi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: [x, y, sd] <- zip3 xes yes devs]; siga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5; sigb = (1 / st2) ** 0.5; q = gammq (0.5 * (len xes - 2)) (0.5 * chi2); } wt = [sd ** -0.5 :: sd <- devs]; ss = sum wt; sx = sum [x * w :: [x, w] <- zip2 xes wt]; sy = sum [y * w :: [y, w] <- zip2 yes wt]; sxoss = sx / ss; tes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs]; st2 = sum [t ** 2 :: t <- tes]; } /* Clustering: pass in a list of points, repeatedly merge the * closest two points until no two points are closer than the threshold. * Return [merged-points, corresponding-weights]. A weight is a list of the * indexes we merged to make that point, ie. len weight == how significant * this point is. * * eg. * cluster 12 [152,154,155,42,159] == * [[155,42],[[1,2,0,4],[3]]] */ cluster thresh points = oo_unary_function cluster_op points, is_class points // can't use [0..len points - 1], in case len points == 0 = merge [points, map (converse cons []) (take (len points) [0 ..])], is_list points = error (_ "bad arguments to " ++ "cluster") { cluster_op = Operator "cluster" (cluster thresh) Operator_type.COMPOUND false; merge x = x, m < 2 || d > thresh = merge [points', weights'] { [points, weights] = x; m = len points; // generate indexes of all possible pairs, avoiding comparing a thing // to itself, and assuming that dist is reflexive // first index is always less than 2nd index // the +1,+2 makes sure we have an increasing generator, otherwise we // can get [3 .. 4] (for example), which will make a decreasing // sequence pairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]]; // distance function // arg is eg. [3,1], meaning get distance from point 3 to point 1 dist x = abs (points?i - points?j) { [i, j] = x; } // smallest distance, then the two points we merge p = minpos (map dist pairs); d = dist pairs?p; [i, j] = pairs?p; // new point and new weight nw = weights?i ++ weights?j; np = (points?i * len weights?i + points?j * len weights?j) / len nw; // remove element i from a list remove i l = take i l ++ drop (i + 1) l; // remove two old points, add the new merged one // i < j (see "pairs", above) points' = np : remove i (remove j points); weights' = nw : remove i (remove j weights); } } /* Extract the area of an image around an arrow. * Transform the image to make the arrow horizontal, then displace by hd and * vd pxels, then cut out a bit h pixels high centered on the arrow. */ extract_arrow hd vd h arrow = extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im' { // the line as a polar vector pv = polar (arrow.width, arrow.height); a = im pv; // smallest rotation that will make the line horizontal a' = 360 - a, a > 270 = 180 - a, a > 90 = -a; im' = rotate Interpolate_bilinear a' arrow.image; // look at the start and end of the arrow, pick the leftmost p = (arrow.left, arrow.top), arrow.left <= arrow.right = (arrow.right, arrow.bottom); // transform that point to im' space p' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset); } /* You'd think these would go in _convert, but they are not really colour ops, * so put them here. */ rad2float image = oo_unary_function rad2float_op image, is_class image = im_rad2float image, is_image image = error (_ "bad arguments to " ++ "rad2float") { rad2float_op = Operator "rad2float" rad2float Operator_type.COMPOUND_REWRAP false; } float2rad image = oo_unary_function float2rad_op image, is_class image = im_float2rad image, is_image image = error (_ "bad arguments to " ++ "float2rad") { float2rad_op = Operator "float2rad" float2rad Operator_type.COMPOUND_REWRAP false; } segment x = oo_unary_function segment_op x, is_class x = image', is_image x = error (_ "bad arguments to " ++ "segment") { segment_op = Operator "segment" segment Operator_type.COMPOUND_REWRAP false; [image, nsegs] = im_segment x; image' = im_copy_set_meta image "n-segments" nsegs; } point a b = oo_binary_function point_op a b, is_class a = oo_binary'_function point_op a b, is_class b = im_read_point b x y, is_image b = [b?x?y], is_matrix b = [b?x], is_real_list b && y == 0 = [b?y], is_real_list b && x == 0 = error (_ "bad arguments to " ++ "point") { point_op = Operator "point" (\a\b Vector (point a b)) Operator_type.COMPOUND false; (x, y) = a, is_complex a; = (a?0, a?1), is_real_list a && is_list_len 2 a = error "bad position format"; } /* Generate an ImageMagick (or GraphicsMagick) command suitable for * im_system_image. Use convert.exe in $VIPSHOME/bin, if it exists, otherwise * assume it's on the path somewhere. */ magick_command switch = join_sep " " [convert, "\"%s\"", switch, "\"%s\""] { prefs = Workspaces.Preferences; use_gm = prefs.USE_GRAPHICSMAGICK; name = if use_gm then "gm" else "convert"; exe = concat [name, expand "$EXEEXT"]; vipsexe = path_absolute [expand "$VIPSHOME", "bin", exe]; final_exe = vipsexe, search vipsexe != [] = exe; convert = join_sep " " [final_exe, "convert"], use_gm = final_exe; } /* Run a command on an image. See magick_command, for example. */ system_image command x = oo_unary_function system_image_op x, is_class x = system x, is_image x = error (_ "bad arguments to " ++ "system_image") { system_image_op = Operator "system_image" (system_image command) Operator_type.COMPOUND_REWRAP false; system im = image_out { [image_out, log] = im_system_image (get_image im) "%s.tif" "%s.tif" command; } } nip2-8.7.1/share/nip2/compat/7.26/Histogram.def0000644000175000017500000001474013351443023015572 00000000000000Hist_new_item = class Menupullright "_New" "new histogram" { Hist_item = class Menuaction "Histogram" "make an identity histogram" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; _result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d); } } Hist_new_from_matrix = Matrix_buildlut_item; Hist_from_image_item = class Menuaction "Ta_g Image As Histogram" "set image Type to Histogram" { action x = hist_tag x; } Tone_item = class Menuaction "_Tone Curve" "make a new tone mapping curve" { action = class _result { _vislevel = 3; d = Option "Depth" ["8 bit", "16 bit"] 0; b = Scale "Black point" 0 100 0; w = Scale "White point" 0 100 100; sp = Scale "Shadow point" 0.1 0.3 0.2; mp = Scale "Mid-tone point" 0.4 0.6 0.5; hp = Scale "Highlight point" 0.7 0.9 0.8; sa = Scale "Shadow adjust" (-15) 15 0; ma = Scale "Mid-tone adjust" (-30) 30 0; ha = Scale "Highlight adjust" (-15) 15 0; _result = tone_build fmt b w sp mp hp sa ma ha { fmt = [Image_format.UCHAR, Image_format.USHORT]?d; } } } } Hist_convert_to_hist_item = class Menuaction "Con_vert to Histogram" "convert anything to a histogram" { action x = hist_tag (to_image x); } Hist_find_item = class Menupullright "_Find" "find a histogram" { Oned_item = class Menuaction "_One Dimension" "for a n-band image, make an n-band 1D histogram" { action x = map_unary hist_find x; } Nd_item = class Menuaction "_Many Dimensions" "for a n-band image, make an n-dimensional histogram" { action x = class _result { _vislevel = 3; // default to something small-ish bins = Expression "Number of bins in each dimension" 8; _result = map_unary process x { process in = hist_find_nD bins in; } } } Indexed_item = class Menuaction "_Indexed" "use a 1-band index image to pick bins for an n-band image" { action x y = map_binary map x y { map a b = hist_find_indexed index im { [im, index] = sortc (const is_index) [a, b]; is_index x = has_image x && b == 1 && (f == Image_format.UCHAR || f == Image_format.USHORT) { im = get_image x; b = get_bands x; f = get_format x; } } } } } Hist_map_item = class Menuaction "_Map" "map an image through a histogram" { action x y = map_binary map x y { map a b = hist_map hist im { [im, hist] = sortc (const is_hist) [a, b]; } } } Hist_eq_item = Filter_enhance_item.Hist_equal_item; #separator Hist_cum_item = class Menuaction "_Integrate" "form cumulative histogram" { action x = map_unary hist_cum x; } Hist_diff_item = class Menuaction "_Differentiate" "find point-to-point differences (inverse of Integrate)" { action x = map_unary hist_diff x; } Hist_norm_item = class Menuaction "N_ormalise" "normalise a histogram" { action x = map_unary hist_norm x; } Hist_match_item = class Menuaction "Ma_tch" "find LUT which will match first histogram to second" { action in ref = map_binary hist_match in ref; } Hist_zerox_item = class Menuaction "_Zero Crossings" "find zero crossings" { action x = class _result { _vislevel = 3; edge = Option "Direction" [ "Positive-going", "Negative-going" ] 0; _result = map_unary (zerox (if edge == 0 then -1 else 1)) x; } } #separator Hist_profile_item = class Menuaction "Find _Profile" "search from image edges for non-zero pixels" { action x = class _result { _vislevel = 3; edge = Option "Search from" [ "Top edge down", "Left edge to right", "Bottom edge up", "Right edge to left" ] 2; _result = map_unary profile x { profile image = (Plot_histogram @ hist_tag) [ profilemb 0 image.value, profilemb 1 image.value, profilemb 0 (fliptb image.value), profilemb 1 (fliplr image.value) ]?edge; // im_profile only does 1 band images :-( profilemb d = bandjoin @ map (converse im_profile d) @ bandsplit; } } } Hist_project_item = class Menuaction "Find Pro_jections" "find horizontal and vertical projections" { action x = class { _vislevel = 2; _result = map_unary project x; // extract the result ... could be a group extr n = Plot_histogram _result?n, is_list _result = Group (map (Plot_histogram @ converse subscript n) _result.value); horizontal = extr 0; vertical = extr 1; centre = (gravity horizontal, gravity vertical); } } #separator Hist_graph_item = class Menuaction "P_lot Slice" "plot a slice along a guide or arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary graph x { graph arrow = hist_tag area' { area = extract_arrow displace.value vdisplace.value width.value arrow; // squish vertically to get an average area' = resize Interpolate_bilinear 1 (1 / width.value) area; } } } } Extract_arrow_item = class Menuaction "Extract _Arrow" "extract the area around an arrow" { action x = class _value { _vislevel = 3; width = Scale "Width" 1 40 1; displace = Scale "Horizontal displace" (-50) 50 0; vdisplace = Scale "Vertical displace" (-50) 50 0; _value = map_unary (extract_arrow displace.value vdisplace.value width.value) x; } } Hist_plot_item = class Menuaction "Plot _Object" "plot an object as a bar, point or line graph" { action x = class _result { _vislevel = 3; format = Option_enum "Format" Plot_format.names "YYYY"; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (image x) { options = [$style => style.value, $format => format.value] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; image x = image (extract_arrow 0 0 1 x), is_Arrow x = get_image x, has_image x = x2b im, b == 1 = im { im = get_image (to_image x); w = get_width im; h = get_height im; b = get_bands im; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { extract_col x = extract_area x 0 1 h im; } } } } } nip2-8.7.1/share/nip2/compat/7.26/Widgets.def0000644000175000017500000000235313351443023015240 00000000000000Widget_slider_item = class Menuaction "_Scale" "make a new scale widget" { icon = "nip-slider-16.png"; action = Scale "untitled scale" 0 255 128; } Widget_toggle_item = class Menuaction "_Toggle" "make a new toggle widget" { action = Toggle "untitled toggle" false; } Widget_option_item = class Menuaction "_Option" "make a new option widget" { action = Option "untitled option" ["option0", "option1"] 0; } Widget_string_item = class Menuaction "St_ring" "make a new string widget" { action = String "Enter a string" "sample text"; } Widget_number_item = class Menuaction "_Number" "make a new number widget" { action = Number "Enter a number" 42; } Widget_expression_item = class Menuaction "_Expression" "make a new expression widget" { action = Expression "Enter an expression" 42; } Widget_pathname_item = class Menuaction "_File Chooser" "make a new file chooser widget" { action = Pathname "Pick a file" "$VIPSHOME/share/$PACKAGE/data/print_test_image.v"; } Widget_font_item = class Menuaction "F_ont Chooser" "make a new font chooser widget" { action = Fontname "Pick a font" Workspaces.Preferences.PAINTBOX_FONT; } Widget_clock_item = class Menuaction "_Clock" "make a new clock widget" { action = Clock 1 1; } nip2-8.7.1/share/nip2/compat/7.26/_types.def0000644000175000017500000007003013351443023015132 00000000000000/* A list of things. Do automatic iteration of unary and binary operators on * us. * List [1, 2] + [2, 3] -> List [3, 5] * hd (List [2, 3]) -> 2 * List [] == [] -> true */ List value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ [apply2 op value x', op.op_name == "subscript" || op.op_name == "subscript'" || op.op_name == "equal" || op.op_name == "equal'"], [this.List (apply2 op value x'), op.op_name == "join" || op.op_name == "join'"], [this.List (map2 (apply2 op) value x'), is_list x'], [this.List (map (apply2 op' x) value), true] ] ++ super.oo_binary_table op x { op' = oo_converse op; // strip the List wrapper, if any x' = x.value, is_List x = x; apply2 op x1 x2 = oo_binary_function op x1 x2, is_class x1 = oo_binary'_function op x1 x2, is_class x2 = op.fn x1 x2; }; oo_unary_table op = [ [apply value, op.op_name == "hd" || op.op_name == "tl"], [this.List (map apply value), true] ] ++ super.oo_unary_table op { apply x = oo_unary_function op x, is_class x = op.fn x; } } /* A group of things. Loop the operation over the group. */ Group value = class _Object { _check_args = [ [value, "value", check_list] ]; // methods oo_binary_table op x = [ // if_then_else is really a trinary operator [map_trinary ite this x?0 x?1, op.op_name == "if_then_else"], [map_binary op.fn this x, is_Group x], [map_unary (\a op.fn a x) this, true] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [map_unary op.fn this, true] ] ++ super.oo_unary_table op; // we can't call map_trinary directly, since it uses Group and we // don't support mutually recursive top-level functions :-( // copy-paste it here, keep in sync with the version in _stdenv map_nary fn args = fn args, groups == [] = Group (map process [0, 1 .. shortest - 1]) { groups = filter is_Group args; shortest = foldr1 min_pair (map (len @ get_value) groups); process n = NULL, any (map (is_noval n) args) = map_nary fn (map (extract n) args) { extract n arg = arg.value?n, is_Group arg = arg; is_noval n arg = is_Group arg && arg.value?n == NULL; } } // need ite as a true trinary ite a b c = if a then b else c; map_unary fn a = map_nary (list_1ary fn) [a]; map_binary fn a b = map_nary (list_2ary fn) [a, b]; map_trinary fn a b c = map_nary (list_3ary fn) [a, b, c]; } /* Single real number ... eg slider. */ Real value = class _Object { _check_args = [ [value, "value", check_real] ]; // methods oo_binary_table op x = [ [this.Real (op.fn this.value x.value), is_Real x && op.type == Operator_type.ARITHMETIC], [this.Real (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], [op.fn this.value x.value, is_Real x && op.type == Operator_type.RELATIONAL], [op.fn this.value x, !is_class x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Real (op.fn this.value), op.type == Operator_type.ARITHMETIC], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* Single bool ... eg Toggle. */ Bool value = class _Object { _check_args = [ [value, "value", check_bool] ]; // methods oo_binary_table op x = [ [op.fn this.value x, op.op_name == "if_then_else"], [this.Bool (op.fn this.value x.value), is_Bool x], [this.Bool (op.fn this.value x), is_bool x] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [this.Bool (op.fn this.value), op.type == Operator_type.ARITHMETIC || op.type == Operator_type.RELATIONAL], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* An editable string. */ String caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable real number. */ Number caption value = class scope.Real value { _check_args = [ [caption, "caption", check_string] ]; Real x = this.Number caption x; } /* An editable expression. */ Expression caption expr = class (if is_class expr then expr else _Object) { _check_args = [ [caption, "caption", check_string], [expr, "expr", check_any] ]; } /* A ticking clock. */ Clock interval value = class scope.Real value { _check_args = [ [interval, "interval", check_real] ]; Real x = this.Clock interval x; } /* An editable filename. */ Pathname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* An editable fontname. */ Fontname caption value = class _Object { _check_args = [ [caption, "caption", check_string], [value, "value", check_string] ]; } /* Vector type ... just a finite list of real. Handy for wrapping an * argument to eg. im_lintra_vec. Make it behave like a single pixel image. */ Vector value = class _Object { _check_args = [ [value, "value", check_real_list] ]; bands = len value; // methods oo_binary_table op x = [ // Vector ++ Vector means bandwise join [this.Vector (op.fn this.value x.value), is_Vector x && (op.op_name == "join" || op.op_name == "join'")], [this.Vector (op.fn this.value [get_number x]), has_number x && (op.op_name == "join" || op.op_name == "join'")], // Vector ? number means extract element [op.fn this.value (get_real x), has_real x && (op.op_name == "subscript" || op.op_name == "subscript'")], // extra check for lengths equal [this.Vector (map_binaryl op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.ARITHMETIC], [this.Vector (map_binaryl op.fn this.value (get_real x)), has_real x && op.type == Operator_type.ARITHMETIC], // need extra length check [this.Vector (map bool_to_real (map_binaryl op.fn this.value x.value)), is_Vector x && len value == len x.value && op.type == Operator_type.RELATIONAL], [this.Vector (map bool_to_real (map_binaryl op.fn this.value (get_real x))), has_real x && op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value x.value), is_Vector x && len value == len x.value && op.type == Operator_type.COMPOUND_REWRAP], [x.Image (vec op'.op_name x.value value), is_Image x], [vec op'.op_name x value, is_image x], [op.fn this.value x, is_real x] ] ++ super.oo_binary_table op x { op' = oo_converse op; }; oo_unary_table op = [ [this.Vector (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Vector (map bool_to_real (map_unaryl op.fn this.value)), op.type == Operator_type.RELATIONAL], [this.Vector (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; // turn an ip bool (or a number, for Vector) into VIPSs 255/0 bool_to_real x = 255, is_bool x && x = 255, is_number x && x != 0 = 0; } /* A rectangular array of real. */ Matrix_base value = class _Object { _check_args = [ [value, "value", check_matrix] ]; // calculate these from value width = len value?0; height = len value; // extract a rectanguar area extract left top width height = this.Matrix_base ((map (take width) @ map (drop left) @ take height @ drop top) value); // methods oo_binary_table op x = [ // mat multiply is special [this.Matrix_base mul.value, is_Matrix x && op.op_name == "multiply"], [this.Matrix_base mul'.value, is_Matrix x && op.op_name == "multiply'"], // mat divide is also special [this.Matrix_base div.value, is_Matrix x && op.op_name == "divide"], [this.Matrix_base div'.value, is_Matrix x && op.op_name == "divide'"], // power -1 means invert [this.Matrix_base inv.value, is_real x && x == -1 && op.op_name == "power"], [this.Matrix_base sq.value, is_real x && x == 2 && op.op_name == "power"], [error "matrix **-1 and **2 only", op.op_name == "power" || op.op_name == "power'"], // matrix op vector ... treat a vector as a 1 row matrix [this.Matrix_base (map (map_binaryl op'.fn x.value) this.value), is_Vector x && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x.value), (is_Matrix x || is_Real x) && op.type == Operator_type.ARITHMETIC], [this.Matrix_base (map_binaryl op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC], // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value x, op.type == Operator_type.COMPOUND] ] ++ super.oo_binary_table op x { mul = im_matmul this x; mul' = im_matmul x this; div = im_matmul this (im_matinv x); div' = im_matmul x (im_matinv this); inv = im_matinv this; sq = im_matmul this this; op' = oo_converse op; } oo_unary_table op = [ [this.Matrix_base (map_unaryl op.fn this.value), op.type == Operator_type.ARITHMETIC], [this.Matrix_base (op.fn this.value), op.type == Operator_type.COMPOUND_REWRAP], [op.fn this.value, true] ] ++ super.oo_unary_table op; } /* How to display a matrix: text, sliders, toggles, or text plus scale/offset. */ Matrix_display = class { text = 0; slider = 1; toggle = 2; text_scale_offset = 3; is_display = member [text, slider, toggle, text_scale_offset]; } /* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add * a display type as well to control how the widget renders. */ Matrix_vips value scale offset filename display = class scope.Matrix_base value { _check_args = [ [scale, "scale", check_real], [offset, "offset", check_real], [filename, "filename", check_string], [display, "display", check_matrix_display] ]; Matrix_base x = this.Matrix_vips x scale offset filename display; } /* A plain 'ol matrix which can be passed to VIPS. */ Matrix value = class Matrix_vips value 1 0 "" Matrix_display.text {} /* Specialised constructors ... for convolutions, recombinations and * morphologies. */ Matrix_con scale offset value = class Matrix_vips value scale offset "" Matrix_display.text_scale_offset {}; Matrix_rec value = class Matrix_vips value 1 0 "" Matrix_display.slider {}; Matrix_mor value = class Matrix_vips value 1 0 "" Matrix_display.toggle {}; Matrix_file filename = (im_read_dmask @ expand @ search) filename; /* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc) */ Colour colour_space value = class scope.Vector value { _check_args = [ [colour_space, "colour_space", check_colour_space] ]; _check_all = [ [is_list_len 3 value, "len value == 3"] ]; Vector x = this.Colour colour_space x; // make a colour-ish thing from an image // back to Colour if we have another 3 band image // to a vector if bands > 1 // to a number otherwise itoc im = this.Colour nip_type (to_matrix im).value?0, bands == 3 = scope.Vector (map mean (bandsplit im)), bands > 1 = mean im { type = get_header "Type" im; bands = get_header "Bands" im; nip_type = Image_type.colour_spaces.lookup 1 0 type; } // methods oo_binary_table op x = [ [itoc (op.fn ((float) (to_image this).value) ((float) (to_image x).value)), // here REWRAP means go via image op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_binary_table op x; oo_unary_table op = [ [itoc (op.fn ((float) (to_image this).value)), op.type == Operator_type.COMPOUND_REWRAP] ] ++ super.oo_unary_table op; } // a subclass with widgets for picking a space and value Colour_picker default_colour default_value = class Colour space.item colour.expr { _vislevel = 3; space = Option_enum "Colour space" Image_type.colour_spaces default_colour; colour = Expression "Colour value" default_value; Colour_edit colour_space value = Colour_picker colour_space value; } /* Base scale type. */ Scale caption from to value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [from, "from", check_real], [to, "to", check_real] ]; _check_all = [ [from < to, "from < to"] ]; Real x = this.Scale caption from to x; // methods oo_binary_table op x = [ [this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to) (op.fn this.value x.value), is_Scale x && op.type == Operator_type.ARITHMETIC], [this.Scale caption (op.fn this.from x) (op.fn this.to x) (op.fn this.value x), is_real x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x; } /* Base toggle type. */ Toggle caption value = class scope.Bool value { _check_args = [ [caption, "caption", check_string], [value, "value", check_bool] ]; Bool x = this.Toggle caption x; } /* Base option type. */ Option caption labels value = class scope.Real value { _check_args = [ [caption, "caption", check_string], [labels, "labels", check_string_list], [value, "value", check_uint] ]; } /* An option whose value is a string rather than a number. */ Option_string caption labels item = class Option caption labels (index (equal item) labels) { Option_edit caption labels value = this.Option_string caption labels (labels?value); } /* Make an option from an enum. */ Option_enum caption enum item = class Option_string caption enum.names item { // corresponding thing value_thing = enum.get_thing item; Option_edit caption labels value = this.Option_enum caption enum (enum.names?value); } /* A rectangle. width and height can be -ve. */ Rect left top width height = class _Object { _check_args = [ [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; // derived right = left + width; bottom = top + height; oo_binary_table op x = [ [equal x, is_Rect x && (op.op_name == "equal" || op.op_name == "equal'")], [!equal x, is_Rect x && (op.op_name == "not_equal" || op.op_name == "not_equal'")], // binops with a complex are the same as (comp op comp) [oo_binary_function op this (Rect (re x) (im x) 0 0), is_complex x], // all others are just pairwise [this.Rect left' top' width' height', is_Rect x && op.type == Operator_type.ARITHMETIC], [this.Rect left'' top'' width'' height'', has_number x && op.type == Operator_type.ARITHMETIC] ] ++ super.oo_binary_table op x { left' = op.fn left x.left; top' = op.fn top x.top; width' = op.fn width x.width; height' = op.fn height x.height; left'' = op.fn left x'; top'' = op.fn top x'; width'' = op.fn width x'; height'' = op.fn height x'; x' = get_number x; } oo_unary_table op = [ // arithmetic uops just map [this.Rect left' top' width' height', op.type == Operator_type.ARITHMETIC], // compound uops are just like ops on complex // do (width, height) so thing like abs(Arrow) work as you'd expect [op.fn (width, height), op.type == Operator_type.COMPOUND] ] ++ super.oo_unary_table op { left' = op.fn left; top' = op.fn top; width' = op.fn width; height' = op.fn height; } // empty? ie. contains no pixels is_empty = width == 0 || height == 0; // normalised version, ie. make width/height +ve and flip the origin nleft = left + width, width < 0 = left; ntop = top + height, height < 0 = top; nwidth = abs width; nheight = abs height; nright = nleft + nwidth; nbottom = ntop + nheight; equal x = left == x.left && top == x.top && width == x.width && height == x.height; // contains a point? includes_point x y = nleft <= x && x <= nright && ntop <= y && y <= nbottom; // contains a rect? just test top left and bottom right points includes_rect r = includes_point r.nleft r.ntop && includes_point r.nright r.nbottom; // bounding box of two rects // if either is empty, can just return the other union r = r, is_empty = this, r.is_empty = Rect left' top' width' height' { left' = min_pair nleft r.nleft; top' = min_pair ntop r.ntop; width' = max_pair nright r.nright - left'; height' = max_pair nbottom r.nbottom - top'; } // intersection of two rects ... empty rect if no intersection intersect r = Rect left' top' width'' height'' { left' = max_pair nleft r.nleft; top' = max_pair ntop r.ntop; width' = min_pair nright r.nright - left'; height' = min_pair nbottom r.nbottom - top'; width'' = width', width > 0 = 0; height'' = height', height > 0 = 0; } // expand/collapse by n pixels margin_adjust n = Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n); } /* Values for Compression field in image. */ Image_compression = class { NONE = 0; NO_COMPRESSION = 0; TCSF_COMPRESSION = 1; JPEG_COMPRESSION = 2; LABPACK_COMPRESSED = 3; RGB_COMPRESSED = 4; LUM_COMPRESSED = 5; } /* Values for Coding field in image. */ Image_coding = class { NONE = 0; NOCODING = 0; COLQUANT = 1; LABPACK = 2; RAD = 6; } /* Values for BandFmt field in image. */ Image_format = class { DPCOMPLEX = 9; DOUBLE = 8; COMPLEX = 7; FLOAT = 6; INT = 5; UINT = 4; SHORT = 3; USHORT = 2; CHAR = 1; UCHAR = 0; NOTSET = -1; maxval fmt = [ 255, // UCHAR 127, // CHAR 65535, // USHORT 32767, // SHORT 4294967295, // UINT 2147483647, // INT 255, // FLOAT 255, // COMPLEX 255, // DOUBLE 255 // DPCOMPLEX ] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX = error (_ "bad value for BandFmt"); } /* A lookup table. */ Table value = class _Object { _check_args = [ [value, "value", check_rectangular] ]; /* Extract a column. */ column n = map (extract n) value; /* present col x: is there an x in column col */ present col x = member (column col) x; /* Look on column from, return matching item in column to. */ lookup from to x = value?n?to, n >= 0 = error (_ "item" ++ " " ++ print x ++ " " ++ _ "not in table") { n = index (equal x) (column from); } } /* A two column lookup table with the first column a string and the second a * thing. Used for representing various enums. Option_enum makes a selector * from one of these. */ Enum value = class Table value { _check_args = [ [value, "value", check_enum] ] { check_enum = [is_enum, _ "is [[char, *]]"]; is_enum x = is_rectangular x && is_listof is_string (map (extract 0) x); } // handy ... all the names and things as lists names = this.column 0; things = this.column 1; // is a legal name or thing has_name x = this.present 1 x; has_thing x = this.present 0 x; // map things to strings and back get_name x = this.lookup 1 0 x; get_thing x = this.lookup 0 1 x; } /* Type field. */ Image_type = class { MULTIBAND = 0; B_W = 1; LUMINANCE = 2; XRAY = 3; IR = 4; YUV = 5; RED_ONLY = 6; GREEN_ONLY = 7; BLUE_ONLY = 8; POWER_SPECTRUM = 9; HISTOGRAM = 10; LUT = 11; XYZ = 12; LAB = 13; CMC = 14; CMYK = 15; LABQ = 16; RGB = 17; UCS = 18; LCH = 19; LABS = 21; sRGB = 22; YXY = 23; FOURIER = 24; RGB16 = 25; GREY16 = 26; /* Table to get names <-> numbers. */ type_names = Enum [ $MULTIBAND => MULTIBAND, $B_W => B_W, $LUMINANCE => LUMINANCE, $XRAY => XRAY, $IR => IR, $YUV => YUV, $RED_ONLY => RED_ONLY, $GREEN_ONLY => GREEN_ONLY, $BLUE_ONLY => BLUE_ONLY, $POWER_SPECTRUM => POWER_SPECTRUM, $HISTOGRAM => HISTOGRAM, $LUT => LUT, $XYZ => XYZ, $LAB => LAB, $CMC => CMC, $CMYK => CMYK, $LABQ => LABQ, $RGB => RGB, $UCS => UCS, $LCH => LCH, $LABS => LABS, $sRGB => sRGB, $YXY => YXY, $FOURIER => FOURIER, $RGB16 => RGB16, $GREY16 => GREY16 ]; /* Table relating nip's colour space names and VIPS's Type numbers. * Options generated from this, so match the order to the order in the * Colour menu. */ colour_spaces = Enum [ $sRGB => sRGB, $Lab => LAB, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; /* A slightly larger table ... the types of colorimetric image we can * have. Add mono, and the S and Q forms of LAB. */ image_colour_spaces = Enum [ $Mono => B_W, $sRGB => sRGB, $RGB16 => RGB16, $GREY16 => GREY16, $Lab => LAB, $LabQ => LABQ, $LabS => LABS, $LCh => LCH, $XYZ => XYZ, $Yxy => YXY, $UCS => UCS ]; } /* Base image type. Simple layer over vips_image. */ Image value = class _Object { _check_args = [ [value, "value", check_image] ]; // fields from VIPS header width = get_width value; height = get_height value; bands = get_bands value; format = get_format value; bits = get_bits value; coding = get_coding value; type = get_type value; xres = get_header "Xres" value; yres = get_header "Yres" value; xoffset = get_header "Xoffset" value; yoffset = get_header "Yoffset" value; filename = get_header "filename" value; // convenience ... the area our pixels occupy, as a rect rect = Rect 0 0 width height; // operator overloading // (op Image Vector) done in Vector class oo_binary_table op x = [ // handle image ++ constant here [wrap join_result_image, (has_real x || is_Vector x) && (op.op_name == "join" || op.op_name == "join'")], [wrap ite_result_image, op.op_name == "if_then_else"], [wrap (op.fn this.value (get_image x)), has_image x], [wrap (op.fn this.value (get_number x)), has_number x], // if it's not a class on the RHS, handle here ... just apply and // rewrap [wrap (op.fn this.value x), !is_class x] // all other cases handled by other classes ] ++ super.oo_binary_table op x { // wrap the result with this // x can be a non-image, eg. compare "Image v == []" vs. // "Image v == 12" wrap x = x, op.type == Operator_type.COMPOUND || !is_image x = this.Image x; join_result_image = value ++ new_stuff, op.op_name == "join" = new_stuff ++ value { new_stuff = image_new width height new_bands format coding Image_type.B_W x xoffset yoffset; new_bands = get_bands x, has_bands x = 1; } [then_part, else_part] = x; // get things about our output from inputs in this order objects = [then_part, else_part, this]; // properties of our output image target_bands = get_member_list has_bands get_bands objects; target_type = get_member_list has_type get_type objects; // if one of then/else is an image, get the target format from that // otherwise, let the non-image objects set the target target_format = get_member_list has_format get_format x, has_member_list has_format x = NULL; to_image x = to_image_size width height target_bands target_format x; [then', else'] = map to_image x; ite_result_image = image_set_type target_type (if value then then' else else'); } // FIXME ... yuk ... don't use operator hints, just always rewrap if // we have an image result // forced on us by things like abs: // abs Vector -> real // abs Image -> Image // does not fit well with COMPOUND/whatever scheme oo_unary_table op = [ [this.Image result, is_image result], [result, true] ] ++ super.oo_unary_table op { result = op.fn this.value; } } /* Construct an image from a file. */ Image_file filename = class Image value { _check_args = [ [filename, "filename", check_string] ]; value = vips_image filename; } Region image left top width height = class Image value { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_preal], [height, "height", check_preal] ]; // a rect for our coordinates // region.rect gets the rect for the extracted image region_rect = Rect left top width height; // we need to always succeed ... value is our enclosing image if we're // out of bounds value = extract_area left top width height image.value, image.rect.includes_rect region_rect = image.value; } Area image left top width height = class scope.Region image left top width height { Region image left top width height = this.Area image left top width height; } Arrow image left top width height = class scope.Rect left top width height { _check_args = [ [image, "Image", check_Image], [left, "left", check_real], [top, "top", check_real], [width, "width", check_real], [height, "height", check_real] ]; Rect l t w h = this.Arrow image l t w h; } HGuide image top = class scope.Arrow image image.rect.left top image.width 0 { Arrow image left top width height = this.HGuide image top; } VGuide image left = class scope.Arrow image left image.rect.top 0 image.height { Arrow image left top width height = this.VGuide image left; } Mark image left top = class scope.Arrow image left top 0 0 { Arrow image left top width height = this.Mark image left top; } // convenience functions: ... specify position as [0 .. 1) Region_relative image u v w h = Region image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Area_relative image u v w h = Area image (image.width * u) (image.height * v) (image.width * w) (image.height * h); Arrow_relative image u v w h = Arrow image (image.width * u) (image.height * v) (image.width * w) (image.height * h); VGuide_relative image v = VGuide image (image.height * v); HGuide_relative image u = HGuide image (image.width * u); Mark_relative image u v = Mark image (image.width * u) (image.height * v); Interpolate_type = class { NEAREST_NEIGHBOUR = 0; BILINEAR = 1; BICUBIC = 2; LBB = 3; NOHALO = 4; VSQBS = 5; // Should introspect to get the list of interpolators :-( // We can "dir" on VipsInterpolate to get a list of them, but we // can't get i18n'd descriptions until we have more // introspection stuff in nip2. /* Table to map interpol numbers to descriptive strings */ descriptions = [ _ "Nearest neighbour", _ "Bilinear", _ "Bicubic", _ "Upsize: reduced halo bicubic (LBB)", _ "Upsharp: reduced halo bicubic with edge sharpening (Nohalo)", _ "Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)" ]; /* And to vips type names. */ types = [ "VipsInterpolateNearest", "VipsInterpolateBilinear", "VipsInterpolateBicubic", "VipsInterpolateLbb", "VipsInterpolateNohalo", "VipsInterpolateVsqbs" ]; } Interpolate type options = class { value = vips_object_new Interpolate_type.types?type [] options; } Interpolate_bilinear = Interpolate Interpolate_type.BILINEAR []; Interpolate_picker default = class Interpolate interp.value [] { _vislevel = 2; interp = Option "Interpolation" Interpolate_type.descriptions default; } Render_intent = class { PERCEPTUAL = 0; RELATIVE = 1; SATURATION = 2; ABSOLUTE = 3; /* Table to get names <-> numbers. */ names = Enum [ _ "Perceptual" => PERCEPTUAL, _ "Relative" => RELATIVE, _ "Saturation" => SATURATION, _ "Absolute" => ABSOLUTE ]; } // abstract base class for toolkit menus Menu = class {} // a "----" line in a menu Menuseparator = class Menu {} // abstract base class for items in menus Menuitem label tooltip = class Menu {} Menupullright label tooltip = class Menuitem label tooltip {} Menuaction label tooltip = class Menuitem label tooltip {} /* Plots. */ Plot_style = class { POINT = 0; LINE = 1; SPLINE = 2; BAR = 3; names = Enum [ _ "Point" => POINT, _ "Line" => LINE, _ "Spline" => SPLINE, _ "Bar" => BAR ]; } Plot_format = class { YYYY = 0; XYYY = 1; XYXY = 2; names = Enum [ _ "YYYY" => YYYY, _ "XYYY" => XYXY, _ "XYXY" => XYXY ]; } Plot_type = class { /* Lots of Ys (ie. multiple line plots). */ YYYY = 0; /* First column of matrix is X position, others are Ys (ie. multiple XY * line plots, all with the same Xes). */ XYYY = 1; /* Many independent XY plots. */ XYXY = 2; } /* "options" is a list of ["key", value] pairs. */ Plot options value = class scope.Image value { Image value = this.Plot options value; } Plot_matrix options value = class Plot options (to_image value).value { } Plot_histogram value = class scope.Plot [] value { } Plot_xy value = class scope.Plot [$format => Plot_format.XYYY] value { } /* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate * empty slots, for example. */ NULL = class _Object { oo_binary_table op x = [ // the only operation we allow is equality .. use pointer equality, // this lets us test a == NULL and a != NULL [this === x, op.type == Operator_type.RELATIONAL && op.op_name == "equal"], [this !== x, op.type == Operator_type.RELATIONAL && op.op_name == "not_equal"] ] ++ super.oo_binary_table op x; } nip2-8.7.1/share/nip2/compat/7.26/Matrix.def0000644000175000017500000002433413351443023015101 00000000000000 Matrix_build_item = class Menupullright "_New" "make a new matrix of some sort" { Plain_item = class Menuaction "_Plain" "make a new plain matrix widget" { action = Matrix (identity_matrix 3); } Convolution_item = class Menuaction "_Convolution" "make a new convolution matrix widget" { action = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]]; } Recombination_item = class Menuaction "_Recombination" "make a new recombination matrix widget" { action = Matrix_rec (identity_matrix 3); } Morphology_item = class Menuaction "_Morphology" "make a new morphology matrix widget" { action = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]]; } sep1 = Menuseparator; Matrix_identity_item = class Menuaction "_Identity" "make an identity matrix" { action = class _result { _vislevel = 3; s = Expression "Size" 5; _result = Matrix (identity_matrix s.expr); } } Matrix_series_item = class Menuaction "_Series" "make a series" { action = class _result { _vislevel = 3; s = Expression "Start value" 0; t = Expression "Step by" 1; e = Expression "End value" 5; _result = Matrix (transpose [series]) { series = [to_real s, to_real t.. to_real e]; } } } Matrix_square_item = class Menuaction "_Square" "make a square matrix" { action = class _result { _vislevel = 3; s = Expression "Size" 5; _result = Matrix_con (s.expr ** 2) 0 square { line = take s.expr [1, 1 ..]; square = replicate s.expr line; } } } Matrix_circular_item = class Menuaction "_Circular" "make a circular matrix" { action = class _result { _vislevel = 3; r = Expression "Radius" 5; _result = Matrix_con (sum circle) 0 circle { line = [-r.expr .. r.expr]; xes = replicate (2 * r.expr + 1) line; yes = transpose xes; circle = map2 (map2 pyth) xes yes { pyth a b = 1, (a**2 + b**2) ** 0.5 <= r.expr = 0; } } } } Matrix_gaussian_item = class Menuaction "_Gaussian" "make a gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1; ma = Scale "Minimum amplitude" 0 1 0.2; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_gauss_imask, integer = im_gauss_dmask; } } } Matrix_laplacian_item = class Menuaction "_Laplacian" "make the Laplacian of a Gaussian matrix" { action = class _result { _vislevel = 3; s = Scale "Sigma" 0.001 10 1.5; ma = Scale "Minimum amplitude" 0 1 0.1; integer = Toggle "Integer" false; _result = fn s.value ma.value { fn = im_log_imask, integer = im_log_dmask; } } } } Matrix_to_matrix_item = class Menuaction "Con_vert to Matrix" "convert anything to a matrix" { action x = to_matrix x; } #separator Matrix_extract_item = class Menupullright "_Extract" "extract rows or columns from a matrix" { Rows_item = class Menuaction "_Rows" "extract rows" { action x = class _result { _vislevel = 3; first = Expression "Extract from row" 0; number = Expression "Extract this many rows" 1; _result = map_unary process x { process x = extract_area 0 first (get_width x) number x; } } } Columns_item = class Menuaction "_Columns" "extract columns" { action x = class _result { _vislevel = 3; first = Expression "Extract from column" 0; number = Expression "Extract this many columns" 1; _result = map_unary process x { process mat = extract_area first 0 number (get_height x) x; } } } Area_item = class Menuaction "_Area" "extract area" { action x = class _result { _vislevel = 3; left = Expression "First column" 0; top = Expression "First row" 0; width = Expression "Number of columns" 1; height = Expression "Number of rows" 1; _result = map_unary process x { process mat = extract_area left top width height x; } } } Diagonal_item = class Menuaction "_Diagonal" "extract diagonal" { action x = class _result { _vislevel = 3; which = Option "Extract" [ "Leading Diagonal", "Trailing Diagonal" ] 0; _result = map_unary process x { process mat = mat.Matrix_base (map2 extr [0..] mat.value), which == 0 = mat.Matrix_base (map2 extr [mat.width - 1, mat.width - 2 .. 0] mat.value); extr n l = [l?n]; } } } } Matrix_insert_item = class Menupullright "_Insert" "insert rows or columns into a matrix" { // make a new 8-bit uchar image of wxh with pixels set to p // use to generate new cells newim w h p = image_new w h 1 Image_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0; Rows_item = class Menuaction "_Rows" "insert rows" { action x = class _result { _vislevel = 3; first = Expression "Insert at row" 0; number = Expression "Insert this many rows" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_tb (concat [top, new, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim w number item.expr)]; bottom = [extract_area 0 f w (h - f) x], f < h = []; f = to_real first; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "insert columns" { action x = class _result { _vislevel = 3; first = Expression "Insert at column" 0; number = Expression "Insert this many columns" 1; item = Expression "Set new cells to" 0; _result = map_unary process x { process x = foldl1 join_lr (concat [left, new, right]) { left = [extract_area 0 0 f h x], f > 0 = []; new = [(if is_Matrix x then to_matrix else id) (newim number h item.expr)]; right = [extract_area f 0 (w - f) h x], f < w = []; f = to_real first; w = get_width x; h = get_height x; } } } } } Matrix_delete_item = class Menupullright "_Delete" "delete rows or columns from a matrix" { // remove number of items, starting at first delete first number l = take (to_real first) l ++ drop (to_real first + to_real number) l; Rows_item = class Menuaction "_Rows" "delete rows" { action x = class _result { _vislevel = 3; first = Expression "Delete from row" 0; number = Expression "Delete this many rows" 1; _result = map_unary process x { process x = foldl1 join_tb (concat [top, bottom]) { top = [extract_area 0 0 w f x], f > 0 = []; bottom = [extract_area 0 b w (h - b) x], b < h = []; f = to_real first; n = to_real number; b = f + n; w = get_width x; h = get_height x; } } } } Columns_item = class Menuaction "_Columns" "delete columns" { action x = class _result { _vislevel = 3; first = Expression "Delete from column" 0; number = Expression "Delete this many columns" 1; _result = map_unary process x { process x = foldl1 join_lr (concat [left, right]) { left = [extract_area 0 0 f h x], f > 0 = []; right = [extract_area r 0 (w - r) h x], r < w = []; f = to_real first; n = to_real number; r = f + n; w = get_width x; h = get_height x; } } } } } Matrix_join = class Menupullright "_Join" "join two matricies" { Left_right_item = class Menuaction "_Left to Right" "join two matricies left-right" { action a b = map_binary join_lr a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "joiin two matricies top-bottom" { action a b = map_binary join_tb a b; } } Matrix_rotate_item = class Menupullright "_Rotate" "clockwise rotation by fixed angles" { rot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item; rot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item; rot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item; Matrix_rot45_item = class Menuaction "_45 Degrees" "45 degree rotate (square, odd-length-sides only)" { action x = map_unary rot45 x; } } Matrix_flip_item = Image_transform_item.Flip_item; Matrix_sort_item = class Menuaction "_Sort" "sort by column or row" { action x = class _result { _vislevel = 3; o = Option (_ "Orientation") [ _ "Sort by column", _ "Sort by row" ] 0; i = Expression (_ "Sort on index") 0; d = Option (_ "Direction") [ _ "Ascending", _ "Descending" ] 0; _result = map_unary sort x { idx = to_real i; pred a b = a?idx <= b?idx, d == 0 = a?idx >= b?idx; sort x = (x.Matrix_base @ sortc pred) x.value, o == 0 = (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value; } } } #separator Matrix_invert_item = class Menuaction "In_vert" "calculate inverse matrix" { action x = map_unary (converse power (-1)) x; } Matrix_transpose_item = class Menuaction "_Transpose" "swap rows and columns" { action x = map_unary transpose x; } #separator Matrix_plot_scatter_item = class Menuaction "_Plot Scatter" "plot a scatter graph of a matrix of [x,y1,y2,..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _vislevel = 3; auto = Toggle "Auto Range" true; xmin = Expression "X range minimum" 0; xmax = Expression "X range maximum" 1; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options ((x2b @ get_image @ to_image) x) { options = [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ range; range = [], auto = [$xmin => xmin.expr, $xmax => xmax.expr, $ymin => ymin.expr, $ymax => ymax.expr]; // matrix to image makes a 1-band mxn image // we need to put columns into bands x2b im = bandjoin (map extract_col [0 .. w - 1]) { w = get_width im; h = get_height im; b = get_bands im; extract_col x = extract_area x 0 1 h im; } } } } Matrix_plot_item = Hist_plot_item; Matrix_buildlut_item = class Menuaction "_Build LUT From Scatter" "make a lookup table from a matrix of [x,y1,y2..] coordinates" { action x = class _result { _check_args = [ [x, "x", check_Matrix] ]; _result = buildlut x; } } nip2-8.7.1/share/nip2/compat/7.26/Tasks.def0000644000175000017500000006321313351443023014721 00000000000000Tasks_capture_item = class Menupullright "_Capture" "useful stuff for capturing and preprocessing images" { Csv_import_item = class Menuaction "_CSV Import" "read a file of comma-separated values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; start_line = Expression "Start at line" 1; rows = Expression "Lines to read (-1 for whole file)" (-1); whitespace = String "Whitespace characters" " \""; separator = String "Separator characters" ",;\t"; _result = Image blank, path.value == "empty" = Image (im_csv2vips filename) { filename = search (expand path.value) ++ ":" ++ "skip:" ++ print (start_line.expr - 1) ++ "," ++ "whi:" ++ escape whitespace.value ++ "," ++ "sep:" ++ escape separator.value ++ "," ++ "line:" ++ print rows.expr; // prefix any ',' with a '\' in the separators line escape x = foldr prefix [] x { prefix x l = '\\' : x : l, x == ',' = x : l; } blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } Raw_import_item = class Menuaction "_Raw Import" "read a file of binary values" { action = class _result { _vislevel = 3; path = Pathname "File to load" "empty"; across = Expression "Pixels across" 100; down = Expression "Pixels down" 100; bytes = Expression "Bytes per pixel" 3; skip = Expression "Skip over initial bytes" 0; _result = Image blank, path.value == "empty" = Image (im_binfile path.value across.expr down.expr bytes.expr skip.expr) { blank = image_new 1 1 1 Image_format.DOUBLE Image_coding.NOCODING Image_type.B_W 0 0 0; } } } // interpret Analyze header for layout and calibration Analyze7_header_item = class Menuaction "_Interpret Analyze 7 Header" "examine the Analyze header and set layout and value" { action x = x''' { // read bits of header dim n = get_header ("dsr-image_dimension.dim[" ++ print n ++ "]"); dim0 = dim 0 x; dim1 = dim 1 x; dim2 = dim 2 x; dim3 = dim 3 x; dim4 = dim 4 x; dim5 = dim 5 x; dim6 = dim 6 x; dim7 = dim 7 x; glmax = get_header "dsr-image_dimension.glmax" x; cal_max = get_header "dsr-image_dimension.cal_max" x; // oops, now a nop x' = x; // lay out higher dimensions width-ways x'' = grid dim2 dim3 1 x', dim0 == 3 = grid dim2 dim3 dim4 x', dim0 == 4 = grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5 = grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6 = grid (dim2 * dim4 * dim6) dim7 1 (grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', dim0 == 7 = error (_ "unsupported dimension " ++ dim0); // multiply by scale factor to get kBeq x''' = x'' * (cal_max / glmax); } } Video_item = class Menuaction "Capture _Video Frame" "capture a frame of still video" { // shortcut to prefs prefs = Workspaces.Preferences; action = class _result { _vislevel = 3; device = prefs.VIDEO_DEVICE; channel = Option "Input channel" [ "TV", "Composite 1", "Composite 2", "Composite 3" ] prefs.VIDEO_CHANNEL; b = Scale "Brightness" 0 32767 prefs.VIDEO_BRIGHTNESS; col = Scale "Colour" 0 32767 prefs.VIDEO_COLOUR; con = Scale "Contrast" 0 32767 prefs.VIDEO_CONTRAST; hue = Scale "Hue" 0 32767 prefs.VIDEO_HUE; frames = Scale "Frames to average" 0 100 prefs.VIDEO_FRAMES; mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; crop = Toggle "Crop image" prefs.VIDEO_CROP; // grab, but hide it ... if we let the crop edit _raw_grab = Image (im_video_v4l1 device channel.value b.value col.value con.value hue.value frames.value); edit_crop = Region _raw_grab left top width height { left = prefs.VIDEO_CROP_LEFT; top = prefs.VIDEO_CROP_TOP; width = min_pair prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); height = min_pair prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); } aspect_ratio = Expression "Stretch vertically by" prefs.VIDEO_ASPECT; _result = frame' { frame = edit_crop, crop = _raw_grab; frame' = colour_transform_to Image_type.B_W frame, mono = frame; } } } Smooth_image_item = class Menuaction "_Smooth" "remove small features from image" { action in = class _result { _vislevel = 3; feature = Scale "Minimum feature size" 1 50 20; _result = map_unary (smooth feature.value) in; } } Light_correct_item = class Menuaction "_Flatfield" "use white image w to flatfield image i" { action w i = map_binary wc w i { wc w i = clip2fmt i.format (w' * i) { fac = mean w / max w; w' = fac * (max w / w); } } } Image_rank_item = Filter_rank_item.Image_rank_item; Tilt_item = Filter_tilt_item; sep1 = Menuseparator; White_balance_item = class Menuaction "_White Balance" "use average of small image to set white of large image" { action a b = class _result { _vislevel = 3; white_hint = "Set image white to:"; white = Colour_picker "Lab" [100, 0, 0]; _result = map_binary wb a b { wb a b = colour_transform_to (get_type image) image_xyz' { area x = x.width * x.height; larger x y = area x > area y; [image, patch] = sortc larger [a, b]; to_xyz = colour_transform_to Image_type.XYZ; // white balance in XYZ patch_xyz = to_colour (to_xyz patch); white_xyz = to_xyz white; facs = (mean patch_xyz / mean white_xyz) * (white_xyz / patch_xyz); image_xyz = to_xyz image; image_xyz' = image_xyz * facs; } } } } Gamma_item = Image_levels_item.Gamma_item; Tone_item = Image_levels_item.Tone_item; sep2 = Menuseparator; Crop_item = Image_crop_item; Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Rubber_item = Image_transform_item.Image_rubber_item; sep3 = Menuseparator; ICC_item = Colour_icc_item; Temp_item = Colour_temperature_item; Find_calib_item = class Menuaction "Find _Colour Calibration" "find an RGB -> XYZ transform from an image of a colour chart" { action image = class _result { _check_args = [ [image, "image", check_Image] ]; _vislevel = 3; // get macbeth data file to use macbeth = Pathname "Pick a Macbeth data file" "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; mode = Option "Input LUT" [ "Linear input", "Fit intercept from chart greyscale", "Linearize input from chart greyscale" ] 2; // get max of input image _max_value = Image_format.maxval image.format; // measure chart image _camera = measure 0 0 image.width image.height 6 4 image.value; // load true values _true_Lab = Matrix_file macbeth.value; _true_XYZ = colour_transform Image_type.LAB Image_type.XYZ _true_Lab; // get Ys of greyscale _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); // camera greyscale (all bands) _camera_grey = drop 18 _camera.value; // normalise both to 0-1 and combine _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; _comb = Matrix [[0, 0], [1, 1]], mode == 0 = Matrix [0: intercepts, replicate (_camera.width + 1) 1], mode == 1 = Matrix (map2 cons _true_grey_Y' _camera_grey') { intercepts = [(linreg _true_grey_Y' cam).intercept :: cam <- transpose _camera_grey']; } // make a linearising lut ... zero on left _linear_lut = im_invertlut _comb (_max_value + 1); // and display it // plot from 0 explicitly so we see the effect of mode1 (intercept // from greyscale) linearising_lut = Plot [$ymin => 0] _linear_lut; // map the original image through the lineariser to // get linear 0-1 RGB image _image' = hist_map linearising_lut.value image.value; // remeasure and solve for RGB -> XYZ _camera' = im_measure _image' 0 0 image.width image.height 6 4; _pinv = (transpose _camera' * _camera') ** -1; M = transpose (_pinv * transpose _camera' * _true_XYZ); // convert linear RGB camera to Lab _result = (Image @ colour_transform Image_type.XYZ Image_type.LAB @ cast_float @ recomb M) _image'; // measure again and compute dE76 _camera'' = im_measure _result.value 0 0 image.width image.height 6 4; _dEs = map abs_vec (_camera'' - _true_Lab).value; final_dE76 = mean _dEs; _max_dE = foldr max_pair 0 _dEs; _worst = index (equal _max_dE) _dEs; worst_patch = name _worst ++ " (patch " ++ print (_worst + 1) ++ ", " ++ print _max_dE ++ " dE)" { name i = macbeth_names?i, i >= 0 && i < len macbeth_names = "Unknown"; } } } Apply_calib_item = class Menuaction "_Apply Colour Calibration" "apply an RGB -> LAB transform to an image" { action a b = class (map_binary process a b) { process a b = result, is_instanceof calib_name calib && is_Image image = error (_ "bad arguments to " ++ "Calibrate_image") { // the name of the calib object we need calib_name = "Tasks_capture_item.Find_calib_item.action"; // get the Calibrate_chart arg first [image, calib] = sortc (const (is_instanceof calib_name)) [a, b]; // map the original image through the lineariser to get // linear 0-1 RGB image image' = hist_map calib.linearising_lut image; // convert linear RGB camera to Lab result = colour_transform Image_type.XYZ Image_type.LAB ((float) (recomb calib.M image')); } } } sep4 = Menuseparator; Graph_hist_item = Hist_find_item; Graph_bands_item = class Menuaction "Plot _Bands" "show image bands as a graph" { action x = class _result { _vislevel = 3; style = Option_enum "Style" Plot_style.names "Line"; auto = Toggle "Auto Range" true; ymin = Expression "Y range minimum" 0; ymax = Expression "Y range maximum" 1; _result = Plot options (to_image (bands (image x))).value { options = [$style => style.value] ++ if auto then [] else [$ymin => ymin.expr, $ymax => ymax.expr]; // try to make something image-like from it image x = extract_area x.left x.top 1 1 x.image, is_Mark x = get_image x, has_image x = get_image (to_image x); // get as [[1],[2],[3]] bands x = transpose [map mean (bandsplit x)]; } } } } Tasks_mosaic_item = class Menupullright "_Mosaic" "build image mosaics" { /* Check and group a point list by image. */ mosaic_sort_test l = error "mosaic: not all points", !is_listof is_Mark l = error "mosaic: points not on two images", !is_list_len 2 images = error "mosaic: images do not match in format and coding", !all_equal (map get_format l) || !all_equal (map get_coding l) = error "mosaic: not same number of points on each image", !foldr1 equal (map len l') = l' { // test for all elements of a list equal all_equal l = all (map (equal (hd l)) (tl l)); // all the different images images = mkset pointer_equal (map get_image l); // find all points defined on image test_image image p = (get_image p) === image; find l image = filter (test_image image) l; // group point list by image l' = map (find l) images; } /* Sort a point group to get right before left, and within each group to * get above before below. */ mosaic_sort_lr l = l'' { // sort to get upper point first above a b = a.top < b.top; l' = map (sortc above) l; // sort to get right group before left group right a b = a?0.left > b?0.left; l'' = sortc right l'; } /* Sort a point group to get top before bottom, and within each group to * get left before right. */ mosaic_sort_tb l = l'' { // sort to get upper point first left a b = a.left < b.left; l' = map (sortc left) l; // sort to get right group before left group below a b = a?0.top > b?0.top; l'' = sortc below l'; } /* Put 'em together! Group by image, sort vertically (or horizontally) with * one of the above, transpose to get pairs matched up, and flatten again. */ mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; Mosaic_1point_item = class Menupullright "_One Point" "join two images with a single tie point" { check_ab_args a b = [ [a, "a", check_Mark], [b, "b", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; lr_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_lrmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_lr [a, b]; } } tb_mos _refine a b = class Image _result { _check_args = check_ab_args a b; bw = blend_width_widget; refine = _refine; _result = im_tbmosaic a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge a'.image.value b'.image.value (b'.left - a'.left) (b'.top - a'.top) bw.value { [a', b'] = mosaic_sort mosaic_sort_tb [a, b]; } } Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a single tie point" { action a b = lr_mos refine_widget a b; } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a single tie point" { action a b = tb_mos refine_widget a b; } sep1 = Menuseparator; Left_right_manual_item = class Menuaction "Manual L_eft to Right" "join left-right, no auto-adjust of tie points" { action a b = lr_mos false a b; } Top_bottom_manual_item = class Menuaction "Manual T_op to Bottom" "join top-bottom, no auto-adjust of tie points" { action a b = tb_mos false a b; } } Mosaic_2point_item = class Menupullright "_Two Point" "join two images with two tie points" { check_abcd_args a b c d = [ [a, "a", check_Mark], [b, "b", check_Mark], [c, "c", check_Mark], [d, "d", check_Mark] ]; // shortcut to prefs prefs = Workspaces.Preferences; search_area = prefs.MOSAIC_WINDOW_SIZE; object_size = prefs.MOSAIC_OBJECT_SIZE; blend_width_widget = Scale "Maximum blend width" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; Left_right_item = class Menuaction "_Left to Right" "join two images left-right with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_lrmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_lrmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d]; } } } Top_bottom_item = class Menuaction "_Top to Bottom" "join two images top-bottom with a pair of tie points" { action a b c d = class Image _result { _check_args = check_abcd_args a b c d; bw = blend_width_widget; refine = refine_widget; _result = im_tbmosaic1 a'.image.value b'.image.value 0 a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top (object_size / 2) (search_area / 2) 0 bw.value, refine = im_tbmerge1 a'.image.value b'.image.value a'.left a'.top b'.left b'.top c'.left c'.top d'.left d'.top bw.value { [a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d]; } } } } sep1 = Menuseparator; Balance_item = class Menuaction "Mosaic _Balance" "disassemble mosaic, scale brightness to match, reassemble" { action x = map_unary balance x { balance x = oo_unary_function balance_op x, is_class x = im_global_balancef x Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, is_image x = error (_ "bad arguments to " ++ "balance") { balance_op = Operator "balance" balance Operator_type.COMPOUND_REWRAP false; } } } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// Manual_balance_item = class Menupullright "Manual B_alance" "balance tonality of user defined areas" { prefs = Workspaces.Preferences; //////////////////////////////////////////////////////////////////////////////////// Balance_find_item = class Menuaction "_Find Values" "calculates values required to scale and offset balance user defined areas in a given image" /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of * 8-bit reference masks, where the masks are white on a black background. */ { action im_in m_control m_group = class Matrix values{ _vislevel = 1; _control_im = if m_control then im_in else 0; _control_meanmax = so_meanmax _control_im; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; process m_current mat_in = mat_out {so_values = so_calculate _control_meanmax im_in m_current; mat_out = join [so_values] mat_in;} values = (foldr process [] _m_list); } } //////////////////////////////////////////////////////////////////////////////////// Balance_check_item = class Menuaction "_Check Values" "allows calculated set of scale and offset values to be checked and adjusted if required" /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. * Eg. Check values required to balance the secondary structure in an X-ray image. * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, * where the masks are white on a black background. */ { action im_in m_matrix m_group = class Image value { _vislevel = 3; blur = Scale "Blur" 1 10 1; _blur = (blur.value/2 + 0.5), blur.value > 1 = 1; _group_check = is_Group m_group; _m_list = m_group.value, _group_check = m_group; adjust = Matrix_rec mat_a { no_masks = len _m_list; mat_a = replicate no_masks [0, 0]; } // Apply the user defined adjustments to the inputted matrix of scale and offset values _adjusted = map2 fn_adjust m_matrix.value adjust.value; fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; _scaled_ims = map (fn_so_apply im_in) _adjusted; fn_so_apply im so = map_unary adj im {adj im = im * (so?0) + (so?1);} _im_pairs = zip2 _m_list _scaled_ims; // Prepare black images as starting point. //////////// _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; _pair_start = [(_blank + 1), _blank]; Build = Toggle "Build Scale and Offset Correction Images" false; Output = class { _vislevel = 1; scale_im = _build?0; offset_im = _build?1; so_values = Matrix _adjusted; _build = [Image so_images?0, Image so_images?1], Build = ["Scale image not built.", "Offset image not built."] { m_list' = transpose [_m_list]; m_all = map2 join m_list' _adjusted; so_images = foldr process_2 _pair_start m_all; } } value = (foldr process_1 im_in_b _im_pairs).value {im_in_b = map_unary cast_float im_in;} process_1 m_current im_start = im_out { bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); blended_im = im_blend bl_mask (m_current?1).value im_start.value; im_out = Image (clip2fmt im_start.format blended_im); } // Process for building scale and offset image. process_2 current p_start = p_out { im_s = if ((current?0) > 128) then current?1 else _blank; im_o = if ((current?0) > 128) then current?2 else _blank; im_s' = convsep (matrix_blur _blur) (im_s != 0); im_o' = convsep (matrix_blur _blur) (im_o != 0); im_s'' = im_blend im_s'.value im_s.value p_start?0; im_o'' = im_blend im_o'.value im_o.value p_start?1; p_out = [im_s'', im_o'']; } } } //////////////////////////////////////////////////////////////////////////////////// Balance_apply_item = class Menuaction "_Apply Values" "apply scale and offset corrections, defined as image maps, to a given image" /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an * X-ray image an 32-bit float scale image and a 32-bit offset image. */ { action im_in scale_im offset_im = class Image value { _vislevel = 1; xfactor = im_in.width/scale_im.width; yfactor = im_in.height/scale_im.height; _scale_im = resize Interpolate_bilinear xfactor yfactor scale_im; _offset_im = resize Interpolate_bilinear xfactor yfactor offset_im; value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); } } } Tilt_item = Filter_tilt_item; sep2 = Menuseparator; Rebuild_item = class Menuaction "_Rebuild" "disassemble mosaic, substitute image files and reassemble" { action x = class _result { _vislevel = 3; old = String "In each filename, replace" "foo"; new = String "With" "bar"; _result = map_unary remosaic x { remosaic image = Image (im_remosaic image.value old.value new.value); } } } sep3 = Menuseparator; Clone_area_item = class Menuaction "_Clone Area" "replace dark or light section of im1 with pixels from im2" { action im1 im2 = class _result { _check_args = [ [im1, "im1", check_Image], [im2, "im2", check_Image] ]; _vislevel = 3; /* Region on first image placed in the top left hand corner, * positioned and size relative to the height and width of im1. */ r1 = Region_relative im1 0.05 0.05 0.05 0.05; /* Mark on second image placed in the top left hand corner, * positioned relative to the height and width of im2. Used to * define _r2, the region from which the section of image is cloned * from. */ p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left p2.top r1.width r1.height; mask = [r1 <= Options.sc, r1 >= Options.sc]?(Options.replace); Options = class { _vislevel = 3; pause = Toggle "Pause process" true; /* Option toggle used to define whether the user is * replacing a dark or a light area. */ replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; // Used to select the area to be replaced. sc = Scale "Scale cutoff" 0.01 mx (mx / 2) {mx = Image_format.maxval im1.format;} //Allows replacement with scale&offset balanced gaussian noise. balance = Toggle "Balance cloned data to match surroundings." true; //Allows replacement with scale&offset balanced //gaussian noise. process = Toggle "Replace area with Gaussian noise." false; } _result = im1, Options.pause = Image (im_insert im1.value patch r1.left r1.top) { r2 = Region im2 p2.left p2.top r1.width r1.height; ref_meanmax = so_meanmax (if mask then 0 else r1); mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]]; mask_a = map_unary (dilate mask8) mask; mask_b = convsep (matrix_blur 2) mask_a; patch = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.balance = so_balance ref_meanmax r1 r2 mask_b Options.process, Options.process = im_blend (get_image mask_b) (get_image r2) (get_image r1); } } } } Tasks_frame_item = Frame_item; Tasks_print_item = class Menupullright "_Print" "useful stuff for image output" { Rotate_item = Image_transform_item.Rotate_item; Flip_item = Image_transform_item.Flip_item; Resize_item = Image_transform_item.Resize_item; Tone_item = Image_levels_item.Tone_item; Sharpen_item = class Menuaction "_Sharpen" "unsharp filter tuned for typical inkjet printers" { action x = class _result { _vislevel = 3; target_dpi = Option "Sharpen for print at" [ "400 dpi", "300 dpi", "150 dpi", "75 dpi" ] 1; _result = map_unary process x { process image = sharpen params?0 params?1 params?2 params?3 params?4 params?5 (colour_transform_to Image_type.LABQ image) { // sharpen params for various dpi // just change the size of the area we search param_table = [ [7, 2.5, 40, 20, 0.5, 1.5], [5, 2.5, 40, 20, 0.5, 1.5], [3, 2.5, 40, 20, 0.5, 1.5], [11, 2.5, 40, 20, 0.5, 1.5] ]; params = param_table?target_dpi; } } } } sep1 = Menuseparator; Temp_item = Colour_temperature_item; ICC_item = Colour_icc_item; } nip2-8.7.1/share/nip2/compat/7.26/Makefile.am0000644000175000017500000000054313351443023015205 00000000000000startdir = $(pkgdatadir)/compat/7.26 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) nip2-8.7.1/share/nip2/compat/7.26/Makefile.in0000644000175000017500000003707113417043242015226 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/compat/7.26 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(startdir)" DATA = $(start_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ startdir = $(pkgdatadir)/compat/7.26 start_DATA = \ Math.def \ Image.def \ Colour.def \ Tasks.def \ Object.def \ Filter.def \ Matrix.def \ Widgets.def \ Histogram.def \ _joe_extra.def \ _joe_utilities.def \ _convert.def \ _generate.def \ _list.def \ _predicate.def \ _stdenv.def \ _Object.def \ _types.def EXTRA_DIST = $(start_DATA) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/compat/7.26/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/compat/7.26/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-startDATA: $(start_DATA) @$(NORMAL_INSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(startdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(startdir)" || 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)$(startdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(startdir)" || exit $$?; \ done uninstall-startDATA: @$(NORMAL_UNINSTALL) @list='$(start_DATA)'; test -n "$(startdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(startdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(startdir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-startDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-startDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-startDATA install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-startDATA .PRECIOUS: Makefile # 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: nip2-8.7.1/share/nip2/compat/7.26/_predicate.def0000644000175000017500000002672113351443023015736 00000000000000 /* is_colour_space str: is a string one of nip's colour space names */ is_colour_space str = Image_type.colour_spaces.present 0 str; /* is_colour_type n: is a number one of VIPS's colour spaces */ is_colour_type n = Image_type.colour_spaces.present 1 n; /* is_number: is a real or a complex number. */ is_number a = is_real a || is_complex a; /* is_int: is an integer */ is_int a = is_real a && a == (int) a; /* is_uint: is an unsigned integer */ is_uint a = is_int a && a >= 0; /* is_pint: is a positive integer */ is_pint a = is_int a && a > 0; /* is_preal: is a positive real */ is_preal a = is_real a && a > 0; /* is_ureal: is an unsigned real */ is_ureal a = is_real a && a >= 0; /* is_letter c: true if character c is an ASCII letter * * is_letter :: char -> bool */ is_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); /* is_digit c: true if character c is an ASCII digit * * is_digit :: char->bool */ is_digit x = '0' <= x && x <= '9'; /* A whitespace character. * * is_space :: char->bool */ is_space = member " \n\t"; /* List str starts with section prefix. * * is_prefix "hell" "hello world!" == true * is_prefix :: [*] -> [*] -> bool */ is_prefix prefix str = take (len prefix) str == prefix; /* List str ends with section suffix. * * is_suffix "ld!" "hello world!" == true * is_suffix :: [*] -> [*] -> bool */ is_suffix suffix str = take (len suffix) (reverse str) == reverse suffix; /* List contains seqence. * * is_substr "llo" "hello world!" == true * is_substr :: [*] -> [*] -> bool */ is_substr seq str = any (map (is_prefix seq) (iterate tl str)); /* is_listof p s: true if finite list with p true for every element. */ is_listof p l = is_list l && all (map p l); /* is_string s: true if finite list of char. */ is_string s = is_listof is_char s; /* is_real_list l: is l a list of real numbers ... test each element, * so no infinite lists pls. */ is_real_list l = is_listof is_real l; /* is_string_list l: is l a finite list of finite strings. */ is_string_list l = is_listof is_string l; /* Test list length ... quicker than len x == n for large lists. */ is_list_len n x = true, x == [] && n == 0 = false, x == [] || n == 0 = is_list_len (n - 1) (tl x); is_list_len_more n x = true, x != [] && n == 0 = false, x == [] || n == 0 = is_list_len_more (n - 1) (tl x); is_list_len_more_equal n x = true, n == 0 = false, x == [] = is_list_len_more_equal (n - 1) (tl x); /* is_rectangular l: is l a rectangular data structure */ is_rectangular l = true, !is_list l = true, all (map is_obj l) = true, all (map is_list l) && all (map (not @ is_obj) l) && all (map is_rectangular l) && is_list_len_more 0 l && all (map (is_list_len (len (hd l))) (tl l)) = false { // treat strings as a base type, not [char] is_obj x = !is_list x || is_string x; } /* is_matrix l: is l a list of lists of real numbers, all the same length * * [[]] is the empty matrix, [] is the empty list ... disallow [] */ is_matrix l = l != [] && is_listof is_real_list l && is_rectangular l; /* is_square_matrix l: is l a matrix with width == height */ is_square_matrix l = true, l == [[]] = is_matrix l && is_list_len (len (hd l)) l; /* is_oddmatrix l: is l a matrix with odd-length sides */ is_oddmatrix l = true, l == [[]] = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1; /* is_odd_square_matrix l: is l a square_matrix with odd-length sides */ is_odd_square_matrix l = is_square_matrix l && len l % 2 == 1; /* Is an item in a column of a table? */ is_incolumn n table x = member (map (extract n) table) x; /* Is HGuide or VGuide. */ is_HGuide x = is_instanceof "HGuide" x; is_VGuide x = is_instanceof "VGuide" x; is_Guide x = is_HGuide x || is_VGuide x; is_Mark x = is_instanceof "Mark" x; is_Group x = is_instanceof "Group" x; is_NULL x = is_instanceof "NULL" x; is_List x = is_instanceof "List" x; is_Image x = is_instanceof "Image" x; is_Region x = is_instanceof "Region" x; is_Real x = is_instanceof "Real" x; is_Matrix x = is_instanceof "Matrix_base" x; is_Vector x = is_instanceof "Vector" x; is_Colour x = is_instanceof "Colour" x; is_Arrow x = is_instanceof "Arrow" x; is_Bool x = is_instanceof "Bool" x; is_Scale x = is_instanceof "Scale" x; is_Rect x = is_instanceof "Rect" x; is_Number x = is_instanceof "Number" x; is_Expression x = is_instanceof "Expression" x; is_String x = is_instanceof "String" x; /* A list of the form [[1,2],[3,4],[5,6]...] */ is_xy_list l = is_list l && all (map xy l) { xy l = is_real_list l && is_list_len 2 l; } // does a nested list structure contain a Group object? contains_Group l = true, is_list l && any (map is_Group l) = any (map contains_Group l), is_list l = false; /* Does an object have a sensible VIPS type? */ has_type x = is_image x || is_Image x || is_Arrow x || is_Colour x; /* Try to get a VIPS image type from an object. */ get_type x = get_type_im x, is_image x = get_type_im x.value, is_Image x = get_type_im x.image.value, is_Arrow x = Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x // slightly odd ... but our display is always 0-255, so it makes sense for // a plain number to be in the same range = Image_type.sRGB, is_real x = error ("get_type: unable to get type from " ++ print x) { // get the type from a VIPS image ... but only if it makes sense with // the rest of the image // we often have Type set wrong, hence the ugly guessing :-( // can have alpha, hence we let bands be one more than you might think get_type_im im = Image_type.LABQ, coding == Image_coding.LABPACK = Image_type.GREY16, type == Image_type.GREY16 && is_bands 1 = Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && (width == 1 || height == 1) = Image_type.B_W, is_bands 1 = Image_type.CMYK, type == Image_type.CMYK && is_bands 4 = type, is_colorimetric && is_bands 3 = Image_type.sRGB, !is_colorimetric && is_bands 3 = Image_type.MULTIBAND, !is_colorimetric && !is_bands 3 = type { type = get_header "Type" im; coding = get_header "Coding" im; bands = get_header "Bands" im; width = get_header "Xsize" im; height = get_header "Ysize" im; // 3-band colorimetric types we allow ... the things which the // Colour/Convert To menu can make, excluding mono. ok_types = [ Image_type.sRGB, Image_type.RGB16, Image_type.LAB, Image_type.LABQ, Image_type.LABS, Image_type.LCH, Image_type.XYZ, Image_type.YXY, Image_type.UCS ]; is_colorimetric = member ok_types type; // is bands n, with an optional alpha (ie. can be n + 1 too) is_bands n = bands == n || bands == n + 1; } } has_format x = has_member "format" x || is_Arrow x || is_image x; get_format x = x.format, has_member "format" x = x.image.format, is_Arrow x = get_header "BandFmt" x, is_image x = error ("get_format: unable to get format from " ++ print x); has_bits x = has_member "bits" x || is_Arrow x || is_image x; get_bits x = x.bits, has_member "bits" x = x.image.bits, is_Arrow x = get_header "Bbits" x, is_image x = error ("get_bits: unable to get bits from " ++ print x); has_bands x = is_image x || has_member "bands" x || is_Arrow x; get_bands x = x.bands, has_member "bands" x = x.image.bands, is_Arrow x = get_header "Bands" x, is_image x = 1, is_real x = len x, is_real_list x = error ("get_bands: unable to get bands from " ++ print x); has_coding x = has_member "coding" x || is_Arrow x || is_image x; get_coding x = x.coding, has_member "coding" x = x.image.coding, is_Arrow x = get_header "Coding" x, is_image x = Image_coding.NOCODING, is_real x = error ("get_coding: unable to get coding from " ++ print x); has_xres x = has_member "xres" x || is_Arrow x || is_image x; get_xres x = x.xres, has_member "xres" x = x.image.xres, is_Arrow x = get_header "Xres" x, is_image x = error ("get_xres: unable to get xres from " ++ print x); has_yres x = has_member "yres" x || is_Arrow x || is_image x; get_yres x = x.yres, has_member "yres" x = x.image.yres, is_Arrow x = get_header "Yres" x, is_image x = error ("get_yres: unable to get yres from " ++ print x); has_xoffset x = has_member "xoffset" x || is_Arrow x || is_image x; get_xoffset x = x.xoffset, has_member "xoffset" x = x.image.xoffset, is_Arrow x = get_header "Xoffset" x, is_image x = error ("get_xoffset: unable to get xoffset from " ++ print x); has_yoffset x = has_member "yoffset" x || is_Arrow x || is_image x; get_yoffset x = x.yoffset, has_member "yoffset" x = x.image.yoffset, is_Arrow x = get_header "Yoffset" x, is_image x = error ("get_yoffset: unable to get yoffset from " ++ print x); has_value = has_member "value"; get_value x = x.value; has_image x = is_image x || is_Image x || is_Arrow x; get_image x = x.value, is_Image x = x.image.value, is_Arrow x = x, is_image x = error ("get_image: unable to get image from " ++ print x); has_number x = is_number x || is_Real x; get_number x = x.value, is_Real x = x, is_number x = error ("get_number: unable to get number from " ++ print x); has_real x = is_real x || is_Real x; get_real x = x.value, is_Real x = x, is_real x = error ("get_real: unable to get real from " ++ print x); has_width x = has_member "width" x || is_image x; get_width x = x.width, has_member "width" x = get_header "Xsize" x, is_image x = error ("get_width: unable to get width from " ++ print x); has_height x = has_member "height" x || is_image x; get_height x = x.height, has_member "height" x = get_header "Ysize" x, is_image x = error ("get_height: unable to get height from " ++ print x); has_left x = has_member "left" x; get_left x = x.left, has_member "left" x = error ("get_left: unable to get left from " ++ print x); has_top x = has_member "top" x; get_top x = x.top, has_member "top" x = error ("get_top: unable to get top from " ++ print x); // like has/get member, but first in a lst of objects has_member_list has objects = filter has objects != []; // need one with the args swapped get_member = converse dot; // get a member from the first of a list of objects to have it get_member_list has get objects = hd members, members != [] = error "unable to get property" { members = map get (filter has objects); } is_hist x = has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM) { im = get_image x; w = get_width im; h = get_height im; t = get_type im; } get_header field x = oo_unary_function get_header_op x, is_class x = get_header_image x, is_image x = error (_ "bad arguments to " ++ "get_header") { get_header_op = Operator "get_header" (get_header field) Operator_type.COMPOUND false; get_header_image im = im_header_int field im, type == itype = im_header_double field im, type == dtype = im_header_string field im, type == stype1 || type == stype2 = error (_ "image has no field " ++ field), type == 0 = error (_ "unknown type for field " ++ field) { type = im_header_get_typeof field im; itype = name2gtype "gint"; dtype = name2gtype "gdouble"; stype1 = name2gtype "VipsRefString"; stype2 = name2gtype "gchararray"; } } get_header_type field x = oo_unary_function get_header_type_op x, is_class x = im_header_get_typeof field x, is_image x = error (_ "bad arguments to " ++ "get_header_type") { get_header_type_op = Operator "get_header_type" (get_header_type field) Operator_type.COMPOUND false; } set_header field value x = oo_unary_function set_header_op x, is_class x = im_copy_set_meta x field value, is_image x = error (_ "bad arguments to " ++ "set_header") { set_header_op = Operator "set_header" (set_header field value) Operator_type.COMPOUND false; } nip2-8.7.1/share/nip2/compat/7.26/_list.def0000644000175000017500000002245013351443023014744 00000000000000/* any l: or all the elements of list l together * * any (map (equal 0) list) == true, if any element of list is zero. * any :: [bool] -> bool */ any = foldr logical_or false; /* all l: and all the elements of list l together * * all (map (==0) list) == true, if every element of list is zero. * all :: [bool] -> bool */ all = foldr logical_and true; /* concat l: join a list of lists together * * concat ["abc","def"] == "abcdef". * concat :: [[*]] -> [*] */ concat l = foldr join [] l; /* delete eq x l: delete the first x from l * * delete equal 'b' "abcdb" == "acdb" * delete :: (* -> bool) -> * -> [*] -> [*] */ delete eq a l = [], l == [] = y, eq a b = b : delete eq a y { b:y = l; } /* difference eq a b: delete b from a * * difference equal "asdf" "ad" == "sf" * difference :: (* -> bool) -> [*] -> [*] -> [*] */ difference = foldl @ converse @ delete; /* drop n l: drop the first n elements from list l * * drop 3 "abcd" == "d" * drop :: num -> [*] -> [*] */ drop n l = l, n <= 0 || l == [] = drop (n - 1) (tl l); /* dropwhile fn l: drop while fn is true * * dropwhile is_digit "1234pigs" == "pigs" * dropwhile :: (* -> bool) -> [*] -> [*] */ dropwhile fn l = [], l == [] = dropwhile fn x, fn a = l { a:x = l; } /* extract n l: extract element at index n from list l */ extract = converse subscript; /* filter fn l: return all elements of l for which predicate fn holds * * filter is_digit "1one2two3three" = "123" * filter :: (* -> bool) -> [*] -> [*] */ filter fn l = foldr addif [] l { addif x l = x : l, fn x; = l; } /* foldl fn st l: fold list l from the left with function fn and start st * * Start from the left hand end of the list (unlike foldr, see below). * foldl is less useful (and much slower). * * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z) * foldl :: (* -> ** -> *) -> * -> [**] -> * */ foldl fn st l = st, l == [] = foldl fn (fn st (hd l)) (tl l); /* foldl1 fn l: like foldl, but use the 1st element as the start value * * foldl1 fn [1,2,3] == ((1 fn 2) fn 3) * foldl1 :: (* -> * -> *) -> [*] -> * */ foldl1 fn l = [], l == [] = foldl fn (hd l) (tl l); /* foldr fn st l: fold list l from the right with function fn and start st * * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st)))) * foldr :: (* -> ** -> **) -> ** -> [*] -> ** */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)); /* foldrl fn l: like foldr, but use the 1st element as the start value * * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1))) * foldr1 :: (* -> * -> *) -> [*] -> * */ foldr1 fn l = [], l == [] = foldr fn (hd l) (tl l); /* Search a list for an element, returning its index (or -1) * * index (equal 12) [13,12,11] == 1 * index :: (* -> bool) -> [*] -> real */ index fn list = search list 0 { search l n = -1, l == [] = n, fn (hd l) = search (tl l) (n + 1); } /* init l: remove last element of list l * * The dual of tl. * init [1,2,3] == [1,2] * init :: [*] -> [*] */ init l = error "init of []", l == []; = [], tl l == []; = hd l : init (tl l); /* iterate f x: repeatedly apply f to x * * return the infinite list [x, f x, f (f x), ..]. * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ] * iterate :: (* -> *) -> * -> [*] */ iterate f x = x : iterate f (f x); /* join_sep sep l: join a list with a separator * * join_sep ", " (map print [1 .. 4]) == "1, 2, 3, 4" * join_sep :: [*] -> [[*]] -> [*] */ join_sep sep l = foldl1 fn l { fn a b = a ++ sep ++ b; } /* last l: return the last element of list l * * The dual of hd. last [1,2,3] == 3 * last :: [*] -> [*] */ last l = error "last of []", l == [] = hd l, tl l == [] = last (tl l); /* len l: length of list l * (see also is_list_len and friends in predicate.def) * * len :: [*] -> num */ len l = 0, l == [] = 1 + len (tl l); /* limit l: return the first element of l which is equal to its predecessor * * useful for checking for convergence * limit :: [*] -> * */ limit l = error "incorrect use of limit", l == [] || tl l == [] || tl (tl l) == [] = a, a == b = limit (b : x) { a:b:x = l; } /* Turn a function of n args into a function which takes a single arg of an * n-element list. */ list_1ary fn x = fn x?0; list_2ary fn x = fn x?0 x?1; list_3ary fn x = fn x?0 x?1 x?2; list_4ary fn x = fn x?0 x?1 x?2 x?3; list_5ary fn x = fn x?0 x?1 x?2 x?3 x?4; list_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5; list_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6; /* map fn l: map function fn over list l * * map :: (* -> **) -> [*] -> [**] */ map f l = [], l == []; = f (hd l) : map f (tl l); /* map2 fn l1 l2: map two lists together with fn * * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***] */ map2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2); /* map3 fn l1 l2 l3: map three lists together with fn * * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****] */ map3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3); /* member l x: true if x is a member of list l * * is_digit == member "0123456789" * member :: [*] -> * -> bool */ member l x = any (map (equal x) l); /* merge b l r: merge two lists based on a bool list * * merge :: [bool] -> [*] -> [*] -> [*] */ merge p l r = [], p == [] || l == [] || r == [] = a : merge z x y, c = b : merge z x y { a:x = l; b:y = r; c:z = p; } /* mkset eq l: remove duplicates from list l using equality function * * mkset :: (* -> bool) -> [*] -> [*] */ mkset eq l = [], l == [] = a : filter (not @ eq a) (mkset eq x) { a:x = l; } /* postfix l r: add r to the end of list l * * The dual of ':'. * postfix :: [*] -> ** -> [*,**] */ postfix l r = l ++ [r]; /* repeat x: make an infinite list of xes * * repeat :: * -> [*] */ repeat x = map (const x) [1..]; /* replicate n x: make n copies of x in a list * * replicate :: num -> * -> [*] */ replicate n x = take n (repeat x); /* reverse l: reverse list l * * reverse :: [*] -> [*] */ reverse l = foldl (converse cons) [] l; /* scan fn st l: apply (fold fn r) to every initial segment of a list * * scan add 0 [1,2,3] == [1,3,6] * scan :: (* -> ** -> *) -> * -> [**] -> [*] */ scan fn = g { g st l = [st], l == [] = st : g (fn st a) x { a:x = l; } } /* sort l: sort list l into ascending order * * sort :: [*] -> [*] */ sort l = sortc less_equal l; /* sortc comp l: sort list l into order using a comparision function * * Uses merge sort (n log n behaviour) * sortc :: (* -> * -> bool) -> [*] -> [*] */ sortc comp l = l, n <= 1 = merge (sortc comp (take n2 l)) (sortc comp (drop n2 l)) { n = len l; n2 = (int) (n / 2); /* merge l1 l2: merge sorted lists l1 and l2 to make a single * sorted list */ merge l1 l2 = l2, l1 == [] = l1, l2 == [] = a : merge x (b : y), comp a b = b : merge (a : x) y { a:x = l1; b:y = l2; } } /* sortpl pl l: sort by a list of predicates * * sortpl :: (* -> bool) -> [*] -> [*] */ sortpl pl l = sortc (test pl) l { /* Comparision function ... put true before false, if equal move on to * the next predicate. */ test pl a b = true, pl == [] = ta, ta != tb = test (tl pl) a b { ta = pl?0 a; tb = pl?0 b; } } /* sortr l: sort list l into descending order * * sortr :: [*] -> [*] */ sortr l = sortc more l; /* split fn l: break a list into sections separated by many fn * * split is_space " hello world " == ["hello", "world"] * split is_space " " == [] * split :: (* -> bool) -> [*] -> [[*]] */ split fn l = [], l == [] || l' == [] = head : split fn tail { nfn = not @ fn; l' = dropwhile fn l; head = takewhile nfn l'; tail = dropwhile nfn l'; } /* splits fn l: break a list into sections separated by a single fn * * split (equal ',') ",,1" == ["", "", "1"] * split :: (* -> bool) -> [*] -> [[*]] */ splits fn l = [], l == [] = head : splits fn tail { fn' = not @ fn; dropif x = [], x == [] = tl x; head = takewhile fn' l; tail = dropif (dropwhile fn' l); } /* splitpl fnl l: split a list up with a list of predicates * * splitpl [is_digit, is_letter, is_digit] "123cat" == ["123", "cat", []] * splitpl :: [* -> bool] -> [*] -> [[*]] */ splitpl fnl l = l, fnl == [] = head : splitpl (tl fnl) tail { head = takewhile (hd fnl) l; tail = dropwhile (hd fnl) l; } /* split_lines n l: split a list into equal length lines * * split_lines 4 "1234567" == ["1234", "567"] * splitl :: int -> [*] -> [[*]] */ split_lines n l = [], l == [] = take n l : split_lines n (drop n l); /* take n l: take the first n elements from list l * take :: num -> [*] -> [*] */ take n l = [], n <= 0 = [], l == [] = hd l : take (n-1) (tl l); /* takewhile fn l: take from the front of a list while predicate fn holds * * takewhile is_digit "123onetwothree" == "123" * takewhile :: (* -> bool) -> [*] -> [*] */ takewhile fn l = [], l == [] = hd l : takewhile fn (tl l), fn (hd l) = []; /* zip2 l1 l2: zip two lists together * * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']] * zip2 :: [*] -> [**] -> [[*,**]] */ zip2 l1 l2 = [], l1 == [] || l2 == [] = [hd l1, hd l2] : zip2 (tl l1) (tl l2); /* zip3 l1 l2 l3: zip three lists together * * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]] * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]] */ zip3 l1 l2 l3 = [], l1 == [] || l2 == [] || l3 == [] = [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3); nip2-8.7.1/share/nip2/data/0000755000175000017500000000000013417043452012266 500000000000000nip2-8.7.1/share/nip2/data/stock-tool-rect-select-22.png0000644000175000017500000000030413351443023017433 00000000000000PNG  IHDRĴl;bKGDyIDATx1 א&gT{ZREr0,{ 0pN Y&N)ք"ќk9#pݞdO긋UG)moЎ_:Ƴ鎇}BS;W~4>IENDB`nip2-8.7.1/share/nip2/data/stock-led-red-18.png0000644000175000017500000000071513351443023015575 00000000000000PNG  IHDRVΎWIDAT8=QIDKXURݶ6~.Av V%!dgh1f!b;ss 74n[_3X0]23>AxfTj֘GO_p܊ehYIK$s'wyvhw*֮xW>]o3j6N|,ף5 e\H&T3NT( EU >؂jُc,VI )9$=Y\fJ:]5(A68,4 V8dVj9Fpggg4e2>HTr9Bno44ׯ_ol6+EQvիW@`ZN3 L&`0d2pnRItTp8V\. EQZfYь㋋ Ϸt!j:HjiyO^]]j5V;LfǏb\B"|>.//Qչ\nXNt666h~bzWWWP(J|>/ɖeٔ?я7|)Z6R ׻wqq >|駟jכNVGz^ZǫJT霝p8d:|0 NNNh|FR~L&ln4zwwV \.x<>>>f-jZ?xyl6,Dj{02lww7w:|D4BZb4߿OQ`;H\^^BiPzRi:R%Ɋp8\,vT* Ce28Z^T*5jǩjF.MӱXLB߿\.)M\Ph4IӴZjeYOzZ6MTnnnFa"t:UTa0h4Ų,0(6qaFCQhܜL&F1,K677`08::Tx+J ^nsuuT*Vt:X,fY @ Ndz x<eL&R)%"Vxt:4Mdh^E\[jpd2ZFZpRVyBH;==,u:\^TZ˲x6|L&50\lR5Nyll6OOOq_x!\.WPv؊ BH(<}zd2)ef<>`j/ ajXZjZZf fXL&VJd2t:^o].N37/lfylkkk<W*H$2A !lz~~~.RfZMѴlj52B"T.AFc>[qFVf|.dT*z]&BDQP($a:jmBVU4=ŢjU*  tmr|X>(h~O4K(jR&L&ŒL&Q+G,cZ)y>hm4r9zQrl*LZ-a=<ϷmBd{raG)J7vW*4N9MlF#B}kzV* %$q*j<d2\l6#C;;NEaBv{q|>jqXt*Їj5ZML#o&mQө`E&,~E&c^rQ<l6k4z(*>2FѨ(&) iNxZjhT*1Mz2NEQj&n Y.<ϷZ-RjEQhB={6A0 !u( zp8ĻYpq H]xF>nf3hn6 Rӡ,AŒ\.jc<C46 ">nEP(4q\6 D"<88`Yv8#GZ*hz(n !aJRáL&Cn{s-މfbr)nt2 3L<ZFxzd2дl,*JX,FHEGtyJj6i\*lFv A(J.[,@ 2EQ\>N^/˲(b42v|>v(09@M~hlooDzEu]ݾaX:mnn:b!mlZLFPa:P( t: i4lyc6Qf2` C^w\9vww}>aPs"[VdWU,s:(j4RX,DQcXF#r.<L&j:|t:ZnBJE|||0rbzdnh401sÁK&FR\.fXf>"GGGoE,Dq"NxN`0dB0h4Nz~\& `fsXyl6B~ZN.+0 ŀ%j4áP(j~n_x4<߿d2% Fqm6(zsswPx'*wN_Ctmnnv:4VXרp)EQr(JU*L&SәNX jX,(z^< xoXt:JQ*V4V+6Rv=d2yyy)"JuBEQVKV+ kzZv޽{(ZmXj/k䫫+ !4Mc*˗/A&)VU LP0 #bh2^~ Fm{i2lFrSխVK?pHQT<WT"i44BS;Gfy<d^KaRzp8V/md2*J&5bl6Z,j5zvvj5 rYT(v>}RX.^un fXZry=6 J\Vѫ^^^,k0p8 m* `>4, 8' Pf % |^.d2Z= fhyRv"&v_,ò'L&le|H$d2AJvDBZ{{{-YUl6NX\P IbsP_cQ^en43ZƲ^G^{\.W(Xf%Sq\$AgU՚L&nb1p8V+V^wC@9}WnnnDQM!<@>jj4|^@=h6].W$\#"˲Ns{{hnd P:U*=OQӧO !11a%Q!t:tn6{6TB1Z-v:N9 pIUEsy^բ Ab pǃMT=8 @].P(xn7ʷl6h\bR]*fY( &vvv`0vǃu߼gXT*lhlFQ? 0 j"h41F,йdb 0:WUBZPjZju6M&Tlhd2MӢ(@'.Nβ,F@A'zFRX5LxkFzvގvvTtvZv>SUJr ñXlv\."l6k@ x Yyi¶4FjyblZRڎNg FQ$A=6EE"* EQY Bnw<dxߐXagF|F8B^s.KRzp80:v\pիWX'd2-.ft:V޽{}0(j6z= ~c^}Vd8"?\.E q ~lN\}7HgggEL&`!/Πn} F#td+ r&Fh45qvBOtycDP("Re;kt:"6;|z^.J%qRjDA]SEQNg\bd0GP(?#ϫjgl6 ZhH$F#˲|~0PUVGZTzF7Bt|dG(J;N&H m)8~_m^w4l6)v<.LMG}>L&C͠ye`0pnC` r!tjCPA"H٬jF1H tTT*L JPx<X,* ЊdRҲP(K&rBT*ArPՓh4r`EH$fWWW fYez^8VV juXF#BHI>{w PTL}l6Fyjc \>.wynmp6/ 9Ncf̳^%VU*rǃ\.U*yfB *JX%iZA0YVLF___Y,ryyfyuu0LRR MN[|d2Yzl6KRYe],P(U(ѣGN1n7 J2s0T*UfVTA w :10M IDATt: `yN1r:۷Z||qzBHՊ[pNî \.bNEQ;w"?|:&`th4RzN)FR@ywݐF#l|^Ղ0RDi(988L>uX;J'>oX`Z߿T*A|4L r;u:j].  r~d2AV#8^r{ }zbe{ww`AF.L ADŽH]2 P Nt:QZœ@ \.p84 !a `!`0x<(M?~,2XL`0D0ggvZ !H@Q(Bx b0|>3Bd^zD" kCǃj[$1 *A0~bEpFxU*hl* !rw`XR)\>ͪ*8d2 x[Ehr\ nw6@X=;⇇@vEVl6*!Ѩz(}Q(zm0 /؍Z L|>#0ܷ~bL&hml6W_}>JF _79\`/+/Jz&70G5> ;h4LD1biZ?DQdJT*tn7 j4^F!?sب4 !,l]@1&lDonnbSessaaFc0zǡ ` L `@̘L&h].bW*޾}[Tht]Asm,krQWRfspRpk;N^֤h^X,m@ ^wwwhz= M\.?>>ƞ!"P># ;$k0(!Bxa4N>v7TLJ`[Ų^~VmZи9f{^  E"G(rAk Ë/f/ BqX,v;H gggP"lATV1CL& !w#BP)d2f-ЯNӝ7.`b6 M&;=,G'VH$<h4j6l59 (* zT*EN)mmm5T*Fs8reYlz@_|q'rd2 |^+4X,ӧ ނf BVvae0!- . jCooojuVNP*y d28'ʳl c4\VW@ٕN_R)~?fzhYFh.X,.Kpo*Iل`0L&$Rd "EnېS5Zl'%@Kρ].!\f2M@%`jRT@ @dHdj0vtZٳgnnnYX,(N!Ai"dVk6!h4ڍF#eL&ssss B.nG:xnJׯ`0(JdQBVDloodpVD"U*?}ndqXރ Ch S2 xb<|-jVxl6V+`R篮`t:.JxBAqJr !h\5P,AZt:- l_T^__?y#a}P;%މ JӶXVVzAV:Q*B>~jn]A3|Q.v;8-P0TH$t:_ztg !mnnŘݮ5xX;;;("iZ,>|qX<>>yt]]]@ D{$al6t6 nff3":;;;b!HpRl6?~8JA̅q|>7 n`P(ilE"n`2P,8(+Q\'ROS{a\.0|ajzv7MjdQ!<+D>OP}rFDBd23k͆>. xˆF]p^A(@8! SYEA۝N1ĸBT!B*x+v9N=zH$qZUb1 1B}D\.ސ{oott)B[1 0CX, /nEA%281OH$P$ % K(PHVkڃv0V%FS 470.+adt:A4VT߯j3ZFVf2B&)OSǃ,i0Pޢ&X, U*j2QP(ʻNn P |>tP8,Jx H}HݒWzCe^vmħn6FFHP*6á.lf`qa`FѼylv@(6f>n7xv>Th4D"t:_.F# B!x@HӴd Av6-G"P(zv:PT*b12, c4Q#;@lbL&hLӰOIfZ C,NSw`^GQC90+́~v}}:IpFu:3p>|AZFK%L f3Ӏ vA–)Q*D5Hjfmllgp8l$%@`:z="`loot:Iòl`F#P].&7`ǫ*iBVUTz-^"S6nX4 FH$E˲~l6h_Ah4!jb 1_bH;4Mc $GF#2D3&3٬X,,{n6fSR RyZ*`قfC\TyNpQa!L&;==:vQBeVl6`0t(d0sdY߇ or`v\4Zg|>nwvv޾}{=ȗ(z_ :^I$F޽{+4P냱N>K' zFN<Y4tR)l`1͠ 4YJ)ї%Q@ n* UU숳 qT1*tTU e HEVS O(FbiT# 8cYX,fY$,\BcO1 a ]Pl6 6'à#jc<cE@:ybB{b1 4JP#ϲlq׃h4a>@QFp5〣$EQp%|{H ӧ777/}W>pZb1LPZ]%A׶jSi34zrd!HQuB.l6Ą0x.ȉ[>zd2-KٌL4JRB!GM,iB`SF`aa)cGu;) .0U|x: jQ\j !Xp~!l6߿N,=PqJJj[[[pgD=% L@!Bve<jjBooos`I=xE@3WWW[[[pX,nnn~~(|(?}>p8|15N?CgJǏvt:5!r/T*Oׯ_CzƁDz,vdaXFp8@0A,k,"H^77]moo8dALbFFvOStRe2L¿XR)#EQK fvplDuP@+PVBT!\.g&bYf$JM& $(ؚA+;(Jv(^0gaN$@@]6d2YR~ AE&AB0l_0o0V$P(r'[?`dV+ v;0z8ٹ\vX,@ѣGBqwwF;ɢx'0 h|V!,1*p컾. y 0W6:|>zD}6MLkڅ5* ZT6ϟ#/#<,{yyynZ|^.) RsiF|ɓOVU,Ÿ'X `޽{NG飣{lF +zg?0,g??~eH$ 녟PǃXo_wLPusst:5NSV.0F(޾}]TBޑ}ooOT^\\0A͟apж_%T*wvv1g @l1}pVBt1^hZ}g <}d2FE^2x,1; \.JP4 V .U*@Z6`rfJRH`|> S*:t!H?쳏>H`0??iۅk ‡S4aO7G}dɤdRRQ;ZwR.ommwL cS F0`T*}}0)W#!I2T/!˲,>Fr2`+;GeW`/XϞ=+ `8bކD"g2fyxxh0>u xv 8eqFA0V>l#_ "q#5Vk6PiCT*1ƢZC]A!{R^xAQ (~v{ww @ R>Ԥw0lnF"h4駟tctooo|r9Xy//~ ^_[,H$K0`Ȁ|0  M5TDrORNN0~ H`4 t>ڲh].Z~5p>g %a^O&Ǐ' ߹BsGŋd2 D.`zp8 3hQV 5#!thWKx<,0P5Lb N&¹eGJoU,vtP3'{*J N|gϞ=x+t ̽=x~A aZ 𜣣d2au$Q՘pB^É?2t\=_@UZb1R-t:OOO1VT_v?F(կ~E?s.i~~;L&OgR)|\.wyyvj3LS]^^Z:8@1Y޽{Lbkkk GnnnJ%n`Zp8P^mnnVU`4nq6@ awvv3p:~\.?996|7 *<˗/YŭwSb`%s?PRUU?PAa|9zntL&S2<cKQ8lNV,ɬV+=a*P(677 !$nBA.;aWJ<h !$L¿ɟ ғBFΠhX,x_v\@ӽ~/_`)R_~=1.bntd2)a\hh1.{{{@x'Oz=~d^K5kX, b;ކ+!=I>޻w@;F ZKJKp^|jgrM&LZbfE8@OtTd;*;+;tNjr6Y X =¶#LJ|>r9N8۽O>ZeL?//"L?z(noo?~ND t:xy9cEhVeRgh4? sws?88,jefccˍ??Yǰƾxu|| :˅C-^ちG0D1CQZ9vax x7orя~Bw VajрKCZ@/=< ɺ\.- (j@v: 0NİnkkK.Kv}_RiZDbXXzϞ=+?~!bzA2Cz?~$z|8<=YfeYxR~g4q>baY'pdGGG^ŋ0'd. c@71fVgz, p... u8b1onnbv݄a0 H^( lZQ(BzvZm6BqӧOѬ|߷lT*9PњvC=\'|3F h0őI84eY@D\.T*4=8drlxmoofF8v +hј6sUڋ/666vc~wZ\.awa n>Vuww888K+h8%ɓl6ŢѨZ>NBiYOqrN3!~™z<X>xޭ-Vfr In{nl>{)P` N`pc@ SOqfܠ!XT~;7 ^Bo߾磏>d2x]}>_.O! M@Rtzzz:ꫯ@|L$0 /)T T*ŋNL&WqkwgDxW'`31"g2p*`1 nwwze-Dj\.Áu\>z. % p:BEŲ  A= ܕzTKwgg'7MǓH$5?ȃ03Rݑo߾8\.___xB׿h4z_~e< L& ן9J(nCtvvv6 8jFZn{||Vw]K4PDy&Ę AЇT*-T7 FGG1C.ypWHiBiy^ G(nzLp*@NuD/_j544LMMa7O}7<\ZZ?~|||otniz9Z,HT*B0=˕=!ly x5KEQɴ 4{u ;w@4dif2NBagga l`V'&& ctfCCCn%O>kZvݻ7;;RΝ;z|R\]]Hbt؀i냹|O9U՚ͦ_^ȷI dP4y!?~,޽{XEM&<7NHdvvvvvgnllD>ݻ`l68Y:WUx^GGGwޥ#i2h4f5 &ONNj4V:|2T^t@}*35bT*1CT*=bN$pz@EK~qq WVVR(v߼yp8\.hl?8??ѣGvغ裏^>yBxq\.J`=p >X, 3Ӭt1_V?Ap80Ax1RC*`mm\[[STxh.k/~ D8/_Ć5?{ G ^\\.wppP*@{FQǃg)_jlxLNa311z>::j699==t: x|PFQϟ?xRiXd&'*q:tfffͦ =ZP@kHxG/! ~Zjz= jZ{bl/noo;mS}}}` HߦH$(bi f@$Rp:(wENeZ) _S@*W_t.J/GGGl:P:xӇ dYšч,..m}嗴{}x$0f$a{|n[ֽ=P\D"\niiF>b{΅ke V bffT,pݎb^z+徾>-BΎH$Ďp8@ ~lmm}emmb\.gYh80~r9V`0X{_H^x-FRh2 $1 6|>||LJ'FЌ(2@C @>gX]] cyyGFF>}ZV?KR+++Xf||OO '"˧ C? Je bnӖ}(vhd0XZf__M|JR(-˧(?H$ݻt9$CRPtwJVE/L}m6hԕv=a] -`)P|_ɔU.M<==C KK0fi2HO$T*/nff%Η_~I2#h4:>>.2;;jxR(p⛧E $jw!ޞ H}$İW lƊɤMMljwϷj/fj>$V)˘8Fщ T:FD//QI@q#32x<vwwY8dGGGƓɤdzׯqTirPh ODIT!`0 5!Z 8Γv)@}5 `B?dxlB:M`S$@R 2GyyAmnnn7q0P(dX۷oFBz%\0Ȕ"Z15ڿ&IʼnD[Z4F\ l?Xggg1wj5iC&aFDZAM[lwH$noo'ɩ) rCCC &?{L򗿤AF"lmmUC(bxqqsG6r #Ҝ`X~5fZ)S@VzVӉJj͍ ܿWD"aX;餢>===331xbbbzzf%G)xxxH|M2) $񝝝T*l6766P+b۷CP8z<N%B.ǐB{ +JB)"xnZjl6DٱqB>b[\,~~J2?11Q*>A}у$be2HCZ8)WWWAp:}_|122266r}5 t! `avM7WoHBHP+vD"0l&7z0h5Z^X s,b1UN\tx\ k}}G/t:pK[YY9<HVG#y" D}0%L777`vgٓaZV.C lZH![Mz'i :|\.uvv6<r|mO%>~ӧO- uNa.K*LzX?F~ Npa4e2:Aۍ^aلCR" U* "///Ct**_Dd,4 .//~zFGGؾ.0 >9vn3 + #J-..Y^^U$2Zv޽KT!>Ç].W՚_mT*nV '7Fqjj@(u(^.z!A.kee4  p:o&MW{gg }[ŢF vbqP*8޽{$N#.زRݣN u\.X,~ V tF8d0b_,= 4~#\*~hP̥v;>5H3pbCB4ZJL&w;y59xg8/ T*#j`0FMTNf6$dVZ¯޽{=]q. jO`UtL&ۃH[Fv4X,l6N8$ܤhOPW oѣGX cA<GC->K4vۭT*NxHFj03ywbމŝ.zLX(ES*`}ttHz4U2L:x<8HIX,WdU$`Jggg-7|!˵Z-D~! !kn]__W(qcZH)J6;~ 3ߟpBe{/&p6a_ nFO~IAMsB4edJE"dRT*766B&Hzv&iNN)N|LV2(iZ_4 anooQ#7|hڥ%xN4 ծ dż{J /3 X,H...@~BZZPLOO#1JRrb e$ș!lZ  t4?}}}ttxxY~bTVJHd6b1NP(2b-:55E[\\v?_޽{0fK>g8|766ݿznn/0`ϟ2 ruuT|8f`a@ z'2W,L&9̎O<8r#Z]] hۧ?~8H\^^...>|̃O-,,#'?C#۝NfgM`0ܿ9;MJddzG cDf5\.?88VDh ADUT $m xV v fQTJuYldddttra6jp޻wO$F[Nsuud2酅le~~> 2;;KP𔍏mCpssJ,8z AI#U*pD:jT.R}L۔F [=[\o޼ao'I!j)#6mrr*GZX]]d4i"#Dr   9V"jNMđs$gv*J,ʂ b333C[ftt-rh4bh"$2R T*T*}>I^ju}}=NsKޒmtssDzGGG% a^YYYL&MNNZVTO<)?YB@ @t vMR 88B[BzrzllFYׯu};``0XThR)Xw%r+DFu3h4zuu^**4 y`jh48f}m6%B"\X<0`J"iww{-@T[)z J"ihZ``2̄zXV' 2*J..Dի*`ooO&%IGGGo߾%D[Xڵ818LrFQVGFFz=VEۊfs$nِi P,[EG8Qn0666={hJ7o4׿5h4X,F]4ȇ sNBkC=F& J©nTߧDR1H$Tv=55x9NMMQ@"q8l8KvC%n%Av:/^rm_r|ooZբ C(w q]h¢IV 9Xl?H`%Mlx<μx.//iq6?D"gݛva=jZVFgff ;D"Ldcc7###H]9<==c񏸜^v{rr`0`|t:HiA$qP(|D$T**I<==xtt3@ @ BR=|tԔH$YYY811//P`߸w HA6X,nVY,%z#^ z`rr2OMMq D pr~?r0TQBalkZIk0L5]YYAfu:ŅF 9nv(V釈Dy &(bJZ\\4a0L^0`p31h4* JL6v} 9iZ0+*GGG}loP%x 03`w:###fSx\F Zd2hv?Nqpgg l6NӁhc @D׃DjժRþ?==UED"ȈJrݱXj?H I,{<,yA4C`Z 89P()h4fX,x]m_~IbbC*#-X=V QQ̙:8tL&?EzX,V*9 y҂Rr. '!``w\t;Y@PCǣ_T薈baww 4ʦ^[nX_]T`>dRߪf8t_ƗR..i4l಑dYt>p tݯG\N{wbq[2Ffl6a_Fn hg2'V*N4MvH$믓$! L{sslggG4 oZa*€lV׷MNY&hH$B{kk+˩t:M͂OxƤdס:@ۃ@l6LD"VK [z5jriAeDQ! 7]__G|pxxt|ra޶`03M<l6 L&#AP>ӭ]A :4BD&IN@f&܃xrrR.wwwٴA.HBr#ԖXdw\hZKnwooR\]]T*z>22/^\FiJL#y؅"_!0ձX5 n[;4+/JǷo߂AU,S%WSERGBGM>O&AJJQ.^ꫯNOOf3WC'.@ Jppss322¤GR]Dkr2§%l-y@h#4.\.=?~ӟQD!OLYVdbbB>??O +\giikMLNt:pLNNim41?~X,N TBIA&4Jz uM2>>g$&'3Cb NVܼg9<<1G:7)Aj5s$v`0V522;2ӡ.5vMIؼSbƻ^T?<(?Xܱ`@_TXz SPrl6Zy||$L!9Z-xRn4q<Znoo'@AJ d:ZT, R(zP\.r9\q8h$X:Ѐ&"~vvƥ.ıL&6Tk0n{L}M&Sx%jJ>t: e22|(@K$|>fADPm |:+()P.¦L&a2ůl6,k6L;BJAnKH3 r~r< |WLv!hALX(XCF]Jꫯ^[[Cy],ߖebP%o@_h 7L !$1 /׬P A<@QoT*՝ Pu mX%QbX6::J!DgNF2L6e&j)0ԊL&H$l j:J%T* r W^1G0 ^B0С(V*XGxGb Mjlct=99jHdGS\(gvM:5bߏxժ [[[8.7X X K4,>l4dgH nw"jEb0ySF^h s0j` fC"S*jC̓udRW(0Dtl6#t(-J\]]N oK;ߢk333AYFP"?~CzMt:BRlѐJTJRi4L q~KKK buuU{˽=/_TT###xz=$Z@|0F.fW>Bt:\T*3{Ƃ 0j,Z=\.K/tʸhpF].˗/'ѥ`F L&#NDZXL&RG=Ntxz9bp5*D@f;|vvvLOOB X^/6Stl6w}G"ǯ~+B,3ؼyjMFx`} ̐ D=,AX[[s:,5X{,zTh4B-'( xZP݅J"e2n&g0:L#tZrbZȥDsrYB@$G4v:,!l0d]b<lW;:JG:`aPAb+2yeeeJ|BɓMDBh}%E.NsuuvA`g  lv p4`?:XZ\.gap2`PX8kZ?PayJX%C`,ܤMrr255Z~D6_h,7LRӐd @w iccc~!U$GPChTs3͡P"N뇇8~&,5 f< F# Zm '[, bLNN ;pFӟrb Hzg`AT6 UgH$qJR4TfH/|^ڙ3#o S;v⥥hLNNbb{"N$QBT"@i///W*9]Bfm6r\~rrR(I"Fob\.Bƨ4iv:9`:z9HqZR y[t&!+V(ǁ[s e2}S,|AHӌD"Q>'l^B(TP D9___?;;LWt] aZ-PX,J2N_]]SS롒&rO/,L* -7Xd+B [ nOiRV >&~  AVTۂ v^o>/ ybd2C& DAR4AcXܟ>}h4Qj "`),a0c" !8pRiooE:Χ% )x8"ro,'}4C]]]mmmB$8:Zah,HX8z^TD&:,Rn/,ah{sss~ 28br^'vyaa#3)% IDATrcfOvh4<88؋hv\*JJ<#@hHRV v-Cb3<,A呑z= lX(w~i0m><&1oSR]]]]ZZbeJnofb0ef D]3` -e/- &6d2 /^pVUXF#6.J6h '} V]YYTdrV5>>N7 ]R1ȫ! g*^/w4j0:dj{\ZԾX҃|DDeZ$|zWH814YI|dd F( r!z7AJ &/Yr8\.PwRH$`Mam6AZ7`MOOcĸ`0obaAX&YTCZHp0 E UY)M̝I?6P(("P , \(rE>GGM/4%[Z.*B]: g!E}Dl TwpnrPAD}n E"ѳgώywwwiv` M=xx Tx:H%9Z"zgsfX &A:f~Z7prE.'0H \%a(X+@8KGֽA$!ok2b1xM&S8N$`I[&% Nbgd2t[[[;;;̽ it?8E:xЖ`_, Jbͷ9N<G mO-m&PISDeP(,Ɛo- P&p:lIhh4*ׯ_' ^zzDHwX[[r2 qXd֕Jb,+ ^*N#zl+ɾ###Flr٬V\Fn].UB;::j |.9+WJ6LÊRd2x\$)  hdP}ACγGN p1 NE lՕT*5}}}@2Nop`rsssȑ;2|oރΝ;^/r̭R(:mZ@A@2+8q| x! PEC"էJ Ð@iNe@gM@ d(D?@)uuu7e,3PJh{|g&kR922r]h"%l6\pVYN'm%pj!5 (|>_^g5N!Ifh@YcDEo+U˯^Bǧ鰼;N$<~ahh3d& ncB-1`Rfs>7}}}zcZaU(SpNpc|_mB8;;;== B*Rl6j e$ 9ch4*LHS2VK,/roH @q UdQvr=37(%NJ =ݏ.1SSS̓jP 333777333/_-!J߼yWѼ~/~ZF)Bh4 dfӧO{L=@Nh4Rh3#Q mh1V>:##vO >'P9n?މsC^#7% "(Ot,|tF`w!,$%`B{ izTFccc{{{1fOn&lDYP @"=h̷| HU 2Ŝ$9<n,d(j5(iPn۷oJe22 Lo,bL'f: V 8fs(Bt\d2ڜ1R .H8.JT[Rj^XZXB7/ˑaU@˕^q'g|f-ڕ7oް\\\Btc)HT* Hl2dS.a5CE ,Ipr^'I6 QB tL,#ŝ2H$:;;wR.sOE݀B [+6.//YUT*P"'aaXT[[[#h49䑼qpp[}ϟ?oۭV𐠂p8,HX9D"὇/컌2žwG|7?r{Ǐ)oy0p]3SG;crz)PPš!J۱XCr  3<<倊pX,Qv#@T[*dVdžu#@ccc/q2G 2jS|>m. Jf(ZÇYpN'o{p;N&A a&/8>ݘo<3ΊD"lh8"%bK硥v%b<&(N`{ б;"E [-n Pjfݻw6ONNr4P׷.hdd.F0;;[.pH!4;; ppTgjJ!3y",d|  4$ҁ[DׅVӠ?>>g{{{ rK<g?99!&s2D"=1=@iYllltVՌ!6 ^jn9\rfzm7S*@P4vͼhi LLL0i6222<<j  J¤#(t2L[ dZ}yy9>>Ib`` hgV+P>R\]] ŻcR}'*wNݕT*EfcF,gBJ܏ٵ5 |ƢV=99/GH$fN wFR)f  0A[i Dq$?jXzl<(4Q]f2tdJ$`zUD"AS( qtp\.wtt D I`ກG1PAVn; C28lmxl6Lļ^*NRn8RHH|v~m Yo\Nh< OX V 6E n} "iT*_Z}-)\ZNwvv(uJD"yb4XSR\x,1777{{{(;*JQt pTT*v;3BɆX~n5">0#D~ts) XLdgc,6ONN鮭d2777pT:~y2<;;bpn eYĽ=R3 γl617I8ƛBMTFP|?b?^>11&:{DBNquuȅLdfyoo^*JrHK.{->JiP(ܿ-IZMF;;;nX^~ GT*"ڣq IZj  ԰~\Jj5.0Fft:H*fQ___n7@+S#~fcnt:W:`'\$)> >>fi?ri:6Ai7U»9r9R B8#t:IH$333&R,,,njvr<18`1+(q\)i*Ca~~Wf;99X,8nZh4Llp{/X@&j\<#1aX,"HDZo\+`6g'Cx.ý[obbI$Haz;$NV2 :8f5,iq6iuz R"R$= N XZZ}brޮ>2e/|>O8̫y*4sYⱱ1 ۱1Պh2A7N:*4ݻw@rhixFzU*xP~GNOO>Q2xAΑ:nX̉R^ \(:SSSbѶE(ܨX߅;Q E2 db y{~d2$1"dJjLx&àlCd|ccF<GO^6Xh`M2ǣ"`U5ɨj$?݀jϠJ|X$_n;fzI6"닋KL2IVH$hȻym2)tra!Т!4"Z F[ aibjݦY̤X,rb:<88B(=+`R ZTZVTJ(GՂEGBd2 gB71:Ű|@[jD2&s! zLN*/@~^*NNN PrVEP(&vX,D0p}}-HFC!$H8 NNNZVpķˢѨJx}>36xJDH$O%IG"  B: 8#t:ݳ1c%VB+O&U$Bm4԰|w|^쾾Cf9~w.΂-CErZ\l6]Vj^a1[ *T*cccccc׽^L& @ ;_ޭJ%@{! -" !!;mNRI&'s0jjR5SO*Ӊ;=#@ $Bv{{}p4v0HZ׺p-[,>4r9$+} ,cr @$5sssCV=|0ɼ~k4U(r|ffr}ӟ4ֈss撩ar@Nvf !z=yq,Py5 t:8u,}nB+floY%A/ʣG E&aT"`^W9nx)|+t8F#`,V NBWWW$iZiZ|81F@]a7AHG!,ưnLR\_An,Zr>&ij"D7gqâf' .= x<mz `;& Z(ݭV OmHalEtcs۱n ",~Ff3N#^Řp IDAT/~ sr\J hc|,UGȅQit08eaY3=B)b a%P| 8ͨwvvuZяhr9^7H%$z0#Db1 bLtn'jf6H wt033s||¤;b<x"AFA6j0#KFܔD0YLIBQbJ,JdGQC6g E4aպ_$7o@Q7 mll@= o2>}gff` R\.C+P(tppf999ӟ488H$ڑN9S,IH2csRr*Rccc !(o(ݳere6zhhW1)>fR|"# ),޽{xxhX~_|ggg^lty%YcffA<0VE $N\|uNKWj5'.bH200H$·9F?_EN'JO'sN j4 H04=`Jә2 tzdd[!Lk4sCFAb Ç8a񩠂` iSx,ds{W7::N% )v L&C)58?!{Ѩ@#O?SFܘ-n48w]`b<I-Vd2auKZxu~099YT`;;;^n C|^+G"pT*C$Fy U.Sd8b1Tjee!D"U l:W^t&2??_trrRr LP&8?h4hkXE/DG\Es2looO~-Ic H"VH+>U*Tj!N鋋 iٙEjB}^gF)(JNRl6*ܻwv @p,//0O}N_1*ĉYࡢ傉KEVT"P(LPi5`P*t[_& N׳/lߏ?Gq[,"vVbh6,[PX__G'rpp U,c^yyI5Q, +.Zwoo tzMvsXFTi!YfT0H=l:].nqkj`q~W^CgDI>C ŀoł*}Q)^54Pڍ%Aƀgoooyyw j; c qLXS 3Of0q}}ͬa,anP1Rm+HV6O>|ܚ6^~^[Ӊ+? j} p/(QRK|c-821OOOV+!;;;ؽJ%UD3tB4d[b[  Voxd$+DV* Ϸ͕$\s0!Ln^7́@ӧfsrrd2a٢îT*}^`Jl}ɓk(ex* cX,vyyt&9obC3]*^xAԃ.2L"`?|}s333]~?-dRd2)1lR(t;bDrXyC911H$BT?AT&I2uX&C%N #Rf? -:x.N3Tr,ȀX,2[S(F8b(b_AR ! œF wͅaKKK*:Z.p8BNsll 77(C'ZH$ƸP(D`٠Ps?|qqXdLlJqttD֜Dq"q0)%lE0== >Ã8RN&\:R)2b[;avQ>I~1סr!NtJT*GYJT {lJ:r 2}fL:r\?cufɁIOCY066ƄoP(0jb hZfsffFp80'''g}ƾ.ckBBZo6p嘊 !VWW?~}"3^0ILqļE' a]__L mNy0TX jCArT% B/Hz7 ! +v;`0;Mb߂lp"*t-pn87TU:JN,QjA@(ɰLsX Znn E" ͍h% X|s9W}ptt4<< )eP(G{o"Rd h3~j18 kkkgx(ɗ@h4pȠשT*'''Nnq3z]^/ϻ\. ZY)Ty/0eqİ$|4x-Lx0ް5^zࣇi?. H8###rI!\.Hp°yI&?KR,#JV t&bY]]^RtxxYhrI2<<<003{a<#tu8 ~ҴaV7ȅk;dFc\hSb`]*,*? vVMLLlooŻw>yvHa z=ѡl6[vZbT*tpyyYsddDz;hK@0՝uɔJB0ILyZx<ǵZ- R2D" Sl*|0 ^Et07z=W60=>>~i X[[KRWWW1n7yNFgM !NdV ^Fz*H$X^\\l ytvv@dBxPN89(1 vsNL?.Jh4pP$n{aan[V<<.ApK | '''nu9&qq{-1,O5F1SAl6i$PFFFpv ! )26 \dӫ*}rLiL@V<9Oe>9*ݎ}aa B(uP+:AmFj2T*v8te┟=A9"yχG椬IA6J&hȠ bzDr||c22 +8onnGGG- CZt:[[!V<>p0sssZmaa(]89G˅kj`9>lb5{eZg !8s J2!޽?)򹹹Nh4R8P(45BI^/ǟgJd2pMp8(Uhf3r3>Ee(XAՀ7RdH| MhJ Td2xOOO uHqDZ93@ J333zP(x<@d5qP|>StB! St뱱1lzzZ"@H'_jbv̚t: GGGqUETHUB&T*yX,R E8vwwiw8 0llOBS޿P(r9HQ0Pt,@@t{{{W9)9qL&x-t-2S s0⨱WWWKl6X`,:J) ,|:,|>BaZU A=J$HI*:4MXip^(766c0 3'* B8::b< _jkT].\*cL%) 3dpRG X&AO(*/A -RSvH(AFᖴmf X,|>>m?!CAfxYS( coooZ-z |ZJ%.x8ڙ%\.a |&0P9U7" BQVU|ʴ~-jMNNlb֣&"w333h0)Rn!*[oY~Gx0j߿, NDp>+YYX1ÐbcC=ŀ k\q3 x2'׳RNRQt:]|_eH;}R4< @k`LNNbzf8N4łqhm d*#N1NǣjU*Ȉf6666:::88ȾYX1d~JBHV@pvD Ҥbb@: |hhp06L777d333###xh4NOO/q:~.//Ҙa^ bj^&@T`vVg?8;wwzNx|>_Zdڌ d ~w&\U1Ȍ$߿>K"yB>Edr8^ꋃ;8$"ѐN]^^݅2|>o۹ÕJ6.݋ B0>\\\g%JGeeemoPآ;JЊŞX_I_s`wijp8#CCRvbl'&&@dfuuuww-N6r6hZO<1L@oH<}vwwbd2&@zc724o4vSh8G ldWi@z= jg"Cj؋׿Vr92JGd...~L!Xh28ҷ- 1fتY(^xel^Q)@8jj"wpxxd\楨V޽KRlBd ~`T4XKC+:88BԱX,4$kآ {_CZֻwﶷ ni>FӧN3N#z|&<"P'OV?zZP,3TeNώB011~/yf5>$iZh$LƲ*ʮsLud8d|‡ThtXWxj5;lF@Oz}<88zxx811 b~X0V*`0Hj4^I^ d H*e&8R fM:L&CWվ{:ׯ_/exP|x~?k\.GZ sη¬q8?FxB` Ulllh4^jj6lBgR"h4677@I BP zzZJ$AL,4Lzޛ/^`ۿK;ҧ>. zoA.~1>bwST ]}}cF޽c>,8)'''z8t:8}.1|>Ťvl6#H,]V BLL&SxW*4߿xC=;;a#f5{tFTuD"f|LP9Ç1 \. 0vz]\twܡSԷP\.LLLYn+P(d4Ѩ盚B9E6X,SSSꧧ#Jk%qJj"prAXTDnlX w<#HXHD J ;!0XB @Dli򸾾>99]+h>P(HR(4Cqx9AЏ`v8Pz:+!O>1hqlFl4 d&:H.v199)F!#0xVV߿}seITI$IVݽ{W&% ?*Rbrcw$aGP2q'/--MMMmoot[l ,AzY4X'Te IDAT4 BhٔJ%vwGq{TW斞]XX /FDd)P0A1L8*8I0Su2>>Αe?p !^^^+ s``~SAUX^\.E0 K4'O~ 0tb8v;?GO^' JNg4d22 [$8MCl^]]F{++jOҘhaEa\V%@)}>剉 n;::de{{.v6'WIŋ`Mπ`Nf]TBĕN]I&ZPtZx<%xwx7D WWW ȱ[V RFjh썌5yI}0::ʮ.Ķ> у !p.'ܹsr,S灿W^]^^ݗ/_rx~'Oh;Rw}ӷhlooIT*dR!˟>}P(E(Z8t:-όfjB2*fJ鐀>q(dRDl61c*;99Bʋ""w~+Z >Z{{{_} kssܿ/..h4R={ƤFebbJNblfĦN7a墙L T*3"-*,MNv=55ũFĠ8CB@c J44Yo?00v5`h6x+:V h)@`pp:I:j9x::zps=jnB&W {;9a!dp8pj`axussΝ;P!ORL///9I0zXZWcrrr2::߽{'*1VhzlEa nQ/^/MƊXgXXp}Vꥥ82.d2B)\NtUD"WWW E7F+++zjr*`B\\\nJȭ ?>v1MZmqq[Ʒ\'>S].0- & 6BH]f2RD"i:h4ʂDz@,ZGe1mL0 u:N ` RVc}oz!>+VXT$blpV0¢YFsrr޽˥566)OxPv{ccd.* m }Z2.t:jXu+Jab1(IWWWG"`w߂+1O]%\%D"Z-)Dbm6.>wkkk<}Qv]Vf^N&|PGA2)igg>V$iZ\䫫2,嫫+f}+d\nddFaUW !z=qMRlKytvv}?z}?5@OJzD"a&E.8f*&B8~[ G"(T*u~~j4VELƼ9c+0a׈vƹz "xx866mJt`/Z+Nz<0a94ѣf3V9Cq8n]%Lyz=s/>-6m@غƅ1JYYYKZ~A]__?{v]^^fu lWkkkoH$^._+mK?9vY}> Yn\__s1i?@cg(yL2|F) }ԭ^_^^. $d600t:i j5tL?f~lOV }@,`+8Ƽ}-;$4GJ޽c4M $O̽{pۣ@GaZ[.GGGVP-JъZ9hpv9 h4`+Gd4BT N -z˕=7Lwz,̕P*PWa?Td=a&!2= 끰2go*0l6{uuU(F#XJEPڸzj9Qt`#l6ojɶNr(xl 3JꓐkڇoaasB4+@-Dݻ<LOO힛cwv~b 5C&&&c_Q*UFrnn! ^LLupfbbł|',jaF|>5UtBN'cʕJd2gG"cSwa19|{Ha|fcOǃ'? !36\d^1dvxR9==fFsppha"Bpuu򶶶plD"A 2*P6،j5RɢgȷKd`0Ȝlb "q}388ӿ !P/\c)`Nu8 yąVןt?naf8h #!h&L&:V.f3 ^65y[;;;|>J1D,e|?Msk*ZZZrNOOHDVq5°x4@WdL[@ȍZ-^ tVFVOOO3m>V.X eggp@w>{J:jj4[^yT*ҏp-YJBnw8Ix^|l9)@ MMM1*p݈j2# x! 5r^9)*LJ1yeeEAv2 _(7.//;sss&zݞfIegD2??πz;lZ,@/,yG)fbԯz=$Zッ8HL'''B:Ɩ վd}}FP3㨂a>FHrJy(Թ\8G`00( |dul4Md. v!lcŪ5˓&+!rJ"GGQ1w\:y P.=jޞ pl6R)L)x3 f?lj+++T{[[[D677zBT*vtyyɵqssRYxL`c-;L8'''! fAlG]ȽO<5xct/\( -7Q2r\ Jemm}Ckkk777& GqA"YH% S! P<;SOs! W*/ 955e."'FAv:PM;1;::QYGqIG"|>7!Ⱦ*zٌbl999p@p$a=B\]]KRàw{S؞iE 'j ~(FċD"ăXC's ;̣JiGL633Cj~~=azzbp1RnBG6,}Lz>66l6#;::a4ecR$ÃvȧRܿ `$/`b6e:CRd4Чa"w:Tx kyXW8"ώ |>NW**VH.r||!_[nۥR~9*h* E`']hQW^z&yyyFAe N 8\Rϥd54Ka޽CzJz>sm@U*|lKҫ+8|:wU,=BV !c4NR2l||8z@0Rh4:YVd2:wt !uB;f ...R:;;ކ|zzZqvv;-ɠ` !G<F|t5 m@P&( CQ@ WX\j[R2BQBvĒi=88NO_KD"q]p "KbMhPm6Iԭ\ HlnnR p޲)0[4}N<<2^NիW~`` fdy湹fx81Il6>w%åT*J^${nZ 긼03BQTcXz+++8{ሹu~5)tKTdw% VDI~>9l¤:` am󓓓lRFq~~>  4q:. / 5i[LVCJf8 f9z=L Lz=lkv Ba#;;K)h:. jd9mC|@lLѐ'qpOk,LpMZAX79@ P*1STӹ{VXgFd2Y8g17 .NdI*hSͦL&i6٬5%ˍEEJf4.NCF ?؆31ڂ]l63 5Ԇl%#9NNN2Vh#JamD2>>}0 brrQ3d2\ԻBk7–>,GGGaYG0퀅³ /ov}V+ [Ìp&1 a|iL"q6ɓ'Fqjjࠏ PZ[TscZI΀LcFn5b1\%c붯X tHB|$;BU&yuuEc 9UXAժf#$ ]@3=|l,IRRn FaTjQ0RXV!Ds:T~-QijIFrR2nX,0;[IYT*aDFb$ nW.4=0 ^\\Fcܷw:Vтb+O]vA[,t3Jnoo P*A2"qFQv$'N2AYa|zyyIC׃n)\19tn7=l6&  =.З_!>M/HqrC%WU z}ss96}f<؄\\\mbvj`j^&>%'$ 8yU*JbRڷgr_)Ppm%q0pȚt:>d23zpl6 +ĪW].=ł|t6hŘ?AӧO<S *\.G H$/k3ZQ2V&Bgӎ8lwPzp8efnd '=l60:::77G F<9#lwG'H&zBbc:v\gȻ󻓺3<<<44d?|>o4a` KrJ%lR{}l~Cfrr~vכE!8orZ].YW߻\R@1 IDATˆl63T(^osś xe2dщ_1R455y\PLMMK !loW&aYQ3<<D'`p6f9Ȉj?y6:.~`ݻwWWWN/~jAˊF_|L&`0鹹ׯ_ݻwl6|>TgϞ2 ljZ5P2pGJlܚL0_k4t3B^h.ch4`1yģznL$gggċQB!ϬD_ a2~ӟO⚇ݨT*5 k6}U$A կ~׿ׯ_/f/RO~dz!&TG;g~dUƖIjGܼZ(6zOi8܇\ d٩)'χKdpp0LOOa9Nnmm5Ǐ3AV@??)fZ?;u=G )VJŚպc0@Ƶ5t j #˗/£qEĨV@㹽M5zvvFEpyyI L&6羞-w0[L&#Hd2?-"B2{! Fj߆ 56 'j}#INw||l&&&ȣ̠?zhbboci1 @.`$FGGOggg/PގӒ !P񊌌F.r9ͅ;K8F_z`-nZbxT(BhBܻw2™ht! RjiWWW\K@azE=yJ EZT*N~/R}tt433Ä`G߄h<{ 2IFo߾t:4Hn!BW(cggge {XƆxczhF(eݮfc(dhX@D`vvFۅktl6;77 Vr9!D.{y^|)HVVV={q^ 3`mm wo<^ `jjjwwwuu.p8"fã#x<1Q`@ hYOjckL+;(bĔ~%Õpqq2?s8onn[X^^~9[RƋ/lIRE/_bvnPbi ݬ;Օ0^eT)(J yBP'''Mɾ7Vh8/K$T xx/@ V*+++;TSjV^\ݻwRo[\JkkkNg}}R_\\|1>nå%Xn5?/^ UH%)xbU"nUU|u$⫝tJ%A:Y tOId"?~_ W8J}RѤ@  0c1r{{c~4|Z0\#QE8G[0 jMCCCXny1CJ|t߾}o {ssŋG0Lfzz3Z ruu;ÇNFbdfffrr57 V\kz^VhtvvnǮbЀ !Ux~Ǩ 3##P*;f27optq1E -B2#bB`| 3)FBo2... &1 äU*{Hڵhkr|rr)Ç\N.ElE`o <ɄNr<Զ/< *Y z=^O?cqq۷|v`D"^_p@px}}d2~xA8j]JerrRRP\` yHaR4a>jz<2J8D"aXئD)]ԋb:NqQ*8Hl6Zh4ϳ!*_F(Hxh4b{N,J44}µppϏU(}fB`Jb)'4]0'z?4P|J%e$R@SQ6ّw$L###<O$!ōB ``ll`0O=Ro6k4WBjJ2Xټ%488יP;65#߄D$ln^F^ ` \KKK3{暇nF#3yv"'w60l䓱eJo- 5d@L>s^CC09Óh4l6p[[[D`onn2d2{^sO4~'''ТzL0u: ?A:~Q7e2FAt:ñNqÒtݬ>b kH !@XL$@{?~L&"FdF^n'ɫ+X,hNnwrrRR}Յb0<<<,ˡPH& }<~b,.l6Ђ;Z-v>( ǃU{x=i;ޞf|VkjjѣG777X,~zgggnnn/..Gb1ۍ%oZ=@ 3!U<%CZ}rr!fr[VvܹsB5ϞL&cspp5h<5RzsYFqnnUnuRɄbg4# F͛7SSS ǥRWR$}i\F@`}}}}}a ‡@Qʸ3!SGCZ*JɁG+ip˰c^%+ ,'bbppr`03RG$) Z'"'XH?Sy}( ijU{tLtODwQ_1DL/R5tee妙+*(my}ө<**->R\f17D27?www䴥t:` sR,cxl6 )QZ"C\l0 T]lЉDs֭Rxhe"/m8iJ*^/:31ĤH@ D"Mz%dBcv[.>qui>x<6HBx0eBB,S怛P(": `0877Ht#eY4mRܜQi:{zz@|Y>hۡ&yDuP`TNNNXHMEH$R(\. kwwwU*U?ex*h4`7MR;;;(p H^wvv]7o~`X~߽<\af0YZZDx`D*R\2 {\dt -..ŷT*v{&988p:}J"\4Ap:. KKKXr\}}}X {zz%!3F|<99rii@%TWVJ4L  zXr?dV n(ж;KxDr9vX  Nfs{{{WW3;uȼd2bt\v]V'0kfEXoq߸%M&/Sk׮iZN8F[[O<|pZZZvvvvww'''aѠ8- `D-1ɠWLRRt:Bm2ɂmkk6"50^L0ZZZAŭn+{7::o0t:\{v')薖pY!vtt*J P(`nPT$ޡңfL-'kppbXj"9X6LC?hA-'Z666 lB@74T bLLLO4 t4%lHP+ ĵROjLNOO!P}VTLE,b߼y@.dFgɬuool6'ɕfdWel?$tvvZ΁3T*& 5>̬2 ldr|wwt}t:3\_ommĸd2|yddV&Tvuu|2L:Efj5H$BT`>쯱Xv*333ГBYT*Eh TA>DDgggE" #t>62 N<`whٕ1Y]]{zzp`o{\ @@R=~Q>=lQI,Acg6BCC[F2͛7TJ&CC\80z(BxrBJVS,{zz1;H$9œB.ROb.[kV[P ZK P)=mmmK&@_|U"񕕕7oy_x.>+JlX,GjiR NRťR)\~p8?†0K$K] n t3I^drlllmmƍF׿5[ӝbIVT*eKK$Oz& R@)dϷEfj5OACtW;UJsRQ"AL`;zbN!߬J ðM-x*jfp@h!4!c|^Vp?HIS9Ac833 kx ƃZd2'Juvv&O ah4 ad|~T*M&d< tʖޚ‹/(9_8Ǚ TQnᦦl6p8'8k &M".Jfbb.1QLZkkk< `\.?jddv棭\^^Fpvc4 Eh'LFJGss3U0(ACZ$MMM!=::]ѣP(hV~ІbPw乹x<~pprP[iP\/_4 \fyzza! =tш G CiLˏψetlS!9>>qjjb Q^~4Pj4d2yMA@JUJE < ita`l6l&.9|---J 1¨鎏 bQ(hѤ V$$ ˅c"y].u:h4*H!-JSSS\v n.ollDB#>Fd2dmF&۝N'lY ԧ~j2޽ 6Ǐ߻w E:::666Ap:RXw} EuNn9==qCv*J޾t:9::*Jzb1̋iZ-;FD#HPzzz02`ˤ馦ؠ2RP*b( rwvvX,4V4RBJ,xaÏ<*^".cvvvddjR~ Ɔb˔#/^T*^7R#a\[[cT#1AzAS.Jd4 = m3fRG/Ҭ.[]]];j/x_Z3B1{JO$l۷0<ݓfå;Rww~zƍx< TױX _|SkX={J%ҤS_\\hWkkk0l +>T(<}>{ss-ڽ=JEۋ/~lkk7o;w\]]~́@`hh跿Ak/|>ߓ'O`BLP@eqyyfZf`0Hgr@ @c]ˬ\PpޡIa fgϸeBEP(I$y^Fzɓ7o Vd2bgxxxɓ' Qd===d(Jf}}}h(9^ŲD ‡/VMLLP'P(DMV.z{{2tNRiii-˗/ k%8uK&󍍍x, Zp5qA;߅;q#L$s '.G1ꚞ^]]ll 2d2 /% T OX,j=ٹv~~>66V,חJAj4܉zp8x6SU*HtppƠ\dT*.ETJhh@uF``3L b !g@j4KL&}6˖d~+L{{{KFZ֖ D"R!@ش!A@䇲3NOOO '/F^n#cgvKZZZ ÃfҒ^C >bӟH$eh(Q̜ hlld1T,GFF\.\LByWW2Eں‰/ p\DKwuu~|@:PWQ |.NL:::`RTlQE"~_􌌌psuݻw/*nXXXj7 ^>gzj77_|s\njj%9`~I 5M|=bXCFR ͸ dk NR(eO%J)ZFlY?^T&&&4ׯFc(B/%DXKd!'͡* l6 ȡh><< gÆQ>\!”dz> ]^^~;ߑd u__6rxdqggg.k_ 0<<̝۫P(,ZZq66H8B1nق Md2&''hח޾}KJ8J:u^F,Z~ǖo}[buZ}56n$AM,R\.D#+++]]]Z[[aa}0>De||Ɯ5g_oo/D+8c(>I|jr r9b%DjV`t be|˗@SAO>Exzz*b1֣#P$ ދ=d  H$jllD8{,tÙL: uRGPqi]^^~ٙlB6885H\.iwJSsΝoF"ׯ3X B-_....XL6rLITX8 Cwww8>;;}Q^/~6,1V%bf444d### (6 jŬ4;; {#@ $!d`pbbblllcc#x}}vf544jnnnnntl,l` K 5*ů /wpjU( " e.JnJjnR;;;4S od $.~d2bH,qqq'L yXV"B{{{܆'dD![D$̋jllDb6\]]ۣL[[]]===lV?7oDiZ3oC,{GsNG(YaV3Utۈָ'CBd =JۃU*j5̓ZrsSC+\Z^_PPR+ pS蘫+G@ 2O@2dsҚP'JAD"sh4 qD644 999!#f!Jȉkkk`Ri4=::@7m:L \A>[jssݻGGG+++R)nTz5ĩ\.s/(x*~߿[. >C$uDCƺ ~,;>>?bH${'ZN X^7>~vvdž" 1븸x)L_xpppyy@b {||TVD"Vf%ZXXZh9؅nmm}GSSSLfhhѣG>w]?TZ^T;w##Ӑ4N0lS^pcww;@Jua>q4w҂ PemhhD"xQki^"R) ~].rUxD#Hcc 3d?$}/~ L  ' j?ImmmEn" A~?)DKRX`yh4^򲎀ohh@ ɄnQ$I3 wvv@C<C'[,oܸAx>/B~V#ٜ)+UX&֭[fjC"f)q]]]---Lix ^(r\`pddq߿ Y,ؙJCHP \TRT̕Thx Fn4Bm6 wϐ=`>>>eBXKs*b;h4TₜF;\@{$p8e&,o!p[jxa, `hڂzQuɌFJӨ nX>H$4]]]f9NPBì "\R)N̈́ӳQ^h e\.A!7F"Vt~rr0 (FNh:fb4GGG9NOO &{`08>>.N8t o{{;OgBP(gvmebՕV*빡!i1d6SRl0D"QSS>70DLߩ###@}KlmmsD"rL]N-΀)`lY10#J7Mt wd2`'nbp,l鱘A^.6ԡ'[ tyyxvvvHu_՞wvvvR\YYa /^իWhKP\\\r||VZ*^|ǿ^V#n\|ݽ=,ؔ0 Bzuuo|cvva CCCJr```rr͛4BB5@t 08۷oafYD'''''',R) 3r > !D"F;1s :\ A[vjVU,C{=:wffP(()RC,߼y"jllcqrrKÑH?fJhNcc#B@}@*–ZT*$ MMM.+~aN)Q/ɃG b~?C^뭭h R)g"zN!2?؝925؈<OXlooqhݻY!C >lpp߼y$^fκnN+0*>blyPcj>mޖLRP 17p" l;"Kr"{c ټ7N9xnkk BH$n߾t֭Bƍ< e7|2Pl89fGGGqd^zfo^P(ЁJ%~`gggkk˗/Vk6ee@[&˖Q j T(W0 8/7n`s_;bH<^D¼exxxvvƒ`>%N3MMM booARC@ZYggR|^w@5dc"K@$G2n0Owpd]Bd`EQ vBۀ?@L<==ۓH$aB!H/|>R&X%q5R>H  x[[[=uB! l6026Kɨ$v3`0( g/JdA:;;b1p81{JE s頢Q`G@mA4mii) 9}] {zz?J`(jH$c,%wH]ЍZX,rEAnjjzr۷%lV IDATׯv'|3J'Q ?͛7 LMM!υ+++kkk'''>o~~n8>>V(`` BRTZr` +ɦpGVXjX7ob, $xXVSGGGnh4WWW  T4HI$.k~~UT$H$`?cs}YssjU*h<NC3R'OhRgggLz<-mH&r``@*8>utthMϩ @" >TTT0-//D/jz}}37I0 P(ykD.,'x,E@

zH$rؔE"L&3hi(v;='d2 0Ncc#J6i\7Rzl6JL& L&Ӊ?Vj~!k׮t:A, \vX,wB!|Z^vA7^qNvZ~Hf%FD"q333MMMdGGGal6hׄG򆁁@ėT---$vq Pzjآm9-˝;wQ(,6>>p8.//wwwo߾J|jjtq ' R6!rɉ ^]]􌎎h2~t:Ml%\|,9Yr8 T1F¸yRGGa܆CCC### PPt:>==-ɘ`6 vww#Lwvv@wD(S>O:oۑH$x- }O4 vn"2-8q[9FC3337oޔH$brEQBtBq Y{xb`Re䍿T߿B1(T+L|>st:fbV ±x<333p >M#e2s^:JBd2!ƸO 'r71Ԡ\H$l0C!Vd:QFb%I$AEc---LFTlWT>- ozzZP@K_ T[JV*02 j˾o={*ˉ gπe 3hDUZ58wU`M`@VI^V{5 ؆qF &V...^|)Ji`kJr{{T۷-+:-*~|Zmhh(nll \\\,//T*^AR؅bp8|]R E_1L\r9ԙs 0XZZQ3(Y fOh4B\|Ψ_e h4q`qX8p8l CWWS)$qtuu)̍/92֘,..Z]]MR$ 8y!~kkkpp=''' cAe٫+ L K'Qsxxtb .ѕc^ψ/FCM՚Sٸ b& V+ ].xHdX(@Dz{{=R'OPQEBQ@"bq4XζF, Fi76621jwp'f԰6 ) &ٓc@!Fv]svTr#h6puww_~=ͩTgϞat\D*R(~& DлAH&8HڭGd7nlR(...`=uW_}/ahhhցTmjQFwqqQ,$5[VZy` >k>4 Z6J1A%F5eE"([[[hQ>\]]\.֘0 jzlxn99PUP5 BzZGRr~RT\.2v;Y";;;6]FˏrΝ;o޼q\FG?صnJ|>(gfFq`````744dZp- i~ǤX,f@' pxx8Aju{{$Z0 {X,--ɷt:j \`T0Y6Zv„;<`+ladd|oo zc{{㹸H߽{y M'OǣGz=\.G֮ AH$dqEJAwxxp83z'*o}[+$ gggHKk|ttd0ZW 0)ˋDC:|{{ΎKI P(QfciKPMC@Q x<qW?ݣ>Fjh.//P>EC,1Zvss3NCD"PVl= qk4vvv{y^n7oguvvl1TRjd pvvA@p8666⋳3B!reF᧟~ݝL&wvv4 󜫫+5<u:,jvE}ZbjTZQaC" 5ֆ14[Ah츢x$ \JI^-el}QT~z,[XX`(I@6"NNL~:_0`55";NL2t Do߾ύF#+nWp|;Ɯ%0LgHtл}q(JT$\^HxP(\0e)x@ d<M)r{-..R毬Q(sӋ9Q* `LH%q9Rj壠P_⵵5`ulh4 . cf8ìIBSzee` B]]]ݬV0^|`0ƞ?*cssL{<ϧ0\.KOX vX"VJ`I#2ͽr|hhH..'5# rt5CrRds"qbfPpy@fv$&FQ %gX̸f'[[[`(l۷@}';;;kkk_};#d2!eнs: :DRN~,a)rl#T)ONN؟Yr'&& &kmmZj޽{]A)V^077U>7oT* kkk $IaL$*4p18bZ.d2@*lwwww{{,=a[[[00w;H1́^럜tFLKA!H:::vvvJ͛7/..TX,6 ݻwlr9VHw4\._WNb*y@ T*H$l/.. Y^Q坝X/..aRnpU՞1X]]Z^cuu5bsx5HmmmX755bGP0AH #BJ@)ѽ1tju u+ ҡP>nDA4k6%X,T*DV2l>.eFggg~?͎5dd2n r\ӊ"s|h4R)SY,Ro`؃CT\PR`PD"Q,M$\p-,0_"j&t:qissS.ONN:Gs &<>>OE"' tE:huH (DBAGa\@yŃ9^1ī< V;to޼U999Y. C+\PC~$(nܸHޙhĈG^4LCCCj?$? BLH$?;;;Aj:>T*moobtttX,ݭNx ;3[Vs X[Q~_\\t8lprp8\.WVVbU`ӓggg7  AVWWQ$ j*Hrg0˪ 8bӹ}uuU,QP_6!;dB.4CsVR_x<~uuN|}+ 4+ \J466BJ$8dbښd666 H$Bi  I*'?gr"a_zU,F#~ؼaX 1]yyy!`tbhnnhBr9ȧ7YzOO_|G&}Z__akk~H$233Iگ~+J2Ͳe$)``6~`)J ڎ_OOOGGky`[. NMӵZO9\>TLQљfʇ`0 QzL&h[LݩCp ?i0fGq, x200t:ᶶ6ǣh]F.惃ׯe8??allZNNN`8O&">1H<1VUԖhȌ|fV5r744ZT<777fϷR})J ao4 "[ ÁTX,s:3:[T18==u: H$WA{IL(v ]]]!B &IrH .P|d2ċGT*h9kF&:NUss"9~nFՎ~W}}}q9::ب\"HD,j"~:5ؘ^  +ۑy(m^VjSSSt3F.wwwĽb9対kMԳgA G P0W^a *D\N?Nf%ٷ}>_6f"@ǂZ:9>>@@ЙFgϞهʀҀZpzdGu\~%tuD石mmm B>O&uuuD"͛7"u (}ë2B룣SáPHu  WUd\&Z%s1!p,q 1&b .X%v!4R\^^}0z<_Ϟ=GYOOh$ji׮]s8ioll#`?~v%---azyTϟ?~uu H$A?u4a:c@ ZNe B RDdwwwww{FZ]__g o޼ Db6C;588xpp@֭[.vPȖ^lfGGX"2N@@"Zggg333[[[ mfH$-9AB*۷ofҲFFFao0d2F#(^h(>dۋ̚h4:11̗˗>DE#jG}$v'$ I$D$Cykk>uZll8U*U\&r8p8<88j!A+C$n\. 4PjCsNC-#=HRя~D^bLl"R'R P`,H3%>(?`T*2ZZZ^~=>>ξ G7mBb8N'T0|[,+^;޿L3A @g(Y2e>ΩHOӦ[W]]I$";%JI9`"F{oWZƶDx<;FXϢd';)ttB}pgM# e6p6l6׿F v<t:$f|~mm H&4 R?O?3_^'u%tf'+ýVjѹl~(g,щ_h4C#t,,,0 chq#h\sTT$HjG"VaR9==ESDJR,+~bKyxxh6wvvnooT*We?88H&"noo\]] !e&&&J*NCg9Z߯$D"77748ϠiPTX6A=œ5Mwd2Aig{d[V@lO:`_|`v8H@u>oWIX_Wc|6$j2ȩhd2z7LF6ɴz>@Q}>R< l Dj6jJY1A/..ѝlѣG\.N:#11.&i.hlZbF~K׃ LbxjL^p HR.VK; GaI͜;-\nJj5e:е1+JTJ" $pfYKq@!`#& ub" bꛛX,vss G~ |Y<||$j"繼`PzKKKпz.ɓ'.--᫅PR{ O¡,`002K$8O` Ғfø PaLH0nZZc2Gpse3 z=*0J4Y ޢb4!YuV_8T3 G 誙Ls`Ҍy{l__">\Fffp8Ծ{ 7opF2n߿PծWҝÇ?;;ò 2AWb6aҧ{<xi2`~||L|!촙\.W,2UUjV!l0Hh4#W)RAf>,٘@G6 h5LR}/yX?|\.L&>} !L!t(jZ@:؄1P!B ¥g8:XU<N?UR2s0 Nr}h\ZZBL&,Ɂ 7IBRI&lFcss6HTZ[[spXRqz=P> p-HR~:n 样b$rEX8f)>l6 x$_U nL&ȣ\F", D/ BY\\bFgP38=.^;2+7] ߿>2 9bH@g۷ m=H!fs1Y BtlM&SӁGh5j>vǕJhj344HݻR2f/4<DZ*P(13+J͆F^O2 {mÇ%FooT n4noo1>>>Fel6IerrPZ6bcK?;; U8Frg*kzX^/j%, +PMNNnooߊ($)b&9*pγ}6h}5X,D"sRcpTh5X-Zz}}3\.fNMT*%X,6 d^Oz:[$|4v i*tNFidDZ $ZMp|8vOdC4:tx|wwwrrRV!B͛7`rp}A 9::VF䄎P(|w$ B6ž5MOl68HV@$'\T*BegFR Uk4˿.--1y CҢ.jʧ2^onnnmm) MoZo޼ :SMXdO&XLᅟ(\T aLl %:ThKD"\<X9N1"`(|>hoА=ebH-sO*~xAB855eՕBtݵ|>'3ejvc BGGG^ogg*ٜL&,&T^OVxn7-Lvb -d>zh4 j5_J=#@(Vh$˅:\cZA4ʻ[x0,..b}}T*-;МcaI۳3.o´999_\\AC4 0E"lrrRRx񂨇JB!C#YTjr6;qbs pL&;Hw:8`0vI@+~YQ8dE誳nݝD"_빹9'ˢRy6 ˎb(,i;׳h4*ĸP(EX^Ij+,ˎOȦ5 vtKhG̪kFV ,>%P(X,p8JVWWs fJGn7૫+Á_ZZBp8x?+++ntyyH!%BH&HQmj{t 288$*"c_/dn0R)ѸǀRL&cnnR%6@ @1Fd2BR^C@nV `شZ-ϷRG}rnnfeYk =7o :{=J}~~.J!’g/RD=f5RI. !">Y !8ʙp8>>[JSȌL'Ge@F|bq~~^.`ajgffH2p~~޽{L>.H趈+ǽ4L( t777:. FfHVggg1p:$`M!chhb=66BP#o0 WzłP0Rϫj.;X*m&a0 !@лL&lg$ DFa2235~hcÆ/c8b&>3-??| (fbʂb8ZV.>hqRy10tk:NFh2,F93$=QLz=^G^t2#p0رp%JBNgP9e3N 2 JVM$h+oj'O62hO$0|R+A2ml6OOOM&O?i h8Cv0#!㡯dj A|?ey}(;|^k#$q<{V]__\\\0tykkkJ޽{t:|^Q :ElV4bXhCPwylVJBbP%$Nv~?Òauu TgтD)gggݻw{wq^]]cJh܄h[,`.;88@+h4'L&M4[hN*gK~_p9E& QaTr&t+`)1|>5BgfLinLL^\^' t̉ ~OP۷o"]*ĵ<\]]iB`˔e9(EّBϚrԱW.@  9H/UlNNN!`"YVD+p===U*jukkk8Z>Td2yxxȦL(n>GGG\d2r9?v`2==f߾}KFsf! ANMՂG9#PZB` ?y4EE |h`}rR,d2L&7666[\Pjzxxxxx Y#q6@FcT\fb(HqUxPㇳ3Z]lv)6}6CpO)vͯ67 `q.//Ύ">8Zȕy$4N]8@ @{$JFV(^d20IwM<>> D=F޾}; v,{ * 3{l7 vrQg=} &p fVhU*Edlvraٻ\c!ן~Zvq !@fnnnFrzz:/,,jr u^"`x:ϧR)T@$kJ$l0LHb"b3qZ& 5]G¸GK?!q\` !Υ@www}CKQ"zbGJB} IDAT4_| i ITD 6W~v\ccc!S#㛝\]]QAr-RC>~_CJ>|VGglgonc9`! ^B _@t:8jQ*xd2f㨶Y I}4‘`0v#k3Pj8 rx`E8χTUKԑJgkkJRy'\]]iQTdLNN$BBw\nJؖF!ɰx<$399Ic%Kj1m8wsb4("HztnnmLP<2T*ڈ?9Ը^wd2 XVk09/˕1Cz.+"Ą%Su@OJ#/(JXz4[x<9NL81RfT*1,3EBP#OeO_zU*f3v777/B6IH@h|zr"z=wzz:A<>3KΎd2bj5 8fPRXb GU4 V 륙VRw8!l6>!8}$ B|tHvj]xu\XeUX^~ ?DX'˱tB I=VE5 p\gggnR8<>Be,K<>>$L&LOQ_&Я =!ǵ5Fl0JSjonnvvvR:XkЩn{,@0䯵l!wiؘG=cE ߿>~~~n7Mo04sVVd2G,xG(nO?h4}Ĺ sh4lGcP(9a0z82ʀsނ3t:VN& G.1# [+|ra7:>>&u_sss}yyrϟ? H,n+(\0}>_HkSQ-..6MTB?]TܝT[v<zP0 7paxet@ *Ɍ4JoJ*BA$J $~2Q$lJAq`c01ίTe: % ^3kN@E_WRla6n74- 5D0jo߾t6t2R|d{\rdn^Sc-sx<Ќ1A2'1`H甃D󄏐&onn''' v ze(* B$Al6].'|"`e6}>ڠ7utd^Hd2V$,wmZen.J)u:L&s8FeE\@M&S<(? w9H P3+aWߟf0TT1PݻS$$Iz\݊Rh+3OdY0љraQn0Z$2rNFbciCfff0Zݶ>8{qN4xyGIyBzYx\j60 2ؐ(+A:JBKטZfLMjZ$98 !CNjU#@dj^8]BۥP*~&#Q(~VH$$jEDB2 }"@#7< & c@Ղqrrqbb%v@RVu`IZq}}mm -fnQ\^^NOOBT*766@D"[V+jK^C@`0ѣrHjas\B`0==MS ٲevb#Igdž :nBJ23þ (C !hǣB h4*ʳgxOMR:܀B@Cgxx̀AqVbŽ|YWȎhXQTXHtF"tO&lz JAs3"_h%kkk BVo/..>#6狋ccc777\\Z RxPB#\B BBd2#{b r</n(42 >ZX_4==NBz;;;BLGRBFYpI2M0I/8F@Zde>e, .T*|)l02"8} *Jn ghQfHTt>N D"a'hDzلJ$Rx7o`rC솄˗/2looo{{ʣ#S$9_~ h pnV"X`GLTR'h_2G$XC\ !&''LV'̣vR"GQߏ𫯾rGGGMh47oX,/Л7oi6/m.kZpE:TAZ l`=/gnhZ#|u-J>~\._[[A5``Gwvtt$[,z}өT*væQbLR#88:`03M}6 BF177 V]cLfX VKpP* +=AiIGFp%f^;^GO&AgZIALtX"BGĶEӧObx||<99L&%(DbtM "*[jvNl]@( * #9>ܸkkkep兙\UFA555E>|p߿0(`O>ZT*5??EZM&|#V iA٢S Q/adwXe---hN'yyyG1~rRt\ızLكd2 \H> 4ܔ)`(T*v6M:<ȃ" <葷Run-Jag"e0%%Z*PdV/F<O"hZ +~;taTre2 PLcXa+D hoY5t:=99 X\*t`e6 [>mpdǺvI0DnߖJ%J InmmǐT*ݝ/ HR|&cccn>G"dgpxx!Ą c_ leT.s}XC׸Vⰵ훛H$ceeիWtpdNBqxwwl>[Z0aq`tD:fSGGG~k3@Qٌ7hDrLsssb_ vAxo|}'|XT:wjIKqDbۉSp8H\ o޼DBF".Fq{{;2x<Hݑ}/~ fP( ( -ju||Սb!P(tHE>pT*>S p8dT* 'p8!lXMNNV&$A<ǏgggKR[XXP=N|<O$BxMGL_{rrP`!k2xn~ w~N1.lyBrz(|ߥ_IR"L(= ǨA0[.v֡T*E>;;VU*5 ?g ѣGc m#4qH${Icp#ؘZft\.xk(^g5MR A155l607xQ1Ć]<_(ܗ'''i!iu"Y$,,,\^^2kkkc4{<9 "NSЊS "Ů6aT*4?`Ĵ @0A0+TJP 2S_ jΦiպŸkFCfgg'V]ѼyObcb&- F =HP FDxtT*jx2>>RPv5L 媘s\lVV1w\r6AsJ)A[ 4Ĭru]j5EѾ~B4=88 3B+XȽ^<,BnnnFFA, 0D}hnЮkbb;]-Fthà.Ng2d2 Wa|| ~HUdpzziD#<гCƱc݅# _qR9>>άIK;HYhY \=\.'EE'Hfff@X !d2YZ%SP(Ht:ܙdJrllŋt.;;;t:g2cJm*B :$~Ǒp z1B0d"X,L5.R, \{tNŽEkRߗJ>|n3Z-Z2 MNN|%t V|^,//S1%IF?\M&z7HbƷZ-"ad2#?Nj5Jryt8/rH7 H$bf!#0H qcccw4 H`0xyyI\b8~D[@405vϞ=.,,I2ךL&s-d&&&nb!_<\TpVDŽ 'ۚ4 -gPo̗e\13̛7oV( ݘ LLL`W?p84ssV[[[j~rj@Su:D"$r |MH$qz=~loooGjpX REQܡ`:>0JSSSpZGE]<\__frɓ'/_:NdLJ<@LO0V)Pj)^B¾\Mj r.o@R{r8$I6r+.JX #d2yssEuPplnnbxqq a#KׇaG,l"N@]ZZZ?#d2șT j5!cZvjj쌂j].w:hhHAT(|zyxxh@"Blmm5 !DRyJVcT*|ؙ@|>Bqxxxyy)@iXNOO5xga8B1 rSZ.{^@KR/lW* V -x^T*.0O9HBR IDATIƅ7ǣh*^E_zH.# ? !>fP(dRd!^r-0pLBc,wRI2NV\ CJΝ: [CQ(4~l6r9#LFHVEEh2^vyyz |БAv;T*ƕP.s! ݤ`Z J߇YGF'ϬjBFF. AwBaEANQ,onnv;ThWVVT*10|@?? ?R( nÇ^׈Y.//Il0"B8NlBD1˿MLJd0Bh4Shqzx !v(B`_CLa2Z"KJ&aQ)H,H$|I<GrFR L~~9,P(Z*?~BȘ +Jh8ZZxgp8@ѳ&,PiަFBlBg;NR܎`"RpHQ*?v:o߾X__GNpzz:Cv\WWW,ƒ̠-:333>>~xx(JM&S0X,6O?x<(Ed2sNmĄL&Ó@VC/FAƉ%gRe 93j4nhhHF^/׀V5HRF )_p8{bL`p0x^ǭV+8DR P<g!$Cx}]*hl-|8Up6$b!ɺh/btq) ?#x}`w>>>{Εvs~~>11t:oD"B~zD!n:uBb1J8cbHJpXA{j0YK Bq* B^c6777==H$ΰ.q8H9n  >SlEX,|( \vfp8بCB<`Dk4|@f %9dgz7!w8XV*'yɯ~l6;99I/s8`p~~>HfDZBc-177ɛ۹tH*N'I"^I"A f ?8@& ՚帆 %I2Ò*32: .bKTp8H3![LJy,cz=??`Ơ"mmmqyL&s~~N,ypd2Ok6ba0؊l6h.1d7(`8@68ލBonnqL*ϊ"MFBI&bq{{q7vvvP^^^b1ϟ?CīdqqfFZ67FyÃΖV؋Ӊ5t[N9[V2^cgg?LDZxnJRZR<>>d2 ;pAĘٷVr8A^CgEkL*B~=V#1ˆyfffpQT;;;jU*+Gi),0p ш6F͛76|8F"X=d`4 r 0B?܎X]^^ FBV˿m+e`bϟ+gj@s8eBny Yx}NF6 1r3*>777??h[B.}!范 \Y&)͗u{<'ruu- G!|lB Ϫj  C>jrFTxXmz%F 0N@Rf()p_fdiiijjjrrudA_}J%+R=) BXW..."Y b9;;lx.ҋ/F 5 R1:X,N\.CzÞe~~Ql`w8sr+Cq/5 *.x Oz tL 333BLʰR{)@n Dpb2։ IVw? 0T& XpOa$` ]zp_{$lX |av}NBc.8t/RI&ɏ3:gt*67|T*fܥ$Lf5:rtrzs̀Wj5gz8& ?lxz=1XeGpcZm(b/ml(iNӑB@J<>i" ߧyds\4Ab^1.,,`]p8h ,N˗/?c_vq'''Hzkk'q! 8dP C.㭲+X,` O9^lDn[,DR.N' >TڬpۋF(aҖp8\Va !$&,xrrBj7 w}&/xP , j42@>Lz=0-NΈ\BmP0 dH$ E<t {p‰VxAР#In6$ F"P(TVKg d633M `0<{ /Kb?WVVȖǏÂ6db\sz=]  q+l6:,^ Zg"@rrr c03Jb(@\[|(T*  `P(^/46 NMM-.. `8ٳg0y\Z;@ҩCLQ*!SՐ=HpSpzT*,Qá<1]\\p¿innnssro޼a)d]VDS*`q~"9qVÇ5͵mB`0|f3q#a9gE.]F 5Cz||}´1Lq֝N'\B!NqID"aq!d0,bPBP266~▊D",mss&;n\XH!"m4e~4x88@oF1kZs,r\Zuv,B^&p0_<h:,  ZR-?R -r4[ >l2H 4kIbE!.L&;;;Ec /_zsuuu}}ߐfA:J@L y܌K$@H!4-eIAwGX40G) pAK9`kȔK w0qA~"EFwYTFj& iA&y"/H$'^Gi#p) vw}}l6CF):d2Eͧщ&K#JV<_4HI8~ C*駟d2qfH_'|n4\ɞwKRtD dPh4h9`(ǞC|iB8??3 P1bŨ^*bML&G833jv(vnm0yD2==tii`)ɘ z`Ov:XBh4ʲ7 d]^^z)X3RB߼ydxz06h4j61BF=3pH~TC,cyư vssS-ND"?~v nwפC`1~ `ŊNAѣG^lZ-`Q e󿺺tKs9d2 c' 38M!tlpb1)G"kd V*Q3|fT*\.@mR $ Ž9???==Md6  n<H 7Pol6OOOs[}01u`BzVMvȒDEvd^WM ; n iK2 3j!hCBH }aرmINtb^̜9Liű/ؘ}G$ I h_wjԙᢧi|~FFFbebZ! 9<==łkTݻ$MMM\@ 011a0"V=OZD wvv(.  rWTnȫXW ^r&1PGGG蝱5MlbA@(Y׵Z-xf? (d!Gч%>??aw"XU\skظ\.;w0Dh4`v^]]T*B*vCEJNV9اCV+Nߏ  ((r<A lb/lAj ߛ|f1tv |R9??gsJ$f0-v{{{AX,H_Ěatt5Cm:Ej|v`'^/LN=BL r\rjM ".3bhZNgoo/?&ZVl>}q(vܳ6 pssh_Kc@D (hE"Q"`q² `քh0wBRKRT Y>08|d\XH&Ir>@S?d#A:J>3ĝ;wps@?< lCr y|XAq[#(ˣ(E:U/ZJ:ԿWWWdf4L;Y4x<_Trt<_YVFjS?P?@RRC7hk6tKm=2ypf{bbEH$}ݣGEf$566vqqAFS1eHXO,3TJT"cN1v&5hL%/"MPy.§6-ܮVz^,S eje׹$2L> ō4,0 ;,4{`/M(f`l^]]b㛬T*xU*U&!%cdd@%///bƇO9N‰b״ݴAgggtZx<mfC5C oh|Az(P?m*t<0Rȶ}z/Á6{̨ۈP(R`s DtvttÊ:4==Zgggccc }~ttt~~vKRVT*jZZ@E@vGR>=fܹS(fggwwwinrȂoE1N`WVE#o4 Pa~~nmZ5 %b+Z- Z=11KJc ׭~`mE)B3''',Z)8`i`MVJXǮ.@.cȢ+ IDAT i nDpj^GU 5jbAɂ}}>\A6OK.\ӟjgn8fP^_h4XhL>06N+1Aj Q7'rLK->|c$T^TJzp6>&355sxx(Jl6 hj6ul`0!`b2\.m/a 488fQP?PPY'1L&nJ$^K_ T fVx=xR),L~yyZ- ؔ04@Kb澾>'KRp8 ?f 4Z՞PbpS`I db84hY RjRF@ ezhRh4/^2EMbM쀜Ώ!2fuEc6䌏*eXQƒ/2d2~c"*b1LQ71js\n7#H5^gA`灲z"N@@c||˸4qFCyN2LTtţt: F*@TЅBaeeEp@x^'Cmlx&rypfW{?5} FX QJ&@gITҸ=XXX@3ݻu@ BD_d{{ E&\[[#w{ss3#JWWWD"fY#AbخjA6DF0zvH`<9#ADda2ć J_N~ MhC8<Lx^loըnūD1lv8lrnǏ6<< pp (lZ tl6˿(OXyST@"<z3aRQRiB5FUP0 Ѡ҂AX,N'>Rf] $-Dfgg666*_\\xޛnx F|uׯ!K`x#* hh^c̾tpH!ۅwAWW~B̦jjSGFPtvvv>(wl'P$'&,m i'DLB<2H_~Mk**2:::¶xDX,& ܦR)bްz=@D"#5dV@o- @yf3xr8p\e1j?# OhJh h"[%r+dD^ySTUlř) :/)LAق98Jś|V E΀#m^1Dt@q#R`2-R5OZ}ΝZƂlbbb T1JN}xm}sgg'y\a$|&NN)&r|  G|>~`Z}>߃:nR;ghh [ncr:N:2F* jL&ަE'H&''yf#L*j5"l$P\qTH\pZ,j4LX%VŊ^;l2 ?Zww,\<_F8^/K*6==-J9t:]Pbg6AfJǏ'I\HtN Jvs"%MF Cww- B`t:~bAdc4hdIp8dС3eeXy :P]v(Btww jd(+ V n7qB~?NCj]DǁeE tEnXb[Q,-Nó2O&$iF%2eC)[*dך])dj{ 484Zdd2R`0F315MXA >% U@5+\TLJۍFꊙ$*8||^Ps"/600@, YQoo\._]]Nӿ}RFٌAu`)V+FCT]VoO&h (WQSmnn&I}|| y%mѸb]" ht:M/`L 4% 6X"X 1A!FZMlPD"0HdggRL$aв.&BUE"Q,+c\\\FG!ϟ?gLc|Cl ېeUH!πhbRjYVL V *+A24Ǐ"WJ _(¥H$Bd!\:#F!Juwwbo&UhLf:>88@[ӫ+ ")g2, agq⛤GL&,i:J C/O8? bYD/Z-"^၁ft: ]T9...,bј3;; ]nL:::9Of]GFCX-%G M6M*p߾ *y烃t^7H4^|%'G?L~H2j5ÄV{F133@ G4>oww7H$HYNNN`3pݱXluuURᙙRIy^TQCJv| N`LMD[MdA{zsxx bvwOO$ŋz95 >|xppT*'&&fffnݺuuu"Et|2{Vd0+XxyΝx<V. dU(qV5Hd2JAL&!#\.6 Y8|>_\ƧCvu:ݫWͦS///{bl>dL400066J'Ç=z߽{766qX,/k>L?/..HtppP.~{a0fЯl6Q2a^P{zzRv¼ :T4&:9<F"& (8A14CCCDj!ΰCB|2 8FNNNR]}`KlۃBGGzu6 8d@  ND"y`722V}3j5Vu||LRCcr& C pb3R gDӃ1 FFOOO1=y$*KTQZr\(rݗXx0LT*W^tM>IATe 8rz-AN:eq, Od'0c4j(m etu\ZVtD"AJeۙynmm]^^ ~]:㇇l^OLL'N Zc///{{{aLfcccqqvP ",E1!:6CO>l6go޼AԿ~4k\XC#2V+q __V``~eww9'ӹŦ`jh4k\0mXH  zN?񜜜lmm6ߥ%]X!Ld2ŠB!sT*2O~?cV% mrara\.7~o||\T~w0UR)280H+h4 \@ hX7o>BDlРA =yz Q*nnn"ard;:: hڕH$b'|ZU,CꚝA;>>ل!,CpLF"PţPFBKj`{Ploob ({{{g#FOIGG>'>R]@E^tkFQ0nB>'FMn/&6N˗kkk!~۷o2$4. EZ$TT*aZr!xGkT((rp8؀p : Dd 㰃hoGo_nt;t8 H$`B!?O?۷ot:%'''333l."?>> BF566688x||<33EJ%$v.E9i\.n@Կf,? TY"HP݆.T*EȈBZz\lLt‰a>;;[*9E"X,622B9$>o~~\.jү2w@D977WT0ŠRG;mx21$ LVhشZ@<z@^/lx^:+l6^; 9: N;V~Ii_$8'TmZ ޽{"\__Tbd2u+ IDATT*Psqy<cCCC@Fj588L&2-`URWPks#i@ԋŢNC@4P"h~~^RAZ+++m: qmm y,CNOO)&8W#H^nH>k*~NX,["¬xx%,4rb|} {r20ԟ"N\L7Kҭ-f1b1vHtvvOOOyY. KBCP888D"Ij!u bRoe~n8 :PjTBx 4..:hBd2!^ةl{M 6 5|"...(Y2k6)?_CP(zG,3XF$VU&$?|z/`uۋ/ٌ>#DzF[$yiZ~P(FFF~IÈ}dl&l/---ݾ}FH$o޼uiZJYhP8888;;{^ 8NR./-G92)ذX{PUC ~HvfT}X<11vfQ is___06 b0n2rfz=Lﳓ=5*mX,^\\dD;y"Xg(0TUPM^wii JR >g4X,6k@ P(I&d.o)vpZ!Y5x?~*X,600011WVV$ɽ{޼ys=A|.kqq=8;OP3ɊaZ,??f#cdooO֌N3U2rXN A. SƘu,0-r%웘T*E!rrM 1u foZ{{{x͛74UL.//7()Hp-Z(ox ^fj4>}}}ͶZyj:L&χtoo/H hQyp̓r:??''WWW{*'w Aqk#\.__/ݻwwܙY]]H$_|E Z!#irr2JQV599I2jX,z>k4Vܽ>uTgg'3E" HY10F:Jr9|Đqfi B𗧧~)"e ٣V*v1fqp3D"]h6Pr_3 xphoa>VYA0%1QE҃N"LLLP1B+;;;777b\.T*c(]]]N3n~JVb6cX<N\1{B\V}m6AaGFL&0 FIRX߲ep8Hƥ"۷WWWM&6şU*v}kk0z6 +H͖d. &ĎvZaǭHRǏB!Axa+Ff8 h 0/?ݾ}xx(HFjX,L`[ngi<<<̭ dbM&I ,hݻw?qz/24\=.T*UT< P둃J̶4I&ij{{/_>PBX]]h`^TSS.h0"ACcgD"'ptEZR@7EMp  cd]bEAѦ\^^2)@'b:^bF5W,[?<<388@Jh<99܄x{yy S6MRo߾pl,2GGG3 /GPԪ Dm5cZ@ )@6t:F:. %[>jF!ӹ͊jRF{NrёD"aP(>}=`) @wX`1ϸ'sYWWWPM6x8\@@єfp䄩cѸrl#t$8Y Nպd2R)Nc?{)=:EppT*1lZxGلkZ,jvJp,BGC_5_~IurrL͛76x K hxNNN$"]t l|?ip'L&I#T(>6 :BhB!2"^~ 'wQª:hu xړDN:::4E( &Z8LGGG9믯'''m6Qff7l6xiGFFLIMXvֶSSS6MѠ`ȲT2n4i`d$?dBhpjMyq},J\P(/OdJцϐ(dlVɤJbEd OӤAVJ=zd2^o___Zs$;wX,A-^䭟H$rDjZ!n@(AjA1/9QIP(DR6:Nfɑc- )JZ@@RGGG|P'?cPHi+Q(  (VWWb8*FO>V:޽{>|8666>>Nh7κ\1 fr=|c <<99Zc6ԁa6%CZ%v)'Z{1c:RB'֤i@`FpوovOOO3oC O幹W^=~\=,ŋP*$0فhX(r9ikO9 =ujLIH,H$I$fx9pI+?E Ws1C_, 1oVHa W*Ӊ~֭[^zE'of2==MQ~ssW_}E=n|>ladYbz%|1*\.ow iD/utt` DhR6Cg&H!rhbaRΝ;@^/^/f۷pA0σi1T lt/^h4vCκbl6'Rx Coo/x[RRQJl14:==c4Q  >_95^z~xxopp/Rd޽ H'-˜K*bl@<3q T*^T2$:PvX,t:d(`@vmj \ѣGl#$E>99d2CCCϞ=D8c`*NNN\.r*jMRN[ ٳgWWW@N0 P0zUL ɽC6ӆk4$H40===+++}8)Z Zc|su2쁅VE$!]әy6Q*h4ﯬZo޼F<7=b/^j5,`(09\.d2l6|3V{=bdـ*-JL&oݺ1G#@Z-)֘JtCbI"`B!;&\| & cfEZ$I*A,$y^aA6Eg&! 6g^k6. >~XծX6{xxh4Sf? eJ 5[a'dY IS!GQZM20.⹹9(FqjCJXyϟ?ّJTɫVe2\Wr9OOOcbB~rr&? c3O?==](<2Z" 1 nl6>`7>>jNLLi9r߼}۷o G^jDXtttb\] Mh*<"(ݰ4# h*J(:??^WUj%[d2ɤh:ؿ!y^bmB7 j2A%7;;b{c ϡ l/읙{DQ(>񓓓$vI˗/m6L&fS*2oElnБCP}=Qz/2. -yCͥR) adttt`_OR4NgOx?<dT=@.8ccc> p}}-P*Hw}Gfm67|ssscfN)JT*rwcٻL&ߧIDt4Xy"gWW/\gkkkcccjjJRaZ^chѺQ/,,lnn]y?sPb>|h6aa2H$BgϞMb- z}ppjY0bO.hTi6YAHA1P(b|> p1|wdh`kh2䨂+bj5Jd2ɣcUiT*I~\YԄ333(% ZNS(6 &[h=ҮQ|T*U/--Y@ 4UH:p8Rwvv677)ZX,F Lx _@ w|"H$/YP IDATDmLm1*J9𓫫hRJGD RPcBM 6 [5^B_}T*NQP ~Y.[XXT*^7\.3ح@ɓ'K޽KRr(~"Z%H]A.!N gY~jj~t$16eXм2 "ghhdb@8i ZtnPdu:><<_]]R& aM p|GGG$ߏFאi= S0ʂ j4 @+g/^pq#I$[[[iO!%>N6TFR h OOOwvvظDCB?G:AT*ٙ^J?t:  J0-f{kk+ˍmmm)FR㷂`6e5 `ݾ˚[Y___"b26WWW{{{'''J-TEn28pc`00z ###bq||%JPLOՂe=8#X$;>>'AA"}z/wz%A(A2+9TL&GGG!dݾ}ʚ>tD6ꫯ|>T*c$qrr\.?xFq|RЄ[v|~b'}.쫫+~Pe˟)Ϸ a g)9ʼnS,#CjOOOA0͂ #2jͷ͸Z ypzGFF'd2[wwwgff~_W"@Ik6 r<==MN##l+)T`-..rxޡd2ǏoooM$>peJJ200uW^#mrzXx|%Vu\ :)LƟwv[ǏJ%_fYc椯1Ҷ\$IFmpI\6w!e`o9 #\}y~^?ѥΒE ya[}6-޾}9 i|Ff9Yyuu%~? Hܰyq03Axcc5FbC+$Q͕5 `< GC2`RGFF0{9::@[ Z!J!-EOYNLLcFA^~vh[P(=H$j>`0=??Ă9qW~SZݻey<۷o+JF}}}SSSZfݺuTnKHd;F\?$%KQShflmR$M(>~qqAT[^R Ӂ"B\12cccA`K4wBwP(ӗJssstHt: ZCP4dIB~_|>|h`v`CYBb\͚L&FT`t:`BG%Udq~:·b!Ňc# X2▍+ c̬n7AGUH&A ÐL&p2?ZZ4C*ׯ[,ʦQ'9VB#h4X7j4ԠϕJe6˼ w ^* 'E {{{-,,pwrrY>E ȋp(k˘[XY ް`0Dn[o%i +6-)z=%ԼaŊFJWR#:ڇ-T*6s"ErF.ùN%+T^gSf >|ȿ>eooo,c|D8 T*Ϟ=co6+8FXn...b5 pxxNѣዋ q޽L&h4~777  xh4^C:CPzL&(8ORrzzzrrt:A8==E3Zvtt"ɑP(7hw p:Ǭ_D8JEYR0QhDꝝ˵d$|_|!UrݻL4DJ駟޹s֭[gggOoiiviiX.//\.ŴqGCǏOBbii):TV߿hdrrrkkkff&[X>Cg X,Je.G>wAϟ?W(.kyyyllL=BV]XXr4fمv*)SydmmA3r>Sx3[z'Pb1rj]5p]/Z,e>ouuϸ) )2!oz>|_+vmmM$yz2w&)d2IqƉ pd"XBd2.O AW-4l e fa&`aFV",xvPHD,mR3ׁ d 5hZa7^J%Y4llKnKDNNN"=MMM=x@P|'JB]irr L ^t:]\_nnTV1wޫ\O{{  V{A V2H$npW\ρ2!N^X,gGo1@+ubq{{^SMdzz%׀z= 7ccc܉jzГ1) xiU*Uӡ+Vq&H2\:D9xooT*UT*ōs4znݻ'ɆVWW`61>>2NMMY,ӹ(G_vMV_\\КġL0-//t:*㘼sN>==}i_*%Gp8 疖T 0FbVtV F}pp@ɉf|W۩TX,poodW6Lhtee,}b1J1/^JBXtaa= v,CO$MhY fRՠLtp8(fpA0 43Ao0ȾNLLlllrtp ˓`0\^^BD2”i+h4gff\v <ȈµCBV॥X,fI$%Vne`ڀSc6} Ç\/..h[>??S;;;W÷z+Lb988`A )JߥęXl!"l.--AʔH$ϟ?G0=&#LL ZV*ֵk׮\b`G1Fgjj N&bss^{^އp8 hfU*͕W&HM6T*Ō.ian(NCO!@*^VNNN6 O8O@QP(,..^ejms8D"HD3Cρs,--N$oT*}wgggFp8̮za7NOOBAZu:Vѝ;;;KhcH\OOO8T777aJ (f EJ=::󃃃Àd 'Fg\RVWWzwK.LFypp͆vy[bJ& ==QٙNfgj0~AbgbU(TB7?vfs:vishfgg 3kہ@6a02~v;Bbqۥ=jr42,J].W0"H#Jιoll ZJ!/T*pc;JBS@r9#C4::Zߐx:99d2ѹJ"%ΨF<*0h p8>V~7 p< j* Vq[pU̐GGGѩ rg(Uغ_~K'f̝Ngbbs3>](.T*Ӥ@d§<|F(&VŵE <2( 4 19%J{GD7 N'qq鉽zR\\.T*c*l6C"b6weE"]AbXh4BHKl'M82^p8EjJ3R OZVV2Lp1GtB!#wG2P 088hta4ZPǼ~Z oTF>:X'5 U /X٬f#Asvvsd21(WBH%⣣#Xxee>NFpV+ͮY,qzzSLoT ^Jcgx%|O9+F&v;>5pPλ\2fZvhhIBL&K&Lnx<88о)gJ8% m68DV *766d</Xif:JRh4޽{wmm׷~˅{yy4**J%H$; l6 .q IDAToYˍP$Fj40(&!jad@8ze_^ `0u[T*555A{qqS￯/Jv;JDGĠwrTX.i=z?r^^^. jNOO+Jf&KRε ;+9`[Ţ0}3nuuuppprr2FbWVVι\.bkkk~GumQ-* akzÇ^w~~~cc\.urrurg=L #6w2F&|899l6CC#Hdmmd2A jw}AH$H$01Zxbn?O0p-xwJۿj3LC&%I ˕JC9< A|Rz-No& A"'&$`dd?nw\|j5U^jx5ƒ:H xw}߼yY,P(rtt?>C.D1\o p!LKut\h4*o;ɦU.霃0jX A*bfS䔊 9pn6/4LMMe2"LRנT*F#L7xC$iY6$JrzzfMLL4MF2쭷bk6lѩ ;<<`08۫Vo޼ILtA6xpzVt:'&&@ut*(=^zzzC=gdkeeepp>4>o _*kXAz7j5@ cjj Jsn_[[T*Pl~:`ĂvܒB*'Gj~?g\L6?0Cف[o$JE"/_@Q۴-]]]C!wF\ɓ'D@yG-[5pC\@۹(FvDNXXdGel(`8dÆI.pjNbv.K$a @ B [o"BK\:NNN={&IZpGOR8(nϟ?! Nlry$GP*bJ#:CQˬ p::.Lm,M:v8؄ ^5q˼ W*@K/_Զu) ˿K4%|H$/KA:N<;V,׿333|j B=֋vj>~xff;d/IacէO__h:OM<^#e- h7xUP"$h2f7!NLL0̃QZrywwZbC^ٹyT*ۣ믿^(ovvP(,ACo=??駟r&A+J~mggg0T*Di^LXJ<ёVEAxssCҡ&޽{qR\[[c 4 ͽYpxL$RtzzRP(DrDbɇhQTX4h0hJU5o :wjszdttp0?PEժL&Í9~Ynݺ0>>N"^߼y?}8??dhD |6!tǓH$J%=:33Kn߾}h4bBP&π9:0`eB6L&jWH`0͑1>Q[MR 'A ~b\ZZB>VjnݺŴr 0GGGG ӲX0>VRVmբ$s4ɣP(bP<<v%X`@o4bR`mZ U0gv m|tQ2ll?v8t+c;K6$RVvJbv6`5tfO9af1RI'i4fMz4|>ϿD* r0$[vww{{{WWWWVV8onll T*|t5mFACsbк8'O0 XT*ZFgD"vJm& .i)zmDRD3 G>elWf7'X,fWT*ŨX,|>78N# 0Ch4ʠR03h.!R?Lnll%UD1L|c6яΰ~aa^c>~6{gRb JiV][[f_5ep8`b1K׃J<'́dnH*ǀ' Y (6H(TKm4&h4&)Jt:͆߱jn±G^pG:lz~nnNRQM'w#;G7ӟs@:N 6t:(7N?O7;7%fh3,)+B9DΏo2GQu9D莀rrrrL_m2ξj0\~{{{&T*?ONNz{{G("'BVFH؜IfE$ ՠQ82rY,"lP@O3}Ǒ.jZ*L&$P(400@Ná'H$DQ+f3fRD7Zpd?s<▉'}vv"&}gwm?d24??]Z'$ *h<88 't:6IjɲǔdA bvhLVVRT^Vϴ앮y;襣#,vlR>3aiiI*?UG}t~~J<OP`;ӧТ)hGZg?A6addƍbL&aN322Xu$qj EUlR n,P(z{{F#\8m( mV4ty\\\Z-Jfgβ}]vl~Xn߾ ֭[U}M]Rh4qHлn!_\.##.!b+(Qb(2FGL`z # 0!nWbqeeE,ɝ~VT ,Ձ*666ر3rV*jdd> ]хޡr ]Ǐ,2" w]B1==Bƿwh_dzsRh4 ~cvJ4'˅ߑ.b%AڂB,JCO&>`\\\L5 ?O?3|`ǧ~ Sd2ݸqcqqqqq1 b^[[JBWVVvX,Vn_:TլL\\rDp1J_o @hGA"T,dbbB,Wk!ˌNƨQnW*jB啕}>ߓ'OɤR,pJW(dJ"qRI:|ff_^^,:A@02h/<"j`0PKj\+ cK:Nnƫ;AOOOXDGrM.S#|ZF7or9D?!~g$\Tt:dVʊdllnooJ'qVVVt\.'sss}}} m2 4<^N{2JAd###0X3C;??xّ凇\ >|Hw֖D"dppT*1/%į h&춀+\N^ϝ4i ^d2ͶT*~uuZ *6Op"@0o+Cݣ1jb1Q4%u],kjVt:B;`4:'!|>OP(`?ˌ:qyyۋ,F;<Ƿ}ttUV)&҅M~l6N~Q$X022֭[Dnk:N__d:<zڵk (OڱH$R+"┱S~1ζ]VV~ n#8܎b1[JЊQ &nH?d^fA D"r|>Nx<E755EϷ% l6] X lg(B~‚Xooo77oi v@u:8ܓ1h%Gι|T*d2뜂2>G0|ϳ,,? O=NLR(v;k 9k`` r9JqFQV*fyfffָb϶$BVáN 0njF#)ŴOLLy؍. BՒ>tTz=6KA|>| a/@AxpLO*zWPut:M&gݶX,>R|7n@%m|D"!N!d2FF_bWn0XY)P՚Lx?~xtt4loo#iDrppm ? ?~|xxH~?fs:fjbB@}ϕѸlTh4 kddrAAY9Rӈ%5xK~"vIrg~9޽{E"L&}4A~b=zex.//4kR!w+q,xqF qfY[Ӱ-ygCW* T V9*wF8!?.Мn`0dZVr9o6o߾NyD"g}F;F(n $יW-,,lmmMLLtq D"n7P o] IDATJHN'j^XX@4Û㷹 ŌcF";E l6^;[=h<8~VU.b===ȯ`jZ?Mf}}}+++|qgٳs&}}}|2nRկ~_.a /z=Ǐ;VE/`U2lgg-,  I\E ;88H13Ct^wrؼ_'''d&ra irr?lϡ sZ SSS }_|H$0_z?Inoo.-- P, zY,/..%AʐWj m8?DʼnX,{!Xs7qa7PT+++ h4NOO[־>OSSS?6Lo恿vNmNN94qߏ_EףnnnxTU` mllPat &JHc1T*{{{YRe[ONN1+K %6QNv뻻kkk+Drj2t *&xh4DuP(^^^󜝝1/5 $Ԕ }}}ϟ?'LA:jwjUՏ?n4>/4MX"wU8+++s+th4Kh4zpp 1 dyyX,R)RDT=vu@].SYr@[[[l(@. 2ONNz=uXq%B:$l6HsYpWFCh4ƐN@!0RY3"flFCVkzȠa'eN?sЏ="Nqpp3,xJjZh4@?880mmmeYb1LR{ttU} یH$"Y,y)ac(dvh4|vc_aؽk{^h4 "؇|Z u ;JB atzk]:3 m/BKR"T2ۚ 3Bڦ_)F:Fo^GLONNFY6JsT*GGGܸMALd fஈBfS*...DO.@Q&@ $3=t#TBfh4ǡf+H6M\7 0 >'NQJbsz^XiN}l3ĉwvvnA ç2 nnVOG1<҄`<|(Z&?os2avB8$|R%&.`,xm "p>ijDd"222rT*RЦ)O$,^ᕕJ_fcbj"'-X X,R4Okޞht: r\'''_5@: v"LTmNgggy;1~bq`gM.gcoѠe7J/F vR E\D"f,EKRi0֍dZRYy&Gd2؍I&Bas|D"iZ% ^&9`)s" ^/Ns- gzzבMn ]z.J؊lZ-uvA(`7 Q7޸w^Z]Tnllq~~肍ALcƛ؁QSRb^RH9xooO^O%P(tUHԓ^fbeN%Ŀ傢jƐ/<Oo `Ȏ"J۷@4v2Z`0llx mN B"Ch4.:`·$gA5R6M rpOr"%*vNHb`0V/f"` H+"㙘 BxX,ga1vݹ`0(i Z1a #V+\.ZbJFf@*JRHz _d+10ePH׃ h,>ﭷުjf͛sss0@V+>^ywhhH&|>@zzNp8 {O,aBuXxT*AAMb.rj^˔k<^4n9$6`'ZC/lZF]dTW&1$X,ggg$;jT̄BjbqzʲYV333,߸q}||tnFϓ4)Yh|n&yLbȽiF1DаR, z9} !擓Cl6eNNH+jD"m"b`jdabc"(J(C|`t:,I`^+b#VEYG(iAR? \~XL*9}Ip}>ni|2f8')x<~vv={SfµX)e`|xx(if`0 &Qd٪'&&YW,l2|;===v^?00o۵ZЏA7wE"_}nS:d{FbKuƧ OOO!ZrT*u5KDbt:?...ӷII x<2韄=Or|| {Dbj8iBƷ 0U RBcĽ#'>fY h y`k`yd2LOҤ7 OjAA2KiT#hDh4@ezw"`Jc6xF-s$Z,ONNF3a#JU!5AT X"sO Ud4+q)r|oo/LR Vpee%pr{{{F#"FD偑dggg|\. (XnH'iPqgggtA<#{~Zhw/FPbq4MR1/t:z NS*ԸBJ5jq=>>. DaPR2b ЍZDbN2`D"LKLnA~W$$ pl-g t:}U6R1 e2WZ,ƍH~Y`iZ-0pZXX@_EY8nnnbK$R)#p+9lCs1)>GGGj:6{{{蛌b1q\I `q^ @i w^TR/p^ftTT–5V2v{}>6gF~&,"IeˋF?֣GZJBhUB2N[W?. Ls`:nss/'ߵbאϗŋ/6 Vh4MҀb2l6M^x~~>>>/}QZ(Sr9t:婩)n XA*V*n?Vkkk+{<N 9h9(3$&Z}3h @."# 1-ۆ !9ǘL&A: {9'l6)Kcz{{Ɉ.pvvD!Hp\ؗШ= ab9<<41GU*Y$a@d2f~`Wcl6KR! h51̼͛7...L&4VI5<" yl6<`0ȱ% aq#ra铨ZY"PIs aI  z'Ў>_]<1ԃ%ɡ7bz 8'${ РQ$_MIaiTo2W_Q ~qqʌ r:f5d+dL&(f1 nzzzH~v:k׮:M7f###f9n t݄GpGf`sXBG/-#Fo|=Tٱ:,)9 ,..reT* jzD<[:`tmH<p֐Fd('% <t]Fl"#D"FlZ&(D<'@`F#+/Cl&pm6[(d. KVn?IzdUS+++,[5<65BVk4ESebQT#T*z%I^<OOOfw8Ѹ0PMčv0xM4bՌH$bi4$7tPjzwww`0 tpzr& 21T>\0OQ˨רv$vanFar=O !WA8zd'm\ O (H gq l`΁2x$-(<11H$(y FQh_g``zgW8VD"d2oʊiAg4|9D"AƥC\.i)xo8fLahC~GNV#ٜo~ߏ|Bl$FFF/anIdQRUUDrT*1EYH^f SDkH*b/A?zRd9o/3"Ÿ{&! L777R(];;;䟉nq&tyu*J0`b8::" `\.w\PߵZ,p 0mnn2|f( jN633 wb|`L&Kl"(NsX5;&$_*^{(" 9!c \_`s' \v ZVPT*vwwf.B\._YYageoV1l_h4(H$pJ's+]X p 0"TR Z͑(Jj6v='IN~?7|J}o}}t2*Aս8kc[t:l60" 4fjy)vGQg@xz= ADAbc׻P(|>Rgz'=:bdtE"*7}}}/^|Wa1<}YL2 d+ H3wL rHyŕ^mXV\OIy/u^YXIAD9ݕJ>st4ƪh4ܽ{5"Cu}lDA888̌-htjZ9,@|݂ ГG7\\\\^^Ca<@7P?{*ͯprrB }V#_ Dƻ'5Mh؅Baii)HJR[[[ 3Z-gOdP \ AKu` sRd>ĩ 3gsWf:>%R|f9{%J=H>x<~},?|cv\5E"1H &z :Qh)mD|>_(5MZ5 ^2^܏NԔlF\"5*Ju(p0Cl,vFVceg0ڊXa*"JS b#c0d2DsDrD7)W=3 f$ !̾>X Ix r:VjrJ=== à %I6bDu.//~?$. `OONbHF) L.l4gT62 pe9??й9& \~A44Nn{bb%vSǩ!zRvY I/r\RvDp;00`٦bbG*,_ N9{rab}m UPY"l6\K~6n#|݆2VA._`!J\.W L'N/汞ѩ)LJ0ޣ .Č|i3L>O,`dY׋yА>99)Z'4j'w \^ks`ETK)sly].KG`0800 c2|=ryRrCk#p:M= l6s@ p,ea%a$pL}z+h4LJ gŀk'niKVᎹ16j̏9$Fa6i-v0{^rX1vT*j-LcZBV@J˗/S@-j5844ęU”D"^/xөhX, SA% &IBR :a`_YfE~_$r9 D~U(8=ONN0# I{~GN9}t\A ["J]^^2oDv hzbP(0/Fy~](@SrCCCl <>>. `!;;;D=* HJ#J9,Vb BI$ۍ/HVCƃ}qq_zUl4$XDv?Wz-<@KRV>ŋL&sxxp8P$0V3WiWTQ@n lllL&r EU IDAT$ZgϞ\>@5M^mN@F(XD5K2m̚L%~rA̚,c{@4@`B IH {?y~P?::O@ X,ܐfhJ2z,Fpvcc#1EByzz6 ^4V''a9,2tSSS\G(@7T ]ZSQ^\\ x-x'Vُb2^~:T*e@F\f! zx{{f)G(;TD"1`Ug!*ݰca%*X,z<ѸHߋ5[[[:.r "\dOad0Cw[+++ y=iAB 볨ܟ>}*PTH|>_:X Tg,)W.;Blrv\.шbCF5 RH f?,RA2&!@A]B1X,vyyda+_^^t:3p8D"TJ#@dp8% 5^ _|E]\\ϐiCr&''5C`u >p8O =0nIgdNb򗗗 BZR Ƙ1#MOO !VWW2޻wo0 ݻG;11AmDHQ8pcZ$/\.W*Mt:9NjOٌ< P 3_KOp4*p8L>U h60jZqB1{ȥM|CV6x<ΓklTR\(4n*J#d2X_ǨW)uL/x7ecN@'ؖ=|QZ`#w.5O;@UEt"`0CH$bvvr.x<>11t:28j5z~xx V}<|ffC8==e'tZe[ ȆFcff):{S߾}8<>ql`Gtf6djCjծ3]_]]qv !piZ9!R$`V{ssؒzh4bA4\.]<( Nh4b1HuOvg2~8:ԣzLT*;::bgx$ɫP(1Eq@w ~dZ!LF)́AsčΣNC"lmm}g!@?'Էziyc~`TB`5\.&krLoZ-Ϳ܁&޽Cd8yqqJ궷yV(`⦭#)Jc#OD' jr6sIf#Gq(R>Tobl6铓jXZ%(f6To\.'H; }@r_]]% ZmR#6I3 ˝RdkX^kZVt{{ E>'tS( &|(>>΍ۧ9˿<|#fǓH$nP(___y y8sr,µL&+ z.Ճ9YTx\199ݍ>8??h\[[;88opD% ~a)X,h=F3[8- sss"At||~[盛uNRG *$pp8݌>ҔapS}㠣jYYYZ!t:bnwZeL//_D-JttWS<3b%V*9~ϕj-W,,,0d BV C} vP. ʊgx^`q3+B!R\Q#KxDk24 T9|v/--!P(4ܼD"!p055 dٝ˳\.'J0U" ?#\5${ApWNᲟBdv5 Vƃ&RLdpg+<]0Ä:B&l6g2if3JV*{d`s{{ ~NRGǴÔKX t$B@ccc >W '/ '-T*NR O#RfC}"M4vj%| VbaETb';AvL&ˡRpJzn2(:H(RikkUh\.ǿ> vww Rs@j=x7G1Kb@%lJ32.YV Wtmqqqq:PV"2[L$2L,dLoׯm6[(Jү܏\.hn j6|:t:R & {I$D4Ӛ1N$UK:.O/0h;RdxgJ%}`0LX %f$\f3 )|>FCлwzޣG޽{W,`0f̺߼yI7 ^T*e2߾} >6rpFbX$ $';LgOOOyLƚPht=PG4RX,H$H$vo `ASe4v{^cΆ- i܊88NjbPcdP4"gS $J0Kr#Rg| 3ёF$R):^Tp YC|bb?Bo_ggg#d1>>N!2D4E:EΚvrvnn.---d2Lth->x:?*Z2)AHW$-R)&$khe$#~߾~$뿒zaXj_a S2; .9nA((__E徴t||>ȁ2H7c^B؄xx6"DIjo%%nV^T*ad2j1#`ȌFCFE}wsO8XJBc T.>1Ñd>|P*&0!Z__HނI8==B)8J-%-'c| a߿d,w:Bc9<|A vt/$w٬^/"~d2V|Snooog2ry{{˜vgg>S\. t !aTj['{ j2LAi'''JVS{8M`0ʉ A% Պ8J+.8P({{{0N#p\bIt[[[n?0L^^^$C2 ]H~vv *HL Am>H1szx<.Jy|é)ZmXX(ͽ{`~I(BW`%)nH$ՠ Hdr8K{kV U4Z DI!Bgb3>Z=F0*i ~lnWT7 Xt:=Y@ dɓ'P7: w9T< O(l6N^~v=C>fʧ,$j~ӹ@¼\._]]z( ;/}tYODR){^Z?0C8g(~uF@*"-@`tZ,RX=zt}?߿N8>\,|>wPil92DlXPF)l .>|u: d><5ҪۏZGF'=zxٳgx0S9~4E>??gQ(tw(e2 4٧OjZ,ϫXP+8α1RBLf` 7 \1,A*Gסn7a0 !FKe ggg dYHo' !M&-`zxL&Ϟ=K555UՖ` !VWWyN 2¹w%Cӱ[p(~]wtFl6Je(K155P(^/PbZX:Bh4 ars~u`~`0ҏEHg9qL/4X]]_ K1s_W*D/KlhgaABp:_5?BƗNCN:q!DY&>)y!NP'.u>PS^xЛ^Db6Lr"siGğjV=x`uu5HNaHh{>;7XPGyA~P"@PSa",v#{J^R!6NJ%rJ~V;88w* zt:}xxb0cDFJ ERч!|0rXRFG;==P1_Їq~~ENc2PD"aU) fwBhdˠLFq{{{rr~f|RITfd2I6LbK$juoobhooCv{{һwﶶxͦJb h4dQK($Hf3 ""Rɇ86ff0V };{8P*92NOO'&&NNN93oÇlΤ>::*˧޽Ut:RP(WUr:~?HR)RO) `0`/ |^BT ; {0t:;==+1S{VZfFh' >re`4Jb\$Z8kgrnvn>J RBVTS3C| c N ǵL)%NJ%Gb -K%BXaAbI$\ZmXdKKVCjX?3e&gggm6[*_[B D.79>>B`We1"n8x<ΕFxAl6,$/^Sݎj p ټ^B5 hnaapP8>==ˇo5BYj,Dl6?X8buuU f4x<L0\.NvO\gCqxłf1 ^Ʊ IDATxΓ#a!L&6U9,C0h4Ԍ|>Kzii)Ͳۓ-C" 儝t4Yp^?}pI$eB V$~JܮEj5NN (\kb CmF=AݎāK.\.jzl6C 7F&nzzl6YT*t~J EMHCP0Wl6499I T!Mw?l~?W:RlhX.4Oj6Zc';IgQQē7{xc Ps'aq;2}\  /#|><{%#JV##éR CKUT(ad2߈'$?OZT*fy}Yz}ww@XD#4:KnB!THt!j5 Er^𐃌Mou:a!BhY ^ UT82/^xaX$77|{{p8| &/^$bȰ;P(j\Jeggk|\&kCu'''zTb*bܐ\VƖKdYonnH>J} s BB4 /Qrf]]]qu]ؓ4IcccY/د]TxxF5>0%w^믿r/X,yConnא3KóMs͛|>ssn 9RbdH$t:C 2j`>:ğBxŧK&b|>H$Zd2٣GRJB 5D"]G80hZ61I&!I1lv.nNFWK0%Z^~P(0b*L;))[n7vz@`@x|{{{d g6-g_(N\__Gfrɛ7ok̚'O(9|,FXJy68C"t:.o1yT.Z2%pkK'''mZJloߞY,ud/..(rO&^x<& |wF2hb(fh:>??XK&*"IiHA>P0` T$`ONNP'[G"(CM_|d0#l6nmm`ZfF3+++\o|4jlz߱ `0Cn5 t:m9^#@C166G h8G=AD/=Ll?Ϣrf933J `t:N.4gϞQ^["nFI "„ BI~,nr|iinh4?6͌ģpџtp83?xr";JQ"4z^:frqK[.B!s{{~ <\0|F-ɜN7|(; ҝxZXX@TFjZknj;¤Fm6[\J۵lu:dl1*A qM Dx9즦<Bvlp8L&n jwF13<;;bJrh4~}q+++xdYHʂn>Ot?x,//r9-̊'''z+J RQf8@r#) hq)}Q0$cX ɰp\.#at H@㷠yEKGjh Qu{{;??Gp46m~~lPHjU*t:m0~ 5U Pqy Q$LԔH$^7ɞFx)qLׯ?*grϓZ( ɆTFgggrynnwmA& Bz=χᳳmǃ6M+:QGA=naajJ{q C,tP[VRWb$@a\ <6rԀ 5aT*iZ[t\N(JVv:X,dScccD6b6x۝H$noo?~ ӧFns>܀:Л1l^__gF c' Myrrr}}=;;ׂIt:a5+ "ggg%48g 8ZNH?C b%Rw3aBFvQ&P(SSS`fANY,\jw :יs<&fĔ`ñwE@4:zіVh41 xaR쟟i45rb0yC>V*̏z}} 5$IpH$RRɉvlX,shZ Z>GVq%1T|i {,RPyS> Y^)?.Dh^#;hs [[[333dXpfoooqڰ`mm U`}R A^-~Jzr<;; < F10)Z-˻;Ov" 3pt E4===Ź9F: )j/Ӣp}͛7+++P%-~KJ",nWV}Dpt: Ku:庸xMVϿ}V1noo2Jh6H 0D'ԃ鎎Fq4Mvdp{{Kvs;^]]y<pvv:^xOVߟݿ憹|jO4ͣ#N^|oɓ'JFZr>9qyy)~\B{wwL&)>X1E_l5ONN3xt;"d2I}NQ?0bFqyy \lqqS,I=ZJ;G&=yn!$ zz8PՈ]\\$ >0 t:͌T*SN1 E`:]lTcs,wMl9Hr||`T*Jrnn*@RȧbnnfU*N~5Cla,3T*%MIBxa ?^`0%tu%HEz48z\[@3a)W)غ]B5\r@ Zn|>vpXDjB^d|MH\TqUԳ^T*߿?99 )p l6HPh>%\.99NY2sssBbSe!R`Mr\.O"yfccB ͎ǂ`OYvEx HP(Ċ sPr:eS'b dKWtC)3!2%wuu*EvuOW6LQg0LOOCa3 묅~:<<$DC5vSjJɯ`x;T[^^VՉD4(\0C,Y:'d2 L& X.]Hv bdUjd(Xѝ?srZM։2!#LJ*S~D" :j1rԘӄǪUNGՎQ&QGGqIR-LY1p:Nerr 6}Ka00?܆p\:bAZ-pc(\'dSB5>)r>N榔JQ~L&.UR|Pjrf7ϰʝR5ClZT,?)Km2޾}N7vn$(޴DGtDdىl6˝x!_!$$[Fgff.\.333䳼^\.'A1 fffMMMUCǕdɤZZv|8;N*D"l!(bY:Nl6A"F|?z~frze2C?ׯ_`& ^HҜApPQR% *!2 ǐIONN1;;;F^.SV.H(#VQY4 ]p[0pxxx #A~l'*>vR&RR:?? 0j~P(t:xBq!P rAŋ0>2 k6qh^W`XEƎv;We{DžVPR??|>k*jaa |~~&dPpL(f^zYMDY6$ɸ)T!gh4׋Jh4Qt:nffN 1ZH q0 lXBBVJ%*!D^4?~̃;CjYT"nwDަ(tzkkK`@Z)JC<88H$xrc$!MKP(t:D"YYYh4r yeܣ-hqNcffFq>F;Fēn)5~0'~zztb󘛛%t:P"4t}}H$v;YJ4*JP޾}9г3׻??[!0Kң#t{{{෈vG, -BA>rVV1@Y"6'hZ5zK^B)XC sss LNN` =v@a_l~)iT4?<<sU*1%;dpH_CؙcJm9fǭ/|:Nv [ C&RpxjC j6h8 2AenٜS*ggg:y?w#BPn?~P(0f-pSvK91=b18й8ϻ.fPrrr||L}Ƨ=Q,/Bq=Xp8L/w8b0bCB0D"T "|W|xŋ \ƃv=Jah4,]덟lxe$@| V)2|>2&#B|czeLd2Ad2DpA&`c;c+vMMM1f|yyW_B@R\Ty>f b~~O>|vwwY7ѧ9Z%qnn.jvP(6v&"6 8˰r||LrEAiB`4h4u{LG i6vdeF|\WWW ҁC5.wY,JrzzKd"`8~Z@3tr8Zt`c'w\8>!|>$#db:P(+ œ'O+@Ok Uvw㓂jx\.???t@ t]@OtNBMJᣣJR(27o\.!ݻw 0@iXm=d;0^Gn/--A9x_}|tl-2aTt:(`B;N6ϣh4h#Sb{{j 1KZ3z$e2XY` ! ح<;8 2<<,IgjjԶnc@lBd|p #_`JR(xIQIRTΩ叏E1ho4V'$@Lb^G?;;O_qf7n $#GMVc: ^lv]__sr * IDAT,3XH|ZBbJ2 aE  ԌM&ׯ{^2L0~,lZeL\.ykkkwww'JUUbZt۝WFhMbTFPz#A@=@K[hD^o(* D"W&dJ%NfMzn\f; i[r\r|mMJ۷p$5ND7Ҷ+H$m|k<`4"|YB\.ml6KZ1wg,H$ig>'h4p  Q'Ijn1LN^SSS,̎zK$T*u`jjG W-''B*vݜ):3T,Em|'''(J MVd l mZxYh4,Θ@윞nLŋp^#0 4 /=?2&sJ677#˗/,Z0 vvvb٥`P( \F_H=BXW\R~- r9E? U2kP(i v\j/+ /*^7F1YYf4*`,FUFzղ붷d8>??fSSSd?:/xT#h0B;dh4JH$d?5L|hՕhDo.䄌@s"DxwwW_BaZH/0S6 {U*ݣ bگqf;8Q=Vz_@a C( ^4EbZ6 ghB#,g,Y" l6/n7‡_L& D6@2n [*Jp'^ѝ\nkZю,Ÿ(CAA)9[áP(IsiB WhccclCAfn еZT*6V swwwO>F,8D ,t~v`}<Z^ ht}}]"<|9VأO6zXbb.fs4jBk\JÝER ( 4 gaVAYfv';>4XFh* U3GeTxXt5VdWŅR$#'Nc\;88FzBG:<<ĨFdfc_,^`B?$V<jILz F3^1t|(... !CHtB`_msTl dV]XX`6 ____^^1H6G IdeRYPV- 7@!$nn7L"Zu&:')X,f2@Pl߿$ɎuV?^4=%cl6{zzjT*UTC@A1r q/t{  .JTbb`0 ?ONN`-@ytt4;;nRJ%f|E^D_jvvv...f3a$NSl*BNs̳ǩ՞={hv_^ϬIV) ANH$d޿K)l6srՒ$YL ?-ʘD"xZvݝN'N;* c ӧB`}=|VdgX',Uu#s.h88 eBܿ}vv[YYEVkx [x.//*ӭV@X!,fyYtw:LD rF{pp s'X4^^^B\LM_t]bXnRjeF>CDx>9 DbojVVVF;$ݻ{} @Xe 'JvJ%*9`b0b}$ˆ`BBpCEQp``bʚMr7o޴mDrō (4fnB"W! ~9TTa~G* B!-L&ƄPW!kvvFfPC,2l}}TZ3T*Mӻ|5@ RI3vKbTBwuu:SZTbxxxHD RX&=Kfɇ49P$x< =`$ITopyy l_<3wA|˗d#/JR1rLjZtτ?h>O?t~~tt{{{kkiފ"LdPu2 IZiQZ#bp,RÈMϡT*,$(6miiB5JB_B %'=D"v"U C^F-Hzj||Vq~:LedG= Ι ;@ . a슺l^?99!PǣRlllPc $\7 NrTbD3W*R(o&&& CdW?r ?[^^f2+Y)eÐ&r^B|/^I$D4 !ur3߿g-<}['&&P>|P(w:p6P#:[_~-D9h҇FV;.790QHr xggɔ0n7! 9⑧දV !` 2d~b`k RjZt!2K'jD,```>>>h4x~۷rٳgjeC#H*PNb`fkXZVP gyqqA`0@,>Tտ U^Vʼnjw3.pC4G q~'3MX*"rnqqqzzl:/jZ"ܻwUN/2H&,7Gyzn7v'O8,0}cxd:9̻q1BՌm ~V&{vxx'ZXRD{R[ !z=v,\N(OTVEcBUnV^ݝpqq:`0#E u:X,n ^3egyyPhWjXKFmT*d(qBƣ\.3"b1 ^Ovp.'&&PHZ-1CުBR<|TB ;cZcvL !s !v\.ԕYF mg'L&sebV`;;8@N >n_q!bptRi0Pu^__rn`Yr,=8~$ߏ|1 #P  _|f+p ˵ZpÃXf^rXn-GٳgRa0v rt̴ZVx, Vl6_AnfCv8Aj^[HPz\NRhkkkzl$+XYǰlc'V>~-,, VH.WTxN`To| @EZ-14x ">|>h11gffL&ZFq^IvpLVc~ss f1LFnl6H`NszzZ.GQJ_^uOD x~^w?99!i[:008::}~~\md9S*GV+&"(H$ÇZVbX,&UU'ZfF 薐y߽{iNY ܘVC#npssCP{R jZ\h4O 9i8ts;;;L= |ssZ NmRsCϘf )Ӱp򞟟Sޤ>!$4b}F$!MI 4@i? 0+݇#suv!&H z!%xDqH\9ǃH T:Z & g{{;3f r`x< (pׯYoxQHx<'Cm)?R[,E:)z80a7؇H>cmg ȀXcR& \T 믿-cS(JbYBjQ0fG ^f# i F+ =I8nmmmkkC(7`0ϓiǘdn&3:'>Ckا(*c@c1Ny$X,}6@vPkdD}xx5>dtlvwwA"jiiiyεbV b1BQ3eAIVTTl6;::Js ":NK2 Ŭ0hKjRAzwad T `$ RH^D;:t:w#FFFf$cKP[3˅\DR ^#FQϔ Xvwwɱdl/H*J&yDP0Ƥ*q4[!*0( cLly෿O+  aJOtaOQ'n-2 w/inj5 h_?DOŴ_z`RFQVL&$ھo߂sqqqyyH$U*[n ?l^^;::\. ky098Yf\.5IYCzc'NPA(Kgggce344T fx<д#0'ޗ/_nll`@˂*V"\.G1@Y&!f#rH:Vkh44,bDTic.(bcd*$ L+ 䙳3t:L&h4LV Mn'pm1<<{hhϋ_Ӊꛓp Xzz^TKdbNcνPPK7a(fRjQR"~5JZF~||ٽhTTp65jifss3mHhz耉J`0{.^ǣjАVq\pTJ j~y###@͐q ]Z^Gj5 =<J8m; j58u}ZՔJ03p8駟677H$^]]rO?k^T>??_^^bT*9FlZDs De@ _\ I!ZZZ;q|>XHvuu|>O"pXD"8XQ ֕e/..VVVИ\ C@ 5FI$Ua۱ PjyN^>0ܠ@}T*ɤf!@PP 9 _7G<7b.# }\p  Bc%U(&&&(!,l0vvvp$3I&ǹ\XAb1nL_===2fnٻ"WbZzwfF?>>l6L^Bp֐M+uFSSS&?9]8M*+* {{{|ȍPֳ*C.3w& q9Dft;P^n@q%h("^o(*p! ^.qXLKZEvQ^__wuu1^\MCB֖db@LJXY2gJy !B#Zl,pN$A@ O5M }-3411L&{.ƒT+ڜNg?P0(z{{gR(f>>scdxp0f3ZXP-juOOu=I֪PЪlvqqTՃYzpA}e."Jˆ5IUkkkz F1^FIӔ!1븼zH~NPG㡭Z"n^XA Ÿ!^O0'b< 4)óE|[&S/v8677yZmXh+hpi>ա!p###XQ"pۓ J](D" uq4bJ%9e///T* ^[[×.3Nkkk P%uVzT*f[__;qR)FDzzz<O$813b+9ONNPqq!UfTfggb% 5mP(VRCrb1$-'PE/j.u.'EB133S <[JٍAww7e#Peȡ8ƭ-̋h*٬+BExqq177Ǥ;`@2R j3VSSS Zn"[T( =4p|e #suCLcHdjoooLl///D cxxoo_b@bf޽ˑ111h޽ˇc=\.Uo wRLonn|>ߟ'HK*RյZ.:)B`Fźq0 C!aV"+zDZ6N3p˜2dccŅbǿZ,!0d-ɤv=== $ɬ# c677% &+w AUջwxZtX KrɈ|xx:fŋOzO>65|>pi.OO 4VC  D sD3 3u(h4J[64HRnL1/ӒaBN@ ZP1Vv\ fgg* Cލb899y||Ȁ.˝븽X& ^0l> rE---&[zP^ZKu6s~1%ӳˆj&%ϫT*l_LP0h:z͆Hl6 zA O,NsppfJSPu*v;N0**Lz^bfU*H$ .qttt,,,T*ÁAThmkZwwn;8%vRCb777###8hp7.|gggfl#*z8KR@J###^|ɀP(Pt:Ajkh)~ttjbT.aB l6ӥ1JmxRL蠺 ?iwp Ñ- C֒&&&B5== =>c 6L# PPhk ݻfgg8OLLjNt:Y1?99`)f4D"YZZ@K\>==pEM0D!sVcdƠ^Ͷ6nV! D" i:;;_ѣGFK$Dz].^\T󋋋QjB|šl R#o^ոɈdcNzjH$ ޼yv|~~%*t: C2yy2TTo߾eSV||<EZZZj% fhRtJSFFFh;:;; nPh4bC!9Cwj @pp8<Z@$nj 0P&6̻8ONNn7F3>>hnݺښJNNNn~x|kkA !H,//COK$ϟ?gH$z}KK5:BAe痖x4h(c|~H$j3ˑ˶bDϷÞӧO2 (O| @iramm :UI$9<<M B\.w}}k,p(@`*z-w L(F{{{TnooqB`pR)ZT^V^oGGԳ1C,(DGd  A1, Vuuu I&fpa---ϟ?v\_}U*(}^cA_5ѫWJC; Rommj[[[X/..0~H,' Usjw?b]]]P|C1.CP(ܻw(JBJIkk+!p8!Tݎriddŋ+܁d2[5N L&i2vvvfYRd2(>쳳3ӹUx{}TW_h<o.Yl#vJR#;2 UTԃP{zzdd2͌E<&s@ד $Fc0 R`@DO,X,H$Zb[V)9i>_[[s\  v(^a|Vݻ711CUI\844t1===::՞kZ@ p}}m&''X t8:L,VJ1ewI$u②b5Ju!v5M&iqd2ɁVA`B(@:$rj(?穩 nǏz:j?#Zѣ)zQXj>4 NcW166p8FGG`Vl|>S`&|HD"a зd23£ 39<}l E"U#3XjF '''䓅{ƀ䜰eIfS,xX"͔=jV/^뎂\.'\.&bhfy~N 񞵷g2{{{ȼB!*Hhb1%D曛` *h4K1DX p8noo OV[XX JRKK dRa !ϣ W"ӄ72FJsgH'V5XWTL&S0D"&M3=PL~QUL$4UUKCX[[V+ݕ#殮L&壣#z+$xc mZVb1\P(d((QOOOSy!iEJѣG'''*vCMRw5L9Ƞ戗x,2p8 A-[7oވDW^u> {Ź\&=H$V"QhL&WdXbIR܄pTT $5]~ aB<#VVV8j"_"󊋋 -kkkJŶZjd2l! "B?a}}˰ӑR^ZRaZR)嗬^y=:: LTApxoo|Z>ON@iG͡P_<7NsH/i2~?8Mt#ƈ_J;??D"YXX@ϡ޺^!st===l{{{Ǚ*jpIPtuu% R955IB: pʀC# j&Hju&X,x)" `X,MMMrG?{NNN'&&GFFf>99Ɏj3]R2J6RtooOT fgg:v'*)k)Jɠ@MD;ngZA*YQ3]VA86EnXb(ornT0CӠR(,ˏ~#X܋Feh]]]H${  "jh4Dmmmu8$S_3+g?r `4 ;&N*ppIyge6+Jww7pXL.J%2 "EJ+GPBe\Pd26=RɝjX,K$D|A[[L&t\}>XHt0.E#Ф^\\Vh=* SK@]'>2j2dy^w.fffns JeddQd>'˿rsX ·)q^Yav*4^B|^6d2h>&>/AU766, I/577#|.v-56l6%< JW^-0x,aeHdooY ǗYTnmmacC`BKUT/@tl6J?1y&NkxC#J!;NRĤ{ hmmQl)"L&#/߷X,r g05Jk`Z{{{m6T*ںZ*6$LF X▖ p0kq5srygg&.|>O\.ƣ15#4r_J *[RPpxyyr7oހn^ZZB#Fc6-CsLF T*ER9,HWWWaQefZDRP2ūj(t:9^g2;wp裏FFFhC9Ju|@gTZ]][(dlllhZ܉vaD“655Q%1Nlã#Á=/4rS fi~)жY,//3_[[c4y:s@ Eʰr||Ƕ\%0AnG #=#&T*|,Ai%<`0ciin_^^^^^21777sssbÝE-f\ ȻT*I$6WX .Jz!/HD ۇ4`tggg"۷8V@ LP(/׵5DGX `4k2HI|ׇp8O<𵲯cFt:z}SSFn},egggknn2 IDATfW$*ǒ+&e ** |;;;(/2$% `z\Ѱ*?p||p8`mnn*x<4ׯBþ`pp/Kݾc(OV x[[ݻwx.Joݺ%vR\2 sJ*G&aLFjFy'd;::!KV zV5c2 booo 2` FNݭV\?޿{JDCp.C"7|v>~F&k4v 41|-즒DDgX,u/SLJ͛7 hk\楥%ʽulvcc3Rd ]qf]0SMd29>>Rz=L |>V҉)]< =tLBQD rpi666 %FK8 @ٕJ D"" AQa0~_`R*sssW_vww|_puuf9,#IFzHyblt*1`RCtxxu,bc&fXjՕN$]y'*wٹ3ݨRj\.Wf3ZO "hTT&p8  +D a%A hUrBHR pu8>>211Ѱ~-G0&u 7, L μ^/~BD"Q4=<<<88W.& zKFqmm Ie$aJӰrWh4B ;_L@!`vt||.fұ1lVj}}b0uT8{zzp wܑJTjrr;Ç333䈈={FwbsN v8qBK3 xxA=46zbȨd߁@l\&S;'*?>888<< 2e"kkk ez*pzz:00055E#d2D"lQ 777o߾_D`J"/-'Iqyy&yp8\.iࠁbO& ;/p81=???O$t<4 6 )c:z///s`hnn-Jjݻgjjjjjjxxf={E{a%C9;;b?66Iڀ WBQRiSS ~nmmEjB(JѰc]jcccPmr/:MTl6ƌCCC3d22=$J(=L˳2pbe4lQa_Kbs:*=~͛7T*L&уݓ{~~N[_.///{zz8 *jJe۽^/pOOO:`fffжj5wxxJn _ ]:考bAjÛ3%2`)_ss3A&z*Nf )0 dT*E"A" l6HTAlA[d޼y'فEsrr4 BLɷ$Tj===R lrqr9^x)m6./P]BykfC? GRDPF~Ptz4d1}v$et\|)ϟ?G8vii n(yNvwwb7|jTb|qqgbl6;??y6>oX]]]]]&g˔yww7}& 3]B!j gSS T xE2jHAhggST?R)np>^bqۡJ&v\.1Gnd2y}ܶ-Ri&~n&immnnn&<pq!O`{-+e6%Ǎ:F. /jWnְ~8#"CBֆV˗Dbii _4XM#>Jq1rX,>`'?cN׿h11b)ӧOz,s\< Z.Xng,N7H\__' bsXI* `\JR ,}j-Ri||<#imm% Zb1JP#b^m^"˗{LFǜl6࠾>B`6 C;PvȠb֠~ Тh#ˉ8BJL&X,& 6{{{?{ooݻwI_"^*x U4X{*-@M/n7tfjϦAT a:f Y6f:nl)b$ ɔ)( g4ICCCnbdd/ÇQr+ ///$M!cGoo rt\.d4 wvvf300ulllpppll Q___]]D30*G" |Qr>SDܔ.Qw9<<r}v!:t:E"Q.㚬V'''{* D"O} i-KHؘb8h߿?hss{*5,E`Xltt-S?Kg}h~~^$}Wmmm`nso }xlq1ed<ÝX :NG">@miitCCC YWr9Ex<ɴ1C!B Ѱa(<+\\\I'T*nz%E^ݧ "p\^^&r9> -V%622Ԕ2( jw q\)r9ZLo~8tEy45L [\.WZ3M$1aa0o~x<tuu卍 dPl\.WWW` zBuss9,8CHw&R @jf/JJ$Ritt>h4VpDkkkVӧA)sj P:^[[dvquu>|L&{f;>>S*Y023W@s T*!Z5 X # =8+!wtti¶ȝ-yvv*1]Ȯ677be01;H0h4R)NL&_xH &IRcsP^޽b^♙F@ggBxiO=[ph C2lkk!666S΋D"6"n1`+ `D" T*CccclM)ӹwuuQC+"lmm|>d2Sg)~$.ߺu M$ao?OVk^㏃ Yv;: #B{{?i00ˡݽn!lllPonn븹9>>&:< Rc B<:: & g?|Tկd2 P6dSw-T+NGN ^$f0vÇ1 |rPA`}Ǘ s K88{.í-d, d2>??rrЫWTe&Ԁ) ]'X,VTd+XQJR[[ xWʉ!x{{T*avxx !`)ONN)T*w}IqbSAH&d9*A@!J)HwJH8!4N' pqq9% +C0^殮.Tr\\fO_P $\.R{B:#%TC:;;GFF C 8  bsI&ԪmnnD,~\.F f2&򻻻 i4NFhyoooO$0~WVVj"\3:wH$hJ08::"{j6**E. tbxaa]2bRx/+Yz_bXlN>#?T&ɭX,4cj`i/8泳3ҏWVVA@puuQ XH$+J6n3%3 Z?n{vv:~}`[RZZZMoo/x;8o\\\Hx(aHe+`a$L2[d^\HlniH@F1a ),@p8 oqqf['`090ئ  U zR)"$ZhfjpI`UՒɤb!Cw pGȓ @ ^`0ommE̓szz7 6O>?<嶶6N|> v$=fISSA ušt||f-VAV8Oc!~潽=["f1UT*{MMM366vmA=zpbbbff-ykk+/8:񱱱d2766^qll 'pbH&^'3 dڒɤFwH `5ǡ5$ dZ:!;EJU 8ږorm]^^"=dJ\.dX`n5<>d:;;i&T*3[$ k!Ukk+7 h4  QlQ僃kkk+++(lNu@7\Wz=,MMM,~FeLJT^Wr~yyi2\.WpssR<NN/j?d2e(BÐt*J ".c,K1L$pb1~* EKǃS[ajjZ U`P&a|s]Dz|۷o3Mnnn^^^V*9( x"g2äR'Uqa__b2ۍUrZJD"u^`I^[[lx|oo۷ yYGS A 6 t:d}}[ ;KAfAE,Y(ؖ+ wr9t:Y777wvv<^~bZ?sŢ}>"sd2vTd2jꫯ( o߾aIh2E޼yhБ?COJ F۷oq7b2:ҩ|>Or  $R)L붶6V鮯no0A f2B *#8gggϟ?1,9V__ryvvy&͒ fcrr Xd2x<^,?~cپXH$Ge*jF)DO>[PRwG H...X.br~~HxZT2睨}>N#ppxxH/-Ɨ_~.H@8 ~UV+ ct:+Sʅ2ݽr8u:]0dYVm@vFypp MRq`7~ 8:&Z^v CՊH$AYįBOR?#dpryϱт3~(Ax%sύFkkk񋋋h4]kH2f|ccZWWF====xg@2jg9 al?L˶rD"d.KE7NH.8M&oNgV}霛 t@ WWW`ATT8=jCKT*pH$l@(lii!R_C8>ӘCM0,*HD ›Nh-Z2eC(dCRÌvFw}Gw\.:H,&VICdnx<;vU*r|ffOv3bٵB@ a0e2M  J%\HpO$IAR俘344d0@xca J`xh4jkkuZ|XQcccmmmmmmDݓ<88deCn*p]D吣f3 RϧT*onnFBET1HE(B? l6y,'DRA, pIъQ㓓*7`$K6*{=5gB !,PDB@8i'x=S[ej>v[kHMDPN( !! ~oY=xՁ5;ዾ }z= Z^ڌazs$d†ݻwPDf5dx!ᱤYT*o޼aHnL$o%Xp</l4iA krL&L&z=.<0PG,yyyf(7& 7oބB!Ƿ/>F"nZ3 PlEʸ# tP(IC+++HЖ)Z1h ߎ'''|3D" g26]KKKNOOuJ%Fj2`$j6M*H쯮FFF~?G9&-]]],Ą. &h4fΎ*jnF"x+++X]^^p 1mRDB_PP(1"^zuuKF߿&Dj5klk\0gv{R!gV.?|ggG&AV(sssBV;::.dxx8@`ff3AHt"DY|,AQoÅwl6tl6˵^Cb3].\]]x +ͲP(P Z-ZCTǍF݉bYYY!І)3@jBrp ZiV^ۓH$|$ k755%흟>}֭O?tF^_?@ v;}F i 4Qz=Uf|rrdЛ)h 'Z AѸ)V8GFF,nGt:љ2X,8ͪ**@b/Q333nCeH9|>W_}ettt_O?trr2MOO֭[HnE$qJL&}>0Z꽽|^T ^(8sJNC?FR`Ȅ+0aA"Fm4 \SFUj\>Ԛy§@2^KĂFB`0x}V(yaB 3rV|~~ND φLh4޻wg23޾>:Cr}9??xj f۷cT X;gR Iƴ`@t:qu|'Ä R`נIoXL&ŇbL3 p:<~Jt:qs(R433cZY ^+NpN`.r8癃2$rÇ WB^u=< HwE*fuuUQVgff}>v6n6'''rVVA&Riyyn{.lp0?Ţf 4ɍr~ "p]twwõ/HMbD\˕xpp)r||<ߧOMNyg)HP(DKBBAk r}rd2cee#Z虀(<[2t:jL+J9kPSG A'6>#"qT# t}[.WWWVT*]^^2sn}֐6r9Aw^\\loo"&Y@q~-..t:JŢ "\ΎM8ZLlmmA*\+od2BFlmmQxZx&R6ye0qh}~ݔޔ宮.J%&QD"gba:!*mZz[(BP244\bhH$w_l^__-: L<ϭ[PYL{Q9::J.@Ǜ6D"dl6fuE_@kj1 e mIfv>c駟FĹpZZ Os`qѡhB( f֭[H}>|rd2\1j5%|>xft8*jff9;bD x0vSFSꅛ ac A,l}e2908(s}&-v#BT*R(jiԺЭr5 ?;!K_^^d2$Jjuu*"!kx|yfzzNZF k'6)?nt5@vd2P4ؽ[VPptwwRT@=%$#_2===bV!ūyvvƁV]yZf' A- ~Rl6mnn$Eecc-o[P$|>xoBx2hypBd'@a{Pp{ϡ$:>99!WDQf 8:99ADBQP(}x~v`)!s---@e^#n_ܘvӧ>i`DKKK>~W^!׫+@(zzF鱱ׅB!nzXWo*XtNTk//T*V AqQ׳ż1q>+>p˺- ΕBOy^R4J|EFc2V?fӶDbȴ>}4H(D"kۃ?T C@ L633ɓP(  MdM\&b!͒ǙH$J-/:,R Ynd'a#Ff0.xf2T( Zڮ Pڨ"4!-3񝝝Ǐ?xhlll` 7771nll4MJ_㍍ &d grd(/ i j4Vp ɗg ] ?\fp$uDPnvG& R3+LLLplv+ʍ%L{dz}}l6 x"pLP({?t:Hf1aCz`.#[|wTFGG:nBܽ{0Z]Z&MMM-,,LOO#KSybblNOO|6޽{+++߿Pzhh\.s2Jd6/_zvvFbbC!Yʳu`ITdB/r9pnw.%  V3y0m1W(333_ I۷o$x^l6 ZVF8Nd *nnd̲V+#4tT(8/..)S2|>!zV?? ^]]y>3ЦuH$SSSjkIBKkxx$̜eǾwrrAkϙ 2,gD20p1t۰H_HR.K d0ZCV W[~)+tppp8r9/\1^2DySL0M]^^h4ݹsV6 IDATowfvk4%m{{ZuVOOׯ}QZnz x8$5裏T*Ut0qBRd6m6~5H٢![XX@ww^Tt!x d!FQ(sI=$}B*b8::f[L;ɐĊ l1"uwLMM=|puu(RPߟB2ELIdCǕ9F# \!D__"m*zRrM44|Ůqz|>>{]tuL?rܫWxDd@.//W*JbYlbF$`0r9z!D_Ep82 IlF#1T\9в[R@q8v\iBuZ8R)rR"D"Y[[X,}yH.;::bsvv_{%Yry}} l/s_zEGt:.,,\T*kpT ' ~ :r/h4SBZV&+gϞQ{-]ȟ>}ʛ~pp`2nw"dn&wy<GHb0zuu|F?>==͉&ri]<WN2c5,L(`eeexxxhh=fsssww2tx<F^)~-RL&C`)avTjbb￧xUoo9W 4B`2phZPɑ0VI6fv=;;F6#,+H85ºAyiZ`͚3`J[[[_zŢ^?{\.|SE<|>rrB^^^>== h*z{{׷q'J%\JJ$6+ !&)@ P*n૴m.TJ:}د/_\eLvn԰lPc裏J?#fDJ%F\B\nB_j5X,ƁvR(u:/k]Dvwuud2*T#h4L[5yPeC7\!>fBDIӴp;rww Z/$7 NIVAaL9ONNN޽g||\.@Hl6 5pGܹs51-Ԯ~4t:x5t:e@j6X,hYU*h!8qj ޗÝWTh!4n{tttvv'|v].̌Z_ݻed_~5cC)fD0NNN<333a(إRjjxx5Sp,JPM'$5P4@5k8 Zupp*H85ݼ^/l^o4~uR?(JvB8 mS|31LZ\]]}駣(&''ͦզlF ) JKR*E gttZD"Lh:QټT9˽=(RJdTVcIRDW&Bef΅ Fa61LX,aCCC8ptuu1#Wp8l&aBR'`hhfkjjIÁ7XX\\EYC l6C٣^Luxx3'|VԔZ&L1,..\.t9ͣѨZ].)ˆ6=6GQR)rw˃N3!!===J%F] # jt Qr>aH;;LPt޴y֐@X&PJ;;;WX|=\saqqWѣGduwwc(Jē'OP%r9N LjZOO\CA 'Q蔩P F@oZ,r&J$Hwyyb^3]a8h4Qx<\ZO~bqcc# l6&uDGIRr\*z\nssSLx$"z&)xH8<<O юd,ְ\^^bVzC^oX Aj6Z'Odn0>z\.cV WX, rBlCaj= !݄rзD"l"ŷY,<_&===*3 3vj ___7pt-~h3D%g}V,;;; 0 Wkvv9GHS#Py$rN3zfR _ŋX(ᎎ݄Lot7Jɓ'd𾟝gN&*b_T rH11˅F@(:6vdb"řt\./~񋑑wycd駟Pcb,suuS& dƸLY}'_|fsffFPŝ@ D.~˿tvv2 `0Yvuuu||`kT*O&@u. BQT2\P(`QDf~~~n4 O C놉f;:: [) ^<g~xx844$ Ky*B"vmmu zN`){?d4?+mÁuh4]d>g}O?:ƼQ B}}}l򨢚#v(FKJ"1`>#@}Gy/*`0M1QDwvv޺u *Jߺusssccc?D6;;K:>>h4%!|"'g}}}nݺ}6陙?%df)52D"=66  ;yWW)v_ŀ(:HVc8XհVb&Dj@C9f8ҒB.cAJO;;dlll``Ç& Dqm$4烃CCCf/ `0HԔL&$  hUp0 p:~5e U2bLMM1g dcc q]|bC$R #~8g @BP(P !d6e}uuVɶ%l~嗠iJhn79B> 8BƸH+6 ###Xt:D*_+HȥylDY!"$gc```ddlZ6 `7u8_~%1P(t-LHt~:P(<{\.T͔L&ICx A\^\\aE`ȅ UhM!6!X <4ػR)lTRTQ 'b|>wy^VH*bqVT&iooj˩T*v@HB].wuOO۷o SɩT S%?xO(f1Nm{nF4Q'IA>_\\S'vk{ L˴f3(LaŨ V+N[Լ}oXfygg-P(JB!r9j-`ggg,b\Fi]]]z97;i񗗗v\H$ ##BRao+wBJcFx;WJX,|A.,// Rwvv^zիWPHَT*oR)-PF1ub`Z\.+ B]^wޅHk O:YPG-p,--e2պ{qqxPloo#;88@m ^ ;X͆R?==V``x<=-//J@F\?[[[H$寯y8;;Ɨn; nRMLL@o)ɐ~E[V~__ZJE`vZv|| LD|rrbٺ")%P?}>`FJT}}}8yYH"$&9?XTf1@%kk~W_}ɫJ6ݻ6nۡVV9uww|~?&glԹ&)x^C>3H R׫)qzv e:J]^^4Jq P*Ll6v1"Apy/ftQK+ Q`[;;;i\*V-..u7t:l OHh@_XՐ Ek` Rɣfꊴ?Z иP\LOO빹9f7i7JMFd2]]]1e7N\.'$=]0B-t:^WT#h4 n&16ϟQR&dmm\-T@h LR> i#2'Bc2äJ%6h(oid!/ޤfgAq:ò$R8NV<ZM7GѠdjyVjg===&EAmbv 3H#+8::+P( "L|罨ggg3D"P Ve^Ljcē mf.pmmoI j#EbuuF luuUF4kkk=|Z-Y?&c\.j#fJ{feY6Hvvvrp@uuugdGak6S[z>NGQJ588i m!}W9kvB< apxxH$-d2Ɗ"@]l```iiF4.R 1f0) @^LX,Jcccܚ8ڹ<|>c1!N#8LD52r9b9𓚜D H$g(_6 {{{$I m4*p_c &Όd2Ic}VP*yP)O M2ҡCńޔbw@"!8vzzzx5罨 eRHRmP(q``t}S{>ѣG>vۿ$}bLDSSS^գb$2J%Er))yN'vQyttY!Dz`69/&?b,υ]]]  L=Z%/R>|}VN DOOpiì?X,,--1WA>b9<%nഐ9u;;;enn)  JYO=dl``<^PȈb:J5p8nr0"K.ف4Vb±Ş .?;=My/wd >k}H 0"n*O?իWFS t:h5!퀦Ħ~k_P4p8kݽ=:}ܙLj +kRᄐnNJёf)̙vuubrB #z5:j8O]B0;;;^& l6 )MC:)"fGd l$Q* Y8[m/ T7fsgg?+ZR&aT❝f^s}xx>^VRL IDAT*6:l:.p8 |zzZTl;C'ҝۑC#jB!L~( f tccZO&''[Hj;s&6 4ER*'''R<%PZyxx5L2"̬p^5B@ LUHo5c:u/2l!?dmnn411aXH㯯j9gȋ(V0Йf z^*O0+c07O//W2D_.R߰ҿby+ࡃbNy/2. UC?#'2%0/ͰΝ;84 V500@톽bppcwBf<[~0w8YhGGGn899U?<<<<444<#A0RN^?AQ !6#^c& 4 9+mr༭T*RTo'~<%rxQU*]]]HI4L&\28zd>*#BA 5j:00򶿿= ~Q7~w\,ʐ9@ _GFBxTV xyIr9k$$!H$qc4qNGWT0ѡ #lj@A1j. '&1??O4G0D# 766߿ l6ɉmZGGG_V///o@wnfQ&ڭ-Zr Es@HVe] qjFACBXvn6l!OV>=B\.GbCZ B2Z<>>X,DX,(LZ{E&!837Zil\ZL%ѣzLϞ=#ә# %2RKrr\.F{yyI$k1?f)[,H$Bu !,U]XA@5A0)d2eu:VyF1?::j4v}ggc~~~jj*Hᅅ0^wggGRbd6C PTTB@ T׊!7ԓ'OfNNcf;ly!ҲX,b~jVGɆ !*Ç&ij%)u}Jbyrrc65 p2 ;| LTZm<f[B#?jy@Bt T*\44RyWy/*iF%T[b`0f IwrrB0-JXlaaիWRիW I^xQ3R;NvssX,e 3Vx !Dy`KO&!t2`z /'5hf?Š wji4cBfqEiýdK$}a,KJH$8C!!///i(VVV&l6k6hLp|4MJrQsBadOMhn59wp|1V`PPpYdz}} M&C}]]]ger|}}78YTzpp|gg4&J'K]>O&px0!}rʔIWIbnle~M?Z0Yd6n9N|#ONNb>N000!]!DVYF!JK5̀GӇ-Hb`)7 FlyGm6'''9B!6罨ܻaMjLA 룆bS#ȳg>CK02J 8y:^]]!ѱvj^^^OǮf2sö|ވjRDVEB?U `0A^!Z~u:F:jX,7;::%&p :BXV` JFiIC*؛YV4~a(%!OP@׏DiL .$ci۱Xt Uh泼%{7F}%.`,YFPuwwL&Ҿz{{ )G`nll$ A. "l j=-8CcIJAVM Jt: }GGR>"JX,z)nbNs<CfǼ(D`% #Fsv{aa! iF^$riTMځ bWW"V4Pqutt8ñl6,:\cnO % 4~8f~r8N9=b!K ZZ!8 f͊oF?<<ѡj?s$!0#EMb0d>0Тf:<<I@4t!`KE`Q*;;;&ri&I0M(ld2t 0d2BB"'T*(ޕ&sdThx<6AC`K>:==eJf68Wg,HlZ(h8d1^1f0v{ƴ:ANԘ/D"XZ@#'tp8l1Fѱ1䀈(NOO%JONN(Bz><< a胫*%L8xJ\lXF4IuNG"PմBE&p:T"jZ&?-dcFjE\HuCw},??P/K`D" &jJ>v?;;;Qy;pˊkfx< 7o +V藗~d22!vl;L&_ tRa8߭-DZFacS.={[26N:?;; BL,%{vB۷o$ݨT*lNOOeJ=xF4BѴnLBJt&X6AvZ͹h4;??棗DL6#K lU`s;x<g2} hX,\^XX`V$7M:><r ,hL<K/eJz|>?==MhАN|ٯqd`0HLuxzzh %@&LVngۃJ% pv2?Qa l 4Fr$!鄖Nio #7}3p1`?xZvdd6rdnnzll,:\~m! j^ehS6iH10+f5::T*v"3z  O9PC!jD"li3 _\\pg0vc 5>>;-X{z=o>\ E<Y&6CCCجTَN;h'`_GPVT ,B$ 4+_bB"s<0v7V6`YQݓd^WW۷F>gIu<77wyynM!Qt^D@;==lG\./*^qq߯GFFGl6[VuQ*7/Nx UBp\)].Ҁq60"zd235ZTBr`>ErR@|ssI(B7V>OOOy^`P;0E]j2+???7Lpj5SYTACU3$Rɿс_\$ *jssC"W f$wv:ow鵵5%1rBgj^|s~~0````?L|>72\uj<f&Z$&<̣iZ'FFBdN V+I4Z)qCJd4 \'94oݺUV'&&M*d2~eYX)_1^r"9`"I&1ǬFI_i’~pTՍ JJ0]r )y7_gg'W{^,T///u:!&]]]4a^8??|O>VŋgGɄN0>x Zo0 GGG0CRYŋ>N&i'lMH0(G X6_` H*tbP"bY=;; 8d2ꙙ":jw^2T*xn$IJtՕ+h\\\B|Z6N!*~U. B*GK(v0*A?RE# #H^A<gϤDCgDߥ{B@y\ZZ,]]]###CCCO>Bݻw^c3LhB@ch#Hc畄.Z&!vvvvɀeCLV`?f -w:罨(es244l6 -B"rW*s=D#x@Pt`v/e +%8kTjhhg<_inTU"T՘[cccl n7zj V q!N}6vA6͞")~?JrH <DvKռBh$FRGTj2(J$TJ JX,F:r<^ӁUU~R4ScB|?fTVQfTLGGG\.ϗH$=O<$'`0p[,P J$M@ NdLAQT '% 8H$WtngEA ΐTM MEeei&MVd23 *BqP̰N1;񜟟ommY,+=<7 ,bUK`χKv*3Cy X"AӉ[p(J* vTz-iHŠa}ދý7˥iT^  _===UTn/>O. =/ jJ9ȸ@M> dC_FNLLjeY1%)@T́T8eꍊSHDzGhhd2XjqW:Ν;lPC:<<<22B '''xF&xgR*po>C 5Luh{{{:ZDƿ ZI"f#P63bÿVF"V\&OVK*J?#65x<biiiffT*mllDb6_zmt||̆RX:'NaBk;&KT^E)p80P0t:v;|>yplnD*vPS pUCAiF 0Ν;hthh"ki B*;(& p$O~ttD?Fh4khL$QFp4 Rtww& ;Xſދ}nnlr22a"VVV^o8wfm~(J"EDIfc{$&(AڃgzZ@@i3/S p7L>Xȗ}_U,pB B`Z.//CG1o߾e$B'ɄaA&K&܋)b7&l6F/// x6^sss&،JoK損 `?@HUA@?'d,13Ez{H=p l!vf*AZ3dx~~\[[ h0(kd}d :!n&c@YtF`27dP<77733 (n;???;;;(zNjra%E:=xHAnoo/..~d2x]PAGY`l63`i(K #De7*J!|ŀ" '''@@,lnn' <>8Q)½J(L}|_DSn<.&[A ǼT*(| BT*0Cht\fkkf- B!4-НD`0CVnXIK81W I͍ϝJ#Ī1W$ʂo +ŢP(nK^tbmUd}EPv{$OXgK*%e㇁jZ tBA{1 o?|nB!t333|!L*>sf͆~ &BG^ABrm$q\Pd0DٱX,^+ U.333+++D[[[8q{6=V0ɲ9K ܥ4L hP#u:u%$E& S*:jZSA>HjY@P¢-!K P0D!Hv`4)F"PT\ Kufy4A~xVy%j5V *I}>(BΘArB-&#+Bozz$NcNea^!3 @@|d/(%DLFRf`fz-u:ZN$L&8@ pssS*ؔy{{8 @ Ӿr 0??Nt:Vk{{X,...`sa|&AMja1^&ڢddBHo.h;QXRWTcjHh|}}G} D$a$a.BӌʦeqpL&QL&Ӄ(2`0lCPAT* HKKKшEEl#%3įRT@SOk t!C`v؛7O!=?? *k0l`pF\jJ>33E : J$JrҒX,pAX^^Fń> G4%DE3 dq4+xpĘאB7/ ON\cjc2'.˗qjͱp4d2mllz|b8"('aǼwaa!pid2)AlF. g@/vh4qݝFa4&W`0[^^2s8fbzdFXsssj31b晝ŧtˬs^BABQV%-TdzzzlǔLJ10V]XX>d8j\.D+~ɮٌy)}\N> ᕩrp7M[bq8&e???Oѐh7Y)uYKRMRh4'''766A,ZcjY.ÍȎ<6MfIԞg6`0`I#y R |SƐ d%+m3X,W bhR(dp♃9<-PGm@,~v'az5vlrr2c:4L| (J8"e2{|[0!7;@J8j:11qww xnP8]y!!o0ބ5FmL}ry/\.鮮0od(s!pPA,b:D͛vi7odYG6;8ıai Kq_)$ F=a udmm 802 . UXvA핕d2իP()k|xx"BAjrrjv&fs<gpJxh4FnCZ& ^,dd2Mx|8kZL*˗cN[>=ZL&( :k=ɤRiZE,eO6_qi9̌ldF&UƔn:!O;={r@f yB.{^Tp8Q`qjkZ LLLag21ں2teo{=MATxZz*3 &T )rVe@ Ӎ &vǤ//..^/~tj\._ZZ + !8ooowvvFcZ}+z=x<.!ʒ%:M&8=42#LGcv"I| CS*≰2bIL\&uv1g溻% a_H&Fz=OەfY/ˡPӧ8pbf1T5M(";7&u]d7\Iznnt:vf2VӍW":v{iidRĿvP^Txd2fsyyyaa*RJVZgJ>zr%lR&@dd,9$*^b-nLAR _[P"MR*j5Fc<39J:pVP9lX,p%.HPFQJ=882 BZd7V$'l#¾iAh+LxT*:<+J@&4 U Iv lWnh4;;;F|8&L&;R& ?-Cu||3D4 [ '''|&bzJeffl$bt$0`dGP()0*d  hJMTO*ȭj " EV^ KdqqWݟ4aQTn4RNN;onnx0 7/^XVvqA?99@Y޾}U(x6@0GGP4LD%&v;MA| }!@dT*b0J%.m~ ,C#WruuKWEˉ(JtׅD". .B 2DA)>V6qJ_3dC%V0<N'i7$B'E8ifffI⟃r.H~LFc 299)PT|>VZnj xK$L-'21oBxu.[\\hݦɽ DzwwJkM&,\VA1#t:f[!H APuX,Rb'bwvv`ݦ{} <Seh4~}"XYY&/h6N3 PPz9[r9[@ErPXãe27N") @#z~b^C,z^W9&^rBA*fYhsb nnnA+~)0!&!vr905˄rrrmm K0qǏ]lmm'ł ~+ I:vM@@ߟgUΥuq///+\./,,pZ:~8_=AiZ~?ƃ% buu<_|T*l>jDG a/---,, uls۬ 8W>QwHbl|F B(J &i2`rc4 Y룣#qR\wZbx]XX%%ٶ;YOx<l6,H&^ @фzjIVcz_Ꮇ6+աH$2&t'''\rMLL;<n\rANxSIjViZ-?ugd &R+H-VP|X, nȷV7o.c 6NCˁNw =:A `&To'Iul6aBAx^)d"0)ۋ f Cٔ|5 "^P(pB兌F \.YP(/F3Lx~~~yy fgr<;(@|ZvuuE FǧiͦRR4v;MAe `bgBHJ3ggn\ IDAT FaVyzzƏBpttQ83336ڠ) MP@f{[,].8d4M&D.bJ-JQ)JhDVprSÛhDdLJb! c5 Y1@mĶ}~0pr M0ENX,x矡4FjŶՕh;t}}_LMM~rqJ.`0r^ty>ϼÇ Y,\tH:$ ngEЁ&ǀ}ii%6sssK^//>B޾};55 ={F+_B!ulaA ;hY-xQ///Cď yk.ŠƆD@8ƾ%EcT4@A~6 uZz.#s{{H R\0Y0PV3l z=xx8X;CI0ve'z{8rV1z: 7'|P0 f3%Bh6Zlx"LyJ˥n ,aj)P31kkkDbLNNL&Lx; b(d2 RZ4vpnr6!3*z,JJDzxlz~~~>33#Jonn`Jp8Lu |rr(JXiG:ZlMOO#sAh4<C$2 x[J󹹹kJHR^^% HGӁGg5vRLF<{}8,F#d1 XNL&3V>q`5PVt{ID"HPQT*f`j"8sfr* يjTx"f84y&z=^CY$AT42Pҙ xQYj|vvR##vthuqA]^^p`PuyyYT0AO.6(|1VfI|<8qt:](a>:h6CpHt*X(`RBFNvlnnnyy/|4Œ&n~MDQNVTP(BZMӽ^$@1 'Tz{{lŠC *M g,'dn)ǓkZxzЕ@8pp#t@d\.W @*)WQ~`-; .//}v2NzDVvu2iGCZ. }%.D}GiqqB{^ p@|Z.Jb LOO3v\Mea#ߏp8p S`RC;;F;>*5W4sRi6J+"%<#'vlf .JB>K z_Zi90pZ0;w !.(C8EɼDFIzDR6,z~eeȣ OM]ViVW*"9bpX#(3 K(Ո'!NrjhJ~2DgfffNOOi`@azz-Xx}}h4R)Λ7o sTR(t4 ZV!²nkk "Ç?#z֭-^bv(`̽m6173-*H4}jj VZ@<|obF3l FZp^}uun K E|t|jhn7K>|HC'cPBR$bZnPP(Gaq:55::A!Fvf&ux0d9c"X(*,"-l!`?f"|-9.qDزu*XLZ* vNLLB! [Lc< r\HPk<O0 tƖH$|4LxNT*W ?2"[AP$4$O$v cT*L5!r̝ǓC9Ȕeؓ"H8ImZ՚fbH!K8:,lmŤ1Ny6 q9k\XX@™q,T$?ojjjdT|YN>`02^]]n 0*j, iXՄl 2$Vi` |XCDt3vCJ2 O(e~~~^  -p,#|d|r9,r۷R)Eݗ_~F_Έ}cq{{{6a {5yhAI0VE_! v51`Bhd\8H$p@"V*W^Ah5x<7M$/btwA(%H$)S^__# ]nGzJB.^;JJ!wcWTʨxZVz|`\\\r9әL&nWի+t-r@/h4'''' ~iz.Az=n d!:G;;g={ݱ?HPOOOJR"AD5f#A!,cCwdz霞f{%_k/^?Bgggf](ͦ7oXVeGIϜ`srZ1]|24',o˂IR %-vo.rضmQ  dod2׋p<j{{3%&Otm38há&OGUj5r\`0ZS5 Zd:*Jx:Kd\y`2Nnj9'˽~x?* 4Z-+;P>X09@+U*A6;1$܁T+㝜z7o (.--XSTV5H`DǜYpΕeQ|&r7]X,H a~G  1Nmt޹9\v:RćX,NLL,,,`ʆL6G?8>8;/%IVǧ ;lK Ԉ|nN9J Ǘe@d~v'aiZ a)BV!qѧT*4 =h0fG*f< R| r<X~0d\Hp%ƖN/]"4dWslNnP(00 i(~⑇)Tx̹,1"CQw @R `0e# 8Lr[HI膭`Cӭ 7.xj*86bP(FĿcL&Bah4doY[[U:&:48%p&ICo!Mj8Tz"J{ dXQɦv:6%[ő"qX,X,awoo2 _c0Uly(t:JRuJD"A1n!9*aliG BV+ZGfO&Zx2ht*$C"X,油$ɕ/..!,{  b }6Nfgg!lllvHB1#MD8v!; " LmF#ΨKAӛ9ب!: #ZZłQ`~~Vlc7=uBPD"h#lqgj422ۍF+^.cXV*PA,؅ qHGA ~}$)^p}rpQ].;Z~ZE:633 ڎ{vUw6&L>LC@\.'k9H!^pƍ;n(~.9n|\ap߀z.ѣGټ^T*V5 (q:>dBE9??Ւɭha;L Dz777Mdb61H`0HTd^L02fԝ' -~zzixx~! *D"M!%HV+ݝ$̟U*xB—EEOUd#1 ,|)fMi=Af q;B^@ f2p8t:墍D":j4hH$" =Cebjh4xr9C3lˣш÷Zv.K`tfD)xWWW)@(#bXҪ ᆠ%draYPbq7phuBT(<^ JԢjd0h'Q2 IEQ 1dG$6A3 )`SmN<p8,9ٍdtXtiQ?_n6xSP$1}@k/H4<$ p"td۵X,"B+D' ķtd2H<;;D^\\0 e-3Jfp8pg_~ٔWggg 3x ovNRPSc^pO8Ā1=5VX2A L okx4 1J%;X~vv6=B/_LD L;H0V8~KP,!2Z,h~z~zzd@`Z=vw-pZW.1n#ӃVwwwR{BJ_ IDAT|}&X8_R1d2J~?iNᐌ.6*&4K$M"’UȻkJE"XLx8mp3">99aΏĤP(40Drؖ};D܆a<&zQoJ7|3770 EñN}BЬX0}:tmfuVsL/N'f#LПǞa ;>ZLXD"p`c%y34-f~l6 (J}xln{aa+N@ P(...&''~M".--={LR1l^;|X喗^n7F\J E"s:=lv@lq{<\k>;;:/~gHz9M7d0DZfyoo=xnS93Z*.,, zD,c0yx8qAzWVVD"у'~pjTDD"1͆7=SR\SrNNNt:R)~UsdH뉍Ώ nO4D"qO؇D"Y\\$oŕƇNkZ֖j0DdZԱ"PEnL6[333ȀQT3Hl8L08qD}?~}(;N F-// @1KhZp8;;X,H$@lry^J8+DoM[h#}FCdD24)vbb~/,A`&QIh,c8FC64S, z] %I\ |[HD[ HQF6H$g777i<jԐ:L F̷jU:jv\͐Ap8| w o\N eA[VYjlsRq\&JX,. M?==eՕ dJ&a=!fL^~nTfqy777r'_\n2NNNJ%Ǐz,7|_8>ya7Lp3R¹I,.l; S^b5 Py/ۑbB^LY*2툐NS& é)/t:M4)ˍFɂ 0}i('T*pI1]g™FQl{{{2lcc,\s{{+n7mw7pzAlfAn=-Û$J*'F̣JR4M&۷GGGԞ;;;yGI'}>/\.A*h4Z,5bxrrfR95;pn^ I!bG9tVġǀҒZud$KTߩT <<<@4E.:+,,ng)[(aX_ o~h4ʄ=<|`آV&///1Qar^YL&}R6=JWX\{U8g*P36j5 4jjj / j,b!P-lj,c! 0dM,%p'7|211H;D-*(0L5 4v;q@H@qL&!#RrpL *A \652Jт 4MG 5c=BW!k2Vi&!OFͦٳH$777JF>J p^L)uܕE"T "4:HD8nAl0 i0~S`AtbqmmѣGO>@]ل[ϙ>QRŇa8;; H$Bcfff}}ロ3u:Zx< 2J$X__j٘4NgkkP(QT B 53%<nQKD^^^lJ\B՚c\.df}`0o_վ kkkaYr ls{{ Z]lVnR3;ŀƘJ2ɤR)4~<G-%:j1t[+l㧧SSSwCG)d2999~R.?3p`7 ,.N^#j)?Mxl6SZ3޺nX̋)h Mˌgd/$vbWߜF> D"bC!TV{||< 0SaHu`|DB,Ì5QpZFl:;;裏{/B$h4? bX<{?N@8HFEF)TcP #8\ TFԞj0f3pD *jIZ+Hvp}څH$vidc`bv$I6u8\.3@x<|pC4CIz ϟ?g2|8/^ W/D"Zv"PT૯©\*^/18$P(T*g^TA$fw ST.N| T*™~aao94ׯ_B-JX* >'Bqtw{{4ϻ\.ۏ+ Pr@jx0qSR3">%6yH$p8Taďy"#jϙfY<333 B!ɀ7fxr^}pR! H$NNNnnnK`0kkk{{{о޾}N {s_׻??? (R)R9sVCcY*bPz⏏z=?R_jnh O>͛7r|yyAu1 dp8 D$3/9 08h4/r 0N Hqq+W^zF9\bիW;RioobR1&#BHg777^e28 oVK!}yyr߾}KkN]eLPXxww޽cmQ>Dn?OE"ѫWJR$HѣGv,R G6E3$Ttq+3+T*u\9dR|t? wh!z.T*E~ooY9 eZɫW<ht\ >|h0~Dx<ollq\2Vw]rl6l%̖\.Vt@l{ JB`٘D"˅4O;55uuu bj=88pl"`QT*h4&/(Lvla__vs H$駟kx<{ΎRhIp8؆zeeezzyr lfz07!Ә0Ȓz#~ Za~1ŀ)ꢪ$eEI2RH9%"FgLUo5]; 0x6ccl0w;ѣ:N-`n~>Wkk+Z0F#FPvz$K0aH&LWWWfF"5\.2,W'''Acv2n[Eǃihh^V Q*˗q(XbPDxg}6HT@ aDhV݌@LLz~ttBtݭ-PAQg߉)|CCa~\HFn[V&!FGG///^/]3B0noosMLL=fZx.//?\.wƍ~zX d0d2i4?: +AKˡeY{{{0gE@\.u}ZP0q*F\{{{Ȉ>R? 1N,qR:CGt>|'TwqqA.fD"J]TAgggbY0950o VO>l׬ wwwQsG{ F*VsZtV*9KKKZ Xl2H&%|RT:N,1'h4 iT~"֢(NkTad{{ O2bS|R0jlVV N*3" ]" :tD{{{P3CLj#U...P7!O~eN^fOO$0.EZp̬BYAHC.TT<4/_X,bfgg٫e֒X_@,Dw>nj2spBJ;nllJu,>oggh$ׁ~|>=}XU+++{{{fY,Q6ˆ&2d2I`T*ч7h4.EzI4{d I!1Ad>g7JRh4;;;h .$r9Ϸ/yR)=~~06/^FX__ϙY}0[vvvp0 ogg 0Lr's#Px]PjllD9EQ6x7<==d}}=RD[ dn$ R 2≵X,뷶hxSߜ>{1F-(0(hnnڂzOYZN$1 㸻&$&Rd2Rb1p4sB,l3$lkk4ˡ}IMz7n F811~ͿC]ݭP(Vkgg'.N1==Mb|%7tk ykkkt::k ܽ=\ XOi2NNNJ%YRJVVV5_{{{ VNV$kn y&NNN"ǞƆ]d̈́Ν;h1쀍H9 |(r 44W:Ngv;.Q}}}TݙfC+H(:8EH@GG `n0uiootwAvMt: R7j"(8Ρ!FC@ !}uuVZB^o."~m4^GFF۷o JfztHZolج:::@)g tpnCCC 9O .//~Lр1#8G"?P(INR|f;990Ap5!BP! !LQCdF|(2^YY,RIK.ppzzIh D Jx``;w4X,x<.իW\9idhEW& >#b}}dZi!J`s]r;::ܼy7@<99xظYv韟k4V+c4kY'%kbb7b = eف]\\|wQ7nN@.u4w!ۡDJӥR)qI~?fwTh`Ќ$Y(+m č4bx~~m K0b01^iTOס""RR)kkk MBRđgyTGGN.鹺ByCĮl6R!Lr2 XbxyyY*n6 8=0L2 /}&3Q[777s;mmm N 0EZ2=`:N~z<0@ @nލ7ZZZ=cO???n,xqBkikk[\\D׸RFGGiPqBk9FLRX, s4LL~JЋ)y#.hdd!4H$| 3!<5n^O_JŕB O>%;8Hdspp`0xtt !K ,sn(\WTf!c":4ܪU*"Z ˉc)f>ÀESCC%dP^x^AeG*B>'k"N#)Y]]JJQ8N$d3à0$C:ơp8 $X,9j,Ѭx<u @܆ӀI1>(\`"l6믮;;P}iPX^^177DFFF\.~3&~iVC(ĸyuuuiiZr>|kX!466Yd*$R s׳{vvG\ ^p3]ko2 н=蝉gB3vrr2==566&&''F~ʱB!n7ߏr:f?o4FFxa=W04= IDATR A@ ӆYe>YD_LVpݨ'''#޻woh4žCܬT*G=;;Cpp ?yAÜȱsxxskk 888sD #Z,TGFF~?36wlZVhJBx7odq5$B"?zlݻJƍMMM~n&쾱/^\\ PG Y.rMF"0M@)\.Ve' \$^l:BNX3g=l& ў Fjr4\Z{yGvfٙfI\_x@ܬ].ן韂DggOjZ@''x:;; 8v\ꂂo2VAEvTKJ"cdd$Lvuuuwwb1x8}^"zS-JA@`*ekKn---0 0E#Lۿ[vv,Nsuufjc`H.òtrrBڪ!2۱X 9JBhX E&a-߯R,$6CX;;;]vwwnE(D{,ld2Z@ h>H~޽{knK_%L&x668z{{766HZj8<lKo=H$Fo߾-766Vk}}fff}ݣKH7ل|r>}zɫWm6(ֱ@D T<$dH$"l 8(H~+4򝝝kkkíV`M/}4Hݠ ! 2&g.0F-dư qri pJ 3ٸDQFlCb.[ZZjooME+t:ЀP'HsBI̜Ӝh lD)`U) }uX)>|(Ku'd6J>B2'|"HsD BQTZ Hww7 xE"pR#RVAJT2yXgjey{XbpƉ?e Sf777'&&Q蘟d2'''w9>>bkkkdraafV{ BajjleeEdߏu2RcFٳr[o젽%wGOKK w__f kmm@xD$qmh4vww cp>|UP+ԔdԮk󣣣 A&/_np2FcOOO.aSSSoosvW™'? ނ)Ϸv4rh41mgg'z|>߿t6D06660m!E";wAeS1}$!,uttX,P62 lbD FTT>p 'O~V t%':Lkhhx^]]Bb^Ǐ`466bVDV3Lnll i.N_^^.--!^ZZj;;;PSsqqJOp8t:pGG:V:V(tPS&9::b5 lnnf`p1ϓ'O,&>L$CCC0RdbysUX @H$йEhtvvd2b;WĈ ryvv =E2rHAp@ <ekhhǝ fTKբu݂  |FFFW_}?`rr6P(|>BA+J&ٯP([ qKnaQ*uttu9::B)8<<k%ˑ `wY$J-JL<k!6?\fd>G?Vg UWWx;lr۷ X,|~```0tvvrV+c>rY){zz:11QVNl<𜻺Ȼ@sB?$ (Eo]X;ǣP(P>G".^gr/e2B8<<\\\x>β2'''s\QL9N< -K__K/JƓ{f{`OOOjvT^{{{FGG}EYw]jZ,)ZRa!IT޻woiiV}}=}NdgIbǜ K9ЛM0ۛnjj|0WVVbabvFPn (xJ>^! ߏ^544 bEJ^jhhh0,0 o/mmmHl6{^r_ELr ^M&Z9W,Yj5O~04RD1)j5||<L/s[KD6Li gܤRBj%@Rƃ$ M&>Ѝ#P(DQJRVVVB! Ҩ4` h4DBdUXxA'''|Kuv$kQNװ`ollL$. o%SCCNK$`D"YYYY]]jShLi @ rhZo 2^z _MABl@NeAB‚L&"ZfI@RŃ1R=\.?`i<99AL&r9mr}}}02XАJ;j._| s\XX裏 AGGGGGGdj:\.zwvv@G~F00%oN 7H .NNN֠c988x7%[5ht;ggg7o ۉb\r'''4 LoܹC\.G xtthY :22= zU$uuuo?t:r F`o~S*\."| AE#ӹgz=F /a,pGAؔs^\>>~C>M`j'z v,׾V\#뵨AHOO>FY(`" 5LLpuL8f̀8BAE+ |7555882D!惋,J+JwwDTm_YYaIMkkkCCΓ9)V9 A$@ J0& L&STl!Dr566t:Lx E*x<Nn"NƍܿJ^6 [ I=kkkקN'(\Lo޼i ᠣ7d%]V׳TVlyK///-0}7U666#.\7g 2ݍF,u"}RrR) q``$TX,L|GO>y^D"z~xx8[,2[ ;w9Fj5Hd2u'<ǽ)3 qۨ|>ϐ d2񗴵1khhhoogFT*H$1Ţjt%IX`F#v;;44D كt:7Оtn㐂&hjj"K!t~V8-`&c6fr8d08>>FX\\\0;88vViZ hzLǡ?=Qy$"$D9bEۈ|`KKˋ/8>={677=z l0D5P, JRd׫Uv_z-ft:T*3@PTA8??G A7kvvvз0~0A@n?kJ{{;y;xp.//D" rƲ$MFpnP믑x@L5tkV[,_xzee s0k4QO?b` j:666J$`kX,R|kkZzvvمT*lPTd2$xRDQPEVpt:]:fj_V庖{ v.,;;Cׁjsppӳ= i'Aa& zP(ܫl6=|e xRU`|nܸQXNPMOO)Tz~? L3 >@ (ALZڼ^/^,Z!cۋ:XDfyvvf0t:;wyRݹs> G*jqqqrrR՚f蕥R)H\Crnܸt:~NZ&,//J/ g^*ɠA2GŋL&v9qnood2\{ A0h4!lss3nԱ}4ɂ4;H0k׋|`cc@xw B&Xooo iZB1448CujH}>Zۆ<>Јbɓ¼Dģ` ]af9 B,x^WD"p8 C`cclQ* .U Ze2J%۾H$o!k * jjzll UwwwCCVSS@ZuDA\n4Yg2 ---|HƸ  M&K] O~d2T*M&j 0aϨH$XNp^wZN&uuu\ihL$P04447J$ tmP[f9Y(Գ"$i6'&&֠KS!R 8??'`|||qq{!D 8$ 1RCOF,c՛>9gT%|vww 555uwwL&HиǤ uww uR. C*O$&)b1Xl0h`Zm4EDͣܤg&!pGP% u@S\cTj5^t:]0 @桡@ ZYт@:<XD⶯O,|ccc]]]hK`JR,~$ LU8٬ f^__Ɖd A{!nB,S"Lvdt:YHXV%[_S(bp80D.N4TOdR)bt:/..fggJV^ vVVV8Oib%ihd!"P OiLGGGb5 ^"_~B qH誦סnQ|d̰n´e ~B377V9z' \˔8D"q/_ kԚki\.Dn7C a@& BP^A&]gg'J.E VaoDi"0,B8\@M*]đxAbC[*"A>C0\>>ES(3bbd2H&>싇 IDATj #4LGGGlXWTw*ȡd PH\$bX ̱0,Z[[3 B $WWWdr&tkPO~[1ˆ~vX,oRo߾{^BQWWG@WKK[o֭[KD1=եjnwoo/ըhDd&!= nkȂ `ƣ /rmnn㐄[i*dظ"Zmmm.[J5007=pzzxaC)@E)A&jՕT*P󥹹wkk+T‘;;;(EdD\6LNؗj59|A X,HRf9Hd2ZV.߿_WW'?rLŅ\.#A֢8Rttt(QF1Ht7i]$ (JPwww3F7N3mjjg-@ҼbFx:.ƞ APTBm,bhhkhhl6wuu={ӧ$Jq@cTT+ -WWWCVmv.X,F799l ur9WNoo/{vMMM( y~~.GGGvj\̅l6eV_|G >11AGYX$=yssSkkkܜ+. ;ILx,[2V8-1=`qFb1?A1"B8&yeee)3@ݻN&''遜N[\*yxe2Y?<i򄜞~7RtkkkiiII@B_ a ܹ 9a3~ E,K&tp.jx|´X2<99(E"t5$`p8i[FdTaνBc* D[n={L. OZvkkj|cڊt:* > gKm ATRb"nggGκ)k`o7 J/#l Bgf!^YYY!4< IDr  v/0 8_G Rgʸ,qKR6sssmmmMU[[[:fj/4JxtTI}}}I`Ap8ӧnd2ųwyEvyqq(^L677/,,d2x^@`sssccHL&ctM096K̎GV߻wpr9ۍWzK%D8LJⷷr:NOOBd2&ƞl(ˤs$ c'''2m{^E>99!TX-\.rp(n߾FFF...Fyp+<׿۠q? 0&cԣT*k xۑH$ 翮ܢq:u5 $[F#hd'@ZuT*qd/^`ٳg% >'GGG="D1H==!!?y( %.HY` I~u)zB"\WWN`7S:??T*BBPV{ŗ|Ml2ڬdcćE@A~_}!* ()?˗/dP`-l6q T*~ I]]]4%"+J$ET*zp n<333 4еnooJ4+ ߹R'#:88ejcc#Jt:tV \\\F\.;Emogyy%,L&O!Lh+J6͝L*VmfRpjwvvV*JR;@&x~2 dr|!uchjd2DquuU"gϞ} Zܠ&mĚETr928E2z?4+666(ddYWۭʐN!O\F *ǝN_~ [ۈj ԔJ522ؘ޽;==ŋH$$=bK;r:9fZ'HW>Y(.+tvv2ZD:ps)/21X 򖖖uf jsد"G(zH u LVS P\:9J]]dсj\^^B4bpc +Q SMχ1 "bQollh4D@$LAg h"aF뵨ӟB7j5=):nzL> \zx~$z-#l, R\ 9A<7 [>>ZvddǔY/z *ġ:55490(4kY2 Ass $ @`X\ՎVZ*?X,\.P*F8NR9 /jzAyf 0==oERyBYNNN#j,2?P=jxrngk\\Pb1G1^GȪoE&D\]k_}U>'.N&-..*JZA c8<HP2߳X,<X?cff&N///bglnn.//h4+e2ǏZXXT* Yzn\9RDtzz:>>nZwwwǵJvUV֞O?{=PkqߺuP(0lM$E,y0b O4L,*J QLjc\DWVVx@J Њ^{&| RT4=99q '''Do|ppHv`0SY_-Q RJ]HCR911!3AR]$*JmHhR {{{`988@SCsrrc'b1A":%$|LF;ZZZh4**NSM>??"]Y3~kkT40͐dC+ ̙LV@e]F%,YV`Orywww0t8n%H҄agHf2fR>}Ͳ&A$MfH${{{Z]4;FۀO㏡2jkk r0%I$A@Ffgg[[[j#nŋϞ=;$X.7QIrX,N$p;Z- e2 X,7...DZȡrl# ^Ucc#c+++tСPh4jڹZJNS*ѣ"hll#9yZrBBӸ !ZзѨj%4@jD"5X,bRؠR/Fd4掎W6 "k{{;1{LC`\ xI>7o dX,Ɣyyyii 8%A k4uuuƍ̤馦&*qzY"},(nw\Phuypu"8lTϞ=STZi}<C}͆vSSS]]]Jabb0ݖ>̺̄c#v744 C_ [WW'C 88R.)'j<wHbS*pM BWP3T*x9anXSL:"A*J$7F1ݹsd2QͰeH$ m3L.KѰi;??Ac0FGGA_|Mh,,}R[.s3Fl$%ۂ 9@d2ٗ_~^oo(j5IZjrT*a׷=== FPLOOcq# ba4"R)|###Z>uG8S{ݻw8r.b,K\V...Vk]]gg"di4PbCρD^OfFȲjă9\.;Ʊ1v}||T*1CNu톽p8$vN'G`$vS3䤷C[[⳾>V;,J)l6Q2͛Ft=??7Lmmmbqqq1Hq%ա믿1Dq ;99IRb  qs6kbbcr&''9mf3FiooGt:[ZZJljj"WEQLPccRwR)4p(4(`lٸڑ J%T􅌿jddݍ;iddh4,C*sv<<Ϟ=Ϡ$ErynnB#ܑ}^M5̽k!pߌYFGGb1-ޱd2vzuThZIŪ@@ݣP('|}CCCgggϞ=FH$(ILi8h9 0b@ @!㙙$. `|"HP@JHc&I&H766!/RbeDC啑Q&9899A666DQsmzO0# RM)3;nrZ~ppt:A`bȿruu7߰L@ _򚙙A sݾ 4CVF0HP(v=Ie@r*=PG& DB*U >~dTH6P VUL$HE[[[1$IrTސVVqNOO߼yyss3IYP?~X,DѵG ;Ns]d4J~ߑŘV11rC2LF"#z-{{{TKh9Fa=J)NNN@"q8[- `]=ǾV%­-o߾MFrӭ[P)F A{7Ldmm @N fffȯ'{t~~Ώi>Ӏ od`b;;;#{j@ p޽k3gT[L &x/4>&) ^\\H$j|@\FD%N߽{y,QTKj`fJk,p N^B=#9O& U`9ZZZ@ؔL&2Ah>Kvů^2L\G)Jye*ם"lZɅŃFcA H#[ N..rwjXn0>A+n; PDbŐ3!l LFjQeZtuuX› cDN /RT" dn\$4qʈ&<LD"A 9/fxYzAghi4\AdaPWW\hV\*R4 B?<<ęYI$,QJ o PF`.cjDz}xxɉd"ivvv##:Bǘa0.//A[tU— IDAT:=GZT?qjhhhnnArrm6Nô'ؘ`288L& gӣV{zzx޽{=A@œg+s,(Jfvb1;N$L)`N'HD] 0!kZf2,Xt*fcqm`|of2S(D"qqVx<`To߾8QT*OJ͛7b[|"\!P( `t`B2x@ƫ+Zf|pLFcTl6Ó7>r>?sq*|~e,jU744z;u[J7\.l׻IWdžO\2t MTr v %9Mt34_ȯ)x5U\C~[o3crr;Xϟ3?|~rܓ'OH“+++|3RSL&L&Fv;;[YYNQ A b7j<B1K@U]]գi۱>^,oeE"m>n;ow\sUŌ@Hg]\NJ~EXt}3L&yb 9D"azsΝ#V2P"FG X v i~T~*KH /;b9Lh4k"JVÇ?t8JÇ(~͛7F^~CW^x"JFnV lddZCz~ssK6幊O vONN&#&0HΘEQ}VxřL11aFB,RLD'd2 hdu H I$///1@`bLRV~ax|>Ds}}G#+qoobi ȡPr-BIvN8e8ׯ_b2T`Bϟ}FDZfɧӿo@!X@Il6DSj5FgggH?a@|P E(N_]]E"A9b0B`@!~`0q'O0&_S,^WT{2{ks8==m2(6U*w\cccsssĖrt: 6u]d-^RpNhkhhn7  }> }+J?ȯ^N$Lvvv8LF霘`yl6CB)###$idfc722RT$W6EؚL&QR^__vGdWϏ].W_}ǃ`Tyj]YY#uttj2@dZvmmCy`ADg0^[[cr0* (ͦFBɢ>r f (GHP@v: /u+ q C2A.sssˬ+GFFH _XXzN"EKJvvv^z<D)f4 cccfyrrrddݻ|0a`d2( GeŲ^/R|:iZ-a܋d=.*C f RTPJ8-^#m0=m6{{w}wrrh4Th41][[#<jav`F Q yD Ͷ( h>99J%{{{;== +Ib(BuK<hI@K$guu& #VO?}c711q}}=<~7$NW&88I7i.;::Šl6^Ox|}}=a$N&ϟ?';t82~@ENjnQO>$;pc<0 xA%* Ɖ D<6^W\__CFZj%,\NדG_Vv:I&*jZewttkRtHTB!~?Q7o틆<Z-v `J&Jq|}co8;:V'JooopGBųgτf^wvvF>.v^F1%j|{{e&'' ӱX, PHfRǁBn$߁(bu;t:9p8f3B`0ټY,T6WOTn[H$ I A?I@~:vV֕Jp8̾RݻwZիW"X/bW+n!\.W*!D{_g_}{0D|%obggqz(Btup8l0@vNaO*ź ZTyzD|>Xb~~H>'evvV1;; -}vvܒ;Tj4ӟ !* :B299#4j<iqRe@؛L&Q"B$ʚHHܥ~{{{rr, mN`yJ&''SJ%WpFYSX(Z-x<`0EfvG"vZXX/fbaPCWA"24y5Y YT*%1?TZdja0$[+x>jZ245ZiZ94&Fy,|.@Xp#ĩϲl6ѹs޿؏RD\.A H$ O@GJv9N˃a(NZ,XĶ•fqR*&sFb3 ;~_q~~yzooNt Ge2d2abc}}}}}AU>zi>Rݻ[__w:U2F9yaYb7N3J,BL&4[bIE&l6ˣbZ?;ΧOF"p84׿5pǧO2G.J?Жb<;;B˗nwuu4}"P(h4tnnn>ZV(IBFp,,, 72>6Vkrr^ )`0%b`#r L&;Dt:<<0h4[ϓ\ζ!E"VIn󷷷2_r{SoX((1 vNo<7ͯ_v\hFр񹹹]"f^|T*̞F>O<Ё\V2зjׯ_\DCU.1{h:\Ő'a,dz!Du:SVndO M&(Qp@0h&&&Ⱥ|[[[r[,m!X*"@]@{{{ccc-Z֛7oJ%*ZX,Fc8ppp'fxٺ9Tԁ ,pZRi&ޗNaI–VF wvv7spyr~²R,//#,ccc4Y03_\\zw3dTBj&b6<HGg4T*ErNKG:!Jт*F { \9 Rq8@ b}}f%IXo߾U*KKKt?7o޾} 9S Ғ4tϷFքZ-.--5  w\.u:v&[PGA)bzrJK!*TneZ+(Qfd2qV\.fpZ-χhqq&\;οۿ}Z~Ǐ i{Yt#g69Rtxx]xjv'x"`0www1]]] !8ժfC >=22% Z<yH !nooc"z駟B'=lJh2<Ϸ~v0qD2==}xxxzzBRݹs'G_򗣣 4~_$ȆƳg0{`?t:`0 zqx2rVco||g15.@8J>>j666<2L 0?/JE#)v_&{Z-jK>>nT*=::bj~g]@&z_5|V5 ;>ٻwwvk^^K$uC>tsss

FpNߞ{ UyrrR&MMM!nKKKt/s^^^f0 ,..>|S n\.NצP(LNNnR5d2M!}\.AۙnLX !&''13cYbhNa*m0NOB7py߿w^>?>> \V6>>Ψ (X,_?H(`0x^LLm6b(8X\d达v8F fY+ !Kb&C".lAv6f7J`00E<R (e2Ǐwvvl65ʌnmm% ň(J777SSSf3)d2[PG3NT*Aj(+Q .R0xt:?AXh8N>[d2MR777Hl6돏cdn7Fy @x-l8sǏ1|& X,vwvv`nj'O3 ZIDNIyK%n^7:: n6{tt:^/..RG~,9,E"i4O}qqDvQ6LxS2`aZoү"sx<^TUJG3فT^(^x7 &@I0L0srR~f RaP(bRkZUw߹sZ>xj-..~(aQ~Ir0L&I8///}·zښD"o~3??2_U&!˂1?"/-l6fGFh2$˥V!4BN+2pvN^eIfYTJ%hEܑE ߕJL&#ҦRdvwwjT2(m EI7wq@0Mn >M{D(œ899JT*R4aa1s12$cQ|c ( 1"-d#v݉DbiHH$/VO%`0~6fggyEd  C @ L&kZL&M(jۨ 1MNNRC$'~Jv\.BVT^Wղ+ Fc2~>W_~Z>ÇGGGl;={6>> VzsH& TB xDr?&[h i$hoz[(:7 xbsT9\t:IRd+je!JsU,FpA@7H`ÇBfoMMMxޛ90pva, 2` @:1:E)2(JlN\.s[PnsjбnzFQądb8޽{!M,}2^J<22H+F4fvSkc;;;d!||>JPZF7o0bt="l/zV+_ZZ"'? BRv Nlqisz!N IDAT냨GGGqSV Ŝr|| oF22>vWWW۹!"rl0>sN깹9:52 eNSSS8[^^^YY!EGmZ- FKKN|7fT2(x BHP jb@:~NRBt^;ij|bwrrryyZ M<zpJ2h^]]e[`,..z= $,?> TPgYwssxh\;wHb3n[, 2~z\ZZg.tbb/Fv; Q ׿FRՠ/?!I$pc‚`t:hpuuCB'U,!GZE(!"Wt$;D*r=,* :"; aft:q0Ez= gϠ t:]RBx<Pe1 ̢؞ϝNVv47 y) H$d&vtF#JO>B;nC%Qed2ɘf^SH$Bq|jt8_\.(gh:`_F Rd2visssspp$ٳg`P___3+2 "܊D"hR4Ÿ+ʜ0pF"x'sT*QلR8aFa61(JR X_!JP,0k@$wjJ>T*dEfpN".-NBd2 boonV BH$j(-A2`ssN"Kf 2fP3LRFkrY _x\*?z:RJ/B)H<7otd,nnnPYr8,19gj2C#qD_zXNsqqA t j  "qXvEhKf;H֌d0c;j4QXIa@6ML&Cה厏0"Oׂ[ ˅~;$n;J5ql4ӸTՍ Z ܈)!et:JjXAi&FclSʕJcc`Z?x<#l(2L^w:>,]F+8 ,eNǙGVc裏0=>Rp>?44+\u_~Zdd2/z! ((6 8`߽{A{,C?0btHJZBVk:>==(1NT*49՚H$NNNFFF|>cޙSk4l6;22B%D"1??D nk͆H3nF֍l^, v\BVu~~իWL{yzϟDن'a~޿2c5f[!OT*ccc[[[V/ipʘLmf#Pi4p@z~@A422biinl^wssnp܌0c9l& 0>,;wp1X2 xR֡& N2d ;XyLq p#m \D}T*h[^S[,N?T*=<<%'Y)=_& bBih#Ax|ddD%P(pᓽP"0evjtJNZMˉ &}Lu3"c9t޾}[=z8! fbTb0"y /j4ˡ*tRgv9:: 3Ib\@ pzz䇨ICCCfVaevch~E/)-At@ig*FG?oy{)𝱀bLbu"+ dv{` ”.Vu]>,L\!^R 4۽h4FFFr __d \.w]R~?.ߝNrJe6]\\<77l6a`H,FVx'& S-y!NFBFZёcv&CGkLZ<b(F}@2&`P|gyXT*]]]$G:EVx<^ݻw...X3X5!/F]pY8S@C9h4cd SxǿJg!d4±X˗agU*xD}NQ zOLcEcbn#"=?7:TjAX\ w '!DJ"aAb⏎Pg$r]]]><v3sjXƄRl0B~rGff3>쁣#l &''߽{WVp3Z擓DRf!|};6?<ِ 8 (HFGG+1ɚr)_\\ z5g*:::|ࡋ"Fa///98d1 JB! f,w]*^h Vlrm٢(_<,*jxxnRIXED \ܹ~jz!V'_>;;;??ǎ 1ߥR 1 8NDNʂRdq/w$47p8r9zAB0Lf__Rt}}x\ƫAZ1 Rj#&@1pFGGwvvJ%zP+L51lFRda(p\W؅y,qgícρqԔ'd2q!%IшoffFzzh4!dlllbb)n:RRHOvwޕJv}cc߲ӧfA *_՘A@c<F&l >=)m4BPr7 !J/ҫ|ׯ_#UBj D:88B$iݾ>xaw aХ94 D@|l>yxrdczFQTx YA cfNoX,#iFلmCVsWLXmoo_\\@HӕKf~?Jb(`NÓT`0Ȃ .ʵ H$*mp0D"+h?1%즔cn(8) 255"FQRI z2~@dFQP!Vկhwk6ryP aJ&ponn..."B|\0ZClONNl6rhQ#i^d}PjCjJ%rQ"qZ˗Bnj+T*@ pqqqyy @H$R \D-K("t& Rn<G n)SKn/{}>NټY6$4vvaj5sѼv# 2jjRc2:,Dž?fQFiMv8h4h &-Qܻwlټ_,ݻ ;M0&cccXb1IR* ?̵]V$)ӢI$eN1b|IZ}C]>r4J>Vkff9ԤwegVCП'`l6G9B>.0mz=pWWWNCs2h?/mļQ:f BPPvpSF\]]uݧRRjVK6?H@c|H$o^^^BBu柏l6/--  ~^>W:sbbM)қ7op'I\__g١!D3 [BBJX,FLr\>g;{ %%8et:N?|"T/^\.ǃ :t  -M5 kZ-^uqdP!߿ `ذtz||vff;% f)V`uT*E h4M&S4eEnZVbnj`x 1$BZX_`< yl6q3bsJBV\,"H"j/1ONg @ĸ\ #CO$YJ S A"kFs9w[|%BbGRŚq=?wkk ~D"߀?Պ]fZ-DG m6ӳz&l6nDBh4d1i\0d J ("FJ:8 |(<`ԿT2P9@ u -CXt8xvؠڅȣgMqvF!%{c|LZ6xwIXݵ,SyߝNG*:40^+* "SSS+j51H$D^ɣ px XuEĚh#^n **m:KWo+!_7`X,Z;~x<@y'-:nBL'd2LQRX1i#YxRVFxa&IlaĚ NnP4vvB///_b1%x*^Ǒ,F(s.T3TvV+\ZZT YZeq}}FTl6 zVa7dZV:F\+`ʰx%ψٽJݝT*^sPqb O\PsFz}*bNOOQ%b ppH$LmGB j(!fS(TĔ(O2`cÈ)<J`n,n(h"fo7VŚ=0ZXF03A7WWWL/.. jJ=-rOD@RnhhH&&''t:J%Jq+J ljz \5:H{{{DbvIDAT`"}nZ===Z`:"Jvժ$._"ʹZ-/<iL#Z<[fd2g5"%=7?*:8\jW0)π/..2Rv9Lw,s٩Tjgg'alaHzzzh4$(N'vtt4r9(nSRaz6LPUYJqL$L]^Dh4>z􈥜BCwVzOjXVVV\.w >??V@7Q(D0h4rP!3f]]] >(Hda~&oXxPu2*) Dnx˂]qzzʁypq2>Lƪ .Cl6K­@IFUVsv;mb ]\\\g 5X[[zx^çO#@17B(*\.NcFр!`jz=|j%BnJP vZ! 덏\__cIR,bt:")$x Z-Cul ϫġP(޼y#`DfbYTfffPh'FYXX@RnooI)5 r0]a9==eÞfttX朞A*>Bޜ^kkk O~~O# 8ry:`0pͻhL8#bEt=rn;&#N&ԛL;oooyusޱvp2GfILT.//nSIњ0O&|(l?:4z ): j5 T R666!R_t:F#D2\YY”K\.qHL-}> ^\@P*9К`]ՌF#04s1fʦ "\.j|S2Ч%π>UXXka*%CSFc~~50zO~!74ڦRdX#fT:fNdiX>cvfdjl' !fgg1DJL, tZ5;h>G>ӿ *eP,Ev.@i/qnnf cgz.kee% Iҩ){jz7dm% 2f޽ {bbbjj>>LF#{ [j7 d\fN 9On4媠z-9 %.aaa0+D#cccg Rtğ}XݞC0N\._XXh6^sm;;;f!Z6wAU߀cJt6DCK8$ BJ^wnnkQ,dc2eP{~~~xxCx{{r[">9??d2Rz^ ಧvc+NN l6c1%8rNCt:ͳbbbbee󨳿ANyІ#%zCV3-&ߌJ ,|jubbRJ5??!RVOOOo>veH:"bԊ"`p(̈́N!=B899Q*Zmee#X^}!NC ЧbjZR7hT-0B qfbAcÚQKP0L h;;#~ A2dhX"SJ6c׀Tpi4n; 3]!*RTLWJ D?`b pxx5{bS &zj<;mTIlM%"\]a:!Rtjޛ7o 2|'Z%d2.?J Bd-bׯ_x"lnnbY#"x@7 іJ%ppጎL`x_ι$qg ~i BU,Y°0fR6 ܤ&FZOV0F"&h4t"t:Ol6 Ҡx^RI; )JY zp=Az? ax(~!$'a*JJr{{[AH.4rP& jz l{Y~YC L&mZS>fÈ Ghd;7<<A*oߒpppl;~VݻwR(@Z֩)Ʋ1%CECCC///jJa>@EIC(H(|H5к3c`% xAؚ,Vt:=xa* AZ ! +!vqc UT+++ez=7;%1:6ctR|>GR! c6cdd$ܿ /0t=27=zsp8s3b`&v`@ ދ_*t:P8y(G"lik [pɁeunsJ2}_!wT _dg*.kzz/0f9;;nvnnYh ~O&q飱 a<jrZm^TVGFFqq'Z7B?y+X]]tZb:`˜izz(j5,,,ܻwT*>z#YLgxM(U/` Ds2jR!2hN ,!F#&hdGy7et\sss@X}nk^v& 2 <{ wZՔJ%\?`ϫVbz=t2|~oo杫!pp^<z$sMh<~`T38(ꇆp3jh41Sg{0RH {w:kă̦+wi-L'mRS!t:=99Yhh-# 6a&" ;"~'{{{^ɓ'dm0@VZe1o]֌a٬D"#ǃj MDTqoDح8<~1m k6THrݩT?[Lkcee5VN„{0^wzzJph4bJZ-L|rii>*4|`rLSiMXXR7jm٘9bq'ށwsoTZBD:l\>6q=yhrW^~}bBK.%&+333$ŷoߢp\TQ...dף^/Ld/ 1^{<u, Ajl6D"fS0-z}L0Il(4B! .\Ѩ݌1@,#&P~u9yj,|jxB cp^* h4tJ1jBhc,WWW@`륥ܜ7oRܯT*0Ͳ`@1wS1߿OWAݳ, E|c 5ư!z=“19;MsL&C9A@pM+|aj;ma]ߍnE>ZKFX$:THT@mW*:=q}=ąryii>| 9e<'8#߽{{^Px::X>[.4ᐋ,H*& c71_bd9BM'"K^ILB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!`bIENDB`nip2-8.7.1/share/nip2/data/examples/manual_balance/manual_balance.ws0000644000175000017500000001514013351443023022237 00000000000000 nip2-8.7.1/share/nip2/data/examples/manual_balance/mask_03.png0000644000175000017500000000147513351443023020713 00000000000000PNG  IHDRVIDATxA0AWg'u~ȽEyxcyxh6ƒ-o︄g=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уDX?z޵5ͮ`˛}G.H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=Ht_s=f_x>$zA$zA$zA$zA$zA$zA$zA$zA$zA$zA$zA$zA$zAX?z޵5ͮ`˛}8H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H GϻClys$zA$zA$zA$zA$zA߷篎O*Bt-~*}MIENDB`nip2-8.7.1/share/nip2/data/examples/manual_balance/mask_control.png0000644000175000017500000000211013351443023022134 00000000000000PNG  IHDRVIDATxAj08_ޜhUgI(__<6YZߺ~xlՏdW\$zA$zA$zA$zA$zA$zA$zA$zA$zA$zA$zAsg$zA$zA$zA$zA$zA$zA$zA$zA$zAM.5ں~xlk^Z уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H 9kn$zA$zA$zA$zA$zA$zA$zA$zA$zA$zAdہ͎ͦĵO:?:M=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H 9v?nnzA$zA$zA$zA$zA$zA$zA$zA$zA$zA$zAd3͎ͦԵO:?:M=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=Ht5dk}~yAiW?ⓙ'ƏA$zA$zA$zA$zAspk~$Oޫ> p"rdIENDB`nip2-8.7.1/share/nip2/data/examples/manual_balance/mask_01.png0000644000175000017500000000151613351443023020705 00000000000000PNG  IHDRVIDATxN1@Q|"oov'ĈA$zA$zA$zA$zAf׷^M;,[ҍ}A$zA$zA$zA$zA$zA$zA$zA$zA$:m|_uxlKy`@_$zA$zA$zA$zA$zA$zA$zA$zA$zA$zAm׷^M;,[ҍDWA$zA$zA$zA$zA$zA$zA$zA$zA$zA$zp6Yoٴ83с~!H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=H уD=Htw|m  IENDB`nip2-8.7.1/share/nip2/data/examples/manual_balance/mask_02.png0000644000175000017500000000141613351443023020705 00000000000000PNG  IHDRVIDATxA@A_!7(!7sx>}MkM 7߽s|C<}'zA$zA$zA$zA$zk箭lmv /lyy?$zA$zA$zA$zA$zA$zA$zA$zA$zAX?zf–7#A$zA$zA$zA$zA$zA$zA$zA$zA$zA$:ݎ箭lmv /lyy$zA$zA$zA$zA$zA$zA$zA$zA$zA$zA$:X?zf–7A$zA$zA$zA$zA$zA$zA$zA$zA$zA$zA$zA{~:ϟbIENDB`nip2-8.7.1/share/nip2/data/examples/framing/0000755000175000017500000000000013351443023015522 500000000000000nip2-8.7.1/share/nip2/data/examples/framing/framing_picture.jpg0000644000175000017500000003137513351443023021333 00000000000000JFIFHHExifMM*C  #!!!$'$ & ! C  ">!1AQ"a2q#3BR$br45Dc*!1A"Q2#B3aq ?F<+ϱC4E`my!Ç5=ݤY'̹wJ/*`m65|Npn݉ZvA,$7C*:{۔& F IUS 2/ ض .6P{T#*)dtspћ8 а~e5 .sl2qeԩ lTqnJ{FqZEZ0= 8ڿETl!`.~Aά75ZJ HEAk.7 NS^!|JmEԵZoǑ8gʺ6C< K"V]Pe͎;ݝҙh Ǚgʫ{CJbנM4]=sSm(CaΚGQc]ѺvI\ ;>nԒS T. +7+09\OhCT㰳@x_(~ںŚQJW^^Oк7uNpeDtp6|UVIWY, geSM顂%!,{v6!V=MB doJqux\_kIQ OM(S1eL9*1 B MOc9+9, 9QH#MI XeYn }T`ZccHgR %uveY"H*.p28EI"'6sLk:4utNY-?+-6!/, }2c+1Vŀ{&텤gS3bQhª<əK]% ͝^ ;WIQI/vwv9Cg59\Uye}C=^lAA;]3ҊPB RC%Y~ҨI+j㍍c,.ҌFC3@apѹ }c<., fq0 u5؟rrSIQĦ@M<my_Q~K fIƋOOҳMl`+/?ezzkdn򴌙ɼ< _VVg;qqZB);!tv-v>VJ6iv\ݓ¿K_/c<>i5fYyos s c:^9b[~QTڽ72ۿunOSg'9 &rX]6 *6?R>WR[9; n@,r*l8RhUv?z򱖶@F\D 5=U,i&YQ6[NJP,N(v8-WeoXRk/+5@4HkClmAE,.%:-E4qGpl*-Pϸlƌ2 ^[UKЂ5U'Tm425-!C(֗\ieuKb ?v9:3n`CbW~ϙ'-p?Zn dSy] JCP}_;~/ :?NQTW'-ڗTnrͤGk g@Gd ȁh Ѐ.ɭBeLl.udfvjRfvۖVX6 [^vRim ^lPSjLs<7d,D%ۮjmq!qziw {.VG<W$ꗚ.,4P9'6zYf,gсar(CTh!ܞօ#^AuZd&Z55.Cu$ZFA||"1mbcEZfe&)ro F1^x y.]_QMQ3>ѓce̢v@sn7S#b&{+./{]fHHtQT아le^6)⺞WEءڍTrziֺ溄\\ (OKǎYJO{w͂a`9lhlԘ%Q{{ {#1+Dז<lSdq91osOq$ܯTT>i$8ܕ_wk&T#M;# '\p) t %͒0U^~3iXhȶMlRGoBre"dn뫍n16WC,%2c 0);0qem<< R"L^Zb@_ 솕xh,-i >$4DnF8NwaBm<̑ǕN Y%bר0VE-t 9<:,zޒ*Ӷ,fU}8c p,G)׹A"ZM5i~NPDf2JW+1V2IWVFl\WOֵFTH6Xqn>nNWiȖZ OzCm%|[ ZοH#Th`)M~ƝUx^Sߪ>G8ªmoU(1;?I+(z\?RMsO)= +Im&8Pm"Ծ@ÑCXZkE=<9sUy]v7 1Rm|!`\Wcx- ň=?HNh kG dcqAͥc _ ʇsˏrz::Γmv3ɵm,(6OQ~C!R`ܘ!=,^aw3+vEI;)~f5گ_Q {S{Ja9^!nYTAOO^_R5m2HpBP "PYա.:mkjiU]v~"/O0ѾB+FF+vKg-{&#ZKH!59ZDp{ (Zzwp zHc +/YGמ{eklIߌ j k`-Q+%Ӯltu\Q Y"/kF3N,}WB=ߊs eFh` ۔On.̽Q*DK`#;-}OCR4IvH+oAAF47o+闰y!69}2EysPL,Gi龿Y);n~xCT49LlZt枠8w C, R=}_X^YyUTnCJk7S=ֈJ7rkQopDž_M&ز|q^n^0u'>jP:N`|l.yq9Guʜ2YQG ?}Z^!zǕ-{W$!^;F7vS "X.9h=wq-GY\ JHK…"0a)tDz,pB1)iyu="`!qvm闉pRY{hHn8X$.Sm)7*¬)5 MXp}4vv+F[v jN0rOʵ+Q}Z 'I q@β6~8#3{"!嬸* xЦ8a yfa*fV@E 7V-hNtdGY9:[KpirKy)&o|oR]{ܧ6¦=IIfxƇX%OXmaV8 "sG Z G8r ۔I y7BU<2d㕃Xj$%P*͸NJY%u\h_9̲,d͘ (u 1~vEBHCK"}$)R*6/*U4|d4l;mREN i?a.T`ZQRS9Oy 3QXX>wdD^>J,fxr %υ>ɇH9PĄ7O6;qCYk[L9Z9Qc:*fʝY7VQ UE\>ڬx`,.%B?rP.+E_S[u`UY#z+\L (RL5:7pbNw3"輍j6 [@/%&al0M/8'&g{H}W}(tCSlZdo^4ZۆI GWxa1NOhj,|;VɌmR9K&/H>_#ڞ6AVbcQvYf Psnl&{BuGZX)&ܫ]!rY.F-fx]*Qua7=Z0J£8Vm!L.,;^EU9-UһVz^AFQ,Du"yNsPv#Z/6=Mf_jYic𞻌]ui,{W (iZU}KHC%rƇpKٻJI\I9UX=w9a)&.6 L rOp1D6;5I1AM422[{̅ZYP%S 0.KqC3 xC246ogK_Q(l1nvHwVĽC.eV(f:k.6j1a|햊8B7ïYAf oUl%ѵ2ZVad&ZP9%_GT7p/7 x]N_U9=z)u:]hk0S*>$u.%>*(8a}< .}5t[dh8wpUOH7G|8%l}S~,p|fIflEpvsKskVca##*`%,[cqk\bn,,_E*Gmݔ'#=u S(Tj.h|HzT$ewG#UPG@(veR/;5kW7Jt &ͣ7DDEbIiX-$u"FMx%h^"xrRxUA /3@nFܩh_"W44!M;}qm?r+/$<4ʉH L N SRktt0fp' nW}RAoOqO~ )J9.9.sUh`lknxHж#c.;-U l] qY.TM\٤m5"uFu"hH&iE9AMfΞ6;YsZZ Q:H$+3GC]k4;t\63u9ϻ҂3隌SѵûJij)34,uQN~ m)+j&c {ZܗvJ $g^ʳbUR6+T02JN56 (%*l`xUtD[ 4G M CHK SL###ٔ53R6Ġ\,5L3SLsWDcOPXxU}SIP%)W9Ϯ}u ] >fȅn5$Rc\2()G:f^Hv݊5y6d&9T4=ʡ_s ? \/@G<1:cE6ʄԭ3 mMR22O i m^7eVKqsF[h` eX-{~s_+ئ)7,`4{X,QH߲oE-V"7k`B] $h>q ;T;W.d[T4q(}ͬhU}vf$eٌ,),a5op \;vOk}1k)~34 p/Xa [v {*7Le QR[7LX[2I zU]<%~5;#' *"GG"T? KhMqkjB#[m{cih_ c?e+`lT[+-ح摔 uh !Ȕt'J{2sY8$oN ]c ,' tGt'cqr618YXk}vPI0cR xUã;N V:Ͻ/ a\Qg(ZyfS;ße0Pѕ3pT-S49.'ª,e5oy6%q#k^muGF:6ۤ\OFxT EalMғgDߪ|5 \Z{ܕBNsz,/؋25F3)w)tŜ7[Jƿ5.QSy7+N٭=>UᬡRZ,c\Kʉ% ٭ .A* :4;aqdaEC4!K<"t4-7#PuNA,yA+uꪗoЮQ-+}7jRFÖ )*ЍTp^W3߉i.&"^<لVkU."Jw*g=6I@i Z}Q_,|l~ے6(ݠe,4{MSRv5V \G#l Xhlzxjv dftEY!熿 '=P6}6n+ &d?i푤+A C͎M{*R8#TQ>2E{kB 9YǍpz0:EÅz9񻂶iN:RFsu)/qim  l2S87A4_RHnOo֝w܇JR%"**􍲥5&ȝ!}вlQXD}.Xإq‡vM]!\g _ ):n<* F]XkeU)TX8S4eWaV}YH&Mu~\edX>I@^6N&M+FRYdPD]Vn 8 @AfZ +H5S~ SK-W<^vGZMK:%I-Z9i4=ܡڞQWme ۣ'.QLDd`fyg;9Ip'VMdMrGӟo*fv[{Hʤ ڴL\U*}2$nMC,G| QG;eYh(TPGYm'[[ oaT?KCbndlTau՚k\i:o)DlҺ*NQ;Tԝ)LИ0teZa 򡒿Q/ZLٺӺHZ\s5 ^9cBRsw턱TP$is\)u (?pv1?];Du_XuWYqxcRAg-U UmpRFKi1cZV⢘VWR0gm0ipXMn @x ,}/ևJ38VV,Im͐\)ϟpTOC[5/JA+R9|F* M+ԳAcU 16EP[,A4Zw{Ym):68BgV/ܵDVVL3}9#Ŏʈt۱6=*8vBlM:~\{%Bh#e=?Z',4" $a9Ed9r>pU!haUWoFʀ3i4b1og?#3pU7𹒁#`Gj`rH#YMSX wM+iA`I0c[DyY(#N̿-H|dnzl..EOe'N'2Ce+8 iٗ$TYRd* ʴɧq qXO À+)]Y,uܤH{Mꭟ܏"=SU{n?dM0@gnip2-8.7.1/share/nip2/data/examples/framing/framing_distorted_frame.png0000644000175000017500000021234613351443023023036 00000000000000PNG  IHDRn8\ IDATxْdIr%fv{}̪ 0"Ù8'#?;_($E(2AzUݵ/wEU`YCʐt7dH{GsU pW\qW\qW\qW\qW\qW\qW\qW\qW\q??HXpeYEQ 4L/z%+?DU]uu6u]uU]uYVvj=em^_o]qpDu]u}еM]VjCmrweYrbS ~xJSj0BX[\ +jnVon^vz軮,<ݻw~v:߿||H)p>x?OSu_٫H?]] +hʛ~l۬כ/߬CUUeQuuU3ðLJLJLJw?x>s/~^DTD81sba"Pk *Y*CTQl\ +`9Wnپy}͛/o.ll`UW+x1 p:_?ۿÇȜIUS`ɨ"*3sVJS7xA~oJXW\ D$D?7vmoonj#ƀhTI1"bQp8Mr>NOwÇyy^YX a T@‚9N,!,BH %&Ѵ, "W|v19W83- Wj67v= n_v1{iX)%ӯ8NLJLJt/2O/>"*"kAAUBH#3(:ksETX犢UUmUæ0~ocH*bP (~ƤJXW\ŋ98E"r֖m ]vvf6fiB0 p.߿ۿ?yi|8<Ox~eRNr_UAU@XAETTPETɔuo˪,kڦaխVC1Đ~ߺ">=@@VJXW\ |Se͓e4u7]׶MݵMu}Wg Y~\Oy8Oy^„~QPY|8iefVe)bJ(,*-IY,kKWtmYmm5MݮaXo!$`Nx:2PZodNQɐ1>kuQ QUUM]5u4jn֛z}?][VES3ΑPX aYi<O住!.~~9qJϐQ`HIc|ê̌HZ@eaH)k WXJ黶moڶnX j]UC׮CS92,KX烤‡wLx>yɇ|>N產+,A,xU8[g #10!!+a]O|MM4u]zݮ+kf5M]Yk@4Ƿpwit\ɇ,>TTET0 ̬* NSJ B**A!1"Z9Wrޮa~۬,LYٲUA%q<784G^|> q&DJiIXETSRfADkl;cpUTFI+J `*avy_~v,ihPiayzzZNt<yTiG4*c`,*"1rL^B2nnmnjX ueҔ5.1x<

4N8c s #@|:ȞR]BZBg?ORRa@%B'S䪲ili]b(i, ~BᕰƋY>F@BDh]n{ɗ_tMSm6*۶QOӯ/~x8<wO<~w " Yk ,sJ шB"QP$, 1U%PCVSԖ6fjz⋛Ͱ o֛!RB@Ҕx;1xӜRC08( 4gN"(U#6. $ O9dbVլ&^;ՒCj%Blu%+~q$A0ZcȐ)u:kU{ss߯׫m׷77mUŏX8߾xޟ8gNR~H4dT-!爈YQT4̓)FDR D`"k%cqUUuu}ׯWvunY$izp71gmX!- Y@C"IE5(,sd 2Eu(̘fI)K ,%RET:cC_C(Ypp B*W?^R<"Xkˢ, W9[E]UuSu9tv=l֫놮U5%~^Nx:xp8N*cVP$2.G0xϢ }P*T8[UYTfU*jX6ۮmv][C }UmSUUIxs!~i:)Eg,q^FN)Hdڦ-&*̉Sa"" X%Q@eQB.*̒b9LVՊ+k Ny 99T TBU_u>dnR@EM]m{slmWaڦʲk ?><e^ۯCO.C`RPE?hbH 1qJETUTU@[U!뚪mmbڡoi롮l!D1hf<>>~ysCbN/{""DH'K:,UaY*kRlBA@"2Y2 (""0 / ʤE!PT4@Q ݪ"֙"|5\{ (p<"b3"!m3 0]CZ aYW??5d2{Oi>=2M~^y:)is3<h]!UY8("3YWtm]] }um]Uml3nKFeOzu{0vm(!x8<QRQUc9h/)<@ADU%!yX 2"**1oY㪲Jz5|իWC_o7oڶmʦoA9Cc\t8|,00p)N)I@Xs2~I)<8E%U)C>(NPQ.{%"@%( b 2$ż*FX@|\(>s"OTDUDSRt{/^%zNەQUcdI9e aRb I3JX$@pَ?e<@T DgMտnͫ?}׶D`1yNxw<w߽{Ç޽=N4 sfDckrݍSR8'3MfUe/<* u3eStf~߽~nհڦ(-jQ?0-~8a,pxJ')BJ1|H)XC0~ΪfDIXcJK H$e,Q PI?M'ͤaY|pƅSLd̳"%&Bc!DP"RB$TC~ YMd&`@ Ubѐ0%R<&gTc1W!D$o*EU jl;JX4I,QBBD̖DCcMl\i\UWno߼y^7~C|zχ۷?{?<UA$4:W#cl" "˼cGD9 N5,M]~vn|vsS-@B|w0g)43G"u5fxQ>DaeAQ8))PiYy",T U,4 s5!(P ̊T$T3 |dMI򍗘Z1% *B:%"8D&9.D(:rexq"^LXJQ߸("!XkZ|祮Bl#G|V.[.zAn,QYeʲ9[uSUuS7M٬nmV}W-8c>O_?>>>=>>>>p5ygrƩ!ZE.AkJ*,8SҖeMUՅ+nv77a]TvirY̡,"Ĕ ~1r>oO㻐N)IEy<;`B_X[a( /E@Bհ4ѪyNe0 SbP[PaUEfe3ݬ+Y,u~2 Ƨja20"! \ %rP$FEQ :(Psx<Z-7T( ֙dڲUƺ ^8SSF.7  Af&{)!Ead뺦na5C߯m۶rdD}8iy?,t81EPy||X,PZcJQ,UK@ɡ2+KγP8q*8cIXJfQEfU@cu2z0BbH\yFT.˫hPy6c 9K T$BJD@J.#;s"r+P``K0&ޮCZEgc"Mu|i)\Y%*hUAԷjXo[ah#_|<%yqUdA@Ę*lQ2;[^168#& ^ҷOD@T.v[v7tm۶_ CwJ֘ qww?|3Mx:ΧeYRx<8ĒRKGP\>DPU!+ܠ7dYg]۶vZm[o~몪 WյsPLcX8~xtc|2,8Ou/ ,DHUXH,bU%:C&dДEM$8[!QTA ً5hD` $c(ޥ +)"\4}BPXX#bMR^E/nU$ƨJ$|>xE PQ} (@H)IU YgblUVuYeYWU6}6u]:״ira֪\.+ uoz[[Yc!X18%3{X|ƜJXt .巼/ дuNڦݬ6~y{lժmR5Ƹ0pNA_W4Ĝ"Gϗ ,^6f$:\Uklan67z~hfٮ/-nۢ,eNZN%>,ѧ?4%"QDSi_by)iJR4"FȨBfV*Oh.YQRșJ #L$h)kع8*B%qD4 X):>;A (GBU#?[a^R@I*9@eE``<^(QTd+HAE8&(Kgɑelf[۶(mኢ(J[[Gd 8!q6&$(MI$RMs/s*h <+nBV3lZ2zxQ[/.&4b,EHv{oܾYV7~] ApioQUc8XPAΗx]"،ƨgmʶoonov7znfMUWeG).q~|z0_BX3(l),103S23Xa+\L#`DML&rIߡ,;g UCv+Y"BG  * Q4i$#?1l$""  T`e-'[(G9j$ $'LcI0EZ2y8(q8M<ǧ$*B"ǶmMY:P4+, 2KNk Y2 D3aQֈr>%Jp)eAv/ͿofuΪϧxzo׿_݇y\B H`(7x)a昲䄀 R-2 BD8WYWEU ^ov7^XCh-HsKV�[)t>}x?SQ99Ksz44'9#'iZDXYP QQRA@+@EGAU6jy+PQIʲ#3狻,C{@Q`S?rl1F)yT28VDE j,eɳ%J,N *:K-ѠZx` d C+tMZaۦ۬owMM\aI#$a %h摅KJ^Qǧ84}Rxqr@J"_ 'TْXҙ%wz^BLͳY)+"@j3d1!DXB%EDck EanY6znw{7uP |O߾q<<>>?=>KSqo IDATKJɐ!"ZV6FA aCX+`$Ⱥ@iuY[8 [7Mnoڮ_5Я/9J* Kj7zXMմj5u]Ս599pWx:<~ q̻$$()Y0(YI%$Q4)"lUh5M[}߯V]S]m7t}릮ma%c%ưb !;?Oaas򋦘ORHi~(u^dCcfQ ,c4H `ȸp>%jD*Y"G݄@"3x.Eӏv؟**?}Nfn !(Dh4T|RD,@6hSيLWիPו+\a]Qƙ.)Tι-t֑E,++hE ! Na;EB <%xG8O/1Zg{/!d:هA4B| 3QܽDhLaJWye^X%Si0I7P_5'vD/A4zP9+F{'ş"$طvٯwzkjn7O~5k*(%x_|>>?<ݏqbcXts bbfQI1y?'YH5 %l(1"Ge֤TRRZ42hA.%x8!$k":ASGb /e1~z>W4&WS> /I"`l=}Ș1ǐѐ)U`K%AAADĈl,un~cc| x&'䓷cϩCmKlS֐*ƺqCݰYn&f]w VN  * |h1(X@VHE9Wt>~/tb hJ 1Id ɑ-82ʢ*gULFIe1yIErf^\<+m]ş$ 9RJDH1El%BD d wa!䫕E%@N$Ej4vzٿyfyMUU]SU,bOs\{p|<ϧy<ȣ'PX#dG1b )1 yRO" DUP4uլnV}ۮjvo6UY (b 1Ò?˼̋|Jϧ,5/nώlL(VK 4mSs1UEsέUv^ۮn\Wvݶ1.p>1JW7*%L>CDCzx>x~9eI} )D.$)%MIRRybLI1PV((u*ۗ10FiCyy8%͛pd^IxQ )Ą"BH"@D̘Y|vQSV ʂQAC +W.]LYX0GI}~Z^~_~ݮmmهZ wwwۯxwwq<#d3_ PsHWH*d/!,+{(! +Tkr ݪo] v}Wu]WC7ueM^,x2d'6}/!!3gWd&ֽ] ê*ˢ(VS<]WVeNB`ӓ} "Jsc c <wc !TrF]:cY16_@cSLIWʜG07uӴ}WuUQUUK,!qay<=sLO~G?hSBhAZ%Q!Q 1Y Z"`5&1P3_ɗ?{Ͱ~ m,b URL4ݿ{݇޿QYK̜8b"D#h [r*, h2ssUUMtU]W]3tfpl4e1NӸ"kc )FI5E%ŇʨQp6r&km\bBX`` X(?-28Q 23]622BPyTXT XM8Ŕ jgKBD4y1QǚX_~#k9w_LX1 "82/e8 ( !QAd1٢m;\,6~ڮ,뛦!j,E81xQ.yS VQc.y>O4t8i>ϣ_0O>fްh=E4EUfa=O̿03ZzZwz] Hs! z0=]UY w?go3[ǃtkdeuIf˾޽}݇^?ݛ?{f]ZwwTCUiP%kcR*UT 2uj'+VRt|?<ߟN^?٨!%d}Y|mod[>]>?hDe YZC;&L"b2IQU@4B@TLDûwQXr<K1 |["Ȇ HxG"o-4;14s!5DjQ%zY;I&^; In4~\6B%D-RԬC:ۏp81+߼4E2MS1`2#.?Ͽ[K{[ݻoES-VkGA轻7?]k=r|A%^ 5H%"?:i( paZ/?߿Xu\[DH|DEd&"pA I!PD~tt:T\823{_=.q]ڱ^-J7#=ֶ$BD(Ȥf9%5##Zcy'*-9&5I1IDWt!2d CB ҙ-CUP2rQc6%Ba=$"(I͘|^om41 OIT]=LuA$jRxnxp8 z__=TkG@.sA2sMG_{],u,u^F'|yz|~ú.zץk\:ĪebAz2R|4!p*0Nuyn33=RDÇu]Z_UD=J2@LuRL7lґ^wEKȁ?__/ e۽QJ t55ZĤS};̓6t<OZJ0jd-VM\>ںFo޺NwDhKu]/V %9$L*T=(WaRb,S8 m -=z0!:<87;&ԉyrlC6swH"[%|`"@ BA!ـE(p\[5jz:x8ݝt8|8T|8?ñOTGfRT105>s?|A XMFﭵ˥-z~^|y\.˲t˺4|˺6==rYGvO'I,zC9jԩLa""e&e,$efdzaTERTHSErT:~gá20W/ګoN~,{QYupLx8tpw>> eUb:K1HA$JX.뻷޼G1f[VF1 ں5EwMӵ;N(,<(ERe*0Ozǻy*ՀXR Uh"-(iK@@*iuy}oXu]]׾X{͗{LOFl#mƃA bm<⤌Z=Xɍ>y{XanC/rG6LL(NF,5D>u b`ZUMqrw.X z?򛇇ק^4ReVQ{pu3ޞm:G^-[|EP$>tZ^PIBC3 *`EQU?@r'[IdH%rȑ3{tHI- &4DZhȐk|C/=F;aXLzdG6q<#D, JR%tѢnsc?Nwtݷ߾~tI';|,:G(téVik76g>4F͜dXR-biG9tbqKcbf"S)X99U*|97ﮗ ⤘HB8A< 8 M t5 '()7*8z: STh"n0?I&T6?SPn3LMDFPh&ɸ&[EU^1氩i>yp<<<|wݷ|w<} IDAT3O^tP.ĥowLJwwUxzֳwe]Zk v9_߼җ-uY/.ޮA$@E=Np{Ve$3ȸ'2(dJ 0RH4aђ_#Lw4BzDmuSUex<wC=:x:~ׯOݩi ·)Jն|1_C~y]/?.Җs9|Mi_m\\zarz0/5QRă@յX'<6@0\4Ӷ 0Bu G[ V}>9G?{}8OPAMmPƋ;3ڲo߿\..z]߽Z[eYֻ@K'%RMh&l"#}6{z:kRFk¤~imu6fRxC \g}|DDd|Bh,$ >Y_*$*Ǘge+u]?TnaZJ鑝"}bjtˎ=E7NH=xWn]%oHUiQ2㫇<;n!2":XzsJtM+{^r]O獉t\=Kk)*q8YKsAւL>pGh$kTQ&t<i1bXcHM.Dʶ7뺪J$"Iݧ4MZZ aq);@BNPpzwYee”D`)禓]slYMse\SR*TbaIU(X)D@&b:8ZMIͫWw|<WNww\~l$#ٲ,߽[=!4H76j@7u]׵eY($DkD %K8HL"Ʉ,մ)`W>NӡiK[m]c{ֱ[W]%ű? ,y[M \yV3+d"ӊ/`FPN]uA@Մ.@Wtj E= iKB dTÔȑ SJQi3) TC:MjiRˇvkou Jyz3TJ)bfo;UaEJR9̂UTJҌO^V馭NQCD Du*n"2$WYQu0ZkRfj6z:`ptZju:0U+ggx{;2 eNsfuچK[uYe-uL55`JjZ:%%"B:P3xԺGV-u]֥_i )a0+eJj]zu]UfNuij؂&0ϔH*Wcae b򨑇$ ww_֫&RԊh1j6:թZjsi>·jx8yy::U&3-**jڂkfdzmmyifgק˺Hk+uDOݟ*豦3)ݷŁRTm+IݩŊ:KAmtڲmm1p8ɮg2nykfQH@{PTPoYr EqTnnLόN: :9d7y~޻0?/8Mil\X)ŊNán&+@z_DX{k75eikI.k#LX)Ed0GXdê Hd0޷|]8gV@S wWSbx&]`B\7RJ5VRN(\XD0:M%G'1Hfpm6f/nYέARDK۴Uc$91}BP+f̢f09Zko[퇧cNCǮ]t5t ( c6M&c +u^\t/S^8j&j>ۤN3  R«LO7BX%_sLjS9MetH"w[P3E4ΈDfDGD}v׮P05gB亮r=Ix>'EB}fPZS_X/s%ThPV`)4&izdu]^_Wa&QzfGH,#JPrD&#|])i02(eb4 LAPS%=Ƒ#Z2:H|x/Q}5"2cr8zqjx8�\|5Zrd$1--E짤]^Bc++ ah轏C)0FA 8 Ln9)B9/tR0q$9뺚o"c0&UԸ^Gm%ludBIu Z\Xj#;"Iݖ %j&UAa܂^T?}PU3s{f=/RؙNV*dKZJ`4.3cRX5'Teè`̾W)".-^/-cZ [!IQJ-nTH=o`׮Y 2n.D{)Zׯ^Z{`Qb>̰_0`X#w&1h/#BN N !ѽKԮ]q"G~PL!.Jfoh 0U^ZYc@q­c5BIa-5ٌkWUD@\()c&0eQ@DSL2M<u=Zt$1+ >~?CT L5Uqڐjw[@L&4YK|^vG3RLI@dR(Z-6:Z 2{m][4?>> Q?`m["Gt>J){`\I{T<J\v{D$57 MHHZ"Jryu]DFkˁ^8*:h뺎C4M+0,3A`K]ČU\  m&ѯNP)39K漈&"$8܅Bexn>O'"Vv]_[EJ \. o-3K)Uͤhl,-/0?*ʠNaו\kkt: 꾉dZ)<ޡvԲ[wHB!@ 4tȖSBtnNf[0d Td!},[ u62>9‚}|꣭tkh}]Mڵ8I6$00X(gOL {C޻T(|%pBր$a.DD.tծ]_SZKVJZ҄A4k($têH@.z/qJx5 x{B#BE$"1PF&sYuqρ Gk׮vntd(aDITž ]؅KzGJ-Y*Ko]Ww\/}i;ga R"<*9C ֮]_W901 ф&((Es`F1@T8B _3^52|%2̼mxu]_ E $JXľKkWh΀0B MD XBjYl-~,e`"žJ4eYk[!4{{gTUnkV&! A!{vG #dfvBR+u{&rw}gG b*vl&h3}CtK w+2!4H0jx2ш4$EEH&B5%sw E0Mu@1k: 7V!#)H@7"({~Į]_Uo?IÆijhKL'6I1OMD&{ ~ba}H* K>_A Z)$s/Xv}]ynUzvSVS",X REAo()X<njP>~ߪN|j˻~JvܴmO wʊ$LTT%ى&lȕCsLabOljla7~%E%M@15 O+@u2+sf/Xv}]>@@e( gpG(.x) @I/ AGR  TaiERJyS۵k29= p|HȌL\R_$3}XoRl,q)HR%0U8JWk׮Ln=s &bIxFキ%dYFңn \ G}kg (̠@C*eHeYW}(DkWVM3=D+ b01:dF2MԊZPt-/,X1;H:1U-ٛ$Ԕa4Q ]v}E$2:B4Ĩ%N~vҒ$,!=u2Z TB D~WB4#f zf م2i(H'I_ļk׮Q3'"B2UceE8D_{Z'Uj$ TJ~a@{lK.#1r ;F6'kAA*1OP\UK-Rs(Е+AnQCT3`キN*e\))$Si$H(ck|5&pfLˠo>X@]tM QMc`|`g,2"XU$QVRY =cҽ^GRadF4Ė0KM:sVY$H9֠_!8*"7Z2H`D*KlYɽbGYpЀ*CՏ,0P`;$>i_y=,RŶH4ȈZ|^;i|FdWv}u%EP͸>M4MSuX@#BLĶu;R4P?y%~gzֲufhr>f.P[⾘kCA 8rdzd/Jf:Q$Q$$iUDM^:Q߳N) 4L0sB~z @QFvصkW!t@$n:,G-@8t,sTXQ}Ⱦa M?~d2(LD. ETvծ]e$W i"ڧl6Z{M9vShlX(P~2zgSQ&,֗T`% AQ1BL՟مl<# ]6+"M)u*(0S%ddpRTe6;F d (87tō<#_Uc/Xv}}EhB]4$D@IpokHQΤ j{^ 1UQLDJd5#ZdFBs vh=]"ʍy D"Y,D$ĉSEX&!ȗX}%ඈ3"R# & 3бyjdD2ټ͙\_,֯{Ů]__>n9l98]@hPxQT(D5|Εp[Q vw}u&2~ͅU"TڽI(qM./τ]v}5yjQ1@E =LJ)DBjHI蘟U3sVK/fJ`"يO,Rh$ }OXv}}jUcZ%9DeݓV:TaN10A)ݭV)jņ (U`m`f5=2 rzF5Es "@7bR'3ˈm9ݟjff{cwA>6fm7FMV}NnnEIL)"<Y"]vÊRj2enx:@`n(n/-X"ޖu04.zX^fGG-3}'vi`DEJ-u*^5PURA&ܚ=I$ QjVJyq"g`237;^ 3NU@TI<=޽gZ"]vm 8| [DDD|DD.Өw*I x^ k׵4y%ðh)wZCU^vk׮r%d}YV|¤.dNS]V=UCn7NaO^ϭ<_k<8*El! P3rIYJ3z;kg%*3!̞#E~Q  aL11j/4/ ' 2[q S Z5FS,D~Y<: 2˱~4 P |KyyofbܸY&? *fRsTomܶ-n\,/v  ˲ ^_"8b!H f-Px8 FqFWiʲڪOYdHJKAKlBTlDK8LH>4 9| rW|Sg2k˲v蠇5d^\RKEf[+:$38.מL%^xkmw-ϼuU~;)DE"aHŬWɟOJ=S&#{ffٹ Ez&^he|$h-",tZwFՃc>^Uv$ԉ Uk#3>#8KⵖٖGB{0BQ}QݶɪX)>f{)ĚL>R`H^L>pop?B0el #!I˶VgRÕ:no,RM<|)Sh0OwYh@G2OAi@Ö"TX'rsaf6 9~)e y来$#L@IzOyc䗐/4Z){k=Zkp1qLv `5P e=5:,gYب?w:&CA }c -^,c 9LD"dN!`P!,Z|˗'|7RfVJE-w<\y;ǒk TGtφ%N ͉dQıۜʀ”C0Zu]fg\dBP7ۼvVRi@ޱK(e&a0eY(:u IiCiH}$5f3p2 ^^j{}׿~;$Jx:u(Bf{$t7NˮC~Uk=-R $HKue)4*֢МO&,G(s!^Zs3:Z,#~LZǾ4c;4)W+NqN=78嚙L(Y 99Gqo/g~ͽjQA9#[B#p y槎{1hwm̺gL>6D ?*mPfFD < PRCx5Oy)X"!OuE9uxy :Xm!ܖPBr3mP 3'c9"E2"n_&]z bYN;SxxeDZv[)ȷt³wC Z-Uс_S0| ir# 懽gD&@gTVE%P Cjo!:anV gX& }߷ "En`T\poʀ úGR; ێ} G'B(Ԯ0eNo7?y0|]Ԃ؟ ,Xb=v.,uI7[ {˽v\B՛H K=5dQdaa]r]y"( _[Z gX;pY.\BTZjCAtGlP(_CTudQ覶\0 Sч9` ǣB:,Ҍ`>7~ϑp SKgIc.K.z]+%)J+0R ۷>;cG[A [EH ǁʌ(RX퓜aа[}Ncfz)@s1_;QK)C6-SEI%y"L> IHGeY1^ evJw[F% '~gՏ LP!h#akRuL2֗K晴]QxfNUdad*Z"22~MC#2蝴c:y HC}#! #\JA,s&zn=F8Gf{xa2P^[V?ͅffF{#G{gq;1j}~j{7{?SS/:|0kk+qZov?iGo=Z 2{|u0Jysyne* nv0p3-L&Eq O.?} ZvXgD)ߟu`MpHkzkg<N&Iġ2t62C1 yvd3''`0],7Dgq$ÉL3[J)%"}Ǚsֲh!J@`-7iỖGM{u%,<#FR@4өF1ޛ5k28BIZ1jo, JDdfq,>t7/O(%ap>J%auHԤ8L>SMoѣC"fI1C19ֻtX2Hp猘nt/ɤ(!/!)bڍN&ImZkO QB Hn(Z(}F^bF$kT8 eY"7R&P Xm,Mj2`z8F֛zwTYWFqJ{Ә #ztW;޸}Kuۢ5`wWץ"2Tekm8ao3̬Ƚ5ӡ4 lZ>R܍,~a̭H_{Ib dadu߽tit,_p+.vzFz_EJn˲K)#Dtꪼ2(+N̛"x$ŽyϸdI{%2̍`F#@>Hb)gc9LzDVvUۙ^ʂ$t2|yߊFθFAL)n¬*Y _Hs$jl۷6ooA  M1L>#z;,XƁ]DI8C7p7CQ\ey,(#!ʌc߮BFRk-!NANnD>e Ңo6cm|<י{VLuaHZ! P+Jy|ڶ}(XxرtJh8w&ɇ~}ch5">TJ[5&8F!S耓1IVG;qI@1"o[{:r1Nž 7dR[+7"UfT޻ $5VV0J錈ޯlx"qScڔ1biㇻͣ{m"i1ݓ̧\|N&!<ϺA{X[ò G()A+Gh0oo``*oҲQFm::VHf`2 -]Z7F ?hd/eD߼y6|` ˗XL鐳tfRA ;7[k}2HoӌTw6Pd{DtR (i>lqzͰ`:r(4dd֊h6TF1?NڰLf>F Fkv gJqHϘDpӝQU=Qʔ"4yO=C;`zN&$2CdD6AC:PDW1"@9uX@"譽n6ګ0X7WeY./#e) Ǩk+qkdJÛHH!(s1 ,-0ZZPXuj r爭/^kUyp2Pڑ! (;#KT &-mO9uX`J`^ׂP3"3)jzyqd'N2!ѭN;~ޔYf6]pN&Mi(12 vBj,mS붥8@҄JׯpYwIqCpݶmlKޮu%l)~[JL&Ŋk}QEYk#O`pȅx  rԇQNyoFWGu3qdρdh[^g=""Gn_@I )oB3=gGC0 fϓɇuI4EǤH ץ,Xoxso$Ph8Yh>="[pZV}Rk]j#[^yi=j˺wVGܨB="#iFW=RZͭCٲzj"~?L>1nnQ pY-YCT!; C~Q?,ҋSk6!4Nq zMu9LFy_XFc5p - 8,1r=0{&Z (}@cH] G`\ʊ6G, `'2y~Ǝ0Ώ*E͇E#L`̝&fN)w45E12;!;-t3`)Ɍ!ewos-g2x "ȇe C̤a4! 0ۧ#Vs5r23^Y( U.eyI8|8m xLׄ}]W3gb%범ZJQD2oяn@⦥o^/KgIԱ8frd?J{WP1ɇs<[+7W(#yLәXe7E@փn f,%`H3[6ͳSB@6"Ws%M&G鄅:gJi=S82zf{04[;3>,e%݆1H/,d=ZۑigMGYR)˗,EVaW73L6Q:z}#GDC[@P,k]/[kSR`iCtҭv[&k3p2pajp 9P5KI=֣3,8WNj 2gKn^i܅̈}CZRu۷ϓǓw+8ɱ|u,>-/z2i#;, CJwD@oސ ˲E/^75/&tLd `w{ [Z}@;J?kFK-`mFw#lDR^<꤀PGB(E,bxgY7?/&LD [Xf~b|գCc>쮬 T2$@d!:[%N`9fZ6{aQn׵X]^˺zY.aw؛wkbXGuS;r5|DWhj$&Yu< Y'm??K(}"S5E\D xJ0" 0:^΂5|$ݟ]vˆwF4S~~ bM,pd`). D IH˲ZK)Y#8-O&&u6$G:UZ4GF}}X*Y=t34.k MI\BR)H1RTO& 99z1|f~7-k,T?w aIëg IDATF2~Rk&&IC9 G'J8GCDZCRʾOy|릀?n`qe_meN5HʥV%Wq+;ZŅNKR@aBd4Dt =2BZ)pȸ[;7'_I-n ʱ[4`BJ!E2 LiC2N[)n1n$d>$dPI%"K-(~d.o*"Fz{n9M'|`t/&jEtsGH#S 0z~6$\֥,(aMscs&?O&JD$Rʲ\J.1:`xYcq(R~~'.%zgLCLD=@$Dm[l޻BXd(p 'OB*8GӈZPYy7(RXM &)#3!؎re2X<#8x}}=07x3XeYzqe0ȝYK%BݍDfF`Uhfsdi1睯!ηq{(ɡEB3IFDDJ8*zˊW N =B9֓iy1f8Zkg 3[./D3'-a *VJ@))P "(d3W²d>!]ч+V)vQ#{UhLP RZ,5oŬޣmAs Ss>|${Mm#O&'n C#aj#ktuREL:ֺ̳TS\^*E~Zx6o^ fBo 4 ʡd)ZkY:-F+IH Nk`n}DbduRy\lTTo_׿|RkI݌R4q8z4AcV3 @Zl3y?3G6X*;ug6q~}1u˪ZO!LpUi6{CҀ1Ɗy2IϽfj-u+z|[ffS $݀(^~RdRq]q2HBpTa)FVtd T$Kczux$2K&d3w k}H Gߋ (f^jrk2hXGyimz+a؍˲g4L>^giR  9\x`^.RGTk]WE2 IqvŬW'"%h&FLp]ux߸YK _Θ 2<`aʐ20vwb{&H70|3j(ȼ}H8|2s+8_~L *GC%hI?#3,܍]k3,Z^vݶ3@ȱ9X̪t=7dym|ҌݝBe٣)4C7( h-HgdQJ 77{N2!*3 4VUcJ08N0Ak)^#}uZ}ײ.jmtD 쯗~odD$dH|a(d///7?2ۈԉNw OWy)G,RkCS.(lD(R gRκd2y.۔jcYu&M^ gVHp4w\/A2"#G%=G97FeL&!^%*@pJ ,UmmmuRgQNj$ tф^}bՋJ9~2#S#]6&s߾}}Ta08ӞoV3[/۷ʗjU]; _,U=pjW#!P*_9*!`=B3K/\ŋѮ{d2y&D{ u̽K)e^մ+RI;G nZjM2 [xXIZ` ={|owa*/K=Wu RmT.-xH־ 4 mk\ׯErʄ"ɖUҫX `9Vn(aM&Cy&6d xYȣZ>` %ĩ-e 8PGG8NK@0.Y+;خA ^a bXQϣref=wO{'.XeJIht*-!ABa3bnnr JSl KSO)d2ya]3[ٶOx+2 x,QєblD?PdtX D37s !*U JB@hDY##Xt/f;u]짚5$08" u8G4[kRj)[<ʂP P]i΋QЎc&i7 d2x$ v>z)>#*f1zc7_t0\d~iߕ=nGZ*%?}\r o8W8n2|8rY]谾|rwDľ5=ygEJ%|Hxs?$T͖_#{Cʎi.:6'9tnYL&TDܣ/r92ɟ qH[ +m'vݲ_.__ Dg"Il>h/88|hzގ79FulAR{mQjbzfng:m--,./u$Cq{s ))8FÅ)N#߄{ss~` gDe$aϭo7./گ#WZ//s4pM&#zZ{ Ook1"ǰ- R5)SRQ hRIHR}M&3̈Ӿ< La; Tc5`#dq\K׽](PV3pFELDD=p2< {?Fq$M|T86a\HދG,]C^< vm֠xqw3`Cӑ H'M$iA'P}:ug1RxfdYj5{3"Y$2"Og ҈a5_frK o #:,%fdy-yD(S%HI^X?KX9a`&x S2eY27(=sPO6gsv@4+ƙ5|*Hu{G+{.y.hV˥P:i;ړ_-Xחn\ #qHdIHrʑV܋$_Уo=o30:,iH=y[EjgʓzkfZb#_;R!SS8PDomD9  ,.cOO&Hm>RL muDxuXe([BA$;qI!FC~zvd#C+a9F4{W ů,(cPA0Aѻ=q5#բUb&CϞKWwyf2/dd?@Ff$" Dm#y|'"_ V[PhLzy Ljk i;I2jYY ee)뺸a&ho iyRZ1Y RF3[O4R/+3z}0,uo23ShA9;sq1ax9Nj6z٣GJ2!~` 2R3{VK$zo^A,9fOq4S3,˰N&)H&V@.;H91jN鈫hqI7ј3!d({ó}{˗ۏf,_8^Y?OtWy[5"q3V bw6`tL>eW܌oo_}۶m*k3qa>&ع9d` Ę+2rR2jz)V¬!M~G|^Ea7Lna7,ްx]zQS~=DQJ1W@II9GDHfh=dI9f32gzv5a B @g]v3U5;p=YdLWu$tT'l3ǎ MV2o1y k?Ds$I0jfpk]'WWw*ݷ@I@i%[C~FDIo"!\j0xd֦L[P _?$dk':͘W6_aIEuY`d^|~Z.gBJ񇇓hxxBŧ,@_e ^o+#y8X4peF (3Z[0%t n0]Tٕ e:Ek]kȕ0K%p0 e4BLD/7y7d("iƽ/*VF/{ ¶]ڠ%SoLVwwcsީ'-J )u;՛ n+],nVͰyY/2o If~؊ـ`-ks\.‚/63+tIn$^:ϵT󒭩+Sٌ-"2L C8:-$!ń h]j^mf-p4Rm^;LxvT; ff۷d;Fx 0`X5 on~og[ѮM˾|FA%3 $G::}QO T+fb`-YYMofz5@8 [}مܲ +)y"< 2f$F4FqoC)E*N$ K*r*Tzt"^1 ~y]n"h,4ֶSOĽ& % #}_ux?wdX}Tϋjf䲚`Sui]C4EyޟPoCwpmv?e4m*˺Z Q|~`tƬ:IKHLZ[4"Vu]F5A2 (,kQe]u-Z_V8:Y֭B}߫o K,ŕK/5!j%,Y8MfYƚ:N3[ٖ奬c0ZkoާJ~h͔klE fVJq/=O7PiD&)R%3{@4u0! $ «[>͎X`]nYZi,i(33Lطʈ"U,]A}rّb oB.k ]uso C@¨bWk첌ݸ_2֥Erm>_ 3#|O%5 ~![UluY2rW[kۯe5L3}RańZk-Z_N()S&lca$Xۣe$huhJ{ë9]M[s24B(ݝ$$<SS5/>`('>,۞[ef$h6"`i]SsCs!x7ݬ'񪁼JBK$<2[Lnp(9VP&̧i&d7'>. 7X#Ru9%(W/=N$woF( ۻwu]%#FPUv¹RaL* KN%7J5fSF&Ap0x) OSOlf @hcY68Qi\%kxZ&c\e`۩Ls5*c-`&Q_y܏ @woϰ$D63q] jqBpwr_IheY PJZU0ĄrN ef$%5[E `!, qc<_m3Z/r/0Č ܽq5!GRjknj1%"D!X ۚLwG/ lj]Ǯ =/жOfü0BJrɌ@LKkFhj'+fNaT:ݐ>0`&I!SP6hԗDI(Bf(Ϗp3NP9~OwW*AS@ʒH춝%д{M벮Nj]3BiqBwzW _GAv ~Bj.hPt%aX>8TAJ#͙C7:IRpsqERV`AAh%O7T7Gq9z#Ґ=@ȌEC5]hp3eb;%띬_Wlef˲Fhjkl_7lW} vO /^kVEnMưo|&놶@GwȲ[wYCwR޿?|7Xud Rz vrꡚzj U%z3E7h_ zÄɱF$$W߷2B??> /aPR[h(@S9r\QƤhom+ {get-S!|ʷ~y^БV3 +H/H K"}0x$̊IĺeYsI^{1+u1na)aL 07`&1 .jz)-}wtJ-୲Mp7tx(U?%h0Ӈֵ ڗ~àxٺVTngH*]Id*4z^J9Nh da# (7s$kY2b%P 0I&t^S\ݑauw@" C"`.A\.>Umc+`{i_uL"qY$|}J%ԔQTRNIB}ɺX>so>Jӷc벣{C/]CJLh<(hÇx~S i@b?Bش :W=f/F4 .RbBV9Ifn0cT\!8)a>$)K)ԥ]GfdcK/=<˲lhq$X%"#2núӪ[K=Ϣyy" יsJKB[P08 2C{|+)I$7K 2tOI|ٷ @t2ԍ|klAB]<"TIxRv$.Vl7K7`f^<3[ġnۺ~J}uR/t7R&|[E@h,PB6~M `vCPգ$@+[kֽlُ.ǺK8JP xj8w3>ZDE?X[%Rۤ 邆^*#]!PJNj[b, XԺ˥ԏ.8j]1OSQ=N4 [$"2ͦWȭV ?_v_eF*:u%==$,QJz!- H<<<|w&a5Yb}yTφ^Э\L[zGӽ'>6A{4ΧS/Yrf~W$ o ŽEswA ͼM* V>d/=NsTlf)Vm԰>(N 7oÇu]U,ǹo o EC  B? !0dj[3,7wnt77;9PDdM"_B0r,rh"F5Yr{<)_X5oYާ~x_%5`M(\ZNln}pY咙ܝdz[kZlC0]Z*IeI/GOу?W3E]y/7u]Z[#HRX+hAkBˌCC/h<'u-fJ{n?^v _:Z]/ &&`â;c,瀔ک{7[T>uճ0_r=``x.`,@!##3ZR]?  o5bi`8'z[=R 'nm$)P t2S5wH)ZEgfl$7`&ɄbQr>'h_\h>,Rvn Xf<_.J)b)uJyd:Xܷ`˲Zp- `v9yѹ=ucF3z~YʵEKk&7 wt5`3$Dƥa.2: }Ilnz ̈h"36 7$#[7tc^I>mB8=\%3OS-__q?7̐@"6d5v,k_ֆ`viiZ̍fm|>w)gX Y[MT^ BXjqȠZ@@^#碷`2d;iHd $XEzy`+YInGTq6bN4.k7~^? %Rj[9   G\o 9ATvcM"K[WqU^ߊdi3k Fk/i ,jU] Z}%U2Wݜa 0IVJfǑ<,<== # s͇˥E f'Jh @D^VqV+eQ^!"S6 }'sF˲|~x\[J- Zc< эW 𭵈lVTlNnaX;2-3}s?AP߳HZDUגo^$h>`+F-ُAgҊj:`Z[c/>'gX $m['oI oy.|<0jDA.x-4ARv;~C9RK2#"Ze$xEQxWI(@}+P3Ղ] Z %ZK)}[ Fwa/3i A=+HO=Ӻr>޵M=Ih-eF mED7u#^ (Jfu]Zk^ŏ6Y ꯲ J1A1GbxxYqP& S{Zևy-"I/f`DϗKLP+LRȦz~7uW0 g|㑃-cD1 k!Eh,M ^Q`ݜa%v8o83OU}͆$c[fFc$r0M/m}<򣀥xIIt|IP< d"7S͚6Wk>6 lQLSLD>'3wWM%uA4O@wo7@+nj/n^[%lfZW= ~5R /Ak/yBA=#hO^ú1`YwNdH&!3YsfZOSkrljwR{x0xB]N-{: JL]%_2iNL,NtzHuvT)m\W @b[ 'FFkiX>RfpzAJImWߖapw!%mցL1Cj 3ź,ZT^8c0Lpϗ4B+Y"1X+3dʔ"BkZdV -0B4f3+cU`TkR *O6ʣnZ[։;amoV9 O3seʰ;12zX[G Ӥh(ɣ_t4mn3n5O`օ/íu]겗 o HEtek\?fivw%2:\wۄe ϾD.rhyf@5}T&dd|<(f^kBnvoƒL={.{0Q8ݻw4m27O[wJ7Ji>}7bOM@R `/SVCG7N>%}ֻGQ3S&As6̑a _kkE 4h#ʏwa jkfw#xKI gqSe ٤}Lqi7]K%{?~0e.5jf?ḠB_aI%3nЍﺓښ;ZF@v+QөrL8[?,?A0@۩R&n;r[EڢEVī}>:6)_"h>`1@TkZ_?y,TT՗JT>譧n0 .deS6,Kw? +#` _NtVi>/?#Ar"L{yw-6MyuyC]{Օ{f]/ 鲐]]KQ&Rkqou'ݪt@^73IRD̺Njj,B)^ Wxvn:1K$(ef"wY$y4;#JORʻwcֺ,.H@l_kDXEڅ6_x'er5e! _zf'W_~qvQp;h0Q"S5]8M.].橖b&sCp̈h Pc?\7#L:= lɕ$3E*г q]í>==nΗ{BXzXb˥ʸ{).2`Uk_}pz1aYBt!$达Ѝ%!A7=룁^vSmE<犃T)ɹopƮm"y ?+(NKx¶+[=kcv+HG5|<[Qk3;mqY.ڂ'k:z^¾HӾvߵ_;=.C0|k^.at3+l>3UwFX-3M٭;76/DW-\;۽V7l|<}B}2dmԑ>K(pܻ6?,HRRm~ݏ,>|PȰ4ҔO<w?J.2'trr|veG+g3`![.g^/߽KHqV[e U_<8=ֻ$3к p0xdF\j|;֭[sG*<iCOǜ$inp0 4sZ.1)f|̾ҡhRV=ڲAex^׷uR#+`Y# ͱΖE2uޙjݑr>ffy͵]/_L@f}1|Dk>U$=7eX hvEGMwWXk`0x8"Ldڵdf{zn$<ΦT( S; |ޢ)V#` _ ;b^kz}X׵z>{KǯLa`/c5=s#q,tw~!:d -nZ>QAėjLt3K%6, @{)2o~Ǽ3"bJX iCTyݜeŌ}i /V IDATfOeҬH]=[tX! yO'/Ѵ` z о-GW+"=p< ͖\JL˥/v?fRx|^KN@-f]b;?rnp09JlU! jJ); ٺD63E*sx_ -qw ]R`It(d $iD!* ⬻|H*<͓f*\?}cGK((|-07$q ].Jh5Dpp5N DLr~7y;*)#/M#Z&Mf ?:MKj`g֥ 2Eho v 1ZZRKlfSpT鴧ǧh-#2W|WKt_'_,tA4iimdXWD&}b=d:AɽLˡtBI*wl2k~ZN5MS)eYI8+%P`0*,4jߌZ7JSB LF2xl-euBwO !`)[T6 W CJu=P I`ơ2MU~.&!`ݭOSUlqV" |<k ~}@5X-Q&p<0,UREpRY`71eEڌo+"l6?!Busxb:ijyY'C$ "<@g}Vqp* H"Ep%adZ֞/ q#ꪫ RDdAy)jC5|-HK Dˑ{Kك lW8#K);$}223 שёLk=HU_B.x5|=[bm>xGƀL0e~$<6}fʆ/eX!Cwiż/n{z?M~; GM8|-Hz\2EELrN̈j`[oJYU1uQc y]@iqCoiuuYtϰ2AB)n2 Srhd ہUAf[-aٔ$'.$f`][kV`At6/*01{w>rdəeY`v{SBl>~tj`/zmC><{{o"@  S;yln( !6M;ͮWԷQdj); ,$&Ax6 a}$gO8C:S=}i ˅dV@\Rc4MfunH:hQ_Y P TyYQAlukͦDo$4&Pmz3D֥ zN4#{1揄r0y!o[#l2~ %QJhy!jJ/ DJ-sO*u]y^Wa`0*HAy1dUVyAҌ4C-ReYZCjF$R|)ò^w~;ϳ)]vc/%9"}`!!ÃV;͓C}ek)%LDױWoOxJ|r@0Z0[Xr\2#RlKۅ:O kcS"9.^xSm9?fGt\v(z:WWV>| _B8A@'>M4M}!,>,}-%aׄi_Zk?.4yi])zoE?a J_SGLTp=k+y[3,ҶŮKk-M=N]xջn4-i(/5]@ݽ2vnXqs/[5ior4ii.SsOJy7\k-S)i.4MK -sϋ2rm^g z ҟMoK% V%Y̌]#8G?^Z<4W}XF5FZj)V{U;7;7ssT\w' ^L3xdqV{~r ϮfZ:^4(s\"b/U@;}gEݻw93kkuOpG˳`!dЛٵGb\-L'f^)DI: E޲al0xKTZNZ-ɨZʻo~N'r1z4" p/\T4OiOӄ`.>Mt])kyp\""o hH3L)OXeyg\.˺SPw0Mw}7M.{&%}7S|!`I)ы @ճ~[=r?W7_R||N4e6O>mٍ;X[ceZ&G1{l <}o@5N_Z.>HA0TɄ[rʰ-߳/բr\B-=>JNFH4=^~|z:/w;橶oV0S""MTu\.?.KbuYa%u>rNڣ__?w{#{be{:|T~X['t45[R Z*V5Q?4OtyTOV *RլZ޻ʒ$gb=="2Ϲު.v$A9jVZ Bqf1f#`f!Z 89$8fG=UEtAQ̓nn}, U%ʩLys.OtR*JEӜӒ^5Ntruk޾?g xz]uUf ɥPVH;L x7BHe(105Fۻu[no}?Z?woU׽n[{aU\RymZkcxw^6 G5Ҭ?-!!@7j<@D{il;u/0o>KՕTeZT%rrV)Y'X.s)")hku`wKA4%(D*er)4Ĝ2gEr&0M,#<"@h+Ln{ RdRV,DY֪5|5B#KNk,{Ql|^ۗo߾\۶^?|nku}{ݻ9G?'o>W_O}YNI^t?YN)"ZFG?3u]}_O??|8 q8"zoT "̾K?x m1(3pDb{UJy U?\_3f~{g F 32y.%],S))2OISi<=c" ozKJG|ʅr.s)O)/O)Lt:2h]z˪i,AnFc:j=%pÍfBϔjV9d۵vre/>\̬պ^u߾zYkok~nnΎ"2eJ TrL婔OU>-:,RG5ӫOyE)$Vۇ֟LZc?#Yn%U\%|RO![yMXK1UKGMDu0_RUmss8QDɭiu@L`&&1`4_#–xV.̥,4IENSw0kڻ!YB“2%M)ezC4Ϛf"v:=\&!<A 3ۮs0%A+ ]LȹvGװ[wDQ^{sD֛{ukob'x}nFdM3'<?II$2.JɪS.2 B뺮;Z~<5a>2nsI$1Y\=}5.Y4Vhޯ:nȂOi +pٶv-T݈IJ)__lk0 Kʝqs/[9M}W0(9 a6:k!gaixwIGIU51$y((Brpw[rTRbLrQX*̂uYy7iHfGL:%D)QeI+"DFSJ Zp,BGi m ھu֭(vkm׽^̪YXwh]w뺵x)@;THT/,,>y:$9 nuGA|J R8Q$oX~2fČ>?׍ .󇇇G g YGa[B{p텕∗-`G>.NIJRIIHRVfA""f&N*\R֜C Td*2"(YUKI:S Hì ,jqVdrT]"ƔU2"st HZB0[sP!3<;SG7C"@"$^ bߥ"9iZR) 2a#1gaI\9wVfQuoFӌ3s MRfIyIY5tb-%/ˢ)>4'C2!)3;|w&RVG&Q5xDo0B *#E-au\>m}*7'mg{r֫{mۺj]mݷ}v;qbbbhd0"2Ο4cRe٬Z.@pw 'pk}0,9n{xh1D8B ;ITDBĀ9O)ì`$oKmڶurXͩwV)szY^Ӭ"@PX̬1fķ_=of>N:1CZ N歵;+NeUa4O44Oe|LKiYrRukzWN9˼hIL2qvRI\ʔ\oMikDToCM.rX2 ȤXZ,$ɠT"F7Y6ڰ)k[X޺oۇu]ͮ۾ֶbv)R}v6 ڪہ;&0Ly%MSg9?|Ora2N4<:rwQeiX#a.  G895 bpc.nzm y6ߢI8h(VFA#6ny|MI6&'A ":|uC)"T$/zѪ9D4&f 3w1=??yG6fPfwnL9]׵]Z Grs7:e%"0QؽW es7whbVQ I,|j0|r3jD:6 ̯ X %"Ṅy&G",A hdq~D v%R[CxN z{)HUrN*RLs^撳t*09ϓe)L_ai*yNIj46Ap|C;;սFjV[%9]w X>pxt̰ҜZDɏ~ǡ\T_urR0s֤hxG`w_#&U*SNgfMR6Ч4luR 1  ;B B:=_.>$U"j !֬л"nH}#cyk{q۶Vۺz֯F [$МJYRr:2O2KJ"UN$%ʙXy*e)Vfe""I4ϋ&5SL ʒݧ_QӫOOǑ8F*}0~\RJGRtWˬ Ӳ$Qk oP#pb1GDA4%.{ 9(^aBBܛ#LLD2x?#v,ޛpf_"Zpo/ߝtDlLr\w*zyY6~3猀uI- 4(%Ԭ_.u߮ϵަ9D:AJϧ/-oa( 9(izmcM b!쭅*%Z1%4S fL~.4hь'$ &BQ.EXգqN2O'wց^:Hݓ"`0ㄙ ƐzFPk#֘Ũ0aqlnk޻֎t̬^ͼ~]Z_7 *FaB<"AXEӈ&e鳬9JR-4Κ'V&if-STJ4Dp3Tu>?G&c8Vknޮ XQ/V{홥K~tc"6">-˾%G*~` ֑( eMt l>BB@} U$afb1 O@u &A0;gdUi.g4Z~~~f)=R3D 1ںYyN"v'`uh~Zo,)޼G̳1SžVIXX5_M83&v@$RRT^e֦:iL4No^_}qV#*sfa!.Gw3^U X TG^|?g^V}@bMO'։ǟy2:$PpD0+FxAa\Ów}n,51N7Pkqa[o6|s_ouC8<8a6- D dMi$(eUI<̋.K>uI%4/ #(ĢB*:1F CD48taNG*t a2;з!;He0RJdAR4&Xy =QGoQ5G= nlD8 , `0C"`ݳJ`:܍\H"?-d,HpnЋ?5o$#Z;sF3Zdhl3VVJGP7ѩ9%fϗNX,[s6u[9yaM;8j09%v'sN`{uwM׾^xEL5L[o1{D[Gm"˲ #B0Gd`=(̯NH^Z5`&U%f@7D'K͚8QApNΚ|^e r `U.|fԓrk8e&d^HJDh|r4[z괜߼y^ ></R0sO'+V͜nƄ5)ˠ@6#o\KgrQWnʤ7;VRkmߚ7zwm(g! _ful=b&!4ȨPR&U&844‡-f C Ѱ#VNYG՜'qz#03w IIUF0yn}eJEj|z(}c̬!#K)`8ip3pc{=@غԍ L^J}{S|1GN醮ޓ`L_`L3ݣ'f88![SZ0Ĩ1%J&bD}߾ j=~#;=`?go[kuOuYʤ%Oi/ߩ(iͥ TIP FLiR.UrQa.-} ®4͔S"IIUGA߾}K鴜&Ƨ?go Y4J^ᅧ0 |GIKzzzw^ލGM(5G@5iDomwO4D=@DzQCgdn4ʺW_ H1S8B6G 'Gxq.J?;+{{a"*< O髯R>}zSe~~fv" )`ĥ|)뵔`_[o5\=<<QZc۶CBB9MZ= Ex 'U"@}cloVqdC|c3`A4G1 {$)#HgT5%6Az8 aߟݫ s k3Z/@gOq Ǜ3JT"C=pшȕ8Z}վՔRI?/O~eYDR|F󡬸_E?lmH.Q"ޣ8-">*b+9ZkvHEKɜU^?}8Nmuj̺'XDMܝLӔKyxxx} 9)&"Df(<7qa[x '֦FQ&"nm1sZf:{$'AzpsarQ{ݙKQiwA>?h=;܍~-ޢyN_G}0$`w~'?ٲ<%9 @J2M9%_/zu;;5r DE|>ZJoA_ۮN[Ij*0R'T9tDp" .mR&`VNts9{op'D޻b!=|<o4YKr9#ayzqI=Ĉpw U8"Ǝpxn ,Y̯vM䚴ןZ)])G '%e^yYgGwXH%l5Ƙ{6s8nƘc-3Ez]뾝ϯà ><>vS-4SIZăca `t""x[JYr"UY! pIn_X$ֺ 9SQЋf#aF`B9f&*S"$S.%Y=ڷqQbI%KNhfNQrR?ٛw_}r?_fػ=`XKFVМ 4#sjȤG}ٛT t JG@_/^>q4k-<7(NzpK1X%3_vg^Y@5qDX0FwJhO4>l$nmQ8r9"<)DJR2Ǜ6\G~YIݧW~>K tVx#DLt"F&9%^ FETL燽m߼%ͭ7ѶdXk{c =}x:; <`-nn2qr}C$~Ji-xiy4sU4<Ytz PN9 9Dv9ܭKAIH{ L)50H>/z1h~kd1|z`  $d[8<*@K"n}OiiHm۾XXU9%篾??߿rn^/~WH[oa^fm)MSJx u!bb[?'_~Y:)99 {"/0Bnk4txTaR"%(@y ܡ@x~HY|m<@ pd'0Oa-ЅkiPȀF1{q _q/z W7.K.n@x"H$q u&bf(xtfs{޷sKM>OӜ >8p6QIyYX<1FQ.4pRIDfnu]hYQ@#0 C6nbb(ZuDIsp0DkD#d(4a9 xmm}cbیU,ȷZOv:޷uӬ"¿W//oK X'__+D,Sw2G{sKLs9 8t Gxt 2Br&^}+o* {xG ޭ -6 bxdh݌E" ѬZpr! DLVș0*O8}(^ [`FAdi1xDZ\T5͛ʫǓNsO B1|Lqe|o1`4D S!1+JL,4NkhHF DvJøQQ!*rVmNiDH QCigByT9>@vAȱ*L7j *FvNPS3FKQGDBl9J@ 0aF]`ڻ!V^kklj'ڞ-+jL|}w/M,_>"q*9ĸﱽUrIOes7ݼo<2e'HlPEa g!/so]{칔4d,in$FAqs[ 0ky0D2ABQ}DϷ ;I~_ExIUqC}p9QfܑW7"W^oܮM oC 'A?:?k)0*%X;2 Ϩ C|[tuTNCj{cP@+eI:O*^G" #B#"W SNNМ8)wGs\'!DLG[G G j ہȤ0itw {C-2'aH#Ȃx+a޷GݻYzy_5}Vf}ڷϥ;}C¨G" 3q}kQ &RN3NcN6SPѭ8J!ʳߺt[sY#% 4pP!aGa38Ͼ>jY&`H(ܽ7s\"2 "^rDTrV:R% ֭p>և gD+x%lNVׁXgG[AD)*t|Ii}oۈ[k:סq^?dO?ꗗ|#:*unZ?RMY^'?onr;=_N Cpa2M}xAQFͽD=n-yAP2)pdIdVu4Tr(!tWUfȚٽuI1dڴ|Σw:;ɓ*0tZu9 F責F)Eeu֘oyY>"z(r$t8E҉Qǰ =\lZ^Χ&}v +Mz8򮭵۱AxJU1%MIDATwXd<*R$:O8B,kr@Y`4%iWr3|eޗHQ:Gd^C%j Bs/eފ鈌 W0l(RW xѥ]h.h3Q vȅ Է{ۅ4-JMl0xw3p|~۷~:Yom{Z;?07sb!\j]G2K@ŝU-Oo{%șsRJȦGzZZZϾxz$ BݫUHQ(K)oNO?yz|:^a>5wtIE4sOr%I9%RCpi!² YH13Q)%J, cppi.E%_;1TuUl5wFٹbRCAD5ؐx,!N$Iϡ6FDr'/Gc۶ǧ”EI 0B~meZ{?(@qE eS)YNOjRphLƋLd*+RN͇f1#/7%K*xY׹l\<E ʩGXmdF?| V-6ڶ=,InVձ%b~1knm<_޿Qa)o[\L0F[ubk̋exL$岵,6̙*b0euh(ǰS0m<"|!8NZ̷}stQU%=npuy"K}nFz-R :|yʢ!6TdREtyˈzs̫nn >3ᬍݝnx ̣in9jP)kd1z_򫯿z|zx~0+*B(i3%EDZkF,2L 9hIV  +'^9e97o"e98u MJ/fJv,HDDg9r۾oZW~XQjfjJ,/MtG#k5E$+7[eY+HL'pͦJ(_Z-ưp@Pܧ/`H/])%&{@'d1@^i?x)7!*0-AI "S$/.b^g *A|S@-y`g[*0ӥ]êAђ8|w}6џ~[?_.c|Fm:a!Av>p\%4ɆlYߏ1Rϔv_OOUT'ctsw03<r3[~CF~\1:Iw;q| h~>"]&_~{qf;*zZ!ɍ{W/RgBrz3 [@)moÆ͛{#r9Ia} 3s"\R'q-M,2>>5i9ξ%;qܟg EWqU۷pۑ%詖o+W'Kxn~>z.Z5'"|Zzl_CP/"nvN-$anVeRI~ov;=^C58!*Cr !RP73m\BZJqǗ2EؐL`p )";r^$)*wBئk1[뭏1͛07k<ޝ#aomZpXOGh齷 pu=D0ҲPU>Rf}~Msr<xuQ\AWnv<92˾#޷?ftT<|T8 椱q:z~ou"_񾑡/E .uIJ%D,r˒-j6e^=Đx.y.~!0U] -B44Wu]1fTRˢཌྷJ*QAE4t9X}Td5޲s-[} ZsFܮh.sE+lχ{6<% Xel";{"۰}߇Y.J֒"NuYaPg7w{=풶 *J།;>3,j2*r?Z#bHzLB#n'xuAΤnd\{%" UTU,-aE֔ FCFQ0"T+l| .Q-PmvE>zSs[2^%70!**` ,q!1FAE3-0I+G>1VUm̨:3W1VwQ + ^_|7y<=-vO?;UfJD]Q$G /f#L::)ڕMc)PNxES9;) ^s]-1Ca'3&=8beEIR {Go^R X 銡W8i!Wj"gNπ%6:x׍ J]$CqS ʨ=*OSLJg?r鵜}Zsq]WU!-MvۘK#LqgM{zYvE b!;A!4 oD,dyւC1z1p9$ nK)VPIUE<q!ϜX>"-Ym?Wt\?}|Тs/O?7 uA 5s6"湛=;)rm`%0/<^3HvY_!(a~s8kنuw cֲ,z/ϟ.>ޚ,q.! !Jz ,U2ߜWHecJQ?z|8a9hwq|,`)Ǡٺ^΍0?;?ÄstƔv^ou =5TMw= w[_|/ffއZD6ޞ-&03wqwqwqwqwqwqwqwqwqetIENDB`nip2-8.7.1/share/nip2/data/examples/framing/framing_corner.png0000644000175000017500000004232413351443023021150 00000000000000PNG  IHDRc IDATxD[$ےd'#GUH z GCgpdUWs2lv'"d?~||xm@FzEVft؀{vV`ȽUQ҈:%%1fZcu#,R i۠LCpb,+ 2l dGwfHvAF2k-(+ Ĺ̈;aLHF{W2 1 j 2fbFq=j|ekdPڴG% 4?5>5X3S ܽ#ketisoda͈{F@ R0$<%H2Ɉ{!IA nAX U = I)~xw #"VS8[TfC5ADfH+ #͈DEd3  zD2&@#;ޗx  lubѱ2v` ;Th' ؒdRL8m`2H a-"3qUapGL*a$P32J&]e#D,mE7x$^XQc]gF:Bfٓ4{%C̙2j 'H(`t$3&ӆ]hdȈ+.L{__QuusS"X{PVD0r۲Aᬄ0y^\6#)۸A}gd̾ΙɊ  c\q\#x$ %]d僑Q2 W2q`π&n[$332:kuyz>!VYΫzǶuX˞׻ FG82YzO/yze Xke\wD}~~l<>L\{KƵ 3γXIUUcVWeu,i>>?N?_&ck_Ќ툈@&=@!>_~jY?~MG=Q%r>jk= \03\/(2CʬȨ̻ȈdXUfDqz䪣VeVOgp`\5 5V>L6ӟ9FDZg|>=sBK<"ƒG=M SIzNkwkZV$ "U`H0DԌ32?~?_x>Wc` 5g{\w=DizQd: Ɍ 0y<_זmfw:*Y>ǹܲd}fEpG=_VV}od{$WBZ˴:>U1sknj^_-UVJϯf䯟cQ ,3 {$*ݵ=e&-WF>(}BLEv8\̜d$҆1`P6L3[ ,k;s "x 0 $-#22\UIIWU#4d̵A]i) Zr=ƶлk13a0Ȥ40c deD6m 9g(=r눯^_?c=$X vf WP0P % 螁+o[2`mko&200)Mp-3{:e w`OP04#p\ӧ[X~z~Fp <ktIaX2 I$E]Î(F%Ojd)@ݙA+H}}Yz_?YdˠH<lm[&5{ 33sWT!N&l8!`뺏YlE<`ZC7̘̙1̢Cs:\ %FEh, m [&`P0md>/&<D-:{dyD ݑAD !qeF)J $g_ t=I71GF);`F4j6>?mN"$;hd°ʙ:֊ n@cOU#2o-&}\cY `Z)q?UkU;vs$< wW\^3# చ*\{Vʰ{ژ~ rUyTģ"Ӧ ETƂ)IR%Q0>tخDsU- 2w7-i렺3$ Hq]#fDlI`2XA1}TfVi$?huT՗ꎪ%c=z~[4\y\\Gez뵯 iH07@:nhBee$zް3A9a#V0@nJ< 2ECXGw`oAnz=4Xe3,#u;b&uEc۳ȌDZfϾ\:얎jA8my3"4<7s D1Kvӎ̈LY)ȫoE1ϯx_ze1|1<*#+ǯ%s,y\>W3}0dc@&Ҍqu\""3lqX4,=׵/+ב"IjlAyExq4Z ޜG;րdpVuUF>&rD֨^pq̈"*[3AFTDck$6^e׌k++/Y4nhp\3d K@+vÂ,Ş-wpO[P,yܗiGf ƽ"Q7fPo3=kEegg/zze-kk:QKy]=59{"C# Ph#%MD5ϒ iGSd% ^ǃaUv/=+Yus`,3- ݻQG-AaΟHȪH+"l!2& G&j|31 I~mFؐ±Jޫ\ʒ<Ӷ4n n8if*5{_ Lڀif#M GA0< ( }UY -_~/o`Z #C$L・\w=ٶ8٦d{ADTI}0&NaG +J#3h4 wݺkUbwg<- ؂)> W9\^k  5z"±a>,Ϯ̪ V`xzϧ<Ɉ.fâdG fJ8([{ue֪ `}l1-HHܶtFFVk?EM!ݫ1o_уu<zwBlxת2kuuVY/ &%\~Op[س(P:ֹZ#3}]MwLu@xZ>_B;٬` (0rUTIFܢ~>3`uK"xW$AuLqc.'$ax}Xa= afvʽU:*N 6V@<XG ({M;3k\\di:qSo\|c9#7ykeW?xܡⱖf}+AEHi$"#~b,~{{QC7伥wpa"8ncXGѭ;:Hm\I̕ dժj`ݰ?+{AJNQ8/Vo̊X(c nlx|̶Tyej:b. R T&eeF"Gj3ZXUCj-[ msQו3e:u];z<`K皙Lvq]1%^GJSYy^ޛ!y\G:=#ZzGjvokHַ|q ~*ʪe T3d-hz&h5한u}s;v7}Y>BMFoi 80ݐFAQ3Uiij.53#y_~eMXKm7LsY#s~~>fhz/DFE⮛@>0+y&2+/ńWQuuߡ f ,]ٙ?qA\)b8=vS0fW`f)xzw^ek*+n02C:ާuTAj @6J'}P~l2HeiByFqdC:-!3}^[2ث 눬3G$G =>JfHu,ܒh2C7iEV!o`f|8`@*Im\ n*WO;"-wKDy_F Sz__/\^f4`g\uH`d0qjX0lbdE0ݾmqfowt/fޕ٫ji!P4 μ=|=;H* pɷ齻Q07&@6nqUOGHɰdB`k|Wo$n*`:\ϛC&~~˿3Tj8=}P8=%'YrUTā|/KM74P#ilnB<Ґ%sA9w|Q'yI~t䒝`"5GQ[⅁2SB˶ccʙ132޵+`'9fK*33JT3:FәARHu_y7"Dđfdtz2oY8FFNͼ$*TzC8}tՃgeHFIZ1c모}s;L=|Jx0x^{3\_Uu>U0$313{tRgɫO7$8R_'su2 ۓY#VuhDIG[v)ZHasW ]>T22e [,f:A@(燤M!2 D(ǣ(Y3KFv"3ϣ@n[wdD.nrZսvmuu=5Z@gE%#ת{Fx约W>Uj]UTLrZEٷbI0a=tLEXB=dxT?2Ht#Bޢs4h{{3W:>k^ດ~T:jc!1s*Bcz9׳zkΠL佩H#V^%bnȼȵ @em"` _[<"DX[n{tkF?*8s_#2kLn2mh07Ȩ طNqO1ʪH&3ӪX*j϶ F\+bue)WCk K֭d-sWR0Ag_y#iglD8`c'|hz{{=oiF{<1:T84S˷GӼ~o\LGp%My#ׯ'pQEƾw%ge3=rÊAD]deFtϵ0UEAʈ ڶfoQ^v;Xpg̪qG"xC3̸uIm } {oRDwT`2BJTbLXӗ|H!ausY2fxQ kd&xO`*ra 8kewǺ*~gL-gM͎hӞ ike͈)VϏCشgHHQ8 cuM02Myz_#dp&о 8mݤ0[LC̼[&"n2d0FV )F-Q ׼NgF=ltS]qcф!Xa$!*edjY-=. ⺚YD*haoߑSk!"X繮:Q_}RuvF<fɌHXM󎬃}^uZn!$9+y1Z,#21hw|}@Z++ؚdCn$=Pq4'`$Hrf||xsE&8j"M0uDz3h`;թ;}5̉}pn`Kd}^'LX,xH􌵻8.G=s-сɴ䠢oo[%hoGm"*0Tbϐ7u{M^Uy[!{Х* s|$ *84\uT IDATi n95#24VGU%q|֘T6@=- [J>5nҚכ]QE6zcc_;cib__+-&z_U8"|םKﭕue ca虬Ló;@܈[ i%@dݭs<֖z=s fZx[`L[ҭݝ2BD!+#ۏDZ<>Y?>?#3@ƚ`9(3@<}vfT@*{z \3Ϗc{<05)E8>Vzޯk:Q?~++fVqOg$I>?jx\#* fT*o$6]mS2mnbzz p-FDFCU$Y,q@x>%Q^ɵG0rA:8xb%u+ɸe |ЈeBoݰ+3X&Bk!y2Pmg(@}GNg$:=_3½I}AVxwuz_ wޗy ak_RGe4X{jO]ݞ@֎Ѱ_{c7җA&{t~{wuYߧS\Crfez FV f$÷!qɂI "*_32+3#`+ fǒcIfU`Ѵ ` ewehY>Z-Ix2NgRϯrVffؘ{q %ݨq\tHdZfU0#44H8UU96Fu#?dU}.k7v34$-UsLԳܱǮ1F5uя}ywl:Ѕ|:C8@ QP[?ay@DE zPH6=l9^ӬgRڷd\͹P]L?( HŨ#l5P,6Sq͙YbAEBsYu^ݎ1 ͰD Øƞ?YKAMvAʬ+Bnd@݄Xt7 #h@4svုcnj؍rlci=(q6`t7q0XsO rK̘;4A5{YLlM X:٩.'{.5߫Ntidf\̇0Q)`l謞/̖9[%:pPL f"$ ?#?ȓs˦gi̥ǧU!`68ulϟC94d?V|/tP gK#@>ӄg|)4!Df.s_C]Ü{l?2! UI޹rQ}7[fs3\&tJu&3c0tu-k_[(-3&&hkK򸪩?jakicv~Y³cO :cz\ tc..>=ve/|?W$!3IάPLf5hDXEQƨ\讪٭>(eˤ$k-Nso 5몈{$Z2Rff&9ftMiR,Ѹ$Oh8]so=ٳҾr4oQn 1o0`tM6lT:9)"gd5)0i5VwlM|M"UvUP]̫blbƐUE̥@ dv99ϨkҟgleÃ~I3^`͞O k=dM&cȆ3f3 t@ U= Ըk;$_AhCbwf`6-DyGwm0soLy7Op'_*$+@6uwKrάh!RhwVyD>gOK!3z!Z0ͭ UEx&ܝT0$Rl ͵oE Rt +$:T@`&{pyW++&Q g8\C}$yf5s,f?JeΌ] m2 tĵVU?׭]1 ï|ט*+3[f 꽎&IwvG563Fusk[ͤ`-nsr-)"QZ }rʢqV]T̲Ϳ) !. ǹ̕)S {-JwTPF*me9.#wWV} %$GdQ O&m{]1R.Olgkk—$DCUMf6k28mU}ӓ-x$mmQUWK$?FޗHՀU@y  1/sL`hKx(m"=DV"{{GO%i*J<;uLu hbWt2[r⏝Ucה/Ӏu#|//J&}GX] .3S7ELUf9;Áˊ 9=>Ck19*$S_i-;cCR5ݻ -c%ǿ.CY׌"c IOmI5 wI+7cO/JSr&ܫ*?U{)!lg#SUyDQr;d>Dd&2-)C\+BFko,3ww ujiMdN`]h}37T7*oy#}Mʺ%T0eU1wwqOBhf-dmJnp]VeqeP~USoMNduҾ*P~ΈŮ;h b2s3L7Qc mWͪb_A}%ÏZPD#vD>&#cU{"daHN)AEN=Q$fIutU?[DZE@ 0m;# 곜Yw=}ȘgZWkyMO#cR< 4~Wq&ORwQ=y*"+d(X-w>Buf;6 ~jv tnc?×$PnE`GVf5;3}O-3H5ȍ)B{9#ʊ0SuG ]fʎD݆?[Jwc}/L3˟Eb.gY1- 5ʬ"[5 ^}@D}w k|ou&"ـ/ޮDg=CZߏAŒ`*!*vu%;=l?3'5=ֵȰue t(bRkWYTSa%9,|JC&B74 7ufFdC~9]~5m`6Hs[q}Ul4@FO!]Kxbӱ$5p﯌]D ,=yQQL 5/PoHim |j\{/}LYDH髫'@f$[fkJU Z;>>_A:lGσߥb^XQ _1&ƕ|3*;}BuFH̊]{@D#;}M' 6 #vu=d*D=ap}|8a6`L>SFwVw3[Y;w禠ZQCv+J}õ ,&>ޕ:ئ`K˖܅jCLTے}_nd@Z{os"kɬ"Fd쌪$(a:'X*t]mƧmyI2~tt%w {6ɪha0RM°$_X$y5*KKPeM?_Q]*}߱ϯgwFuee;R1HL [NP5bd+@Be__w2#_4w5)k#84j69sR}EUWys;Kf OVhǧѝ=êcw~&_?ʺXg?s &Q;Q]Dc{OZfw1ؙqρ){sソ.u߃~"}]7%1ui37e{׃z.v#3+#S|;f)w7QwD^b"θ{_MaY5 OPwD4ѬvQbzzխ-]wUݔ1TǿVs"{Эk,wI}MW@Xޝݴ#3lSn~%꽐"DŽ]nuUe]QyG]AU(!4rO"Yk@]Sۉʌ]U!}ׄ^U/Iu5IMO`'arTS肮ꌺ[nx۟^^GX`hsnfԎbƎ:I7u003 In2 Mof"=~]:OӕE <lNB֙یhu,@[5wjZ#PulJuiU]AaHar8}i _TDˤLҎ$OLL}YrA#S__رױ(}-7yXg)̅adwREyUߍ̈sqO02"U}_}Ge",wV1=lW$u__ӏi|}zCaO5Y'Zn.YE*3Х*f>x~;_ }WU &MG!.lT*W$;AuCZX #b}17eqQ̻2,wpNa,w#L8$[7 $.J.8e}|9Dɦ%~3"wYugRVQꬽvTuii䦚2̽wVuAZë޷L|^I_fG7P&+ʗryv Eò4(E6rJ\>46 [ǹkKekKzE({s g~r'@BԦ^nS8Py~huH%!$} gq1ݹX2S"2"bRݝdo2&j_E&[a$uE?v wڹsz#*@ebW0WUӄP9|c9ٕA/J.&-u;+i(P@gB4~dS)jf!3j.#$5ؙI6ekwr&yVwYFv:(EUeN z13A&サ~56\Gt(s5u@Н;W+LUU1 @(8qDVd|ٱ;kLu%:1oZkynLqPzzMkA8>`(t:u~Vs Fu]W6;01+dzgU]Q w ׻##+;2@ͧއڮÌ5]Y{-4эU` lw_f &"Cf] bGm2<{7Wo*Rt}}] e69ˏ!rǗbO+x'2a]3tÊҗݤ7t2 RW-FWf];}gnάƴ] [O\ԌL30!z9ͫO !$M"@4(w|Gp-BϵWUcnـ1|4’tǁFefFuSFmK+*7'lvGeޢWVdW~8Pn} *EªB0[WDăg~(Eguu FVSτ0 Rk.4fIXGͧF1sTwUiBg\B5QEz/$Q nFʪLu IDAT4izCHeBt=6szzצOIXMfWV TRwhwE5wkuF}ݝU2P#ej(}Q"+"L.-ә!"X@˩IM*2=)O|SO3#2 P237 B׀oKR+#.B;g{gdWj3Hʒ4)17_m^_3)k dBc p{ L LY)50* *DtG5iwP Q] W5DX7+H;dklfi&*Oztڻ;+[,eed+3\y Q̗='TؑݖQ] BhUaӕV3FLhdfv({_*eɞN4v$e(%Ld]3ʌNfpKfΪ;ٽTgŒ\ujF:Jɚd\׍&>mtX$ͨnJ F>&[PDBO_i-%3YfU&MddVuFr,֑Ca^&S#@V9cy<H-H |PEi;+HN42gqkfys\ GHOqE6jr UENk8o&M j `n]((I+sf](0zXGZDI>BJ FB A TvH{f]f $ Mq!Cؽs |@d700m3WEƮ|[.tٚD'AШ| ~e8ެs RIl+a͒,~2j1a{F9FPd㟯.GE 4: k.~IENDB`nip2-8.7.1/share/nip2/data/examples/framing/framing_complex.png0000644000175000017500000031015313351443023021325 00000000000000PNG  IHDRm^ IDATxے$G,{dVݳ+{Vyi[Uf{|L4̈p7 _O^'I۶s2 X5CT&"""$ ~GICE *J03} YUU$@U'CDTx>DD*T5ITYJU uBHjj$` B B,A^KT Ao~OAfR@ "@>dd}P/$H*TExUI2 DUEHV+dV<*JuUU3UeH1"EfYз>M%DZ{|~o߈Z[UkUU T53X 3-NARm 1g=UJDLU*#^dfQbVDde !Qj[$l],Q Ū*Eeq-ND`fN23##8@ `ً* ww}~<#1|nn~9ƀYms5}Ĝ~o?|'U?[VjCv.m"6Fdv5EdǜVn:noG>}ʙGQYvÏ쓣J)@E4fd qc:bUe dddVUU% 9Qۥ".$oS"c.O>gD}E5S@2BzU2+$oUBT_"/C"2ArPQCEdo-`UVf(3Ou׽7f< Iݓ\Te9'gZ:`}q̸ IQ}α~_۹YT51Fy#,wW3q7 `YAG/~D̼P}k"1#@USD vS3U;ͱWDLI>0sUfm;W V7,')Pa1fdD|c U~zcvg1Ï%f|mwP"(bUEkYDf*oY~@&s֜gJ"g#bTb2)0V"v<)EEeyTPQiEẍq<ց?2eW(Y 24xU333m$3CܕI wD͠Ŝe1φa01f&YewTRv1n{f:1sc|<"&;LcA0gU[Z0Q W31羙 T>5* U˚ETXQUD(n K"WH# P}ͭC/1+B)6L \H"+`p:vcDA͕ƈ!ԃ,CA*J@ j*yx8CTj>\b Y*PHTZXلƶdJi !c@&o x64wh*BV @˛4EU(ҷQ PNh)H0.b\EuͰ15LmƢBT6U%Ȏ("I.NNU"PP@{*Y\*`\ btUs[Xc&9bKlMD$BA nR *uӈ ]) *s>aۮ^UÇ U*"&/pd5ܶ8ghU:3 a茁>:yu˪ǜpͼ2I@Wh#!+Y61pZ6t So/F68E90w{UՙQňv UTp+_6uw ooGW)*3!h K"!cs P5d uzPSqjdV.‚H%9yUMvDDffesjaiTqg,W#2$DDef GWD#'5fެmùU;,0_20\gi`e%*^ Gb65c1CU̬8*Ӎf\HI8.*D:Q-Fs(U|<dn3" _4V~OF_dzL}aO՗ E2xG=)'k[}&3c'Y.bǷkyTUW V.b5` 9@dDDs39촋'+sW [ Cuc WCu&ii۶ʈٵEA~VH0|bEN~0ܶMm%gTo?~26ʜov}1JHM;#is9W}8NW'U5wQmW5T*6;TrX'ջ2-Vɚ͚5u]„* w@7w5…|!UQx6ĦMYvbNnuTshheR$(@1lS})T;-pоwUua-udUzb"Bjo#)c ZpwWm"ƪjه̶m7.ҙfrY"*b~Wf6k ~4[u'u9+shD g\Ѽ!Y>7Eܥ\42٪xJSfcn*6㨊D\v1x/NT8jN1l@M3738wffǜU%' $2lc߇7{m߻T<$_~ʱmIc&1(0Rňs}~U?~}߿"r{:PÆ#58x@g8/ܖ U)Ub"rU*099&kT Ji7g曪t xU}JFYln)mF勯xPŌ;;tڷmۖϜ2WUH?6XV޵6T"!ª)33Lbi!9'qVxYRD4dxME}2pU}<@Ud&+1U55#h -e`rm~Gf>L##" efk:*ih!cPU{A"Rʁ °m*|u shҬȇfuGM@eAUmu3^_oU$S&47QKRěhS9~_~oqU/ Ip e9{Ƿ|m?}>}$#˷߾XVVpo"6W圙9Er Wu{i2}="Ԍ2H:笌m vNހlG4hܡ8^uɷ,A>.<:o>.k&! J%=A„FBY1̆yydmaΒ<,71Pױ7>U|Py؆@m=";l޶F z⡨ NujUVXP6۷&nIDfrV$P86t%gt4[fxL۶UQdF YCF2CU bm$, A*MաTl^P$Ĝ₭I&@Ig~yپ,>Dn0HuVTY=h?ՔN NWgzXR~xq9aeԥ! P<1q\L*3@f=(JVgbh 3 B#~?m#H"0bṬqTv!M9Z)Vi."۶8~|Ϳ?3gf+q#Ӈ*2Ï:8Z܋&-yIm]_= bl¨Y]dOĪ n♌8̦~`x12񸻏kS3 > OUUӑ3 U  z/>%@, ?c[sV*)MCۍ y$z>h<&jWUMtQ-XYr%vJv5 X8.˘nZ9 {dE s\o'F1$ 2#0>L;HYuUcSַ.$ך-$AՋLɸUpsݏHևEd_|UYlBzg\㷬I|VRPuAM"MHxoo}q>fbe7VaLƧm7TZAW5߾,h X&촟~۪*=]7y\8F??wFd%{~oDdsΘ윥T.Ӑ49TUlL".fN^(X~$ k )KEg}̊xJ:"bVexf&ڽ|{[;L!KM%Yg(]%&BwI`={jX+ox⬵+J/D ™S N*vJ?HWf`¥?X+:<̧s|]7S[l],V u?m/v7ǁvWm9ge1#&P>UN#D6JT =*q۶]t9kϸ`ISz}kU ~'O㪠7/=mg}H*]>`l3鵽.X'p1W`WU3""/<$'Núp8Q\c1#2Iټ5+ xʌ՘.ZPɦKuaZY$EIM:\+ԕTY>VKWKTQiIAt tY$Ϊ1W9K, $+d>- @Brռ։\Ҿƃ8`.vo& ")tN~YKWT(v'x>_Wj>߿8`ƨ??}:e1h<$o/o?|ލCYy>p wc7R,IY`VzۼaΈ\wɈ"3܆ ]o@*!ڸ "LeqOR\;EvLJ R}i}|jztVӬXn0"bffrd1g{\E)=</|X=YW'SNK]_շNyޖ>.khx-GP'1JñTj6x}3[Zˆy`|`+|^ս_yY;/qA V9I]}Sx%OW|6.r u֎2SUo"seGl//_|l|z}u(Fc3wbf1x,+JR $Uy_~%۸=y ͽ424Sp}h L]WP>;t\ٍ@>xwqCâ9RTX,u‡WH_ƒ5Hܨj4@Vq! H^gM<-}WzriRs4p̈||-ђ=s]*3V;wgs1EhmوEi Pd5Z|Y93ӑJt7S~ [\x{GYv:;Q4-,/(fm+M:g%*_]Af ft?4Ʈ~9zz=+\޿:,cʼ/Cn.L s֣@/_c__?3Yf>T՚=Y@⯲P*i(EnNȚG|~rǾW IDATﯷO}_~m///Bա㮪T &(__>}W_CA͇YSV,&fw\ҏ)9笙k%R;B&ߩVU5A~ڄB&#"y mcc̤bG&̳L TǦj۷%mNN[wTbeu+7keJhB̤M2,;>䜣Anfz%-~뺪N"JNvmޱ>ʄۮkZ){eTts̔D2[dTA 73<&}2$MaNK̘TzϦB/{SDٱeTn"nCzղxJ/BHzmO!grzNDF12ud""̤LDKᛈnGů6o35R -H10vEf5kF/! EUJ33 ?z>}.)V UU`*"ni=`rvŷ+8P?m_ɋ>DD㸾nU6*FxgsH J[zIYɏdѐ6R1Jd>T۸ŜĉޖfO>sp~Ԡr^?~6Ȍ3' ̸>rXJA>X +?gV}~{¶m28Ǘ19oۏ?rSU8$2^ׁ<mۼW"i7|`6V ?o}.6R-_S Լ%&b}"qcw?|ߏJ}vj-Tn۶6i ,]-Ȍ85,p|1oD^h}xUR bkUծ2>kBC{:RHnVJEd4BIpŢRB.qMs,FfQJuRYU@$Ww}vS>zth|2\ )J>:fm<*kv-2sMD*=AڭK~"CͶŖJ']oof³*ccIvvkm֚tmsv5$7R1LT1Pֲ8>J?Q_Esm1jVREU i&D5$3c.fV7[]j)_XG]Pi1jV84Tmo*֘.KxΎ#фlVyV(̨sy<‡T(TfcUс׻ʯĶXP *)+T9`Tb* +"rܬܢOYFȄT;z%5ܶMD@~GFI'FdS)PVuDdi?OﵳZJ99)d#)ק͙¿|"1Ecm3d_Ss7^fdqq#<U \wbjxU9y߿~} }鵪=̻Dŧe~=8!&X@qqx69~j_~xM jCnTj"B)"6l6^K`l6AVϨr ]ŝ8١R./>rdA53ТM5jIj ԏ#E.clvgs >T3W{G)]:u ik'Yg9uhgWQDD<U|Ǔkš:qt79l(ZyKm z{[gDžHl]>tSPB}[•ݬp1<<_߾1olZ%rpml^@?.V\PrsE.CoϷcN7UWS+~3oϷh5LMRA z8ݹ9|x[y O 3,W,qlz:0'KHL,RsƬ9;Is -@x7!۾_4%8Tz|$}(.9&\`:H^eƪR^j8ʀDnJ/CYغ rlHkĂ^jUyf9b[$->a ;0+*"gy͚ g-q빘}<wG@k;Y3 yB"zx3`Ͳ z&UdB}KJV]2pq {heҮهȌ8LuETC\ gAdn`%,bǟcŏo}&Y^c˔nj`@C8*1~ Q9N6mR# 2UdF =F udk~Dò,+,~Q?QL/(vz\_ יRN,@2yyV&%P y*N1 ̨$7]ǰBE!Tq*}7^9 3:89+AL23.Jw6pͼfxY>x/o?}$s#T0V^Zò&E.9C!yY3sZ 1B 瓛q3OZ}Y̌Y@{>;ED яZtg2{qpP}AV/>4&:'9EVBO`CEUzDzSs㦢Ofcx1 FDgP)D1U"0ܣ 5"~~ode}ͷ"ǝoo~jD??m.c3D\ɜԛSc8.z؆a=?D)TREzΕMf֠VxtLu,IU;dGHÄ^ (jSO2o|'݅Z'D 3✁ 8.[)ksW3N~cXHFN>6ܝUAIe_č](!p1iBTGǏs)Ed#0 `3!觫t 4Pɳ|D2}ZVϕN.":~IT]j9L|T]¥k=șe_k̓.i##,R[miv4.?ZksNUuwUnw n[Q,, @D O %Qs\[v@Gs)Nd9Zj]x4؋ 9ƧX^=L4t潛SBB)er_`f|'gV^7 ?9;1sNT&eןG =H b3<HW<\ 1 G*{&ׄV BD!.KYuEU{8:R O"r\n=}۶!c/2LGz].G檧u]Wm;^xo>YJGz@ S Lچ WA [FjArv>q(0ݾy2m)GE$ΫօY0idyḰu3sfUb" Ð!Bx2}aIiy6޷Rla$VIl| %(Rl̴ (GoölK&ֻY|atH)WEoz*Dp:~㼇G7, Db溔|"I%A")Ks:!r nQ$_^H荐PaoGfQTyqj4wpc2PJ  Ҧp21!,2~v0uPH",iJaBtz:4̬Z% Sﭵ)gRRj+ϻߚsUvJ*tχ5w~l%fNKxpp專R߿>m#XzY-5 pD0H7HOf Esa @D /I%4L`w<ٙ0^5tZGJӢj\|r̶mQniHE4,*zZݬFcR~BnHuUD0c 6<\Egc2bJw䆱sQMdρ Vs1]Hm{U 6Eڼ}o!hJ;%g-?G8,VT݄u=-LDJO** 튩"&`~뺆ΉQ[es2HƷt(Ox<>jf+7xEuGQ'ލ腈oEwޮ[Z "R$Cfe!ƽO$Ec9n ZED d۶$l_3p'ZּsDJ#%țSM 1E šk-i7yn v&AqxEXz{HpNl:ĹMAT2f1%!891q0v(G&`ܥbI`޲cw<"BD="ZJc]A{8Vd=iFP= ?Ylc&AmIhWqBq0`4&367"c|8&&EaN=ȹG9MyʺJfT kߏh p2wBe)clˣ crd1`N*iaiLp /tGlfvLNRyS#@l&ꎨ0WUmvwm@h s^Ea=3Tuc:)*U' e"DR˚V\@XR 0\'D0Gb O߆sS&.+6c+g "3%# ~b~xeǖlvԡqEh9W^jpɲt{h&"Dnf4g>ts=YSʧ2mQ]RJo.$IB> Q7澀@as˂w~zZKFf#)%~VH8n#Xjxs`-=P̭aBO+137ĢLLP":y6 T@rn2Kax>0GEtje 90}} e!&%Vfv{ `Q9m)V.Blp837>v n :+ s ' xH蹈۞`2 T9RD'M rG{DI!#z=E(T KHL}sdxDCȗe.@5g#E"*Am!b )?b?;qg~DmϓOo~-s:-FP?l6MsN1~wJ-dIȽ]OW>sEd>{1 (!@˗دqJm9I$˲|W~yꋄoWAHoW]c%,(HlRŽ8(W9'(U)R3ZRJN=dN$mt5 a CpcT9ϣpD-4n"3eicc!19`h4R0=a,J-Tf0'GD "vnю<#"Ba[DNyƫ\\r"ORovk H1|CtB)_H4dԥ[r^+mH:2Df*$BJN"R*9(Cʥt*CPуP 4 -CNjR} bĹ#POQ)9Mab0) {X5EṾGYug$`1$z! fd_aEbԡk@Y0 g4&yY/^JHKTNFq<bĢe01 ԲĀ\ /eh=-x=3|If#IhSa<9ʅ'>).kE%,= c$2P#0FE+3ǐ򇁻qJqwD"wM .Ӗ fpJ)nyr"lAL:EW$ =Þ2LJ!ND"CejHЪ'`"A)Ddpe `)Ua᠁w dm IR [ݎʗz8v?>Q?̜$ #7ѡ`ϖpeyA1| %[ 1 G.Ǵ%J1}A=~ (DNZjjJ1OiEdq"">(q&ҕ\OMȃryLHqis8!aZn|>3ywid,"Ii |j,ZefHB#HZ%ˣy[̩#z~?ʷN%gY-n`RtR"^ʢp`wgeVH4nH'7 Pa)Y\JYE9`.KKJT ,"n&NL،PDDvMQrd(EJhGw,cT;IZ5'Յ޽ {/0\"}p*q*"`͔4m&@=̬1pp*/_w>z0.H4u*1A*0ڃ EeL4R$T8zv0#J)kb{7 %|:N{ΉDd]Rʶmqww?# @Umy M' =9E9Eԝ[KLu9,һa@(Zhpw&w#vfmo|x>tÏcYLP9e1 뺞'-`&,WonMU{n=7N," QC "ʨU2Q7n&3V꒞nr^XY']5E^]V]a)\'#MDXYX1G*HMRjcfQRNpr1IO[wlSvʱmNjQE1PN@ CA ATJ wpPndT]EJSv퀧պf'vne Mv'whpU2:uYT}4PE6Rgg"hkD)N/n[찂?W~Zz:NZ #UUTe۶y{r>#b\.z\JھMk]T͛7o^.rv"^k}mn7www^Zm_~zw`ح1]ypYrFnpʉ |57'ZIHM<)d˱,)TXQ=Q"."[wn IĨdїֻKQݷ2GgYA)ɂH,iab]ײm<J8<e"sV_ C~,TKHW*f ~acܝ\ꢅ;x;c*WUy4~!vwj',̏4 Z<LD1Z4qC"Rݢ*ET к.ڟhԺD_"<_lnDZIʟPf&`2k7tHE*S[v>C .97=`z?G>_?juYT9e_}o۶!BTjE[k˪>,w)9oy(W}iJ} m|'sв,o6R\ZiLO?w)=Yr;Jaf-ͨS?of=.njlǹd-ţ%`|π1GB|ӹpADpnK@$YYD[{i%a DS7wt݄d +gD&" tﭵ{iޠ؜ }]Y}J'Qڛn7ſt[Rix:qʶ̺YPyΩf;t`8$DrA-c#BEJ2nxR@ '/<'O9{m6}]h̵mۡaj]u|Yk-?1m8?txdяQ%YYg ) n뾹;?>|5ff2'7mۻ;$-<8ZQ2mg*TBN` kaR- K!)S]Vњ粜K=iREhV U DI9aDK)X/#fvupn* =eI4騞u>Lijl )$G!faC . 4ȴ,½w'_jYj>[~{?ԼWNֺJ]%*R0J<;ANy@%ZUda04`Iw߷MKPc#(s%+!g8YD fqYr @hmK_ؒ1-*@fC)+.˲>Vju 9O(Q};E)\ Z,% ZkRwg=ӗJS'o{7BP7* /hܥ "R\[k]:h#}nlU)0͍!tjfN=,;$!;[jj9>yxp$Qmo[Cv!L*})6"n{LZ1DJǽZZJZʮ`XᜫQDgy3jiI{W 'J\c}_?BpwRùpEȢg1eA,e;6) i3Bęͬa$8YR7=>h0v;B\( 81J7~\X "z0wU*r=UbP1axU WIZYxIv8GjmDB$GZ "rO8+_ҡӣlG2Xpb+EƱo"j ND16m'Kx-J wT8C0W49]~~9AVBZ&Kbmz|\-K%b'瑲GDUeY@ g78.J1LJ̀BDO D),幜f(USf;#ezR}=T/[~wm##R Ke%(Hq'!x4^3 X)(+@8z+ /ӽtAͮ8˗뷘>-@ZU1z:C*!)C_BR-P&*Ց,fpT8ɿG\Zf9hEDYF,xJ|~3»̜leݝD4P8-̙zCEjt2ǭ;%ߐ5J`:Ql"'Y2UB"E4O=c-Z:eў+YmdfnS媔t,ֺZmKItw뭵{QN2Ǽܻ'N5M*fo*t>UC0)ȍEu]yſҿ'_|4w޺Eu*u~L̜zdO9R>#K,HUI@d6%rRđO=[ hzx s2C.Zuo~_JÏ@J`YD{&G 9 @eYw&Qa ɋl/$E>mĔoka9C)pz kyFb} &gehI"Ґ[G/ -B`ʓ`"e,/9)R 'OjkyTNV  ҩV Gn&dPTUHykP Q 3#R0òuYe!bwLJV =BvۋZ -: <ݘX"CND?trߛvf6pjD"HUn o?/Մ|OFjyjYDAr8;uZYk]6cfJ.hi=3':bYz>Cny۶2_D3wHD'0jɰ0 ]逐iqDX7! O>RVo}_;e Mf3 ``Rz99e= 2ǓGʷPj)U=n, fBp-_Ʉ>!2s'z@&>~z#\% 7Q3GkR ߶߶OU<'M9Jz7C7 (J) JFr pnnN%'txPs2J'^\Vft(8Ӛ`w{g_7HK1w&\d=s -˲ڰvZ q]R|]WJIzEr:us4m)\v/!aUTx_{Mňy߷ 9(TS[ΡyL ⬢/i{ek3i=494m~w/uv3eEyzP،{=V? 69R>ŭ z>۶/KnQk5t9~ (33nʹZՒަ3^DDQk6׭/lZS)%EW"E -pir&&I”h)5",Vپ 2i=Is@(eHy3[wK5c˗J_Y'>*&ܞͺբ"v#D wAfeʩ0.UJ2}_Tq޶zMVsD'1,r7{$Id}k; ?` +jf=@T~eGx{zI=zz-i-n3cS1ۗ_DsV3k}w]Z%\9.6s"6mV/}j#{Ͷjf洄n- E q A,SD4#޺#)CDzA?6fjtRE^9.XjF~Kǩ)=֚I ?)"9-6xcs#-{l% 2JGRU"[]Z#ݽ^٨y<_1|ZBȊ$u\p7aզ 13"^v=?1ŗV.0Hզmc qRRZp;[Bi C > ofnp"DD%0sด̱Ϗ')|i. f2]ZdiP+;/n,Uf^W4ԖцX%}De[WTuƶ= 1\n!"eXʟ &R2{Zj>(p?mL$*\RŶmc$}GAAݏ+Q'4{#⧟~B2S3OR)"x.aYd$鋭Q`euˡe:Ϲ΍kEHT%JN?sc;Z 9E$#߻ޡ1LBr~66x X ʤČ&v7eFƜ6LHQ.\x0 'L9>nօfE=37P!s9-s 1V28R"M/Ԋ*2J3i"Z+۽Ks7#9ŐqoYǏ1#<#==q4\RH EDҚ,'v}B3TU[7BU( 9sLZeGF8|"2#˗/ӟP3~񷷥?UG̪:YT#iCҵaa~M.9Qoz2݅HX33[kv{T=6]4 Pm}F;Qs͉ί/32)p30H|Dv[Zk3q|]bt/>8,คV9&=O\"˲DD1E6mI:הO˒Lh{ﻔ 0#y}:%Yz7b]e[cʣ /\xEVQt^6e.c1e[X\EUYfy۶=sVy{߶-b+y{c9l{E 3;BUZo~XHX CNq…WQA=:~Z> 13gLQ%(X^=q{1![D{?Zk^=UU /I+8#b6p9K}Q>2L{M,D1| Ӗ^e <ǁb('gzez7ϏȨAv{ri晄Y@,=a>ntx2b) ^y#IgqcXLwE̪Rf.fלx<眽wF&=_bɓ]MD#ϹyD B 0 mٓAΔ>aaDD"6υ IHJd$QМ2ٺ0̈́MbISxgjKd"JƞHKLK4ݭ:Q B&O HH& clc ]DT% bPF@ 3CAW{u+P`0p uES\f@dV>Dħif2ӶLɯ_:9N"x[5,f"܋/_xܜ*pP;%}`4rk$pᅰ3Lŋvs C 6՞j)t,yv0{skZ?}4## lz#G:Ù?UidCD4ưid .N}xCs߶.uJP?SS'@GsN[,s˗7e <N#5mwF,^]#'ZfzF/ bZVaD-Kn~ms23܉@J'ƔL?~DFWNK rk?#* Ӝ ^ f29.z#khN;uL+2OWt <>[ wVmb"!"C8z[nudigODx }wv FD_nsV G/\x)lSSwG/QT5\' R}SU1gn{sW5j +hfu]o 1G!u[ X+1Q210LX%̪Tf*4$N95>JJ&%Lfܻ0'v…WQ8k>L*ʢ*v#BN}Q "Ui]n[42RUcH[zZku⥘>E21kM"eH]Q:r]z! ^*(8DHB,,D,/de3P&eXz]p$zKfO n q }}jxYF4:֖EZ97jdcE3ӬfIs9(i1昗…W*$aEx 2e!ϏϿ*/c[źawe`WE;2mmy黻m:,0߷E˧&3euWHC&T5wMDe!brxQX.N<4gnլ dVTNTf,\{,3SsΦDae<:B鉶b]WtaiGd/ U"B*`*7úpuPjBF65; N7E U#0gBqSsV1*$`nQՑhYuRN@fju(as3A*ٶmZ*օ /UU(ض(:Ÿ봰:2i je˲LlD8/ND˲,og#0K5\5~*XuY0G9֠^VXTi|<Hw򇠲,$ .(!OQRUsV*~:DD(BQ 6XBNm>OwRe/b?S܅ÆTD? QiaP$Tl}Uez]~u/\x)x]'G~`ZT['X*/cac3s]zX$<5cf;}q>`ǰ̢{fƲ2AL!$-Z#h*MάVU.\x!FZE"9FȌiaf%DXqR)$*Z6 `  1#D}y$"N 3 $f6#|$H@1-6bƭ3s.\x ֘gfZ`L2™֔YY49H#nʂ #4pwBfGJ5kXtGuXTßpDXU@c{t11qy<ԜX]̌q\ r: y]rYu۶8֣. @9Mk'*5N`nnV|1kkt"RAtcԌw\+Ɉ '3a3ȢsT>815Y._Xaf@DPRǴyV#KD8-?;,f*v AI{aH~|Ƚ6pʵ*vݖYv9u6'ٜVmׯ_pE51Pfysڶmũ+#_g]MN# TX%#m۶@*gY[BD֫3Ȭ|(muvi*~6Mn&*Mfy?_: r1Ѳ"[J^K閪М(/#-ҽo?C[/9ibRDX'ND?[SyLv0s7wU(. /NRD eP5|RCg("0٬W(wc֚ʧ V&jL G9w\MѮuKa2nrӈP=ۡt[@k#"PQDLI--,cr#A,J43(\בu'wE ,bfտ%A"&MKeњjYAm7$p }۶7>ITyZK3Ȓ g&&Ju*ƘsV{*m?؋GFIaO(;ɔ_\DTXQm7$"r ^P\6@`4UCOȘVHT{o=fO?3*PӃ{唈s~d&.JNٟj D~I.\x% eB8$Q(D*1bnND<_me1FkKyܖ%|v8];~>B,SK<~HnKg0{6/i ƶMWpeIDr=O =?|O8 6F9LiO3ss[|z}@,#NyDqXGjdSDX$"m- EY31֥+kmȷcۗ~U ^ [}?K9_2V!@tjÄ0T"{WU1m5Zt"[siwMd&߿{PAIѴ;XDsۭ% /kV:i~ w'3+IoX>ĜnĤ,QE;#rnDz^~Xu#朒%H1"2sOy 3E{ERU,ooX.""#IQꪬ~0>]OQ:2#"bձGϮmI|dD09W>`fQiMGilN@&g"܍*Ҙ:'Zzɭ;eTE[dhoN]Z31%_K ^HbF$9}_^1 &YU DX b ~x~2&ki|z%#bYV&," C(")`3mY}^g6)Z> . PCX%q(g:033##3"`8K?Hal]ޡZk p"2*F=aA'yV_3WN>ջLwfiMۘ[dm?_ /a.}LsRqطWqcw*> @i!mHQ%RwzݞuH<^`PeujDEl vZSEXDDr~?_Z0s`戜sZ|:ܨ2X2R*3۶}y]ZX?;, w:=NNXX4{W!gJQc؜,d}_3p¿DL0/|nFE ;~HnDk]UAZ{<D\,M`lۘsjj &VUDK񭕳S5UVeYU!9fG"6Mg@s .-CUE4}Ѯ[~lg_};|cI 2wU%}\H en33J|8 (@tFksw'ٔ1 si}Y-J|.\W^@UUw_|U̪h'qNLRfu9z'Ojw4*!<ޫGA ̉d><صqj Vfbeә̻W\.jXT*d=~':Cd]ͥͼsΟm{zI"uXu" )D VӢ0 77 mܺDMpDi1ҍ^BFkL b02as=$ԈG`fmeڭP"|g 6"(G'$J"$†or'iB9No~>$IL17ݗMJ$…  b&VnynAU0ȰQ<A v1s&}m9"gu(1ǜ%<9fsNg&tq8I OR8` }en"7 y.\x-3Ψ9ѻc;rtv;YnK@>溮eYGw%㖥?Ǻ0j;VZFUiִHٍ2 H2s9猀UF",}Y4an1m WŅ ]GØsQnQ%*C_K$,514E|p03:@bpk]d1ڢ,fLDF٢RE"2Ӟ 7b&?vZ~c޷XU5az…+TG}s;C,s M/o=+8m21`f3El)*RydrLjAs8-YnӶHkj}n}b4 .\x-whM~jiGM"jU,z/@h02EuYUG+ ̷msq;vwT{D=I349LPfi(眽-* (=<#f!f.KKnǣ>qUO Q…Bf^z=p]m$껪*-a: P%̻mgcH@Zj+X qSb;q8<a+ QъU#D{bfFiZsȰYJ .ȄRhkQh+υ>]^@$L*B"&Bde˫}9HMDz,UzOr #`Kw9lZ M ǜ4UdlOe#Ec){*&q D98)&S(]3 /:ܥs0lpm۞yIu_|mzf*3I]po߹y|δZku6x>u]k7(3{ܿ,Sg%|V}fyN8,aQHBL@}W.ԹFH)EZi3S[%Kko6 jeMX.\xYo]8ŲyT1s3})ҽt+1imtO&At޴ٸU첧c>"\'^k+E…B&v{,\~VVI±[x,Up&=lAL0>gD_jDaVncs۶B5;Q.Jɽ];*ࢨ;/AD}aKu Nbݘlo(}xfnA9VfVᱭaaDƵҗ,KrTNL(X[tHDIXﭱhgfڶ锉L&zks3)ڢ폿ۍē/ ^,[*.DRBޗ*`2m]\ED,@sn$H$MK(*ĄL:(Q15jiifsDg" J&Jfd"sΙ$[km  ahk$5^28MP,a5~vO懖[ NL 'Qd9I(GTɂ2#R(wA>\c1F)(Ll}"eϏg][_烿p_jZS^&V 6;(v^%fI9^@uٗin̶mc yaKFd8oWa8RYx>׳]p%_^eYxeC)GDDM[k~{wYT; fլ:,pgb.Vl۶m&uT f=]+J ̬PGeYT⩋q\r=PUίgEUȪ-v8adjzem!g<3hJ1Q{33N]rj "4\Z.+A bT~f6V;z6" v3 pJWZV UgfcG=[_Dߓ WH{2J~k}.\kQĎ*xD{I޷m`PZCKTM)GjcY:8>-fnIgElwF"QX @T.~5mcYU%ӹpg:>vER .K(ay4AK%ǜ"p&""XYD@ ?U@ZUǨQ,2oDJI˲C1aU!GM8ꜻ 朔^Z9'H믤14ڟ ;ArKdh2f'@mHE$"E5e9\kX0f(lQ\t%u)w(~𴼩'4iW"bmN;'.\Ĝ}7pSݿ,}_jWXˆpwSn@ltf]d#;~@+TQ/E| җeY>>>m;-aS+/\7̨=L F eFܬJUhvv"*qo*K="LGXj*&ZK5z8 +~Wm5\aWٗ:͹pP3[EӜPȈs&/;i^9 {gﲆD{~`&}(sΏ˙s3|7܃e?Έ<=/…çx 轭c"37YRcpKG^UJfsNSS#:HwWQ΋jYyjf=zόFᇯ"2$"=1a]zH~[>\u[7E#vZ"M3-}2*{V5<;TPG+,ۋkדPwL%fz[v]هOGZ"}қ'"-)]1s ^" HU!@D4#F\Z-6"ݭ:5 CGb|pRNfUfY5"=S|fLX w'oནg}<6|f4[-eθpk a &$ħʙBq8)Lf`p[Wp 32#\eLSd#v~̦%Y8U';[k:{1VIYn/\jWNPHDdeWTo$3ݬ\8|" O1}F_.IEpI]県,}=PdxW۴i7i*,Fa]RB3aJm$"Q<1,NʛeimF$7E.sf.iQ)& IDATiKxbf՞H&݃ANO_b'T X޺A `OOLjX!]~. L) 3H͂Q5T>"" 2bѴ%;dLNfS\1^*Bh0 v=1ý}oB뺎9o~۲sNsX^2(aNdzdHmҺ33 z$֖:U$EشS! (:m<8Q@BVj݉xUaS'[yZ1Q UĜG"yN7g/^ tjH^E[XZMDa-:MuvcwomY[|$DLT̥=3UU3*ն}`ܼ@ &U-NwG /#"Ms[\yZ8|TXD`"raF&!aRڀ0J\i:MT'&!Dјrm@}#!5!0nc ,,%fR} EH}iD*A12Z@ZP%aD [x@vm!hKﭻ9a-\pC ++jyEh% b98p FD*cX5'-Ab f0aTj!{+eiK_~\̣Ns dL~'͛D"n[~ pbR@n5Dd=pG y")HȰ.5OFWIN% 5$ǜM7 )`%p?ޫWyz\f'ͷ->D8AQ yXo s<83kO-^3ukKB7ʓ +3p }tZLj/x\XXKqwJ$w>~[ffQbUN&no4:8 ;qKxGgD~4^d'dKkB%1pZmV&R4/뚙ei^z||U k4@ֲ# 5S lZkcR{8H#fVK-+4Uu;NsaHDڰ\EP:^-˲H3B~U ےZ(ܓRitw&ksO'|>NSj&#Jr ª/D$t/~?8Cz#?;}]PEa4wI"`c0K ZqmuWZ1Z0PrVM)X5]̵"Z&{FB'<cc|!"VnJ3@&ίJiQD̤LR*kPS%B۴H`5K4dJB>v,aw cRx py|Z+­a[vm~74}es_w\|!P)EΧq~G{Gϊsww'"[+4ɥ&JUZk{zNT_m魍"YUO+^{i_<`i O*03 QhD+[Dt ,c1 8QD;91pQݓ Zkv e)B ˭9 ֞J /Z"(NٍV\JRE_.eܿu.N޽4!p`^wwa0HQ>ϯmmAUH7$ jZ* Ѯ$8 J@<LJVwW- Ks3r.,JZhtt:ϧΈp:b, ڔ)^f,Fpݖ02evtCDZsNAf#Zd pw kR%|CSmXD0 h-"*"f{fD:E:~Xb8B_ɬ$e^wfKElY|~[2i)aFS:.2s0g>OJ JSGhatXp:"F ga)rw&͆ti35_<^vRl,ob<ϥ(R꫚<<<0EMAk\a8CVnV]{_ "6ŧ~ å1i/íTs0 zQ{u7>Y][n—Enֲ,_IJ,ϻn  je̚M.!P-Ɏ.0`/^^Vz]gnk*6,stxM^i/w?OW8pȋ[^׻Sy7v^| {%³x 1&\չ;@"C>.~o4;Y(t6p 0yN'`@6l_|ETZwq1BY ~_C̏DH~`"D+LE-:3߼wg R`ݻ@ *c0x;[7PBYU\jX/,.˲%)>F7Y399}_/Ul6ZkÚLA%sT橔g.~;~`.>|`㕦22*qhU:뭥#pzP>MHOb>++z#}HDӜ vn)M vJET)UJ)*2SQeY)tY<ɧVUGԁO7[ie" S!"/}!K@[k0'"#23bV_=]U<<<ȫ@=5'eY.Ktu?{?5c؎ w嘈LIY湾˷~4ΧRZ4Ȃ?Yl{3;w~MZ|[?Z{ۭE7 oY^֊; D`g[Ӫq iJ;iv"]omYAT% ?S'Ę:Mn_Z;Oo|kWNj{"s܃I:T|#?{sڸ{}NDξqOJi]Y />vo}Z "{TN2svd)eZTkCU5Ɨ78¿S!x aֈB] gHEN Y4TK) {n Di*>= cgr]誫=7D4̲~JuB-֖vmsNiJYeU|\{0Ŀ}4Y|=I_ \"n[.[̚@D?B_.>L2-buXIG9"eY RښY P"bE0πi&JP"Rcq|~BeqaQg9~'Uֲe,TT~go?*KYGITx8̾kF U_QnGĪ ٚQ F.a}`ͻ=٩:p#|w2|&11F|!-K~^/vkK7r%B"zk"eؓO_}S|w}fe"XPkf23 2ԁ5-EVu&DʣM%{`)Hy)C\§i'seܼAU,r[ܣz1@/}`cOϜ99yz/w|݈x||\p1lgVx<(̲q `|&3Ex[Zo )E`:f5h-m8,ڕV8NeqݓڟM_[k0fTj) k)fac VMvAIUdʶ-ݿu em1=BˮZER욆]' fbF)Z[g WRN5oB5[4Fh밞b 5leE(ZTUX|:uޯr%p^!]Y#?CF^> [{7w 0 o_)EyvKgF%s\k-mi餐6HBě˳`di晝NDAݣdTPw潏dA|˭]*EDhJڲp@t>f\n̕H=,\m!V՛&WyRCr`ZӋf'yif޿z[Z}t2zSb#Bͺ G3,VM|o}.]ۺZis3ۍojEƋ/MEv}03(e_rDxd-f{!–v9cY-R5F>l@n0gg>zc%kzRJ2[Yvu@ĩ%NkRt=ӵHPZA'7|RTB.#HTIEeen 9,zn8pA<'#n[T3cW_)y̗Tyy7TQgeyy/ٮysJhkv?f^esf3c4#hg-ak=5bI < /lik[.(^]]op%Ehmۛg8WpnxJ<1QtOZ+"qosCi7o#Xgf043w"N,i vzvN֪ʼvzPWUǐ+kT)v]WAI׏L|*eHi(NT*JH9/?{8kһșΤ<l} o#*{+^E{TEDzo->n6.܉o_R4OyWNLl棛n:ڛ7ssIr[ IDAT@毑3@ ra%U`iM|pX|x>pόc"ѽʤ6-)"c7x7~9Nv5YtșjGTku{o yJ Yo2;HqQABJW=b=-V feLwn-M9owÊn6U |t\}qbݲ"`Fa {jJ+|޾dJiF(D\kuwfA !Pwcx-E, ]'g C43S8ںeL?S.Vd3A4Շi*i9")"d$E+F_]IJ4܋{y#"fQ;I"†w"+UN16F[)0GIE1481s1m 2?g[au| ߅j `?3c\/Wwja4MEt+EYE7Dp# f0C 2笻N>,o`!(k#S:[ N?7yvhVyiRsa,-/Rtxyr>\_xR QNr( &0,@U ("8>4#Cl({>փg]. Rt::mCL"L)Y'xv纃 <'̦i)kKJ`F*D֗˅@ nhLAnB\j8%y|_> nc|MM'VmGT}xchK6nk6t}c|>yD$޳[BU"nMzm9e"g2<Ͻw"e>᣷G6y8O*:Y%eɪ`UV#  $Ȋy,`l92$pTT.WkmxO 8` RlD$AⴼU חưREH̵΢UU= XmtQ-Gouȼe]q„1wY +A6}7֚141rS۶^V<3OdskQhę[suTBR%|i uUG61ܚ+yw{uvnk"᪥OUY !qʹ<}f_EއS af^TH{SL6F&ꊺT-cYǒCG/yz|4̤_>"'g( yNu D%"De{6LF : $]1 ]ڞRfbX s /=`^Wz}V2keb rw'Hr;ZKk33"0@O|^VSqz|! xx Pbԕ{f,kC`NUxQ y#eMK_5p̧DlPlRD6fΪ7s8!"敟Jr)w oY9EĠJEWW˺z#y%WgZ+ .Nt*YSocyjF`Q& B SmD  K0h6MOE7|7GDxfl܌{h>͹c"HM|A"c@PhQ'݊.}1xx盲ev~VV{CNH-k~QShp#SL+d>R|.{kMUUeww-T+<$"*$U2fj{گElAɓᑢ1Ʋ,1Fk-3|n0Fpw*1ot|&q__y/_?j*х7*rU.۔#ªy}{6HfO8T̜q8Z ѝr[-s;':z 1matpjr*EE<֪iǞT !8}t &D :1r)=pN 8$ybbr7BZY-fzoǿ6e(qNɂffFLf2ذlP4ULgAZO Lu7{Sjl=Y;kխZUTE+i޹; "BLPɰz!H_8ȃw?pCfw酐]4FОGS{^33(RK2{N}Rx< D?bRֺzx9s+" iF#b#snw2fv3RnCn_E̹M@BFX̲7r/^>0e{z)P[0s&d)/[108?uʗSLn+B69) [ͭT7yHΘzF[r"B40"뷆[]pVP-UTKQU= f)Vv属*2v8Qi?x-vMX9h"ҧ5v>jU9e8o74JhiK,|2bxK5#}tZ=&KIAO#&rεɇyb`]-v}DxlEKk;0Q snݷqoW)~/b"" {o̜*"ǾV"Lw_R٠"Ippy*<<-0 ZPMs1\68Y>/0dl1h ȚFi>mAIT$ZGKR6,[73=\5NJYNYoafZk ߷Tr$^TgP0󰑙=\TJqDYfp< V(dlΐ}'"M{)%3빵^\iie"#0`՚Džc< <m@1!Zl'$\9nDei-r^{=pk7wi8JFY2@Hy7Rdx @TiҢ9h ww^o`Df*j4)eY܍lY˲dVWC6̈QU,nޓߋ8pCEj!m[.aUYfm.KK+Qf.$` 2#" qf;gwz>iELTue͒*z yU @ ȫ2ZԢԒc)JLtioArL '1n>F^> mDPʛr}}ּ,"{~y+aկ2W^z:◌)SDV!zn-A\ lZ9+FlrS{_W+Iz\.7"%WgUHaVJUwJԠ)S A?WWM|KݵZOb6rjXoٞm jCߊքAZ/DYOPLSXTWe1_^#!"5i?[G{32MD1ޗeLKR ܶive@$iJ163YPm ̏_>ozIttL"Gͧ[iU ˯lAܽ&"/_^˲ }1zָHD)El::ӲL`.Qѽ7U&)HLgQ*Ixe.Y<`"厠ޮzk ~H(AmzɝZw+Kx' &JDXpi)^˲|N},*T+2~c`}Vl玗%(e"+}Mj|B~/&2m_ޓ07; r<>>.˂g2,g@^2AgQSMri1M%_<ȂZ)9+ٰS-p/An6l@0RYƗhAZŁTaB`wSk'"PڷpdxGͫltj͚׈S~kF,4fycY8Cbϧ[o|xx(`\˗TJєF4opYD<7>^%ͯ"Ί  1Wu'?>ᖶ\~-+5TJ%C?&0H|\=/I_0[zHm5_|cHeYei:MSw^VeU+LSyZT41٭SV/?C=Iaګ78ƿ{gGÝYiJVΧ<O^};=] z3(dk!&rއo01MG͸^o׾0d 3F-+TT>FS0R#kDPZc(]Iںmp Z'Zj-]*7k#-3TxW?ʧzSU-/ &pjYH.~ے \U1fZ+-ۡ ,[̬)ϧSEQ0~?o~}ӷ… 8͵&3[{7u ߷pAHY˲ZyNgRydRJ)]vI*J@R,?Oaɫz[k̈9[9 s4 D,VmYFo/_J"RDV\C߅ 1֕ \m۶L[ GD7W@ ʆ֚H!73&=QJ)nêjx͖"9uHavH=I:M,R|ڶ '+f…ςpS`VEZ[ k!͆jx=5Y뺪T3ںct1HMBC8e2 !ڹ/ |8y63(/xXewwlm*w_ @a4B l="DDMes0dYugb裻YJ;~.\@Z2>$s =֚[´;/o#q3=e֌,Pkkl.\LPu AB3[fp[#0D&Pka4[Z'`z+2A qDDt@Rh]"swr?Lf[z4.\@<ֈEe9a9~1aV3SMiftY=Yg8S|5R[>"C"2ݳ: Ru즶\ o[[Z'v…ςp(us ੫:bu 6yyn>Ƿu]4"jNeJ-33x(Kɭ]N!APw_`w }7%(NXG "!=;}$TgɄ;ؔ(=O3,:M(s}:9.,v…ς"Ze**N'ĩ0G޵ֺ? #\/gf`}ړIa!igP"He FHxVRVom"lj:t" Ji.]Å mjԘ]EdYGbQz凜eYR%="Mms2ɕbJUUͷelEꍙPW˩s~MDֱg JSߵ,<{?iSD`>8uyG6 ffA IF'ozú i s@@͍|2yTKk~KxZʤyWXI3xZ[+na6M~/IYM\b > { ?5)inH+"\#Ӵh]WHi"bX~0 z0RLjR0Ƙi"L4Kᖘ4H)e[g1FW…߄,CwG6`ـ=!p%"BcĶ pE "0WiR@К"n@ۦ}}+F#xksmyP櫻 n JRH8YZHn>6/\DpRjm32`4K0J@kuYl ޭG_^^o! {׶m<RW!Ĉ[@U=rTX ŀmϥɵ%p3Y)aN* L t\1Ӕ:db'3?brD2 f5otw"L,2Mm&DdtK^D(NA}DJ!a[U/\LQq2c$pwny1,Y##'Do۷o`|ȧ+f#%_J)?" >䁴=H…O5%`3#'5ۥS HO翀@Dl]s)[niCCsY5"{){4a kkmK){/b6в1h'1;a+VӜ O%Ddn4d# 8lv=1ﳏ$$U&h"bY3η9<,%"<,t"뺜.\G)dzRϥaF/(w9 Tۮ;MtD("nvx:0L|~` pgls[tSc"~qw|Nϳ}H9=ObԁQJPu躭z\#y#"xzP\ߩU3J*Ӵ*ZdHY2M!)+br,'[6Q/˲nxu[7p3uP\…σ\З^oiV[O I%eJ5~HEM%XRQe YwTI=NX3}<ٺa5BX9zSmTզiGNt/eÅ }fq߃C³9 ,8 "q}zD))؋]@GIɈHCΊy㲟 %$1FbF ɳii.:n~6~§Z"":Zt͊w*)ւc!M~_{ǿ2!졭pz센 إB,oy1ƻTUF~g. ^_[Fn[.\L@Poߞ_uɨ&sJ=,+RSuv T93YK-ϮvhRA]w[eQ.{BCW,ҙKjmMgDž jM轈Ԗg؏^ _̂h_,IDDC5Rj)T!C "2Ti<<TT: icw[:=Hi)5m"… 8CO{kS5%FJIUO)u݆*N=nk u{P g~BMD盝clہ#:XBLR~qK}Wn.\ p_c,=dY&Iwȡ=oz<ᚶ%DB&d&$40&'BX@tí uY7(e~}y3)w6tYek-Dx'BC#p iI#p ԐhQDG8Lx@R} _"-%o #tʅZj60[w7@kDdpb)jַIӽʅlYWׅ >|RY'"4 # dt]`@HnLHUT #G6pfi'm#&J)E DPDtgRk2.h'%DIEۺ}Rnmvl' ~hB5 9nduhaf&)̌t) bO)6M$T:M=5UAy|^ ё ǫH<{ڶMufD5!//…τ4b ,\ϥ F}cʥSR,Dj:KeA$w8"@fnb?!JE=ƤPJAˆZ#'ofwy]p"ۗ/maJRt…"Ri~-z$ߣuT F#bS\Zn;e({v$":aqgpT>J[ex10 U&]u[<[{yXLS .V2tbBUU_?(=ޮt'f`fZy4cZ9`$m]! mc#"y(0KRǬ7m1R!>ȹv > "E0KC;e-'Qgjʵ4uxnч&n CUX-G9xAP>+O fIk`7B1'.UF(S x~y\H':1uji EJ)ssc"s]1hl:, TV Zkm۶o?232X;P`AdN>Zա,üLwnVҀúpADPEũ4 A`)Ap7Nҩ t\*@PNp1jm<{{{ORަF.몪:4+|…OdZŞT!]% ~m[}%1LDn:z뺩Z AĔ'Tl(cy^MtSbyÞ"ZB݆nD\Jf_p7!3)#"IIcRq }ww&6mAnAc(G#LiK}yf&5߬ڔ;Aȗ85 \kc\kr&&n{D\~.|{81cDXk NYwOшz yA}8e[w@8-oKKPY0 "Ss+RR 57sF > RcE""ϧ-qO{ȩ,S5+{.FD,RKi+"4_ء߭ ;<-8bLt@DUs:aku|fD%ky24Ř"afIE„*sKz_p?07^s;w54WseRJ!DT5 j>@C)`yCDmfFam2H1Xk80!Ca]Y̬#EKdg$:^ɃiE@1.%d.UԇA8LSZʜOpO^wφ|'{1Fҩ1txW վ""w/\"n\hY& BYH=T}td]׵1dșF Hp xUIͬqn%J+D$ˤϬy"rZY{|{<u]h/օ wx1sY#" |J)|CU2pW>P9#)y?4N D4ݗ ˯_p?_Z4"nzǰmu(o`Oƒ厏j{U)E ]jm\{R;c~[(q7yZ|ly AWo_?1M!^A.|"G ;"B`ĬC# eR,K6\.!\ށnZ仒/ Dsl a,f9eÕtG Qx0m[_~gn4#… {_ERՄD}SU7 3?rJ\ fVz ɀiN0ض-U#Qav>:x00Ə/UפݓSUUD?)yDX.|:|˲<ϵ}C*Oh롴,Y7Nu9E#GV~0*LЀlH>_zI?a5*1Tǥp!+/_^DHt=@TfNV3ƀ+?n4U}7Χﯯ/yocS {ko';앎@/_ ?<3Hpᑧ3<bŒfĹ; X0`FfR"QDj6E`*Up}cYV3˄Zk ʹ03Cx<m۲Yp0c^.|* ЭmCw"UU:ܓ-rnc6U1tnfAE !֦i: j-:O1Cfm䲬[jٙ1С~QX.|.0s)kkOBC1FDDdSD(|OYRRp)'EtpzȺ In@4k!aR5=E΀fǯ… i Lu+!islwqՇ(̜ }eYK6_ĄH\m1`L <'xD D$aq7H)4M"=|R7nĥúp %8 h F7f%ɬzc?~8&r ՀP*P("L{ߍ O}W>%纀#TĨ [_e 5ͺkiWpӀ@̺᪽)a8j J}VyYwP%DD0b ut m*04<vjWxxm}C0>4M6To"fWv0OS-$"@v>zj[流օ $qJ̬N"Zލyr14Rk97{ĻAut{}wSSW5SVCnVDvSw}x~J6Mn|S Bm+pyǀeuKT(J-i0e65);CBdZ)| Djhӗm]e>YP4d;"5۶6MhfC6LcD+()7 R狿po":sWkc[CFwzƘY0"̭PC&K$ӗ/)naC GwUKK9q䲺Qmۺp7beZ>Hb.\T(Ez]U5u$E }՟'M?"b`ipVYr R8 Hցȭ̈́EJZs:~6D!JDзֈ=l~/… M8_:16rf|`;6[&Y[RRP-ϞCǘ{F#rYr*Ԏ"bz1,jTmݞ}f&"IQMU.\<̕/Yhu]W ؚ_nY :';Vˋ:vɯ|lY!H9 0#ή*_=绾mYX`)rߐ\"Fzw".\c QfY^sꪵ1YXkLv*E*T'o<KB͒GDBGAcX9H#G}3VJqp7U7C<"VDTG-w} b!,s![„nBFF|./ZZ2"lv8bmNT#wÙ֭o=T7;"d!aWp3Df ג:K)1Md΂H{NDqC.KDLZ|=_U)l a<3c .n{@²R (6a]L2t6O:#,2R!0(1g;͓i|@nR$v2o|ϥ"=掀*1e\ Q:jغi .\L@RMvo)s?=-N)P !G.vZ63#z7AnO呠@ "j1@r0?k)et}ۈejSvj}a.Rݓ/\Y0R8٫벬˲>^ypZ+3B"g;dؽDT&>?Hv=0^76R/\j=NKxݸ!;= 5͑38'ŬZJM #Q-- zD… ZoRV___{m4APmZ@)& ]>'<{N[vbc@ |u1x L6s]וm|de;{Ew@4#w% ~}KeY cm- ( -3Tv_ 3p^͍qV$G &aa"ppUtL({+R| :Q u8: 30\T9'1{ })B'UkẺN~Hs@hPNcZ>;f挔>&Ν% .Ã!"F_mRDX$}$) >FG@R38ZkH{^Ắf'=w4{(!z:fgj(u\働>d}y3RQ 3Sv1EDKpj4J0w78vl\]W_p $A1F k3s?xͳpuY)EeĻKd k M>$C;{l(P +)xLm"")Xˢ"R ܽ>B1a]i ܘDjm%zߺ\ƶ) VTj/&u%Pt'UӔkE@\&34 EhB2̵OTPP'B!B eYkm曆eF)R'sಷoԽKw}BVwOU "!/3"i#1dwAVBD# E<>09f5;19?wq5\퀈T83G6cY1wNT~{"bfǣXbkمόRAD\˃O⻞uHD8y kk1ՋYU?YUY"4XD"sN~}e_{.Trkpڢ,LLz<ϟ?"Jϊ09Y' ,˲^TdO?c}):9ƾ~-׹Mc>rZYipsfa$se"Ź73}UmMºpT pa9ft֨8x1}Z,㑙G=ϟ?㔚wC'iQ0G3r8ҨGgCHLLOE ww]Or/\!fum%1gj`="JQUNݭKk{5̡G}!3Y2O7z<͕*ӌTETtQedpVޯ %dz""ڲ/z;"N8B3{Gd{ˇwM v1f@D}5^ !v`GV^ J`rkM}{3kQ ?f.:+ˢ#=Sd41M7f$l #&v}JDPڵN(…? Z GxD;鶾ݷpL̺+ZkcLaQLn10TqB3SxyyG2̲𨁯RDZQK3f>LL6FDrJz漽58JGVCrb՟J!cDx-eNVY… `7jLDw&op'cnfnniu,)ixM3D$3ޞӳ=crUgzחuFDuO{/\GMWD,~*Eq*ɟYuE嶮kV[VR5eO9z28e6-9LR(Ns I? VUgUcD溬cK4cfs)/ $6T^ 竑-NVՇmvX!րl^uil}f5QFD#{Vu"1>vPv3ac :%ƶoR"OǺtp &mP.\ @>]5mcHA4OyDYI_ץto>9嶾[w$+qISVNql6mC<}4j{8LiybXy]"sz'tȳ.\==3V~VYm&{ɬ"V{M`Cpzo뺎12  "@E0A[+IgiÑ|ls)h?6`^[+]e";jS½ .\Vv S\U⁧Bt 1OU437P=jšz2Qpx2ӰINdЁRU9Kb*H͹uY nfVac}wK-K~7"j#-1}wēY1􉥫ުaI`&~1%2:+@1 ),lm<}zfdV-3{89Ƙ61/ڍu~̈́.|C8Vվ1p#9oꕒjs7fcz2 #ocffz:aaC0W:28aeUT?6*yl%зT]pᛀ{lr4JsE2Q#UZj-!VαoGtǶkگ~RԆ`QQ#piw&H*X5V ZUOכv5_Gp#22ă42 aܵ鲮`1kowCnz,2 [o%pA̤RmP܃ME/8s%SfF+fï}vE{iS] .(J( ZxYd|yZ{ffp5a,`f$1)ږpÇ"UU+Q@'E2]8ɵ?'I]z6CDU9ܼ]aњY#a]𭀈ZS喊q\~X'KIL}$b9 LfmCDdf `3"2gy ɕ\X %3{32cTԌCD|QT^Z_;^p/GÄ:#IZ cDֲp [k\jbb6F"E5-.,"Y(3UeL"<"TT}}{iIH$GUwWCjɺ <#2c0qEFd8~]̀m|QyUDb:}a9d/**S vp`6Ek$D*դln8e2#gt"қfz[gFf9Ix뀰0_.|K < /`#1hM߽Zki ex V~iatHtsB(IA9 w㰹==lLaVe#NȌ32)#ws7P?w… Z}SMWcuZh0 &XE/ִ-+Ap;EgXһ1BØtOo?z鰕@f,%Bud "d"#3/kPDMD%sw̱_…o )#DϤ:k-Kۛy"30>ط1߷u]) d&2+FEd1X EHgV6Ne33Y'{SbAG2!"G-OӜZE iZ>i)ξdc؍(>z=6=3w*`Xraf3RO ǺrUU)*:"8˟94}XqHZb/\MP{{_V-D䜾mۜ=@dG$Ai|(+S"ش8Hw"d3uDx<ͼ#[?]Qs{ֲet[,Kk ,ÓY~~8q…tѲtm`9,Kg7Jw꽹/J|(_m#9J{D `K97O3"`bk:g2z"&}ݻat#z934"}\pO՞W{Uw׈/wamŚZ 7}lI>9|jиN@egv+Yd&U~_ ;׶ r+EYHޯc4JkMrYZ+fRU]u]Vǟp…-NÔ:s|ه1Rl/+oۖ>"e :ʟ>gn6x]U&:L. ˈcW93YHE 'e68qĬD*# As*PFkݷ_HeXĒ9L,p7 w.Z4I۲tQ1vJk…o6Q96 EX(! /)bf6 @*2w[m?0b%foowNĜ beP.ֈW. w~ [fnӲlp<3rkp[Q~w?}6#r⋡G#0c;@[o(s zz?ض cH;r Uu;v.ǒ * ؘ/+Q"J2 "P)mW=vK…?D$,lgpNsXͰSü1=#w ֻ٪9qˈhϡ\j#"LdEj2[+bY[A`0L$L9}c / $,ˢIlmuwVsef>=ܽ~$223SD~iz@ !sz΄[7Zs3P3PƲ1(teRf̖fI8 ?хpŸ bTpQ~X^U¡,j{KnT#ҷ}gfd999oۇߍi31t&sŹ9lET Ľw/r s9 $ʋeI $8ﰇ0숫)k8+Ɠ*PĖf~y9gwo~m'.Öƙ,Q1BIRDD4mkkKTeƾ71Bۭew7DFP@I`a'KUiD|Fs{Ke9B%ooURփ4"Y&8'owY6ʤ*ȃwGnLmٜE .| d9V\xIk~1qڀ"#[kJwc07??>p$q2vpyS npw5%4]Xyc-=oN 3iq…x!wgac.癠G_vfa",D3+Yf>|PR1kD"kl%Nz+T$JL>9sp'$~ +…o9&1FB$D <1QJaDn6%U$%gw4T^D_O,3A\V)&$dۜ9ڝ b $2CD"… "Oc(w(*_1YU#grD'v[$܀֖x 0?vqNUyᎈSBzS9mΌmnї44[., ;5\.\GD<)RU <<Q "/;YgM{{{f)LNm0i=-\ÇP֤Z 1r\9#<(fa.  GH>CJ ZZ_ɯgKP(Cm:Q$=ӧOŚEW]5=5J9VDRZܖM= \3ET}4W… (dX""LçX%@H cwyu `wfU{Ĝs& 0"(8ĚcLrf9v>" zvp. Or/\gbM3@w:MYcSs0Oӽ/3-2A,22就ɘc {H'qȘD:h bpۺ.}}aŘ#œ 9$ Ks>.O Nya&p&fl- t ޅ'|lΔLS}q(2ADLWędH3iyn*2uU5fˈ*uhfT5N\Œ)=˱^A$\.|C @Er|LUhLJ%@TsDucz5'yX - X8qDZkcd"2Fx"U3eFdXۜmHml, 1Ƙ۶J1$ʌlUAZtEfѪew·L(d%ڸ{O@V<䪈O>"{޽+֋Y`Dz^_K\F\ C)!F&#Xq,$1PYB|34"ĭ*3tU%mYn&ƘKu731̜u] cC OD'3LcǶomO axH׌=Z]|W dH&t 0̰ 2]_|ڒ8Iҗ7FȾM'.\W#<ԗU;6mc͵GfH EL73AkBȉҝϿ0[-ͧ3EvP&6]  #U1?O FȦ.>MmT{ …  "o03a.3tf!&01苭S_΁@ d[߽{ylsjNv,JP&[ug6"Yf! iHfcpΙtzD0';kdpfl^n cX>|/‘}x?D%Z{< }ߙ26᯷۶o>5Mό}afQ[m~n33lpOD{kڨS_eg1S< JdziE*x Jg$@g~+bo6]/L2ifƢ 3 m e !D$ұW%:SUU48=4c6=")O|]И̼ј v[W^9x493*("0#3)"対wӵݏJ@Dz4[[kܧ徬{f.fSo nL$u{?OpD`&,"YTL 9$$ K֙%rOws pW˲,uCeY.ooosGBxm/Um#ޗ}ƘL92Nīv%! Dű]X*3#[Od]}ߙv=YQv[F9s9[kwr<oOZG_ U[w/w Zgww>^S駄tO1+VˋgF @LHwu Ih)DHRMx{{c TV&ՕQ6g.uRb AA >U 6(a٤nK-3/M)U>7i(޽._׵иyRE؜uQDǾ0AHcǢS(מf;o[Fkjnιݺfnh"ʤRfJf 1"BCY[s #e$"U`D1 :j )9ux|Y0ưu%ACR?.f(Z=zkBWLo&!9"sr0,9ÏnFd,pO'L8j͹6}F s` r%ψbe`lAM|<6$<PhM 99#swߟ6B7M~៑.~û%UR}_?Z{}>R]+ᢛ]H_ח:D#!*n2[Qk)iR`Zg, 65Ț~f6)-Yh]߈=23Y{}VAmcݷ-T#HHXMPO em&*L:h*,sN"M¾ \Tn̼mKnYd6q֦*_LU%"X }Qbˆ'Fc?*x^_~_B!it$ H̒񉙉AAY- @}&ߤkֹ5 P0v[(@ fn5ST~TO_1XnsT#UN"EDX{-?~\<)#3)E WZkNLZZZz%|32Y(C2SLPbf6mGp8추?(w IipOG@Ċj*9 vuA92E@AB0wgpF<ٟIY֚G9DXHLՎuC|N"D}pMIFDO0w !e "{o?ƸY v?AqUw@R>Ũ+}*،2FzdD>'U j+ЍSU t*;kҢ#6X4YXA>>}Eb%IǶ_%. IDATMs@ɩf J@>Һs 8̦cF}]T&1kc$Rc߶h5D(gfMOcBgh }m!Dh m]3sһv}˿n]&hPkCRoM[C߅ee,GHn.J; %zk]&UfD "$4%hb7.Wߤ/cE`!pz[RT& 7ėxۈhD8=Hצ:ƠZJ P@a.ˆ#$Bf*QpOxF HV83cJڗQ]=XG& sX]/f011GdeYx kIAXj_AAE[FB O$g*uĄeLd !pqdGF$"9Dos"z|R~Z2"} R" t$§!X>Ffڜ s1sрk"Rrvws5pwQՈPei¬ aZT6mM«JP*&QayYh1_>1vV'mo>m}]n %v{.*afcP1//3߲DnQ3s-u=^޽ zYw$VybACDik|{{{ߺ(8L pRDp#1WxXaLhRUw43wbaF_͹gJӍS9_6-U[H;G̘vjTŌh>;*333k@ S,jIFfS`N a$"&t8X?AĜ\][f 1¨_0$n7%GD1_ ԝw:wi=i½%mәacT)p4=#82#辍nܔiKgRO~ Brw:   %#KQT##vXI *:FU[O}*R2SM~UJ:>"fVtj39,|>EPQPQf#NUx־m,@%fHȗg{ DU_n/wD>#kom"GՈʨ,ö́J٢(aʪ<|wlq46ԇ Zym*!iU*L3nQ5 v(ZWd:XBP-EP﷡LsΙde+4>)R9y@u1SED"H*e Ɍ #2Ӭs{:hzȞ^j6NeK *t4vfJi)vo-3\F~.#jۺ{Z~ a_E{6i @zNtgd?O a(Gb2 / j, *$ut۰WAecfAUݸH w i-΄X"ϵ4\"Վৄ#8D@H.`g}߿~_ۿ~}_^r?o۷oPedlCm'{!^s 6𾧕jfk*\YQ~6BKc~zE<bVy!2>|R5LOAZݝΈ OVM3ULOEX%U)"3\ !,V⌌1ڶДk'ǥ:y*0R!(TU4LFn"dk˵QYWі-p0mXK76]@Fd̉kf?k2# ~3Xh$8Ded9q%ڭD SO] T@4L'B)5B$ at/BD2@%D~J`Bvm&=/* B{E&sDDX_gy:W^̌ g9geN0I Us: *}lZPG4cȧx_nCY`2Xy}hY5g;QTlX$B%H7Qڝ\j.X>1X*}竲h 0q>Zx۶>O/}S"2*e|Ͽt?|y=PN"TQ.bP)Iiwi?L6Ci! E6,Kl?m"%"RrGU&"ݷ3d ~Vy5q*P o*9~Fm6TU}J Ϩl (bHV7э_eEUyMEܭ vEbayVVoU'4ˉ1433 g)7B}S*.QIAC"QȬ˺hpIR@2]Y!S E* RB=:+@nYmHVw0""L!RuJYUGL* w!03*ns>L.5gOTblJtǬ1ϓdUwwY׊}Xe 0>~ Joۜq%7 ^7!^]#"X"f:jccdaàhˊ**A$!ooooEʬ>~/!!`Im*f/퟿,%v" C̘J>l e[SI_>}sqGUǼ&$*і![vDIjTݽ DIu̠B*,ZfBu%Ծ/u (c3"mXe.=d7P"G&JPmSH,짆Ow!='ѐS@mX*?c2HdhgM+bՕ'(YaixZRl;/aԀ(>L#TM 4PeF&<ђB;+zꋡj+eHU16vAMIEiW,SBSqHFBaQCG}YvJh/2M+?FH9j(R(p~?}@<^ǰM؎=7M}{<%"#<3ޏW3e1jfɚ՟7\;3C52"}@ ᨒ3461g1q&rP?!$xGdo?_>}n%TFo;?|@*ģJ E%Ȃŧ/QU[+@?[fT2T)T_EN5 yj[f,*S#l*BmN&^\Va=[U\P1wmPdf[d pU qI/#'xYI,O6~c36fy۶-1L?">LQm"!B_[SmXe~zp:y>CUꓟӋ)-n۸㼺2QU(fbz>h*mDtmʶ}X bJ*ѡ{dx&{,gKz"[Gr"?yL̘$ #W#ѐrI j‘'ٯطm@"[zj|{|Cau3Pg<]-\1=;|=b0P(BEu5]"oh m@ i:z͘j U(Zs"H붘 5XIPgYWRUE!3Pi*1L ΖSS&^fB#(D,,ay#[Xk9WCVVSgaȶmFA!ӭa+USVBz,*UY\r2<UBUŌ*|p)浛>yXb"=Zn .fqz~8޷b/ouabx@9qʕVK%QZö~bO;(A gԌs_}fO/Ӱyf@dU32Uq&dSժHm kG#c{d0\Y(|c R լS0zZ7=SN(TC*-2g;oݫ"[AĠgd*ch5:}ĴD(, .UꋂlG!a&zuA?+}~Nꙹ8;(Ek)7/*yNZKb2{P#yN?3Bټ`DfeyFE+<"EDFB,\VX[YդJE `H3\Y8OW 4U(T٩-%QeDvu9:W$Y(H!"#ELfBgt4 1{4''e%8K[ l6?=IPΪ̬,TCIT7T[ JȠx|^E3}ض:>߿#hc˴f1RD}JΚN2#[^=7M.t)D>RT5Q7'$}23 <;!]ec{}y𷷷v3镩f=ڀTf[Dܷ[\v^\qUf:LE {!%4-kyۺoY}f.wsx:O]:][KZuupm^腞TDkfE*&"-Pgf8*[`u=/]mǶmsv}=*'yG޶Rj-DO23ocFŜlv&nq?fC@4J]yclœ7b}T1u̽,RE~I4{$EMP*U P&DW=DN. Y|5""$Ki]l] Sn~~NB"ߤh%c4"n|kFZ."~"k۶1\ 6Xg*2`ΙmM[ֵdז93eYg&zߕAľP?cۿsv6!-OB>݇iDEB.i߷c v{yj qGV @mЫ`f<^~O"!5д ;0<= ۶ocQ˱V`U1}n~? ^PaU}swREFy~8>~H<ψlR"t*2gZ|)\jho=<92"QBBf\'D?YB[MG K_ qD 5\;J"Ks7FHP˗Oo_JT$*UOUJ}wE̕4 I8},#Ѿ,vźd (ܫjZ f)`IQ¶-D!^?Sj.;n"A|!a۶3uA= fǏp!9daQq?|P*fC3JxTd$EfTtR0n7QUsN =qAʜ~/~ Uef~8}Z5 f@ R5;TP1ۛv>FVuW!!!~gnnCqՔgxœhA0r,׏Q%q[#Y-h.gG.Z eoYZO<'U;1_A D˸|<-sya}-9 Af6M snIvn>Kt~3!]U&@`vωi2/PU>c͠Deb+r9'S"ҙ}ƹ{D* gJ>t5첻s}h+wsΈTb§0޶M)]r]dS˲̩"D'<6nmx< c:a>ı$dú@⥔sBVnBhlփ3@۴[~}ITE23HY6lf-$T%Usv{B^IE晨&ՁU"mfc/]B/ -ɪܶ]Q6HJ_T򜓐*,(MDES\:*k[ -ePKY/evVG<86$%ZBA}3_^v {fvndDBF 56sN9q}ۺƋ kv'G;c>,J icfgju>QYf5fXQlEC8ب߇*5&b5)Jvʨb$"R!m԰VK w>.Y+G%ϪPLbU^YF+ǀu.y VAzU™UN1ZŪh/V+Ҍ.fƜA KRlm 7nn*LȄML!L%2z$QQafv]HhۦҬc zR&hYB%*a:/2ÛB("XRgj$W]1>`)>Fgem骃5ΰdn-'ۦfoQ#Ӆs~oI"&9^1Cpa%HoRIC&c0R}3"<3s^DfzI`!}$?@yVz5KTr-4b/,8[`""=EdgL??{{ŋ/#{zRU-Gz4&ШJ"EzqS%gi:-"lbzEW )CQ^?"*)F@FTKvzUI)մVT|DTx#F?O뜈*WDb;x,cO'J{&D9j6WI]Sm*DlO!HO>Ok1Ȍ,L٭`ϢxmżT=lw32+Dq.7UBiji6D-zh+{^Y@X?hR%Έfъ%]>Xvf{۶< Wu}.X=sS)uqm~^kVVuǠYW6s?ΪRU/㕿o"u^+SUo:H}gEi~s3[ bjV7%)%K'!Jx9=yN6")HD4ׯngQùHDPuduN?}_2Ŝ}KM;p/±U<$+ ٮN"юj`z)"D]>JȒU2v KF553pRt5JȾ.{e6_cl%7*#Pj-]f1wW~A?z]} Ҝ"'PQ; vO+KR*th@d}^."5Cn/( UUD"Qh szav?8qτHGU7YRTOQ?_Ṍ,U {̪RQ u]bqjmꂥ 'zYd|>UY1#bzp~?̘////^qHrV+xiǙ墼6{a8_lљ JzD'j.Ez=N:f~ DU+li Af{ЪmȥTdwCz%afv-ގc =jO]{`^6cl̜UQQs!YQȕrQ~1Ba ACf'Y0gsQ$ Wrf*:l!UDbox1s^p(BSU ȋe^/3)a~+TYL6H?W&N33fRE1Bdf1jNMD+#޾=HlCV`VPu.g:)ta!B맧k8Hf1YqgUe3XoX"""z$ A*p&s#sI@_~ȟ'C*HO5=;y6}:J?|+bJ(@5-UŌ:EDD*ٗxۗ.oĪJdYgd(dNU!4UU?q)$=T"P VWEH}$m(s{- XGA(zϛHs6`M $EYqLT%B I-V6HU2Xɘ W "WOfXI#h[ Ș瓨ˎl({V?"Td=ݬw` 3;ki`(ǿ߾fD"v9g{sۻl/gRID}r蟊VN6^vy'dm_>ge+G-ٜT ADז4hpj+I @B,vbo孂gf`,#?mAŎuh2}WT_\\Z`?fj˅ͺ m+k% #ԧ-B :J/Vms;VU/x@1U4^&*%CB. |"%{jzk x*X)yԼ(`E3K LVJ6+|}Q\Hf,(Zb1G2Z_ `W?p:S{~:PxYmEjk C`* V0iسh (yf]\ lg1ZGEyO*'[ `ίt΋.Xcj_H -K:#,z8E9*SI  WC;xSqGV!ȬXF0XX8DAf³\/ .Gl. e[Z%% kG^+I]uZI3*s-2d,LG.hMJ Zaf=fhJwK";AaR9: =-+._,yW=NUm9YKю<=Ov+ }U`7[QYN]-6BT473١]9m3\S[KĞmxOr] BEG@EғKVe\7 `f# Ȫ`e==3 GQ2PCdvG͇V;O*D+)6 [A -kxqv'AyGIn_~ފQDsJ[*Ȭ@%YfB6"5'1#Qdf<gcdK+ǶSV?V=e8s$F;*:F[DdR5vwm$fF/IiuC"D ?@S񨵣Myܸʜ@dS l%F~z@Xmj^Fn#&H: +H<5Eg5\ᶂ8Hhv&me $B},,1jm\/X@t ֑k/Uz\LO,VUY9+b`21'kCkdg5L )"Aj=.@YvF; y, 2ۥg,RTau7fȕ|TB Ud"Z8F5:HV'j`ɗrM\-XZ"#.R D#b̊ LѺ?NQ#ۺOm/U"&Zy?ZWiqJǁi2F-`S۶Y7ic6o^iĜ)f)ӡGM ((S |&3|!lD,3> uɮ\fqR$)o^e2xP8 #]^Iг\ Se&`fJV9gT,?U dl߫Z' wf$Uj9/1GͿh,"+qTa֛6M }Ʈʌ k|bWz6=ǘǜTPTmm8:ֱ~o>sf}oΘY0)JHF!2rsgBJ p٥fwa>G_^`'3̺jmºuXꃔ b7K!!HHƬ ;DQQZKzU*w-5o*>2mS5UmI33Rl36GMyL]LUd3`@F3]U$YPN( Hv (YP-$dM(&&V$]gf#/jUjVZD*.`e ~{ϔ4[Į2^ս]uvfR !2K%" W ᒡ v x'$FApS !\1#VƤ&UJBDx#)T2VgDS[ ^9~A'{O浙Rcqﯿ|~w$7Oxf6>ü͹[Bc+ٳ?^"JK|/Js~P'ZjkM[r=–*K%Šy 9*_g]V1mv\L*uJPLKrZ7DRfdmY煦I$᭤paY6ݡD$K2V[a@X A2u1^,4l{o58h&ϤY,S+K1[[vbi# y޴gA褤ֽۖp*O8۾5k$;d3J~SotWjѦQ5O *t/&? }z rf)0ɫd5Z3bV+D-rZJ\EQ* Ihp׶kH@YHʍc+LGESRU\Pb<ۊA>m+.9CWDmca@ %יk?=o\?]ƊȚt] Xݘ/pA(IuNHHU{Zkeg's1Ff]Ik2&JL_2de"_$exAt.tѐ(-LR}Vcyf\ 4F[tUꉸH?!m kVFvBcQLR#nswift@#EVń@e+,/PMHɌW_JWj7k]&-a*Pi~-"}:PFLdoVڬ/-Z(ӪsdjA<-aA$ix1ǹx˕~Y~{=äaID֫-g#Ğ,Jw2E;Xa2;\ 0e5 o.$;(<6xQ;?c;戀'cRX,+lI%G1UT5Tf3d **S7"/iO*դHcXsej5}QR91͈ߕ(Mnjm M_%zx!@4m K{+fEe\(-L%Rˎ?.K*]2𰕈A{ۨG-GI$aXQsڊk D;t4PzaR6 #<R: (cU*SE dJ LB gE,rrճn)Z_bl"FmCAPd GL(X!%Pi!&=m.Qle.3-tGE6a^L-m*iۃ:8+ȈvA~[~ݦe=AK_̹:燈fBdšb*St -]D5Ő 7 3S1yA"ʾnPC%:A[G̵w@(9~nۘVc}MT6,3f /cz]8Z,.tv)3/LDTS:l]PHC3SLQj 2JIAeJ1MY) V=W U)S\R;<ʡvg{ˢM\/㜙xqXy9:+U: jiӦi)al*dn}ekx<9GݵnmգT<Pg\=޶~9 }oaS]B4#j-8{R/\=`d+5 ]۽/I H3;`Ӡ0sZ2yC13jXׄHVK?*Dk]D@uN|tug|osΪ(+*i%4HolBNq̹`augѪZHtEzY|SئٴUu_]]2q;g 3kGG/u ,e$ü)0U]_[^Wsk2cD[:ܘj^]nVw(S| w3_=u.2l۶i'9g<"VkD$>sBD^Fh"}a l$DkgѺ8fȰJ8#çYCA1mZ08:ȦFv0s s^^_7m1}"a="D^^ P~m} wkYȾ"2csqGkpwm{9 "ZU\k 1x<}mKq\7hB [k iNFRecNic܀Ȯm"vϟ?IsDjR635Y^$TTqAQ%喸亓.inz++{F:h"]ʞ QJmVg~Ḕ\7ՍѦ7 }^ფLhŚ2A䬫[{̐cԔVDf ]ǜ6PJ}.^<;[D9k{h{̅pK`fegj,1is߿W@1^^^Zkyǘ9 5%LTTQHIhr- ʼ6%Z$p4"~Ǐ瘋f./9d!y]1j<Pe$\ ֚iK.}kMr${mdh 2晘S5?Je,DDk)ڃEy"Ҝf9 xi[0o?~?扏&ty~ggf= Lȕ6/ZHv%^y %!zy??m^~*0&J$D@ZeAZD!\/ /}DU|gn""l`S /gHCTW6o۷o I[@UY*33 ^EcSlۦ~52"2-p {|WOeG_sBfmBHurc(/ʏ%5T +>i|zRoNbeRDiWܷ"ejSM Jqw*ӭ{Ekj[۶Q'JnZ\ [^ Ww@".c<0kP@H~jܶonQ`Ub1FHQoۖ1qZ< mz33?u3O)IENDB`nip2-8.7.1/share/nip2/data/examples/framing/framing.ws0000644000175000017500000004754713351443023017461 00000000000000 nip2-8.7.1/share/nip2/data/examples/2_point_mosaic/0000755000175000017500000000000013351443023017004 500000000000000nip2-8.7.1/share/nip2/data/examples/2_point_mosaic/full_image.jpg0000644000175000017500000052136613351443023021547 00000000000000JFIFHHCreated with The GIMPC  #!!!$'$ & ! " O!1A"Qaq2B#R3b$rC%4ScDE&5ds?a| $d P6It5Bu\ڤFRsIav88kRB^$O@[* iq9n䍀tEBFZYCNW8ښp#.4T@0r@F/?+.)zJz2Рtڸ7,>T*bT{֤r ig!pGZBAaHRm~U)4^s 89{9K6G\ױKŜUK6'UB2k498I4\ (2j<r0s)" $@\(ǵ{W@gڸ $N=kQzM7 3nsJU!C\"s)[`wsa٧G|oIKyy"ѧZΠSS @i͌׊0Wv$yXf8¼FAߨ\қߛښKiH =*@aθa]Ejt#>R;R',r.r0ºYA85܃YB)W+!ZV5^aIV-RF܊CO֔gڻM7JR S vYs4W98O O8{טs]Q]WٯS|ܭi}^A\-ֽ.M6 /Ɍ0:WGKk8J9T Uݰ;Ut@>rO LU*~P?dj ѼLRE*Gj~qbx餧nFw&yFmuivFHXZƨb-)&CE!r{SQ<9\v8\-c; $EI4;l r=*@'{{rH{KKm"DXa˃fB0񦿇ۃmēڛ4x‚S)f5'(ѹ9Nsvԃ tƑIisM(|?`*@cgBB(cD*i>!OjBXj:ۗV &-!*`o\nFPnH`b8"f*q3gXsOkgxBiF0pA̹ͼ㔰.E4"Q}OTy. Ȓ#7:+#L1ߩݤ>=rFIȨJe"@ m#I֧-$-Vb!GSRԪUaK5l3I Fks޼rORb{wíHvK򐥻WzvgrێHיrA21rKl/)ˬ|C䐌,I?Z(QvcJxAuKG;T8H%ԁh\QJ΄9J![DUS̀?ߵXa-c$!p^Uc||;n#6]ÕzZK1f cܚ7IJqGQw?z|(z-2F!$A..,rVa+gB.Yd2Fyrfoj%Y$Q_SWF`S)\0әHn%q ):8${Q5)9 ~D%p OjnnnR#4`#֡OCiH8ϭ2_fsWcXٓqV)oq2ܙxʬAC䱊+l4ҁ `~SPw (HqS [u, VOaץ뜃Uۛq3O.a~{Ÿ́LU aF\]rCނq!wO w2z(lji>'O3g;{{$$"lp(| -.wjOߕ3MH6Q+$+ٻ}`0f%]M)@dvQe5UϞPތF(S7L;l}36K,q{Im1!b$OGIf!P[K8˒wOfC廙EiWqR$ LXZҝ "LG9})\çJQ."Ov[zr ,Fp׹yT^l`SgcUr2w&vYr3JfP0H\!pv?S .)MA03?F!5,g)Ȩs!H#&A7qj$.|M:3OGy I&Iᑗ|j>aZHF9IzQ s8$Jkj3^cCKEM0A qHY[(:&2Cˍ{Jߓ<˃\+:@-˨`lH9wqOͥw0y{` KRPۉ-pqv M8Pᆱ1><@cƄKkX$NIڔ'6Rk9L1),zb,ҔG}ʤucNܳboĀ|)PʗQ;;1e7, (FJ*O]B1'*| eqӥAk'w-ɷ'n^R5WIn`˹O ri $I p׮3#6yF$^n=L,G $ Rsn#g9\T{ xo݈N;MOU`H=FUAʧ[Ȫ}SYe+ZNE 8.噋r3$R9 gS.7RB$UcxJG1oHGҪ7堁cQrhSjWOߡWa|(Ϙڑk ^vR۵I@`})#_z* -/jSӛ#'ri!qyFN8u_IIGLOZxI :+ATQ7u #zn9ISȩr?:aFRIӯpU/SՖS3q{Q [,.; A{x@rWsߐT["@A9 l*}Ij6: w(LDCLu2&wQLv׭#fS _h)b*ű K늰C'OJ"aJ4\H).UP; Z&y66) WǽtF–{7ZCF5U!q\rwuza+TE~r݊% Nz)HhΑ귨aa4R;UÄtxn`S㍶>taxv{ dɲq~4݈h1(8naqcs9/*~GޣҗQXS^l9=$BX.q"@̗L1za޽r[9 sCr2+WT@82H y 1W3w+q˚V>{WH*o:LZw;kg޽}2tf($S잣cStɛ1lx)'.09Eǧ5Gnts{r=]zYF17_Oz= u-br3!wTx򞸯LB1TRhuc7@ N |ۨX} Y'VW3S2ީ-q,sdOo⽎HJfpzfRycYd(!@oQ{=)‰.n?O;v1tK#ܼki /c <ȋ4FG?]G;zu$Fp3ڦX3xy@U`?*T}ַ&Twj ٷHV=.=aSv ׽\9 @vv5 I*B\Pz=aQڒ)V5eFRM 4j*ޔ!U*)ؐ(*RIF% #S@>45$BF$iǽ((ޯW;'T TS{^R:Ap) `ExLcs޹2#ߨU.pOAJt!bAcwiAy."Ufشy Y:J's W;ҧ7<_h%cMsDuQ8"(9i|njt* PzQ}vXH*zQG׭ llf5W3ݽė21R˾ǽKUıJVM/QvYE>ެ2)#tW l6 Z gb=Ep2|cHgDZE%iVc w߭NxUgI4E-*?ż3I,E Uk2H3u??|XHPЋ|H>[YvIGvMng<܌6,-6=z%f-|֍h,3Hn$xsM ԭXg%vF{Ut]I>ն?_SSMQ {jmT CcJӒ)mӕKoւP\ْx{|j6Z{fv9ڧi ђǢƬ#"Q"jvrr${A^EH"ɓZ@> H=*5ޘ@ V4 Vxj~VY1"g#lDl6@9GJ9(Ft~l/pTaiq,(p޻[Ksu-BJثd`Gj .yu#"Z\"crba C`]*%ڞ"0Ѽ^%A rvR_8ڻ˾stKFP֒á{ z޽^),^Rr0KTa8:rú \Piaq]W"B p5t1\PP=*&qҝ dʗ=V C"썁Mqg0'X8NקDcl3}vVCk}8bvYU~2LoQFv%X䅇1FT_6\lcޭVZeC: xgПIu+O,vTy[/=MOqL nXc|( wQ*4qDQCמif*rh2Z rT5$wnH˖9:twwX7/AF"l6g+n-ᤍ)dZf;-+sb4}Cm"+8VaZ,:Fku`dMrH c1+I4nfdĈ?t%V|bٮy!f e}'a:; P,xwKKhr>n~54iZRQY?U28)UYAT@Zi-U0P4KLPȤCu=ZŶل&zvE@׸vW o#;`7\Mu)zdra]ԣO3i(tu'SUn̔1p?/ޢxBCÛsǽ5&< _{S CQM q:c:}m#^cOzqSA*E,,'D 2$=̄d~jmkIƃQm33rޫZʳ=1$*IۭV'ӭcʁIg-ȡISUoynlU@QOګR…j0,wjSdt*>PҒƗ\ߛWI#ҽ^-j]xg!PI8EK{eH^W{TYD/*}oޜOtmڽ\r?:ٮ@`'"S̏')ImUM+*$Z{P-׺3 !#|׽,r/ڗr]|($`ƳNK m ]Qe3"VHYOT!u[3b?KСr>4&=P>Čtu9ގ-(Ѯ?b0Nbk)_RjJÕ,S€p<.=YZiGXoNis/9::T ^[sV!D!V0QIF 2vZjAF K[nl+yEO|5<6ݚ>ʪץN͝w5HZk|^XT((n?qy,٨'\q:oQN62xG&{Ba58|e=@֧g:\ͫUϷԴ0/`sާrli ho “`6ԍ+e 3q(yyG]7ρZH,OYjVEcmIn6K2:\KBF`ʩw3e3>Gu4.Z&'bC^kSԣ3x`g'˅Q~t(T5[un !iazCU`d-ý#CN]d+[ueI1H{WSI8WsJ{wYqJE 0)fa;ԶǕL*u_%Nix5SL̤|k 7.Xu= w:ӊ6aRN9RnAiO4ǔS9I*ܸ*ؑۘdEaђ" 㙇iP$PGWvTzQuI/6 WyyjFdunzeR}ƁW*f: @Fԉui[h˟+p;ӡKO׍7M(R$ю:'ԃgWKK˟6<L+u"$xN% Zh+4R\Vqi4taL&7^e *85F ۚ+ʞ[x})2_ߐecHDsQgHFj~.X\gWډW.DXp''Wv6:Fmkk(299?{O͈dMd-edXf<ўՉ[f0d9u畺:]$цIR9%i;M "(l!E$A2*<0r?,CݍIam1oX OdІ^:  _zmdia4xIzq@ZtFKyʎ/'ȿR VFU\hdlQC6 F{ҢWK. of  J+Hd!RP1_6!kzR';8Ə˟uaXܞ½rqډ[V9s4XxP$ON)hXX\RGښD. # "$f,RS;TR-czd@T%A-md;ƒN%"%"<ָ9 Q@Z5'}k 1 ~UV/|0XءRYS$ *]wcSi/L{|Hd!`` NԸAhZm/$,lE҈[w@*]jΪ3r0 ?((D+5NNS(VeaCҚ+7j9 \-I48K)$8+دb jTsj<2LEڢyt;̡iA65frr=בJUҙ\`d! (IȬB|]i1.{)O'`r>߇^5OK9t;ۛ9GWs#P{i22n74KQ׮ b\)8oc4X] lqS,u })MYYΒ$tǵHgFBu/حX-mnZ4_ @_¦ydz 2Mqi;{$.e`4䎇$0Z+ OR~U[8ď*LTf7\q >&+ ϊG?X,sMOr{ ~Й/|޼t (ickƽQ+8w6v,]glӒ(oi!^!宕.@ DX$)^ (%v5'O77[ÿWcn*P;bo գ= ӭ0c]NR4,ƞQƕs⧃'vo,6M$vkXC\4w>ViY?MיŔy?\vl5-ou@2 K<#l=*DZa1"nT;Ycnzr;ۻXmtGefRxٗF$I#asj3[Gk,!!0M6ڮ9H][6A؃hk1 nHYAȥ( 2Oj~"IH2 ?R6asƤjp-cۚcttF;ZY5叛1t{~OduF9p Ad$2{׹iYv As$jNp@ϭ:놻sфfK[\x9[ }AR߭6Ҭѽ*utUUoГk5Qކ]< @;چߐa:t:VsLvSKd2=-& Mjuec=z( 3a"dOSTnwbW*[j9\4s`ιI>ié=Q<V,2e}\4Y\FI(\QiI̽=JF(=<4Ic)iF9ڟW LIxhIڗ:ojl"lWEvq0*37bHؙ93ކ]+f7>:t"K7MeI߮Ni`b(˪0 Fl3zz'dѡVԧE#(F=wt< r>ۆha4YM:hz2i\zJi l';zV{.ueCo6,5~衙1\BLl#[^KD䕖 R5[׋75hBw `^r7%ۥm aikqX9rѫS,]Ɍ9rO/(^xZcLTlC7Hw~ch^LU${U; CKKvY3U-O `~b,q]  ^ %~lSb%8JZq(nTd1EY.~˟0آWՃKk I'2/* nqNזr@=hGi1\@LlZTl(2KȀ7Zܗr}*4 EarrT:{{7:?yF:rA5/{Y™vipijaL scUu^Ps餐n2SRY-Sq4Rgrq™o4)I"9зCO%Rxzk[,$FzS𼖊ܗu洑և <4bMv{ag:Fá^HC5ٻRb Im%EdPyPyP~t.Lĵ c;|GVI8CPg)`_\Vd6D3ҡޣˎ+ʤc=jt *X\v֤*zHRTVWV3I֭{7ߑb-]j%@1,V>ɥ@;{Ձ,`,`P"a~4s*gX+ƙ5U}J&.U|7PjŧJP&-BB;z@u UAyz4x48J1\FdQ&:Us8p%yqDa}t*ӳ%`@;`b ߭)ֺ=6^JOojmiɧ `ʡkD~4kq2}MHnK~rvzmR/Nђvo4b̝jiZ8hUnX*8wAE 72?~Q4a-bDD =8<8W }{sc%HF]$7Vtq4ͤH$ʂ9{SVZOk:x7F |}a%uc9ĶҴ-Sڕaj%ϋ_j[rSX}&Ncխ7y~*cq7p}W;zzPܯ4wO)bwճ d.ZdL43̘?ڡO@ wn;s:pWڪ“^xMogޫ9kA+yIsʾP2I0}JX}tܙCL@ʆޜ`8UjiEgggD͞aon<DZTۆg3E?kK*ccU^72$`̿.N#m;# l_"to1m:櫥Km+[K%1Bv载$(`;=*OUGt ~c.R-ל5E\!HO6ױaP{ MJgG!H_BKM´S>ǡOit\0)᝗sR< LR,7o.T-Li vLW':Ҭ;zu cԏΙWit+sKɞi!CqEr%RPa:_*eb){|dbB{RpQש$clΪX2;<rwD$:-ħfsjjgqTwޥx\K`6G>RUe=c[Gi!SU+F|'WYbB`zn:+sfܠ҄r|6B9juQ%bzz и|+]ΡRp+FdU8Rl _k$(ss IE@ f2a~ǯ^U09zc54¨͔ଣ'ʩ 0/7^ /CM`m]cp>𧾏/I/q .:޵x5XمeHAgNU&>kW/ј8S hb]Qˡ#Ǧ>uO3o)7n{l׫nQ4bOLT[,pXwaRӘƼWs84Sf0<3BNK,ϭYJЃҜMN8HFG4{MI#{Y\Cƃ!e`6Vs˪r$GrߗΏ^MnGR?Q6gU__r= Vu˛x"R0;7],vpk _wl䓷J3@L4%O.d򲲇c]kzPksWng(Ǚ*kM)ܕA9kԒܚPjH\goJ{D@`Niyd%'2TNzT\7*Ǟ`AQA%Hzxl06?Jb2L; {593r`:jvY9Ze>AQ {߽_oJyV 9}TTFaN2z `ںFs! f:qʁq]?URXHi ) nTy )J1"TmI#$m곫39ʪڝçNzyHU[ %S?xU~X/_4[ԄFѨ`0Ns}?:t%55?Uq̮~U`XEmQ>I1v8=GzEyו9A֘2ǠQڻ޼O"YV0 wfa)j8R `ÙNEp2k+B'0$\Y%A](2E{hϜ8;ڮv@b=EA+DVxeU񨖫gk,slD񆌌Uj% á,;gz-#I7&L\լ[+ H:{ai3)Bjĺlʊ:),R1B4 ՙ"Pw=jVPKCb1 {ֳFGt":&gA̝RA}T+8Vo9jWJ}XI֤q$ {ZE0J( ulz ^v׎q$}J+f9UԚ2`{T6Zz$$/`:0):D NKxU=[?:>l2A/joN)!(pBdg>(ُ>S= {]Ҥ-Agir\NMB8^o5W҂ z|E4:vMm aN)%5ҒN6f9)e )dʃqT(}k?iQSl~<l-P}67h\&ZHB1QKl7jޟ@Ky3xyN@=*;dRásjxR<$7_zcEgpeIKa9 pF R Ydx*Psֱ sM `yOzvUw85bӅrl:.M(NJʝ75fw"9}EFIqGp/[O~C!aZ2ܤ&v pBåTmg|`dtW¹׳I',pklFc_|sFHe~KfrjեZ- r2ަj-$;7%=F&D!PØ|xd5OhP\=*}-63(sTWA#-C=][^$yP Hqi*S<ʽ=}jGͨM09VcsRn D( Ѯm _)q\Ӂ:+==kʲc$}3O\MzWJ13R֘eML9]jHr̄'Md`ڑu"$<0B b$Y)p{ҏ0'+͞v$y_0Ǧj򼇝9@qRޛbHf tt)p)00;Wi%N| [I#`è -w,uxVBo>G#BO4kqn a",;ӑ;KGH=sZ abZt4|+ԙ ji,qtk l)1`7ajI|LԮrAQʽh%$j!WB(J03EQ֪z֘ D8*N7wn$.1ضqCHGrg8=*sk ԋu^_lzJE.[rUZ HX_lP;dv5ӢcJ~rҔ<SGQq͔ -S#yZ$DE =lmS+%;Th 6+Y_ERuqV.-b+gNoGwu$@5+ )m9hNo⥨Un N[d-˓Bq21N*|hrG!*ezMR1ڐq:ז$ۘ%9Q4y|;ywۘiIVW CKЯoY/bY9p z{T^SQln-a+235%D $(sLȥ:UH$ײzxڸ+jBMq֜ Dʙ\ju}bCQ҆o`>S*Pyd<ߵXQRrKJ#J$vbB|"؟J[]%] YUëi슏<ƟXHHǭ5#㸧ǰRYHzdR7NQ"dz&RJ3NFly6SmX wvvIHòc9[ `VUm"褨$Ԍ9aYe`zS 0w4ʰ̠3^O>rӹzuhnPҒ4 3\ N :TN*yAaD#7TqF%d ;vgVy+9vQ(q;NRKr=*3!ɧN1ҥ-sˆuJ0FF !8O -C]UG'Q~g{I*}km;=tn95>`q)*J< P4다涍&Oˆi[¨#@H>|︦gBȣbj-?=lU&bFXzַPͻ-`3E0%ħ4R}5W֤ԵkF\.fy[ğޭl(HهRkFСH7)Gl )+'3q,Ri1 3r]Kg8Y35,~4Ngje6ڻ^8,QA\(NHוitUfѯ٢RḌ=HT5X RXCo?u"c@*˜%gJY׼UU6A'm~qeqfxX.#YA[[DR3DdS<3KT ڞWҜD9#x)I3ls2 e{sne׭XYj6#c`k)RP POY0z`T#U@ڬ\:!lh}WvcVk>KHso^:;\TTQ]\zjHCuLUPtC@`;+>f3"sDgn=qYf>|H"%z X6⪨׎☘VJ+EUbkC VTC=| t?kݢsPcj{FߍQkE-sRH|ERdb[ .;G}ljdqIԼWUFrISHEfhVK9 j3HsCZvIɮ0<~mf\gGkS7tRoڦVi$y"m=Ȗ 2y\MyEmm(נQ<1l &sns@bHՀ'NI`IV+\rˬE5@Ao|´DJ(IvϹ gXPJ.EfhےE)޴'I @:G]Je3}Kyg}NTEPCgGPEܑ1Lp̍ Ӯ2y}Fn$V$ޔхenj~ w&nN7ilng/ `wi9w(9nxv,Hrƒ˒"$Pxez lLn|(3F~|E^#h 22;%a+I0i>嫤o0:ScIPF{Uq1<΀OFTžGW 6$=ʑU:q֠vE; J.ǿDWr"R /5p:_C6\czLy-͜zӝ׏CPJ~fr7+;pѱ% $eфv#"'ڝ[xQIMX saI[lֳ*oiN08v?gQO0GZ{j\t4 {'%!Hو\_b_ϤY~"LgU|tSiGfxWqDU͜Ē), >4mpkØNaHE%#~aoz 5+!獖J@ S;HEri:H ӛ>~gi ̠0%x,E$ PA\רL̮*U6=ǥVPsV'?A=•klnmp"ʵ;Dz-ŒAَMGBdVpzP-n>s&wB ,NE4;nr{FDBD>cj6P(< Mo`,S#48>H|#i 93n'u1)V+>8|8 6z%%)cP48aCGZxF A@d+2DBaCI:ߋ*qbq*OLhȖf8Q;M2 Xs?9sb@15 __$ÔGUXQ<zraRFriè#oSW[8+s MҌgZ2˲ GoJj[ K220r Y3Ld*2HC܁U8}tK^ɖCԶQ=F .ZaS8Pϭӵ+ On]2m5;pq<H/íڙ~`\˿ZpLN[ =z!][rqNx|Ό~a6d䎣ڋjSg m~c(UcjG(##wueLn78{WW^pGgRTm~Drv+WX8 8c';P{Qk)c4Y d'MN Z6;vdY͞v?GׯQʱEAй.9yƚ! ep } aW0{մt,BF2t`{Hy<늲,EOI}挞b@.1X \F ':TqDባC2S}hL03 ȥLZ#0F,fHωq !Ԛ+c{A9g ε8ϦKR~8a4ZUSCBw6*3ϒzsIP$0 #j=cv,tȭxG;=+rDyX-ANpwrq+8 |h%(,ڧֽ:cerns>uv]) 2Ui6Mhm$1U}RRGPsjԐd?ޗ.+&7 #5Ѩ]7w/#jоu88(eSyŁlRZb2#Un&avMgKxןf*qL˧y~t(=s/qQ0=*e) )۳TRh{h$#avr3M"P$bJI \(JQF1@[rVl}+r_OMv"O O*_} P0i6DE;d@>P[vOn_1:R_*1DSLXu爌FULH^l7VSq},(Fujxk !#R-J/00IVK֝ 6FE2{rLC79X|Jm ]>IE_*0T+~lG-ߕ6pppG&"dP- (<<[Z3j{K%= V5eTe̽ z:pD˞VӀMs@W CPgkIz57|VA$̖8e*OJ7ԫkNb1."'(;SV4 #2#ҴM)2r9?+0M؁^ynZ`$ 4`[!Dv?ǩɐff;ribkk{bc(g8hЭ."ncct^$a靉W%Y2[25cwuiҸ ڴn9mr;\E(vqUۥg2JLY\h@gs1wچIp-': #3ӘHɮ/v?/bʬ C`NaS=l3^+W<1ޤB vɫzlA\䓌s[njdB J]qa*sc@|\oUF2v"N\0'&oo-F@ܟzrKAg ʎ c;ze׎db}av+”N)>vi&Xbwn H Y_ 0sF*7$ +SlXqՆ>}^OHy ki31idD۠ .OdǧޕƲYN-\?="i0*|T)W2“G_7 BML=i{b K#I}*fA*BnSvbT)-#P˲w #7 nbOJ` kt\k ;6ऺ`c_ECi LwPgz˻!p+G+du>"HYmsâ?:gp bpQD1URB<9;ѪR~uWhFy;wn KvWcQESץI£ř=IP0=ө  >UhFKiF{oVPAWkq^ K@̏*lwo nj;3;f$.ZtHr1\Yn'ingm]H k)Gӵvd`< w#.K'18 V=9pŲH=jv7*N;]2spڽ cхhV0s֝[(O4(sPu .ŭL89MgݳXb 'J̓(U,Dgaio׈`.vzqҽ/#L8?V=!ѿUƉKo!I]A*rjB#@qM69Ͻ,7+>Zm6"᱿[i%FĹv5@!"8m/Bգ捇1Z$US/Uƅ` pnW#uk[lMHyyP; rC<~$NəܸU W vj<'l#6//1Ƿy}u=Q*'PxKOw>j` E4ճY$v Muo#pG87֞\f؉WԤbvGQ_iag?ރ,c$^h&;jiGl?Q:ivs`5sAo>f<ƌB-rq\%:V}*h9'`OjQ"s"#\3 N+ȦVi`P H˷_Zꀀ(WI^k ,tW"D6&ol(8ǩSHkX+z&0* D95\D xC2ce3Ur{p>˞/jspiUjJ*WR\* Zn7X=j3 l(lszz+%FF Z飍cVZiL0NĺLO;nsU5G3z was {QKh,o%A?e}kfoZKQVu[aͪ2zsq`NܽiF&ļB`Q8yfL9[j,PV/;zWhTʡ29aZ5mn _ezڡݐ|C/mYC[llE@KUEca}֠\#F3d"9'1o7/@h2w0MBcku%1uފ[귳831ƧCm 13PoɑO(*äj@L%0Ty!/.KpZymJ쬒/Bs{c9H4zoUQ\޻^}2'2 .OJ!E)Tc]t jW9FPݿVhMlu:'1 i=!f_˕=ZDDԕnBTY\77O搞W`vT"Ʊ[^h!lw.sOok9e#$;#xÐ{ zQ6׀n]Msz\J9M4UGlW K =lU6)WfpHv _%>|91@?kך2 3@V9 a/>thl@ ƶ4b>'P1R-UVRY|09cĸ9eiA`wʪO0zʑ<=*@ nMkG:tzjPcğ¦k<)'Q)*6;Xܸb1 *+kf72;3"H=Fƛ: ş2nb=L ..$ {I6P+Pze%#5;6 *aL2ϦsXzA1JY{+kn-BF*c`m`j}̒ΐ<~=?tdi*8Asr@u'd%YjteSIoAP&:kULSeOjvD3!SMډVUGz.T*'N[ ڋڣ"d)"w_Xu%EEOTmR#/ky*^tm$ JZP n[Fr:Ud0k6:uIJʑ1lcy|B.NL.7-&-dl ^wRBzoRm^b{$uD2#FRigWCZ ߏM^^]rgQxK пbV*7{4rt1?ts]S 0{9j;Mwi^Hud={R6ǃzԩ)|Brj.U_QZQfw !$UsfZiWMOv5lt!g|R\m˅9G*sBUTVi68l\A&"a 2]QDiU˒pSuS{ve&5&22zӭ 9[.ÖvNrx9F$P1jix+I^W,w]y?Zm@p) yW]Fj lG'qMI.fx*Uh鯋`ޏmdyy\wlbi(sV]c4|B0]I;\r3sۥ,I\ڃ 5ɍzJj ^0y":x\DɑֻODO5gQN$8="fR+?.!@Ԗ$´vʹNsզܫInn 2Hs6;S0ƪ=*N+ÎtRwD:v%"(WLI I~T%"ܞ{y3w$TO3 {c_QV&'a@.yO  @ֵ:6bAKOt0e jwSHbmAuyٹ'޳KUʳy>Lt ؕ0q]$ 6c\ DW)"ia]) |^=*iRly9x!'J=QNET(1D#1K=Zr]N240X8FJƥ$&NR`doRSPٚd15<5vD_P5Ƴ[Rsʻscԋ}7H cM~l*tZΛ]K2c:Qpw햡#GτǕIT]d܁Cto!e#95aSN' AÓwQ.AWs+A9ש+ ¨1\+iELׅa"]1*[-PA^n/U|"Q J],$W{B l \V ]@[H$C\3sC.ʳWhDK"j="N4mT3}qV-Kd5Ibh* i"_HϖU?ALqw޳N&Vnu7CUmFEhX(ҫAR"$ZJ^G/7;V˦i EL7Z6ܹ;*4ʹߩ{WHڠJ6QK/S2(FsJ8^f:WSIѦ)@>rs?7 ߞKvTMhDg˸= )]5[HiNEh9P1DQi_Kj l#Vcn=K}ܑ͸6}iAUq&1Df_H`ހ6Qu{ qVqNXxj XV˅|d-.J8ƌ`A]Kq sW.]<=~KFU&PJ#oƠd~"s6w,%fu,&.Վde qWrMB]Mb`zsT5ZgW6O<^θzESJ)xFJyGʓg V]bv@0+^ Si19"XW2m*JmL#ʪI$4^bPDzzPˌ`(#fjql[Gxa{{ևŮ"=U |Z~_m(Iv *Uh/؅3f I0 htּh/;i,C?hH&Hs+)"JR79jJۮ+̠í k9SZD;xY9rFwΩp(ҏ3~u~Xm]# #sƥQ@ߝk3^+ܑ|cnN ,g=6fjWI⩎)"#r-ޕ!`6S5+w QNeԡ1d{oFg!w hء*($zR%"u xNL]GP@""1h2F޽XjQ'SivҸ<7Sqpxav^^SS$w4(U I$SE&e/Q2j,HYw[~֧%] sRa8.yZY#z?oڪ gēOII//sP) F0Fd򁏕&kuifFY;(1jRꚙF(kMzT.1Ƌsw hKI۰Gl0/9'6_aMI]h7yvI=(RDŶ,l@`Gn4& ޥj:TG>3M^<$ % \YyTa4Qu8QS-6AzR h2Hޠ[dtބ]B"4;T"Ji+YA*vWr]s^ՈGvx` !8s \cڽk1x=ELe8z=XHoOooz,!qª!Rn~teU $ jF渺|jW HjJqāGNĻ/nOg*ܴY^MZ<éRIG6JSsWs]PqZ4mHSeF);T֍< Ƞ*J++sπ:HJ\r0 W8Y0 cjEު!0tsޫ34slg$a ]OUJ wXy:V-k.R2rG|wVW_JyJ I 1R"\d%iݷ #$bG-0vX;lK ~T/i˸$L*>@牴k )]/cN4*>w8){' &f'P|SB܌)-%„(Ð[dLȲFHee8 :֩Y?C"b;gDnUٺjN : ϸ}k1y1T+$ !G)Rw=*L%pc; ciwq*]nP a3<в;Ӧcm5Akv+чVY: #< ⪺֥mc,w?TSy1Ilg7sgq"ğWb$>\VVF,;Vx&ӒkP-klMq,rr`GU$FB`s^с^ ~?j1˧-kX03$n.BxaҮũ2)Nت?ۘԜf~ՙ]mH@9] vf|ސpzSl[ee89ڐ3<Ciq:$QA]?[,\lV4`̬Ƕw)IN9FCJ X$fOMsqrb*/ZռP9. vyCǶc"[tfLaHjNykxq'* s&\Uz ӭF5{ C.5 %#aF#HrISSjp,>UG>#k'^d]ګ&T„KSMB=# v 9WNRܒu + JWp)*Ao̯C^ [oLP۩$m@'$L t~)ඒ9I?I?Jɪ%=a5RׯKҥr ,kLzz%VG<}ID-ln]>rb 8ʻl79 ]%1_ 3(''5 [GCM : 6)$bϦsU{,YWaMD8Z#kRn/(0W%xcH(kA6D6Y 4o$ʼnFmm(A`eY}EwGt9&e;Oj8# h8 'qӽu[שׂ Ir*Hot1sW&t!(6 M}N.}sCnEl${HyWJ7%'^&N+^o58"ʕ‚}Z݀Ⳳ ?QIydg%Kg|Srq҇IcG;TEN TqX1f!P\g0*rtg>l1AP׭t稪İ:czl jx{QFz"SbNgo*Q)o eړ](,)u,l}cGB0ȥKg IJ*ƹ%ުZ,.lfwF@!9ިǚ"z 5Te&Rjn;_#b4Z-ڕg;VwC?搪R&BCQ$._6Ԛ yl}l:TFpNOMVWI$2L]S(5)ԎH/ݮ\mN7һש%u&glPǁa1(PޛB Z0AQ\ShtZd(,CL#CLŻBO9 =mww qd6oB=-#DI ڪVIΒQ64f1'U]&wFS*6N3E1 GREljYq޻jQ@b,l;F^h8X, h;Mnؑ>};+CߵG(P䈤}(卹^Yp{Q8(խהoEH,Lw>@Os=Tj:pi)ml"9vXsqZ4]v8&XexN8we$s?Tksw#psMSH%"J1GlYi/eFf &y?UipE yrT?oۙcd"XZEX^6̷/v:֛w.D;JFrTPOj˓^E kl^ƸKbq╶66rZj,l9V'ª:4:ף'I&()۽Tzc~\ϐ@<_t56HWSO4r> I2ߵ@[K*w&n\zmM5u#=EA.6Hλ9ߙFǷv7!=hK]J.N3Գ᪱tH޲n:6F$~񪣯_HΊ77s* [|ѽJK)ti"Q+}kF^{׃f $aN qrFWU՝֔Ntt s)dUo]eQq]>VvV)oر%BDU0A!SA'KNvuҮM |5XeUlt<&^X2Xxw P"A5.MsxqSu?N\X-Q0AG;(01MA5̟՘ ;@A\P9b:LZt3 `:7LEr_jGm-ŪSӘȨ_ݡu'|qw&ݢ{`oΠEp$#;`~5|:fmc $2)ߥ p<z;r+lk9t̒  ӪIPOz SQ322c]'˔ ֻگk$] ?ˌ*52GŠ4aJ\-3uXE9ŠS$\`g%b#΄. Dy1:m؅ W85ŕɃNOPEvNi9SWXծ[[ TnH~i"F _q{ KY{l?Oʉ:gmx9Ž:'yim>0essY ;6S;sYqjlsrmS|~_Ydѡ 2g-2Y"Vct>-ӼI&$NO1'Hմ]3Zˆnq1޲%uP1\(D'v[2ʢH7Oyy\1fcԓޭ2ՊdWbX#ѤX;g>?.ݪf0YQHQ% 27h{A8JW$p"'rjV+ Hb QYG5/˕ jDuPk+IQ޵VjnjI-5`2bX5{"BQOFVf$1zvsʿOASt˶u _MuPQ#sVKraQ'ҁg'S -;Xzsld@q҇hq͏(A#W9W$] <jh̽w y qhI`9Ҋd TC(Oղ}JR[i<cfr4.Mռw"+D r@W0*V-2_Z,yteF>yi s*}qJb[TxCPX|V5jAqq\7׫uPeV<۩TlrSP-Y󃁰WOF47&sF˜qKg"!TnNcֳ#]F MdxS"/)@Ws0hVZC j rte`*L\) mi< YpGl`zro;bTސ#tWrJzfHҬczRv$WXdbLYOz|E?du*0;ЍKOKH?eoƳDjxV'B6Lڤ4dR22=NH ߨN% W;ޢVLŸN2sLI>UyY_vN drUXx19>j>X(NئҊ"(tE% N2Q5! (Eky =ִ}I.T 7G?ڍvO+bjT%WFќE8;oNXN4~#~nL5NLрP >bY & 9?xtK"^15b9H9AH+ id☒l>f 3jyTW^WӱK6S,Pjx.ˍz#gN /O&2)|+`*.O@*BD#=)4fHGOff>R;]UKe7@Gz4De]۵:!^ncjs4$v>ؓ1AڱxRx$!1RBE&fҮA1LP ʌ)%[.e`rw5ktĴFX(R O 6sּ}(^d.,XV&YHT@ISOiH o"|ZZYxmwoO܈s5#q1piR'q0MF٬C8O]Kb*t6GS|?aA>qO5Wg n\g7hZ6m*[!꫌UY>Y9zr:om mkTs'$S"$z/s 2TګKkpgɈ[jf#(8i[<%Pr3`WImzTyF(41DBFvO/03*hNE|9⡛Wi.#;.X.aYc=fW:m߁ He\b{D͂9GP,l')&k˓,]tEzW Ҽ wRO5PmZۼ!ue#!WNMIӣrďO\w?&*uGQr3TFqyNmC tb%eSrkQOʃa]W,tvlHQH#hv"u!O&5!T(vڶlndh#n\=֙{JkFԔ̰N6k-zds\ lw {g@>S>2倉PȧJ1'';$΂E`rz tۭx u]^IcZa˗(G]:=봆p6k"7$e@>Zv0HV:&4$0?DԹpFTTG8ek\OG[~uP% vLj2 o#c=i-gSB1Tt-$*ɱʇ8?#Q4bb 5@~5yVM3HRN6^;*->$4,If>$lȨsFw5fIٻ@ sEx8Q&ѤLR> ,->?w}ky.ma#gQAvcިw( 93XQ;zM&Ѣ,Ǿr|SETނj]^ {u`FIIt@S 6Zȣv/,6*$zpC+C^X#M98=շLbHlOzj:Eh6KB.% ssΣEeƮ鎔zO 1b'ۺN=rG՚<)4'dFmG,l`7ɨZ2GoU;nd.'W^WnGPrޢ2@ڼqW&VH^Aơ-$`'2Y)nܘsf%yG|z 58kW*~F_X[Q6?SV8T"/( sɩ?ZI9S<ܠˎ`'p{ѡ9%rs O |Edgr,~dxPZ!JשWFP5cG9@*Ne 7c6/ng RQ="MģnQUN> ^//+ʊh֢L9C<ǖ9S  !rk5tb(jAzt{$&NfT`1֑JHAsRvsһ^T7p4^XcS̯&N4Y`| *tzlV%:v Q@d L?q}>'liuvv!ʪҖcB Nrv]Upڹ,'aR֤VPdc46?7'=|6 ^?$L޿1zyYp U8>}8x0΁ {S\$,&āIyI:Sr+"#)ۛ¯1jW|¤ztϙ#F뺵hf.Pݛn²x !;4zUG6~:Tv7JGwip:xx(? i$r0_$to‡.մɎCsi/xnXe90~xf&/O7+\۬L zUnjݚ6U6}xKqzkm%XM/3@\uUksxfnbq1 G},izMњ$TFA'==j7DbVXȽ.hj U~2A.m2q]1S'5).PuЄ-ޫאcU1{XT$N]bSBcR!Q AuMH #NKr l-=?z+#}h|+|* qᣌGqJW孌FA*X*'1wY&3#EH~4bɼaq#n sɻj|SG"ۥrIJz82'yN$29bf^$9B)qru5/޽ WvuY-DgWa5(:ҫK"K boS=#ڝ;g6ā*dLbv>ǔHb1d@UT7||}SN^e(Z=7"p!NT!PRMGU#VmI5P:WO2cA2gOve9":bp9@Ҥ8-oʝuXOj\Jp@AWM6`mD36g'qY⯆o3K!'+;SW ZC֯`7kPeNàUCHxɤfGO"3P~R2=Un),mLR"boG?Zx`ުS8B6>]8iW`\KgtPKZ;mƂMrF`|1a&C#mS%8n#haެv*PV-RqUl17!UcAQMHɅ=M;Rvi՝!Ͽz"o(n tW%/A*`@݅,!Tdt׫\eʑ[>"m)dwhWit-X9|r Sv4ֶ@ d ӚVj6Xd *vڍuYb @clgD rT&Q pq@t:H&3O'|4^FHb0ASk d:?K{x 㘏jjvwέ70MRJ2ЏS,+|1Iwv[rgbH>DgzfdfRrqf$bD?S˃]bsRp !Ԕbjf) X8@h"L,퍔,5wRPG H è}RAߵO1.v;.ftIPF`rE4Ɍ'vRt9R3+CP.Bk!{`1>](i<1VrV?Ě.q6mёh'@7QQ,fͤW@Xd#"-k8ڹOI9W6!2PKD0 z|DĐl:om7ҪZ8 2ݲ1.jrD qE[B[ݛӥӊ"lK ]ʀz2q a8(BXvuq}~죰 MnX6"W*B\9'z\D~YWcӭ* v,jꚦ=B;L^8U^N@"nz6{g|cGү X(b8{F-"e=hݔb#~|k'Fz5kx '|dF'yt.F q:Ƴ沘$VKEhq)T*2ZF؎`zZ#qgfPGMuM.E1iJAY6]Z]DK,]' sE96vϩ,I# U=j>>\:ũ!23FGOQZm3<y>eY# *@Zn7p}=*T0<֭7$9Q춍G⭰iAz;^T@ 8p?O2%ub .Klzk,O'_ƒ+#BpPVku"Oru8DcL--`Kۺ(,ȿq޳-qe(aSϘj''*h! _%튐RC"(WRl1ֆ\H{_+?0jmO9Qfۛm6{s:^q-+'Qr:aU~,@Xٿb, 69B6@#|yEr=t^gNu'b+؅zrL rp ׫)$RTdmR)JWw"BeI$V>%#)7Riiq՜kvߌCXL2=Fs]"'$s @> @lӒ\LT՚6S# w PAw'">=iHT*1zTZ@z\jT3xrާ{lH~|v]lPDҺ1(yc[լz<}@p{JLaU݉6铷z^y@+TyMsO,X%NzEwn<2OWd9'lTV9 }'K=vpT0z}`0ߥEm~dSWmB%yYFX@j F *)ʻ X_$]ɬF9iUI^VU4ڸh$$gƫ=3|}ϣOI,yW\SҐ_XB32 -v,F7W̮`GmZS ra֔1Irnө `a0O`*uLT_Jw}^1#3rZM捣B@.@W;}"E\g}zG9'\WC`)by~Qg#oJo4f^cޔ#Q沽HԃNNzC\+dN zafs|O6ql1t脄*D0wIKgҶQ2v׍#(簤$66ַ7x6FAX_-ƛo1D.ӭ:e%.TG&mchm#KryPJnXl942-$0Gl*,,k*ZAXrczPM!Cǥgre9Qyǭ w,ǥ)N+~pw@wS 1 j s+LIlt=ǡ.p~Inm1鎦s<7 ߔkRFz0Mx} |mR<lGz&#nآ:EU\9MhFH5 GW9=S*Ki8O/AQ=6ݹ ԩceo:A*=5*=ZгeDSIx&3wQڱTm|j-CI"Xn!@=rzQ!.x?Ą0{ZByy6n_@+& 0QӘ<7vovC ǞaSFa'ڥK? Դ3^#"8;Jj`1K.[3\eadjP8KV0^B@Zi3g'X# ;?Yp5F,3:($7={ެ#-XJZ9P)`20j}t"C׫z{UU-|ߠip~;[i+8ܚ'=jxV1F*=: =e kf ˵K's{S޸䁷ZBL׈f9#n¤CmpabN5&Ǔq}Vcʢ,lS|i)dd{psu*Vz~ow q< S>Y!>x۔hE~oJnO\6qj-kjv4 x-u|l[ne+m뎿:%ac KsI=j\qsPQDkp2USJ(}Ɠ Ls*u2P|gB#  d cϾz>0;Y|]ԡu2#8pP'}%\ CҔQ@vInxbk[Ws?z*ň {z`ؒORiQIڕ^^"ѹeh9})@:HQf T~o^PQ%}AEb)'ћ9Ke;bםb28* ΓvC4k:_ʲBGz[¢,rj .yH2uR:†V*я. < *3M aw;c҈lu*u^`wdIM4#,phtn]҅hƷmGcΌhBQ 1l ZUeзE?Yt >*ތCwr ;*'7 "枹ߐ-F5ҖgIrI#TMﰷ3|usGugp+/փ}/j_|L#.8 Sbcnc|MQ ,b{̶ 5qUOl,YsڭzZͧX''a.-fl{ k7;T#:eq1_>;fhQJ myNIudU^%aM9`13cskFDe\ DK=X76٥4: Ք豐Xthd\]ݽ]B(U` i`E2 :ۭ%Gﴻj.RpQՁN*!}[K6m Ɇƫq𾽢ڴ1Xy0j1g'8J2fUE)nBֈ?Eq ÁwO%Rx˞An..;E_T7u tw?,bpݪmAʠsRf.Ol q/]%FRHWs@5,5[\stf6>b 993*- dph#\>UBr<ƪF6ƦySl{WK`br 1%IʳB GMlR3T :cCg :`FW]YXNcyC;w#U~YM+Tijrw@yCg&ڣ.{fRV 1LEbr0F |)m-b\̟zKW;}{oV+bUQ .3foĜS*NGbE˥ܙ;)R2]5;[fyQwNP̀q@5HSA.͒zd "!CDF( &eMm~H-/ÔU)Fڕ,Ȁcr*Fygs)SeY ^5?URZ?IY`ծJH{vYUgڌ cGvAb^csbHYrs$,{jzY7!%cːzPYno6w,@ڤG$$Rpvi6qZpc織z_0Gi[M*x1`\ ©S;Tn\C⪺y U J:Y)+GQF$ӯR#M# `)lM՛fUb3\hZN[#>OgoSDxl1J'HbiYm D@URP[L78SU|)L{.;t=fۀ=)ȩ `dt>3ݩ2c,l&kX%<7rw-ڢ\AaވX-"N=yLO!)SLXXwjRm:֛fl>y0ǭH2+b:S'9Ь_B*2Y.@dqT;|Gwq\e;߽O!n1Lj-V4H1:cq9k1rԙ_Gx?GC7oG}zӴ=']!{iol}ջ34V7QĖLdvLp=v\zXKH8bH=(] .K :պXаBFƫo1g|FcQRbК 9FT7ƒ֪]V"Χ1H,qV'xvNVvbr{=U sC.Ydu'@H(.v'9FmBi:jK9U[~ܺ0"9^y!Iч+0DḊBuŎ prܒAzBL98dҔ#=864ԓ2@iQ^Rl .yR0„˔g_IW g)y`G9?!Y޴ey{Tٮh7ne޽^+ ޸␳pa_zpڻL;.>ST6Xޠ]KjY@w jXilLF) t0&SoZ!][f f=i۹)NOPA$B23U`m\U~;=9e<_.U9Fwj$Oür:*\Cm{g%(d~{Ѵ[fV/J59'9 ^nQ;TiIiRK3RE̥Dr3ԧ.OvLj N$zYMM 68KZ];R]Jv#(=X;Uq͟ZS\NQe(Ω:-E1FRc_ :~{7E.ܚ)6@֯EZ qo$H23 {cTYն Ydf̐Qi BrN2{f]E 2`Աϵfzwtxr U4J];Shfx-zzZ޴iyYLw_Vt֘&ЮԦyc.? c)9poCޏEW\OJrM8N٦|niݩQ) ղ'^BS%Td~;r#cz=Zn9@J2~+2 ]؎\F Ⱦ)Q¼e54`Hwrw;T{xs0'LV Typӥs!bcTuF:mR%ݰsw#xv ]XdԸ $8=7ă #p;YuS<Ѡ7 \OewSNT(#$v5qAjz76Oj"҅l͊h4HyR?إ+2Gv\)<=}T^X*>zeܦERqIZ4X9766缑+~ޡɠ%m&~ d8o]:[I]縌 .<77u\j,v̱!>߭X짏l:c(>IcQa\a'aq-&t+;~U | TjXNݐb:t޳kHQOF^/yZ q? _YBg  tq%$[Y!܅ZַqGV# t8Ua){o:k(޵%8856%c sVzh" ]`Yf@(g~#yr6ڎL.'Ba&>֜%QLĄC&}E8RI#;T4Mwޛ *l6*p zD<,RM s]N6Nx\zuӅk */2ҀNΘ1F4H";nI05xo )R$@rq6)2"@#hNXQxy5ݛm\AqD<ߛӘqrN&r=rp'(tjhDs\ .CNMkKܤl[R4_ZvvH>nUoT8KE`6@y˩)^vipʢ-68eV(x%@{]Aj|So+eL2}zh?=oo*OE-(Aunr?ZG E*'0Pu/案ګ-"C3Q=Jߘ#N:yؤN>ЭKS(¨۳|=*$ ImQp=cН\McoyT $rs'х}@ȳIAWoJJ>T6:Rcc޺׫mDldUgѱێXՈ=w'ID*iѷWFAg[9\β AG׍Ԏ.Q cE$ڷs0zzXƱ?V}h͔sS^Z(`C>>WfjSL#\F>fy S'+8fX6)loNBŒ gSOSf[.sm]]XFٚ5|zf))e r[47YJ`@΅_iv<NJFd =6Ŗ:l",}hdn`1r=9(MΤMԌ b>.YYG9'4zW wzE" wT{gAl mQٚe(,hS-): KBm#B[Qe[s\AOn12J)럏ªo%H޵b` "ۣUW^^{=\#}ėEdg {l)0j7 [^V; YXKLԴ2:9mI.uǏ4 b1VmuH2.yEP~HNm{e qW- nuKhy7 ּ5րzW7\(jG>ֳ ծ$纸%ϔnz x ߝG:u׵ ]Q"# -1<0.@lUCTdX9Ӧk$eHy>`Nrq5CupjeČTP$a\5x0]E ݱ"U\#I79"TQ8>RVLA9'sƚ@K>)T*S%P`1ik#a$,wI1V[A9;=&Yݼi9w=*`6ږiL{ғ4G+_RqC۱-X5]Q[ʭF{b`3 iq4gAo bW(%qCb֖od*ʡ)n,\dWNr@|i<=Es3d8Wߎ˱PTu]=cQNu&DWzSWkԞc͂U%ب^FŃg:>܉:WB`Ҫ}sR[Xaky=2%TEG;6DGP;smC}B|Ȝs\" :UMI<4&F Z'j | E:8cVxKp" ݛ`UUQ85/#+YX]KM")t~F;.Kgv* š&- c,uxKhu$}VY= .GO5չx"![| .vS%ƫ:&ʯ.9}hA4?$8$!H֞3[rJ:lOƠ[ Cnt4`2GpE"v(q1iLt"d9f\V3\EVks,%(J=zPrInfv)WJL͜?SV9Fr γnE2/ vj E "{S2q؎ُ(UbkE6H;ˆKˢ$$`7 v ̑4bwg5T4H␐D^܂P ~p+޽HwG;gjjې{)hIJP$6jZ3+RC}*ɣq \w/+JḅYdVV AՊ_fHsUC4y4dL -^/kyO?Fzn?ָq +rQGUNqu/<Jb^R1ܠ@$zʮTSt{;{  $zu(:Ʀ&#Ui'SPa sQb7U2jipF&mC,=Y4Ǘs9ֹyV-@rVPIO(iTs!r=*~$;RFsUGgo򪞩oxԟ mf:ռFqR׫Ԝ届Vir7] HJg|WX`R9ܨ!6>%湴%J)}O.k`\6p}"3!᚝s,2rڞJ5JBVIB@|\q&qϟ9wjhJ횜56O􎦬?wshJ [F">m)_9@Zy&ʎ˂cƬ#FF=6U'5/?\N#C⫨2[.`C$'p1ZT0jڿu 04vрACLe=+o.\aafpK![ NwC[wTۭ";VyG=+`(( 6-T]^jFO7h+wRM˜?0SF2yrhzJ]Iղ`7$k3[*Cns+)ٟҩeȾ 0Gj1it2F{uoi@ߨ_[vIr> ެZ.ݔX?u۔%="I @-+AtHx-!@Ew Z +hiHc83: \Ⱥ7p$@[=JMjc%X;{ 7R!19pq^50[88yn#[׶c$m܀EOϤ?N}gtq);C4>HRl(LL;;6$Z]"IV%)n#Ϙ8k rBUe*`;9]=+ѸKTKkyUAbDиFZtġ 1 d. xlAs(ƔfIT#5#]KK'nj$ReF-%d1fb9RrFM9 ȲA#G")gӸTCĈ>#^Iu'W;G`)@Cs)DE9zR@w53%r [8e]ǽH*d]i C$mN Ҹ:׈JgyI=i(Yhbqr}::r&9ڬ:QT f&Vc_P7#&Qz0NTTLziٝzo\0cuo4'4\3F`+K LXUAD<[h lg^&&p h?BіMqV'x8Q4"`/$)J@=1Zp? GMv7ݺ] G=r^ʣڄj<%aF~"|71Ee+וqmsoBc%I?w1փr,LyU9ލ#eR W~^HCe_qJ@.dFW %h];vܥ8u`]$f0 oJ.OR>iEf%Ьrj13YB9qU-Jج*.B ߍ&$۠jâ?f񼼲0Rp"kg4mLH99*<>fc ԸķzUG5/]8[0|(k[4Ġx5޺,nd ާI~;wFjpa .wJ8<8iic0 Nq޹,vJҶHiWJ(U֕^ u:#0sJS0 ;zҫH~495fH]n_Z1mR:KR%*qLr `!)8A Ͳ׻ucڜNE*PlplV@J)#W& ڎ$EѦ[Eޭq856;ﮡrIh%hGVB0άYlr3Γ9rf:I`cuUo`'M~K Do3aҵw4+9]%D0õ7qq= ͕ :P#=H4Z@ mp(D)#l3vzkI /z~+OaCMꁌ(=Ƥʠ`}3k +ٙt=GƀGLRZK6+p)xxjڕ^?7. yqսH,KtW`Ե$ozRwrO`"vsa 5vsH7r T<+тjwtvH;BoM2F;Jr$1Ĩ[!IH-ңISgpX;^O3E C˂ czv.w7/SG,q,qƼ('z RvZ9HA4gɥC@Tf~L+) "rz|i{8Hg;z*N`F]oĒ*G,=~s^R ztɼ'RzJhx;~FMe 1Շo^2i ɫV}[4VeZ>@wWchE9ttgױG4_KB#2u8o 9MX]=7}Y7u|eSg*3ד0ZK "woje{X4gv}go Ω0+g~P&61n6 ֑@]YTxoV\պ>U01(S!WvoJ=M {Ы2+Tk\,k=>"Ca>rˎg5c&mD5'X,b7*!7jͥ>oR'4yy.T;[G4Re#M Vv)Z&)2@jp7=).rI֘!ӛHyQfmIԊ5f3Q\渎|V(=Zr)RT]zvLǥr9YE-$YEt }+gG^pAr){cs"Vg0*zLUKSP604[Ϝۜv>>kHFIQdã SEt)$"FA=g#/6yM<"@܃#&`9s)K>m޺6Aew60#y7>0vH&ib `5S-Ċ?=BH8Ȋ5,3ZmՙP8¬zb=yGHj,S\,ʏBF?b;`{׼x]WlsJyjzuvLD1U Njb&@4*V<Ѹe2#5he$.:C vW-61T蕤Yw&1jm,6wN>#ZNh@ozH.FwK۞YSXmkp>274m^fU daZxG'8VWZMFmcN4݇QÁ|ݶ ^l3Y[Oek" = 3Ñ>NHhAOr69)R6odrnlΣ 8Q&}w={U USۭ9p[Id\n+7`c(,ĒvaP5[X`Te~i:n7W -Ue zUPUEE׮>ډC O#FKڮ$@*Wo-ɱf2rg3e274I 6ӒB.f?W{Vw{c)! >Qav?ҡk ma*rv,eǹU*{TPsHrv ImKcoj5ɜ'<5P[y#EL H(R`.v%í|![ (s"VQ##4gBd/(HJ= 7-{\R )Cd*7=EE`(光Z/==)cẌҞDV` go]Jw r q޺8cZ&{ ?~dVu { t{R|W!\ߠ2Su;/nzohב] VzMOJ {v$Uur $4=H.[縥^be;¼7CI!NȡXOz{}ke{' 諾O vQO|\ g#NP64s+?az/b7kи#͟沝OU -'2|'**5;d2+ŁFm#0Kxбe\zVs?\\ML&˙ (-A,A|ͿV7ƲmNåfh9f; hc'19ݵe[Wlo ^>Iʫ("ge?{ϥ|Ēsw-,dv$䚱Zޣ(NQIj* Fl\SS&1oOʝ Ԛ4VO|ː,jZg{Y93Fl'2\ GLszGtco)]1Sݽ4ihO3<9 .-LRph%";=>/#|Rd֬HYAܤ]@HŊjѣk֑vX &?L746xX`ߵ ,V-q*) g'BN[#V8S񩪹NT;0#lM#D~uES8W G!](04.p\3]7"o3SPH滼4/g č2ڢrMyvlTEH`MB6+N}re v ҧC'+`$0wfiQ~1 FcmѭgoWYj:業E^5N7'h9·K r;-uJ1o5?\q>pO/v񞈃ߙ4-&NջF&D֕ixϟ ]fHLya} oU_ 0?3Uki# AaB!)n `vH kȓBDC)-ρso488$yLO9Xdޚ@KʊUK :7Ub3 UNN9Թ~Eϕ{#Qgsdy&: X^EerJ!ΰ[U-NKvV`q6:E@3&>fǾN?* o ͥjK!␨POҚ{件,H8RОm^%>rB}T85M[LydEm;}j1hss'Q ՃzA[LջJ׶,Pg/Υʳ0/9Pdx1wϥ+@z7hN_͒n>QՁqFjŽx-$']v c#s:XAms^xвCYCٰvڠH[Vá$@YsӽXN8 < r[5#Xtߑr+Y&絈}-/dmAc臶 &,˷QZ岴(Pb@# v|׸jDt3B f2X/oM$Q;Fc' FJڢ[G2$hfq 4eNǗΠD!TUܟ`:ڥ3sjB}6 (`anrң$ljݠY[Hȋoc34f8]'^ :J"ET"QwRR.FJ[(HfT2uFA-˄UiQSkVYhCjq.N.įn\^E.Zp-:t9#;Է­<5]lb#r֋bV^FC*V9ޛdeNf8>Mϫ(QFfn6d%\X?W8 %p>N&UF %5iWjyg  ?LvҨpގC79_#X-[1)(s\=+r.=sҜ@ܐ*-Q ށ\jFxQAnpN1-6ӶẀY.ZPFa'zMV0c=Gk/ ŧܦPXzTs)h\g i\|cО=v/$HKcڏgpm؍U?ILZ#kuVQ@Wewn>G0#Q]b זH׳]3}9eP5Q}"ZvEUNm*=ź'*4݃d_H].J7`@o˚[+s$aYw}*ag0AZGo :ߓlW?1h=Úe\ijuJK>ųR }J1oUU=YZKH;'v;*L!NTНק過4Xmc9:Ֆҡiഄ nGY-qd``q֛^k e6P=5IM2ۨA;I,5ddHD`F3(+&a$|E:*3LɞC@5 p^*=sCgRǭo:T(,w>̫'0;rRnAPy\ĕJv3rS:RQHOZ~{gg^f|#W?4wِEvܧګv"{z|YWs=1[E\Û8B([EP>WS5OzPY#cHaʬF nʱDUJ=>4ER3i x*7$u4 jl>i_WLKGg.󇆨#*y㸪iֶ38hF-Px{zzYEچR\Ur]5) vYT^d*͸;g"'M$%8%WOާ[K1oެV q;hYА_3 yIly589?SF6ޟnXb:)cUCk]*K{(Ў}iGf/PHczдZu}(@ aYhZj%A9ܜT&Qu}rL{D3 ~ݢYyVn_|5e٥~PT|zE#|qG4go G "ڞUMf[+jM4ʭo# N>dp>S֛ 蝒̃vXoҖ&K=5khݎa_;^˻oZ'ho-$m#ޫڕiǓA;лN[:oLx>23 T盧rP5x22J;XFzxGɢ6(2ҳ&&Vd(N<@1\gޙL+m|TI{ROUBj!Y+Q0c3U.#nm^iB>ƹtܠj x>fXc6ruWZt=YMol͹~Nռ=bNyObRA͒1T;,j0vP6[]Y%%wI+ %͛> 4 %F3W]#[ 8@$PqfɩacViPss Ӽ$X1>Nip==ju}*Fq^kQKe1yhÑt;I6ua+1;y&cF _2ny[W_mXe9Xޭ\G;IĪ3ʟ4CQ~:UXZK5L I ޜߡ~uifueY op: ~_MS巍xLNvkAS[' l.AAo{Vw}j\PT].f,'c :zO_Ʈvk}J *u-zϵ-QkXa#L 76Z\lV/ҎvP5EN<.FY{Tb =NCfTPsP!HG(q! VC[#p1֒l'f.dw؅?ccEpw$U2mˆ,hX-z=:tmIa旧<]{HǠ;( (7+d^SO]xcRғM:un_{clSڄUˣ$ Op0h&APw7q*uvZ僌OVѰv[Hfϐe3V+8iqa(k;!V<4fOVV;~»1FD r3Qn,$eW-"1qzMncFk PI=ͦBh?ڞYb9Hh6:od9k}r{N[QؿnZ% .+EZ-ᅔ,.ڳ+#ס!!e,v'cT3sB1wrlg7u:Z=SǿSLwHr lau-]F+{sH}G·puvqxKFbp:UsXu RY>Xse|uToļEH? /vU4/6Y>| Vúk|/g:I4Td0!ĜKx]9JY<gZŨ3KY êIKArȦ/ZeZhU0X{VoĚ7RVR'sYAڎ%ɑT(̞Ը80rw$׮ h U힦N# 8$)lt>pNY{#1{=۬Y(=Ѓ8-֙xGh E7u¹Kl U sg~?ޥTQtsU@ ]~ޢE>2[E3!'YpMEZU~U8ƑEGcuHaһޤZ۽9cU$(]xb`0|?jA .ڕvB@F c>G8Mu.^ ;T^Sҿ6d5UOP:Ҽ5[FBIk|)B<~TPhaFRڰ+/t=>-Fa![p7K87a׿Jq6kɐ- ǰVQKSWG=zʴSZ)ʺ0R`Iǯ», vd3*h3 6w0eT,W98b-ysRb22x/^IطDO\nŚriڕOFZKp2=3z 5~VXe5âP~ރڦjA"e?:u)YQD?e4Q6:&I+WКo{ؤga\U{ڞsX[p\#J^VbrN7~c^NOEV{w{Lxۉ4u-9(fq\.v1l}@x.$8©elUb/S$Dϙ <ǡq]5(oSUķ7Xie>EQ\oiZA.yۛTnh>/ c΂Y&Hۖ潡v"89z^p;5kf#>tRK ǔ6{y7(?Zv;RX@5 FU@*u`<9&Tvqg5m_o>"G{J]"0U|xV. ՃCSg) 9T<Vp;ªԒtxpv}Gj}a5!m፞F>P7 "~0(R"- QM{/l߱oPCmol69v/%~ :Z}vTPR}Mcc3hd*2>? ow=GշSv|xX,vmHU`rYJ?2ln >pp%DA%oVoNK ^S# 3ϩf!_WR W3B@F*Dçh.g Gkzn/ Fdzm7 _"A2yKcjw R[9 >NkH=ślrRQ+7֢GZsd4c_Gx8S,P:a=p:uY#3݀SKqbمg0V۷PjpY.@7&ZG6M,*Bw*{JF7*`\/qE|hG+o_n4|89o]Ȯ7Jdpv[%3nNM]j0[ĉ{)EBI>4a&xDcr1ӁHFjjϦK!u².$.ŤA$|;Um7QA5kGTQ΄y=-H =j5(9=EX-&;O2H(AKUص{k.$s,s&vǷ9 -~;l:T p)rŃs/ƫ<Ҝv>_ΧGǀKȍ7'?\&ȜޣC,ňmàSN*\eȮc506 !xr{F1sI8 hwbv1Lw1CbK'Ir=$,>Fa9biS%J5ˀsj^jlՠ>{[_?6>t?Y?ӳooĚhtJmlɑ?jG/;絖HʬɒB PR3ʀ_ނlɌ5QK[ӛ Ve*f;mU$ \ܳ):-R}'‚W6Dm1=bUG#F?AIM&k7l(;+ŅNC)\My ;cN?U9z}2<҇1%}V$8dIbzFF<r{`k+8~ I-͖$ `|ջpeq#F qFQ*+F>Oqވiz*x|R;FpVoJuBLc[&?كŒcZ{b$B EWѸF^'b]:Gk{8g9N}I0Y^^[ 1~5??qUOG6 91XtS$L z{>sQ"yNr2<5@|#t`%XU&ԯt"i hcn5kW sqg< C~Z.?Q '͞Ơŭa<5&׍[x7ohZFݷԎƿC^T ,#ҼQ,tc@cGMӂ!I?*A_aшٲEt*K9[h[D|jg2A4-= \:\uνz ec\zXn;Kqyo;(UA&O^{pŎ3%U л;Twb[qp z( H銃u$[U l)kY1IFǽ=oE/ozc>g' x bq N:TVI)nuVh[<(5gJ) )ADQzSqr2;)*1ion-m+frrs(=פ[QsҷEkԜ"BTmwຬD䁊7 ^ \a|(A|LaUҘ33[|&E1Βv=Ia:P[vR--hcۀmhQ$|Bqnabve#9a Mƫh.[:銿eVeRJI[iҺ*wnݙR~R Enӧ%G{{Vu~xɍk{օgiAdEi!rLѤJUq_C*Ś|ά#fr $=q-]I},vvQ02]>-w.3^ܾ—Eiqi#a%Q_f~i{ a9Ԏajuzd P]CO#&Ky<)ˠiKfo3`cҫ 5v>ZbmVI$zd+ وow6DL+#~)u&W=OOjX}FNK,% !Ӯ/8, &x#QzƪEq4B__SC4#2c [yKIu1&4(\UXHϰ=$dW9 *,O>)(4$>^fӵ/Y8.ڢj[|CW ҟ'94a*-ɡ71O.f N&S[#:JkA?vNAkO-6Lhr =1]@.Gn7YŠYB#@Sf"7<#V';b'OyF h67U(]Qcgد^g ֹ!c wQ;gYUѳՎH[[3[  鑞61= {l jJ|8ABc C:-I!'8(BO/`(emA' zpD؊@UI '@%uo͌Q;P_OPTW=6If2em1MsYb4n^iOm/Vֺ~ 9XHgDp2ǔ㊠5v3p.u,sdj૞#}Ӻ1d6s'0_aZG i[h|8G3{ZiLĜ=aP$|5c"~ՏEkj LMCH}[4`y iI-̣(vԯ/幎FVä2'*w8[O}=Ă 9B ~+Yf l2p()Izwtl(GMK[900#S^ÉI#݂c~VԮЫܔ.FT+?9,Ű $Sw-!ufwƧ, /Ɓ=ݫ#HVX% gފǬnWݎ:dzvke򎍍N /;˽4FOz#y =rh{V02{՝jN3j4<;VE}28遉#gO0b8pFg\𪤜9q&(޴tq8_[pQfUOZQȪ2hXtT?z8Gnex{יB撲f0̸'4K#b}k$UnZqw=%AQA@rHY2U%z7/kWc-дpGhnrOj)r,䓾IDW&_-G22*v7 Sˈ^^UgfJD$V]9a)ᯘ{ШzE!H¬g}+FFӡH(L|EN`s䓧I|b6$ӡ.#r1yȮG܌҂H9i$3SVÇuKoG7%DHD"Ҙ((޵Ng;׃ 6Kmi)Xץ{M_S:5BJI-S`Q~I֬yaTt HrAj 7VP;N#{(r˻{ '[tH;D! sBARSTN$Bq=A 껨pfy,EsC:Km-SO O{P {o ?7?*j~ea4+? |ṪgZ1$}ƕ.K KOE&QfF(qYnj"¾׽AtK#uHIva ,AHٔ sH=Udc{W y$#Qn(n<76 3TĹkXTR}QJFyT+fI}g GJW3P0e3;L#'P16P3r0lrM+ X .|L{vhȯu)#늉$w569tsT+sM)̖D#ھYkn,MDO7j$pG70cYat>h|ö g \H2?ސ5oMҷSFT^z*Q%~˟Ta,wHI!:̫=4(yv6kr]|mQ 9$!It> <^DZ5O5]5s$L zn=4R) D| "yFd׃6M**NơVPpFKƆ[5Tba< p$cC%5*)+a'Ң/m^?.zT76 1wJ,B)fzNJV`&G<~嵷>"jJhRRcu8=jysoۉg̒LE{Fr폺{Sc0B1u.$I~aIW'6Hm'$b2Y!rUwz̸"]NYjlQl?} ]ןɓ׮4Y'BfXWg#jGZiP4w1NoyQ#F1 1kLBzK֛O<>ը=è74S'0tB"󇐹@ϥ_r Z>{b# g>Y`0:zPJE9/ JjZŌ`Ϋ\:=]Ν,́J[}ʧ &f:j.&c> 2'9ƴj%s<7yije>svB|(v[h|-k3[`"cX,BU'x1k!weUU`ZHXvQ/J.Q3P%ƃB)_^r0*\r(* L[Pqm%}Set֣$Y2 }*-<۱bwv) I_Y}'ɢhI1M /)lH.6qשNaGou#\f Q8aR@!-0˼۷(8YVIsѫ%Wt6yjέ% `z?L_F *ˌx|Q[떞M#,ꗩj}-PIy~S,&,ӟ kS\ x*h\v,kTtrYv;juޥ\;2$%V s0*};*Noot`/ <.qo!>܉BKo.. #@6*Ge_բDBZkk#x2ΚF,:MHJs-` osmY 784XjjVS06":Zz;vxӋnO.< un_i<6O^q$wg2־x=jZͨbmCLP2o7y;־r—\#5hYHS B0$>~%o5Қ6tœƓlQ,p;R9e.rOOȾ$l_YztXYd pyG'q5pox\tX7HzE jg f`]LWc 3?\#xƠvUM!iظ~%Yv#z mxd[J΀wq]1x<$v\3&>a?诩۪(sJy4Yy%99UV,@ȷUv%'}٭L77W(x{2 ʧ?­e=dFޝ?*pci-cmr.9iC[; 672zzW[60pAQ~.";GqU O(s66|<Qt̬cӗ3ꬆD S-x[NĸtySz#fn/Qi%[\#ļګKg [0U ?qϖen5~ѭ$esҮ&w s(Mk{!b};WHbsig=Gw>ƣ*S.5$+@A*r})0L󆅣8czz gnš}]rl ,i9P`27Pմ9x3 $/2~5wukrjNP z%626UnOCW62ܻiY/¬v%/q<dXjHB?4 ò)Iaed'm*3GHi[2_7zΡ;.>b,K&S~QY5 #hmΗ񈧈:oQ:ŧ77< ey{W\'4R5(1,:{֛AaEH@SbvhP{[% {7CUӆxka`)jW]{K: euQ)\M8Wy<'Wv8Ek ,`n^aİ#ijA d<O4BhfmĬ=>uRk٣71ֵF9lY9w[;eoȒ& O%ɒYI'߭5w2I vy9>UI^Ũ\ ,gp+Ud#Eb1j|F?Ģ5O=3gB6Z֛[l.C2}#XVaО6&~E"padch GƩ/5d(N~ H2cۍL|sc V ֮>iܢ,\}qU]OgprZ~NMjGw2̜G0 t~uY[% :wґ%ý>=jsZ_(ĭXz꺹©wzo3IeN9 y^ 㶘ĥ@'J +0zEe ^`$TvB.4%(Yy3!@1i"M4.Rg-1n֭ej`[{W"FYp5R]:BR{jD+e_L[M7S0$Aޥk0[B@z,4%9JWb? poQJgڹ;~u  n9oS`{Wqgmx9}3H c#{Xˍcdo_,-k,z,sP0̄wT\uޚ\ 1IF w,c=jc\2zdVzmE+w`j&z\:D]#6Z&$3Ju"#V [kyaaI#cN]XHZ3=:.L',z¼"Dj6IԋQ߈ޫ.gGa EH.F1 "{ +Pf^R#h;sv5dMIgc0q>VFʮ1A^#jB${ Re%v#nV7FƦإrjJqiY\g U D~v`;{P;͕~G7@GasjYsjR@ v9Kt79*q dj܉4RN5.odÞlk`Yg9y ;MC\K$9凛 xv"0Uj V zj^ GٳB%?U\.cM!$eoH4;Kd䌀{kCR'z SQ+ xD]pEI9YZmV8g~u]Դhդ&4GER ^oïBOӡ{N!]O Fރ?MHXvQ 1"NC [0?7 rH~S7R215aD2222j^G !=C E4Ȱ(  nN7\/6Dg<Ғ?`¼s޳7֦ƞV"ώ/X}^ cV,da FH?XsSi,gCN*D\9C3.ƞJ;FH-&TmMv*т794F:9wF.[ª*+`In\#x[qJW=+2yҘ6s^ -);`  YRMN9&}^f=&$~d0jOy*Sޡ5J~4CIZRDNȻ'Z5H0=dH Mv5 R@9'a$jQȇ]"{ug$n hE:p}"HyQpd 縯URvdN`ht7s$Y@rSnv7\@3O֜+H$,vP֏}VB2"?2F?z%|Ŷ|W[%Z{,J_w~Hv#aEijM MyBF9=M]q-iQUQ~uGSobwRBe{ՓMcNCqiԐyF{n'J)-=oԹ2O(%Gec1 hW9ƀjY4VI߹ޏpw|58)k-`O!# G(F1ڭiVWDlr*^mF.goa*hL/*>n#$A)B:(*mu]=}Ӻ}vC 7p':Vm7'R UI[3ԓzoOζoo8k.5^i%ۋ*:WJ;p=JWhwڴCk}>ۉ1NIcI2՘ICUq?j:F> 06'^8`>:Xdc4W:VwP[v=؃Z<FĈPf?HڍޕėZr˞pkY-#d*/# cu ѰY(nRzVCt 8N72ZOɹcޟ,n-6C4"!C9\IBFQ {Ff6ڤBTFwm?6"_\M%#rDWu=*kZ0K3 cjFClq:B1ԎCq"-QTٗƜ~ `m\:CȈ@'s2t1^sּݛzB ISֻHo9V^[g rޜE\*h--đD@1P7V :o*^&eF|]p})n# 6.yWyŗ ZK4AV|6LY9SfUw}q{B8Nu@plTAVeXn X–yߥQ.#4p畍zR%2g?ejͦjv,9+2䌁WᘸHQ{-ei Ǖ 4&]SnI@FFSf? jg\hSl[ rzm;=q[G!iXvP:@-4`6ZH]\m;t. [(rK*'%s1ǠH- ̇`{;X̃H𬨭=*,0#qE#k2_j:i8w( iqصȶ蒲,H ;o5Ij86 <9fުޟ%U[Pxr1Zpo/n.#b+/2cmxDŽ*IJAOZsMLI ֛GR5}(?\[E@9bC0^07iv\s{戱!pE"9JбÏSH`^u~r?2!*N}k "Wl+F%vhTҤEo5rBF}*GO fjꁹ7)(7, eHɈdɢ0@}#Pm#\?"0Fz{KY_4@ jlw)r~`cDJdz#o ڪAtIB&fs*.*]7.}ԛ%l ; tdQH;lG<\wi#l"և4s 28:BnnlrI ܜ71?7# yHlwճ2c,s7ðO.-0NGf#(;ݿʏv5nc7$±gl~dռǩ'{֣#h.6Ң{ f~3p͢Zܶczז[36Z[G,ܥe9%I;н^FZX_*I"gVuMUԦ##~MWٮjs\N F8C6Dܩ $E 9'%:ddRT$~mQ Hzi|]0j ZJ[8'/hzUz&eHB;U^cɅzj|[s%628c,ksiVVw2sl?Q\z%Q~;W<}ay)?W oOu\!D X;N9,R[yV@8ݏϵZ?'BXF|'Ђ|b ³H${oR%I`zn2mYl eRxVƻ( UPk:Or;Yd ~5XƟC#M'?|)R3(,GAxXx@ky'Q"3 XWV!)9w4x$lEiW= ~kψ4ۼK,Z6`z¦~&3H6=jX]ݜ\dXl.Q>@73+`kÛ,7-DX$/f}wp\Lܒ`?n'0S+ "H$IZz\zIm،qOoV.IH >{NhC69LZ[xwOҝIKHOcq$"#7GV֥"7Jor6S&6Q֙( ?\_2As֥CIl]rmmV[vBPv]]`;nOr?W4;浾cK2$ 2^$qsHgV+&ԡ,A4*˂MDtև$׭$HGOZsbu<Э[4@:5q/p#5ȼv?,VMpQ1 spm_֍ \.)CpX1=ONoP>̖\"3U;#U&fň ִ(ƨGJE,:ǽ#RjR<6*>±\i oaMbS}E5֜ZH\( ˒6zٴ /8;MV2 bR={PO[>hp_f7&lGV'# jlqKG+Bd]D-tyU kxZ,%{(ZZsqˇ@xˋ8a8w9#fqoq @,\/#LiKk&C!+ j;y 5a*UZ{H$MGN\֩pM~o8MLP bA>"QP:]'c\mq2&BV_mV;eĈŋr{B/frg^Xj}3`"M Ғ]¨Ͻ<3A47ں`{AY˨o@EJX!Zn=OEn Xx]L Zj%O+FEVy<Җ rĞznE ,Q]4a> Kc̖};J:-Q rުz2{G\]\fKVYC#eϥ)#3GM+ Xzth- ޺N!E4c&c+GԽFZUۯ7oN\ B;`AJ8[肋Le=;ҭCq_?|erƴ J_:bhL&AU98k_!0"/~bkyǕh}af7*p]AӧJiwb;ծ)OZ]#%S=g}*}2 Se,젌:fkXI!V:-AV̇|z ZVV+_6 8 ?tҾw+'˿ΤiWni㴈%arY{װR8{E{X+xSƿyb>ʹZ4gMw>(L=߭d%旛Xo\YD5lm2FNu `@ Ā3I!•μNi T/6p+(n \+RFjWz? ϨZErʮ$'nl'RֵW#P }YQ<WeHa\ (HdH +Nүi;(yY>t1ketI 0WjNGJq#.6Z}KF|1=iLQދiYOH1 gmѩ\QBG,pSzhzKZJf3p:j:XR[0i!qPxSH#"[+c( YaEZ!Ɠ{5DؕfnK& ?ڧEV*<è.U uiEH@ysU'Xd1=ԜB__OIbrCu @Kd-E#ت_Lhzj-t5gv(@sV+ ^,p]ԈLP;?*}Ҥ0҂ ,֤h:k y$$[O6䏇FOG|i]x:؅>@#ҭ<`_͊4^*q{mgTYEvAϭh)œr,#a1:")[&(:)=q U~٤7i:(H,Դۋ)RhJ6\s+lveU[GO&7B(vFcފ:!fAF4FU lPX`sQ$ pf+p֟Df8>٨y$$$pG">DvZ$ 2S9cӥH|Hzwҕ $!qHk$`oaYL<#4Xi4K_rhD3cPnEO֡MrԘd( sSҧ(΅6ؚuصWs8 ԏ!$M.5+JDkk[$r*7irm*,S,2(N*:ZZnBg:σo5"Z$;Uux{Fꃚi$F7 vN".oZִ]%?SAF%* 1UgbOJ,8pOoZGA֤ه;)zD۽PEIj<|)A>)?(҅"rk5Mkaq2BqW>5daTJM\I!‡G,nQxL5w$.FӸW .lK+c_JgXӦKt$(ި`4 1cx$m;ڨ`I`1BH./ QbdX#r4I*Jk,Ll2Fէmak{[> }P1~5;t $^]Gmd$gg!Iy[H GpP-89GҎvĖ#?eDY$AX5gjP‘Ѯ XZ8:Ry}NG(&tޕM[uC2F4WϊҸތ?-wQ|j RF YtoIerJ竚ʾm4F$vod4؎vN@N{c̹l Rih܌fivmD"zJ$"G"*L,Jw'.c>z^Xʷ$H)kP07wGՀQcN<v#<(݀N3hR&0Zs&f`v61R63Omei6PDK: wPtBO¶s )YU|6ג %trp2zr(&vQVm%euHC/d0$itC~բ)qfU+tK-dCφmҪLJ%g+66NfIq(Vg8%ԡI©q#}J׵NohH,ycuT}_ ǒWsH QW._MɅ$fL֠4؇#bJ#zݣؤ8,=bm,lQW{rWѨ=I'N)jUBNW.M-uٯG'8;rS]vBpN; K\Ԇϊ(`i{vd5pEkyė>x`4oj.s엚5#_+KBu:vJme%~HȌw#y6.#l5S%2 FÔ?+= B;y{Z%^Pɋd֏KCh5[X58VDž'/ڷ}#ֹwah򾜯0iQ9#+J 4oR=_ w9;y#\ Jd8|*g}% 0R XnB5>!=֖*dBޓi'jW%]X=zuO\O3\%=Qnn QAjȤ6ǧr]As?p/3h3jQ3絶-]A,0;kJU͓jky=~5뚢9-`;Tfu(i@޾ 'DEbw\UK-2_NƒeOͷTn~Q{s5*;Tm+M;JS|z(LT-7;{dž`1:iIU?*DڎZY9BȬZ4ۻ\ܼfr:w֬Veonڕ<#[m9-͵rǟ=Q !aoxsrmԤ9dZVgcEcxUp Nb̲:T&îpfJJv;UWU 懛~4*K08 [X # 9+DƢHmMZ9J3ⓊW2ӕ=+Q&)*G>3aq;[A\s#0l]c:} |KbndԎ|UJOH}(NIR=)PI0݆w(g w؃W ϱsfJlR.mᶱrAV)QcO3JRx$j{7:lX=aȣ}orMNexQus[' zzg+GVK{lb3Xq扪-ʣ{#V?*.Y̠n+8R!fne2+ ֟!a ҽ,7xwN1oֻ9|caDt^>xʞVe8 t?5Ŭ>+[֓HԦ'4rEA> k'Sk9ȵQQ* S똍ɧ$Cm*]FN~l9@zc[vbҸo}>&0'$`QI9&mF*ث;NR;ZņXsqU5bM2}n?:kqub̅err|,wC$F9F= 櫷&|ՋM+hAcY`TRE͐^حiAiyN75}~[<#$SƒW SWDWc =*I,Iw7I{y=3NQ;]I]?W8a[%`\ zW,4R)rP>=tcl=NF>7P˿.UxH!| '9>PsVױY&NS6VAʠ&jٌs1iX5Zaʙ=`ዸ~y9"G A|j?H=pGw4@OJu FVao&;?pnc:16?#֦qv#H̙S5N$Ӵfyel魭e-T rܣ5'lS- Y|.{!G摘6NcP&--:W//Nv H)b@Nf黺1vd=杷10:e'cxi\,Q1>U:]b[VԜ(^‰%$%Rl#aı&[,| | *d;kuN#c&^䰍O.IPc=r HWm69[ )V"I 9]CK/fdVSUT}TUk]HlX|@BC_0$~%AW'#TK9pUN-턣":rE,wzUZxт6e0eğuIK%fYv 'ӈm->іNuo/6aWtG)$m}Lb[y(s\Q&VgwڣxI欚vʒyױ8,Gj/oxU ?,TW?.,$z車xZ\mnyacYĭ%Ѵr*HH`բTH֫%΁ecZ] ߺ͌k3֘K8A?F˸߮OOfZ7=\oѥ`E/feu=9{jjMNwkG6NcV'V;#s+`+Y`[nlT]d\ބar);u=BBm uܢ"FmQ[L0'2cAP;I#f9,NI>@' wgޣ>i9JVŶ]&mf qQn/ *qd~sK. 4($3=ҹbw'4\FF~b)Vr3׭7uencVO_Rfxd >El S!ySOA{u͸z1w4(Ha\3Jɍ9 o^D+.ck, Ԝ)&ıHѺ*ph_if˺_BWa؏Τyr,fjeGlbKs {;\X3.Y]RF5:ִ/LL# 0;W. 78q}L<XdA_QdO2#;.Ph7R6ޅ4dmЭOTV7vSP.!{? #\M(xjBII 0ʉs̽4&LNgv?P_7,0wh GŗrE;=V˸c ʪe juV6cyN;j\n+#1\d,8܏ZD&vGcRQBRA+6u"f˵Dyٛ·lXT{hy Anå?-ʖ*OʙⲱsBjE:2ʅ=?,~ s~Ww@e}'OV j{ L 9EW*IRz1T^23bBY ncbORT<ϵtL&;fZB:9rdWsxR̪H9ھL{ۗ?w=[^4$$#kl qVJ W6;qڭڮi}nY `o}Cjϧ:kYI"LONkZ鲠YsGC؊[{ȗ-攮WuoNϗFW Rcd6NA RXg"\s|h}*0geOcB$է`Tߵԧ$ yA؎z?遜l$9\;1b4C4d(1EaͶwԯ2oq$,s>&ztP 4$r:z1i[Z'!4#V) +{fp<)6*~'W+M] OKxīf'w=绊o|<3 :8ʰ"ޙ~uX=~$r֝ىqI#%gϭF{g7'֦E#&.t#¸Cg'J, K$)I`x- (~#D;zVi$}BjJ"Ed;5 TKo? YS;Re,G^1$Zj{+ zg#21 iW2I#sgM,uvgc]>"R+ )ܟޭ/ i+eXEwl۴racU_{x)"W~ glOKKUueb(IYT`֥/*=㔋c9g`jL72&qD r=i6XuZCȋKPں=iY8=jEByt]Qk==GqU-VTebz\¹}՟qF}yn7A(ZqyЫN>XOZXx\J0Ah[P=w5jn"b1IɏQ o}hիsFkCѤ"}ٱ /PhY.ɪ_?LwI Gs၏ުr ^tFt`r٪#pַ"BDZ`CjWR'jەo%G֍ŦK!PDY9 C7䁐}jBf!qO$T'ySױs vgX]ۘI<,W:$c*7@>8bn!l)هR)vEIOvDgf =1P[YÁN _JSwtDOYf#?߯J\qx0/9,ē$if=I6 :8|RˍQ 1mS3q5}b, q@ 1D`1UKuLNmYLַ{? е VҸuuCm,J%3 =z)Q4Y#ۗ!7:nEGe};jo^xK-L$t"֡kk:~%hR4M3ccehUxʯ:T"hwVT/':UgͬQ˅csهO;|g]\Ak Or2;oh-tyGAUcQZ";(?kU2f.:uQu- Ar(YA8G =wi?ZYU]?-ZOzæ1peܵ\o?\|*V9&4oOBePqQdY1qr{[D6.>J-ϭTy#BvҭuP7er??zд=J·LW؎ ||‡YAS> SuRYJ%gw\^C>6BR%6!+ʴ0o1 s?N9<3jl!jަ fo(ڢĒ͎]Lz:PqAK6lˏGwKFW؊kmh! r|jr0~u2z O6qMӀpƤssmݐ]O$ oPfXɡ\\~#MKt9~{R_xׇ_ڧ6fǁ?qv <KkToSsLX)o1Gd9OoC񫥶 rJa6T v4# OگLGBCg% HfO7È5 >{K2¦cRL 'hȧ{VSdWoWfAR:oigV>0UBNX%f-v5?D&m&(:վ"M.K7n3ԓsZ6Im sZZ`g+- Y/`>|ϾMgyyWWڅ Is+74ܞz7 o5·6V+;y%pbitxgE`vea@.0cS`E%%mG~$¯*k^ȄrFd V5$1= m-(,{ >xNMjy$6!GOWO&Qʬ[o1UFF(H(1qzzD@c\z'q6+f oӘփ}a3Wyy.&ͼĹ'sЦ|Ú(^PM.+=.x]eߘǑJ( E%X i*ԻҖS;VsmjI:zirEPKXA9>*G ~={yVT%OPGiGUԪ1#JC?[/&P y_#XVɕjpvζȌIb(Lsb0|͹UC]q^ţEijs#Kdf<ʥ~)Bt]7@.7|J۱ϧKwD.3`N jc8ܚPZI*5`0|5tHbN:P+yn lsm$a''sQ$>$9]kv+o0Z눯2d$q^A,FK(Q@s DlraKsrՖ_DdǍ|{C]夨&f,XF'ױõW+Ըl]Y"q-[ Mn=U#>㼇+wn'x6GUu Kwvn-XU]#Z)o ; W} w*5sи(/xO~wx=6ݬtY.a]C?foq/rY$SStsU%D0/26MoG9$X$ԅS5k%9AN@Lsv:ML4I.<$jYhVOl>t©Νq ֐>"KN,<{dsӚ ͨ$wԳlޯ:_p AV<4Q\lqڮ)i*UzFw鷵NԀnQH-nh"A.Ěpihy2ISQq7)do`V)1!ܸT|;$ưLrc?|jjv2h6$d"\Ƴ_,0F'~{XK76#Fa3jp͝9Ss8 {Ym0:9o gȾjZD&=jZs0<#f_%~;VN ۴RWyy*,ǡT5It.I)T;€|QPsAצ&ݯ7ȼ09waOVN.;5n./xzFeU\[}Mʥl][b*vĖ #bH:nSK@m}j=ޥ~PF;f$`dl| }ķR_ܯCp|63VVKfr-UQU qIڵn~-w˸lq _W;jkiR3i, ulJ"0sRlgI2 9uu%c j1,$]D+) ܷUV;鿬[3ʹEscIm;\7$xەpϝK -2_~UQmY Y!s*\80SFI >PވQuB̏`î*[SҬM ZgYYɒYrjvp䁑:l$4܁]P<ѳ89Z,-!U!0=zaIev_ծ- yI nu⽬񟻱W=3Wϐ>uHbs*o!dN͎cҡk7HQF1ZMse<̦T8e  XM+=[Vkw8heDz)ºtC]Dey!{~= {e{4$?+oT]NQ{K&eαGmY#U7Kt F]TnأIcnXIߝIzHf^=jzoEn0|nj4_J\')f'$b{)=jZE=wq]HAf1+{/<1vFkwTV8%* UTIl̎ /u (|{ SilO(Ac.OcržUP[f7o9kC9[sf4 qn+)c{j˭z-ʐ{!ڬ:Us@GB;a?Hܥa'bO9ڪ-ìq5hY p+k`\DL?15e *EQ)fel:ԄT;>A bW;OHcFyϿF-l 1ld/Cc.m2ծ.(d=MP?V`;/4x#oSp. [EY=e?Mfqڔ$!#]!裷 ]0ϽXt;m-ZL7ȧr3MHyHg M$FKɛ$(;/O"L.?* #N;X‘܈m+s L x{cB_Pk Hr 6jb81CC5g{!0?±]oKY'&w1}W%qfpqOZr!sēNLfV *w GGzw3*wշ0v֊h]ږine/ gfTC)YxF@N6VZ\n[|6`mX̷Яك)UjEbaWߠ]'ڗ^9!H,OhIj6S6[)0y;MA xYFB׆˔K|);tjgxc߭9ȗ'rvDd ЫvBq;{GWu3!'z5mlITMn~CGJ;|YO?zULmln<='MAv'YjO\U]TϪkCۏ rݿSֺByGՁV8/Fr{b_j>o$`3(=Gn6G_f2RUs}jsvE8`>=tOuKuK<ҫ[϶kB$UGaQ3`S.89TS-:`t"H(o-G˺v)ڷsvr^xJe|YIڟ#oBf3K&!*%}ĖӤ pGY5mVw#2$24oWSn i\2\pE(sjY%Ę9W jյc`;|+绱j:Χs#pAOEl?A2YOA _p o{}ox:1/7ji.QfG ܟڤ]f6#GzERyc.mUr{ ;%H<J\!ms v 51)"SOПF>l,9E9Д]^p%{3 gt^#kOeG^W0N(f#{p԰n4݄.mcbFFGFyriRHDܙ0KoX?]ZXe '@;_^r3FŘdAe8HBVV$;%?o$>MÑyYI"/.Tmu*Ŵ<_19؟Jp.)iFf wHNkxm絎Gt987jWS%ѣ$_ǣ0絑pw\AGoOid!4մT "v`}A~/~N(oVʓFGȠ]#XDr[`j5AxZbS~5CjcXxoZOmҭWGP)"0>+O_ԡ8$%VI3Qm=ơOu"yDk7?7}pގV)V@`7˂s 8 HC4`^D!ps4Ժx$KP=GOC uy&;ޗi髾%3dFrFwv@a?m޴ ѯvXF_7G*SsV87KV4pH2c58RS0^4Wѵ[[ Iui w9*l=ե*uU_j6`+23z_Hmo)ejWccQE6+74b?i5=r/+"#Kx37=e¶۞ZU机7 O{$ґg'|6Ŧw1'4BN"$2Iu֗]Toїh]慭)m>QJ:MHX]ƗNԵOe$TzmRJm|Kx^Ug.UI gjfmaHqQ`v!0aٲ:45Vu`SV.-dTq%hL:t6Ε%4ȟzϗժ]yt*$Fq~;Q K[}b ƹ9F2+^@>M>V>ޱ){Z.[ŽʽW|'3g<#Zŭg"̤+s! :kK{j\v3]m%YA57:~uYkH4ies3r~`I,8j7|vP0Ν@^D1Q͚1z\Q]\qρގ[YYY#%^obs"@Iyf#8$3Ij[Yc j&F|h0_^^XdrT+ԯ0+1v6*Tn+d8:HխR9$!*}i O;Wغ|$Tn$BկEa+ּOR3]GM!IϠ%0tHHTyV.Z%6I9vk X}!_rs+fO rUo{mB.4xҩ#UHߨXޟZy +Iu.pøދFK/\iϫGBTPy1΅W{I'ȳ'B`Ve-ŴN:9Y 45RYbG^/U]Tӧ{<{7$nd#$ޫw:R<[6+xZWKд ;L**rq_BD&˅"hmߨ#/NgÑWTOPc927`|1Z-༑ddh>hpFglӝnE&8+R7&\H1P6mm,h}cPxNi[.{{P*``Ԉ5nSCr.7;O඾w&!8# NQ9~t SyC~I(GcŜm#J5ӥ̧)b;^.^-I!:Z[y#˓"$ gq?N\^(,I=15jڅ} \ Hj)$#oc+Ӹ?],\v/qa-t!BGOcItmI[CH I;z լ. W_Cu}T[[3YNvMÐlRZ5Οh#'T a¨rNYȄH{5^Ϛ?OqD3̹؁YHФ} O {bS)| D1G}(KGᓱ#S:v.%;IOP *A5'<0|HwIwn%G{ZR5vWx&i AC]^Fז֖B0 aYkyIV{*3W/c"ˇ0Bc?bH$3FIȡ}KBFO-4@:;N8iK(?u)-)6Z=s"䌏%:Wie纃?+CoX?:˾>Xqt:R}$ӭ΋9Wd__}jumdK2e;SSES~5 MA9oj]/m*]%H94l! 9؞[FHp 1\q`֦IE-Pl]{:YU4f8 I'+_࿢mJ#8:]@s翵mmY =2-ײcIܟsCu[ێF)O+8U,Aqo G,{720ς_)[)WB͂>&kڍne>ư.a01^޵Ohm  ɁUWp6%Vwq6p3`ziW<5Ks$xceuEueYC4 n?GxfqJ~'K- Zɩ[$. $AE.RXSYޥeMgŽw *8kklmc*Nd~(^i@IOZXpՖg_;`=jǜq/k:]Z4F_wps_<nF2}{OKjZbՒ6ܳz g5p u66ȡ '7c2MiQq6?kop/J|#ĢIZ! c'h?=5ha[{ׇ4]Y]5琣Ĝ+ۑռ,jrwZ|Z{FIVB ʰjı ă2¦TW7RA4QwP?hh.aK3 w=*dEUZ<ENXb~\1ڞ%KʧJMO{kX۱\"I2`doCfc#7qҫ\-k:lm5H?kļ+4rIb@Gr}=-Ŝl}.lp޵N?IoWdo(/f ʖ~ugՓlr7w:z@CP}FUvdi"$碁U(.ɗ )K 2y &q*XE$>$# Z%!;Pۃ')l@J"^:Kp,8Mnm_Zu2`1ힸDP Pp3Sqyz;+*;o~T;.5Wm8a梷[[VEe$rs查n6^x҇\YɎ]MRyl0)cMc_D} K7\h)Ŕ݂ē?.̗-pB+Lz-Z.~Fv#yG*0J2"EhlrH?Mi3b"YdBaf'w&d.rVú6 z]4ڨH|oçD."s#wݜK|yql~(Y&8W~^Ʋ[hEP%=>:ո(kvrܾh|}POi Hi*?VFmyURX;;#άl`z —ߎXd ca]򇧵OBb^pF֪𦌲j$ ܊78'B;'Ӛc"֩f6W*pAw7 `JˏWDޝe$Pyd"0YK41)B)tE3{PB#hb9*]އkir^:{Ty5>ᘡO<Ѭ2`+ufwk:5mJ%_>T-4ԒsS gֈ/u#i-zm%dwkZFq..u|}L_Ev uĺARQ I$YSߩڍJ]DA@.<0zb&\Cf?Sv] >TIn"x]* ]rN7`qU.-lt+ZVRU#?kzm .;9c|Gjķvs U]'.dnTovdZl}2!œ3.,,re*>t++P_ٴ #(ygNFLvV1;?pkH YC{W2%- T[Up=|W7*R9g҄\Y[2dQ.FXӥNmV/ >y9ړfr63}*ym-I"8ND\n*ȼh4MFgKYLsH2Wn%6:+JjW]\Gݩă9n'h;oo9!&;Gl~_VIDG9wȬS!GmxLe w-]ѳ? u"{MRm'S7y%}i3Ok[bR޾,fa=դ[2Xr<ݾKfQxmYdRrpT}Owd;Qجގk#YȤ*@=NvROm#\ē Zr ǔtj?'x8T.7 Hg 8ɴ}B4G@zƴmE k"Ġb #8ҩ/a% \2DOߕZ4 ҵKn9VawkG,WKhDQ@=1}4s'ewV+ 9ߡ^^(Knm3?_ⅼ0xϦ=} K neV ~c럝Q\5rJjl*`/Q@gڌiE2s QAZg)L\]hH#ҳ^)j?OJs:/AG[r?Sڦki`2Ǘ.Xs{~];?0pwjuܬHύ8ۨW6k2ҩ1A#~ngӑ" 9dcCtTK_S0F_3H GJL~ʱ#DXU0jͨFWp79~ ?v9˪yNs*tQ={T'GgĈFHnV'CMCZU#alujޢqq$lߊd/m.A?!ČXޝA=MO:?.zU33zU?_&֮5tZC zoc)մH"3yw-MJąZV,*]tzîJv-HOW4u7[6ޓ:~cx?McL"؛Uv#o\egnW( `cֳ[yd90iGq3nK qhO l?'𪖯qs Iϊ6;Py?kA 'C(R@FQeλZI b=3#zV{n=dr߭Hq;ƒ>u '%3Z!+k nb* 3k:u@.YU},A ☻1nmdoaZ["jS[G=BkLӬ2GPȥ<) >8mDF8 ;}(I9V~xNJ5{~+6y- $[">U8ˉ`ڥxs3ui(cXP[A6^<{/֮pFdv n!Hn;+= _4Z|+  SY25#aDlw$QK+TRD G1 tvHC'f~4(_NU E9m$J3H<ҭmQ-6 6w“T$rs"ȇpֹH۞g#fz&AVRk2?7cI"ϕ$>ǡUxVMΩCr 'g|Neմ-"Qq(@0@SXਁjrBLFvji$YEZ;daXX&}'2fLSj#F2!T&)j#;|{T}+3Amy y:A-9֍s(ls?Mh9|Ksw5ԭ✞gO]簚K)OP=4\u=֘m#N ;uT[ $Q;6 ?~u[ZFI<͏z|9Ygqa([` ` k=.gEz-yu~ޕP=mmI}z^ğn!Lޥ\BGzC*jhS!# G O1JUF!C=3u,i;BeC *|T8\DP"*Kqcւq6oբn?=*sj/o/4g Ϧqs7/N>!V&۴ ? I ֎uda.wtGZ|3Ղ+N4% nC;ih HcbM"\^\r T֫Z. At/$2~=$ViWZzX\Y(HЯ`rjywIi|U=$w̼K ڔӬ1acw7=cQyg`ޭvkjNu;̊g#g a;\41䓾԰`; hjr iH;̧~iibIن[ 3©z i$nSz u^m+RC$H =h~{gkl\WYYif|>bV^یɪ 7F=}X[VHڅKhzx[0y=U7mhVHĖr<`sOlշRb{{[+ W8x{H@7h)ez`W T2F}xo/nn`rFo*Lz^("ȇ]N ЃZqyͱ?r)2z/ai7*sڮ:VTk ?Їj?D4۠H_vaTKٮ'xr&wЖG@xk%0fM0ZnŒ*tTKIi4in67#~[6֯Ĉs$"Fr{(OWZ+v#s7M>-aG)C~#}Q~Ԛ Ү䷙Qٰ#b{۬t4$Avb>w4"wk[MGyOl90G,vʱ r(¨ڲ2Vsc}s^Ui(ܚxFs&crءEt2\1Wɫ|q ҝTsL$'4#2sRrL=*[ulzR,ޒ_S]0nDqdu!sP>9 дDjV<7r>Pq_Z5 WFX1,cpG:U> 8©$Gzy*bI0FrbcsCkKda#3=֦i|B4* ƂIƚ=$vTuA㏣+/n^.[?S9 %@$Br d#&Aire?ڊO\lO_jGk2Ǧ_:jٴ@WekiϨްHO\zrk*^5e-σ; >z Zcp ڮvQfX\ÛzCSoq$͈)P:.ˊt}IAK ݘrǧP5[)o#:]IJYT%s)~C]7\-ԀEV`ӵˈDj*H9ڇZMA5ǞTmZphzkoolAS土rh*MVq)[+;O,`[ZK1S|ꏪj04-)[u*phyh|Q 2f|lxmA1. ~r:4e$-#6=@fI@7ҤCYG-}N*Xd;Sz8E*M+"A>+*FAxv]롲H^-T=bX.hYd8i c`)6X<+/xt oLuڳ-e p Z΅͌͏L{V$Z΢X$VF_PI3pΓ}2,\)~Ƴ9m{v#qި2,FS޴ TkY:RFXN?lr͑bLeĖ!3:ָGԱwAE%1c?T9k0Y2S>;?k=R=p+';-ͩ" /&pk}8 fȿ^p*ɫ r]VS+翤-I5?hG$|-8ﭖx7eК{%u@xu6yQo?ttV[#AKK8Lx@u$~CoeC cN\Q7oSGuHΑw'L>|(P2sU$ n`@ʖZչ76۫!#cCs7cp*xr? }"ZB@JV ?#ܓV:/.O¬|jGh$ZK0gXF?e:1IY<;`Ը4x )4y u8jrRyb:^΁{o%$FORGEoe P7Nq'Ҩ!mۦW0]$ϙ0TYGTkAζ0uDnhEj|~)M2 Cީoiš"W.xa0o|NWBT2 NbhzI;PwR2D,cR.ZdyhT'ڏ:(8tƇOcR1y8<~V{2W3Tf9 {CZ63E*sW*Z4K-]?SZHʇ'«OZVCqZL`PK~e2$S>7ZWmm+7[iע73YU *; UJ_pĆe[0YF2[̲ħ+CnJ sЊl)9&TՔJm,=mD:Җ@:q|K}U9k͂)TrO_6-;"F3S. 1HۙsX-V}UGs͒ޖc4fU_Kwxza3uu/*ZY*ψR\]1:ҍ6à§cw GoU%menysHř'm փp姴Pܼ}\'pCzS7: J=C01j+.f?i7N"j{k9ʋm<ͅVf ڶM0ߡ5#t>:  ǽd[>2s:T >v<Φq6=p3}z%j[[ &$r3IE0=Ҵ{';dT?SVDA#zt`>Cjkc6Ekr>3ʽmTA$ Ni%^qo$M[Qk9wn.f\mV׼%)r\\B "x6c zk;{cv mD`]7Fvo OlC8k E9zUp[\ $1Ζy//jD j.[qmp~ oMX?R;5r݅׃#Xi0As*YNyhy$ ?+n,=1[!䟙5c-ȁH$fE2Gn߇"5✴ױ+l; *anR3E@kXbSoM2oso |Yz*9z|G6hmEy_F^@s"wú֑yWهRDIE$vQ%Tdg\~RKyOO[œ-kgە0_qY]Z6u 3Ӥd S;.n~I"ChIrmEW+6Mhe{H96w<vV[Z[9he9cU?;)dCVr(*֓vgnI7 :4zZ+>[yGO_zǯ ƥu2Q;?4٦$fи9M*$ s?h]c,sy?<ڏ@__.*ӴM2EfQ#w*w7j-:*&F6؟އŜk n?;Hv+sJc&$_}jဒStPZD*g8}edѸ{ɨ2A e('8j&֚lG eAx;KfB'89cZjK+Ȏ3G 즚x~f_j#kZ\k'(aM'#8 w>P[ktH@:jem5e,rygjX\ZΎ0O81}bQXX \KͰ=: kmԖDr1aLϼ[qYx9p@-ɂ:)>ƒ5V13I@^^VTPNЀX6sLjKDslao+ xiIk>,=~-ʚWs)䜺ɒWy5K+K4X'|ٮq5q4O%D>SO_VJ:w6L8W,gCWoI!<ĜQhaeXEqGF"Bæ†q _ˢټ#9IYNyN:n~+ԾFZ p> T{;{t̲s #"]ur2 Tld<znlIL'Vjf>~cZTe]WPJQ*InO`=|]j8$:)I'e2XKăoW+`DkأUz8XהaJ=Rħ4#g$Jм2F[j0mL!U UC.|ýQ.&K[Xƛ/dV1C!!~ݏoޡ4 yo.mA8][,ra&N9֫Y۔L仓бG74aQ{tZxQCn[ /-#b{r 9OAWYúQkx m nϵf.ldPy dR\DЕ ~=+M*KƂj+H`n4ۮbk9uoψn4xI$7  mUVo]\Z:#ҩ}];OU~=*Y'nfW,4{Y]UtY4Q>gzu"{b,׮q5B%r䜕'|l@zM n/m(Bm ĶwΩ1P(|P|S#N!,1rSֱaҫ+!ZO\[ShȚ#}dž#$.//bO®= *qr@nRQZ)a!ch`T%Yb!Rj隉<ȹ ;uzQKԵ}"g8s S:ʾ~+GPЦ/1+c CmFI]cSm<z;c5vRzU ZF-_:-xMum< #+,eNކR"9UvF_kKKIm-S8D@؃#V;XD} _8~i(>oaV9˫vKީ蕩" Fŷ= BHn?W›<'~8^ q#zc;U G7aaQ#;׭}g40FqRIOH<x9Ȭn-Ӵhד-=Y<ZCmml'X;`T>sP[nf0pĺΜZ|%GFM6nc89qIO Jt`I[iX+]/:gsKk1ޓ"#1$i`lh"6ăRcKo 1>6L1̤c 1UOՠmxji7JDmjܺPv^ʒ!`w7;F )cք^x/~I "60ǘ~t{Jⓨz}j +MY"8W#B3a!*;UX@V'FMF~45,,p=R=Y5˄Ht@Gp7'1Z$]65Qc5AO[8'~Q\RNsJRQ1/1nv [֍i6pkDyc?[{KGMruFq K%^U?ʃqCZ'ˁ=jkFTA6TdF&=^]6u*|Nf;zfxbf4-zdjg p.$d;*'Iiڼgl'۽/L^lu=Rɳ *9 #zmd-(UϨ^7,YZ.n]9Ǣ?1A^Y2N%$J_DDŽJ ڀ['6X/R ~8 -h'x˷.I gZUd e9Re$A8óvP+,c=}EaptϮ\r(64OG"YK'"7n>q;FȨyc]ZdspaT\9.ѸZƲI+Jt(,ᲆy8$&/4ֱ;F7vxgp; {n-(Cc̍oƊi|Ln<y:~3fAe}Ϲ rVCƳUs,q7$իteusGlw{|z;=K9iS2,3tCKfY Ҍs>rw;CYd>"ZPJk& #`FifDlmOZbFp6ϭeJ1uM@Ha#'+YFP3IjwYR9dUb;d>Z۾Ց䌋 Hʧ{|(%!Opzv++)ur5=P vj5&r"sf+v<. $ڷihS 1z[BpH5o.G(+Xzε3). >܊p6[f/90JH b;uղZ_E_HDk6ļeO u#F:4"u)3ԏkYFT UPێ5=-rM-Ʃgue g`ޞ[ky&4-41 #@X5jK{ GNCL\6rL$RE}SGS91\#"e-@RiS]>4<­֜Ima Lf(B8kx%bfvi -MsQBAq*et :gǽvT+]!sTyS][tuQͳ3ڽoLuRt*؝t[ :ͺ_<*z:^sΤ;B.(TOozV#&O#Ej+Mgš],Y[z' ƹwvRfu*GE B 12$>U^$3ԂA}Zɣn@I܀ Ze⸅ #R{YixWZI<ڤR(}ũgy#'rEQty0ǔgH/|j-$vRFqJ$1H*8p]UiA3Phu!ϜjvR)['0 f޳M}/ +9tkH=*Wp]j_I?iߧ7Uk}_IY<\ ) +S-oẇΠ؟z? v NBSΧcokcjcH*juis .ci1o XAAq)}*íiv=w< Y!S+prIAޱߧ]&'&i4ms 8O3ze[q֖vֱÀI$8;WҖrT'#u1i$3$U߈wL;gH-9f򾠊 rC3ګ3& q h2 xG4 OCL,=0(˃{S33F;mKYfnz7[Ռ?k%x^4yoX?^`i9H\!}mj9gosZgZš]ݐIƝKkXߑ|Fq5kQJ|/P `QT Y0 q4Юc5 m?Uu˂:[Ĝ9D`Gm~ Q5*s'Us9uLյ71Y47$llG]d/*tޣ.yy&ᬚ!ÌѽZUYWr;KiB|gv'TU)U/1؃ڠK{ofenqֽivqj u2msRz xE!s>CXt溘DYRrpvͦүM>#FVr0q+ ʟ]9=ambe挓Q&Z9O,U)Yg.2'Imfy,Jr_JBrRNNif_NWҋ ($Je#P˵Wkx (> -9(NpP +P1n4}JjeSL/\Gv6m`qp2 Ch6ŭTdQKh ^c~T䎻jkSGn !32_(J,p3ݏ%6$Ioui4gN`J;l>9+mm6q@8 Tg55Vھmb10or߸\u\%CsWG̓W9cb3\ K_cszs{oH:JĪj+<3gv*eK9IP-zK p7ڇYOoaiqo$.c|0jTݔR/"-ӪGѤgֽ&sB4vJb*OVo:IWҪ=t]_ ԥqwBF7>Փ}"_$K[h=6zwF\@mbc<]35óucwLEERNŔrC'@T`U[4&*_ju[:!b?xF"6|7nTY&cjzzri~ ה۽[mAmslt[ܓMv> ..Gfm~UA(۸ff$)mB-F(C$0EUo > aԟ5T#[GRq˾կA{2»ߝKn5ocuxm$~ۏcuZEbLLTsRr[5 r:0a@xNцtRIN:C$cjpE}iDdaCizxxi!Pvz աlvH>.or|ܟhӠ% N`uo l#a[c_GFFzU4с?1yzYWbs:H {T{P뚇ԠP0dH`fWv(*ּcclFc?%\4$ l(H؞lMJ Zef|Ʌ޲{ q#V&<Oj?z5p@xrkeѵ!Y@$$#+j#q~Co5U51\cpA B ]K-br7@KҵHC3$z[.M+NĘ ;[hysZ dR$ J%#OG }Sat:@xmaInNySJ\H2v㓜 T5_FkL8[vP;wyD03ֲ&XonncYonc_Yowm@;tAK=n"#>'doCZ CK%έw^ܕvU1(ޞ9V؊L͊r2{*-mc~R=?jq5kKV7+.|ZTRl;o/lXtъ-8SKIl$/=ꑨ Ե[bJzbMy:ƶăqUky'2?=j-ҵ B WSw-CM$fe)'~g%Wl Uܫ/F$t$W:֊WHªVQh?.UgTkq@bzY̚W\pGZ ks@ncua*,LiBǡwZ6elE\d3X WΕv+ț=ACJuᡔt*wolwƳsĚw¢5 zXm#xz{ قVS؝#n_G?EO:֯p/wS\wuA;Pң6ڳ GYwE 3vP8 B٣"78'}Z\(%7pAJ]#7:rNr{7_4nӈuHEs>EHM3L^f~ndPAw\}Gn̦34/9=rj ucp.n$6 1q޹pе&hċ'8؍;US$t43YJnE<#?Dnt@~SAN"vX>f9,_{ci*Lr7nm2Ubw=:pm^igWB^; \ŲzQ=2ɮlsӇ`;JDձk\wkZO2ȧtA_Z PBUv3̤V?Tu7,}qY$HdZ녆gȵp K:zs|U!SR`''(uXNYI20{Ӽ;|W%b coY-vǨ*}h5> 1 +IoҭDG7q-r}VtFYSc;gqeLn<7WNPjkeɧ4W^-wNl%;[9h$tR9RN:wVI s'$ڻG]kT/cV[;\zUCX~UhV&6^-a}_J-F,=?OV~]雙98lP$D+ʡyOavE6yHKWNunWld>8\'qwM%մ[O܁퓽KnѴy5 i]K6< eIo~UM*Jqfc\dP.fi8c].n0ז>}ÉpBK@8v-so~ʒ2u)>4-+C5X;#1F˂ΣH|jFBX¯]PRW/}(>vLaOfi` f.+s99 =:5ì1oZx[-{<r5C{˂yyTd _CcSG-8Σ4ZVNRԜn9f?nQuM8\yr*u*Bv_jsM2H#=NAZ'C7)z)cx~"qU·4 r Q T8wㆴ;nekˑk/}65 A8OUlwCoVI4.k[6EfYlr<;|smQ5ޟE/<s?sJ\55^Gp=[Z)l;nZ>i؋*aտWl6,  pe#_SYUne=AIxO( gB $cevVt*3[cU]Ov m(,@UY/omBU#,ȑA@̚>k'<8V-]Z.#?sr&xUq𥵵η ev>©w=1io~>6w%XoV0ĆsStm~Mh3*.隌3\r!{POtK %Ic^l>zź-۸Ї<Ž4*-_ZRn.@< T˿\ʫ!O]-KI; M;$Qp[$9NAqk+&l'̬}KoSJܕ gr8_Apݷ:,'nzlYnQF瘃C/X̸GKEYGh'SWnZpI;3qkvaV>ڈe-ˎq7Lvy6X\Գx0#[Bw^VZ]Ͱ񣻜F^@| FMA꭮nuk0/m#܃U{ήiW&K[u#tGØv\XՕ\KYdc!v;''?:/W:XhpIqry:(ϧڶ?tb^c`7T)SU)+:'PJ2fD|EVca)VSSnwk.OvǬffEAp|K_CFn9 H#R:oP4{6[~nE8@?"JPBL' oNWRn_po^) Np=\KK[yУq šIe6d?vW.!AU/6e=F~i^$UJBrk6H)b%=8 Le3h4ɘ!{vJ-.؝:nnNT6y] j_L/GK?|M(i2 ;lwMnȘ!CJ|1Y  zEm\Oe'p?jZ>-@oZYLmFF7Rm亙+7Hdz/_qV}"QW}ҋ$"8v=1SFwYàd?ޭS ʺZ A$/p_6_ _q- 뷀1N{.*դ&dyɐwY{p+A*jQΜ^pe*ݢ S2.0i[Veĥzv9,Y'_6#+:̪yFzBFv:h Vv;`3ѭO[ $\NǥQ︋Mc`: oRgP>G gΗĊJ\t=*Um4" .~E@:vG,iWBKo%ƣ93no_^łFmĈF=+,C$rczuwL=";gz`sNG.Dgkv9.ނ^^FnzV}d{y+$"Y7̚u-4@3#! , M,lPyz8Ӛ6rGR$2܌x1w;DIcV-'O3#k9ܑ+j&f4k'XCE)rV.ӁNXR:ޮٕͯȶ bUn. ڬѡHҢ)]ALl1ڣ͹څ^HA}Jϸ/dxO*ExJK132ĝM*I9&L%5j[is|"[ʁ_܂=7}  Ғa:Y5;˩-R.AM*YXn`OO}o9'PN50c>C Ė{h-WJXn#u$s_5qfq=΍XU^HG|tFkk-sKDs%UԌ RG8akł]XiӃ/#=,"x\}([Cj^Jƒ.p_HyƝLBX3,ϵ\קM%!(t v;%!O|~oDkl.~=ߵOlHB8MyjG"c PEžR?zDHhpr̻Rleu VPd\ 3GbˋXAʪU8~WY2s^` Yssq|c߽Hu5G糹I-QԀXWYM.M/O_OʑnaW>+;RAy /q­̜= jj#mð@-*O% ?#TW"dE3pޟXu!ߓ{oGbt K4WyhX~h$` ^mh=)E9cU9xu;hO:ތš۬  (¨PegdcI?ĭx)rlkdMKhܫTrb?"w('iLF{5aoOsk Hhd򞠓?*?*ꊅqoW-48^A%e6|Sd:yR%#]?N@WY!@櫜Of (u`8UӮ [H-ߔb@mk6#eIld; x7ۻkiyycp=/ drA0Ec:e$ 7&)n̗w(O ʱ>8,-J?[4n--[>KfH9ǹ=ޯah7Z mbi!:=>uqZ6h 6֑mU1jX/^L!utmH[5NqtJ`40 j>$szN?=<wyOjfmĺf2!?'/>7+{j]B'<*!FD:6iHp=`ӳQU.5/ۆ{@v vc cE{ļ ]pxP,zs]0ea+s+i|\CL &Pc$S@#y{Ve5sIӄmG0H;V-d[RˁQ.crhCjSF_%C =1Qet{+c2ɜ$܃V kymDR fc OZϒ"4<"XBF3֮9~/Ȯ[珘{CZ_״ IE 6)TM1myo48%c1? 5er'lTm?F;;u*|ZrȬrڊ[XJ`ܹƍe~ʃulyک͢H(ßQuiH^(7o_JB!Im:TNMJ$;v5K[k[@|0v!{be.粻&({U7i\H|2~>޴N1Z;~A%!ȇ|k@|7DWp+1]ؖڤ;i#/1RqTIhCc}YT5o?>xЕg~_NZi}mlU#*cӔmYpD~m}J#F[ ;0__S T%,f2zeFhEkcsڏr 3Tj;]\I&[s}/ Fy?g(qbgb2L|{[^EAW6 n}fWgbyɒ]$L>j , Y4 }a#=mxGm:2/UN􋙭燝Sm 0#>D\@k/ki#<ʤzj&3u_Wp˒7P._"C:);wUQrR)\ݳ:G r"]]0m=jqnmku\ J2G7_.K}aȸUQzջ:;C,o+O g҂sȧ&*D7q(MB+%BtfYSFLJ߭G16vsHT ZSiTfs(DBYp2.oz/1rBy>ޕc8J?i~܇ww(z*G.Iؑ*{w[Io֚2zZULr906Œ]pvmeO ZQ9Ua;tW=)ے@$f^‘:E2G>7i:TMMB[|NHc{^*,l*>}i, 0$о1ڔk/'nV fņ1$Yr{-tZՖj[[9s?Ƨ[FJ1[}kh ۵.0T?Zͧ[wErl#ۭV5;WT|9sΰoXg';>8Aڼ {T/Iu~{䱋 ʭطJirJDN ck4`i^(0 #W]Xc=h.-FMj ڦQs3* &^OX _M#tlm> p7x|G H1:Iv*W~c\:_,Mޑ#c> ,?zK 6)Ǡh̫ʵ.@zU T:}3iC1EtRaf<ђ:J=:׉47m9JDm=MJX5RQ^4[$Z q5E㰁:>\{[.ºv  t V% ªGjRil!/շ  [.z8Msx-)sjr{[r}# ֆ[TFCp[ͼww)8O }QmQĩOzeˌ3)`}}]si4Oh$+e{du}] wSU-v*NuH>{SZUyaoi46\bΫ&etF cV+n[27BF)d"|R؆@Ʃ-W^MKPdyȻ퍉=V+{TIڮ Cd{m#ڬIHGUuDP V6mH%UJKy[ZhhS,Xd(6g|NqխJ|MÚT/Y^3gˁc(]ziZ]Ȋ}dU"]v:Hە; .*|p=>umեa YG@>IԳ76<^=j +#/ri4doPZ=M($g=d`W;1';Э~YOʿq5[`ṆAWwJ`s]5ـOjuA ;۵ubnLJnSlRb-TaK1if\p T$,kvnmԱeA3Gu^%CzEjnFp;bZAl`rnꝯ4j<}э?>T9ZDѻ I`M<ˑ9eqJw5 V1swu$V.Vt]НIúBWth, 'ut˫DBc Z&m3MUzba~ҫ|4,͹{l̈#ncjweaL$1 = PXe{k#P maΤROQW:TTmV+̱P=GIZXl9=6EeAo*FT{P۹" g/]u)a-^YX1#'?kWY6z{SF yb6 I ~eaw qlP@A$rPOcCͩ_%g*" JF2Ogw_|Ea\;"'(ڶF:4ku9!qZ_YEpYw=골H-oݻ{a b[>)6zr &V ;m;}ع^VR>(aΧj9cphRu]*KY7' :oRͱV#b=+6F) n p6S֯z]OGQ8JY٤RHIf]UT=ک `J&dE7*)vч̌(`;KVQ[ ;j:ėҵ0S=>1LŅ$`!v9cԚ6Wx~}syEwrBp``~-7=.w2)?wjݫ-z//C(HF G+LҴoxf2A+\4 ?3W9$}&+ڻ")l7>*.I5 KP}N+-;.HR4:7NMB % :D /Nqq60_MOǿ񬏎kKQEO ;R'N"cóIY7mꭦ#xĐޟGPm(9.=A5ۭA˦d%c9QP@V4RU}J42d7 O1 UmCwܚMY&Rpqz)kow"]Kd'nEڭzGjrLL0 }eLŽçiWWQEq 6FvV(IeUU'+)!gkt< "QrFF?*dԯ=Yenmc[ \V%y#=x#Fda+=;,>1ysW*,( |Lpv9eo5f3=1ӫcqyPgE(py 5UⅸW+bnAW~FwbʒC WJA=[ERd/Wm8$:)ڃ]`އ0wW"& wu}+U0.u-X, FmӵgZw^۸WnA!_+0 7CvKxyƴK[!y{Vv`[YHcr_zk_ҴJ[˞XYsi6rilVFqA _ Kvo_W-^-~.36`` #u5Xk:9mn%;7?"i˽*g|*ڱg]./zcP~x ͹H{CPi\6wVip&P8kPdA.eo9OԽ*jyt4Fgz4kh\#ڬQT^C]Kզy53߾+.Zyb>1BeCUXHxT5ie3˖%9GZD&v&oc6>x oobSDUA Чm.1XS ne>= CMB 1 rdz5B !̲]A,spjTu~qZJo_f83ŏZ۬ yzjn[-AK*O@>[K,)у9U~|Yt(tԭZR@ҪYVB?j5#jŀNw:E15.RYWL"Ji.VrAGQ@`ٯ>[j&$[iJ`JMAA?w֡*s jwNuF3} #B ;})LdE3s16Mѧ CM3t6ڂYt (Th6<N zlHܓ`1}* .Ap)`\Ǜ9n4gѵʹja:ξ"Ij<|Ϥ 79\u!q#f#֐0}G38QӶO&҆qD<6\8$sު?¨$ ޅpQM9\-ڴ]6#cd3Ge_KxJvN+Դ&+b.tX"j\:[(leLp1*F2z V6v,m0JԸ"5.rpCVN&;"K=`3نzXy$u0\J#g5O G!"g\O,c}IR-7Q]Ogoχ)|1'UoSi3, }T-GM(Ercf[R_.z64nEm)a3Ω$6<@Fz=xѢiJ'zU{ ʱNUn{.|HԮ(j,)@9F6FDӷ'R0&rVhF'%^43eO\=\8MUfGKrY'52-f_ǭ^4ՙfmy3OW^cs-JI7Qر;O@+ 7nHVUcII gld ;]Mh%P|[dcܐ`׽U2 4k_%u vFc.\BPYR+Y9 C߂c# ʃUݮ\[, E`w'C[VZA#8?]nHܳ:`z-xSRHxP- GV=0w"ZŚq%gUq0xRn&V^fߛۥC!: >}TlLL^GQDH*Pq׬ЙO[84_H9C(ܕ-v`Alʔ%]Nz3= VU O3.y}Gf+ץtcfX`mHx@Uҙy#RJ\=ik-nbqʬ=Vq6g F}MԵ&B"*˾~t6Fx̨rwi8¬:]cB1Y+̠ʫγKMnϏ^'9M(Sx!p0[mmy#Ks}+ G©gV ^ce:Ze弾=r,Cpr}"[eO$F̎OoeuӢy8§ϯj:pxQ mō# ? Uah9m ɩ-TI\B[lwqqpN* _v0}\~)aEQFmmȡRS&'EtFri=腭:S^ۖ,:W&Ӿ[ TکM~d&j*ITN9ԵtbNaZ'j_bee% 6s߿Z$^_6'>.k:| ܟ` jNJWx- ;xv) g}VMndZXYA,F0w=jBbYdteQ Kʃgq/J~u>8Nx%IWʬ9iz <1&=k:m}#w=ߵԵy& VE}ZD̫ZX@d <ˑoBNsH13_}?LmGfc@r ҭ\UۆKaº Zb)) 3ʣk[i.ee`̣h/{YOqUK) 2k$o^!2: +WzF_-upῢBw [1ȷOX{H&mpAׯ-d;q$cO—-3H>ҟ[@֬e]FXH}Z.\̋,(-FФ*UBY gsjoҭ/.%*6a}Sѵ+]^yYv Z]2G!O>;yFUzU m  s矘DXs Q4PIx=d%gLR6]̻R4y^]d5hcJrH2޾M12=F@| gF7P:‰fDH؂j*#d g*۫gF*jJYBd`pFjskQךOZDۻv5H]£`J+p@Ǩx`X605v=ϥyPc^= -/ov4p>-@I4旦h{mg ,OA_M>zI-o!?f*ܯ\?A5%Ivˮ9>P'U  u 7\P&AygX-"y[`f?!W}߈[Yu8ɜ3L3\Vt !W 0T]r|yj5ˡsۛi;M3ߝkz>zeUp3yXW9bd֠|g5I{.~K!fv}>Gկ6"8T; ڴr N(+)/Q4WJbNb@`oDEݢx|A#F%V>lTK|%- 2X{S:ĮbP:oH1zSbj7{+`*^ͥܵռ*#{(_}/vK3_e"$oa1ǥb2kq:GjwsJr_E ~F=d^~#ކjBI`$~b4 oҬYNv^s*eoi ]]H9bS~\{02Fc9zZ%0[[GJyQ@ZXZi0@E~4WVĺB墑d r-p ӛsV-DW9VkYN CV^ ƻk\v]ӿŠ!&ŕƽܭzΖ[E\$*85]RѴ4NoOe uyks }$y)l!BU~.Q--YL1$+ ǥkcVYvL<sΠ`Gj?p~lcK}l0jM=dx|Aq^o䤇Ҥ384ƖW'!QΛOpq\~xm _)WWۣM;gRk篥]zN&ӭP7vjin!ue\[iMo獗 Jp-]OyN7|)^0,ͩ0ݏ`s}⴮ i絺1 ^^ou!h4J9;Տm{W\0*b6o{, o()ށ]q`k^F*Y|ciDkeFrp}siqC(`xX2 W&kXωjL`C`b8b~9֩=,*!z~ChU0k[NBKUvmO2̭Id,/1O@MVDJ[B g$O+/0]mDERSzwm"#ڠw>TPdcMU5-RYYV}{3Ow$>£vZq sZRڙ!DE=b+ L0N4>K7Oďڻ$* S.Lc<>Ƴ6ЩROjiŏ\Ta*@(T ȁXyFQ =&[<?kV*Z(P?r{)*$u's}% އ_l1A29d F?e%VTVeʱ8ARIRr 5(f*H:: hE-.ށI$]1z$ 5 PpkmSS[e?U盕p7ܟq_H.A_KTKk VEK!Z;]mN)X[ae_9}U_hv(v?*unkeCշD̄21R;躀IuaUۍtU,Lgjz\RƵ+sC/.9LpMU4;+,B9yNF ;zV;LkhI$\/.Ͱa 63P?z_D:w:7dIWv7"aڵ!eK+o(ڬ}vMilGJ9G}.L4r᱑ꃧ23WKi9NwS?V;f晋%єYm9y /F}Bh|Lp2 >4=`u)̾Tֆ^9pIme̜bVN*U^j56 CկԖK$7)^v)VkI E*k%d I*ycI$ )C'b}C>OԸ ,啘x\3|xnZF PF_X8'%${WKwO l{~k+L{ÖZe3 `qNLYĨHߗd2k8{sqGX㤃s?k>'0¥qj3$BH?o5v[+PK}GR>_ŠXcY`{BW;ԁ8z(d r*w_~p[V߄FI捥 F?z{IO˃WɇBw +yW`PІ`GcD w'j%ٴS\7?CpE {̪j[4 J6qfr*NR z2^c5j}P@bNvڧ[j/'_Aw%Kf&sXǽ @YHY!#;[&`؜C-FM :k}>V)v2Y=+l1ڇIc7! 뎔?-7˜c* A1'~,ڈJ7fKWS#ܦCžԿ-ep;pDӴXsM,divo.% ~BD^Vǭ)Od@@2yiIzo8dHML5qd,٘9 |VN9:vz6yn yHcV ]Z$pz lY\s?>yܓ֟ڤI2H~t`5:HWXԫc#=}6ʏ%# :~6 "wsVw Y7 zo&S%=V56KyLFx-/LX nfw<ASNCpk<<ҳ6[`:0~t{a4zǵlEWS:(3{]Sr[@qˆJU#? i֯ʦPѶم@$Uk_od(yr҄o%݆I/1߾WʪuKQGm < mo%P>nW ?k1wq-POX U $Zn_bWRMmd#dRvt.z\ݱGjeY }sZ _>Gjc汓 "P:0n'qmvse#`K,nm5˨.ebDY]k̐H܌ŀv'\ s,(n!fǙA8?=}FP 20jb݉_bq-ay0?*k][§#+7iqΛaOzTy"TE,vfQ8%WpFW8 TWvRIhPnf扇B;Rt(n+JIeV%aa2ɻIOl{XPf(&,;͒@:wX'ü[./(3qk}9#.-K0# w1SV1qԘHP**SsGե'cjt@Uuo&NY2n\*59|}:c#SDJҊZU A(+pAN[̙AUhdA ڡ)I?9׻c(k)İzߐU>2Fhe"Am r}N{y%k1H gSk:Vts%IN^]JծFA3ѻ+WL[/ c10Zѯ\K]2ZpUz}#ڝj?M`z H; Gޡ9Ad~`Vl޴Ϣ*dWq%e8GG ;F3 iu@[P$lpf+$;NPUb# qI>?>5Qqk>o!8:\^B!p&BjY~ta'F/A(exī2}hMLHSufh$پ?"Z~W=3VyY..$)%y3c͝ =h8T)-59;3nhnfv+'#Z4MƬ.c}hne.}3 &frI Qy6? !6z |sB2'@ǭ>9Ӕ>C3c;+aJyL3}zUf#$TnI[nz֠aoݾҗq?f(l-rC9Č'FIHlj2 G7X;  y >֭\:S1G!*6ycN%S }ToN0#LH_+ NmMnPM &ry(^C0De=~`Nxͥ|9dFY[#4A~4>JN0a|n2KhR:g5kb9Alq騡V3)eŸD4Wb1m:}jkahcH$pŊ l1X|}(HTG7dVEz:4mo ;lA%$5``Fnt+8]Bu bTzWyJ>FK O(1(q+ h-U'SN -/!MeLƐmߔ3|;R0#[¯uհp : LuҶ XDK.=ů\[5(x0;tskyr2Zq>'Gn`z?\&ڤ9O>qW :F-]i01oRحQ 4"E.*)ϥ[KG6T??sM9X#RWHy@Q֪EiWjw F Au=ea -Ԫ\M `7Y"kZ]=]X$öW89^Uҵϣ۝gHKfE]ŀ*ñߡ}a=Is_XݦX#SԤ0: %. V| j[HV ddr{WWV#3U5%;@N̿ XMF)~~#baѸfV). P;R_ŌM3ކ[q6#pe%Ѩ%d9#j>ǁ!YU^B;|j]r:T ZwTR6cԜHt29TF&?B/46~~OA_/jO__y/;rQ>^I?1^;U5>+!JO,N6-#(ơLԗeS| j#Oδfpbu)j\jr_cSWHEE9E1JF'S g(F0{T_?Hz(Z@$?Oz .f+')>]J|rZ ʜЊ)c1H|) `>L=aLLD3V8$JIE*T^Wki'%s5i ~$U;hƁqkś${46dq?eGSC쯕حOƠJ^;/ 𨭎c$g_bB;^Pv19Nd{;GznecjbYs|}>&bu}&L|@_WbHhg}eGcoC=iSm rFJSЂ*^OwֵͤqF(ARpAfCXį.wԁv6rN5#F:P'v'Ͻ_XF4h@=sNhXdQ5[/N[mV2l MRuHn֊Hyʬ:wMZG . mN7QFBX9 ^oN? 7qV o3g(TZvѿ(ln5붞 `pAة^o`(̫#/`H43 x8u=}Ʒ7].Qr1#ϮkS)aK~4^ წjW/pm'@9F(sWUGX*6UO#[YZyoZ [Ʊ)t-OSXn-c%`ށ:ll%ǘzA?/Ů{fFϖ+: ; kS c}޸T\If(4wO]J䬷OD;|Ei)gw9'ޤk 4NTWOxrabM6oC&a*zӉ5{xUt`vZIw{ias<c!I gexvFov+OKd,9qSl4'eaSC/,FPUt>E,:uVC'Q-gY#vT1g3F:swvХ"rCH)c u=Fh ;Q[ 0h;Df~lubB.پyLzX0%`nn\ӡWs46p쀰.4 uT)=ܤ?0"*EG^p0=qʒɸ@kNv\,lm4幎o|g=*=!h 6ON(>X"J\j'? ([@mAVY3Z^:Qn<D[UUխan*1z YoŸ ẒwVX&遺"z-Kd 5ۛK^IH uHJz˿߯p].4ۀ ɱǩ)dK \ՊWYG_MȼvA}jѨGgd^b2KKQrz?ډ]eS:I1:g=1jowrUGZ)a[iz(~ ґ\=@ju `*v1̑RG|W{hcd(;|+_G^p/O++W[WCx+[UYYż)3UZ{77x(*hFKl|jqO𽮗iDĿes`@ڨ5-F%KSf. NK8nbhdV @V ii5t>0XU^Ynlm""lSnU>fxnA^HӘvxɵVe/C͏|߮\j1Y`a$_Rp& 2R co)BHǧJ@^&9U6pd89gx$dIzRڐ ڈZe<<) LX(z'Ң_ ;c" 1gNI}*6eU$񝇾jocef4ni9Ik6Np r5ߍ4eXu>CqG2):Ǖ HE*^U0gPi ̡eA*tCw"FĻ1A֘f,Ř;8WsJGW]ss9T&0L7nzzEzZr{Sڔptފhz<9+n= [Sa"\ [r(ϕҬq۸Hbi$8D&utq*J0i^i\;Z &hV1n5]$[XܸѽBϽH٦!\ 3OK(')jD܌Ԛ^w@2"Fåf\Q=Ry>AWs+,/#Vo*g >S.D][yvekRӵ_ZGso#}OP}>4F]Y}~EZn,k5Lj. a72ʃ5TWlwͦXCZcPi\K{}|Ojq :~>l7;J$)p}\f#`w׎Zm#\ƙ?*/g1cڑ# lzksTEy.:7@֌C Ñ 9`qlc`s>ΠhqTxT>ՀQՅ*ΌvuCxK[x]_ is |yhsƑvmdf * :F#9dL]B= |*s,é9M֒i mϧjPP3ּdZf 힔 ͞ZI]^jfNfޤW9^u;Qv\=k].J9ZkB| WY>0^Ufys?¯1ǨxnP|+3@PJR& ')P @ǶsY[_!- pzk:e١f^__ѥ7 <6^'!A;07l8J"3 Ġ7z+aᡣjz`a)nѻV6Ql8LtZ-BZwV7W~ƚŨ-YZдug;UH>o-exWi#g#dq8*ܐ\>>q6-pq7J w}moj,4M:0"&H2&|0iGjf,IA֭E8`}Flwf{eA:H횪ڰDT9܏Ȭ"ԯVx`OFo@4`o@Pd~Km.>&*Vi$N+0oLdz/PWyRϺ:8g\HazxWL>V@#{@*NIjk+)CǸգ]=DHt]\2ij YXRTH;4!t{ءVNSjLi|V_M iX>IWMNUtyJAڃh:,Zo1%7vUa&1cNZ$J:{f{ҩ*XX`W9pޤ$&9[{Teb0|ǩi|?ؓR4徵h ?QRaOoJ=DYw x'ni1\XsҧX+tGOLDXtz?~-m" Ʋ%CIM,S Ȝֶϛ#c8fkϻ;jE_:Ү֝u%F>:ޡh ʬZnan)s=j%&`f|O~5v.5 `rl:0gqO ͣ)h/8$Ӫ7ؚ u׊s nCKy̩&qs',|H Lh\d=j}g'T|ldI9 ` 5NPig2H.{QWR9NOmÒSs>קՒ9M( qS\[h#t?Ԡ歜imiZ҇XTqAǩ̅{U^'!_β*$ sw%ngcPMl)Gԣh$vb>扥i|5m, bz}sAuMF8MB@ڞTH5'KNYukH5<dk=)u9MW*X?{U2'fvrz9/G+ h"G=ܽ+G̸GPSS6)VÎcj/AVI$d|AA'W-M͝ nNkE¿D1 fp ۤ'Z;?ڡIpHs/K_.2I$$Վj/j wFIJfvbPdV|mPd_]jZA&]Te%OڭU$8f& p2oY.X-c:a]鋰1ҟUv* nTHxlUj7KjUNQ(_Ҧ`| cr>fuXs m0{ԩ{ۆe2AD➨̃>J_):Ί[ t<ͪ3UPv*(*Ď]E pm~ۢvqvj5rSm$٨('iqSdR '2Gԓ-~|*R]w?*j_Uknip2-8.7.1/share/nip2/data/examples/2_point_mosaic/example_im_06.jpg0000644000175000017500000011043713351443023022061 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?s1O?Ok[eÊN}y ԌV81ٍDrj)XX0+զRw3U<ǨkM%'UO.cƥ3 OmjH_sT`8`!=>_rw*Ek >;T/XYSJ|1|֮nAyr j.։D\g>$?;wtۍbL#ۚu vXSwtZN$a\(}=^ME]ȤcZ&aǵrq%F[(z7H [rY*RIsp\3Y:qUԶ7zPL#I5Uܹ%.*UV&`Uisk6OWn"݃qXu-i>0\?Һ+o~n9*۔Tua295]18xcfYI<_%S+k,rHֲzE,UfweHȹژ:sHӸQߏ_ܪ}Mho1>#[X.IQVmջBK0ڸMsY٣sJ[z~U5Xߔ#8|LT™!(] ]xdzzܽ"A#*(T涜9yYO+|0^mU MwH'usiw5F6=sM3V,nVzGW0֐[zgY/@ >(Z皎xz}+2M$`2Z58Lk$CJ(5ow9E“שFސ! ## `}s[v ?ޥy5j^D37M~5^b; dp9<O~*=a[(VhLvm"?tp^'6BHùVĬ%L*g'9{i)c|A>?],K鰟M˨P5>jƁ ]Ͱ8=M!|FJ냂?|!+Im AuCh*dR5\i;SYF92cpKvņ js-LoK$>ՁsMڅ=zҮh2_[1Z3E ^\;\Qe#$mdp@= gJ֓y)6ۘ3yKkAg͟f'F@ihKE9>l}jx-T|E\s>|lqYq)QE{)z=+KMlm+rz.kJІ*1Ywm*#Jw%܁MJTHml@ϽTf= gsf@{\G-Kp,B=]-4-CY1Km&Eq,)RtPW*0VBuε#<ޕ48ch8ssQZx.6;0*g{[W?YWZ{~=p %Ŕb"-!G>şHU]2$?UdK*mhQEWS+s0; Xg/1WY\vxsccc^Df,kX̃j;'v\s[e3v|~j^EsĖNReDž8<}+m5 ukS|r.;3gӞb5q0*}{V``:V!L58ta6یcǦM'\ Gc2dny 38zWpyu?/U4[xcwmm-Q&V xww*$渭F2k|$zV4H2wg&e ԐGJV+op\}D{S5-r#c)9be*%lFWOBT {9s4FwcBZ\gi}q aLHLW)Y]Ȱr*AV If8}[ћ"m4+G"՚|hy9cz֊G=I bgdӠKi&<=IVvYd\S gҲ=*nMۨ(Î֟.(R!~ks,r`~%cXMӖO.}[sSwC GG65`$id{4?޷8lIR5KWW|sErG b]f;dcII[̖F1$kGXs:lS{M^xe%6AcA~H j4{"ذ'xuSPҦ*m.VIVZ[i8A;4{]J;yU}+h#Ɓ@;[B)v$%_ik%s٢X|0*:mQֺ*84-TKg̹>}ai49^{siD2ST':v.r0 g9>Wq@ ːL<*$\7Ȍ a޸f3Dw/Ӹ>ɛzb[fOVpql=[ՅՏlG֦> w رӨEgϨjF9"0ڨU_2e`I2犭%wd=ҩɷj.\G>EOTEĠ:;\r:i8QE}0ē19O3F))j֟3G"v?7@ ^T ej +BV%5[A s~S\jwl^Y?$TmgҠm:̴u*ZV^\QؚMf/s+[Y~%Sg|ʌ3M]aǾ$Yjf\J8x-t*e ^j\}P1GsYwL~5g!VU!R/[s3|՛6Ovl["mWV1Z'϶f 柿=ֽ9tl>JcݸTfV&f4إqs ~5^u/6$&͎#}g\ iQvGXn+'t0;B?mOɵ$s̓Se9SU&2X&&3F &x"M\sW<2vVlĐx !yA&)xd;W`MGVZ8gxq_|eA^[C|[6Oc*#X_;JHW]-ԑE}juZj6`<?H']'dWJoǃ}# j1cڟWmˏq3*Ү)mqAֱu1>εwx@a9?sikyo"¤ljMceyKΪ7pM3 %p{S#W!f$S[b+OG=kB=*]rLB򬯃Z|Cj6QGZ|N" vV8tT@<'5j\v~ëA"Y&#(n"'AxN}Fcl\\YZFl^5z3,.)29kzǀ1lbv췇ެWjMwk l$m եiY5d.|\Vc>tdJGOQO2H2ư#k42 ycO y4Qɝ8`Nm]\d(i;(j4c1fc{ ko+h1h-rI$svlE<*`<|p>.c$֬{-(߱(6^z0cQ^e6-./>r׌G88{Sm,i(:cҼYҤ5l7{RU=kLB9c6l9|6ƥn+Լ/:hg89Z^4NY$+g$Xp<_ι7W\7Ydg?Rskn]DR*8\Ox9'#oX~u?QWHd#8?>"O7?PyMswj무W d# (G/aZ|\,=հSܚ{_a'`Xy-o#'|5:88AV8 ONK @Ϲ[}kϼsl`2̤9ֹ;HZǰSº}PU%g 8p?_½e<:U$9q{d=L}_p gJf{ۀF@L{rkKTT'7=MX;A<994Gi ~PZ@͞0#3SKKSqKIu6v?*Y͒ڬ֋( _.%A<~5B+gnܛ *AWh.d2Ky+X #+̰$g5i0=k0#!.U5݌?X7+]M@'?ʼ]4+>Ӗc\x>GQVF~jY[ Kq j 43! 9lÁ N,d.afLףVuxsLh9\L<1D'-=zӽkϺ\+U8Qn6ZË7X׍z~6+|z{s#^"+κ5j^ڮt?!k'B\ZϋmS˕#v08] su-jo )6 2+Y,m )4I$sUmY0<3|+eoGdOڴ2C氵mmu,1|0N+ vAd1j֓d9/BkDpG] 9;b+6$jo:lʹ_xUuĬw=JtWTtD,{yL5~75,[\ư\Ü.N}lz˟Nid@՟6@3b8.Lm+xG  `(Eyv ^zWSZ[_m4ʓp?wzO4c JǗe}3GtۙIީ.֨[i[ċq];[9#5ŵȌ)ָI!|:uYl6ca1X%*m#$[P\TI8kZ]H1#)r6Mh%̟aR[zkm~LLA$~]lv[$QzOԮ-m.RQr=xgVFVORҰWp;}r1k:qW KTB7I*Z| O2Hg\Wv7]o㯸v#?]ӴD!H]0qSP|:9pqVbhQݜq]o<%>N}|F]N>uBw y+#PBS\֧>PHW]첑p%cp~c׭WōuwT,!r}+q\G':$trnЏSu͎sKu8X‚Fv#=W MQG8 `Vce1rNP[&Ԑ?W H@U$/t*ېDan${Ժ. ɌKѐVҮIcÂ8=V#̂no:Fykw%Ŭmn|{}?fvv8%Oz^Yy9gpbb;۩LD 3߃]]m㼇v:O-djGe.$l.:Tw7)absGV>Bɮ%SylzZfn GCTHm# iD^SX!-8Q=LyC =;>:{tIR:$?՞{9bŘcM:tsr}ڔv,V+6_Y@c}r+F7U)$xT/1i`\ǿֱ!2!.x5Yv!˒[v~_@UDnUTg'`:Ȣ6@sMsxᐏ'5w،~WtHE[!s+y'g|iuhS(l4}r@kz>fI|vc*A? ^77|α$=F7YrGZ$Z| {r󀧢cX7QiW;p[6ORl!GӽfjW 3K$6}k[G)S5>lfk\cv6b*y>զch˫mj.C?O^R`J]kGΖH2NvZ\|]q6QPxC h \No?Y7{X=ֹ[;29J K; Z-*1Wr`U\uNU6@aOJz)7RZO8$p+%ؙV5k8%FkTnI9k 4䍜aEZHD`ɪW(oK XrT)v:qdII@{QFpUA 8E_6!cN1U& 7Ou6LdU@pBcԑ5I7Jǚ~1?5m;Nn#@ Wt$\1X_ӁY*:Rۮ|r 3Zh0JYOHuv * 1Tf?k 9cG /a,rev+7 %7@›A r99]v&e@F2=}궘yq`rq^hm+F`+Ed~sjr~NTYtQ_j ќvEڂvrk:%Px5qpaVT7b?uY.? EIɬ3qbr{֪X:@6@8W R8<Ɏl!cCUVuWp4{?^ߑ?Rŭxeh$ʹa*2"; E-ۭVd A]bX[b¢B~7KI?7~kAm,c֭R ϥ>\H"T11X~c跀HU;>9o6"pwr$,nUqڻkOCqn>b<>Ŕg}k-Nsd!8e^[kZz+2Fzcc Q;11|5N'5_ܥ0dYlYʐxI ,5.+\Ls`4TI QAoB;Qް JPYv(s>44O+#qʹ'<5Tj36= G<5`W?6Jdj?j~ rٯPIH ?E4.d9j+q? U/RcBÞ<#- ѴFˆ $|d:{ڻo}%{Y%}y'  -S\]Hov^_kE *eSVEQja; DL~dUmVh kBCHX$UPwHEkAoIxUU)wfʎksm}4,]AXV wȃqU{bG}@5f]Z|n-cY RD9F~oWך3ӅdLAkD"&>jv[L3\^G*6zee\5;\F BX Xӣ?%j+iZrb ܉-f& Π~uxjx>w JޤUζ $mq K[ 4 rUҬƴHo$xHե$Q$$'.ݫz U{!!܀ lw_S?ny-co^OpJleQy?x]diMπ(I>Xe"Ȅ Ak +b|rEQNB7FX-Z 7]`nmV93?ζ|5o&yC *hfvHnf\+>Onx$ښ _(MW*8-O6-3η{iؤ;N2=+M֭Q+99uh5q ux]vu8*{tǿʹMye95\9ls]o ^yRɮnKoUǐ?)L}*ޙL.[w{׬MB`%?շLv5QNB䚳Oi$N u ^}>Is4}ʅWfMyGCO7pk*!2=)mqުN ڷ$y@9R@[DKw*ky2Fabu%Y,©xg隕nxR zթ5 +:#8V}YibH82ao\`0$k.Lŕ䑋1 FFաP OAKNTQ^ [Ҵm3=B/}ºm OI0dܙ3zWN-HF2pOg^\CaV,U-eEYZ:2+cO$` }+3R6caMh Vfa4{[P'TYeSjR}+>{)$\3q]g0#m[DC޴΢'Oγ.w9?ݬ# 9f^^RD 40z7(vf."!M C?/lU }*/>Jzmrt֒jOnmA:Rm7QɂHޢ7 ݫRa} ;򨨢g޷ld$ﶋ})d* "Ć1o}+oAA&KΗ p3GxˎHK<USS\ou]SY!.KB0S֥ny>xEOjZBi'%>lhcK5f ;sW'<(rImYk2=6s\j ,OyMB_Ο%=v9ޯxbض^є]3B+5im-ăb+z%E9yYNf 1A d5ѕm/zx+@iMʁ[ڹm ``qֲ\R0\̒,($-Jl(y~VgIET CzbwG!5 h5? U7GFLғn"X]@ӤIYcR\vkVMC|OJx.;0r:O=y$e Al05^KԭW(},YgpQ57U[-s+pȎqzc\`Ej>dDuHⴴk[q5C>ùE^{'ꮨAZ<`~V,Gs[6>q֪wƺ}/tJ)s]nhdNI\/?LAIx{"MAҢ(nOhʤpqWO6 ְ^:HyOcZbGFf0x &({W/vYJ,ImдifJO+#5 XmE7XwHY 9_su&ʅBeu|G$ 1jΗ?_nFk6Ӑqu67^a*?VIJx$?.^Ykf_VC]6sȠ5[D)P2;@pZn/漘_u*:`jb b2 $~:+ S2pymvjr9 df-յ%*۷0u顖k،Ĕl{殬fI1sy5]>2s]-<׀s/_EgQE}Qj>i ~Fe1ӑ3t/,;g:LYvQD(VhV#Pv\Vw&vҕ@ڠvED%zR: 8RBj;vRqTݱ;V-ဈdsԓ|E,& 9x>| Xmݢ#=a/59X z~_^$E@Ә^DC 8X㓎EUZ$1\ދL|{T PcPg6cҼ:I5bJ/aQƍgcynEt8~=?$x֨ҺOqתhֱo!Ebem6E"y[:~U3ʇri=H>Tkv9tkQ0=knPC$1Z%FNvkd2m :z /#Zgb?l[I-aڀug8ް[M峇tHn27 [/$tٕZgdFB/9*{K/iEq'En}ݶnֺF.rֹ}IʴJNUbaCqLH.Y'5nhgN8U=wŭ^5UrEr@F@`pGdxUKJWmc뙑qzUAN}rzd srشqWYY9'{YH:t4P{WGk67Sck\3XvEzQO,SA& L֩_D;qT|clI"c^8҉Pɮ_N՞A\;|# :^jW5{++Չ?ʸ}{U)*T տ1YC m.?$6Of>~!{qɿM[;1Qݬyd;z:--٥m0d: "8|{ uӼY Ѥf3-DZpkRX%V$,q~ \it0t#0fxiJ7oÊY}jbBg`KVF5n8BѦ )?AޫFj́ =V܄P* ~#Kge5ȳ˟]]V,1zZTε:s*y&XR{=+L7 U5xJXr_yOma՝q@2FzJ4rXݮrz{ϩGj1ooSVAˇ#8^ )aa|{`o|c:|:7Z '5[I gܰ|R$ P*G?Ub Ǯkvn'38=N\II vZuĄtʹC)0Oު/  |1v/^+ܼ)5#8|Ì$ƽT[l^{YV%G"Hw=`{&R: UrI@=GSTWIHfdh0ucMMSHVc׫fU*,@ =֫xNtvvG>׾"K3%no,"'oe~X_BD)Qrcx2c#|KgLkG oijyK/˳&3)p!u"-J|Zn;* gooPiUxbUV܏]`2&~95$O˙ 5Yf=-m氼]n^cK7WRkH|qc,QaefӒmQ/5;K߅D?a]=/ӂ?~u/Hr[?C[QvZSJ0P58]O- m;˷>Ju NOz+q9'-DϏJ:cnrn4}6SI1nOXV,n AUVJ^T;`uC[ʹGs7Sچ.!Xwu⫉>IکjF E9]5Za%Ctc4du-ǥ{7<#h#pXv##Ӓjd7\ז#aR˟)OZ:&qoHѸ?w6+mFDc+u kIQ¨V]~'FyDvf*^S$M:5#ج9q֨Jbl<%6}Wi{`:d׭z"5䧖s늇Y;r7m~}}go_qՓwYGm|EEkR'OZkAeylrѸ?֯'˕ uʟǵ>y!cq#OsȞ\RƠ Q{PTBkA*0AZ_ 5%' ejzgrYPTwf)aTW!nmĒI#D &?Bz4:^3ERׯ'c 0UkXT󬋻+ < '袾˨Ir너m_v?j{q߯zYq* %т*ϸ%ҩx( =$q2)l =l1Z%0a~x~oCG Tݾ>ǽv0hm1'dw+|iFYKbۅI5K\֫E}o 2r͌=VF ;,:|everw+ڪ˯_Z-- 'jy_=r*) ,:<;SHYTӞ}DV́{tgit݁pBMkUeWu>^$_^]q^L@WݎRfs=2~=j;kKms1Ig Bc ֹy魯L;תr+jEaF.hT-=NJԣ SUJ(f@|{b'`3o:JznPO7:[ ǿuѬr$^|CosYyu60UI?/3~+zs /#?+8C>)9.RvE{$f'D_LJ:c嚩atvkrN|Gd-!#w=]AȎ2L~r%p>ڝ1[&xd:#YcW,|!`x.H.6rc?\V) *D28MM؋ur72ryST3ҷ]ްY{'+6+8=)s 0FǠ´̒\YF~ƻuT(NQ25b [&U?aZu̗/*Me:M ĈO'8Vl gKSd_P?LvCA G`]Y&zKB,qDDkZ{'>bҳQ1ޭDjD-a^->Ԓ5d{&]M h*iPi˺9?W+? ,>X=}OJipkkˀqƼ١k; KG?_Aq w==n$qı}ȟxV/ai3 93z{M Q<3_[UaUZG~+𵊼3ݻwt ` )N?!rkw>`ך󖶿 xI^ I-ƣ/POajΝe{nbx$s;<5{~{Mَa> lY as&[V[Є&وYTi8vQY$G#"S+ 41qZYwaqk/$MzttU4 #֮KHcnPAEjRzIӦ-[C?1#(ti%"5 L #H,Myߍ_}r1RÔ;;Ϧ;OAd<̍FEM]MR =G\Ω]i-+μa-aEzPhGvL!}aIA><$$yxuܴIsT3'PFsUC|ˑzx'E#"{#M)!@*PBBΤW-@/=j@%LB<Q# AA9۝4֢i< R{i9Q?ʴtLv[֦r\ 9ާAAVc[pX3*6 O+S!a,yپPrTw[PtQR:N 5q5X^i#*8FA23|eю!彫>Yq~OSe{CsN𶧬^ȚEDnp#ݞO<ƾ?ºRY#_p+&lc1=GaKtžNM°=ƗvT8gX(Ws뚎dIirNzciJ ȬkgzUM7$GLqD'ҭqI=xzmm$ ҾK0=:m-F@~}=zs^CoZ袽B7v3߼^"sM]Նu1;w}ҋ_*|>jB'vPc8_gs: iP'|JZ|ɵ̨$kU83^xc:mJڴYE+]5ob:;Ҵ* >cXkrF\LG8wOb7#⠺Ф- CxF[M*?ts=}W{wBLLCVl1. \_Oi dß{5WwTn-}+bc޲>X5)%x@[rm$\diܝ,+"#=[hɓnṛ zW?,p;E8Q$4iaO Rdt LP0x"=*սG)v{H7[1,q #\ַ&S1!QԚaO(\@9#ҮmRmp: ^RVJf2k%%ƌl}kV[!6 ;ֹMA44eNO ձQj˙Avyo-kVbN?mEpA(K+тMRP:`W>"ʑ jxm$l)vE?Wtʪ$Rfvq 'W溒c2IQ##n 78x.xqMw&3Y&]<7ky#rR;^g& tB;v^Ayw_muW2Z79F<oןhg@o Q5lmI9aGҭmecÂm{xE[+ph2?Ͼ(lxŕ#[KPzu0ݫm25w(09=R(]$1#t۲Xt 8S#?z2ƑK&q=M`=NTs;L"#p=O "Vpj/oᦅ\֍kn'=j;B1ѽ+h&)۳zI GZSGkx&6`g袼LpqAst~?ɚFg%k:AOzMx/k+ꛭI!vj)n{4ݰY7@/ֻ yo'uFXm9遏|WqSSU;$HqiO m`%U;| S]ׅ 6d72(!GA~k~5س 8`O(s!cV-5?2UY]a+#Q;V> :&UWJU]z4؏[b{sjTsc8osFs+|5+5{Ub(>yGrz/ֽ*It(# 9OHXE݅#qӑ9#Umo Ew2zeeAZVQ x7aOJ te~vê=3Q,i;lj{uGnՖRz$eۓkw[lg4pqQf,5ΘZ)O^6 XtQ^\H'~a!ϾkZ4iIb~uZ? <@& O]i.pBV|p؏Ea BBDT3zԳY3h=ֵ-6&r(= n8ՋI ]BΠ`&`/%j<\"Hj l.㲟̵|`OLgiD9eU5~ɥ3,:Y-OzWIsiV:X5?mn|ߡ>k2WctfՏOSZV7Ɇ~pWe8#v*1WLϥ_WD j*qzTW׋i뛧ffI$䜓ZAsޣ䂤gU2 2XV]!)U&R9Wt٥ SF"Qu̹=XE *fH͹NO"_Z*[>ņֹԜ7p)'zW 0rz6e]!jhZ##ڧhԦkh7ڧ*JcP7Bʼn9Ǟƿ7_?EVq$sBX=-+lmtBB'?[oi5u(d\E8;I#g_W4Pxm/$@F&\a~yDd<`p}mh#ǫ̗'1Ώ k3;d]mLAqljNg[)2o?6@={X]ƻcs#;oΥal1mF~j4 ]jKn( !OOo %w:p*zlr኷ tljy0taZTqa,VLst]HwdV"TcTo"Nwyso蚚ɶZޙżet޹̲JJ lVO&qlO4‡<.cfQWYpOJVjv85iһ54r o-4q+=~Ozj2/ֵQ8ipfӆɬ-#F9f#b8c⩐Bއ;iWxFgֹ(ZĹ}68jo ;y:,2`r+DHj¸q!#^-~s$:ZJZ"?\n=ܯfG2A?q^ h9rL e_oNeш]֍$bO&~;ʅg8zjnA;xadRݸ'3ګxN?'?ҹֳGڑv~HbźGL; ps޷6REal|ɪ75gi cDK{uke@jǹx+:.ɬc.pxڠr =(jLX\՗xNF}JҮ忌fhKH:0u1qu +.Oԫ[]/?h\&eY'5?#aqT)hb.CPJ?l~pg8VS}+i@\E=*v-ٸ` -}j#/t ,3Zۣ/4<2t*gmϺ8DV{,j>ԫo:g;~[~56赮~+;im`"m?UZbHvl^MuS=Qͬkp2⡵Yc?ֻ;pp"klt⢟1@-C}<3&Dc8}N6)n=U?zB1X7`zU)qZ=ۍάCqַ~D0MN.3*XY^I9j̊0BW9{qpq&f eIǭh,ɂ uQaA L%v\O:H W?1D3ӊDfff<Ղo?=+ȫAOS~Tۢ,{(yD8likpp9*'WMjHyn-k++([ܢ@~UB~W;ilYĹgޡF0A3Ը,>cII%DBzVvYV'|Q6'_XHW.n˹2H=q]z%HӽM>D^kƧj.|GF>c배+'M 뇼.i\̪mzS.X }GcќלcV5{cu{`knO5"79R2c4*Ha@]{I}D@ݒzQ%W4 tn FגxFgְ(l;U .\~V8atpW;j-£pKzzb/Z(ˈwGܯUjރoy I;0j A5+[F&G:ބ*qr+<5j9K= #$RKyDԑXu]:DGYQC#=Nj~--f˻d(]ҷ'a:U` *`F MTaz| #y'n-k+!v$?pIlֵޫ/.7l/jL~΄sIDŽ/f\smWqo|.tuRʹLq>³(mًrs, TEtba+>PKWʒq 񝆖8է?v F^ew{sܙ,`/#Z&0{ْnɒ/jދ6,zDoc݌[ÎvwZմH s"+`7LZxU,x5-Z]I6:Vܶ4uSpe&:ϐ['%8ANz҃)sRCO5j&!t3ڕ/I7̧ENXUWΒD0")QJR=PjXS952C o=*}(McqҴ!GX Մ$8N_qT z~jw1J['#c#j)"r`>vYrHֳn57~u#1<0Ǟ83漗Ƈ>--k+ƴARG?wI;GNqORMH+rTp5)NS$dj32QR'5jDW;niRz -G*ʙS:F-Q+ϥQP@7^Q8ay('͑L0CJ;ך !]F{ӂבFgְ(Aw%QZZS#3'tDmu 5FmjH44GXdXK7:V€punws 5nB ׅxYOIuVgQk;OZma[(8뺆<`yg;7 s cb=OּrinaS紹9BOpr+욉`(܂;0;H3+3R5n n9R7r,~W#SajSSgIڤJ26TSb1 \[.ʋzKinr6iUmy&6IQ\@T0O?:Vla#xuE8ew1&@9-&=Xzg3Z(BsNNj?3-UeQ#7i ׵XrQh`y`’@Vpj~L? ո7iv`jHWWTVf`TiRVdsi @ ey6.\U{]6@&@? y/I5):{D@SOO+`bאx?Z>v:Ij#K"O ?]SHp:K(BTMybȽAW^[2;U# t9WW_E}bAnbQVlM">[ҡ3mN}k:okq4jn9 N6w޵o"U',zWy(dKNVd4WFrdq2:qOw[g>`PAj9\RB:\7YV84 qt@y5Z qy)X 睯҉!x\x$T w[#}qQ6cΡw4h [\ߚu/J/>w=xClZ[H; ˖S4ЗFi<) IIFij9r:Nlu*dqNyo-k&~Zt. ;@jFISRG09\P78קqXMr@\U3 WsZ7j{5#HSS]eݑ{2S9L D^I],5Rvq?5)IUhz5VWhC&F]4 2AN2*X[;S^c3zS w اS6nH׭23nU0ITH@0=)[ +.yJ9|SЊ. EF8IѐU>a?3=rz@4{R猚3FN)|S玴 Zy2 p@,ƼMwsqk +S7eRu~?/- aJ^,aSl%㕟swJ:HID{څcKMEAER/mgTVU" #o*^c+0 ?ju8W \Uq>%kr-tqK7up"gsa'Q ntOo#\mS5fZ`Z'8eb=V=\ yGP5u {.*Wow~!,ڸ?ToSGM_}?aOM\}*6}*&zXP5xEToRm2[+)>[7}O'?C'~De&&:{Y~&kS*[X F]@ufME?*5u\ kM\˽#U \{o*|B?NϽU/,m\˵U',]_=U(w6>?m\}* W?@w?ub۾e?*>>?T>>?TXTRxU7\}.}%ʋ$@@U(((((((((((((((((((((((((((((((((((((((((((nip2-8.7.1/share/nip2/data/examples/2_point_mosaic/example_im_01.jpg0000644000175000017500000005447313351443023022063 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?(((((((((((((((((((((((((((((((((((((((((((((((((((((((X7Kmif><{?'O3oKg??Ɠ8lDOC?Ɓ|'ӿ g??Ɠ94xC]-iN7_sCx=駷O7O7oG!q4x9koAv?ƏC|A@4j#]iN xziih7_saamޞb(_h??Ɨh>?Ɣx7_##OoAo]9h3ah7g9kah'7O9xSiy1OahKo??ƃ|u'Guq47O9xh;_{_C" lyoddc5[rKҭ aGlXX-ǯIcڱ1,{.1>nA+6H\a=ח#ln-*!PYqS>K9@F~k\22zSnS@zU@jqڐDBU[V".?*?׭Rp y-{K5tsgpN+gNEBďLUy*}+=¾Aҫʻ@[P0X}<)n&eaW+,rBϞZvZ0]|Ud>F |> 0=3yF{ ƺ/o#^qLnlb<^E '=8)v˞d\20*V6#zxuEuU+E@tN89֥AG3])QTUsԎT-y+7TC*#qY08R 8lVP~^S0YcH(ȪQF9p5,S8"K{:\`g jTއrqpKC6[$pETEpx\ҩ@ |d(vi. n4nɦI}Sk*\N}G}L+mxȪC9iw0aXeT+EvfR*U[I_=I^|UЀwSKE4}2*&sT_InvF<#2I43#eM?|„XgwOkB ߍMHd Vm~A % FǮk*n[=" ['EGqH7taXSlP *R dgS|D/QLٰ ix nކX$ܚ9< 6֦%#Oj=1VH|#1W=DнyN0G>ަ*wfCz6)W,.KF^/5) vJ~}%ț6Nv!`QΕIoƘc)"99iɫVnaP<,:YrF޾xA5]J)),}ӊޚQpI7MinFiqJżv@Is dPGKo{A#݁ NhL1@yP=9cPJۃISTA)&˜vhwj0nG5$ݳ\g4"E<jZE]p".5=p*b.-yz)8h 2=iD#Yt~SZjOAO}8M=jYp1Ҡk=O}.Qn !*ųH0ȧZքYbj[o J}s4K2ɼ01x~ɯ\?|]o '9H ;smRC*^)CӑNwBFjY 00)htV4NP3KM^i{R`g4oJHɫ 3 kwHgA.7+v]VEb8xP+cջÃG^m:)d?ҠC~b3[0!]:{&ծU2AH\l=N_r9iY$l;W14>r 1:3U X5qmp%NEkA{uh}amu&p;{]f䟹Z1)G~~OJYq5*7FyUZ\+jOa^cg $TѨ^IED*AjO:\;`zU6( H{Q\sR k ҩ.*2_=J@y▞n#q$Q:Pen>jGnTS.jH`S_hm%3 :prݡbq zYԜ3VN1nrr:jd!aCLw]I$pqZ6:VFzysH|cr} UK=;5 JbjcCSkab52n[6r`:O{MǑN<,;{ӇOD\SzmI7*$ur67zҒ=M_TYYI=k5ب0'%_'ד[噙_V 1G."wm\栯E7z+۸Si2\~Mk=K_+ n\Qn1TW|£J/rOZoI' zUx):תEr$m0}j@'Fh4OGցLx0>PrjF՟s9sU Ě)ګŒ1%L$i70 >0}}u٥E`kIs.Nh[$Tx; Ukl~&2ӝI$qHצBjX VdqMcijN6bR)OMڶָ$6kw$S9#8Y*E2}@Ss7|!GJC'r $Bon79,i`O54녊6Q#iv~:{OrɵNZک]қexY.#pL; qIC][`HۊV{uۉ<P]%9O)XcTb.)84#v&Qx\09#=izRHzRFpqim"lZJFkk`XGأ *t(#>ՠtɑڨ("S圩 {w1i REf[sVتCʌ׭cyj6nxf!mԹ'xP=* cߥ%ޣ1Eۂ޵O4{ $cUr1O:ԩ!O[ڙ3m=iqҌQQHBI)3ڔAa&Q9e{TȤ)qFqGvI[rǭHzoׁE?ש;OkixQ֧6'=sP4@ڳl sPc^٫ qY{G;yT!XޝEA:nU$rAU T|sɧ@oZoM}ؾ} M:RdRESj`QE&2i6т+70 ^˵ݬlW(V&,g4L{sjKpV]"&WఌO5-ń . UJK@Ci9SP]E&$*F)) Ur3 }~gUtmrzZ+pT3'#HcZ;;`^$H! G"n,!xk>}0p<I jF, S*dȦ4R!Tii_C:֗XXe1qh'@gH4\ 1JAx2VF*1ϠM73ҐK@\dr2GzH$jx<҅4gڬk+ȟ! WFA5&uڡztNc!uS*J @V}҇m񹺑V|X=x=*[f"`s6P֦&E>"nNNzbyޘ'VbzR%b }i$X8=qW֞$;P916U;(c3!)0E[ |] _@AMzzTH 'ִoqcϭmM2!Nk֤4Nn$T✞TVGlf@V0VPX~6[mE#loj5c85*ϵy܅)\FOD?ʱ^LOZPv=iw#a#0-zuʗګGJ9C#޵b84rz|A*m,h lֳ Y#D\P*0Wlf.w^K qYr[9?j4C#a5T@Jѩ@d G-VwZ[wr [ *@#kV1T)0y)ʯQ TP.Hչ=s&v1|]7`GTªG&zeZ<u&7 dQ[\*F:fb18ʥIV~"}y~UF3(@1mpNKwVQʜX&lIB;Z >s$~&VUcP(*{-}*_un:b.f3Ti86.8^G v2ZmnU8H7&}3V}Hs5630W)}zpqK]Gh;3MWS杸ێi!6A {ԞclI8h4@8!?JZI"d:sBD7J*n)cl;$t&򻁹Lмupv$J${VMez #έ fF*Jrzv9E^@<)AO ҁ(8, `TvYMX$ޚŶz՘i3FqKxS`R֕ZjͥlCrʇ tȚ++xFY@) !}j0NUU*OaS[m8ݞ3RBi2?*ދSY\}яc.K*1<_Yđ|JHl G#Iф.*HǼ7S $ɺ*} b 8<0n@c[e Lu[J,'?##ҖIh+)G94lJ2O#u`RFy&E&rz D@iRH4)Ը\Qӥ#6>[K|Tb׭v; H68QPFU/洭9r|3[ x `H(q=-aH7{U-jYHpl ,bVY)e8Jdc ꬥy0㯿K! 9W/kHİw<21suqQåM<(48R3p{XUñlb K(n8`i&J.ǙqW723Fq)w{RQnL7FqU :5~;]0VL50JSA SiHK c@T1i P#j̟e#i,Hj^GJI1et.ykA8 GZb;ԙh=Fh ̣P+XJp9SI pЧ9@*ztVNn ޽vRfuTazdzԣ4}Gz &9P wKIYҬi[8ہӝ5 rNkJNMZQCF%9i0kS4?ܚZYndq]+yk=+JMww6p*}`jյ6`;ք|dS[psL#fJ;R u49p<3@^i$8\U̙=d2W< ˂qpNЊ:hiW՜@ǜq18<0q;yJH5;s)#=4&@88L2i^i#ڑ2kjiVi$*FXoۆC<|8)k.?*##c&Q\x`nحjN1CT$-qj!N=3W#F0xPx&"azǭL1~M6 ]Jm q5iET=EuVrj"T[9BGTl{gZ }q)SH"+$IjLS%O,s99M۟_UQ$A+zVڋ*0{][Cq!a~SjhdA֤HU\\UvRIQMN!UHޠh;v4և ],QzRkaJz}+%WscF2㱎7$+WQWfиҺ} ?,g]Vc9tmT v;.|q-엨}j a{2S'nc@i/4 $E]$y;ʮ vVF!WI3z¶,&Lڤ6z0QދٴQTWVm4 $dں?GL[Fc`9?5B[)mԓ`Ux zb4՜:RڪIhxealBSؼ>PH}+"K [@#qwÖLaM\9I&7 ͛fJuZiH5h@>. >Ȫi¿2dyyA|W!WN t1ѳK%CX5bGU:~U1YwO52)rOVVoZ8M}`ok70 XU-1&޲YO{[ռ $t5BawRsP[ƌ2)0jaa\x|AJ6csԎ٭YDac ܴ"<ִ"p5*NwcVfb2FrGz Y Չ{+~cE羀8GUTUYn SNp֑na#֤ذc+u-FzFD&mtׯ<=idp#vXo0J԰,%pUosڲg$-$dҳ8@XV7ERVjUVEM\O5ruHŇh, 1ЛhɪWb wםPqP\ UISUJ*ޚRf21v-rN MiI!NY ΜNMX!i!S\] PF#zƒ?*bpMR9$ žU9#S"Rfl%~5V˟}i³;3e}kbv 6歭C+.7 ׃Prq޷,K{ɂ?ҲcjZI0z֭Gڂ:Iߔ*\z65&; F21u9 x؟'kՃdb>85]ybrNz$Ht wEqzi(p)DTWc,MX&5IaҒ W]=I4-.Z@/?} "bq!I_z.G]\$ W1I=6ΨPvwn "Htx|G43֣w r5mR|àUeY,}qY7W452YSd#OPuA5o= \n(cɷb9{ҲR_z\8[u#X-(#=I*܌ǡH5eS߸5q (sLM{Lg*F]K(by#_zjFwJGSU?՜HUjͼR\HS(]zW8W5j5[bUtNZѲoOP܏Υ09kX@ :9H9N'c,2j$D GW\D! Qu I2]I4Q,f9dCxrWAa 9ϭY6` U9d+k6Y$ޡlc8cvi=ܓJ7 ]>$d 횮2uQU.1A7Αb*}ODAHqUdze|pbͼ{N՟IZ'Vfc%{k`vEj0g =}ۄX\c}h-c䍚O(5O3/sǰ}͂~p>@Z̎\SUF:|;){hyv-!g+'8aNG[[ųܟ#2?B;wuضO\2Nix#+>{$w(tp~cڵ-mF!/%cN/u+ID sZ"2+gu5Bg:V\rC;F NcY}/,psUneX˞أGb1z,yqHGZtK(6\W?A*mGD;5"hbNKbW+p*;8sOֶZet ıs淠ʋ-ۓJY8{۝nyXגI{`+9w*U$裮;piG8Z[ 1&EGS*Ƈ҈gYA ƥ55aʽGOH]8׸8U$xzuS83}* s5n ECp0+I޳ <j͞CpIJg\'/!@wP6a)]¸_Sְ>k6ܱkws^%܆;U'VR=UG̭ޓf30Ajq'i ِ1'Z=/f#iw-"r~a5H֨.>)ENēTSִvH6(_wL7j.Tn{v_zVDN=jME_Ӕj;WE"$Yq9J;6 EU+Z&ŝw~:5W?p;"=fX.I᫋ D ?yUu_-"xӭV2kTB-zSV-mb11F åC.}_ $NP˙qvZKg`vkY伓!zvX4%G piH ˋ$k~:( #糌fO?\XFXA;)h88ըI+.uc]})gPP Tϡ7#*Fk"HLonev<2j0lGkD ʇU=qHPkO8CSYv.rkZs-̑\;7T:Φt&2}[+Q%,Yݲ{8P8mM^jjT<՘#Wri+NIAQZTp)ӑҝHFzB)# q)HPr5FYsUgZI]>y̌0t=@ʱ\"хh iVG:V#;Ea_MpƖ_6ʴtˆdK$= qҮj:[+*=EOUi[_\sgx9%ۓ]ɹ#90ǭxmLʽMMa~307q5d^[\+:`pk]Z#JP!ޠ9?D mavRj+iL7E4g IlB+N5 1*Gp S<yqQ;]X'D `|UE~tRf%?t[2G&4L'zP~BNi*LF@s֖Bidb#F6 Vu-|[QxnJI^k.:s\G\қCО6EJdZi`[1cag'w*#r=kGLY sioapkgo^mn=rӁxElTN)$[ Nǒ+=%*@贛hODnq'71װ\AeHW`9p? X+i^3lhXp%9<k6 硧4PZk\:*EQM;ԓpIצzn ­un *9.ǽ5Fy'#8X9 $Rxt1~7Skyطî\-cv<Ǟz ͐SU(qD`0+gORF~Y$ Vƒ zCo#)kRX=O5_VX:szLPDѨ ^-o}n#R{}YS`|¹%:qW.D2=_miM0cGfi"pf'C "`Tʳ〴 kF# ޶.gTXԒ3Үʾ`gr 7cQMfRwmH <05[p3+)ߕ*neM3MA5,^԰zJ3jHVԂ}58zUK;f2?Q*CTI=Mhb~f5VHp梔1U6<*Y I-ҝ4bžMT5,KҼ߫FgUGk=BҬ6y(PYwr )NOm8v\Vg#+1k.ysYg1-^ ^at}?:Ԏ9H j+ASdMlҡ9Z`Mve{d g2XU]*<mKqS~-F!-;kojֲաlb2#=2*Ôe'>xByM1"#y5!;TJqdUd|U9]_䊯+~徕_#"Va'ޭCELU-װ%̊ȼ)*2:o(#h8I\Cu>+ZGGNM#&_FO99W@ƣ.sڛ6j(kc _]--lǩrUj$[G~!\ψ4wuֹ,#@NVUaҴmtH+<,9k7)m@p7J&TL^a ᵛ$c$շ|jTV-VltM{3C5]nCj؊X @8$t5r,qR)  %I&ʹ%5W#iإ7c4k}UK8ǥ7'AaC >ǗaqY0̄r{ ^XrOz0CduBgL)B[jةwd;7aZEݶ4l : [+I#UQY8#8wQR{V;*S;lbfW'{`2䕻 A7$B=3Tnu[h?}*HuDU:ԄQ?(>ƹk=Mc =|0I?mYmnn洖Uw,Sc89SX>'1hɑG_pv[$i c 0.쾧l2(kl->ZtՖ{+ML.ҭi;**[$ՀW$ޱ2Jva^NNWrQ~c֜@C#ڠ>,4$t-<ل0{zCje YI)&oxHnzf* N$rڽCd==kzy o^Zmè#xzu>LqWrz#'ER7Uܹ#M` iDrN*fEBW1-BYF]EʐaH~uut"aʃַmD؅\Jx5$,`ݻm j[sRYZİ<[- àn`A"-֜qKSw{Qϭ1i6șEVPG$6r\^_qǥ:D8%3ӟJ$nsSrܚ-ҮDK; ojb>ہ ɖB֘]i J3^.`8ȮDѼNrzZ\"$gFldOlcZoϋmċv>^kdQd9@F\D˜p}mYt@TԗruĆh2KL\)ǧR$'5 1X>sָc@-cܢF S*'ќ^7J_ͽ7ĩaz7;y[qq(VD,;=sEݏ̼cuomqm (rIVDrx렍TG_z?/&1֐Ia[TQ3xkTC7Ecޖ;Uԫ[Y|]/kM{]dE9&fm$~Xt?A x곤0 ?"Z<0!۶HjUBi MV9@*D.[ȁf<yu+r8R#\tG( '̹(R?v@P3?8˾?AXrzVhGt35_v`zMzv=i8 p54izTU۰jeiW=[50x2I~TS8ku4GOH^j)FۆqgeǦ*]RYhH>h܎QEps Y w))!ZPEiKy5CTЈGņBVAs߷{8VE޹-H9Gic@|UmVrX\BYjɳSj9]$<)p c+K˶s1JҥlWזFm㨩cԲ~c='Fi#Sj[HHWP:EGk6 wp#[:f$89na\6;qRX:S+!o^څiOlIDvq:T՛,֒d'ީwZ/-_=E>?IU [=X)y ^Җ>ZкTkJ+RO:'IԖScݨOmo~uTzvʫK~R=\JhZ o?Zp¬AJz#h*nip2-8.7.1/share/nip2/data/examples/2_point_mosaic/2pts_mosaic.ws0000644000175000017500000003135313351443023021527 00000000000000 nip2-8.7.1/share/nip2/data/examples/2_point_mosaic/example_im_03.jpg0000644000175000017500000007273513351443023022066 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?m5$ƯUǵLX.3ZBL6 :Sb 4HPfB8Q\}>-leٹsNJx]TԙѰ z$ AmCʬ;Ugl ( FPZU]NisMGw1/óOJRA-f* LG^UBs$ynD){:n9 ZϗX]cG#\QlcR4lƣnIsWQ6OZq&;T[ΨZwŏk'=7p$G>ջd;BXdD=H-s 8u<ft2^yTmS-_ʾ8B? >akZCo 2˲$@.Vq;,=}\t?>Wf/փ,nb{ZXKɭ-fydsU+$vP>f11G\ڊ)f]TyX21Rinx'Ҙ'#/AQHAyFH W ;g"%&ǭLGPPteGY 2j}~X4{fY4I'ʟ[ @TiPe APISTY$ v M\iWa`YI9yEA&w&]*L"DX oA֨]N"T@XqV% ch^zwSvY1%F_j.C46_~GԌ6Wko^+a ԣh']=H9b HXE'o"Դ]IN1iwwweY]oE?)T+˧H?=}*8Siv o%eF!AR:6iL<}}OO=s0soCmDBDZ<U]w5Rҧ*7V*94G( p9Wu#8Tg6}TU{AaА+_ iZ#wPKzqO2h*͵$ SZɒdU'ڵlMy-ُMY#i_֫\M)fp?"_ZH@0z*0USTrlW.!CiJѦ[JI"Cm(ڛ~evJڠ[zטϩy1ۓUK[[+PXZU ]eB _.PÀxN3;V{x~Ikhy^xNGҌёKE4znY>A=*|H9N5 ` + EejvH{LrVKir.wXI TʭmejD嫱"(-ԑUtĞPrQvڿΤi"dœf-2I`F0 c@r3PMcOU$_ 1A\E܋=䎣NU"kyʆ# yy5K$:Dn)"yZWi\"pχ"]YH}c=**(|9G6)tɣyeP91vh%(9* *ov<8PC#Kt"! "ġ*q#8|1w.#RdEySx.اy{ j_/`zcSIũO 5h4#)%YV`Xۯzӎ⻐B=3ڱ_!JcG!Q=G:q1Skr[ګ_钴bX;m)[]nF''r4Sg`n٩2)XS̑;xgڢ=rMH9P謤sڰ?)ն.ϴSީ^;֍Ta|?*9VUEc> ?O߰bȮO:ԳbV'5uNDq4n?Df;P7n .lW?G,%fH#Ù1zk4Iܪ An bz͖q W7=͎g}q*+cp`JׂhDe`XsxcJ8ϵVUiPDq[#cKYr> Iܗy}S gZw+mp7G;U1c0+61hZƕFsԚ˙JLr1xLl8%!qex\P/ak%69dR֬g5OZTPham?[W\ۣ돦krk&v$W]Fɜd}XVSMrMw08xvXbbr{Uf1kK\ُ_ A}^'\;&6e?욊\໊4]YæxϷ5qX"*'БGD$'ךȼ.RL?N4L0N^"!WvUNO8Ve,ht5f}uαHEG1~ G8WM|n#c\=5VUD,k>ᕘ9eDeFrj:(1ɪ&Wo-k.Yb/V$g $ V]pI֥i=yF[h،`EXx(U^Q}hMMDKu!Yd`>ćS4[۰GZ ҷ[!?~en6J%V}(_5]r4m^0=@Ygy\rkީ2\UCIߕrs5Lӷ5Z-V[)-ڥ䌓֞<PO\NQpQck.d-7 ?׏UjkvHLcASޓ->L1# /YY,̒M0 zX7f 07v^HsA t[ #]UG2?g'Asqjˌ1Oq/ٝoJ)TdӰEIKޚ fXFjydξEXPsH^=^ЍԠf]쩭6,ɃpFX@ xe&Y̛%`ϿU Ecu2/,A'+vi,"&rb|WjXBƵ-<"P$'#ex Aףx>1(`1HS3e4ҙpIS$~'ޯ讋9XO7!>Eb-{[6,<+%M:3|~c+3AMg,8Վ!#pːǸpBOj#7~pnUGp7I7\Vn2iZuZk$W rz:ל^ Wc F[5FqZC/f*/0:x>zR8RXw70*x2銒M2< \y [U4#O"%^ ~'<񁀄~S֮Y͵x*}+k>MMb$E ѳ\:bZ"T>MA}8)6 uJ3E|EmÉ7j8)8c^˛e2uZM֓<T'^֬{gꢪsSʩ¨=q`LfYL6qVL#֍dքRj [&Rʼ~zӾԑՏkii]x ~n 8r*ktmW9q {Q $>Z宴r3uFky?;OohTnp3ֶ)d߹Iv=:ֽA,0K֤(GB)@jy@kBMs&0Y.O/*@9vHYKrGli<c#y2K:fKq{I^69ZTjpU8GZ"Hَs\F%Ԣ,I\M W8*G^*ylW֥9"|u8+t4a 3U Q7Wֳ$Y ZpC«sH˴##iY|cWL  aJj)rN5JPpEWŐh~+6"Ͳ#I]* Nk 'o'Mbs2x=m[jB7|qWQkvR-"WE p} \O#l9pzqNMa'譟 s[On@ST' PZ NiXoZЀݶ8hYc-{mmF6sUn48@~*npCJ*Bp\JĦs6Vg5Fy p#Ғ$|8, >/.I=_1$ s8D,z(ɬ&0'ֺ;9|OAQI"n2G7J؍~Fu'jwU?* R긨K Iڹ@6-Lh6bWwҪ.?ՉI<@'TUǗu3 ꧷]CF.0ѧ F;7J0y2Gvr*gq丆#^_­C[YrNɩEE \($ :iD2@Jg j*0mGPD.<bӖ6d.Y&HlqVumCXH*pӇ+|J"xYmwֲ5kH4Q*qKP`VOv۱&ˍAjA=jЧ8|g8V<qk>FtSfhfYu՞9I>ǷX|Ң"rpkCpMJmܩRڱ FT,H 5l]{ڴUIF2d/snY~mz3:z>(g[5R=:RZATEmJ Ξ*:J8I`@hǍtw)E!(^4^ܘ9&ls|Et>9sfNͫ|:SOdky{5Bxw+U p;ͬeW,0܏qU&(~x׽tX(P=ZW0ګAN),T՘l5;-lG$=I=뼳"|4p?گ)j|,tZ|% 1[(IiFWzfcfPMl`UnO\n샓\汩\^[p3QoNh66}>vP ;VLȌ1 )5ek~ <F- ݋$\ҮXm$HvnrTz knn2W*}iǮ g]͝w'mCفw5hqPāԌV]>Xy 桻OkdwgԾ_:$Wii~q55lwlcK"8+Ba_z|Et8j\]B9܁2NqӠ]N䀾'֧vhjxGҙ.nYmyssp'H=W $b'֥N<ԷZu ,یj- KKSM7w@O_^ۛ[ˮeyEYpf %u I3.AZp8&Zmvls5vvvXEw5U2K8'n>Q} #؊u->i#Dꮗw2zK5 LH5kٮ3+sI= ̌v'5!G0V/4V[6T" .^ZID1SF˳=? zͺ+A ϧJ|2(eǖGf}Vmx|Tq;0uhH\eqJh$v;:)l})256趯oIlw;+v$MRmLpTʕmDQc=?Ϡlv)'=rz+p"$8)5彂pҌm=^eܳVl[;,Jzw \A't"d85[V3Oc;2p66T01 J|1U;U:r? $Rpvwc*^3'M>WdyIWdVh捈Uv,0Z6"F>]ǓU.*ets Mf-Hs#V]߇uKHeHw\Đ3U*6̲j , ZZapBGWGaJpkWo0.5+w[QrriwܤLC`2OFd-_JҎ᭬y@ R\qc& HW2*xZ*6nT' USA)5dU enH\Dj# "6$o:T`=sV qN,c~^*5W}jH l|{Wa*$G kh]h$3R88?2}[qH7Qw7 `j4Q\midUǧ^tl0*<+{wK<3/t5#$6.ugugi 9>tNuȀ9.#Nƹ˨ ɻ{5'#'">wK fB09?teX?deǩua]p +3Z%KcQȮnY~x%(mcflb5*c$jBFjȉ;(m*𜘊A=鈤n#+((ί{A5/r1[qSִbCm钏'xsj7wQ0 qQG!@rZ;T'D%rЃYs6J$b>V}ܝҿU@p݅e*vx񚹱#v2Jԃ5zV[ѧxjZs6*^^{wMes=#6=+H8SGAO)f Cjo5t%yy,&a3](BѰwMn,iX{tl%fvU=+GF[Y3߉]DV`I ڣӡ>kCߪl+y,^IRұtl ylyZOJuq+yqĽG/QYXjq}+6ƭ_lN8<]hz?ɭhx:qR27퍎J}OjUvUt$2V7M2m=EHw^eż„G߱I<`#\SP_ANE֌C*UdXqq貴Ff{/zm15[,jjJT>*%[[=[ڽsި]@X7.Y[5F[pNqV$<O=*Xx~zUQI <heh0/0 |8 ku^m"e ZQfA\emXa.;?#xg:0f%ZUk9xxOҶAKsf:_eoOO_Z?+u!i8?,~>iik`ʻ >Ji|/:y?|EY)yHqF:@MZk.e#(%$TRJ\P& s\e?|Ǡ*{[k>a"]DE8αx&oʬ҄jwJsp Tw'x%sY9ڱzWŤv,ԞMLq՝[.OקHwT^sOipֺ[ n[hfU.Gtuw,qӱ~]o24y `r@Zy&ք@rOt)퐄jjјsڳ$iWCSyZJ1NS}).uN:#NׅQ]#98m^D!,5K;vܕgʼZ ݤe@l9V㿾θp"5 >]-Q,r jeùY(9wU}qU#aH5M^Қ7WĊy wI~4c5s:4t3Ipq!{UĕWGbUPx4^D;}F+#222ҩL&y mt2[=>.ۖ X7O_Z)^asYsNUss׵Q$sZNʫ25aR`QG!K/.B -lL$x+1 Xۈ#'>Υ䅯&.0]DVy#}Wݶ֣I\JP$U-f專{theʧ1 80 *N_,JA:Sk4Y1\;^d*s8Qs2rhjhV!p痷$2CciI=(8Oi6 '8@om^WM۲O|cӽsRxsWFH?>8WِKktvZVG(\U n8e5ytD:ڣ*ȏS}렓W,QSWEϩ|Ӫ{yYG?3,l`VhNK ;Dlktk[ 1(TztyB ԟ¸#4$1,@Jol~ NkReRC `׊]&чpޞsv|g?[Wv6vr{Wei)W$~5.ͺ[G><4^&x6ihҼ=g[iً3}V?km!yZ6!HSߥq1F+ uSڽ*SihI #%c>k;dfHϦ=+V{c zW/o`zFxEY]xr $0L#\ɟNTa"0rMcTL?ΰ'mTNkZy-60kkזIdж W2azep*qNHvVgieU`q98d4܈ n?UA(ndc=.Ui#H4(w! \lHF=yd$JpvzH$2 [V6lfF ZQ1S3Sn&:QW,39碏ZNieӡo_T.ь͹q;gc^咪skeޢSUU[O7q9{\Ikj\Ddd9<}3^j50y<_&J+' ?D5P)b,riPNME NeJOLN`(;+KfLbft8?zn2WuXH$/Ln#pVqleW!už''޳'a۟ZV@dBFk;Cg(Uv+3UD." Ⲕ1uQjGHᙦ}*#FFMb+A!C}*8^oģ֬5q>=e1IA0~ZՕgʄwF|lj֗mqoBCjSsȧG+K0+nKtmC(n_=>sw7?)'XJpMs_9KgrZi|WNq֬Yԯ#'s^* %J&RYpTgֹ~W|) Y}:暱$[h' .YBhn]±Jb~TИ`91w$Ÿ«:ʋ$Q%c -r{VeTѮzS`n=ͤxdd@q[޴Tִ)4bR90AA@u'kNh"?Tұevx;֫ʛO?k Uhp$zW-*cvњ1\Rg@I'd#+>*[jkzrp$bIݎ?cՁEz/++)Rqni|'b E!:[kטo118Oa%Jbz* S7qifyןF0穬[ˑ1⢒GLUY#ⳮF&~vE+z+7P Yf)W 9e+&bwdN*9|¤!_ƪ9YZ4zNUҬ50dP@U$+ujC: CG㉈T#(թltRD֦z1H2(aPK֎r$gСI/V35qc<lVb6vOnh\!qM āRk2W=MiCU Tj͐\Ly!Ija.R]\ItOkِ<ҷ5+=IN(d~Qx9n=`Z6TR 5JX@d :w ,J&1ŰqM ' n?SQMiq'ZUQ0R,ŶJU5e#sQׁV-%$(s)1vHq=tLJ)` \WRG,[+B+.J MͭώTaJU IIf b8_֣@A$g"V=YaX)x(Rj8.b]XZ(y<5^\h_Wu Β8LZ&1SESw[p8rZ\,Bvx}ߝ΀XOga5ɅT ;#rzHP}3vsHU VEZIWSt5VIi 1i]G<'#m+*TilKzlV-ə_=E[a(APA2'R,S~78$h#)d$N0AȥžԴRcZZUQ:1e Br5閗Vڌ~d<0hUV^@oQ5_iR I72: G3EX&́j!~aҹ˻B;/c_6^KJoO%}HX( zr]2yA|P54ҞȈ*p03U (~H8ZX a)#s8|Y6jKB $d:L# y=p+!-tґ jM3Uy`VN mܨTeZ%% n; YLwè23v{KYл(W;kK\puee[Z.( )Okv +pHO˶1}A]io +(U}IA1 *$TA(皒)Iq޺M7WP1fz(/ƭ-㘚YU:eK[X8OsYd02@ɪrNzc ?D#(aP00*,H5UX(eNkYT hDGANc0)c`{;iJ{b6_[zׇ_xvYYW-)Aڱt6NNsOFkiG0]x^ۙbq6;+ *J&qw?w޹E|ۗdEGP:Vlb,j06gpېG5J G.H7C*7%* `UgsŒ)J:޻=m.#"0 O_Y!*c1E'zA5@SZQ'<CrVAMf]^D&E%9MY2|QRY#OJlHFYAJ2̀*Gc ?J)GZu5P)8N"OwOUP}+ִ7/gh"FNz1AgV>Z;D_HTp_ՁUvH; jh7YL%=EniYH=:RLq@usK\qO~l֬s"ǖlJeĎ̠f"$4{rc( 5"]jHoLˬ""lq\mTV++sr3}yh_WQE J\IJ p)hZHbR/^lnd`P 6A{Xd1 |?p*)2 E==8M>D~^6sWAi1[v1O<?h+s1$Lds?*H$7dV1Dy5s^bH~5Z[(T zp <>ߛ~C0k_AX2$TI,u4A"6[T>RH]dO kеϷ/JƷ%&;XӲ(Gi&mvc)aYRFcm0A1R1ⰯdV?F틲zֳ1!+> ^пI䯯)b#-Rn]w 8D$oO }&nyqKi{V6mi *g*|s{+|^׏=*0r0z[V 398ҶcwF[ һy)>[u~ߵbc{X-KA^㊆͇E.fUĶ1ǭ;4FjƝixG#7oo9IjܐKWqP<3R}9M:ĈK9Wea9t$ݝV#MNaV+) "}*兩U ڸqG*nU.ԎԆ\ܖq1p}m7NesW|__ H\9E.:69BBEaj)V8 Y0̷@5#&a#tQ*ZhEVfOZuEs:[GOS^kدX<~a^eit.=~>+h(u;1vS(ϠGd7 9xJ}>eyK8'JbX6jDErYHMz~tREPzTmEKo]0EWոƛdB7Zki|P<-њ%zR[N@NZ"rI.;Qk:VVJɨNLlU *9R8ڴJ>%f<:̸[k6!2j5*=I r3lg9x2Iye Ay\Ԑmָz+3*cDy?J+e}RnRqij+ l u2BmZyK:2O8~~eSPNj\mNddJ[ -'ɐ!3g8W0+/=UՏAqQ 9iȾ3I֎Tmğsm=jXgw{O9?q"F[#5gXU=y&5XYX;=kY 60<󎔞^0rjxlq wVj(XʎiL9OLP'kRq՚6KNi0nAWP \FfvwW+Sb|A<İ~s,`}ck]nޮ>G|Mv+$'j/3g*5kk`ṗ5 Ҥ{c":N qWs^WCyg]nb\idֹx0؜8$R R#~iV-'ކʰqO \fi(7n8V"u, 9P2*Hwgv d >VnEZt#|(vsҦ@RB85kp{{՘0~kZ8*V*Mg\n_$pڹo$ұrd62 GQW4<7j XjiqQCu͕Bx$v ] 'Tćh1mcW CҴ/m5 n Up6qϭDzqY[YT.{יjad9 ]UBkHek)5c?p2߂ֆOo?DI_Y_M39)ldWjLk4GF=]b};EhۋN_zњRN=Z5=+lhT?yGcTA*j' S遑+؇r221TѢ-* =ide݂vgQkpI?1VV krXIe=>882:b$T"6*1Ewjr$1POJk;DdZ֯GQ҄Pc9>Sd!ɓA[{S!#*9nZ0yF=N͸`we XnqZ䶳8k$Q,YiYT5+yd]kDQWJ-X`/J(2Ux셾)#20UZllzS2VEgG|G4[K'7qL JUJ+6F?JtM>ovyX٧RE=յkm6P/[Ba)cTVշm#͞ElOzÏK'pNϺGzbpU$*{U&|TZ0pGid[/<$l 9MhYF#b99$ 0ʜ^a$e}TŏG8{f5].cqpޘ&(Cǥ)XECkk;陏j"=aZIpؒjrޙcRi< gace%ǖ袢td$8>Ԁ,vc1' wOh/ Sӟk*rzKBCc@tv{pMWMAmfh-nfF)#Ƹ9#19bz͢߂ͳކ'I__ŗ%6ҟEG3qA>QE! Q,2݁}yVneCJ'JȶT1هrj+1cX!3ҫT`$( }k.R@Jkl(> g[u@=@PL0cSH25=-±+*pgS?J’NVWvz֕d0}iacqVe .Ei49 XqGq֝ݸүʞa\Hڤrvp{d׽gr{#N}$qO8+I)G=0+='|>.rXM'r+W;hWyv@T-ǘPm2rÊοy`p!T'Xע[dlc+CÂsQmyW1Ew?[4(Ww-uдY<9TSŷޫk*LNT=*^{ sb0ņ%z3i&Já-M%{b.A߁'(`sޘ:bL01 R̈<ռ3@ZYy\.l g>Yj85MɜԫOi_u)=VcXgpb>G?iČ;U{S0+Zed/KB#(cLj&ұ8L[FCϹR/Yz3tۙtiq2Hg6~t$ P?. X*:F0 FG8dx+/&DAׁV+޳5U'^3k%q? |'i+&2??DAE'\8_@)AȢ`L|c4(]Z޼YZ,VWM\3Ŗєʒ\4r2RlM#on"dEG|qWE-kIeT<(JϓVS袳o<`xLFSv`Ҟ{PTUpٛ$V ?9;RlX*f2[/ۀY.fJe?ư~ocWZV*{fA8l`fēLv6ԒܬqtyY' LsҩQksSNa} t7.خWappU: XNݣ8yr+m)W"pyz+> ^пI䯯##f_4()2wZdapўA>5E*/^J˺̽p?!WV2{V}Em't5J!cҔJꌞa z}Ǧ*Fn8M!():C"i999^_TwsJ%`㊄1<*O*r0?ZɓwSw'yK%F9Sңݐ) Rو>q>Vڴ)EG ϸ^ ė"Fs9QsU `~N=+=e@A\h_W pA㸡(9KEC\TM:1 h FA9ΤU]CQ{8xrkS2˸'62?*nDru듎)][ds=rJȟĪ8J`>sYw(PI\d5 N?QP51,|5Z膐I_Hԣ?ZCqL*8W-.@Au2I4ĈYLou>.f7##0I=AۃRA鷌vm8 q֜ %I9V(+n'ҝP)y^ާ5P+:)UK0Ut*xBO|t4˘`  FpѸ=s\l=Xj~T,#4?q\\1f*+> ^пI䯯袚ā3Ly9#Ғ5wbH5'9ښl~+;RpxڼWέaXq֩t$S6JdSyMnE3yJQ&*1ԝ9OZfKQޯt M7um3~i՛9 w'ڸm"-øՅ_* t&,MF|pAujʶ*|T;x8S٫f 9晼۷\f'r'ڴtۿli]AXm蕝s1JOa\gtˈ2ۃ,#\m\ DhYēi9T(LP8Zjh=sR'"V'd"f*{ $J#$ޘ%h893V^H(dF  ׏2L_C26ϧX?k 5nip2-8.7.1/share/nip2/data/examples/2_point_mosaic/example_im_02.jpg0000644000175000017500000005420113351443023022051 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?(((((((((((((((((((((((((((((((((((((((((((+~k x1}$L?^Lof~[eikˁ)wk/PUi|cB?Ɣ|2?G ?ixQDR>+=?o&?ITM}d''Z|D~a^?OTcxC]^uZ`ńRks!4ájag L:>{MX)L^W#0]/޶}c4'U4¤u}i((((((uԿ]ӎǵ(Ru8M&$sN'jLKAK *JB9hajXj1S hhջsUͻS($r0ic)b )xo~ )Cp qҴڟ+[2/S閹B|76[o.*3m>/i-= Zg! >?Ot&<[8JQhs?oi֨πKv?k_h<\]K¼#"}vF-sMyᨿ~t `C|:qSSҴɯZ$XNHQEz(?w<`z'r/8b9^8яSګP*0:QP3~~'bT)^[ ֣[;MHSR4qHqi6p}i BiD0F}E1#Lxo$`SfKE5(_zwH2)p94zSqKM)xsBaN3O`P1SH .)h AQct|dvR`ּ+> _Jcft?.?Jtɺ"1mNGҤ,v)lT:+23 YDW ry5,DSgp`)g*я³X҆PA)?cv}+ImbD aZ-g(qOeQJ<ʞ%I ۚBW գlV#wz1V!K%^1PcSJ8OR)8J9j? \i_4c4p( Pۇ07wv5xOnWՓBQ^aGK1.ڕ@2OSZ<j|jvd\JU۵ktUVsj^ik9w}MIs僶8Tz ]<im|ܧWZh{sMz2E8j1֬EM\C {-|c{Vt" :iN1Dp5l qڢP0T[jݽs}:{ZVFhO^jC?ȻW!ۜupvR.r&总ҌS-1/Qr3?#p:ҕ'OjjG%j fiw4ۗ1QڦI6֕f  )H%r{r'>.IRRF9i"!{UG42 #W+-:{n2q֩$t'mU,wcEդ>TښFG4Ip>h-$sM}`.~FylS6ڔco?yW3 |?s ]|Vwm9 j70b)#f,ǹC*yyCnv,IyZܰbkrK prq֛qRF Hi#$YF ֫l1qCM$JZB3JO0iуzNE3d)jhxPhUY ckk%aSMn@A,q k#Qubp[ّ!IaFrPhajce8P[1D)S1MU P1N&(4I4ԜqX',`*.+{B)mԟP)/!ڸޞ,0ԤvFޝN@O @R1U 9 î)~A0Vχ˾b>Gute0Ș<ΈjWRԊO`=GըX("9Ђy`YiIYV7J&fpcW;yb  y@Vt9"<.0J< f 2!|)ϧ`wlܾT!>u*ܸ9'GqRW Z,-b]zUpA<N7/0]aUa6y)F#!}֪8Mqk 1c֢`6EEqZK #~?kYE aR6p𬛻:21)UK -H,V^98bv9@[:^"Xۧ!3N*FɫI_S[:|&4-R~eɬi[xUU!W'TGqЏsYYWa8>ƴ84J]$`U(wX2.dhe5*C[ʤ>J)V#<4X2SH 4 sҝ\_CfԟҼ+<a5ǁ#CFb+) ӑZvZٛPݱ\ܶR]]aCu&bӖ**:Z,rHu[$?S_ Lɴ \|>kpnmm ֳ|_ۛi {2NM>ݮնasVZ$bO1;V.?*̨&@_@(4.[5s`;qSIg /B? Yd8#]Q2qt5$ Q8Utݴ]9XlQ&\ɐKhyD G.9DUoΥx~V:'^{UBo\o:+^ xmcW)ˬ4AV)1}{OyFv ՊP FױBˁjon˸AKN3\ޱ~@3 wyHӏLqNN|E? (|?z .Zbڝb[Ue'T~Ґ;vC<,Ҟ UnlnI,^w1VoDzZX-Aq5vX:le.TR*$ Y!b ++>]'T.?u5.T#  wxe\l@WoLeK ~s;k+rk>mq9Yx,wYfWR6֭N5(p#)(0NyosޑC1Q#&?R4/nsRq֢ TMEAҤ;LdsS 3NmCߥ@M糱z v~$X'cZ4ExNe1@Œt41=? pQ^'𥍣?pC`?&Ęx8uH"Z_ZpiRF\+V qTQ^ӡߵpr5ϐ|װԁL;dv5=dTW()bQPjD܄d 9#GxL6sLN!?yl!cՎM,哼zTʔ) +7f梸' Y۰ (U?֕F:9מ|@}څ:袽G|hh~*v OSKqN'{өhCG#&*7mr%xD#/ZUrh4Ӆ-1752YU2ܭ^[0Bzƚ2KK v Ijw׏85eٮwÊ["w^1NLG5FD]Oj/A\4kw޸I{5Fl8EfɧnpiHpՃ;qZ]G#?Z(8`MPxŇ~iiy?Tvf5E{>?C׬_ʊybPN(4ŋT搾:)'ڜFii$ĄRq>șK`sٲ]w un&7N}f!%uT =Z4&Kfҳ.b;Z2i]J~H}z:U:ToCg9>jci ]&c`c(T-Qf;+z-{[ uVO]PJ9CU'mÕRsPцW>:7q(T8W4[$̶3)lwYW^5fxH$SnF3\<(ё֝Qu4f=T@GZֺ{$8?JRG:c`846*;eF-Ҽg'h= _k(-+8ٙ EYjPS3ڢ&STBz:2'F^O4ph4.H6vQUh +R[bFk=%R3  ҭ ; 2kUr,N3U`ˍxOzH>Dz@kK(]YB䲜`x dVDpO\Q$`C) ;5Co]+ud}89<֦43%>nmo x&APYHlRt^G<)cnU%%.J5*L`I,IjBAAJL2z*8,4~ (Bֹ(vI4M99`Jvm$k.@;SJi[qA|׊ꭴEf\Q[:M %V+D/zRqJѷnƖYP)z($s6dӡ99xwFRC S;ͼ죺T ]{E6[ƑT$jfUM;1zթFJd8 V#8PzɼY%dϣ\76Hǚ$1/4G⛜)>M4CJSҚiCp)٩#Զ~{ԎPZ,\nfo+T?rQ^V݉dPzYc> n] j*C4o)aq P&Uu OF$PXzޖPacU a$j ;Ty"⶝$U\?w޻""l.0@\QMbU)#aWTFnAFqPd'0?s:ݥ-7[-m?Z )$ AJ4g*qV-$y.%ݰzU{hВH'ꜯޖV;Vm8ɓi7#A v[=I۫njJCq֘⤦`~Z-I'5"L=i1RĪOL֌R dr\Cƒw1 娢vB0X`)PisI,韽NR qO2{ԉ:cKZbnj2yn. aJ39| WGw-՝z 3EZPpx⺫K8FG#ںG`mҭh!o<4r)̊NHc⡜Hb>_)ѮۜZuu܄z,[sR4"`Y_4;4f ngzV~p.;cR^OLc)8B08qjdl=*Ŵ9mwǍwXk\W)2;TLpnj9rJtx+ Ҽ#nvr{wR̷Ur*$| r{5o:¹NCA"Adr+V(^5?XWM\/ҟғZ ɼp'֘Sz5 VىJh9Ҫ.ʁ)ZW2{Vɨ ' d1ApTVs0A~̟׮V@=\bOP_W$Dnsz'^J8iaA`YԂbP6.sN^Aq$j`Z稫:$݄r*5j %zRQK).8#}f~ѴSze 'ڵb@ /|WX" lP2+Ifd>ed jSf]F)K6⣒;X~Zdˮ;UiUP*xۜҠVbay"bFO.=*d+X]*EFkr$$p z )"`93@4ojPBF>Q}28 RS6sx|K]1 Ȣhӿ/Wii $\gp:҆ Ȩ$ԠbA*+`{h䳷U0`2NGSkVr#FEW!G:bu#XdVX _|Ԑǘ\D.cV",Rs;53{H# κʱS+գ[y$dǸp1sTXݧ`?J!Tg@] @K>\W R{ޫ\FPEqF0ZjFsɧ:RO4-2C'= (?6;YRǁ^?dMsv*!?cЅ{?aHI?cN@y&q(QK:PHw69݌G?Ost+pG~Z0:sGT..=ͻn@=8Y:E&9ef̈O "b`H I$j\w:n{ÙvzR,`2[.>TJ$bNrMt6#suI>o9ew+J! Դx`@OV8kͣr U^ih/zCOTOFƚPwRCr*ͼ^{pab7w6ITt#n>O]D_QBi#34cwZiԘnqH#x]g-V[F?%qk}:4Io~lo)Q7sOa{ST-6MKHN*T۔ZVP$#, 5b\v>MsC[WD@3'޲X+ryxI!z.6Jзc,zӶ4 ;UY&>ӟo<޹]B!@c)EiBqLc֝bqj%rѩm9N?*X4wi*ƨU ֚VFləzݯj'O +GAGpEf"6Œ biu4+4OQFB`cx:QR3sM`)Tpzӳaw%7Q7 u!Hպ$c{W࣌df$q0j8R8UdO)Cc#T:`.5^5>Z{ 혟ǽ+Ma^}?|̷b~`}R3Kiw]Wfc+6]FO-X'V [89'mF"J찳V-ؒ"k 'døsTzfuma"w#9#U@8˥HܳեӐ(#E{n/?{k? ԃ%үX$n:qYGLX=zVmCEn4gvC jEMQ'V9;Y"{T; P9p7@Ab|=ڱf"dq#O?5NÃS[YZ0<53ToC[-p=a$%H5Y:`vIs %'Q0c j[Ft?Ƴq1~E^ |wj'V?WI 3\ڽ].d9B$_n Qth :hܨ2C$RD$b"SA$nN #Szֆ-ҌzV&k&$C{Ti5r` TbUaAqeȩ-p'oj--/jLuLeEƑ2˺n,pknёTdXv3KE1g:֤A'OY̬A@_t3DdϠm|}Ȭ{J, '?l3֡W5,Vq95=!d_V_eʅAT'&iA˜~aZ S?;|oڽ+ؚ&d~Y:zS5Eg5#Y2Adwn ' AϽQ(T5X r@>4lYi$6atl9 4Fw2Iۢjv/+A۰s|p[s4Yt79榹Ӡ2Tןٮ%xpWxj#M#-}-A FwF1*>1Weolc] "i8ְ5Yf@²n)H-\ӦK GA5]CΣ1v r*36X'w@m*Qi2IZ\^s$h1?E{R.ߩiz]CIs)ub2Enڸ\՝I2}ДN Pis朩UAd.)}*xd?ۢNjkjT֮Yq1gzMzuv#1j wiK(ۭv#fE-NOwT[n]|,c'+i9Ӥhn6/L碼ye%sRDc! 5~3:T)F|nwW9ҚN5'QLrBuv8_;hse~x_nLs#H+ku(V0սֻ2ֱ%`A]H1uVyGՇ>P[³foUf`1L R}KRu1kh*$3FL*O6Z5Fӓ=3D˹PS=*#wX; V'i)AOZwmS%+lY]$R;ZVi;޴ceyu("{HEMkw-M u9I?{gC&2 u$B-x%&*w >T}i#6B:Q֓h"銲FYp0ֽ+Fm7IRp3VWvtlfRK l'=+d9 s*}k[Fb1]a0tkЊ#4:bioJֱ@v}k^'2)Pj\M'Җ]s#4|٩$RR1N) n ؐ#ҲIȥis3N'jLJާt5IZLJN?^5ExFw G\8&VĬ{qZET\ҳPIJ˖2ĶH[DfQ Eֺ:}\ԒY ,H0Z)x@Ed椉:sZ(`?hۓF{U~ZN:Tʡifny$bRkgMwGo&O Xc"ڼK)8g"7a84FLJo1a^?E᮷>'O0F2R#(1\uV.z"lYD0JÊnofֶ$c vICd5#VaAQm7 .u9G*"M&JF{QHqހtW;S ܏VA (’=Ou }@תi8$:⤸@#b}+B@+Ԧy*y UԀqO\犿sJ`0[OpI-S42]m^j>@˻DzsSʸ\>&􃵛joQWMsTҙ\zQ SG%7k ?DyuWMË ?B Gd[{^FuϥZUXSjp;ZE ,PsZO[uf}zgy.$c|SU}UsYraQ:с@4R 8Ɋ,L+5fFeBp{1qN rR)2gҫ ٦L()Y~Zbҳ G$GJx 1㿗ÇdμƊ+ıukM ixрB?Y:3ȳG{dFy?*64˥;Vd0pjRNIAT)'14ӹFAWj1zU%9=M=+9 &Vi*[{Q$wN޷&p^OGҒ7&%m+J<,H2p+D[-qS}v`b撙#BNhY]8ϥ5,~cB89(Io_W)G RcB9J8Kxf-KL[&tb k E%DSKgOug5waؾ:V=߅YIqLJXZy8%&s`5]ى,$Mfo<<WEuZ gAZնAfl2+’GpEUiQOQU$F#|17#j)/-S QXw S$Hwjt1Ué`֣J~U\#;[M9incy"<ք3tZ\[Eas[mn=6{d<HۭUh8^JSGF+ΥQQTR$J2O"sڔޚr*$qS8r0cҹB+yWYߠ܏lO:*gliݼ} i\nLI"aFiRPm;[vjñ Uqj\c7*j4'"qAt!hO)߇48[(s^:Q: TQSb(`XOz Ju zso.l*[hQSv P*8|B?'{즼+n4bW3ȧُhCqѠXϷ#Fk: PNP0="VMZBO5zGoΧr9ەbkEh#$*YE Ƥ䁞+4ɸ4PA3KMcA8px<V#=irCcRQSPsHP+ЬM,BIwº$u8Wt 0W=EY ׷JjCdԌIW5UcvAuShZB3M B^A +ptkFդ z[K7*-XJ 2;1iIbmǮAo'X^*2ErHC݋|B}j撛r=kW(u^A[!ż{ sޮ0jesdMad aד5ӥHdrؤ|ZiIсKHW4 :`fj0)ځox8IY7LJy?C]EzuxqJ .)~0ϵ=H*VF}(+'y崖2C >]*1׽@䁊X=j\CMp~=Rԙ?Z⨢Ѡd8ݓƬJAE^VZ]0I=k)iҫORkcMvA S8EEA$h쬞fP ;as#rrsW,1]%VXTع$hz58SU\2}kRё:5X& >+SxjFd'5.p)\(i8 byn)UAF Rb<0Ж.2;Pu>ԖzZĂ#Ɵ9qW l1y5E ) `pz-Wjc$v$1N*'UUsQ%`GR=[=+y&` HFx( Iޣ|т5B$xiHSݪ6r >׌+mhsAi[>vڽ8pu=> UңyN*hE3΅xZfk2#8+RERkyFF@4`KE&21K\S`=+]&5m6OVHq#hUQqNhϛ,\VL` QN m&?qQ]Ɲpba1 G#4.3UJB8 b6{TFd)K$ҴExP^2E5P:@x ߽:5iag;zҬ@oxA7˅"?"?]S@9/=}MILd290t5#NK4k C+FSNAcdIOUW硧&Bi“.ygVƸ(HPF F]63Xe!x9lBNeUJȝ6+B3\i7. ;8$5i?ji/.3G5X-|0Yd;UUqt`7+j+3lX}{}F8nMJPM?  pr:c$597CrQquj|W߱p;~5Ͷx#:C)KLWjvk~ 6Eljh[GH69LZH|'v6=>6ک>x(ѿ?U#[W,-w NVޣuܹTIjiu+kUH*TN - 4Rb$=)u#4Z }~,db h7kjY@|w0`R5$mM}C"#*ۡUⴎ%#qn)c40N sZc\w5=r5Al.(ژ9(ϊ= X4QEQEQEQEQEQE/hs̱& *N gHR/A;/^aȒFv0 @+"+nip2-8.7.1/share/nip2/data/examples/2_point_mosaic/example_im_04.jpg0000644000175000017500000007014313351443023022056 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342  }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?!fܻ|\7'bY2zԡ9IkJUX48fmqrO&,2QPqոth7HݱSO8d WeMmIXrb ݟJT6Іu@<ӽ67(3bl઒kg$z׵X7J+Aph$dA6VtD=OzKA2@wo=d'iX=ߑh"lgj̒40g;>m< )('O3;3:IoA5,K#uR\1yҴްP\Hyjq8\4`Zpl>Ab-b>fL8VOrwCkT͍JkT$ 9I#ؠdgc*hp>hWkۧ++9GN-fJL֩[ŽaZAp-#ϥ6iqT3#!8(O.EXyI=j6lp5 aVvw1cޥHLFdn U7/$H=O b=;,"AZ6֤hYʽpG -)7!TR2M|c'LX֢#nCtrI$Qx5=!836~@?Zx Ң}sqK ",$SEcsWH?-R+Sӎ{ROݜP#&NpW`rkOlּ(iFUXO"5%b/#=( `O=;˞՝ n7 Ol7ҥIzXTvFjDѿ̼T݌O0nϻnZk?qg 隷ǁZ1UM\բs}#bzUdD]8'Ҫ0]5P>@ɨ$*7ȩN:͂GZRVDžn|Covz ezUvy!䎵fІ`T1ڬ "ұW(0$%rTpjN9G:nJҡdKF$!)U rZGs~f:*>ev֬V/yz{F⫲H+J8$n٧ǵWvĞ:,jTNOhJzֳĩ ^Gү$ p|U\c!B6=E7P2c[-@z$ξNg$bHHIސ4d;wvi4Zi@$&=?­/=#9b>d+{uz5z;}>㊯";6CqD0$R|1F1\W(:oQLd(T~)b2A_ʧåחQE猱ibvcnk~N7Uu|X,zA:NV@H$q&iDWޮiډ f9<剪g\wS`4AKҖژɥ RREP-!#5%+%H+8󭟱ɟ# Ֆ{Vma1ƧqlvI@7ڃDJXZ Xv# YPj@~"aK7^k#`'qkRdg擵(&+1]וQEꏖp Ydң{Rͧ0 do%+DhrkcO}؞+Z0rA\G]^Q2IQb\228}IT "A]^, kYJpdcߥ/J3CGjJ;њ2:}"1qU@u5m01H@zQ,f6Xv ֣^,XijWT(}]kzGeTSZ^ln-RBDw)( =]zڄw鲛G6ܩkr=NV#85ɀ fTtlLp2ө[kXBe.:;;t1/5? j n`VyћLEW*Y8ZWx=jJ)HR(!rzm.T"S$K=ڜ g4QPݨ)Z<԰V?JQ}B=*~m]6 :Be<tLx\OfGGu,xFIW#L"kGljH}+ehM҅zhreێ*S\Z(hqv«+>0sOղ-dt+zƫ偁Ү>kdrk&4ĘaZQD.|S̥jw#`-Ngr S97zӋI=PzcDjjk SȤ\C(=@5j(QFi3S\ع$չ1[}9[K9r]ݜEzFt\sH⯻8a(TDub[X5X(qJH|UȘAy R1ܨ YbT|s~-!KBH8vS ln5;ur>kʨO1 lP%8<܊@yi28aN+R  W 嬵dSd4ҡ<1@;iuhiiwRRiݸ 6W##5ᒱ $-t:' 5,;zҢia+<inK;? <1v5,N94B[w$8jX">L23jTfIJ(Q-\t5R9-p$= 5g W̚mL/oYE/$u‡nI56)H?Z( 1:QvRsLu޴-&}ĮCWm6 #\c24FM5 g-Ҟ4m4RbeQM*QR\ ttQE{ 3coҖ(N5#A ET}&lidU|Ѽӻ\\cY?5z/y)B s߄0_bjSɤ\$*J))_ȩGJ3KFh)qMaɎ`2j̠*9ªUxTGz#彩ˀ=zaai\yDd'uM˅ɮ{Sq.g,0FxiN}=*9Ҍm掦8▹_?,tTQE}sYEG*^7q; ͸ )@GRGv,ްod N9 ay :J [fR8OjB9R9u dr}њM y$[8WQehdO6Vy@v ǻ䷔ʜS-% uMϰ,v-Xpf= ۶ L߰k`bG9⢺[vf V!W1H+O䶓G8,Q_ֺk)a\~5D~qDz鯘 .ujX*{GU,@8Jn[sOmcڠ,#:p:Vj42v@x43IXZhrpx +pF[ HH^2N`g,A}ULԫ(2:&r=ōF$*0WpϥEw2UKV,e}!cZ˵ Z) h6p+k袊}F n+H0YTEc#֥GR=GJTkU'+wH2:{7hsN<)-8콅k^:VhD2㋃3x2O6_=@84cj\ RLca֐M+sO(<1 ^%8TeM5[J#bZB7msxxxsƱfb]٘$_'H搮zl ӺSFc>f <~?,+Pp+ [un+$PґpF}*[xN+j8`1F2[8qV~斕vj{gH;iA*]Mc& : r)̬1MB$qɫQ A3L^=j-=$8?MRFJVYekGL{\idg hR@ЖQ#VLGj5Z6rIo0b`%ُ8U5m':CE!36'.[#O9O 'ø&O^[EW~H=/X W)O6Iּ(Ϋs i& ˥+5)@*r3*E8wN4)KAj+ qFEoEr2dmr$psZB.  oC@̀.120*ʛ gެ&~^ĺ'?x LJɸs QS^+-,ݮK rZh*;\bViGȧ+gQIǒ{_c*EXq*+2K HVc+hK /QW>f''qN uE$*zԊ0) bO^Ԡf y8g{k ~?yeQ_F&0{XB+5oʡHtK"$.GZ@N)c-zUgWޣ *jH`#+JQhIu{mQL$.Ǫ稫ڴNB UdDZ3=ª\C;۟pC&F_H~fRUo >Q@&$; " n"N{zե2Xp:{SZg ,[SRs%@ֱѮ̳j>S*JTg\&fڰʶ4 `gTv E-QQ!4H!ɨ%V@& xcּ(ٹ=5򤂽Ѱ)#ҡFn땡G˃֕Wm)84,@HM<N("S0iR$}oBIP޵oksp39= c\R3\=_D\|Ϳ>r+9v[F rc}jTaR Q]ќY2ݹb9&iYB銺 %=ja)y-8jkQGJBޱڌ?6)h=)S:TdH:˒ .@\W/Enּ( 4J̼mSIRFFj"_:L\QLfU8<Dd0='RhKiE_ԥDL}>0յjsT聾ЀV^,mF@ḛJsJmF[Xj?Z!5SIi#ڵ%6Z||in%f"&SRqV.Mc\OpQOoռ98S6X=A#SA"?J̾+6>fE.TzW1Dvyj: )h4Ҟс41KIZLq\ 8זQE/t2uk+~]"+ #©)hymv))T-˒(1ƃ!F}ij6R)QIޥymak|]Ղ|A>J[Zȯ z *ͻ,̿tM_Wa|KcعɰڦMgoklF9+SIӡҬAH4OU;51#y<s´u-Wwa#5)Sp'ڬ}Xzƽg# %cv|EmQ$r('JV# q+$:o8ŽME8ײsird؞bP2\;R4w.sC(aZ@5%%-7u.s\OwO^UEW{"*j0ZVL6ŽQAl9)M9 [@1Q)$+WRd*G#dm<R% X+Ƣ'QȤq6=)ROӊyqʝ 2ʓ4bIT\d.Qp(c&&fqi:qW-5) =N+82H7L)h4Ҥ8O&SN*jE@CNSv ۏԃFQW)9lּ(`~停Z#/x:LPPy_έ6VHUL=*S/^qQ#g8C#v9sӌ`KHzR(&I0Ȥ PypJP'44psOe8qHjWRiKg#ިGiٛjյ 1 d2o&5)inƭۮ(fG4Bx<IڐS4A#c8 Z)bi❚$`f>y!l @I|+3T\(u N*C7AIB/:iY辵궚[i8{E+`r*LUEPp1WqFxM]tE0݁CJ+t4O pZ(;hp;Z&|㎊B)^XJH\QV-%o BX d`5k&WwkFUMc(ߵFnv=aܙ8y}++Nnv1!EWדupDxUSLܳ3R˓dn,|4= |s\W)I8j oYF TiURzzsXL:z[ٶ “ަ:z`)Hn^hI";:zVl5JeT#sJXY~ݬC`g(2pF$#8*pR"95 eI g֣ CMrW,rj'z{-KY /s*5j-55-!h y1! Ϗoxmu$q ̀iKo&Z:?mhY'S;fZm\M U_Z󌐍* `'Ufl$鴑Z] ZFִ+v5 1̬N{jk)Ҳ9נqb|(ZxX#O?ד}<#cZvF`ԫ7PIMSk/fˇ=GaUexpjkY<ȮA߶IR9[W_}*rRݶL]9|dn0\UP[[ ~X0?Z䓑 q &͓Zw Q^y#d=$H 8'Z 7]?tu%55m`8jygy\WۍoͲf*`~`AXB0U}V++flsZZdko*H=jEW0oz<ѲAƑd@jpmA$ fȤ9G9*{RdX޸oTC5^Xڙ$x#1[w%L. ?Zy᫭!`.$T|wlVΖ2$jNJy*.2zG8STvzzv:4ڏ\6u/CӡN+"X'!A*Z H,G_27@fRf!#a^*X+E"\\{AP6=io`sߚ4jpyX1dգ>4ab(r T'gq=BՈdۗA]^BX?#M#1'ɀ$jnJ=*{մ؞ّIa!{}nh7eШRm^;i $GEvVC,=H@jŅ6VUzN.O/xxs|QELkHҭE6ӂqVMR[՘NZliUmΒ=Ѷ*9_T7ZΑUg&Y^Ĉ hH2^%g$eæ!?xglz*EpnH}k1lSmI% qV&jz~#)2sO59 Y/,`0ʪHI-w8$?OҶgc[xaUN8Ul$aw1="u5Ak-/ $ Z H#0Du cl2okDZ | .OȄFިq\^g{{A?u->m=BtsLFYW@ӒX~Gs\MgrN]91J~SA#C*̇,#ֺ{cK*t= i¾\GLWA ?5 @zF*]jb;F2md [ pJ5w(8mWx32|sW'P'5 :CS;^k6mh*^"Lμ(ʷVnAZLu#\[FĘ^XyY0!UK~U)vpEV٢pi@ZpAR_Q]ʂ8-lReu݁f[EĖW>].ݕL>ë[vY|>&vd!ѩGWyz{{gb5X>FAф4f1LhTn= $`:U PU5xǧC+?A^ws޴)D l@=wf iqw\H ?J1mv$pkeǛk+hcW'WO '95"&½jGsޝp84kDPF&O܋w!\{9K*i67 , qz1 p1sY}0 <5sqWesm}cK>31$rkNT*sާ}W׭k]^G@֒Z+d`9Kĩ%4@W?qhp08ϭM )2lla8m'ڭ5`zFG\~r g0]oo`[ۀOzBHFϞ5z Kj$F=(c;YpUqڸ+H2(08Om2Fֶf8Q#*2UAZd}!FUR/QҸ?@c/2(dA|\0U5z-OB.浡+*Odܼq>>ވvgT$doB`޵~-uW>Qar܀ 汑gL:]"8FqQ^D^2kÃҫ ےktCue1Hy]GK8g!z5SӮ;p=Ev[\YS>Z(@ *5+U2"cZ (G&!=2c :UHQܾSS^]-]ՙGAW+q5 <׹}|w@v lxk[q5evX{Fp#nA\,}-t~9W}mvP7Ѿ3ںon^ iM`֖]2j;dc꫖{ Ⱦ֢9#bFG&܀+5b6\ *@ +MCZ3-]+ate?)yQ_FD+5.1j#P)NI'Ҵ'{AOV0YUrq\vnNy'*, K"Y U+Ocu?μŐp|Ʒ4 2|cd}2 W!.ԎMr*n^cH(Q6y 6OWm<i/GꮃK,dŭcw$Ҕe*T=Er evXsIw\CHִHM2F;K(}@ZWHOyggǑlta{sw䏧ZZZ"",ϸS'T t~EorH;P{W)xVɛd8[t9X>5^9N=QC-q1b6ٯ6 *z֝ht[{}苺9$cҨiqFyJ=HYs`7yUцp)]^4LGҋL;Bf5<[K3+vS3}T9p]=ޗ-FYTj@]~1ڥZeDžrV. =knBd{ * ĽkVNO+hDUI-u)-5^Dr.+[n"/=׸'!Eis/=Oa} (\@j ,<"oZg.ZETjvв4ϻ24P |*-$yG5x9RKYg| auQsB_Xj= 줎eـ >bi*OP=hvxpϽE^#26?o(e6@{TIՎ<Ԏ3Tc]ˆ9 2iֺcoo#+ʆ"~gwCsg {s@pI9+"ݙ"LddgSщ.vp8U (ac@mD$+%WaJIm `zjL[s+.NQAzR*XU_#$Xp&yȈ3\[X{uvX7AFRiM gcjS mB=+:ͰGӚ TL=#fQC*<3hIL9 C֭ rCJaOjz_웙I x*+F4K@rAKg$M 4cڳ^OSZV^KPa'gKsJ=7+.aJ^⑴K&(P|V|&viۻyhz.JZ,doO7Sn Įr3L"c asT/m;W)/uHntDCTc.4NՅE śn#x- S̉4$G#oSWaDr}+(ϕ@Z:(s\`z&K>̿ʶF#h#=([7A8W<۟jе{+;M>UvhT,FR5--%A hS^@0\gb:V=0 rV<=-Lv!~sldqX\8[i٠$uD2If j]NG?Үjezr+;&+FI85--*;;Vy6`!Aۖ'?_\Q_@$i⯈$ Z1^F2+R{Qb]\{ըӲw VUb\|эjE25lvlrz5t0Nj"W\7 TwKL )d?Jxnv5@nI+ ^fL3Z(Hjڻ] jq('MwiUjiW=6nQN})d݀{ոm_^2G02+x뚃PXȤq\i3#.9pW) ;tϵlcr~5)! 2<.WA dz{] JUa)};mG1dF8[VvF^3Z-D.j\|:j Vk~ǨF-K(pۘ:TCB.:3yyRîOm@+N9cxFV'$a\)Ԫ7 i[P`P#ڡnW'ZdW>_mf1X=s޷爑$`UN䏌RF߭gjp͌d.j(@QV`܂x[f&# 9kwqT ^4*猚ȒC+sLVKmx>ȀmWc=j֢ܶ?yXZ|AUD1ߵX>Kd}Ѝ,!jcw?1a²wZ)e2=xIwƱ;>VӬZRH`}߯zkޟ9ɘzWwa,Cp=m+Oy(P)Z'`=YKfFA+2ї,x|\ ; rsV0~mq@F?̦ǸFy#+K%HC3O3Dv z2a^' q¦ M.qZSN5^~u,2O򪁓ԚidmN?S[eRqhFf->kV%+IR#m; vEg)Ze8&XHZo$d-:{ÌL2i{DԾr'%I< }̋c]*ʸ`^k=hC;PpWU.XT-ߝQk`1ǵi*M W%5Ƌ}9n$` ߚ V {VI~i\UŅA`u5CaUq֖;>OPDF6/ W-"cV֛;N Gku6޽h]7cc[7q5qparN*<y-YeL9+au(n;HꦭmXr42\xuy-RH\$bV\T|G3@{e.ۦk缘U;Ն#@Ms;yMR[Yp \xgޫ}dguWN;ʺ=KŖŖ;%,G!"o>;?TZ3)|-5e29mC*c{pSy ezzaz֪MM4gu 7CXWn&UucOFg6E Kqqu+O<񍨋Dޣʹk+ߨ=)6ԊO ?:ڶo9psVLO^2.WGYljDQu6%XN7 V.( ^Yrzⴭd >aWM}2 $LW!֯[.j&>!m]qv/5].IQ wRI'j"[)w]z*q63Nu{8mg!\xiB{VۯnO|f)#9q(XrO5oi]ֱ2fg,AodaE^N9+V; MUup+J`?;bЭTs9ZgT'+Iӑ]3vzG`O?Z($H IZrc<ՔO)'gќ t2y*U>ܱE!e;pz59X[ 5ݽŽi#܃{:ZLLwզSզ)r{b˦G m%zwgiB>a1[fn/$u3T]Rnc>Z^uټc$C)z*Bpǭ=g'ֶu[=x.#S$)@`tVO9* 5Mx-VB]p[F(sfQ œQ)7 ج+s:kԼJֱ>S령k>FjkzVڪ'ںomnTJ1'ήی=rFG\.uLsة4F)(~G:R:q7o)??K\c, '$ 6WkH궖cGUSS>)M-:v9bđ:=p$7k[,EBW!@J\ޮE#vb1ꆬb79@X4q' }D20ŎyĢ)¬vb+ 8~tf0oTJ,/*͹.[G֨EH+j kԋ}qe'm3 nӮm߻a k:M6{8BsQ7>JԮN@hIg1CQt5ږ$ZȅW#*4Os,0j4"g#\ p+1oFc6Jİ1`=*kh/\-.zpP+1T4:J-̤aAL{F Zg;*@Ȋ9}+SO\4,A\~{5:N|lA>yvuCEQ_POl!tHXTI&8!_c[1rN*S8A䚯HOi.lS}ͻ$ԩ+"|O3@+ ]MUb=E:; PkP[j{G/0AbX/R[?U!bSpZMihmK[k"'+gM,sU.l0RO#֫F ⭘$zoNay vĊr(NrGXӠd]Fhgo9 b{k*?>0RJc3,I )i&uU>Z$`) 92'&jh=gp A#uPX#zax%Xf$'e,#U{;Q(Ҵb}lcQhWD}ڼ̲ ڹ^BQ-ɺ"#V4˃rkӮL^}Koȑsׇc)QE}{~eUAv+We0IvšP8H6.U|c'uj9=iqU.Yv,UfMkPGJǖpH@g9h%i[LWy,R?Y״6}~ȿ+Ih'ͮtEgECk}m xݏ~m>H 9@3Rbr;ZynB8x} uY_*A\X]]*˕JE*Oi%P7TJ'[zlRFjYDǹ{:m^ٔA>.wmBJrPujK^5HgE5ןWaӿу1aY6[ \s\ƫ:cr+[Ft_*F^/vuʨ2Ol,00f$˸RYH횥X%vsyN[hv I("8AYF|$ǭtzV>Ւ(w5İW388% m#[ϑO%; jEW@\ܓ\ω!x$LVL>UiZ*RTdU9!.sTƁNk1Eֲ܂+*G0?:I,W62+Hʀ'eZQvx'"3]Ưt gl2ˆm2jM;Rf+RMN[xk1Jb/1'&"U=E6Kk-t96:Vt@I{L\܌u m\6_ݸ1ӍTInKM$K,JVNkF`kGOGql~%v8K ^zC!R^3R%{$'®ǦEg Vq-˞k-<x#宕 w@UX;S RN(8dj^2vq4Oʵz֨Kc!PZl۱;e]+4|y= sLt u(a}1tVj0ҬJHdMj[ ƪޣ{T @=dƊ n 6N}+umcZׯ HӘߑ$xÐkv9a1Ȏvn$XՃr=;V(m3֯ N0YkSמxFc EKk :#q^lQa%/ҩ Jo(,]?hV-^ƭ\A{RMqztG9;}aܥ$eS8ɪTQE}8n⢚.Zڠ [Н,)bv]C։X2yqThAGfy$C%}k:3N15eA샧ɭck*l ?56Kl^k#lg(`stp Zq.VORq\{$99Rk?7%~,Ha>dR)R:zWAu3E+yu(5ؚɹDb0r >fmV뚍0GPjut<ӊ/>YhsL,+Tbv8qZHI%}I>Z.#u4q:2y:H;Ԛ/Y*-k5rx$LcNje5L}wOj_xzxZK;؄iцE)~t<778u(Ǩ860gGZ0S8V[MQB3`p^8ڠs޴༑ +cU+V#W.Ǹk"K G˜QE¶WR͑֨ǮIEA:-zTht!(!3T;[{K61^yvY݌1#V*á[K G#yuꯚu (+wCMHx@U][< Y#1qTH1sYڤ W%VSϥsIʌOIhQާ >Zxߥr[F\ S!S<@ۆQRC1]A,rrNM)q[>kFIkM@KHkҢ .;B=OBX~#v r-Җ "`EsSDIykiFu_FHNїQޱ\HAZ΢&]petyR򧔽z篠o%AJw$Ѭ/{" kSS 0FFEùVӉ# D/b&E^xٹa1+[Og j й!~5Q_@B<ɕG'53:Ȫ\*]R~]\G>PA,P(UG(*jlFaj3Op7bpvǏejڹ'WaIlذXOOz뿷t(ҴxAT}QLQQ[!6C7e&2T籮z9ē9_PHބFJrM4+uw%Hqku8/MqEm5-* %;E;TP C>: kh3c AU.{+p|dk>>z TaR<̟§|+OO;.Hק\"'^OS.LY"_xHad,; BHϥiiDbtT5[^1>Յ򯤂r:ںYrWjktU[.r9*ƄCmv՜tt#=@c Ĩ# $C+mu vVFyURdnUGcY$6e 71QjC = w>[!1z>igQ\ͱ.r+R#g@yP/<5q~(L T4^jUSd!UV'.G';0mFd!1 [U`ioF\Ni#3dˑ熥Rx1p隭uwGbzg͎O;s#ڍ. Mg2bJR>UEmh3io䲺Aiz85 w5b&unZO|#!υLg5j!%yz#\#`;;Wzoj1\dʛRiry؞֖e.ž Ryg& |ޮi$F =5)^I #a]r1qU j])Gi<֝VFAKyG$:+4tX)=z_f 2?,M2ua@UAmI*d*)R8`Qy5N..7/ =1 |m8Vjr7 VվsMc\[)!fjסQE8f  8Y^Ud@LUZ\aQH SZicA5"qL̲tt9$vvs sU KBRq[ϥ1k0wg޶ AKF6}+2P6g־F|r۩~Ru} YfʹC|Iނ҂a!tٿr{Z3Lm+y`q=u$df6W Nwް[|Z)d ҷ%D#8iS7LPdP(&ȗ8s11X[ Èz FD)pk_N1G'\k`ؽ(`{+>⮹2yl|~>Տ܏-oFtY:ٮػo~&u08j4 [žjٗn b~+e8@pROfTrz)Vp_hk :$GX1Td5o5EW[8K d5.<Ɍv]jICȧA!)WC8|쭊a>VN¸9ΒR:N+`M]qZ@13U.ӮC'Ұ^j4 VΥk`bT Qp#>桫6rBpWI<* k]l9rjz{ްlGZ-"[fyZbqcJ5+##{ʍI195xOH$S~.~uMD Q,b5_ v[帬/j-/С@$y=aZK{TfQ4D< xN[#nȀ n+Ҵ^rGN["Pۭq3/;#l=:ƳB#%0)b]U_}%B73P7S]7#fIFZ L{W5FQa9ec bx,VWڽ/AFsI9vU|x+g5n45бMx̱Mk%h'ş,k_/V~xQÚ2nb0.2 &O=3ʴS 8J|x?. g`_7Q|)^eƋ3OzoxX}Ig?`64j#̤Uy3YjOV{wj"ך0}##Smt$*OT ~٦?O:G*[i c$e7L?%) _%*7'g ۗlB3g"RIkO&Agw%?:aA-HoedPOrӁMo qw=$O"ᮅ?1j@"]gWO&ᆕ77cg9M\OZuS^K,nW|8Th~yTˏE*χF _xvHwO=̪Xi>%,ch-YKn̩ͲqQˤhQض$ײVN@D?™HU?Wdžteؒ9)(M'Tsh0L&}-+mm&"IKGzd YnXcȇ\7EۘᖖeiwWw8t 99cwn(`@:B.BG#rscQar~f=SMI#Ȅ?IA$t=BzҞ9=*kcvt5:w\V$Uv ҈6NXg$H:})Ę> 6Y}pzSiU.BUkHGzsOi r(9aV< R]C iP^?ZFX_zԴΟ֛qq~?0,=h-R@6T[?#|3(󬫍GTUe*ElK[I&̸LyV=4W#ڙ. 6Ƿҳ.9~Wӿ! ϛ0n1F Rd/*8|T-S( 8cȱfLRXCkqtp3VPEi >ݸh\j`ASUn@%ǽPg]m%>Ev /4$1ݴz̖ћ ٱU#ڜ.Uż|T$UX=E;G0eW,66r msʊvIA :"⣆0=k^zԑDgzT7p8=kbWn)*f/HzN vCYnZ;-dz֤]+d,tJ)qWıH3@'\2DۖF>i&܌vXX-׽6+鯂hԱ'گOaYҼ̨\z k3Kfi=)8#II rAƫlg2RX#cn5={XSߝeN Em95^SsT#>/5UV`j'HIdO،Usm.G'9ے8kB4ۭ}U5;ɍqMzxlsSĬ9A{|L~>39(Z6Ŀ-֬p'1˓x5ude%0'Ҝ@X,7gq;wU5kMgR08ȧ+fnW̒CliqQOn!ִM+9SZlqe^2]. HWb1\xMQo9ã{(>˸`3'֘+I˷ڦqaqNIA!FOyvǽ3,r, zITR}z/Rትgεg,KbU`On4e9V"y^Ql1YeǜPh'=i &E}1 aH?įQlE8LJJ}Fi?*MvrĒz $Ͻ. P-A@ȪSvYb2[cP)'յ7Q'TbWFož ]1ROHrkHEW9ZeͰ(<.n6 qMS2u`9h!2L|*% J{{XC;~>znv7c$؉*c"3 7VAugJF)z#ڨ =FtOnk +KҽQ"bsO=).?Zz#(9= #R3sޫБ~N,sYiS:? vF9NXfrOҸ֘gPXB➯)J<G=jXmM!,9C))ßJ<(8mwo?*֎q;ƶld~Vt,tq,jS\՜WHIsМacɂM\ѭ;ݎC]/JM@{(9g%==c@λ:367zȇOm'N*nJOjfE^8-j(b+HĜ pR[t;j)Lҵʹ,@|h-CG"]F-sKǥv>>bIOߏZ<1T2}pκs,*W &1? \UyonW&^I⤄Pp+ί{QE} =_W?bSJHFH>˺/Ȥ*w0nO_ 8EeȪbJX,J1c*-Wd6{6gw2_I= ddwN dѠ #4d[}=LE2qgI/֪u?:\nazԓݴw c >k2iFb:UB wǽh1֪ۉbz5Y e}UFQdv;>OJ,nK #u1KidҞ3xB{4.D0<8ShX 9jv0n!;r'nHup0t-FFô~cZZTNLw`:V7! Xޑ_{ {}1Ew5<{3I" U44lA^}%f=i<+ȤA 7(LQ9ǵPӗ˺7R^ώ޺2Ve 0`ۡ?HpcUeҳd4 =xfQۯk+Z ?{3 wcRA%0Ɔ"Cg9oĖCv[Y\Ud[*mݷj-ʍVG .>c* m%Dvp r]p\< tS0ڥ#eC+޹[HwЯi-哜w;K,*4%M:ʬg"[ZXgYaSJu9otFV@:m[#$s+vH*kVP]bl5Blf?/V 7-ivfaݫ}E|7!Pv&3dke[5/;Ì stQ^=m+[cEA@JuG$~қS|SVx"Nb4RX$QHq^#ԙSso*s9 sld{t`*z 'O>v,E庚E* A,wɲ!OZQ(TsҥӉrG8a\G {}K+תh֟c ƹȫ_H[t[ {nʼn[kQ#}OJgY Vޝ}m&UN=R=89VWa0Ċ3VM9ҫF $ $VŴsDIFS+Y5([vc&/lix["esUBՂ*4.{ eˢZFH=+=!}H`Ik;Cb|@I$ц,e:[/If d6;r `-;n(\ۂN>E(ҪGgK,JBBziŷXQ^:=$^(5F5ۄwVZ;Z8`بQ䄪>{P[*Ԟ/@Q3F5ʼR6+YzY{UTjH#o={Rɿ'ҩRlنCշg8]Qv݆FN=tjzN2WcC)y,F̪2 quh9g{|C563ҹjLVe!{5kaoCZ21Tfp@YrIXX:rb)$Bu=jVZ9.곦jI<1ܨpl, ܍gh[s/PGcѬ6I/%/8$!}N1<&2Gel&dy9eCVX n򨢶D"0>R3+T`uo.#_SYsBӑ9>})sd\ƥ)iוz޷tNicI{JſZYC`_olSKխ+X)$ խSMU8 6{mP2k:U97Bt5-;;IjO8m 8hХƵj^ q($z\{%x#'銉I:Ck4kr|]p $zfH'!ufu-fGcYr.J|۪«wR# /^I%$64Ѝ2 ?z~56m-@p klz8>¹#n&,~m ۊֶ%RRWUaC1L(;{ ܳ.o:!t,GR})-me±p-zH,˞qW9KF'M_ʾ}ΌwtdGZZK4xK&_vɥ=lybGcE?1M{ P6#qMiT&ӥL0Sbge&Eۃ)_iobw;|ai(ћ*v 6Njů QoOƸ ;JV䂒S{w- (989)PܩUi5ڋ[r})'yJ1Q cZʃ>]Ģ "1v$H"r+PMRUEͫ\M<,[vt޷;yl"3$cMҴ{- R>i[ А&V!2I7¹kto,6T)sU7.rz7)# GyKeIHZ.Q18FOkO:x]]H0hc<+AAPprzp3\>ZjSETl)ۓAJ?ytTRԒMZg("K?fNoZE;I ':g֠XX 9^ks)է}}5%0GqW ZJǓ ,*ϓb`@>@`?Nda384{q<uo\\aC܇8*_iͲבWiVi$JKHtޒi0M6GZBڥ|7qr ʬޏOE,ѣB QHX`p '0y] 8u>znj>&oyq0O//!G,z\ bOSZVGp8⺍6ȄT`b&{o"kqEO >sǯLX+KYgOW?h6IԛTtğJҹXnU M9Z:E/>CGV4ŕҩ݄G8\\ c2O|AΛ+:y~gaS"yV"`1魮PsN~ vܲ4RwJK5>q5a$Ea-X5ּ8BcUCSNnYZ!ֶ4W0^D]>Hdޫ!t6 "(Rz`k<[IR >UR Uy. dQEz7Wŏ>VcE~JUH큊CLH{sONԌOVJ˺h8H k)=r#zXH!qujVЙU[r@x]mpA\4Z~#GIUT$0#PIY^ ~z5V4ɗC(/o.'E?28@DF>ik(TfkzDmmH\}XrInmi% h'm.Dn^YXb\ }5 aʵ&d˟A[:7yFI xLLz#56ќԏFASZG8.~Z_&Afd<Ջ4"erdo4,B t+ʵKkr#fQEz6?(Vup 9B2bj:G|ªڰD2I(Hdl ռk,ٷQßcדjzq&½-nRXղ21R=i:;F ۔~jQ*FpEx!Oo֮4nF8(̓uѾQ\l;ϵ31Y[ï\i!.rgaWHb%k8 ts,*j 鎔c#nKNrBtwNacj}G%yˤ07L`cD`ϯ{m̹ w @ .ԞY˅>HͷvGu@mܲ;ۼ ޤhbbAֱ55Fz{JY}UŻfGQT^H/Y ?9bB7 $jWHc(K;ƪ,{:fk3[5Xc+=`Gk?Fci Vfl)~n}*}mi@p{W ]Xp'i܉[xQڦ3lWg!T֔q"X; :+XuhL@K#\u4Ϲ= mH,:u4~QU=Oʸ/}{N u3Y_ iIU&"O_X,n/nrVqh_O@kJNۣ㠧ks=| w>x '^\qR“mW}o?!ԝ˷\.}ԶH] s]HcKZXn \'F6A'9?d[Z_j`+N1a^NC4cf^fx1YEjPCJ?*G)ydU'EIgav;1pMiGfp1kVmg,_k$[rYHZ١d0;M,1>vOYnTǥsv0$cޡaC$oXTQ]-UݬbLE"'Wĉ1ګGV 9H:Pz`Q#' kʪ8tp,J"s=潾ZfKsǩ+CI&=XV.*sݤ0kNo$RLR;zd2 ԋt[\޺FGP\ [R _Y`ځGOT%s½ӕvq f*vM`FAb .;L0X9M$N̼$-J%v +-#P(W] ^[4M:|YftVzCNʧ#o9hWEǪkq8F8:ӇN*EFEXyMjZ[,m{u7^Z)}f Gzwv³8@x$bؘ\H:?P;۷q*&"ى>?چq۵UreEQֱu>be+dLgޭ/xEi$,)Z=E{ ,n2;ɸ#&=j3P$cvڻ0ڻ׸5K^,0-jBLW4r,NHŘ&}KcLah%ͥ*/'W 1[ #WEʝUۂ#QEnx?F{Q^jӕR2r;U!@pu8b42g֫~Serpk1y$6l-rå1V n[y1MkX\7W{6 X-qmuv U^MYӧ}O[J>A'=?6*ט E-r~{WjWMByF?ǿw|&zⷬ[h>1vJKF2(.wW?ۤF}3ԫ'f"]Dn`0-ˇ*7,˷>!Df OCFws\\N΢&=9~M};Hzdrg>( ^ǥ48ݰ҆SʟYi NVipYOWa,Xiy*qSz^ #:(I ް'>gZӛZ:\6FBFGZvMk$hH8dWK>,%k]*:V,(sZ>$zȲ gzXdcʹ?<` Wci%{lj7X5j+ןx@$zuK;ci_ ,dC2\`}_֭7:{ku8nmdiBkYnG,kp$~g `d *X2*_:iت(p2kԣnd &qөI&]HA-׭mxvk6nAW*q^!Y n[sp̧q\ 8PądB H%$uGzӚ/YbLA-$0 ~F" CLKV_q\sHN$dxʞJص#{q[o%>mc36}P# !}q5(5J+o')y^(8nmm$3kdICj'fc"( t򄄁Jn"osڱn9{ WaC$+-F3/2AX7+qֳfy<ս?WܤČH?tv>hOH[9"5th62X^Y1G'^m/ҬI8?<xYcP䣎9lHI^^[k, zU&M9MdP*Ki ycoƺ-CɴHZ-b;;iL 1j)HFqQe2jD/[YFyV..s׭? 2}\ͻj5.Ipi>fO;~tGɎp1W,lbFHɭKVU%Shd9'+*=VVڗ]~HAf ^C̒*Rk?O-^lFϹ=)|Ag##ک[U1I= V/q&:!x-BP8A^- #DžפxcV*]cu?ƺ.U X: {DSku= uxB7/BK$}6zk>+g‡'|&o")! sW,oWP"#v{Y8 wⷷ12ny"` qMh&5mgMw$N1r¼_Kw9hX I'aq7PkR;h,OsZ+K9Jͽyʹ_Z Ԗ16@$8=^%aYOSU[0x~&+.^Oyko⽲P[iius!{FP%GzVG&>}Bkp'#ڶ%a=){s64q?472I5=KKsa޺ HSQ_使/KARh^!|K FثĈy k'U;EAs5 az^o 7LרZ5[+ֳo5t,rcaW!Ei{^h犻kz🽷UCOoHa@%#wg b$IU9 @'Ҹ-QE}Oz(a]7c<73Ȩn7)z$`C3޷[׀L!(=* _]ou?%ωQIVIkXc^m}jFLe4=@u,.˓~[\7)q&1kor>8Hz5gM_[EBCZtu+ue(dՋO\\$sHFÖ_+Ӵ4@gӳ+"I`M>bFef NJ_ٹ ӖY 3sS^== x륷.fR:?#BCHtt $r%'Y,Ĝcɧ,>lvֶ-G)&9n % M48$`[}EOjp$\wmYPHĢuWWj6QVZ АU=1[z]Y\Ak]Q\fUuJ>z([HFүZ[Fe$yXWhsD7 Zk2 Ȝ*+kM{qtF|FN}}|)wck43BYb1|aڜY"tb:V7J& TZ֏8, =;SY/x&R$.O98㊂FitWyjixnH﵇$ƪlO9W z֦(JM+5(ЅK)l 3ZF@q#ڜ4o.I#$g=>mwX`4^[E{E8״O1BH$qަ8*SnQmnwͣ#O&ФBg*z4('qj!Y$g-ܟAX뉬Eb@GVxϽ:+cfu%iD>I R' zjēĻW$`{f|'9M[["HV_C?µU)5o)F¼Q92רn4mzb2IU/).Jcm֝gn#Н iblX瀮 S^z7e`g_]-$_l0_HZWAUzOѾ,*GbZϋO(Ny=jF0~F(;GVV-\>wP#33wUZ,`7=벸aHu2 sPR[8V 'Y%yvkӤfcͰgh>=ppt6uVD gca9q۸sRHr+3RKfr0^8SC(AƵb}.#Ѕ{*cw%4FqT:Ch8=gQ P 'F W/))1zfX1$yio.I?c6$)0fKh7 ȧx;tWO Pn'2HO}.F:W[Aw%@L$2F+UfH<՛=ɟzv(egrzךAwp[z5%LUTW9rrqQrXn89)L!)ӫOW**#qFmcU'B0'9ss]hdx.{ p7 ;x=j 䝤j@0IfR$;UuP"[[WtvVꤲrZ #']D6l!_0|-?^$[Z~ϰI?kÚ>qqt_('tIi zպOnAsPxe!Ju4Qme' khi?!^ʇ< ךx8SRqЮSR,xոհJcv5xrCRݒ=8Z7m'mⱵ?"Ž&D.7\A;6F}EzE&q:D `5Y.Ej#9QPn&.~= "ߦ:bm 9-.!]GK0==): U";xXvsQ>R/Z 䎃9i.cӝ'` )GsU֒얗)ALMԂHh֓婳Vgob?JU_]6qqD5{6٣PlOtIMyi*kynvxb:, #-UfR"28# i*{V%֗r/xnUԚt۠af8z{ѵ<ֶiIǒ_q޷#$ ffkR[nE 凥m_F n+dů[;}*G=\}F]F<Tf «IGRE5eg< Vo Q3$ x-UFdb)43HN* 5%cڴ, yHkђM:wF{TiIfq}I5*]W+i7 5c5R1Y~Ns;)+q՞4ZоѨ4̹HF~kF҉lWb1\ԶRNI+*,Cjʷ9iڮiYolPzWڬ&i_$`=+F kBF zWAjt*XH"(ÿZm:\۲AԘ~98d;ڳI8t-N%2Yko{_;|?s]EY(Gb}; 5[$>zA,r㨦kh`p+ [۩3e8±{ ;T!W"=4J*AAWfo j: Tiyne\tync|QZZbqs ƹff)]Wak]|^4^[em[19f*Ks^M'NfH'Mc)_Џ~f_ca*VSiqs "PIĉ.cj iH2k&1jKOka·l<֛c4ìH[kҼľ'ijA3,IbVl`OgYm2vcm/ZDž4ݍny_z/zkٲFc~c;o׮}f-m}.X$/dFǀ9[,T]=iP<>E?½rѓf58Vqkȡ5{)E1Cu$88 =XqYF&C - 9ȣ<ü$g5)cN+Ӽ?۪ \ְV j=;8ǠAkFBrG]w"ix -O^2Ue_=}kR5HNYd#[SNLCRXIAOa+0 s3]=Q² \ ҤWQ[\YL"zo*~ i0wľ$Ҵke qyᴽJkdIz-mGWssyE^5es\ϊtҮ+߾BNa+AD+~**LtUw՛ctb_5uf%Gp8'ֺ{kcoe93T-y%A9yw|5sjj++HGߍ `igqj."d`z0H޺|6 ?uWr8u{ QKGއ94#~ZR #2tU[s ;+p#L䀹$VΙKQV~&\EU*; GW+uun28ZZC ć N #=%սOjQYrN>FXWOX0BZ@85KtahMkH(8I=ҶORzfyvdz=ܱ֦< UF ORjځXyIilC9Gtpz| { e+;ǵi$՝=ͱTf9sos bXN}jЂ9l_qhUBL잕&] `{pk[Wq)opTQE{r}@``QzEiu4K F=*Ω];Nmؗ;|E뷈%ĻG 61^jIC6c CQ1r#H dG H89oګ,^I=MC{j3$E\a;5%711$8mf" QE fXas.8GDd/:f'aeWo0"+A֦-j0H *ߋ]k+HgY|(sۭyQoZzm:&S3䞵%è.['?JGN:ں #%>]D^2-Ivk'Pct ݗ9jO#&  :NHr>nel$l {rj حd=5xL`M#@s]χW.7 ʨ Nwt>+bF,ڷ%{%;d]J x1"P_HO.zֹ.ndHl yv+ #vߛV^DF SQF\Y @?(ckOoD8gF=ꮙaWq;}8(_m8>*(ݷ[ǃ*)<]`O1sWk4EnI'ڸ؞+qr z'^adJ讴S*A]Ŧfjii@~\zTq;FrYY85Y$KNU/5Yppw)U5h|B}K3`I<⵴j*jk^0@<+|o;X+d9rNq[-<"E,9kSSxYL{Y@b3q\`޳!+jV(I$5z;¡c2kּko\$O2[57ī¬v)[>A>`TK &Yx`-֠6 %fN*=^uTLq"ve_kz\bUDƷvd\qt:>i̘FSĭ5\*#bP*F|4n5 #21ҺaTe~ȉ"르ݻnWD <+-1"m!JE`Zouy k/3 tvK;Fy#Q WQEVCm$sUsKE79\Gu6G'N+vf$Ikk=q] WHڽ-d]TU~A.~aҰI.5G5^ZC<#+"-RY1Z;cw x+Z>*5'~JVY7nXyxOF%">yo浔rZ2y_Oz-&Ԣ@{ֺ- A>׵`8"E\H" t5}+ϼ_l~2犻*`WO= "(;lhʸMt+Mc癇AkN1Z(',zr],,98PJJ^,WA$}GE MՅ EQ?ιi$goējd+GOzR__# =>;Ґ%ǭSq+r<YNkE1Qz^ၫRi .u{ ʣ.ByF An2zy=S)FJ#JJ(ktc!V 4+esN5bxD]NEhqC\VL ٰNa]M niOT>HT'`9ǭgZM?[`X3X7zb+e ˿=h$quZmXژ dbGjǿmFTUnv0zzZOWnkky5m.#c$Q,#F9OA5g7 WAعIG\(Ss1z;G@c(`gWEٻnUsY29լD\ee~V`n9qU(nH\\Wom @fG®01Qer[[.+Q-h@!{l͔VV=p/'yr~ v=<*LW+ 7MR SF(l4x#5iE+ݍrk_Jޛ+KFԟzWMq` κHs}yJ-@z}kY%lt۪,s'FFsP2x(kNt3"7CQ,ަFCY:lo)WQDv!:v?9.Cm?6r>:v:lIsfx\éI: }+bi0*jċ5a,--iȌ q ֬> +R$0Ih$k>8Fa,)*Xjfr0+֒WCPE 0hCSX#+۱:yDjlrpDJGƨ\^Cf7ׂT/-x3hY'+(n3؇.P%Ey@&gHZ ypnEcxD-HA9RA V)%lBGZu[mrG3E3Þ:ieu[6 F~?Uf͑3Z8e|~M2)%9Hym!|x㲊.t}+tWv[70 :UiRj0q"9ǽyωv.J|E5n:Z֗B&lWyp3og=~?jʢmćO?*QPMc4 SE4>Ԓ) `&ýuz.i|(⸿-[ʧ7Orr Jhÿ8mq]9#~ ȮBʐsYHmOmKif(:k%&R Z5I^N&Y$~!fxֻ9On޵o*)bnc̛{Vm TGVQnsSe$㠬mzt(fb jmnn#*2kͤ $$NCq]SMkpUȸpYҬ MWkZxͺHTXGǥsΧ \-Vܲ|!á)%mcY`a<[ZncY.Bֽ1sZ \gҷ 2ϸY-zHch*7n,/{5m[`cl~[dn=?yR?`MZO]0RDVNAp\ebO^.F\`?*^V ddu)яP]hWi+(UA/:tWbW!B'=G!yMV5^U 1]5JזۙoU9_[Js[# 3d\Mk=]B$W<+Ҭ4*َ;cZLCvRDn]2ڜde*eWl TA=+$X׃kxRu9V;袽sÖ#Z=8Ң[~OZF:Uh4T\#KuzWDo(2JZͻĻPʏNHR< ѵ$+Q..xmGvj$[0?>jyi7R5Zs7~A3|SXK%˸B76}nCVo|94«͏d[\vD}i౮KR_Bܡ=mMz/mcMiW F[``&eA85ynBWQE 3Lzv&EiB]WZv1[bW"E*܃zQؑO~BQ"W^axVgP6\& D`eM`j׋nqҼi䎵Ikx^y2 iqc]$cSչfVxUG-К׶bOe6q[i*%LF9 eϭt^Dyml1}ln =k5 ;P™I78&h'TSU2/k*9cקy6vZnk Tےs5fMGT|k=M4_ZʟCX3NLr{W~#yx1k.|ðUCI,TI5(M'ҭW6uD#گI{weH 3ȨY%Rd}k*}PRKSm*ˉT5VE?絘!q^y:4V %I\Ug+WwwX-VE5 +1받&7kw3U9/n㷌e`?[H##]Q=+\Z˖a ^UxQnԥ_B$^RR/~-ۂg50𥥽Z nzgY`2^MX 6B]U%*BMdݬrῈdӧ4UH枷8g2=>ax8⪾R\Ƭ0ĶSLǨ2Q!]V3%FT2]<>&tLܧ֍|5Ѵ柰0$ 9ko؃(5w_ؓ[Ulǭ@?ҸG:+N0=U״s鱿£\U=q;z51t"&UMSMċy/r#aLzDx,#fhp#DfipvFtފQ.h|#k3PK&QEvZ' )-e )?֯ݬ&F~!C>O?“"@Xfi 4h?MAmOSa\Ɵ! ay,#A~zYQ7"xo{V1o*h[P?aH?R_FAY-SYSc\4.NdO%ұ')դh% _mNVE IAm~6xom6xom6xom6xom6xom6xom6xom7xuy> Gbޫ ގf /fE`A˗>xF3|g6 zCbǴcf}uAu|E9|gzиcZ_W۪c`c #?:iz݇y1/1KmoxA8&Z\<=/&=ͯnp;!g8{Οxa{LW _7_$|oRD3?7e_$gy!^5/~u_kˈ_^F(wåOIp: cʛN꺛DԍcCe0wI|w$!"j<,~n%oа=$I,_]sW> zB0>&>ܯҢzE[~{#*%3FqIq̹7~1!(Ao w}rl8n$+}C ѢcPNs?+S;Vn6A1 ^džH#.s|q|zwbl#ޫE&7X}|>16b s?:Ap YFFɯ[<"PՅ|N_ p]$)eJ7|o g0NWH|1yX篟/ҠI@ʚ' x~ldedadfk :ḭqr*} q=l=? eRAkN}8O75 ^,bl Iw9/emKfhHEÄBr:dzyX܎]HLЛ 8x_$Hҟmz@!n-!Xõ4@dYہWNejBc$c&vTn[, &ܖv\7b"#UN` D8t8nNh"mzCd~r rp?s|>eA;>ddarS c]3z(\d>aVn0u[M Cg1wϒED.$f/*'aSW,4[6AYE2=( /96x$Nܯ'܋VunOiܐcIiAxY!Iij#g Lf"M7\R>1h@w6S@BP=}^vM˰csS9ݝ{<' fLDfO{L ) X (ߎiü4i#4 ǧm017^vɉ <)}Z&,祶mn 33`?gd`,+Q"y L+U`#ẅm~/geꅌ UEWg0o}=P 10Bg<"ux}y[@ T@k7cPnϜ]~CpNj#a13 gD80dW}c~g k/MAi8ixy##; 0~_/+ HePc)dwOID — ȌX;c8r{-C{B$m8e~02 [[jz1Gٽr;5-j}F$Ӫe?K65*Z~Glw2^L|Yuل-[[u%\&#@f0ܿ8P0W;&FEIv:CeTtw @2yo%mKHkmu4nGLX &ujy)#JEdk6 |a&Imy/5m#} d,A9ku=CG;: 97m9O imHriȶ;h6nD8CcÊI-yaۗ[Dtbky[B~e=_:~*8*]Zp>vŔxƽPG Lj@3Azn@N~;B< /K?=b}X#|?+uͼm" .PE!j3LhiZeaKY+0 N}a|c)s^J"OId 2!3N8==iC,TòjapASa7a4ǡ"Ř28%&aK6$uû4ɫq?e3.WU<ݿkKmKSIe|n+@, !1ؤ%dgU.Xh ^ʡ na|bZ 0}>Om *ʀ2Z,tNˈ<G)%׵rAȱO쉬h:Izd,nPØ !ֵE dcЎq/q:ȿ|=If$\ݱ;i9}0Rе~W>x8UR*;ڄ\m J!E @nN(htB<~,q* nkPة F59 lq"!$ n z$h䙶 1뙼#=#-3p>BL؞Z$ 8p D$,E> /k$G$%FN?W"t$ItQuFKtЋt[H<`׾tez-nNua-yyP@|AXu-htNu݃%PIxٍ Ɉ!AC%ov{I38#f[r8xžla#!aAXXrBR F1CfF. `=14smw:~){^u۰P^6-Zv$U) `bmYw[k2=PtnE \DqnȘDNiG.]qdUtiO.ia4LѢøI@t lut~"[Hnj:9emÿ'F.$ $"g ͩJ:&V%#%;Kn(g,*.5 G"f3s3 w/d=rywR!6n$|. #vo?NɁuCA7\J\:Yɍ$Q*5ԯJ}N aYe{=0 9O'?td f$nU;NI|z)UXՇ`ZDi]ql1ɶkI3~, i!@"&`of"yR.3yQt!U A+g|w2&dOzJB&aFX5BbAHjynIA._%[d)6eO]u/ fW' N FB"[ `yhӥD?p2lKβEbz )fKnҷ)<~$:F$눡/^ +'b98׺lۗ˲bj_̖BSGO\%/s7.=]t%c8Zҭ]@D[oR$0,VGRFIap |U.}cG_.K#"&ögd`>0^~Q{jݸO־b"`=]|_NZkFHen0YV%@`?Ko~ץյs9,a!˲7le)-Z&f؂S}fԈTgu,_>nbAB\Z_>vKRޕ6;mAh\4 0,rKOoրGjY 45l >>O=#2`Qh+T Ot7Կ1NLm9EH0P]m{Q,ycgfMi9 Co jAs亂A-ݲ\vkV5 IQu69d2RuJh^X]=-a; @tu\Žl!^hx֦{EHKrE;9S9jSsf-UҪ*ڷ>kk~ی_lQ#dUO4/ۻ*4d4a<cNIPtI=ݟ["0{nvw5F/-CęC/yQaywP"HQ Iڞ f0"g6q3}1|z6-U44/O_޿;?&bjj b DhFh=R/ jˆ\v|gl-_g=2D\կ]ȡ ]ιu*Uӈ̂х(Gvqn5e X-;"t!S=:aq;sf 2!N)Ě,/P#M9-У֢uTdp ɊZ{jiO/**j#,\)3ѣVqXk'9c$*x|_̺x`s. L^"G2#Z0ڲ䆶Cˈ@®XG 2k ×YOF*U1lhp+X`#V'kM%˶ڵd&N??ﶧǧm@LD^|6YQdbrE<5RNv%"q| d E O4ej4Vs[mU-_E_FC<$z`;X4p3{Nvߊq 5 ҽ .` v̰*Zk\M{ تіC`rGt 4y]_rZzkCݙQ&ch!Ywl8 $#F&IWWzǔaqu+lpWzd W5\AHR#(G֞ˇL ÁH_6P $k.2kጂQ8>m{=n:H>$;@i^D73~/D6bG*/Nߺb7a"$axOgh1rhJ3Z4 w*Fv%N ;Q%w OL˦ lB;I; n_~zjN"Ӷ6 LВ?Bk숦q$ϏC-}0g1AG#ƀOK48Epe"fN#K7 [L&%DT!v{ u+ϼh9rY|^ sӈЮ"MU3 E,??9#F#S#SԈlG<|<~ΑHv05R?"feQ @B{/[x8 R~T;8¸QJ;qvBe2 p"QSDPٚ8!wY6l{?JE8˕nOpE$>F0TD`lW͎j"G̱e`0GAfεGl i}wk2DU#bj'"sr{Bp]|YB}:0lhv>v+>=$>`FA#kVOuDd-wHyXf!$UȶF,0~h ->N8Sf&GS,=tSzB7c+n])`V!zfd `D/!Z8G沜&`d{~>-0-`c≻yb(OнHFog?pz״mie23s08冴D0fZzv ?!\$jghT9 j?oJjk KX}|gx&?Fj$耡}<佷vۈ٦Z՗w\\]Uff: `;%68QNh]zԴmtcYA0Xmeqml;#ܿyķoKLh[ 8d:~5bΉж?\>y:WDkQ^-V- R5),wK NˬV^0Zȏc[E.T3sWpz13jƩ-fF!8_un_Ͽ]ȴ|J|}&1H)dX's$dPZ,?e?lQhQ4 uCY13 D2DUG]f*dz*/###뻓.o~eDKJ P0bjY{r{y K2P]"IhuNDhhi?ۖ:pJ ]@k̵.hS8N+lKezjM+6UC@`Ĺ1ʂ8=\ԗ|h҈ac$ Fz2pm,ԨVS)=9#1_G=] L/ri;zm݄T畄|~N $#q|=7]^M蕽b@@41,bpMYUBS\?~RNa%3A]̜.MzTct7KP")Ow ]Էt*3|x> h 4( 0.̇V ;\?Vzlx`1+( 0׃xp&⋙I0iF(("Hm#"lV|z; Yʁf$Hˠf|v6O\[gVTzKV;,zB@'_.- .8lUә4d x,m|Tu>~3г}~W{N_BX}9OxBB8P’ -ѷX!pif!ew8D.oB|f˨+nj11 {efLɉ-kԥb}_̏>:l0fϬwe6luGOޥǷqV ̬KwATVdK Wo=cºu?mWkefGkk':rW~Fb]̤pBPѲ <ӦlchKk9Ob\#UV9%?hߋAhIH\zLO GѤˮgAtT#rҲhV:0رҦWrOr<]k9-\&mG%tdsԞFdn-UTiKL#fT l^vu9}㻗3/?mɑ$<TH%".]=;"+8󶲏+-;3]];I3UH%2D2"N"nXB%֥Q.YMpL(XץS!b92B\*/O\p097a-I-qw峰BT(LxSTDA!=`Un[uQSBF~AK)dr ?= T2"py!njUxv.R6 zt۲;KreL 1ͅk!++Ub|ixF;=?/k_:zĴsN=}ڌE)$L!zψR|/?=(= t=ɔ(xQW%5$MHoђq2N0ǮQ~^Oz}R$¥@įi~v?}?p*$?yiRUæЕo\=VWZ"XAnv4""y|_7ǹ|* 5LhKX}$?;I Tj\JbFUEkfVߗ$2]6s5MzOITwJ=EX5Uս>:Ji;^Ŗ=ݻPsN.$d*?qo1qpvfE|oK{@[isӃ}UP+=% {f;uu=^c͎l%xF;<ԠMhWRgNf?@O ;A6?smW-EDj .la >۾^FLgբ<@$q _ֵwb@Q&Q/aFs|h:Oww;î|?Q>^Q"Z#< R-TL~Gn))fZs2ݾ Vk\M7$\ٰzm~F gapPéReuWHB H C+Ҋ{+]jUS+SQX)Yv,?7ƫʷ + d\Âh*!PIgNAw}|%Pl|4Lx|SpPiM6RtF=q)Yh˧KS۹DHI@Q=WB'3vH_'MPdﻇ޺v3|0!t",O!Ft2` É9[@TpR;(9 dm^&Cjf*ڃb_\@|@weӲƘL ߙLާg)"4^dvrZdxO;򛟤+Yʺ\g`4Wmlz'.a&)"JJ VSp쌏'# R-p?8C1MZb؇[n9"i`O织;e'#DK) O%/&w6=+2qWky(QQC?4/(c X]hq q})IکCsΫX_S۱&| (͊u<81M? T \^ Ott"6 g)؝|zufRYϿ=S;5 јwE>W-we#ɲ;U-[Ҥ콝I("g}zkԒz8E2F6Zh)qY1<R|'߂ί]ʅ1 SU+o2|CGH~B' 43Z"* 9560}9 tRvzHU U S ]mQžQSݵwfS3QaRNE{< HwU|lڠs"Cdc+L`͸nV0SEUU@$@xwni%̈K(38]m#7š`d{@)R,$ԞksqZQzK33(vִ>S9;Sߊ(jf"z+){ЬTЬnQ+jcS.0#8߿8&E 4}{Q+x4_#!z9^w-y^ IDATw#-9rgoR 1Py"Pf < /o\+uXYu*.٭NtB!E5yi)晪m{%+io2rrږAٝMplþRbZW5Y9*ޚj)]7H 6-!*F]j, 1o`uD3Mƿ,\[F`{.:>=:~ـHtjqQ2ZL9c=sm?a-DԆ&?_e/Au˧h}zh`}mESrz?MZOeJ΀j>ת|y* kmRK }]t<\Gj'׈8'rV| Jt|}EofW Ty+UQuΫR_ D2\jd(1hGԚ 3qYu*Qg5yxq;|Tg,'G(u#UuD(ZLHE+/%s+E/vokShqu;l?s¼D1V6 UJoq3Q _Nt G~5kx5)HL}wHΥ\ʢ€ɠǀEOUmWIvYp_C|*"?/:< F]Y jVT?,3 x:ZL=r>93yپ+o)@7H q${hj5ٴ!b `.I^@mF;+'1-S#LS;@U%VD#eRݣtI<ńO}9Fh5Bzx^Y'5ݓ͋`%"0J__^DN/] >T(z;Vc?V|nVH|M\Ƒxۛ:4OpVL}W6nÏq^'2ןX-cBpXjt$NjQ+^݅}B1K?; c[/?k̼m)[\X ϵ"Ғ0PEHDQP"BM]Ia?b*8tuqͺ8t0KcYj.E"^ETt'y|X{t;uia޽w gE6cOFGw)qm68aJ}l;@L!ǀOVcs-0gY;R`DT'!BES +KɈ8Cg`Do"V*OuF_ߟ) !Jt}D3n0HjF %!pI"?aKfڽ=D9V'}׉##[v?@!2,\aj1FJc.h5 B9Ls'?za ҹTG5l !4:C̽nf$b9|=Ot Kᔦe; v:=Ydl~TJ<)?& jlB^Qep@>gIE ;NƇfrN(` c AU*N>4݀ɻFxCPR1@2I"j&BJ-b}_뽋L~|Zx7LzC]aeCf륮hMv@0`#/P%;,o׼AH60lVG7!UFU"Hx,x\+tZTPU}UH m@$56r7ֺ2{>5ߥ&&,|zex7WW|7Rf%'T 2S2}|ƈ pظrIQPʡ(B\Myb:L%[K>#9 Uw{aQAD[֐K0;.Qa= 2uiZ$B1ZJǗoOKٙzOEA}tϞPd7XtCi4cl&Jb;n T:)kU1q;[hFQP#TiT ]br`P (VԠ BfbN6}E$9TD- [#ba6ź##)jsDEHIEr ލXaŝ7/G-Ӥg ^sN [ &D/Q3򑋐 ZUH"j@Qq#^ і_=5hucͥu0fcs:B7>Kl#d0L:N/qSPB$AبNm/J\on2:c %Xх*BO R"Vx$l6V W)"/mA75PZ20x@FOͷZ׻SI}^ԩ8kU֯Z2ADXǿkWjq@bs6֕wff 42ʆQj);i* E2;d=N[F-P%WV*iaD6 .t_4JjRbFJ* C^ (k55"DZ-w#1$(<977$9=ե):ThBzLx T)eiCNF"}Pri`uYIi"Zѝff_uNB7ѯNnWmj_`*UJ;7trP:$ y^o& #Oޚ񆍡/rɫmJJ:eiBF]P(QLT3TLj {0=&L塠 X[(nC?*X @et_jIUI6'KvQdd(Dzb'nί4W(xjow\6L(H+ۙ%Dkʺ͓P a@̓"IE"9Hk z,ugFz)NTҏN@T2cglkzNJ~^3њu~zV_`=6BK] >@$`NVG7pJAº>ofNhpbCHWuYM U^[eW4I6;+UR C&ŊFGAEa@D龄>f@2G;m`pW?;,we`@Jwwbis"[[)@ W u5 @ n'ȓo3Uz?EF7mnTe2Ufs*Ucv"ʡSTzFfTCs~Vf;th}t`ܤp8LAZ +y}y9we 9 KMm vH c#@=DlqW @Ù?vWAԊdxKS,. ;k?≻c("ӭA0(rwpN=t#@x0]c)@V>[_D9B wU!v%k3C~4ȏz5 ^ -^f[ Phl4^d+˜oV5.dp7[=c78 0DC!W!JU"R&z}`jRo| bq{FT uTِl1Uq?NZUm*GiW|]\Gf_nW%)2ͲY#65]ئl st:{6PHUvԲAO)AlM'D\2?X!32|d$o L߷r]?n4T A39]Kok'`v>= ViEsI{:cf֏!HpT_ʳ *ݥ8O4DD3o~Zt7Cm%a e Ɉ -^"˲W {oJ}/~e]]'S[ i, ŒN@q6k1ŧ~:Qu] [G"Һ|yJkC ;S.c!DЃU+*[ ݊Ixa7cZU2>xO$?K֌M/2"o2M:5JqYb8ܟvZ|QbMX'y*G4"ћ%I 6xNHIwXt{!N_E8C>$H GS}ھ*C8sV? 6 .BY1Vm<}p-FXkj ]aBOVCHm/8[b!.[5 0 "$(yvM*5PJ?x$zZmyCJ?Lނ, jws)G,FsE ԭ=О!cvOuxL@H:SD F|(3b -=f墈(oK [u,qqB~n#_#=hKRvB8ܢ ץL搢! ZZHrav=DHr-3yL dX<μcB"s8[8n&d|Ayk6tƫqDqÏ%Lh`N Հ5 Gm\RetU7&von&-Zw -) 0".cZ ±&D^#'0. ːLIr= IDAT2uпIkd7׏>y{ƽHn_INޡߐb*MU "wXc750 $ez7Kt;&$ !=˯$U-C1mbA3ؘ`dFT0.߮- r<ĉ@N04nR%Χ)j{o΁b=ܐ»fEhvwY}֧IHՄp{|$dws'2sp9=* b/F^r)"?[͑O›mfk  6 5bjsd+R~7R ZwW.VVS Y|YVäA--.5ִ7aHZg$]F0d;z8u2Liŋ9fj\.84?X`RBa* 'PN9JNyG6 * K21pz]A8?\AJ1[AU;$"P/N*]V×n)PVO%کVؼs EJx MHzձ2TJ3@fZ̟N_*)|'rאt7S{V"C" %KwHڻB-E^|YlyM.=jEJ111KWLЪ"v\R3Ys_Z"G|zY" _6'b\W [=a|y iJϮs}"F5Nfh C@J3G~ xVqٻ-I$GbfU}n+| e .stw]2L`YU})3GRnngkW;u= nr-D'сg~}L0FXu /n۱Hziis\k

Ni\>?KRC)1̜) Hʴ4f3ɜ$tXLfҔ~z>ol Af}$m_q_[3ZDB֖%@nܲDƩA>7ӫml):&Xlj/y;W^.OxtUB $ @33I)MG*.*TT9Ң =[SYd߲mfi O.1iuJ@($]JI)Tב9Og4Os(K[D(mUL M թ'j:@h93_|zFP~rl5r}csw~y`çd943qYHhhF/5i?D2|.M1z>FL.2yAO13zg%u#$B5^4/ҩ}y@Z`c]ϱY*͞?ۥSRҦ`$yh苸Vܺze:`Bf!%2er,vVs nE, ͆GM!^mqy1_w|_?h8;+τ \boH2m6A?&{ ݜڠ 9&I)7Hs# ^fĵ-kD4QΩcˌ")@n)=Z,_X3;^&Xb v)[9hk,dD"(WC( r3sᚥJU22Xx};%3o? e%3un\~t},gs~e[aeCwƘq D,Wkk8$;Ɍ.Oϙ!"B$"%Wc/mD*S 3P0ҨHp[e C4k iVj¶~wy*:s3¶ide"{f2HRם!n\;/Groya\w7ԌH *k7s3֥_D_z"'mF/qͱGrbBi@ʔQ-HyH_ֳ _F/s{N KSS9t0E(Ͼ/ngҡ 3U b2)eHЌtYUmh(Z_9`HZ}p IЯݚRrEcfڵw/rVq1ITFQi!>Qg32;C KH v8NVզ 4s!LeTf+Lt lNN8kѨ@kX7,&f+QJd5ۻDi,&2٨<:"W|`[[GڑI7f|!3S#ҤLfM'jP(Rm22y_R)s[_AL6dWlUrR0 3/ hַZ葒,J2 5"9;!\TʥdQ +v qPIC^Z.Tvѻ;g/F{X)];PW0HŹ-g;otwo^ pe0tyǞ𥤇>% RMukn)5bZN{eoFZ[r '0Q 4ۅzcTBQ`Mdg7\!!m<͉i&4*Ls QC˦# d/fT1H!`E%R0EśZOn0#cT8#y,1{^rg1Y$QCb }&35[8˄Zs.;[cߖW3,K.4j'{9i=EoLAWyˈOڞm ;'xA#09\ضHiQk!p H+J{YES2<_w0Oy2l&8!5lu_qG~IXJGѯ["-Y'Yr&+ra) ,Wb#ۢ!02eDdZ7d|V%"HΧ:vhKCvۯOښ}1'@QO% JqUiz#lV&fߑxM:[#Yڋ1i'mzO< C^|d;+.rY[>%hca[]8sXlQr y'.{R9a=ŖoG =9hnJ%M+;ifd5HMsr<~k!^QЫ=dMQvQٴvsW{sg0^'cVHKU$jv!.nu]4~ qc1TSXoI@#2o(Ed sIXJEPC{(v!@5EA2 B5:44wYjPtz?m2 筬0)q:B1Q~%/Ks*Jk5s+ ͤ fn"Jܓ䀭53MdB}Hǀ!zy=sQToeɌ&@ $T,I/zwk>2ak cӑTVF mm|9kbLkUdZ8yTfWkn]YBJ hf@1w #J퀒綦2bd6hHjp1"jŠ AFQC9o@LNc (8,dʌ{߿{fꌱ7#z!(7qn̞1RRMNe2zm: pLL\餻4/KKʱ sAwf"qO9a\y&m\!thy7]kRĹ6ZC ؕ#@ lOoʺԀgp*eSywчhaӍ~+VnM::w'FD"bb- |ʡP (]5 vc]MoSeoƱ#V(3o#=`k.@L]PSqR>a:{fuK-1p/R8'߽0@|ъ J(g91|=EV,=DDt,DLͧ,# 2G:+ZZpE,՚f]9*`W|/sv*]/nk!ty_ͿT(WV^R +pNrƖzZU7hON)6>AAZy_/_3/`& clhht`7 ڳ/㍮w \7ë,q2 " ds#Q="FT.E5'EBbãb%mVS_iOI}*s4voeb%*-ϷsZ3a#MuVOINo bS8^"R0+𭂧 tSl]%yՐخ|1.6Ge s@l?.M<1b\kV#G?o=RXɔQuELH)'# O$uA=nмy۟}$IBib|ÝJ/xX}Diև5)p%2F^ GgGYd#Ƚ1@dR {;w:`֫JBMhf]ڲX(1HS_gu|Wm֔QQxY&)8nt[9q9H^5 rW\|J m˲PݣT8o6B) )*+ѐW)anf{&yzcX87#en_޹bi;f>.#7܍ rӛ(BqoDϝfc2X&Fx)5vFh t\-%TS,MfTɚa;.SޣqN-]RRf_3_,r01D#xu9˽?)ټ+A ŻzRml)a*9k#Ǐm++"m 6q*3#YVm*9" ;PQU^eJ9EU\UW+ެdY r~;;`x(ՀLEw"\0끣-M7nW7@ /X5NDF9h9whXHD7ܷ=6'7ypi߯sR# 8%/>>׽_h^rZ\=ULIwzw8EDe=12#Ռ7`n-U%!~}΂hԙ1g;]ˆ}$TND46sph ~6^#wږQQ'B'dqxe86 6Ӽ (M|u=Msl6-//6or7юY>UFUA@$/[*k^跾jށ4ś3.nNa'қA[X<{8Sp5H 6["%L92̬\>Bx #SĴFh7s~%ƈLOڑW>NM_kYOnTb%-L?ޢ=_zFıjzlaQ*MvV~q%u*Oy=cùiwB3&A3 Cbk}s([ˈ`ppwHKnC~^۱HOř˚W 7ZGɂP-(K2kj#ԛ@{x__]isԫ7b?[x˲^5w},a}xx7M@g r 3B =s ,s׉.#LZ֊Fq+n6uʧ_99cYYV6Ue*:fg-߈ Tg _]AU?ܛ/7LTn#͞ϛ–_%.-H:?ӐO6Bܐִ3}_#lYB9bEC4:Ҡ/6 ]%[Z6c4˫­n#2}IĔ`-{d;-I ^o'/*X$ߜrxEe_SA͑3Fi<Qcw??zFdƘ39 'cmwYzٷgnA7U I%aǿzOP`#,b۾7+ ,u p6ջ~_5jO5urba n SN_zG|_yet~y:1 c2n#ǟz s,m;ɾ;&Irf>/+AQ*@o_,c}r o#M7lN4=@ \|w t'_ĶPL12ڝ=|~/fb|Tq.C8C "g[m4O4.>b]e.-s>.䨵9[漁ИYY>NPZF4쮼2=*ʪe>߯@:$oW &?Sc>4C47e^*T@{kW9vo {8/M߿oo ~߭K j9Q9ӗ}lFd͔>'q׮}[U`(cm&P/BTT_G6mYLh_n EՏFvn=;rǑsI 82i[Bp7#'j PBz?ຘY[y?~]㓰Xm/ٗ`F"@]N|3d޶laM{Xl>/w\=_Bw2wҎ"HCi.4,^ ɷ |ṇmeR2ǻiz?5`mDkw%bp9|NOowᇳ3{?940J 9^c/|tsЮ=/vnmqf㢿ZM0+K ,& ǯU @CcQ3(̍zo6,uȹ@N,9%5R(& 9"w[e7M?ڮ @1ԖƑԾIl>?V%~{;CDLR=\= =l_~}ts܈ev-UݫB8Ư9K2a+H%)E̾fi& =/$*UReO\wE }[5xOOG$$rj bg[mϡjOxw+ϟk/ٓe$7mU@[OuoS`hJ8m:ssp yVm@|Y#3>pogbYzaٗzs>XHONiVr[ܼr4g6<[m-JE1yRjxq8OݦA+_efHaVGWo춰 7WmM_o%9m!_[QӒ :Ee.1|XOAxeJ6 T??!bhy+y#@h Mf"#hb[Ȱ,n0?}Q^U3*c.0}aLU @ GT?s҆fUrOxl7+t"0so4q:0{swCYl/ZIIד%/D4QhFޘmE$cO[jb|.> QG$CR-z#$Mrn:"7)(R %ZF"H$dD烆Iњμ&&b#|P)ko:|2Fʹ.6?m73Sx;d!(`H(b$4aI4@,֚r&]5eƎWET5jK]/u<)Ud@eޙAj^I't+9Ơ2ȞhَDo>t׀L]F rm #UH|+3tw}k(ƍٚ-r$7BO^,\ {^$#q!DcԖ4mŏKMejO {RM?ouc`rTE"vV_B-M4{Vw v[^?ޓ̒12j55v^S~ hۛ>u8`WUYISVЬ |ʈ$L""z$RHzQ~5RȂoqu7s;cXkMP4cr'hxa%=lNo/rErQ(؏W-' ʾRMRv7Qʫ4i.tQ?<_5 sr4O筽鿬P[Jn&vp/)s(k6m[Z;o鴹ZpKA'deUd3#ؚ77 %}Y) ,A8irػS15.gH}4t 6e`F[a<27.% %g8R5UNif=b_j;̾c{?n;Β>(^nXkU)6@9OE e,l߿‚[~ =)܍!>e+i1ͭe=(cU,YV*9Ic8enq_} 7I[~3Ů/THRjTڲxI¬nePOPei0J1-"N~*e\7 , t. *)øU6lP"N%4QIzW }s=1cثH@*jX )lBe^="Ggڠ0 `٭딗߶u%z0ѫ' MQzZ>]@5zPrd݉cnlקR9>73I9Ɗd2/WpkhH_P涛!3bެR/-i + G̑fVfn$P nYЃyN)Dy'ݦfLLwFu//W!n ŽV̾4w0ݵwm +UNfj2_ߺ2u/7U]H*31_BeQ]܈fIFMaiFruQ @zrWL)Ȗ9Mدgdyj[_isyW+f/:z !Qj)IX끝j& t6 'U:?]ot[ZժݞChݲ^Q׻Sg_֧5h )<ǀ XX%h@.,D??ʠ7$*X,'ih~;U:F]{Ջ;|e-_R2ϮIز-ٖ5;$ZY4 @7G 6;Gzśfשc7?߯z~Ī駷Yv1s2\&$blTZ(OO{崶k27ξ[yJ V"Ff3E^N+竎sEim,1MtxT/ʲ)-xj/:ސ{OϹq=߽*1s$fG6mNE=EFWᢹ|Af˻??pzywFeҨݖv #C5㛚[ j9!%7rPKAUwM;1qh,rBh[Z7uƬEZL 3Oף'MkI.:2al~wǻ%e*JtDН`k2Yu%cSGm;>P_o8ܿj1q[']ƋG[ Uzx(S9J03>_n3]>0aRTsb7(j [lΗY߸Pùu+)X?_wfxFjM&4DZ;ͬ$;`g>~^ 3XtY.cYgY/o4[7OQ!Jራ ک]?=ԒVT QI2K᷾#|:<>#|wn-ܝׇ|pEe OWx0ҹ"EҤ%XF)qɖ:~FJpM&-dBa.>jQߡ=Jۗe|>* MHB/&NdI&gzE@ J@,r̾]cq7/_8cq.צ42jLP黻4-Eahhב٫w`Trh+HMPRo8!R)PMPأ5[" z͖sk9Z=g Mc9cHQ;&}):3D̞{63mL6 &vnB/WҔ[rB Gc(_ZcZݍf0j oMGmJUosp*lz|g2"~1yI43!2C88(|DD%XN~kjgX?B}X1dGρIw24d wSV9j?ڌ4|~gQcVLڻ #sJϛfȵzfڼ͹b#SÉHkLH"hָkiebeO4DBn`#R/R_?wuG3p4!˕06bj rF*f d徝OAmĄ9%cM0.N^Ol-2jidT?'7Ңu$*R@[3-_AkW'3N|YNkmiq4Q1_lY8\:7fš9[0MWr߮ [G}= Z>&f5.39U-KLqD6&Kz}??] )-=y;2reûf̷i?%TvWgZF`߹-~ہ@s?MA} |ٖ{>G0bmd?ӻ;<\X.$7Fl"нn*]iJ)DC#ڹ2w5N07b;P[ 8THP`0NPH.DhT m@К"ӍLAιc>o\~mOu,RA[Y؍uk22͛4a^[:\ohuX(0Qv!SUH`"<~}Sy9;n:fOVȊr?bK #X@]| f 1K/l00M].JUU jHlajtKg̉)VշI?L]Ϋ3J໵"ץJNC]k.EEvlv wWLכ+ H%jUo~kDNJCK(Oxڑ&O"}q$KMdɓrzvqEML "T8j&U J8./J$lzfӮ" T~}6~<EE E55y#zk}6_qô}Qs_{[XlLBmFn*A&ǵ?sqx QWe *oR/TL5Ro&D8G2KLUt\R/_P {`RӚ"_|t>1 ιަ2ǜU2~oUE_=C"Asv+YCR?Ob2HQ??彍ͬNMĥD1I2S̪q)B IDATϽo.y 5jk[;C Pr=uas;Gù+97Y@T<=u1A%濫y@/x!){x[?u7g0ych~t)PqP3R|j ݊rh‰9$-u5eUK`fИF/<+ql[3-OezS&Ul>`ܠMJԫƖ*Ѯ/B`z[t{:V{'y2N礩/6Tt' жSH4?wTN繊m8?fHu&;Ԕ儹VMfP?w>~7x n#".W^b.J,En͙zS*t(6F"")bNooVp/kgeFȈew0L3ě+~v_oB.yK"Kif"S7ǧ%أSCVtmY=YElfprV? "^dPOi[k1)d1u7*e>Cճs+˅cYbO8+x\uycH\= MD `Kb|ZYq]Nmkmh.j@zkIO79R{PT%B6*Y@;n}-Rz -Nؚ0F 3iuV9 cIc^.EFjO-SU)U, sbfҿB3YCBV3RkT)*zΰ{Hfq]JX#"PUQ"JM5_ޙTt^@?o0b YYP_ٚj>TkZ0TR]j͇(m/)94T $&J;y=cdcj%RC< q']/.ީ&jnoZcT}N Rf`~͇(xs<;*8Nۜ~J,̜sdca1c0/ˣ0O)e,Q>`Bm[WڰQ9 j}7{ot杢wa +}XsK)("bz~T̺9YTu:T$ܓŒ̈́7nzO]9 fPc^"5%h+3wC*GsL{Mo%MJ 3Q/VJBAK3`PVŭ,T &Q@eX.^bEYZ9#iXU/^xG[?EkBJc CUjnu.sBǠ?~x/[ںG('8\a;Uoe%~(d֘!Ra)A.WL6*8Y-xxӮJ;CqX(R|"4Tֶ\Rm\Cp$(Hj]9폟7}('U.TU&ULetARt7$vCIP&,V}3=(jݻG-mExjyp _tIkmL4 !vMXD)g? -O D(Xe˧Ū*kg^;3"ĩ 9E&!'jV*L̔{;-번`]1w}WQ3,*PaqH +!bHnq7@^NqEN;!Oc/59kaTuBOi(CUz[J`ʋ"\Op)RE$- ׏xUdET1@Q*5rZ.$)D5l%y_dP̜ ! C x}ݶ]^OcI!D+9f3+G(*ϟNڥ"rP9Y"j=#'b=K+!Ef^-A]Ȫjo{dU) "^ q1R[aJJZi2z\K(Q~EUVPVN #~G̚C3bğ'B»V%E 5-pHIsǓda=T Pwc|!;kkȁ.:rUx<'x^07|I8!DUU&{隇!Z*c);!jJT*2e "˹)w޴)p$qn*vwjJh<|YNpė!޹_0Y_UVf^# Ԟ-2JJ)ԭ\ :Hs&Bp6i 74)ɱ3W}rK) 3ݓj5UBBe;8fpn+vW, C(]e}xBeq)h>h{3i6S/;ILJ,s5O.1C3@ 1UmU]4W 9ÎN'ufb7/y~;c-]/R Oהpia'm.HܖDDMǼXMqz%il#+qby %KXzcL,2(?^[e"/0wV 3ɾ֦-RO%wLY~X#Rj^"meN2, jFAėM mhCM[oZ $sAlT);-\m46(]f!*I;*-)2XYuNe^3)v!9 PrRLM`*c:BgYL1wX(HU1j&2z=o3ӎjy9j)Dn7"v;}aiTc:E i-܃)IvFсwyofuAm%i!vč.n3 8L&4Bfġ4dQ&)"2- ˾}G17tAđ##"+>[ÆǪBEVӺoQQ чϗj%U3uB&VbU(rQQnYȇ1 49V5?Jݝ_WQ֍;ޗ+ So_7Xԡ`!1(^l,۫?XN+GOg`(_EThGߔ:lh^#E}*JlQRf5)D2k۟w[9"3X~%MՌIRAeq݇EJ_n<-bg*lI9zZcߟXbbEL2rdPOR-pgq32Y5Dencl#)"P]ìvb` j;#ۛ*2LTA%G}#(@1)3j*H:ArmRɶ[0u_*xH Paj7kWI9*ɂ<27+$}djГ>ꫝ+QJ/͛REr ۷wmD}d=7=fMi޼TN vgPpC}?N2Tk6&{ȵJTRXd5]'牄{4  2cV$S\!{7 FZ%>2Zka5F"r<ͣ_/GV1{no'u?V/޾yzX˔)Ͻ-QrXEu0nh[*1noKƐ|DٓUO)' (}fn1ɐM&8O˳Vs~0%^I^kVb(b;{%`'{n}!8Ob&shBЮ[!e& X*`O[e5oNYfb}XN]sV:(h~ڕM*`䈢R6+cYoٟ-Hr;ҋL87/v)|0OUd>o)g+^-U*8GI~ͯu]?s2h =} JZ,/#|кE Xڥ2)ٴڻXЮKF HYrRTCUH,v7bQ\|U훷VђEBt- UeQ;`dTo.6z`LH?H# [gP(>{Bj4Fk~IF xuݦHLbɫH vW?k7G&= NO 3n䊪ɐ%EE꫼[m<5eÏ,ca=3O庒a\sKY3*Udmr$Mm,ܼr6'__kK SyVfۮZ!/AcOJ~uU%FڲjOf1[_;2qIEH,st]0U*Eav 'aMi͟7y CZ+)Ikm> b!Yjf6LcPPޱ8}5vYXUb&Ïo޴2=NJl( btaDU3Zhu?rf"8JDN\TVC^_>5v:V‰鸔E;i/=!9kݗgPv6,d:‚hT֤ząq]|?B\? (MڱͥD) ֺAg-'1'1U1FzG/|%2B^2泈6'ǟԆ!d~0q;V oR{7^jG+a.ܝ#e6jEj1l.ٖo-7Su$cZchkZ 0'ֈ*j[Or! $T3tm̭ZTQi6 W{Rb=1muۋ/?0M\r߶0nvz**f g bni8.YdŔ&UÝlnz#GE&"YUYЗ2) D<;zT ) *2<ڼ|31S)HV4u/N3-}'|\L5\ۤo-9t= m-@%˫Դ*K]v84wN#^A˥Npk3V|wM'ҥem¥ԫ?9iVR1Umky|wC: CEE͙WYZs.xʬ.;s_6>Etq{,XQ0`D得Lx²ϋ1}z渼`{.sܽ>5՗{xs2!+U2rzY ,.{ᤣҫOErخ&s1tt>/U 7j$xx;Hdn{{{PI[{-` ffR ۳-)jǥN>f>7(}uJx|̔f6!jO2rI-v-em 3dRgj;3Yeʖ?/>v_0`^AUc )&]#7mn$ɶϹ=KuW[la~1f4{SuuWe2IpwjS Vf ~.g Y@\kV/ TScAЍƌf_l6quD[ b5;dZqG.&Aҫᔜm/!L;+2vyj)/|~Z/I+=C>>]`F{|=}咝t']l7mFOrY\ cYA֥IVrI`$'C0 A!BV&㜾Κ]9[ pa߹=a{ u]lar<ʯ{4&t𫗁!*́jlD򜫛F/rE5voEe-^?΅9ןK=nY\wD54lf8Ѕ! Ҩ(Hp/Ҍ '\ȼԼ5.VdTEo=rr "z;݇e{FŽ^7D*rVG?+T4RB/78׼I2ߘԳZ̠-q[weǺWԻ5{*{2<#6}zzu]ӯ@dVsWXC!G=hOͼ{cZTDvRpREtw_+/NEo-,RJưRȌ(CfiD?ER½; NGZ|<cb]ַ/M-`DDR=FK=uvTehٷVnȈ ?<';>-%f֪˜-Cw| F/VX1dj#GUs <Bo8UZa(2C}1}$i^J( s??/Vw)a޶ϗ.GIz~r ެw>=~6[1=jQ Tw!з@r]B1:#d5ӑCeZSơzw\{nt%NvB5 3S^ E*xV UY[ KATe\<3.^o\\eP^Z/(]fHH[Zu}kn'k[,֭ҋѹ>Hv؆|fՐe/ ;qϐt(!B9*Gubɂ-"a Q)i8[;o)RA)9aﷳ Q)Vt\ޛnxKfK6Ȗ@IqZqfd=ƴˬk5<$ӧF-cyt'Fh dXe蕔0Ri/mS] 'JT>sAqv󣶩1eNoGtF݈ӕeV2r$ʰHӴ[9!4Ӈ-y E7C/j=}9r-.oD_sX*h;5CCJxC%[X[*eaۀ9e卼4IJ̡rW]iE+9H6ŖE1N vX{lA@<]TRƈTm3(u`y6cq$;sZ:4f J{nK-nk̴p3'/;fD#kq'2sz Mѯ{ {#4$Gn/y'X,ޮ (΄pд󁁟@" i66 &y}u-B).K`O4B&v4+ Jh=̌r+jx?m s<[ L0 20T&eĘ2Mhbo}rO~[oѣٳ#"mXP)-GoŠn'R9 őʄTS i!~ݟmkO?Ȍ"z) }]AB~֌IÀ /Ȑk{C g00vN^VJ.tryIHR0:(:&1z1T6Պ*&mkC_fLƿç_/PnRDM&rP9Ta!Džf2lc ZUwI$tfgNfڋWPmd}׾뵣p{|՜,Ұ.}.; Y9\\%X!fؐQF(3\}J}>Ejj3>xնcp GCecf(p96hDF eP#$~=VGoDLT>L麬.K{VZQ􃤺"+i/?+(T `$ROszX%of`o.{ǧ}ҭ1Wֻ32Fo]!jnA!jǽԱ@3o%R@Zd@nuGs*P>!LJ(L & >t_\JKz5+}Hw\`ٳ͏O~0*a}ӊnvZG0ׁyHJry8,nтCjj gW|eNH<2\*2ۯu;wPץҽ2WZʾ3;G$uI"2^_L)o^߫۶E{j߆lv8 `A2x&3.4Dż̵Emkw5Hs~ٷvtZXu% }v15 g9#ݶƏk}d,P jO1iVދOm鵮nZc;p(C`3~ݿt2ֵG{=iPy^V`W0:KRܼB5yەP`|>$ iV"û,>Lއ}h0O2 ,#`G=KqRc[LP ?n;ͯ1k\ ?w- tl %.>樵.½ |Lb~{s PBRɎ~%STnwuT]eBry6,l'@Qǰrue l*S.\ M2`;_7jiP{gK~\d^X@3~vԸò5Niw,:8/m?[?vyw/nNٺffjmd0oY^J#s>3K]x^ ].`FYJgejI["! f%wʪ^Fsc~ަq6A{|gddq9ָ/b1sY;"V>iF1wK]_Vzy ,{nso !yW:p|8BȷTJ4eq Ch6%iA1X˹l2XI<]ZR˻J1Yp!mG(DJD oQY]]Qϗ@!^݊4cMGq$nmGk=Rc>TԯϧmX )uJ~{נyfy==ݩnԼ#ay9^m 9E#)eVLq/l8b +{S=a3涃CIpe] m4ؔR@Z. $2СruTrRxXO%rΒn2ebp47.+db25AD/mj.UՒV!jM1=[:"vT 1GXsh(۪߅l{Z=KEqy|&Ұy9?;U=[Ran4ȀʦEpq_~(ə_>+wnfJ@ aj@R8$%y:ʦctXv~JVߞC9*.pDLjq%3sS="GۘH;`t6Rs~>LeDZ y~~ޣk.lŠaT>5NhԲCʨCn&j˜{oDZ~UhYNnSCPʘܩoza@!l;^MRf3קƥC8n2 IDAT:'/W$9#H#0F]~8̌R~xOמ!Che'CVXL4"<[Y{ۗa \a @ITŜdJe-oq{mq͘8ilvLDtHRkBwirpyӥ%渌iE=ǚ)Dk܇īD[1#s=~w7`9 nW*IOw>X)4k;dpK>ELc~8󕫡G]6SRpݡ^ ^SحcT7(F]%6Ɖš¿5a8 p*S+6%EL.ﵐ4?_?4p|Q p˥cDzx~{jZ]4(MP d9<þ}y7TpYk`)bQpݛRk-%*12 =O^4)^s,PB)]kiki۰nùmXKgPn([_=?/w:q'1SkzKa4fj斪ovC)3[11̗dfRՇ@ y@Y) >aJэU+Cɀ1w/D3O](6m")琿`YfƢ:'V}F B2& rLH,YF8چ'U+Z-6>L5nWŽ#ߖ\)%T椊U]34>^|b4R2li-N;@sv8tr~i/ Þ~˗bc[4wmFf grd UNYuLbՀRO&lMWB=eo! ]޻U|V[jEmgxpĠ[nK3/9D9CPݪp;Bg_K51?]{&ͭmS?_!D}$P:]tX۾d z1Ѻ DA-R@?? !GȁOD%;Ⱦ2I+fs/ Roy-R9yf6ҼgG E9#z9nj Սdn04[oW!9-,Vg5mk{9vSZ%lUȁ0L8`oQYYbN50.>X!bt0۩?8$.2pN,܈ t`̊zd "̜Px@ʖ{)lY%84 _c\A s[,>A1٬MHaŖrK$K2fTٱ,fŋ{]ý*2dTK3'z>𧟞]cY]%J^qCμ.TcfJpdJWuHv3w:%:dh]xq y}x)0\N* BMkksC|cOZJ17pNqUw˶}9e"CB3-[ו0# V,}fNRӃېW7ZCW>>oˊ}݈@lk]5ƬNj.CjvXwWnXo}#| 05R̔lz(,ŋ kr;~bu1/D &-%Gb뱯 悗(c۪/QG=wH´-hb$_ }I9qXb1Qʄ )iRvsFuq(mS<0K@^;fѼ,&,bnmhp۸AD@2w_լ?>~yMf0!7I u8-mw%_J7L(NR퀷59AIIhɔB9?*Ya^veUn\Liƅ?R"[P=&bNMցiFdƻwX^2R`Z"P3+i'ZT*VaaLzȍh;M)8SC%Y 鍴F$gYRSGJMk_±pw)el[*Vb(aL!8.*/猎Z=7f;ˎcqUeU&`1η#!JQX ¹%]8'G6z#9 7G^ `/#s|:r_t/uo+2GW!{먖*|x2OzvZzʲ3a>smp3*#-G{a)mk {9\J&VPxn#/s!T0ω>}vib$&MfK^..y~FY Y~|uXTV7 wywG(yу%TԃzEIdF Ѐ,u5hZB1nhEEbRօAkl&|>}i0ת7Uf~/pÝ)&eȬ7_~,kɸ0m]=rc}wjR5@Кrsw7dv)YQY^RN* ?_Ekb>ը/; 4o:zմKyrW_Un>Qg48:>k'TC&!T^Qئ "Z\}\W{.1Pd]] 33b,'Ѻn GR5T _=9Mk-?W.T^5q=|? OØR9ǫL$Ҋ*^x/N藖%гCcIK1qQkLe@YƑa&Clwv!T U)ƉSM` VJFcmrF7-[.Ej ^?} 9Ѫk.{i<7B(ÓZov۬+1zJ]$I$1fU3wȬWWwvcv@K7|~ azeUfNBs#9%tĴW(c5tx"7S>}"+Iۃ9򔙔2Zvsr=lRҫb] OtlyKq `r6T숌ֺ3fAh;m㍬*^GkGف9Vn+itfhF79d̟#;5 eiTji\T"PL/2dtFmRQ1ў~Y)kOPOwp R .$~i?RsbJFXו7rSIO R ˣ dkAˆmx鵔Lŕib9>Ȥw9 Lſt:QeNPu0Q$gp;bYD,fWယFSj9c¼$92,sHhKǑMeߋ{7PqW`uAe7?-ԭ>;){dsO[lkeDQcjCGk}yoϥzG+I X%9#h(@0<5egsXIbP"Mb>sz6lOb}3F3B/n64g#ܡۑ_ c;."nM  ;p{RNspW=qɜBQklVDYν8|*},> £h͈hrbսظ1_bt_!`K`X1O//hOl$,<ۭ 90,N[ji$UD4,ܦcV|ŒEºҁp@ Wb͍:R f9Ș"KSp. >NZkZ[xNrm/Ke'00( =Q@?5?wh.v9 A͌܉sJE d/udAT03 IDATm<$;uYq}}Y*7f!)Hfn,z)2(3sRF)W]ȁ;Ij{b47wx)H?hf6[ar 84(9K Yiq=ѧmQ/uD2{/,ڞnΪ-sdX$3F"oMɒ2R'pp+ U~AϞ%%33CG3SPվQHR9E្qcB\t.]@hr3s쯑,/b^4{0 fэTx7U)}SDjh|.͠qomsQ:G#*cTF8'pwĉy1mFCsrv&Ҳe ө2QzT=ݝ6J:SEJ-H"U"K+r}[>PIE1E̫G 8ArB2d@$N*5`Łr-Fj( ?2H=n$ "CS%eǽח?@c4`K-jAHfglNfKs`\J8df@C K'w~,'qeb-2r?G`ad`/<3y~-{/9C/ÂlXѪ f÷Ӧ{=r ksq `Oa/(0@w3@ MľP=ݬR paoJ61JqQ""n((1zm`ML@]N?HUiWE"{oi6ɩ_EhPƩ WETR "/?p `J6J#œ!ҍ4'*!H{'CA93Xj';T 6ͨY;X8طZVN~ ;iњ'mb ܒuJA+D)`6PxSehul1 ?D`>MÎ~|dDo*s.ko{αW$ܓfQNDz7nHE-)Reh6& ``%zrˀߙQIJ9zK?K SfBP%z̚*}g1Qcfk->|c(D0(Ϻ0 2d%EEtA6qqs Pf aHI~- #$zgzC,:`aM;uPÎa<3vf^1Xǎ;R^yÐ0ψt37H6 &3 nxo{,wZMChH(M>)&rp`/ЗX W7_y!9&@r4 o[=-~O_m/ mOo$kqm9:Y1HZ{R}Hxf )g41!e|:ݼ&~ I3md^&jH\k-oO4S$=27'42#  P?$tUV| G{~>JLT+fm(a|yCLb>t/q뫿H5|1ֺVYvzwhRSWRk2`C#Q~!@:GW<(hY jUy*2"Z^Dnoiهi6nÖ|/|NpF͔spk3Ox9̌mFI`6@B&`n!e?=?>JzS94n`f 6/upyZfu68:qhTyeL/[OuXX={WcL ^"j-{?ys2EOziHe&cHq 6B(Dc¢Oᇤ"'N=Ci!a30`>3=HKG,7خ)CP%}V"$&1 3D5:'ٺ%޽?AeL|rzFOy$M8MsJNJggt%AN@ uq}~0G?JNC5eUJH fEO~‡x?_n[тnn͒n%/A"}O?>b?q׳I`aE\cY0G4o8"g P#ڞKU- `E [։p.g Mz3d2&WȄ'"DFgqߴq:p^܃568}7J싗=>}&T~+#|g?~x\i2Q5u;θ-s@Y|Yϊ5'_ϐ 6L&K sHDQX2\>rA}1; !UO\Uņ-2b()e{=xMq*R+ߘRA#Ɛ}ەo][k+ܠp! Yh(=29J='.N/[dVڣ} ~mr^۪>p8BG1<%k a$f2#C3(^ ;Ԙ2 M=cσdxsYl{ip G~0?`-!KFyĻ_.J5:iakr x|h]Z=v=ׇi@z(&?GDCϧ #hs%PfaL*?هy 1(S8qF)~-L]G}l =O,$KfhOQw35P'Hf)K=9[*ݪCtˈïײ$O|/%{L:BKrlʨe*sHQBLޘ+{믿mEQbj̮ĝO<W 壣m3IGU!}DKߋϥ.%0(f0<5Kx[9#5mMy)չ˯s`ui  h7Hٞ_7k6D\3y}cdp}ɖ=(p*Oٺ-KlV?u{{6DL.+%3NeȜVԳxa1@a>_n4a>W{2Ciet3d2.eXRFvREkSGHzZ sB7#FDLrq\@>oИ=_-&Z~qe)XMc/9^4dL8H鴖/~ f7ɭ.{k9"|~knuBFR=4(Ue_߿?}iw?\1|9a9=A_ǿ\қRJɁO7t }:f)}JCQkДb&3ew)UO efq׶$shn˺9!م1 xWzKOx?qH|7*j>wpݰp/:匸>mخ09l2E<}߬ܗӏfiVw?]n?p+bPq`= C6D t QGy?*qj7( )d枛5"U~`EZZ1Nm> ^(D"Gkdϵ8}H2G#]KqDݧ}3H$??ޞ{}wrIm]_SjjVCь4RҖ^lrY&wPmnl8I.5+ڶ!sC^2LY\Kar{KUܔTI܀ȁdf\`u)t{g">+EٗTa\O[ MusDwo+M{y? "N)UDF,_}O{\?Vg뙽(IAHPPZ@Y>/_](_n?jTs3G\N4=] ǻ/jU/w^y{/nGt9}w;?No0 ӼGHV #~~; jְAx;Kƞ11I,Bz'M eOp8dEA J2:?0NOCeY`IU2zc3hwO[ kć~bZz{nO!#ne]eڲhq}R9v2ѿn`f+D28}h[NF!ftdL Ry>DKu\2 z:"bBN/)d0i"}ARo"-x=?=ط̝Ls; 8}cO[{ulޟ/*s8fŠHzGv^5\wc?i/6H69 G! >$ HUl=m_(ŕj>`[loKȊ@+4bL\GY@MepӅ04D=1VA91+ᥙ7+{1eM,6/j [={gvQʷ/P1$_ǿ]nh@\>Z:c*7N(NQAz46~!s[AE L4h=I'gFt}Mvˢ43b4 ZP2!JF$4F3QJqd\ŹL2@E* Z®p۞BnBq2J]Z[To>>?u`-A%Ow\N _r31_E^W4 _i0hk-E n!ׯN_V}^2ŖtVh2`07'qo<Џ1:2UA;e*zD%nj>],;&ћC"%ܢjoFm*d6 b9OqCeJmqjJNL 0J^2DI<|ӵϾ֒Vӛ?] ڲd(ǧsAX^ pe *#l>*ce9t|<6O;!86R@Erh{3M5ͫǒ[aA36_`י׫N9yw'ԟ#]˰QBLJt뎶|qDe)Wo~h]B^o`9xXhӻg,SC[,2vxi4yP1ۓuc ӗt0{A ychuGIM1"$pXZ J"`4}$P)#y>߭+G QHHCex˷m{o:[.}FK3q?Q"@[ p'WkMovj<$$RBLF;ø$^:rzIe+"s^R^}( u@qS"߀wdao<fj0 >SwoEHc^%"K-&†A)Ne/M6)oO%^&iTi{b}۠}je]|GZ̢l9Yfa'}!М=g _onv/4ă9h.>u8'JM !>ymϑ]r}8SwDp{M~ݛKLG9TCђW![X cӟV0rJ2uYy/PY/[2bV "ݖo/=!ᨬ:2|-l f"24 D,e9iSIeF-n#,Z'֯TJimgi }wb5֭ۯ.GE`yI/ņ2sng&[u6k{'G‰a+f3hZm71G("z5Ruf3$B98-ڤfPJokҧ&]&.3LiJJ}k(=.CR2 FLh P2[&w_գm1mQ,;Rx|V[ :T?dgȁl1^ ZSIF-Ջ k,\wS$ mŠe/p>Z,X~xA; eOTmLLvCz(3֑|1GB6qdӚ6(uЋ e5AɰEo/Eݞ"%zA rtX/Ex)e6+F?Zr3JuURy8 އ]z8ũpս.eݾpt֒Nu&s='uI T|19lN6 0cJ]j_ ݮO,lC SrDg@J‹8[BLЪl}{|Oo勗٘fԆ`c=a5U?n-~/)lSkb.Q<_Y)fݞ=#p_.KKA$޺Ѯg|fҬiK;ޥ4fF.wSiyیϐZ<~U )c,B8iDDuu??*93L Kd5Sޗ&oѮĢ=oZVZ܂HPe5sj{-DV쟜q)CN=ƨE;OX9:Ύ,^TM9D,l3޶聣@ɲrFssAi`uA@i\Z\Qv" IDATAv)JQ>m”/s<x{|]%q wBwrf/ "ՠ(,բ#%;-yi]F][fF9١*  $ kFJM_2ioG+&KK ߙ88fH,gq\g!TH"92zC{ŭ'xe殡Э{o-.6}/+!{uHBs/~8(3|uItg˲!Pcr祋=7yH},JuU"!moz1k  z9"$hq@m6g0k#V6':CSݭ˫^x̒DFC)5n[_ee%)Bb\b/+#8p>fY ejDf_4Fx\|1uP7)62BuEgqdˤ_;Ƞ9ǎblj_~}w԰5]ۛ|ISǤDYbxoV^ltVl-vmׇv# rŗӗU*kϺ-1Ҵ]z5sL1 doeNe!))T Cʼh_GLP1t% Ճr`B!I\pN\#U=z52Ffe0҉ +oۉ\홖*()3Lbʐ"z,mbٲ2ek߮)@ `HYY>6_ }nt%-(u jZXqS @uu0ͲPZd+`lY {O$GXI, 0؍zq\VO2SVg%T[-15B꽔zw{x8Qp W'zw Д3#M%5j%<߿O/͞tԻuCo=if>TKe)"Z:HL R#^V2])}aFC{F5|Dc1mB–^KǺ.v% wO<ѧuπ&=kI)%@FR/x [ζÊ(~z d -bGfnR@fϞr8DMk "4 ~ ju>.zV/LJjU{.{uuI\r l&w'fcbb&T~Y#a)[vv;m}{.0j1CϾk]-yaʋ[OZR)N4<^e'!i`]fwzD-e= T|LZv)ɽC-Oa?d)roNmgE\?TNau=MDŽI I`)L]=P<[Ƿ߽}OXв]$7H-G8L0sc-re 'On Al@N&hDf=y@"CeE 7x]Η-39?2vۨiN.Cը-h%FL:SD9(7Mղ' ]]7 /]xQcKƳkRdP$ܻw_꿻q{/%Xo\{[mDB=/YV̬*&wWhhcGC\N>$(`Sv2 0aV^YM[C=Yy~h,SR_ e$@r]R%AE"Yܗi7Ca~Dn??\o{;ãޝz"+ X`\3eK+fVY&|'xw?ٿ?=^|YMorkv7mfW ׈qH k-YOXs3w $ 9"'Q` `V֧﷧ǭu{q&Wk9gvLxY^/H"V}_o~ۭTmomo׿nD[V2,s+U[n,?^2S2Mo "^ !p0ұ9)cx `3&ubyRV/-,Kg ]X^#i^+ۘhè z߷tr(1r?^? <3lkr~T$dvfj. M"aOO~77w֒v囿 9`F*rӮͽe!j!bǜ쇥 85O ̀!c19Dnpq/b-#VA[ue5i-޳@+f!_JG17e0R>xLA_ߞ3>.t4"{jU,RFg3; x9m-t 8d-n)H!o{rw~>P,KH+L[!*uYf F "jI c?bN$:=͙hHGBp/ Bn]=3)uQ,Ƹ*KtΐT%ﭛJ@|xQfux|T%r:smihn+EfeֺIZa)0.bA7w]o;M}|͟:}yYXۦش\0˺岨m7U{a1htaC%i86Y Zrx,9L(eB[M2@zw|@KcZ5k8Vr_K–%K^l{|vLMLJzy2 ,,w//YnaܞN;F ;ܛa\7?9125+_s[G}O_TlO=uo凤 d΁ݽ EA3kH'=B(dBvмx'3 ފiٯۺTG}hB.s!Z3zfI+=;̼^]@pFFhJFZh#3jL4]u_~ΧGztK(*ʛ~hg "jtz`2SHBvC tEіsKuPj"#9Pd1Ls2Ev?2m̈́8lݒIUUgtk]a$w&ev.Ҷ|tq~U\hCwi]AQbcՍIlJ"K1SapuImCd08F$Lm֡eH'3UE hzۧLC9׊$=%b}ѾFFdnbm|]e;t9qESK^.O>S\ ׉j<[O3|YZ*cH'_v_$I޴lբtb#ۥ 5FvVL ɤ8uS#G( eK#ػM TYPCLQ4nyDÎ~\/+F66i|Nc vF-3#G<l-[<jZz 29W;o̵5;mm*\%7)r^aZf0#z>1ǩQ\e[^,)#ók:/]d)h1PL>3Fܟy5܋vpnOE]cxﵺhI1,b $rw$Vrj=IH1%ЯϝT=bǧ&^%?9O_֠ĺ!t)%[G\MMǥIuy2P5{:qUp]K^R\bX˩uF%XޭnT+̋!,a2u$ܞJF H-ƮϘ _ KD\z,=ֹ-QL16I{|QL @i,J/%Qt[R=[\jtP-}7-ek"Pҹ/s{P RkQ OuN|n=)*VdN%S@TȱXjAR\Gu"[;uv"#Rz8$]THەu[0/2t"{D'kNu @^.y*HJo]D_E> .$d’ .be("UzZoA9y:aTCb_ag&$RzόunZ7s֐{|ŶvY*0"SR$rZ- P} tz9&:%vHG "Efsѵ&R_qȥ)D)^U9)coFxĘ T _vTbVj2+Pۖu[k>Q:j^-F{n暜 !b8dTQ^o+N>C} `T IE=W,UɈ] /` \dsA%a9nBd;7U!ܕ;1]'QT`H؄Q9@*ZO@9%}!ԪXds"<_]^X Ӱ8MUN4(5×]L -Ҵ{َ=GV׏x{P"fH# ^MQ_W쎞$$Ll/eZAZSs5F$A<Ra悡(b Hv23:zM]JjR)k g] 0J !NLzlIϒ5uYsQ7o%%hzXRxp̠ivY_q`5p8+=}SR.痆w?  M0 cu>z}`=MvE,8`3¶4*ȋ*Vp$`j@CI=E%5ցdQS24:e0w :wgVY-]"s1ݏ!EҲLoӋ8RWE{="ڭ˯昱5=nKySԶUCQtm{_~$s li A\k(9"H)bL̈́x& s%Պ+k%2gԄNvkͦUETTr-撩hnzEBbd?XD4UEBA詶>`쵚^ÏH^pFiK?I O5 % Ӕ\G^ڿg}gv4ꮯ]^="Tuh.tyf{]*BQs Vf`zB|N;Ktm$궷w;nnipC N^:=L̪ "\5+q-#3hUu[wj8Uf&fo_}f{ nۦuq* 6mu @B5+uRl9[ ї/}͎P\+]I5pCCK)Wr(: #MB gmTu1QeiJĘr&u:f5|536܃L^Gc?sLR۬z 2.A&aFLE:MeTǴN]j KPm49Te:"\LD t&ȯ.\/;y?b)kz-qu} NTuź@fͼzd2QVUdb&"jeꁄŽ&&2sGO2ZPGJE>>~y Q{JD)E;r*H2U }fHD$#i Fʲ"2BDěXPVUѳǥ1$'}OrIR3 zRsuFBPP\!~QT hy=*j>*c:;̷.oP6R.dBIQ eN!R]@{"#5t9_~Vډ݋"INtat'_PKE2@dBA@1`cv1kѶ)">&Р?1fO?yeyRuCfhIC'|\!^Z2A2z!LFf`,$U 9|j+ᢗ`$hPU~p sf3}ph ='Y绿IOSN[3Y`^6AdH7ԅSq/>[/~ڲSIqjԥe"&kq2Rm+\'L^Me7mRvJp$ĉ]ndp$I5D.aa=EĚVΗI5n&}E)е!CL{=76z:dl~Z(և)Zm,_zvK1 *Aۺ2YG:yIbA@xiKʲ&4HRDZWwlU9|jDfo-R]Nig*qߪqPGA:$ܸ_ezkHSIMڣo-i9!]obJ!"#h͟!?UYjf.o~&kR4>$׎RoUV4m)zq@G$*.!.ͣ#9l:y^=ߗ J!H!agcCIk /lؖcWI t= D;1R=lgeS2"&&j܇hphZeY:EMfOplq%Ą1[rsnj4Ķ@94ZHUb2}/%^71cUSy=ۀ!=ȧAIf73wI } < OL-= %~ynfj~7G9"!I h*2\JQDòY*d,f +j=}bb۬* nMq% =ӌDՁ%?+ML(xhI)ӋW7]դ?OnpE='oFHsRHȠ#2sLQlOQXTe͛xe-2}#Ub@SK^a^|708ѣjiD>^2x9[2vGR><' *̓YwP@E $Ql>iK7/e`V4#~ |7pp+JIn4:1I$A+ٿ{]CpY4TpgU喪ٓŧɥRgD4*ۥQA{3CKt[¤E 2p\brbݱEd5v2 NA"R4fR[`ǿӫx i1oDaM{PRD2" EUL{ܼ|XDgӾowhvq!WOoT:Jt%i**uss&:ûTiPb%n$.ES:˴^#i!HHlRe_1i4D5[W'TC'NDSߞngm될Rn.@ZMثʦ_Uom P&1S>Oا55`?zB@8.OҶsF"&"~3wV#y#~V0grH>o}u0%@rfŕԹJ2X"L"vB(ʞP[']C2!Kq욋]SU|=g?|s= PQU rqS lpeڞڣJc.; w==0™]{$25~x4:ryW|p H7{o*%3eSH3gZ½3c7^'W5d٢p`?c\toȷ%F!=;1~{*.RX~Wmz\)߸dO"LX}R3+^Y&? { 9qFJuћF~wOԥ֖&x&?/?__ehuWEB *IwU }sQǡ8{>,+:ݙBzc'"-5Z"Z{ފIFL>6AM\;>~O> #> 8?ډ 3fQ(ƶxZ1UAv^ ؅)Y\c.;Mbfao ef^}t E5bULMTVJJKٙ.PqQoeB /R.?JflýQ|%w0] ϫSRӄ]s3K -)*ˣ/ߋNd) 59L53ӝFE_z4gR!jn"d$-S 2{Ps!3^;+6ɄEթZc%u-MI3(|57?>PMr`Ϧ,Z&KQvƩovmT!͋ IKfF~<A\-.`.-K7|/<=j5STdSfbBb۶6qj>|0fhleՊ^TU'}{yP`rV]ri_txEJVBdhB嚜]+'cŏ82yN=no|J Y"ۺl_0SSuc%%cRjR]*fʩl^M,)Qq{45DMQ)IFE#5&nN'ڜJk/r8xr2vYPsq8oj/ UTK*Tz`<ݼE3Ë_yCe_a "!殣vO]L[}> X>z-Op:ږۛãJf/&m kW}?*֭NF/32&,s.g/w吭a$rErZq=CDTu2>Frb>!hd nVn/o_lem%CUmuW(>?K--c[+rM0nF355azL[ye.Aa;>I'Hd79^8 ii ;^Y"b󡨏 \r).jݡJ n[VӦ9rD|Ϧ*)jvWwS3 c EMDi!`.!KWe:hLeÄ ͩ.UYMq<+ҙBQj:xUraҵ<^F+KNf0m^G[7fOhRd4ݞj~z2"L^&_l^ܞfo)ʶ EjwrȀkkLm>yaeoab/vaJQsZe$'׉$/.-6pe+HբYk51s :^n'R-3%#k<] 8 #]B]8(:`Q-ɞZ2!U|ӪhS2sE+fs0)b{t@LGkRYg{͈q''ow?/S)л&&lTd<9mvX0_~x胋%0UT1r=tM@0tG1W̄tS%]FIڻ PDU&[̡”DQuq͌Eo3zU*g doY~JA㎌E *[Է !z#GuuA23Dra\J?a Ù&`ݐxY߭> vrZ7u'qO[y@ e`#R39mm+[a&&@^\rRF,M %Mw>`+Bݹ3m2,k{xM7'4yr@c/> %75̠V&*8?#RA2X?5fœ҃T`A9L)txL)B-Rsvp=Hj~rMצ, {" UBilv0pCdHYλ&02q;ͅ[J m#ntE|&Ř;GF 1\R/f4-asv?S"aH+pɼ&uJ4G̖ IWC%!X"K З謉a2p%:; nC⮌C2ɄXu(l RYJ+V*W:NA-ŜȀ3 15Φj_-&ԫJ];?Uxѭ\k;iÓS"PIV&d" 5eY 1IENDB`nip2-8.7.1/share/nip2/data/examples/clone/example_im_02.png0000644000175000017500000024464013351443023020260 00000000000000PNG  IHDR IDATxێ$I%vGDfV_?ivwUeEშ{DFfW @*#u_ǿ:{W>u8@Sf<ܖ7VQQ.I@\3 I~vc혿X߷ylPq7%&I$sO|^ [NN.1mP?~[R is>kQYn xܷo<;L`"gM!CS4ߟnVFck;.^&Ar{i5|%y1b}dAb]8oOj)Cy~7Hax}y Xݔu8x~>}Ecd]z=vL)5FӌΓ$2̍ĶOH aV]L+)Sfėby.ay+ 23>xW{hv$g,v@1u-0$K.rG*H2mbgHJ@3&i%o;r_vKn4dD^%)AyMƗVK݋愮uqH`E( ()5'xHe>)E$i#3LbcHR-El+r*7x#I8ڠJu3afnF 97HI.B[wOM*O$ޛ1ӓ`a@J IօJRBC$\3-r׾ $cT?"fm' dF4"Auͻ O q$ @)2YQSmOJZ/| '@Hww@!$ג]*Ybwp*ݼ. ЛDžL[i: u|(?\Ί! ܴ1]swd2{Nr,&\4u4Tҧ.1QrZs%PX"yǙgR[m5N CNr"7$Q)ܳaCgC,"m[f.hw#9+ϯUg!ޞ~!&XfcT Cy[&][;iv3ڈr-G;[֛2B+enUڢ]YZٔYtꧏjfJ@$DsNn:4ߊ~OdƉ|UZ4]A,,S 5KJIzq6Q譙eTwP+ng!efL0o M܇w(g]4bN_g"ӣ1% 22R_6[D%ILQLs@Íh"v":Tt&为5LČGGfsfkݭԓIIf-JI#@<2qEA"> hqdz*KQҲko]2 ;r2NV2x"YN )hnaDTҁ[L=!؜JEg^;5BpkUҰ ~ 4O Z&)fGVI֝].Y9ㆌ4gl9cwO W]Jb,{i& ]fH3tfd'ԑ9"aL F pT$e5![!د֪k'Vs3ˣwhԜ{H7SLQr&W$-oiQqY5Rl9Y=jF+\9Rn2r ߑs8OcTgȑəϧ'BF##әeFXDqp8UI[3抈#Sp"R󳶖Ô&0"[esUht(ec } ڹbieP[>O;XŜ =xX+ȲQYdI}e(3D&9XU$Ni9Ѳ3}ANJF:$Hx p+IyDfdY- Tv a[z pGbi4Hj^u@A*_Dcy${sT~VV8,n:Odh \z+#QiSEjD}; 8ӟo4fpWi$m2=Nhc-S:2I$RhO11̍U hD!BӈjZ3#+nN'Kvdξ6j5?;I fv&[U)=YRVaY2Ub .Wc=CySB*,aXL$W",4mdFɔΛ'EA!3@HiT0?"hT-oغBKZ'S^8*[:>4ҌDWۈ̙8Pk[=Z1{+QaoUGJFV j_I?N.1t]qa nÄN`(Q?Н3d;X&޻]'9S2oĐ1ƙaВ`[o}BhZGdlꑞ-% \5kTS5ȯ&DKLx zȵm7rՖwMේ:5?b%5 2Wȡ8L7rT*l%V MO<@\k5oVYSfUA5g魷2oϨ ++/pBJ.%Z;#c"4 gE" 0quwUB% ֕CHWedBQZ52Z X.}U2,)9m{JnEYmw硦(ze?iKAȘ\'К)j{aW (HNwA̹ikÁ ] ˆHhZƐn& *L`J8]M"IZU%Hk$6߮{ALȻmιӬ.TGj§#B 7܇?7t@ Zr&g!)GjN2Ebsz5+4rue=4 b߈x }v剘|u@90xӮ*(}p*aI!eڔBӳ ZruDw|"l)jkufٛʶҰ+klO}y\#;R,[RDֶTm nԌ4HfA6]`?ujYd+f"#";{[m#@,Zt{okUs6LJVٷMccx؃ c#Xd5#20!02h*mp5<3n)#pL KX[b ,3mZ-#4;!R mhVPUKJGOl.; Mַv#'eXg~F2B/26>_!Soa)z2/\<gE bcϚDTɸ\ܬ@Ce$7 ǮJQd0`K4H7aS[EEV|KJw`j%X**;F _w|ng# <cD Bx"*j45U S 5.Xİ ="+IO7(m`J`u HKX+Uد&!m;Z'^),@!ai,ʿz_rPM1Bcz`@yy7a+ Mqǵnyk^bθG/Mx׭]%k3KMm+vYQ G,Y+H6q~aLNU0܂7uGSra<FB1! HGY' Q%3mfe>F`wϯ/S8t};: }L5G 5d@H[VCԼ.>՘GE:DsFp37ffVx3'Fsg$C߿>j~_籏*.[}<, pToyU1VcY*;(S=Gd{t;cplkcJ~:4 3fGZpf}D^4cԪI!n'DȂj=監EIvoy׿ +Xyw5c*U]e v9-ZN4RE^3>9غ@vb\CXﱧ*\z5 .H Ju/5KQѲ U);M8PRc {w4 0,zׯN_^qh"T#'h޽ J6gԨ5Wy7~XOΉ[L˕24uƵ9rtG&[<'8$5./pC$ IDATV`KVn4ᵹRF1B jTZf!SV'9 ת\܍ C+܎CWR~f&eJyuvYb ƃbZ9bzM7DAV3&Mh5^)sv&/)"Ѡl3ʱ<S @XZicЪ)g/yῗS9i:{K*hd\C-3>2@dsY]G-@1xM;c2[rjF*j8#j̰qd*h C ?Ac`^JcX Sz9.LWxwHf eBs&'VJ"q%gl?bK{B)ai0Y*2tL5f${$xΦ;g.oYgwnOҊhw%'Lia>>fAW~?UѪg eOsR,jNHx HjrU>(_CaN+X=p )'c$ͬV9[dS<"{8iw?]/#O;.rZsRbnHqS2b?X:WSi@G2 (+•W>dOl[WB&8ek6^=:g{FuՆ]Ch!RAP@SMD/!ơF t23@n!FLs&o-?h_/Z6}߳[1HSz$`F[$G]h66YL% ar1rf$SAـ7\耻'1d>Pv*@!F kP 9`"Ԋh]S|HRRPfHkOc(06tw~# ,Sz?kpFhFi ʭfWGQd>cVF8Lfa2Id`N;ST@0"ECLxˈpPWUNMZ@W=,1ŒCXr6[Vd% P1fU0 ^Ǟ) BD9?6~:gkY3#!=Li9CכL"ߪRJKTkʏ* tG䬨BIX3ǨHbf!4lm񪀷( 5'M3E|ݔ gUqE.)06gV^EiNNwu&Q֞Mqv ZAk=.kkPk60f#6INƫc# !qN5])s mNS)|sdܚ[kMD0=X?uM)tYc+#*~V>="qBjdOEʎ=ph͙?{z˃ɿ6x\4s>[O`m/}_,( 0CaӰcX`2>T}W̯]r + YoFTI9do NضJ4&ht6+WV\3#Sپ9T*XQu~17um)r~93.s^ ղR[#5 q۷ sҌO\2:'%.dnȰdΙ4m̠Jv:1Esp(GaHvx>y,'m)k9͕WFk#SE(vi(edoo_(omm ckܖ.Tڶu|VY+}2Ĩ8o3#d"5 f)#h/LO('v9 X9㷝4!AwoO+1FJ x}\wV'̀ $C769G9m{Љ1(Y20@g5? Rg}&ƶ=.ak~ ztZۖi ~d$quo7S_f+! *= ,+!6 )b[_(#y x 47be#@$(ưA:Qo T$:Q+؎|ri{|QM `V X*P';K薗Wez뭹,udSTsnV ݵ+uR1Ѳ`R77*t$d>I+C5LU1oeXc0f9d#zv?26݈F!#vdn!$:òq\w e;Ww(}T8^j-9ZC\ij"$W#mk%ײ)s̈v( Q]/R<g 5ҬMyfoќJeD*k69}l2BF7 z!񲓡vy$ڃF3n4/vz>_8Th;SLБPl4)~/ |Uc%bP$k4He?U5. ؙ2VYl;ukY3triQVisX5T0ބ̈rW22'$hQPQ;}t<`Y#$3݌']`ܮՋ~>IЯ%f^bf<]d$7,1W) :P ?$ϰ!{8ǽc74=1g{hBKT3v|'2:לmpZ 4V' #8gr -Cakm sCHFXVqG_U/ RӃU:*VƀB 3?žKԬ6OO+D?rRi9F֐+VW d8C‰f9Bc8 9ᡖ)؀t[8-sNx= 'em >为YpD̙"ʵ 쟿<|=Օ)3ky#fFm"3_~$ f)O iM>CioT8;6X[/@z{qzs$$2e0j'=}1Lo1AzҖ!FI,,hޚ3{%_263y 2"tٮnU}?=oIbi7H&7f!Z^&/J#z Qחׁr_g76Nki:S!Q ٙ ^#0 S5.S4Όj %5H:kE)12`6%PoJ~~:Ÿ?sE{|:}ҷͭ&E"1ϻv㊙ز<lVRtI/<ڪ#b'XdD\/X?F ^&N\ <1όx|xr ݅N`uXuo>6St<ԛ1$ܳ5#mkگ|;pwwrFBFaG7!ׯ8?ӧn/'i_~v??>=l{5[CU7]vk)\7,É90韨yJTV蠹)M~yyӃ+tGo]IzFo}d&,b?HNz6ewz3=lz|2=2T,e* u W-)c>3&3%}HfB˓ $+gikg ҜONsw-_=R>FpHj{-9j^s7,WdxrԻ f "Fv1-cQ"c.7 pN4 7҆'ޟU0M'3ⶍǿ|<{%1)G>s'=-/mYΛ5'!I??4$ia$eb3ћܛ*htɚTg˟>||\ҞI㹪g0vbd}A^VЖS#^7n9lu4%RbPqӠP꧒{1?=]ڞBy[[* Pe34Z~js`X/kdNwoVC}c}R/SЬJfNK3W>3JN͟2ftY5mu_v^ŕ8U%Hk;òS>FwIAéQm9H+M'S |b͗%Ծ|V ?IQak_üHVe؝2. 2:ЌlkN]RPt72C*Z>096) Vtg<2tЗu]|au]ϙ[^Ս PǂaaO||0,2oi%`nfΧɖ n6qzf<3a5@\ )l2_]F{QYx2!u3S^-t& "GKip= ̄5d܇{VÇg7ssOwk^צP9HӔ9z vv8S$[=?ݶmNHkr纞_b[9 IAU/[OuǞC+vE=~lj3[NW餒5YL0L$R4 ~^>!)+ , ErvdCbk2){6軇}J7 Pi԰}콴rd}׳ n2[˵'ׅXlJL:XotȴLrkzcYFc:˾Nsy2fȣ=ARn!kiPf*xE=>߮"9U`SbubGkQ`j?ISmb07)ur{uzwgI=oxߝ}z hˉ+7Xo[G?kKqIiKC+mx-[\f1GAhф@n_+.xٹpCvD\  $JD!̔!,&+QNw2pG1zo!#D2HY .ݽB/:o\pߙÍce-5F倹30LM!2EjXs6 ҞWO|wrݨLR#2 a?4>^FDcvn=fKf4u{ٓD軯ޔ1 U_N?r<ې1=oc87dLRLS{RM>/>7Tzː8]ӝ|Wk y}o/H4R#-\nLW.fSl:3IvRQ+=e:}=z >#l -h1Cܞ[vz[=C} OQEf^_I~Ҙ} CnX"]WhKT]ApWe<6 S"b4:"`RvIo5&YORKfnsk1(Dr6D۔l-;dfS&*@ZgF5Y(vaCؐڰDcyc-lAúoKxr08Q1p̖Ӛ:Q|1y79@w"^b#s%,3J-nWVn"Z[@9n  of+uAS 1@"G&D_?}XU[P EBBfD$W` v{BhT[fC̨K_c j?u@ٷ-`etoc4dرإ'L#23`;OBu<ȶ۩]G\p]jd^(RICfnVrܗ[o8+𛶯n;Ǵ4SXы\<:WW\& ('XO[m}&bX5$4Zu8e(?"+)4mï}YJ~񏋡oW >2#ztnQXMl;6L6ũϗBLJب1IRPGyGo\YPeuh׵zHIx9Z<U*c9OEXȼq6n/W3@I)zHD߶c|mul9eEr%#ɳʾ0G,)%`V2n(-1HD5:_}i+ڬmzBFh(uBS'1q泤8LP;>c ,Z訣BGe*,NY!ҞvqS}V|5k0,ϲ`+y][u9)wM*K>h0CFRKq$Z2}o9k`fa{V8u_sՖ<T&S|1 4ja^a"=˧4[N0+S0:S^77/cQj$Bs#5?g$8OM7fzB[jVmVm{LqhHNZ5G6$콧2&c.A# pތN eɼ1M+ڜ/ &2K<ޥ~[ %$^3b*2|*{M6)Nm߱XvYڳ"aMpq}nStX srn[/ }P%i~1N7GL)v5;fW!!Eh'Cc ]y%k1۞H&u\XBUd^P _B x$[85_A7_B.Ydf :]˗k:$5Hv7=jQ4cT(\ bx,WKI:O?fdܷd*z3sR)olg}|#:^{tdQ l;,j9Ow'(C[n)bRFUmP؎DR@9>WtKï/qpXBOiK'C }H"Gɹ4=O`;LFLFMryfBBZ_ ˓"Qc KLg{4FGҧ05or=s.;?_$Pbǔ/,QP&Bl4B;y,`؇gpyzl+[f47kKGV ?ŇGrPL]0$z+;јQٴ~oKSFѷS&-ŕlه#0y2ܿ<dl=gVhy73j/K7PPʡQ^NMYyz 9c]%yN2+EiMۂH:- x^ҼJ&ŗ'upB[z-Ċ:L}='e%ch?p/LZnӧ 3B\.mv qYi чD'Nפz=6c뙲~Duw6o DjȜZmw'ӄ s"% _lyxu;29/_Fz3a5R~x09|7'@oo QVgԐ[ʴsMOgq+n2o>{{A1:ɌLtMn#̬WC:jn:_趏E=0n薩g)s܈zSJ#ҲfxoJxᮩ;w9bOѯ[H;.|;^+''j -b~HG苜^+'.f[C_qHF ";1Rڑ6= k\& Ҽ_;b#䧑oJRi\ыT8N}Ř#^ՀEs?ߺf OO@ i֜(OYfx1\lQns3c~3qI4y濹* )u Nds* &i+YmNurM?dњbo "jPsN6}]2s]>PF_i03F}pZ's?ڝu\W{S@Ue #{ 'l/yN1m+Y`c5\o& / lt(4X|`%/Crú8F*2l_03Tﻮ$њSt[lA>lm-{nI.;WT[= O㹍",GӪةMڌ !$ryJ|{:+ogӌ+;w/rR U#Ti4[1yw-3U|a}Lخ{NvViYk£ie_Td tk$?~y=:ϊoR6̒Ǻ?3t^zJ}%TuvZ*d0+T^nR,iAugu ~{!~p?]j4T}y|ͱoݟ"h_jn-%2t7pY4Ѹ˫_LؕyhSvJޙ'bEg[oNI;%x~Tny~Œ,HQv%R*!dZ bxPt~mt~ޏ#^@*s}C[QW^fVhi r秿<=" HGGٱn儗$.Pr;/dc߀ 7]Tn.a2K%tDg`kQi,`;0kci?{?@?#??hg 3&~dE6݊oo.Im xZui@5rg;J% bQ:>b)lwֽ>ο+ٔ0駇^XF,:MБh-LUw{7Kᵬػ7 -:W~3xz.pU3Ѓe}YߖVȻ( yHEr2\ct>OM[>[Z{V]#8R 09`'hH -S?wv |Gei;Ŝ)}w{Hy@$͔&{f#3t8Ց:l6YgD"sЌS1lˏ?fuY+X`fme`C3r"F]3e "mcjDD7(ǜ圇@Eo_1o[r#5+=XtaJ 3_){ e匔t1ÚL~U{4֎S0xyj6ZڞOܽiNP0?%~{3wyhи B$96ysgJw>VLuxxk6lj,Tڂ-淾2O2*2Ɣ̑]`d$xhK.Cqs-'9BL` ZGDfeR fta)mzߟ|qy% ԏLe)T5!z2h6o\Rf%a,d\Vߜ+#c"lӼqﯱ9t1[dcxcR te)"ݰ,$m 钪W3Eiȏ0P )]2ȱ/ͻ5Z7/{N{ @x!R:N`~XTd0\cyۑ;&Q?}StwCCE; _V^_H>d҂263KtdhpAiVq&\%-Ì}3_rt[8=8sqU@*>l''T{闲jkiMfub_"͚wXl,c&Q6vZ`57 X,]K~"~W3F`ZC ˺֥${ՃX> U#be!b"Jx5ߣ74e9k%StO-ߎMcwDsdVgfͫNT^j>g`jcM򭋓Ƴj9x^]iS{!b}G(GD炶Zn{j-%qZk;dE36fA#ȰuTs7+Dq ` @L4?&4YLVR@U0װo]op*FճkJ_M1#J9q\v9Q_vx4O!C6Ē)DwÌq׫Au6*M9f}<QyրÖHa~bt60f MA<"׺۟^L1T|~~x|MPYb'o_eݫ՛?EP 3C{\f1jnNW/6#`늑RFB5sx("4VSӉ#z3B"r`}I] }6Zsf>4nʥ~dkh_nyrZUg`벮죶ά<'r0keK 4\=z"{pV(霨~C{| p^ R ,M!v` ΛYx,[kNnm]s˗ӏ}ҘCNШKRgz );aKt ?ph/t(/i۾f ;۲fcˈM?w5߷]e.Az[$@_:N}T,JfUO^/v35Bg-'rd"#+Qj4|pOn/ρ1~姏 GbWagH^@9ܷoǓ,@mbr 8i$ +&k$;:3NWWJKNehL/߳GA/z[y{[ k;L|_~xrr'|9ʚNOUH@\ m=/2-mqaƬaiѷlff>} $Z!=C3`׈d򟳙ޓ%Ɣp@Lτ΢*ҧu*5H}ެlma1_>7k^#k auZ ɖ,$h2dD u컉Y:P:8#P|ÍYH42Pkߑ:ɮvMpiKJoy{X7g֖ō}v7N-1'(N$lp7$E4Ͽdzoط5S5})%,BqY!mh9/J}s|9t(#~^Z*# +(:3_-ZpN|[Mdyg-x|BeYLdpyefoگ~Yf=)k"ooOiY0}l=]cU^@Z'$47# >W\۹3.|@r?#,]}d{6!cMB:뜒-Bqv^ N\Q'Z|\m4\>|tlO3qv :1F,iy9oy #pp|>>>bg[S \kӬ焍Sw ()((w֥bVCylZxh֮WKMgaBB >l\uyնq臷p,Uo%F_=iupM>;}/LNQckS<":^e{||8Q ofKSO[ZE`)I%*P}&ؘH'6g0fGYkDv촯LOwgϞ6[1,&ݝofڇk::IQj|53uܹզL! wօj-іR$R} > Vr`ٻ^EKç}O4@ nK,Gr{dVU>p?`/(KY.; p[UeFydfuwY.Rs355x[l:4kf#qwGĖ9Fn>=r ?x*uF\\t|gZAI'vN*ܷƐtO`c_F_LgNWc7_ޤi^|<㧤-{P3Tr,tƄTD 6kK6H4Ԗth.!?}|51@'!jLc$ƌ&cL\ܼy9Q/t +d5 l}2V ѭ-7JYkպ 鼆fH9|6wwg.JmlV-X- n[4p2oQI Ğs}&Mil%2rj>ȍ 3|n/T)9a"#%IfdSѻ`"ְs֪mVcۚ# <t C = pkY i Dlx))lДoq-.S0m~&5FLo5n A(9%-im!-c/@Ks (0fS#oHoxe1q}HE23ڊ\<"|e9n`laR}(C1XbgD绿ӹ3qS;P}7$")!\6>Mt[;ݸ]ua#oCTv_if#1 PuNӚF܌ضI S'rNؼ/bΩrAb`L6'6&M;eF$"eMڝʑu b[G -%dq ,m-"Ѫ7D4™o`b4Fk),Yi_pjĝ/"|p|K3"/ߓ3y&[\rL;0GZN6aЩ! qyqWm̘c #Mcvh>?-d/ J l8pING/7D*1y;aY @$Om!DMYlm{>Hy,wĞ< Lke};vH6W܌VfۇrWφZ_8_^DE] zf7h}4C ~]DuB'YZonf loۛW!uXZd-Wxk 6\n ٥S:>U)HחV'9{>6{,)Siw~?؇ (ɰ.[i^k 2h3$Jxp3`WAՖfF&eK0OQaΘl rzcy5O=57IBJ ƩO{v(>rrmH%R-˛o4M~L4cl@sfw@b)!I7!Sjv#??3ֿ=*_mt:7ևGl~JbFE{mHbp%/>HL Sn/O]=D5#0]e PQZ$Ծ9I0\fӧu4\9ILŲ+}:۝ J$q+Ƥ/`(JOb]՛ͻ"ß'Z|z|\bց*0iEn3Mca"Wf;ɁN^W=a)?NV)H*"Akwr<@3Oou w0bmSnrrL*V[i"0jFo KI45Su* 73}q{bٻ9r=O}-$48fLT= !J ]4|yck~ͿW;xדNZg[o`fcFUԲTb&ad_5uY{[֋_֛C͝Raa" iUB`4p;ƞǖ0wcKLj! u.{{*wov,!n׳.ZÇlvs#i{li/ԵʓNei/6N'#4]h31 4VF5.5#&DDcpOPݝDN ̺[fV"u.V@wS|NeffF`l&C0;_ayfV'm5 c[@?g@1Q㜰ܕh2/QМԯI?pҗcNJnae%ЄWFFKB NJ>~%>3&1v3RV]L@Aܵ*>ʋSI'!*ceb^BJuGAȏO-ٖa7o=fvN@=fl'kyf›;kӉC*G>;+ѻk}f:4Uuf4wCȭa,~<3L\ew>&8Y|]жёhSD3uofCۧGAPSc1+ /֙D@34@-1ܘ6!Vy5O.ru$LȦ}*x2FB^pB2ArLq]uq$ܿz>/oszV$@[Z6IN:q}*ϭ4tSqIm94C80R<5*x8TgU⒤P$leȜ-`8?j<&kJK=?ǰ8eB9 sDRhKw"Kie3$n|[WM ׾`zT&2Bh"X6M,ՈɚyVz{sI.",lt ݠ(oB]؇bD(XjUe}&D֋jrmN+5V{:P5aHctikx3ؓŸ곿ݔ \6ܹMu^smU39˻ߣkr-i'f Unf+o#ÏaZV8INu/F*g4Ru3aV|"^3tddN^amlŢʹ~PR`% ١o]ln"Ӳk{oh `n޼WaV@df xo7y|(ʲPpcmo05Y/׹9"^wuޜLIi/؞<ѿ+^w̚C;Xrc2aՎ0#2g\e(v򊤱%*AwL;$n%֪$D\`1 奇̂wk8, ;!c%ymdAPEpBMpZ4C re_vxf햯<̡$8<}ja$$vqT(eQBM쭈ؽ%1mcZY ר+ƾl㠙IVi0mV d4~ IDATr-Ǿp%TvN{XB 70PQr\KWA4Yl#5ڙ$,x9oSj?L(.-h.Fye(RludZԝ-莋l[G;,Pu(ؓ[-$A!~kqxfrfY(&de05x'/'U%bp{m1 j܋)qxBUz`?Cg>n/%=xiζ$T(&eF4A][ B9"ܸjΐ{ I.\@Y[ϳx]4'w]bѬ 7e7QW3ruK~I kSx}:jZ$5;;fw[m땫&᪒^Yh^H/.;:|+9F#a:PŃ ^Ic| 8&x?ۇ~t1fL4ATЁ {)JŤyӯmFҼG7zD #G» (:@fLJr;|-ft= 'DkR}ʠP  MҴjv3mqo˲4om44L j;o?XK2D\|y ARNvkr1h%;ڃݽ779%:ǚ21O\tp8$ J㡽y >M~n=1h~\fcȾ15*ќ9.x^}OcnŦRX}L3h訝fDҸx^:$x.)_D.?(ʾK!ubW_ǝUg07% ~<~{Do˾~}N܇.UDbvw[dN*/ь ꖣ]O{x߷lչo(A-kyinS_l ct#PsAD+RcHoFXkU_A c ;[ꂩ\/ 䧬ôkl}icN-x<rj/X܍ܳv5!EijAb%7 CH&mק7vMxx&w7b&O4UֳG/J(y>VR9Hnf郎@Zc$m #m<e4 摉֔m=i{mKuCi<;lZJ90t(/na[l,l&`[G޻MtVf2&^[rww)uXCnLE$6 ~A^[\28Xpva q E3 fswKrLK&Z` iWu吗#UV^9;')i^ASDߡDJmQ&5n~9L)QTTC\7s :z|[l#a7Sz'fؔa{*.?s-&]j3:Dp죷1Z[6[}@8  [Y[yM9[1bq|)nf=-_?%5I{耙l-4n?<{mv[KwcY4 r44)yof"kyΌ)aClc5 3q)%8G!#souwkT /C "^&c%vz^ZOx"اK5sdfwg߯L%r+t@Y:҉ 7 Jbp/\hrD"qc4]J|[WQ:fNk\9PpQ!x Hb\IAj];@U~ө{ۿ<7iZo,e+"R>3)۪[ eԢm<py@vOS8c-=y4&hݙaQ,-CZh|*Cqr??RUg1$c'YcYAGIf Yb%꥝QlTV+\2.wÙFLfͼ%TCʀ9eK}q‚/kr̈L蓜Nq9RvP{39q^~3̨"|Iix~ܐRDV$LRQP7ͱn1|֛sZe U MJdM ^!EsWuĎ9zl2S?b{A%cqI_?U.CnNyz̙8ܳ!Eڡm<ҍ,d:c[6B˫$e)z:c۹q2՝QgD&dB\4ZLw|w6exzydf!5 sOg\2'hC_|D7^+@f[ΧI€0qۚ/χ^;޴ q^{sNqiJֺ:{[9$;#pM:lj#%}U;Թ 1Z!y6h۰?4դ25Lmnmr9pao>o >bܦe`*\ z+)f7y[fLDEܕA(Q@˴ۙq}r]~ȭt=4|9-m1zˎ`ІȪ%DxP6YK[Yz rT5n cй~t싱 Vkk'f+hP"a/斖aÅ[9Ӑ4 lͧo:Hv}:'䤜r vwֶOϿ2 &yT2|z^(;D2Gy ՘; @L^c: EW[hޛykrwr-`=!)Cbl+,_4y3pv?=Ҷzv겖 ʈ2nl쇧22Ix%v3?u-ܦ$po B:Ҳ? 4*mUIs6jvDʔkw+..Ȥ572 DY!gZы~SI}Cf %&|flyLv=39ZL8`ܘ+: H0H.{뺽IZ/|_acݖnCq&hxSqz|tnheR 9amM⹚COTBGR)uJtkSy#͐ȦQ>xW`ۦݹNِR-hy3hYVX]ɟ_|~o{cb 2fPAD -ϧ'g ZP0j!_r^L0jc=@溶òj.x Lilp[ |2d4 O, ؔ-Qڇ e4 ZdiII."t3!aW=YXRauzam-2ݡ+2T=NXs/?? xdFׇ;l'ElCyM.6hTP/~QI9XAc?)ñuC` n[nB&x:~$lI[qj2L.=Z$v;m:R}n۰Acu:5[qT:@kn_1VͶ'$ /w}#кDg֛B<.P `1tz7YK[?k{Eyu{2bܷ G8rqU._G6F-MRt Qatt2b>mOM2E;CNZfFݭ$/M i]RC]dd zb)jxLq؛py&]h3 VD;~ vju ƛ/wmjd8ʬ]瘘vV65g722԰٠uZv2Xd$n*U2~3Om-Α!X .Mi$w ޗ햮~ R6\D*U#9>!zv?#Nomzٝ$Gjq [K9;[d$ҦB_t 9=T1 g#+3%Y[CM"e7=~]sfe#dJ̽`fpasva=z~lިcv.YJU9CM]hlX9²+fZ"t|?,;B*Ek1eb"![>kcqcLM2S(nK^.d*,__Q54J,tnWaF%)fěg9 &z$ PHs3cJɖ}3K_:X%h>DxTf`a̹AP {0c;֤y%3/7])SF'|&s6)`0_Y-Ѵ4]C$UN54]u.Kc|a5>#[r\Nhz+e`ܝuTHʘ[ι$מ^ay5:3Uޚթ%ZX mn%:*TK 7w*w^T2!㠛޿xNF\ޝiAHmL(2~w6wlmVfrDI9vqo`&<gy^}ڔ N Hf% ܲJ&rc˧-^}>萄uxgp|82FbKQDk)@b*&~^ϩ.Շ94ջ~*Wm:zfUDAG=Dg^xmfu7klcm5F02/2z y}+SQÓC3Xyn_]e&c3}m$ es 5a5N#Gnd$ Snb|+"zt7e͊2 % Sh4Uzx#IUlƤZsC2c҈`s6m5Wy̷)7;_Φ9U!81&Ϊ0LH;"hbu"*4a飙(h<*o z2{?Y[ڻ'fTDMnlx%* ^R=sQtimsm$?e}9?0b?=wo swʴp}>ON7S:oLEϠ4IrH-K?Se@_~$j fLñIgѯbsaIYY"r ~Ί\ Y_sr+1 KI&w%+YiF8ٛtnn}`SߐЍ$3L*|]A l 8њ;Xz|o /܁pHe-i)QGܝYyx_nN` L41(WjDԽ_N#$zUJŦB-!?H?-JR V蕹IxW'r's8~~‷7q3+=`^ӕMl8Ҟ葙!tU FZg(lɐLak71 IDATkzaLӜNTT~ƒt+ 0a8spa";=gCg_)kCzKXG3nHN^lu"g$8Od>zAÈ-^ ) E~[ڦ1ö'E~:IŶ3~|d&U{_Yh\j;huⒶXQ#3Mj>os#ʹBv2N5d?Ι lyo\2̻Cx6Prn}Ֆz$I4fxD&ɪ9|1;̙饪Hf;`G2Zz&.]d._@B-2ZnH4?=9ȫ׏+~Pb֬mvs>~:" 0܁-Kdu} Q2/hihAGϦ5:Nk_~8=Sp_IX_wM=Q=RӗI#M19H]~vȖKLǼF*W<5<;uMvSo5D8JRG`)![0F{=zV,\}!6_r~(-{l󰥳)!we)YYqXʾD\ϫO~-^ pQ͍*?GrܟNwl'Af5Y*vbgj&|=&U /gf;s#l5",IE&$QY#n~ӜwY鷾,sZ3Lwfq^p=HjHgrlmcjqY͙06JޣgX~ڰl~뢽ZCIRGTHzgey1N=R,kvW<`=) rYWRfHEj+n3! I~ %vf-@2mctr~FO 3SRJHp)4bY{l!M1ҽ2;_n+$/ikϒa={kJW/3 S{b{LJ=J!)bۗ֌1vƢ~~6`c+uPB CƈQ0ɗ3FķPb.[]?^n{,\b6w sˍw?kO2`/a*QϢ H@H~27S^BF6oWp_rᖈnϗ$EuykZMP^[c#ëtB%X&/4?x>2bDT&̖]CĈd(,g¢9JMu~ݜ]߶ ڮV f5/dLsD FeڪNy +v:rf~;@Ѱt5 e fҢqse ş*O'kwAy3@~wOϫKX2o76))Gl'.>ﴅ6x `݂\Z} 2* Dn;|CY [3-֕NU퐹Y3-rBr`R23ѼU/a-̋}a]bKt~gܝt;2!?ٿz,6nWuY"ļ6i{2rlHwQ,˥GJZNwaE`M1O' [ ~\[oe\riϴ)>y TV1Sjk[ȬLH)$!F:-3F:I'e8J\/”Kb ӯKs(F eR2}ӿ.E.)7)ۣ<ك.Nd%R!m2"J - haUx.&HD IRL{E'טӝ'}U6q/uצ4kQXͼ׊?(SYnkQM2 np4 I2S1~ͺyu/_ƧXl3ڞG:åRtDEKk7^\,_+s]9W'-mD@⓵sc\\[؞. 1t,w1aTdhNP,WixTC$W$i W,o-vk)_yyR'c_Nj1bvKISYu;)2w1v3>qwJ+s{DZ%-4}/ՍvR>tŽ&c5reYhKe/‵T}.dVJ2LPLr_'I/(n"3rQD /}oLc2͛Lyʈ оk qFDL*i@7ĐZnEfrü^,F#9rr m;m]|([bм,IqYT[jQ6@6aݔ;k+|cq g!̒|DѣNB4FĜ)9g-Eyj.:"r$CĄޖJLHd I(PDDeKPQсp, 8yD۟}K4i|_Ó{&?ܹдoު|'has$_cׇ_mmec_,}<??>Ljav8Γ f&W%mRǞ!0d*0YqvNW~LiI6{mT2˭Ì QU8Q8\Ebt /fϟ[ƒ< /~AGZ(7۩)1S~z/u2<݇\?l-lݛ^MDf392[Oa,){;[HcpDCX45:a?{nHo{DHE}QBc^#ԇ/᭶H/!r?_f2Vy&{Z^򼬃i?~ctb˹e§,Ν 3.2_ھ l_PTUŎ.)tiAdo\in/bψaf Nj&ԾFЉ*\4*ve(5WZF12|elXIt˱#+B1(cx_׿/>OOĩiYŨ]ϾϺ@nbWٷsX,N82d23iQEM}^^6~1sM_f5(:Ј/miJέu΋y_ϻϞcHcG6WdɃCݺ^?qgՍo?;?w<lgmϗ0BLb}?'Ǯ>:Ѓj!x쳅Łk2w/k`i 9N_}63].lʙl4<9*͚4M۞jT*6Л3e5?fULksB,3#TuB35CQ1Yk"Q3wi\c/ss%` ?_lB9F2嶏_Gبfi9z=J|R*s7(nMR)ڱ%Փ'o%!ra֜v*7m&#ҪN<>eNh=oiyZ"Gl-#uZoi V,͌Yii;לRm4zь]Va%>>mlr7а=-3]=e>iϟ>z?U/.ժU__GH[c{bC ˋ|Zb6[L+si~yi|_OqR){m#tD?H {{oC9)lf)sa3TY_dZqHdGXKnݿS>leZ~ U+*ig@v5p[2J͙A/~0Ad)AxL92Nd.~Ġ2W؟؇?.``=,dS r6Ry%'w4GgC,@2P4I҆V5gDsGuqUsd\/v?j֟6w)t޻ux#KѨ)4s-rɤQ9kt^mI+!z :"-[ʑ؟nضcYkf4"B b#N ka*UrUi+T)ҕʺ+C?iw 5ܖ{YTYJhVUtU a||ZC+Ǹdmze<̟|Rnrp˗fnumYgSbWX60!3Ơ{-cQ/=ݎ\Wo PDn2HXJ[^[#2"LLŷB!H[\/1-FU5ϻN$-E7Vkq3[g_j{|1=H堪 NG+chJ+c?DZLepw[<%$o\]xt_Fz+Og!3\U߼sЛ_!ݼ1'4nkB (iq)a!<;?ˎV*5c~EMA+rQ2,?5tOm Y##s6@ ͘ k9D>@cuO>PPd.^ w.I#aE5. ֚g;Sֻ֞6+[,fbU^)#[9 @{tfjR~:`ksdC?~<6.jG%)~cla5Y"+3}/`EP`DKYf*~[̌Ly9nՁ@[Zj;%AJIl!oXSsRo@'o@),.Wtǟ~7 OO'3(+^+(_J|' {{{[~ڢ]xs蠵fGhɨY^t?@o}6|'Ɯޟ۹1MȐ -N;j}Gw=E| $"{q8$%Cˏܑ2z}ރN$5FW&= GU 0]EfW%Ioydy)8t' z˪8Iqic4@rƯT29z*hƙlyY\Hfk巤.bS3z0ԨTUT<|: :ƈ>u r7o֓#IrZ{u!AcԔ,zYp_Ɨy>3%/&[/FԚ58iH|iC!ؕ^5*;n[mpKaALBa@Mﱏ=1LaLm!x'Gޢ7eWUfhWٽysW* Ud6<㺮Gq=ApJbr\c_'+bT)xYZ=GT9īM*bI*T9?jNĈH)GVD_bFPD1N[cRX?K\&e}c"h(ԌԮ/1.W}0s^3#ԑ8sqy|h+CW˜5S b1')aR vqC祲3?<ؘ@{^nLkU(7A,ˏ6T~%-CqZOwk0KT?\82,3#4舱ĄDp%`ncHS_8| z)^b~ZYJf1ZʜCzWȀAm__86OoX_rw3K#l-D3Q@"Bo.NQQ-Sx|nm~kkd intB6DFS,} 2g+el-(9)Fu~j[#uh =Ba{zXz{rQ'JY@ rpTڗ[zW}UsW D^ ܤA&Go#d,(LRшcs} |y_n*aիi,)ѭL8j<,*Q_pOn(.9m\jʁ}9/Z0׳+*3}M IDATȗWV~y jrDy~z1XR3Ɉ1"WG]w5Jcu.=z^!ĈbO~ U*zZЂs@$ͺ"q7=_/Or89ͱdX¢Ww>_2+9QeA RIihp{+7+T5y{59g"JLs!}OO/(U=53aGY⫘~!vuH@}MzI%W][_/#fx-ڜ^WPNM=JfbDO|K׈}>iY429FbP]b~<vx$5cqCɔyd}e >%mԔ(o\}vW~.hl=J1\ioWy|+rE/1"dޜEs:P g nE˝SۺgB10ZWoo^P*w}CbE'CC`$1#  xZǶz06F۞ 4FVO^h-!p9l9i/a}]9lMz5fbh]o 5~M&eY<,y<Ĝ8!=?G+-Ak=t?=_H(.O4#J*yM0*5g A,l~M{6l=,~pAȈiϗapCm~rm9ӅRwKe1S4e9KrJq4;MaB3uء׹AHpfd??) ǘγhn]ܺaXkȧDV}^M1Ȍc_ry9yQ1ƈ^w8O2˗- a,<7[[M䐜1}\]qx+a7zNon~#;Ʒ_WfSY|;g6gQ۸'}AҦ5ƗW};~}w΋9S @{ u]<hp-|iGB$lOy 38@hwo mhKk ͪvۼ8W==g^;F?-' "M L*xmd[X܉#X_[!-փ}JR 2B̒dѩbiF}--%F!c&AƐCJ cqivٴR%fZcP}[@7|ܯ^Ý P?>'H D3rvSؗ2t^A]x}nެz_*mG Cpkj=ϗVڅG s"l{\LuHJfNev l_lչA/ SXί PJ+&U$gld)KYTp{RO#m0V f,5nW`揳Է̉YS;C*eI;`,"dil HGPPL(lT1촎t$d!/nv~ [5 ;\oUk^QeY>[ r+䭚\ESҲ GW $VZb6iMh7qwBs1A(fΕ!YHd 0_DLyQgt{C XDHia[ nta`M*H0qv^%Q;\և?cw@+.rkHS.뚗rYHWʴz^**9?xPN/}>~$˫<<ͱGIvՙ@ oEӜ>dFM[Ve'tpU%<TP`kE0j=̨XϿ>qIRٟQhɼ/ax-|ukfջ&)mRző~B:sU1C ,϶b>tvwNŖy$(uǘbO])e.mjc[R"16TaHY&7+|A껾_ΦR$ VU257NPkTT! O0wbI1ͮ?C1&c\#p${ZOpf:- y1F -H3N D XZI05R)VA7T?̖?F#}|:˜cSNii$d(bl#1a#u[زyvXּ⟫Ӯ#Do[mm1r6miN5侥HY93xP*j-(`6pņJ*bHK1zi͆DϜj[<3ӯץNSNU [&q-hmӸ,wLe !KXz3MbTPn:ָacN!cmm]W$갳J Ӽ47_ercfvEݒ( n܌4_|^+x58ϢȟeKv2ƾ*a 3:8&PRR<,9q?c~՜Nk#Fi;5CH0{{d d9@)55f&zSs"fíc8:!^|\m{}R]jY@U<,^6~10~8ҌT}c$@Sdb@R`L#qNIS|^iwx(4璙E,D$+M~ Zxw_N(N"3sͣ\JKӜUps86o7,IZN1뇱$uMӢ^Q͙Hj^ sBÞ2ec;eJ@&z7m&d1]$fI}:ޡ&AJl)(ǵaTS0Ͳڴ TlZQ4Y)XNj^A+k Q"$ա6w̛ݙ fzQ5HG^k*wUI7*|\UWnkwS@]4/mu%` vlCX3R\mYȂ&7CkW'Pmu[yMi>2 c$9:)iB{[Dyq^.cYbH:)qъ~,If47 eIAk8WFe+:*hv W<D8d Qme֢6J"m!{fF wkESȝt#LzQ@9bP|:`ZkZEPAYېV-͔<pU%)>bpTK ;̜47DJjGtNƮ}YWtIN9_95u0|]Õ)6wh :C{Oyo?#%Vy14f*͕3ZWH^ۣc;[*LYٔI~=3A_m-^C`TqV`+? G RGHyպnxn_Amܪ>cv[cM-RFfOl(<NTIf(^۳Bb9Fq#X[~ۙ5s^tɶ>=4\EZ dAswwKh|T0C%Ȝv\rƩs3b=9iTlG%TnAH~Z0'yrVc^.{M2ZR~Ŝ %^R7>u"31˜YMK/ǟO[hd4HeL+q|M kz$pؓ f%l@c2DixUaJ?q:w?3GͨAa7Y%@N$05%*Fq\7g3QW῾dDD$̲?tX]MȌ A#iwJN/4\#"ա=b4G*uݏ9A4'h4⁾,1h<Xڲ3%hi#Es{m:yd4)b10g,{çz|(͵V PU(|14W2Z}ayF|AQH!yx}%$,u$̐Hsf |Ro`.bA\s`vv-i8d,Q2T!&N8tMM 3e_hWkZ&$15Wp̐F(#.??|0 暞˫.kr7@Us33zotaN5fȄAG(ܗH1MO.ɒƂ@DVur(dw֮?}+9s| | 2g2+$k:m踸) de7q"Z'!Lot$ ϲrDP@FOx iOƧ:GDƜ=t7% ]1L1ǟ~8!c1Վ^IS{\EZUN /Ov;f`hR$w,2-s2k~|'w)$ތ 4UG˾ d99qXZu܁XcWwonq~pZi ^\]p`~c3km ʂY J*_gTnN5<%FM$֨[J(xx..9g~}qrEe_ -sRqgzu˙ g]b؀z;s|b184n ѰȺ؆5d=|WxLJʭ~3{d2 i.UZXH4HdDD);Χ;G&vB~^J8G<αO<)[_tj(ëˆ׉ksfyؖfwiYƼ<^W{ m;u?q9fc#m e͊bJ9qy֖o%䗍5<榾OR,TU %Jt[$>@E*BF٢Wp+#wʠT)\O?*~0SiuЉ4>&y|z9ΧSzuub ' y ̢5B, &L9XdBKD^~s`+lX˜I$,yyqQ, )S,f"\3V8C|۠/I_5tΫ-JV9??'km:4"a¸4f}s &ɀvmi<9ux`*­$3< /k v ^D&Pam$#)RR-%dwsB gjWe9N^jrC=>;>r~}>=]fG8G$-eSO64@(3,|7,LfSN/Pʶ?kg撶Xe|/@_n_Cpqda!_3ss|k9(v΁Ӝ RWf)o7LaNQHI2xLъfo(ٛ3ױ]>(s\wxxB1JqwKsSF(-׸m+kzkNɩw?\)'2PsE^Ø\N"kP.JiM8 1}#&:J*9elDtNU}n|/`qr=b 99K0(m\H֫j9D oҪzuQk Q+IP_?C7vy3=rw(imkI!4opY|)2E{|8رX8:-|h}a:Fji@sGDR (U_~ TG&q~4ja&UE_E~Bv|!M_7y!MNfb%D 4Q+x/3N9~[!c1dU\o2 [qE-N0Iu8m;o+HwPV =PAMk{4ƈbf@c@6'gD;,,jr4' O'GF7aޘeID)H.q$dFAQdYk|ND DtV$ b Bb! Cҫߣ(iks.1 |2͞L*|Z H $u Jj,yѷN09D,E> 4ae/mϸ;YͷS@K+L\| Ƞu1f=t0d? IDAT c.u I{5%iN~;ըSGi H@RJݫT$uOcFӚoJ?n0Whh Y[e_oF^k閾|roDy;7 )fFJQ9kTa䖄&oe2f[U#A f{s:9d& y>22g- GNi8e]c}:p45oR  kA>l#_<1m׊MwfrGb_vT!2`1ZHk4<\TKJ傫,X܌ ө<k@9L_~3sPj^^tY+\M|2D)2ҥ{h; ɒҋ~vFYmg~MX 4o GYt3R BIAfivP#[ayZ^tX$I͕֚[4T56ɀ|QuZd/rA1S[>8i2f2=M Z~~Ճ6g5RN1,vqH`)F&k<~A~^9Ƌ'xDeMգ[E9kkm%ko7 ;YTf!W!K4@.o»{uo(r{$8/`3Hb?|2 wRL$ &M7zf]\IȕW`eu#S3 9B /$cˤrԟ}+ %fW-(en+GP~4_tR"~ݜ2X"c kq`« 4wqN$%%Y)960f*ϤVve|bsJ !t [kTpIw]2&s"s=:_-=?[oX撠_`_C>cEswreΊRK%T`$ǔK-[ ϧMCȆ1 דM*gJ-˚]Bo[wYSl%?0o G*ҽ9{;[N;~!Bp?-qy޼R̶zo. v&A)R/NVvWfVS0F(!%E\'kc&r&6|6ϛ 3M4xOћ;b#']ҹ0v[<0׉ !om޺qr_1Gi5Ÿl g3ۯ?7X|Q4)q[1zbԜtX_=ou6绨4t31xPܚQjJ4mSV3c\E |jo $7dg+zuz+%8`BV:XMmۜ5Nޖ\0gN}|-}ud/vMntP|F3!St"dr+*߳9ތkYEG)@J6(v·]<`}K0Ia{~I>dZ5tk7h- =tךӆ0o9bJ0DǾǭĔ6'gZ%oRNFv]P?y]J`Wچzj {v' bAoT$3#aKi<[ZL$v~->i9^Ì4kJXL#Һ76"2c:}5ۨs=2V,{֔M[gR{4w͉Ӑi7fF. =?YAnNܞt$Vp?X^˸^aK&tVř&08tnMϰ K_l{ ߃*d2: Ϯ4>)^a bys& S-^#3̸s67m澃hkP\t̙,M ^ӶoNWA!3"h}~H.RK+SHukND6Qu`k#CRŋϋ\U&Dº? ?MjTDJꙙ {yS"r<8Ju<{wۘ= s\CFd" 5iԙ#)2mXaN0P yMNɜ7j|E䜏:+ի#Kάm[n̚S)nl{M\lX-DE!Яfm߈ۿDX: c XZB33L3ҷi;Oq^X,Ώ `FagtdD$`ͫJ~zm{ȶr E$ nSgJ|ޜ;jΔ3c2v9Y,.F Y{2kިLvWf;SZƄ' qT;+bU{tUH2_C?GIO - 3/{П8yAKq}.\[;ay@fFa&AzsF>Ƙb4d5oHd*d[gJtf [of4f `#2#3u("AvL5@'h}orqؿBX'U:,/Y]jyJI:i㯓=T-,KQ\Șswo&[iΙ0B\39+?W *g#u>jR_)@?u?Ŵ?y֛r fY5+GPObf~;Ayf$g\MgMZ}_Nˤ_N?i32 {.3Ý\?ܶEREm@֋d9k>LiZ˴n9O8 zZL! 0 v@"-=bB{#IZ8c֭iܯݶ7o6;!8Ncơd*pV[c_mc1yPª^"u2sժs)t$Ԛzk_[niݙ$dto3R0/YF% d,lRDBV #Vk0"él)1joû,g31cT̏sWj~65`E\!%(:`^bUB TA[窼&} j>BH ܖqǜֲ|]->8kݹ|fR1X1h3YWf5-!kZ +HCΝ)HClg)sexFVLX0!#3x;PsZjn8{̓eZٟgoH"k0& #MYW!x~:%b\l&gG7sʹk氽u ِ`d V/{iec۲<1@RD?H|a\&fDd R 0+z|ctl/_UYI*`tRiK4Kb){k%QAYU#03a}$a)yݟ6K:jdMm2pA 4ӌ9:(fLSrq`Lb/a +3P?"B7CX>qwc1\Hչ|$,"UK j!P(y! e3:<@c&}Ϊ2wz  XC_q@qEgqGeHP0GfDPjz}Ӟhq4Aw4SXލK2#On$۶u&O{E¥)iq,E 套n}MZAEX`M1X\Jz+M4| wHLksBp0c\~u*T+Оs5^??̚[IZ8戆GzB\hAͭAif9e[C#d֍*93Pc %ջHܦd6W$ubbd St6IWr,-9_GgRyGH*M f55(9Mb2ڪ8A#hz,:8K'ne~Ǐɗ֭b,nTYE=n,aNM:.4̒m6mƃûcҐ9S%PҚ z*~2(D$ju}=9C`ª3ed3]I@d/S9MTxFFtr1` yc-RB;/3&:U]1FV>A ԋu^9|-S) ,)EYV M$GR֪ ?%qIEk͘n@ 4aG J4#R9`/ε !cK#^ 370Eɼ;a[w׮|IPSJv#JW/^K5o) 9:x+}ȹS@#RTê3*|=ѭ|HJQJǝʛƌ"Y Ĥػ%سv^s˖5JQ0jhn9E[qxykFn&B޳odl (5^8xXg(=:b¬x¿ 5j6/Մ쮜Ͷ9oUޏ,=&!1_5C{q{IhDjk Yk~b|4̑m3 8m[5P%myFO&x&^D1{,:@d[caAufMЎ7_ IDATtm3F-Io,FUzDZsI rdЍܿXW=?zsj~&cgpwEbguCM ;Py` pK(U6˙@w3e~lq]ж ̈昗:Īo[Z/BncҌ#y~϶vq!(Ll99JX_A~Gao@K#wc;" j )# 9VKq 7;"52^M"Z]luye!1]#xE*!*~ A8o͛ib)UHìѦlՃ~w9qʞo.{|-A0>]_[ =vq./EBVN,ci0n.9%KY~44֬BjiL߼<)VS+Ϩx,z7d=~_Z 2CQ\"dIik}smHG\߰h#a5cm'D3GAũ*@~Ic2cm"D\7us|FvAbǖ#{sd h~-YN ~hGVxIJ'(?? oO f+T5۩v><><(/EpoK+Y>iRS4{2ׄRH#TBp<#}-aX'hL,|w&bf4k֘ (7M{qkP] 3B`_qy.˜Ǐ^=?BO'ٔ29r<@·3ϜK{Mz8[-o3m{I6+~{wexQo51)6/0! ֚UOPq l 9'C6f~zClFOofπBHQѱB8YK1Kg$8y|Û35v'Y 0)5CT{4#@F;0-։ڎv8cWʎ{|*Kˇ"bl筕}v%B o}l(JZg+MVnԈ88o-BvLSytښ' q/#5a!4]cN~Es:@#B$h> %27rLf^Vd>1<${;əVM'2=JJ/^_M %4Ѝ9ݎؽ4Лm#bOIQ ZAzU=W7dƨU@햗Hڄox-i0+ˣf=}Jd*:L˹IG!eGE'͠𕬺W;C[n[<L!R]yknR$bSǖ_vD~y/ό9r&|=4q^lݩiFc4f75"J sΙn_ 1h枩ؼ)3Zq8 h2IoȸQ}"#Vn&|Ug"Q9~U5v7ύh''?&>t46fSw*_밭t>ov')\؁9փLOPrZ3Y}s![Ҵ&d[7EF a xIS6cR|1PbGN-.ғ}~0;w-f_gS\vKg3Tk5;ȄL}!2K"/-H䬦o=婗 "sjx J+aVͭ]/% oTUJZ9g3BV,6mU! 9Ӗi8Usş)?~Ç=nϾUQ ]ƇsLoΣ^£4o΢ DӍfWxK tTZ ͥBzbmP5w>?] !$u1À9ܣS8qmRƘs:w}9=ؗ-zgRv3}Ǜ_uXx Y+LU>|u?AdUR'_lL"M`!k[JTѬa(+-#oޛ)(f#U$fNͼoi4>kmj\*QVܘrQkTHg7g*T9f%^%I _-i48Y?ߍIgĵmg50%b(H bVRdWJ\͐#`_}~oZBV6AJ"Qxxѐn1S_+nb]m '+Bts +/U32e1K҅•_~qס8B /uXުZ]F%5coWio*f.kZ/c[_8ʴLmnKn >»YP͑CB$]Xo"BBP+/V eުIН2$pgÐ/; 9b9U )YV2qP݇ノu2eD,yl" Yxח.zBoy tKjmxYY欌)*t ڪf8vK7b?Y#SE5Xea8rՖ&Ydp;>_s=^6JMM5"yt}ÚFʛ"+vJ%VE|s:>'8q\*eX:H3Gr8&Wq]qU 3JSr*$\g9)cLdQ@#?#SZgZXտV%>q7fL ;ئi41bme[ {0' j\d~S,qUquIvG2^QS(XCf-][mg s&eL&  8Vv HWtdD FƄ`Ĝ[Gk"ܭD̡[7EP ϊدc?)={u߀ 5Zaш8o>$~ҹ>ے$I, GdVU_g/"$PHo|yXʙ3sfVU(`Y]HWwef ( -s&F[##R-st0hG!PiBMyϹ" Z;ಣ#R#/^@BG5ӭ6pvtwD)#bnՖ-{8;(sUzKϰ* {'"SFZY, >ߚ IۿgJ!Ѐ9km>-:A$VOC-P>?8J5z-3'B2?>}#FoJ 0cG7zKc߷[2c۶UX37%f$mov&72M}Qe]( ,Z&1OC-w?C0"glaK~yfNm&ݶKa{fRW!@dpϡfschWIr6}9osD" uۓbBܖ[ z7qTJ؃m[M}Ͽ!;N\-#M!~lUJܽS}^o ^Aj !KL[0)2kh7odu@4T5wY:T뵙XwITragaZr@% vϮ̩*L3C~{Wj+֘pfWixP5[)f|y3Ԅ^7y{wAں!#2 ^3+,-IJ _', u'tvZ8o9>4si4͔$Ѵ+4ye)7V# noL:X+ Dg]AGbg{jNtϙ8L5Q'P]6|񳛽Z,#&Jm;z,v &$"lbvxX*XXL9uf07$%LkWA󤌜EX,zDm^5i&*Ӫua7RYN2cdU?_FG Ŵȧ;jECt0{~GW$cf{?yIumK.FUՃf՘Thy7(g[e1 ϩ<Nw˷(5:HnI-=!g2 !M6J ;0޽p>>*꬞aV(~#Uns9V飭8=̝lEfN?D%J-Nrugj3F_Tzvm,G=mm-мu dTƪЅ5z:579#+JeBbmCCquK23MV~T[Eo@Z[e .ԋg.r){x-񞞨8PxKI3h۞m=ymT}pp[8 vCQ#H/̰biQӼ}H 49ł@G?xXNuV XRi+bk|̑tOůwg˺a/-k7Z3\ض4K')o9 7:zTdgXTҋFSniȐblܓN  VtIYG2EZ ,KK78j=¶8;3A'lJjLUhk;5`ݜG"@w߸SU+[D<R+K&M]$7*f@]_x۷d"/X8v'+̯;GaB=Woz#.$Qˤ =@t6Ju^J٠67͘ZFEC(cX;FXLK)!3er]M#Af4Dmuwӫ澞=Gu}Tdz٩FGԱ1xvG.ɚQ޼ds#ͣmnV hczu-=)V*h9@U~~4o"pu7eM+W1*hNBGK+C3tʈ}o )YQO!wGxgb|ƞ̼y@bh0kXH}Yz`N<83ٚdzuY)!AB4l~݆Ltٺܛtd$Px̌:mU,APn"C͘P9b=쀛mq=-1+c7.k pϯZ^A8}됢<1/~p[ρϽrO -al1[]Vf!Xx!n(we=~_ɱ4\޽  zjAGr55Zk9>OKMBc*%ڌ͝U>6XknyE[Žc_y}J2f> 8$Ҫ40F'"^f|'GJ%%s(s3Y9dcLJTgQP lz1*=lѾژ@;gdX;Yq"1y xSw3iݧSڷ π[uiC&KCfʲ^lkn t:۷WE jؤ][8;>-4R5X˄8Ԯܔ#C4).tC!/嶰p\|9ƶ"zJh7hOdׇ/0e9ݻ1 d/92_Y)5UD`*o2c"lV3 [qDepԢJF Ly)=ݭˢA"TCc9|NDcBcuUњh05Nl7$/A cG^)k3XV'Bg/ۡ WMnVDՀ餮yZ-iD0n IJ/k!1:AҰRU3 3 ͑Iu*KD6Ow;=g)x)^\uVm 㘈Eyk(H1Nf//ݰo}wl͆Ǻ8ї)Kfgu!Q 9_TP>~}M5ttAp50 Yy3{xO#!"ߌAaLElN)4blp˔=+zNj3sm} [N Vj 1FIl;uBWu79Mv_NR\~HbG *|YMݓv6.ެ11sTf׮@+{NÒ~t Rk.2R׽- }(%smkݭ܂jdPL3`Lib*ޗ*;&2#ț>Y9)KW[E^}/ˌ}Pˍ92~)!n";j|_0WB1!J?l%!c߇X#i]u\Oοنt' އU,] n<~ܗ!E띹mTG5Ӄ42P>fdw a^z !Te,ESiRl#aA} 58,:C tTQ79k$?;IkHuH֘}6co;ƕCWhg C@[ۑE 0_X|gwo;23dtN{$Bv8~|`jn7ߓ5 4ZUx@$Zoɓ9О/ 0}k%5:yȘÒ|Js5b&푒Mö4#@]}Lq'KL |4gSJSp?ݭ1X2J|V&db&I]{xcN "Qd yob9[A_OKˑc/t KsBr0w#tOo}7Œᄵ>;[tLP& By<)U}D՗fϲ#tAZf[*1rOmSol160QP@dmHX޼܍7˼*R@9C@X.7d+l)>OӼܤ8ecMaF(}Ծm0*̂( vj 4r3-ڪs~^]OJэ],/i :VU&'"دjl[<^=jdR0MMT B?_>T3淹UƬȇxǍOiBۥ]E绞Oeq6uP:Ӊ@OPzнOG޳]/c`6{|EIYq)&/&LC@Ȩx 2dnQfo#tزg˧ЕRʞssvDѭ@)@5nE[P1li ہ.a}u ඀KDj^k%!h1Gm:@Y#HCs֏̋Vi,G.y|rkVەn6!G9Ԗ6p}?~N4/oG9=O'Hdݏp$\2g*'Bh{RwI#|lI3떂&/ ؆[zk}YVFtTsݚC)4UKR;n_aRN*Q; 옭Rc*g9˛ M9L%j'4/No\@2k%ͻؖ!"+~|!gs,վ19o%`@UUYd2QrSܝz27ZT=!3P# !S |ΧyyB+@ ~_4!f;j.m,288tq4+'_K3!/tLBJ)R!&)|꿜2f.ګ!p7_Km1s1 Spp?tZj,-cO0&/G#d1Wjs԰B60dd3̙^<Т %Qf~ Ԕ@ ?\6c:Xm8_dEa9B9vnJ( &&H yw{!ߝiuIFK*:L%,jӭhsqHVS aW&5H1[nT-\^&KS=BBGkr2qة:]Z;O>:Z;5jfG(vrHﶆk;F<yL!i%BkK_2F:BW&{7:vߜt*-W$깟ܐvAJMkDDw=>Dց,Our+q sH -@;؋6SFucq7xh0'G[nm|v,vGcc'wy^3{ [..fHrvd\OW'<fG])ݜ F$at|I2Zk61L\y!^Q/SfسpPϓP O>z/Xci@Ru '-BlQ-M(`K.VHU Mhwoj/8ʜ(` @ϳ ]^dEfɃNҝ@f4vdɫ_Ɣi? h1?v{D-E e-#gӰ{5wjˡ$lݽ 4%5x\͉<@Wvuuq۷3 +%J Ȧʲ>9%eƥ'YYyF ҮN(E *k{mc)b eOOAza8 ыJR~U@? LH]&ra]TC Uݥj"sMH_V0S ePM 37Ξ1SĝKL&f"R( 7ȜYДsU`Oh5,QG ,.2nY Ӏo~urqYVL0\p7:ŠibG"Arw2.ʌ9 o;vz;L9([rJ@54,cCf}Ag܄ou_*ݱvs1% +6Y4ƑJ6{19 }˛&mǠ!=3-lϩ7{/>'jFOK6qiI?oI[^㟾i1Rl_Ƙ#F]V>W n̼f(?Fy*G7bҔ&+V"GP9IMA>䚕3/{_zBsS @iڼt>%1s5?-EHFvvwzwbLQќ9*XAîm$ch1mK fy j1~v&Mmc NAr2OGI Js*F2F3زN !#Ơ2I ʈ8Gi.csk~zj]{6Yknbbzjoo==(tp/4)Ɏ/f ܦԤhHݷ82s+T:xA#v } eYÑUiĂ f0z&FJ4&%VSy(qsT ˔譫a8x^w5wae-ؑc=u~,9Ŝ#r:H2Yk, kscȬ3Pk @Oveyzg-Qɔh9馄| *9CffF#D`J[s78 &'[BW"/?? =~=9IPU3 OM)Hŵ )z.>RcW\H_Gc"3O_|G>ǭ'a~sH&cQak<!ǘ$y>K_ofdcW Lu{48IYuCMjc0,#hZT{@ShMo,DnwxԋuK\J@3.~-03`wkȀ7*ƢN:OyJP?q*xW3Kr ̴inL B)z]K >{m*<T&V R1x<ຩ ӡ}& El{x) t{CƊ&ZwEXdc\!nm]iU5j$`y۞->{ @ѯY9҄ ~M@δsロp,\:K ޳KX@2Ð(%lwVĔAt/ҶLJK6޼o|u߾[$gZ=S)"vYC  f}H.'GՒ!^rߞ x$BKENYe_l+0SyV""0s"X4!0 5oYlIkexSq0W Y3\/Oݼٳ}۶g<#a^3&Źc =fыR;_{3%PX@t802?\5LI–s YH.۳e;P"ds\ BqG!32ym=PywJvD5kWQ@Snû-¬\fzN óu?=^W}ޜ#ޟĶ=2``f:?ߡQ#`ΘÎmɨSI7(fAcGN)XC9%=S9Yqd 0FF ȬIX•IDATUfNԺe75NqQq--ג紌OA(}w˾ڱ&~_~= 6)$cX"N)e ι΄8Rۡ:'< Y>3ܕ06;E}%8)-ic.*z;/} R,3?~%eanh[凤#p1$Y[aKyݶ=s6[s3@c"I*Ǟ`Mڭvyΐ)7fϱAArv:m튚g1ssӞRZݲ0R*',{0˺|z,dԑB~ث?𨓶GnѶ%PtR.tyEA0kOR\Z<`l/Ky:jw*`|P0s!3ckKoYM;[lP=gp[ާ։ Tu%_M7_׆52 `ƶ$sTQwAA1Y |gB=TB| XhH -e{},"DuAoWҗYΜwFBH44~cY-"[^ezZk3Klx1r 8Av6ĘH1Ļ9oWxB}}"1= IUiV\bBtGjܧ9OwO:#Ejc  kiY˸fqS{בiTD.9Up"`yw/˶ƕE0#.5&1ޖ>!8A'ۢSݑP=Dvݓ6B"wuX͜?*0G9qm*yn*e ҐfYg1[b>\yޱWE-˾ 'oҚگqAd;f2ReHD"_)6 h7Z3c"h3xV2{~b$w=xt|U/|?=}1D$1ZGfInvg,uW5$!~ Z*Ef !3mkVoky줹!33jh$kf#7~|%HYZ̸D7V5Tn.}Y|u[8ruxz^ 8B2ʓMШR*.RbY>BMS"[@誄9ؘrasZ Cm}0͋Zaqiz}>fCB9/O{}ー'= ^2>MhMfkdIj} "1at_\ZVA~< r 1ɹ&|xXX?}ln :d8b+ؑ{O)AؘA&Nhz75ZO{k 2K!Zr~v8gٻuilNG&6, ;Q2n@)GKu :=թR=^ 1ES-L,e\8#DsrV`bTz&ͤ2iH6EE ћգK&.Ų^2r(ֱ!9dtRS酴fcE!ҰEO%fG)' ̔=/;[xM, R+f=T_ZK0C^0f⧈A`IENDB`nip2-8.7.1/share/nip2/data/examples/clone/clone.ws0000644000175000017500000001404213351443023016573 00000000000000 nip2-8.7.1/share/nip2/data/examples/logo/0000755000175000017500000000000013351443023015037 500000000000000nip2-8.7.1/share/nip2/data/examples/logo/logo2.ws0000644000175000017500000015036313351443023016364 00000000000000 nip2-8.7.1/share/nip2/data/examples/overlays_and_blending/0000755000175000017500000000000013351443023020427 500000000000000nip2-8.7.1/share/nip2/data/examples/overlays_and_blending/blend_example_vis.jpg0000644000175000017500000001521113351443023024531 00000000000000JFIFHHExifMM*C  #!!!$'$ & ! C  "? !1Qs45ATa"Bq23CSb#R$Dr6!1Q2ARq"3a#BCSb ?Ttg&tMoT~L"M -)L!OuGBa0m>a?Q~G!: #i*? Ш$>L!OuGBa0c~ Ct*? FmOT~L*]5004FuTοQw"^M7)eΦ7L%{:t0ˋ*jyB4B!B!B!B!Byn7_>ű:j3)Pۚa~*_rǰ,(h"oSY[}'sK\Zb Su {5ޟiӎ*́B>o\>oIŗgjEM zΦ7L&%ŕ}!I!B!B!B!B!M`cIX JES}AJUs*׮: ?x&L&1r N#'3]||mZF55rQj(EM!g8wҒQ!P;*}g_;*}g_;C.4ԋEgSn&=MoLK+*yB4B$Գ骦v@] F*\ꩯ7^GLOvkoaSTTdDSc,{q 궶r}VqSdy)ߔZ/Et ?>c_1#deO»]O:0!Z&?[D2O a kLqKZm,[ Z[~0ڜZ^? "0 y\սoO-'M$cpG?E?Ewfo07V܍)U]( J4؂]2B.揉.~RwM2Y4UˡX3rSF,JV4ԣ8|`j ^ Ck]]%⽞+"i#R8&1U۴i4z[E{ֵ8(^ŗ>A\dB$>o\>oIŗgjEM zΦ7L&%ŕ}!II0rLN[WZѯ7qSx/Z{>У)"rf(\DžpW;cNM䚎6'#6/96Qۧb&CVI鼓Q̓Fۀuy'#MćDiu5=grr8ْF%29p j69mFܗx![[ur\+%Y>>GZ 8#.OSrXlh|owu*Dc*qLz꼜("}+HՑ\JQ>-U*+/^Zu$cn'J)z 'dy Qޖ~Y)oB`ʂu㸫u㸩48LHPu6a/Cۦ ĸ! #GzØ^;lX4[ΌKU#XG9'r6OlLbHFBv7YGF|ӑ6ؽF''##%'"v$nԝ>7d[ F7w'#rܐl0Q;Rr34aHIܣucm C=o5=ĝ^)- 4KcaV1'`.{\nI7$d'pPOXHuVC̕o* ۸\h7`cPm}XW胚摑Tc? C Hꕆ [/p?^x*}g_;*}g_;C.4ԋEgSn&=MoLK+*yB4xudY2aϣR>_VSpRFD z"bϚr7(Ϛr2lV ܜڔ|G Hl0HFY"rv'&[ 19|nܐ`NFuf2-ސ$[7LvjIBeʊXtwGm NessH 57Atm]ҏ04.+` 8?¨b}-S՛UkVPȮT.0U+cU+X]k5ޯՌ?dj6*9B?Ч4/!R,u㸫u㸩48LHPu6a/Cۦ ĸ)WG6ɟe`кPnL! {t[-mEb<dnpq=A7}ن4p6j8b`5(o٧$1>J !:hƍm}J~([TJM>EHG٨>0^rPIYZnM$#QoF5_u9-=F p2jL!Fֆ+*FD| gz@kjW+{gO#nHy=X$Rj En[O^|жND=+Z5eBό[O>o\>oHŖ:gjEM԰ÐiΦ7RDG#\{yeivqqeeSrelc@. 9.#V6u h+wz0i\k@a5:Fu<FE%񺉞IKUwK,\JE4klgh,>{ ]K'_25JMӚτvn6 c6S^pOhx$hV9ezUxQhOjof>229c[$nԝ ʍ.ă$bMעo5Ø%kF7MԄytj4LWoZo5O 56J7ao*=R/9 R ;[U;qõ5Q( ?/m *[BԲV P,֡)x|p<_H)j+5Aq[V+$O_?sy$#6mFKM'QQew0IiעQFL hҍ6zn3GO[_0I{.9 jo⃓VFk-0ڬXgTbbe~gVX=DKFfʥ 2ٝeП *k*9ΘmJTJ Yex4LSFۨ jU@*{BFH͡@_Q斸9J;)JXS:FUS:FTzYgjEM zΦ7L&%ŕ}ٱj)d$4^\TKcʒJ\*7'AzI{X֍&0,fcOnˢad!N#WԚKN@BFYbx+,t{%k>DnzmXkQP5,j́KMy?Ldm^5׺e $hlfY9n֕V̕ik;䬘=qtp{e0:5;"nƍj06yu}V_ܖ]ƍqye `6REZ N&dmm]ieX5 !a-#%ƽ-p*ERbԵTE(!+j%FR}rb u|>ki!Rˑ|Ë\Ua v>+}蹳eQܫXë&QBVWIep66_RIrJZt< dVQKAvUNOQ!MRWMX1<~x*~x*xڑhmx^M qee_y/6BFGbHeR)zsUJCI BiQR ˂cd4\cʚ,~;>z0i]B_YbդŴez&;Jgy]Bv ~?OYK/;JL|dK}/8SDwY[ɗ(TߡG~?YOnakM26f@*FHi<9X ,>v\ B4o es\2qjTۚ^Q Fjfp}PpE6Q"d5K[I8"&/$h)j)I{fo&T򮑀s]]} n;yZI v{G9_GK[PGn 6uBT/WeҷykC.u8p LԬm? ʴ8PƆcG5zجO[TF R2i ,<.udT-P]8b{o~>o\>o7C(tԋEgSn&=MoLK+*yB4B!B!B1~R4UTlGcoZjk';Zmr_B3W :W} XmTvU)o fWz1:a4rqkg׵(lm[kUJL[`]u*8kZժRS/^W)۵ku[-3wʬpv01{[E3@$~+}LBNbO1M'8sn9+l,t|NO1=*x(!_pBOqWOqRhqeƙڑhmx^M qee_y/6BFB B BmLd6 mYo=|O{/f)\ -w[FGepRF3QW3VZD{\X)1,ji1B-)m^؝)XOܫgELŽ߼v*-~r7-UXPD$5$Uo$Y(7%&[MXt@__Jo.!gv ʄZJE%5yt܁BR*}g_;*}g_;C.4ԋEgSn&=MoLK+*yB4B!B!BkMRtXi0H7ml>.<ՏH)Tϳ.}\曂6*4H޽ $J o-TYk HŌH4jrԻ.HfkEfuнጹZj#B[P>X)ЄW볹NB3!B~x*~x*M,;R-=MoJQu61s1.,/6f\I;Qs4,.vjhX\E аڋ as;P3Bj.v0f\@` ڀ;Qs4,.vjhX\E аڋ as;P3TοQwmڪ5zx*M,#nip2-8.7.1/share/nip2/data/examples/overlays_and_blending/blend_example_xray.jpg0000644000175000017500000001177213351443023024723 00000000000000JFIFHHExifMM*C  #!!!$'$ & ! C  "J  a!Qt156AU"q2BCRSbr#$&DE%3c4 ?Piu2QYhjj);'7F;f 5#&vTppR;*OojGeI ' 5#&vTppR;*OojGeI ' 5#&vTppR;*OojGeI ' 5#&vTppR;*OojGeI ' 5#&vTppR;*OojGeI ' 5#&vTppR;*OojGeI 7uZLz *&Z-GJz&vTpԎʓNAjGeI MH>&vTp6-smd7DUԫ=zzK:S!:I2KU=%\^-bU8,|2Pz gSP#2b^xndF֊Tn|"o)m-['F;fI;Qs| Z+).KJ62X䆎r}Ҿ7 d̴IxdV+R?'SVbɈjfcl?U!.dJ4K!T`C^ *Z>O7ϓDMˣt~CByvu >9֫+5;65:Z]oD'IKXJq4Ỉn᳐woD'hYxH^/,m%j\&ܐ(V_AfMIX Bb/=[bEBsJACM,^[af4UC@'0kUb9?} !e @Xꉝ0w4':Q# T]I ؘ"=Xbα{N9K%W9sLY:[+iS_ű}QTn|"o)m-['F;fdr֎[&Y?M諛jC`J\F~ J\F~ J\F~ J\F~ J\F~ J\F~ J\F~ J#T"L[lM}j%I?6p7֧H7/Pz h26VqjDuEJl8KqvIˋ 4/¶IY#WTn|"o)m-['F;fLC_bZԱO˧ ӥmrQxK/X^)uD]bu.E/X]`KQxK/X^)uD]bu.MFRE'V/Y؊>*-8}u{P^bO/q3Ck@&UBJ]Ub|eb'Sީ, N"-b?,ۺRչhTn|"o(]nӶh{O ]F- ԿνG=3Uͫt:,[tXl[]J*;&ʋoj讋U^薽W~ 45EKW@x5ES&g"&g"&g"&g"&g"&g"&g[E -ةS{yk$;GJ&E򁱾}]b@_Ze6N5+S?U!UeQHT͏ h**"ڊ }a4IHhоS`j?DR*Z>O7 .vuڒѰmFN$Q?N١Wֶj[,O"jjU]fhHz"_Kz߼]%ZFlSm6*yׁ4~~ KLF~ KLF~ KLF~ KLF~ KLF~ K8>b>Cv9Q*mE."5uEbX_.X ,5"a9S] =4KwH9O-P]عbހ*Z>O7ϓDMˣt~CC|0#ݞvnӶh{B*w¥[3 Ńg[@hF4EYqpXٴUГ? 5KSUP,q 2W#O(Md5j/xk! &^&xw ^&ekx3xk#"9SQCUhk*cٔ;E}Y'U)̽X{e⁨}>_y^6&u}_?3K-SmU:[R8lXO-z+U0ުcnj RչhTn|"o(]nӶh{OCQ2;QRJyF[#@sqAݟRK@Rs,&3YR[V ? ́;a2zstu2yNө}AAzLgCAzLgCAzLgCAzLy v1J4 EĄ R-gZ|8YEj=jr!h8*_I?8hj;3d(~+ڎ2+QonjY O]AKHi4]P8J}Hh:mУ>TVT^2lWR_jeHRʪnN:$i>bkOi_ yU3c;j{STn|"o)m-['F;f CgMy-;bثgR(e"G6oԯ "G6oԯ "G6oԯ "G6O_X־=Q]ӧ*Vj"uNeK'.~&HJ8H츽x s\^<#+Y8H츽xbgVӑ;{DEE_!׳9mUmj~{OGQS)-✲pPbX+Y6$Rȶz5j󦒺ěW93S"=/"AMlT4E&r|K'츔z~[db7: ԄlV|j"XRչhTn|"o(]nӶh{Oo '!8N_Y cP  |C$$21C.2B\ r&҄TCDNmDF"ږ5ĴӐRչhTn|"o(]nӶh{Oʙ0XV1"dXLb%zXp3to+]eaHGKO@"C4n|Dz"i>"b֢" )0V5JkanW4$bK-['[EKV&eѺ?N١ nip2-8.7.1/share/nip2/data/examples/overlays_and_blending/blend_example_ir.jpg0000644000175000017500000002641213351443023024347 00000000000000JFIFHHExifMM*C  #!!!$'$ & ! C  " N!1AQ"6aqVtu#2BFRb$3r57DES ?ҺKIgt=4թk]:ClKi'm9?GΏO(EkCI~ O(GCI~ G '^&-< '^&-44{G44{G|Ek(EkCI~ O(GCI~ G '^&-< '^&-44{G44{G|Ek(EkCI~ O(GCI~ G '^&-< '^&-44{G44{G|EkwMcY}F]r44l4Rו!@憓/h_O轣M~ZyE?O轣M~Z>hi?5ihi?5k0j{%e{mD$!3 Jc;Ep8wYSUz}T?GΏO) O}&PQEEPQEEPQEEPQEEPQEEPS]J].Ǝ68xPopl2pj*{`A{--LtdǂA Yr`adbF/yQ=54}-+袎{Fp%DϺQ@QEeMUEVu} BgGIGΏO( (( (( (( (( (( Xf&wO, <8ܔhr@9^ě~nEzi%i-# Ӹ[K[*IC@Ox)ݟU9Y zYKn"nYDxpG ǞGC{="A+#*?)kҿQT0b.:P[#-FJ]F^֐U"w%GڪZ=oAǡAfcJ'%C~Pns2U5]7kA^֭蠰++|]n?A[qnA3G –Aq{+?һUgWT=?+ݟd+cqJn)IZQҔ_ FW p4chٌ 84FuXS.Fq{P~Mlg3mTˈۈQ>>9|(ZPTJOT(#>P6_o)XKEPh"Ef$ҜqDJ I9&?L]5c SyR{<7 hL#KBzP5Lזt:).!|gSKǞ5#6(qp.LMoq.KW%:6&ަԅRqTQ@VT^~Ujʚ[?-=tyHZ{ 4򀢊( ^ =sIY*k#^w[ y ~H3g^ H;䄨I$u B)N: ZW*q OVRܜdxF띣fF@iYNvO!͊ڭiAf Wg~{Oem9}"UzR]mNR2@(%ݦ,x4mJNS? 6."JAk,]=b?b;E5sń?dKiJQx{s_VWt*}OAqM'>QA6f0jM{iqD?7ċv;{f Cv@h;oIkjnn_|GҬM [G!u66_h .[RW~U -K8!C!@1P us׺u$l{ @ RP$~JgÞqA(aj; `%HH3q.wǜ5ېTpRjoS5ޗrJۏ,:FR6 $q*+2Zq :ӹ `;m1$*50ddG@N]u}'-ΒN9@u\Mg8)Rºdu*;c(0F@{p!JyH^YW|֐XqKpK<{Ԟp/IrHNP>K<@5FƕnZWڨG II i[5 2aX"ѐkZRT@p☲`Җi @^zRʹŕg*Wf2{W+0e^ S@Օ`bʺRºSONh*Us:Y骄mZU#?^UWǴhJ3 =k"T]|~8D7J  uIh}IZ{&}}a|fٜ}}D)L-)*q`lܬfPlntB١*FzgUaRgǎ䌷!-\t4E%cU\-)\8/z*œA{i=žq6aTH` 脭n[uKHB=Th#&5`y$NIT/7 Ĩl?'<U3㗣>6r҅{3L|Iе֙r_ʞ'~p203AhA{u}u5W߯AZ{ 4PiEEuN(\eĵ 0sPk_)1R K՟|: 1pe0MYx}}ezVgS\םSTh7 iq K2xiVv'BuZdNqjN2$-*HuE9ywCeJ/]t\B71TVB~\%0ВDrx98^T-{Gk5$-jHQcS-84io['y"J(`u er UVƸxJ#h BN#5`/ChƊ9rJJrYV\DH+J-=8B #1d92M!J%Yxf1j91<\ZǘSqq{ȤuqS!274%m2];2Rr{PInQ߀Xqo2J= JwFj+*j]o_*]eMUEPh:?Md,YZS+K2$2ZJVLqBgGI˦z,[ۅ ^՟GA[(џLQe/y8'93DZԡ؀*JI`;RL&KlSD)}6iz2 4RiV޹KjdI!EhK+j*N+*rx{+׮.λ)TXN9 Mvv@A*jY48Ey)z,ar'{Z;:re)j:mmń X].,ď>K*w I r@ώkR͕&#a0{_>j +I!#gfܵe\v$2yn*vpH %]j)|"/"yGg' JBݴtȠ.w:0.qquݕdu:Y :VI=i*4 V4Bqr$Wi0=<_AI|澼:< '|+/vQ]ph 9zK녵H'ݚd aߌ:c5kfubmm 8uVÁ 7gWjV:*]ɏsD-E u5k5sQ+ q<=k[' A*tęxɎV!ƟGA֭hb۠9:sb3;#gm*J8 jm l%@+E5L͘͟; ]i9# AQ.0ٷI-Ca%9VHI5D;),Fki RTW\nnY.b_\J*B˃{C塚I^Edrzu*ۑQ *pퟤuC+ VG9N֑lXVE_Xr9ȭd[<؍!ޔ ph%U5W߯Z"4~ O}& i& O}&PQT<X8_\WW}wVi[V9VS:W7fK*fC(y ) HP>h?u82; Sc1wޓ= 18 X9g:9jz>H4hKk (p Rh$٬iώk9.FB!E¶('uE/H ST‘>6=x5ey=kܗ/%=P-\{(Qvz'{n:m $Oi[ąYjsV64I'cJonA:2kK66 w )JTFxPD!OEiJr ֧*) 9Px$(v;.[-MK󆷖*(JHQRR5$0˴[V0f7#2emD7t4cU\! 5û@0sq bo%j)ŌQ J@ڜ#86.]ņmࢥ[V6I*$FTջ-hF՚n_z )CJK`+ ARr?Cu,MA;N$:oq xXql/n͇nr9;!/sʀ8FNOU7Em6^^yC&2#nEa9>'4;ӨH\I$jIDf l+5نЗT9 roϘ]:wRF3Vs8 YAnёf XsVH)q $cGA*j]o_*]eMUEPh:?M;,((''Ʈ+~K79F_栢ğm~<ϒޠ-W x\gSN~z Y(KqƐAR[NuKm,fb0e6JxM :Ad&]DKHxpI91t Y$Hi rKxOJ=9APZ]ɫ#ə?;vƍVTrN}#=1%8n|f+qNmpRvsӃoV}u&Mn+Qdݻ P8Ϗ]n5ۤbQRP!ۊ[J'yR@$L`PG"5*\,o/H\WUJB@TI8ǿa@Λ޵wgj\) R9p:b]d;%rP*lbPxaZU!{\g#zmp3@LwDDko)P9s'JO+n-6֣'8Mo%OϲNƜsiCư.7'enNjjC(C͜sׁuX6TJۼ>_{}V mFm-Wѣ2Ɖ|b;U̫RpvmER$:)*yg-wWmVF,In<{J Ry9䞝O[2c&9jB 8ϤŬ,x:ےC{Of7g&< YlC[J9g}hup2ҕ="cIb[dڒ*449R8?k뫴dwJgjԄ8p9RN':TZ3d_쑭-H@ɒ (($'23W.ӌ[r5z[TxiJ/I$A=jgN^lmN7BN)D$RiR54LŌ8} G ^ԬZom)y{jie Zi%(@HU7vr9'Zf{w\W 胎j((+*j]o_*]eMUEPh:?M&'ѓh:\|M>&'ѓh:\|M>&'ѓh:\|M>&'ѓh:`paұ!4d%!)@p+d2|MZ+O'ud2|MZ+O'ud2|MZʚ[Mk+j~z9nip2-8.7.1/share/nip2/data/examples/businesscard/0000755000175000017500000000000013351443023016564 500000000000000nip2-8.7.1/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg0000644000175000017500000005646313351443023022777 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?'֔pxJ P=3GGQJ:2iFz4,OJ֓=0sItN9<c8Hzր m8`IgӭGjZZ`.0h#'_ΖRQA9 1-&~j1F)qHr!?@sKZ"sրqHxȤ(xEQ׌R'ZZC@ 3@KIj;@ zS@Ϩi> 1K&9)jNZJq4(})9=(:\Z=P;G&OҎ `3I@ AПJSHG87ZLs8@H KOILC N4R\)旽9?JSi0AҀ SE>@zRcR(A֗4}(# K):_4u){;@ ϥ-!$}(3'ZpIs@CH =iǵ's@hPZA tIz'{Ҍv(O֊='& d`Ri;Қ`74Rɤ3FI]` EZ1L.H`J9Hp}(hZCH:S"o=x.)1AQ i9ޝ֛@uKg9/#G^ih贆&CKF==(84 9)E4GJ\g֗xBKӊ\CPׯJ3Oʓ;Sך)(1HibPhPh h4p !@ĥ)֔JyJ"Qڀ/ғE (zҏJLRc"^JM)sQ1):sGoQI@fs%"PtK֔t uS H{RCp2hS)bރ֌fPc%wN&oSA)qGj@4RRwJ1K!R%NQip:PjLON(is@G=?@8)(q B>i4ғJ1Ƞ80)c$Rpi @1֊Z:uQ =ڔfx8t4ȥ#4h dQ iq}GjhJ)r)ړi?L4Q v)) c-&9zzҞ;g?Jbbڊ^Z7ӱR{) cN4q`7QQڀitA֒Qޗ'Qii1i.9jyJ:GNM 4=isJr:SN}(z1ڊ(ғ֓<恅/O=)X$;)ؤ(RwO\IHG8(;PG4vLv`.3I;@ E.3ILzsH=(#.S1?(QiiE>4)~&~ZMԤ;yF)p)ҝc'LfP341җh֗Ac4S Hr{w\v-Ydl)vqؤu h$v4]JT!8*) ծʔ8};@ru=AF$OrsIҧzs & &9I|X帕OUO ahPQSG<3 C\,#d GVIS؎*]ٝ88;ZdFjJ!48h@ ;)@#`KF)pE&EHSi;Pzяj^ -&G=h=(A&zKNh)hҔ)1 ^)z% ~4󎔘斖1:֔@i1Ki1@'yϵ@ Jqc= ѷJ]sG8!;ڗPGbu ޔwchPqu4@?*^)ǥ::ހ9\P=Gb3\׉m,stŷt@7 8~M!Wu vF:*V2j_(x '4zqǵ0E.3I40ipNi p?ڂiO!⎜ґ.8 {iCKbJ=Ҁ 8tEjJ2sA4Aydt@ 8`ҁ (^pr;1PvgУ iNccOh4 (bQR9 }(;҃Hhn8w;8b&zqN=h#"ޓ'ҝzNS@7n@w!D)O@|:\gZB &;INI> K0@9Kx4KvsNҁҌ/^@A('ޓ>IdD141ޱ|MwجҞ~3|Zĭss,՛5bj0k_JMr求Թh78Z鱘ɤ[!y1 zOt,tQҪ&;$Km0(ˌ?}?w޽CWh`t~ oSN(7!nr:fq?6O7zTGԐ;ק^ 9 J93ҐSW-'6qL5I3RGҁ3U@u ڴu\ŇLzRI)j!/%ix8vs#ff8 R}M {`(A94))zS'٤)yIN8>.qP"2E0?J;N#iy.9#`(7mX_KU<'񞆧]j;❏c0p`RqKu!Қhދ) ۿ:p=) \ԥȠ/=)q֙#B8x*g,PNxPhAԀtNޜsGs@exA8ZZFW;.$F+, 1¨'ҼRk&=v,TVa[Գ~=qrrsQI^EM\)ۃQe+sG\Zq.2=Mi 6(#8s $9Ov'^!\2>\}k5L%SZKHuf PqzXxcqTO5ҧ=ieڟ" T #3۩4GLV"PJK鉞Z3"_ OnUSv3Z 3ӺZ^s]&hg>vh(&8"; RzR"=x \}i ץFPG)aR){R3F:i1#SژXh 90sMҞNq"❎94 fG8zfuasH;fOZm E v(?OZaMJG8(B%)pq\)çAa'(zK}zw zqӁ4q8R~i n8cq89=^dsF@01Ewm0<};N[>kuHU`<曻.*ȵk ш9?LWcǭzW>vvqק.Twv, b9Ҥvmx!H"ؤOWYzA8 hU=NSk֮0ڸSb2X~1RIZs7FGoJ֪Z3&ztv*XTD !sHcD݁#z&ǡV9ԡ~۰CVOcp;^_> 3A֟S #lcIN& !㞽Þ< &h w8ҁK1CoapADD&T6` lj2*HqVs[]Hi\\J4=QƟ?]lWRgol%du?m.vG$t W>ݦ6uWZ.;Ϗi[h $pONË hڙ0We]~Q ?b/-$.M]%Hdd :Tʜ:ֶT*cYd}k;ݼ#/ڔzL VF|f8ϭg޴qǽ 5"ڥaGJstȻ^~@9;99޳[ N5XTќL@QOTb+Pp:W=Yr<0?t@q]0w2kQ;80EP 6㎴=4 ^48ɠ`J&GM`?! FN@rZ; F%))'uz*-$_aRM0KTVҫbӘF npՉұ1ɦJ֜A(sһRsI&N3֚F9`qA84(┌qEi4u)qяcփێR XCq{Zr1$PzӰsҐ{S^Gv ⎸9PN;(9)Fmb"MⲙjySsIF,jD9#&: STUʻ!uhyzz/?κ(c90޴ƍ<lR2){ҕ`֗h!EaVt<y#lIa{٢t:8ǥF+$0P92 „}Q O *Þ0q5UY)l=+w䷈ԃq^rhǵ ғSqIaxg z|esԀrF~a57y3H-A8$5z | 5rsJ)6T7JIiYGp;?i(qڮLn+{N6Ms+ _Xw3ۭeRwи-nSMnX{9E1X89>niA)!DpkVq+2.Z-98?|Fj4P4y>3@ՒgRIzt6 QsNh40N)HǦhFGzSz_&yOE}z:u/5ÖP[-H=O*U_nzCfw9$!5  ӚSRKe=e$U9+7+ұ  9dRPc94I:S@i[A؎VjgP`/5/{f̫v_dK0qޥj<H}kti6k½@9aoZ/Ҍ}Lcq[܄D3zRN)ph8zP:ӱ4mjB35H wK6=TMo Z4X@xGlw,?qf7͌R'ӊckq\[wɪw@'ʰ ?f:::Tgw\L1ۥ4\4`皐.H)\ p^)Ib֛4 yH} n=i1R1I8xi1Ojn=uQmN4y4,;hF(8dddӱ׎iq;1"%r\όao $9v'i+$~5l8$}J*5`RFirrzRP m c49=(#]r*["vy5c PǠp3JZ8O8)1NY?Jы5hCv5 hFx֤-Pc|t:N fKZn3ڳfD)iqKyȠvNi@ҕh #;ӻӂ90/^kg+k&uWLgQs'8=:}h`j))B3$ӷ@J859IA?ZFbGF[N':lI9@4cZr;2I2G?^P>n"F=X מi?Z皑#ҐC333?S$sȩXQ&FF1u]j@S@Uf"BTG apywpތ2FcqLjں`2i6Z`J {SqS`p}\cJ?҃ @G]dS㠦@ n|ԝM"M#x␎A)A<)vt;d GpiqJqqJA Ny`4wkZ_3\AO^ \`Hsa^gic4dd@;& Åu]zΙA#uKSV%Y9Y!HI2HE4Tr| uwn[ȪF軣-v.R‿6DqA=)=qz@F'B=)HM0ZB)ҹҘZ'֤=)NqN0M R  @8 gOjzF\ӆqp_~h_ҟ4F)BvGZ6&QAlr+u}3z`EG~k5Co3Jff8Q@1Z3 ւpqހtguEt4zqG88)q<8$)>S0֥5jE(l~ R L@Xb)`_J|m\W`⸏@>,WRG^+L'ɥ#czv)歒'@iݑӥwNLʽi1{m\Ge]>N+;0|;j1O6d m=i6֤4࣮i1Ii,F9JK_hr?݌cGиc$/$U*5یqԱ*9X"v>VpZD\9()ų *IU ֣!y ةOQ7|z16HW4=)F}(1`gS :tKJ3P1@Ob) p~ ֚)I#0&xR18#l̀OxVꖑc!Pxk7dzfJF:IWM1@tP~EfbR|FDcqA0j&8pj&F2qK31n9bOZr旜QI49HH( bAQ99.\W=5a)Co^qo_-ܞc/j~m`GQUu'6Aޯe[b1?= Ev==+Qsު[1j2+@b%UAc­Gu6Y?wV{9UrNLDLxqiĂ~i3Is@dR*^WJ=S/AQH3T8FP&S(.t4ΟրUi CV9E"dqvb{m SBc<6בOɠ=*FE›k zQq#/HFJBҤ׏NhFOO—oniqN 9qNNۭ(^qݸڔ v]k&l7O^)'=)N> =ݽRc)Iڀi?^S)H0)ڝל隌ϩh1@jy#QQkkkQ#xf;כ|1yqtL;WKqݍxN(DZdz~qǠӭ 1Pj,S XTB*+DD?#h4jvpz xndP4JS'8y3MIn:SO_Τb{Hn @QNYX7O!OJ P")8W>U5Y ׷J #ҝJhϥ.:zgS\s 5k\t1:ӱ)HI##S$eGizZhi\Z3M`EqF?:~i;Q :b~_qڟE QqOQP ٥um34yӤȿ]LW) `a30j$Tw\Js֔}J@! ~4$R=*p1j?1J 4 Ap)Fyp w/qP?LP3KsH08!:PRG  ai ɐdHTb'B omHjM&83h=i9֤֐)F #ic8==)RM OiBNۚihZp҅杷OJ\q.9HVtoqo𬍁JZk1O +~L)2T[i'${Ef؏Թ8LRw(<'b8kr)HN(@3l{ISw{|Ȫ1q\In+>XVDymE-U}.)RVP_n?Zg@1HNHQ2ܴHyIџ֔@l[>:SZBGC3֓zvi anr:f hn7q8 8 T Pr($4+s@1KL|h ^):fyIPyoqSODsMnONiF9̈ʌ⑗{)1ҝD{ LqT;} 59<րv8֜Ԍn *AN|杴~4>xC.3c ~4 JFo )>Cnk[^nyz'ֳ?JӹQ=,dS&k"yHi q%``SYE;ZCddsҘF!OzzKc'v`V[ԝiqa9= ztLMN1On9&zP ZxH P?;N0Jw>Ը>:Qq h:ӰsրHFu+~;Rsjn3kFW ;5ȄzYc5J1D5i;R~ԲiJqLcڄH)OLrq֘ 0dsFGI}(p (R4Ԁ(<1ڃp) ǧLSZJqjKAc+${x,Mgl|UO_GҚ3 NSmT#5Ʃ dC"'֣2j[(:}sHNH'7N) @) t" i^)柜ny=(ӎM&=@9JO^LnJpF!^2)ST GN#qL4x1Ml9aR{ 3p7AÉɨzc?<`)Za#4L/'饱ңf4`rhۚP8W$=NeEw~=M# L*'M"'9R13v  wKޟA~$R2!0?{?j{-#^~SFRPiԃ>PHc-Hxqs[°y$w&Մ c N:Re);)8$r{ iݑZ2zqsJzC'4 NsR@x>lc E'\dsG/IйJg=/ގzw GJF擏 wRzsKڐ|R ɥP1x4I@<Rr)Oޞ)4H {S5IJ3Jld)sHOjaLcMa⁊O74SCJb:<ڗB4{ޝڪ4 \s֊Q֓1F)ph74ցK" %b{JːCLץM\k6:ۯ5+iqܤAd0 O4&J 7'֘ PMqZPpSqZQ`83Q;cPy6KQjZ:de班 gxY>ٱp/*u-Tq(5o3x#җ) ;a^\klEb^5HkQT0W`Բ"v9d~#4␄#qA4f@i;ȠzhGs)B@ 9ǭCfAnOJ1Kq֓zрM#{R ;Р8`CҤQcJGw@"N`wv4]͌9ȣSQґlS<|޴cך^r(a@ zRm*.*jns7pEHhQK(gO8ɤx#4dRIZzQށqց׭0b[Q9WOZ n!ui) yPvO4\mhۜԇL瞔L;HI oq -!M4i)s@ÿ.yڋ S { (\>gBI;wt8WC+z?u%PR> i`H+z64U5u=9Y zS c`8q^8yȠ (tu&g ֽ ndXryz6zI +4&L߉`O֤dWQGCjct{xf+➰yᲣsUP2kzSdbksm*8אOM)k+.0oͦ "GV[i&] B5+bE8Wo?a&v6h'LJĺcB8;1QVrM|Һh3{RciLB@<ޙNzQ5''9=)Xd34<'{licLiz v~iI3IÏJhWho $ 3҆ 1`WS2SLfiVJ{lf'blܯAcCQg^]G\BD赆S^6dc L74C[v7ZK!a*2v dF=hտt$Tfzs?< pVQ W3D_G<\.8Kޛ@=iԅM1HT皛M@$qMv֬lIisR"OOT=*uMv様vpSRR=)pG4]S.) *{Ƨ>mr6ot7ټ)\˧DXt ֺ RlZFTOb1D=Vjk) qSs1뺂O5)~2# -kW_=fqMldTOuٔh}9,|8n0lƝLj2  WeKzsK9cc^ ızxqć_s+㏟W|wHUKMUg΍r)D9[f~rjxAl';](ǵ .y{K~OAWb츫xoq*LRPԘ&?JJRpycQ@:IۚB?nip2-8.7.1/share/nip2/data/examples/businesscard/businesscard.ws0000644000175000017500000006237613351443023021562 00000000000000 nip2-8.7.1/share/nip2/data/examples/print_test_image.v0000644000175000017500000650504013351443023017555 00000000000000% q=j>q=j>^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ z ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~xnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn ˱xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtLtL|ȉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}q y^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰǰ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڔ7ڀbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* u|* uf"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF몮8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888<) A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A AGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGxGx_!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e`2e+MIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIx/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫉᫑͞2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j j d \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTG,3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ &@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@&@.3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@3@5@@@@@@@@@@@@@@@@@@@@@@@@@@@GLLLLLLLLLLLLLLLLLLLLLLLLLLO@YYYYYYYYYYYYYYYYYYYYYYYYYYYcf@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@f@k@sssssssssssssssssssssssssss}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Ir)I . I 3T  J K   l ;       = {  / =    :  . 9  k p "   E    J 3  K N   S    I "  3     \  I   T  C  z z  =  C  2s   H     ;  J  D j 4   C   }  ;     9 6 p  w  {   \ H , s  <     I +l%  k 5 < &% s   k  @     e [    $  *$  s S     l  b p J !    $ j  ;   d          V   = 6 p   6  ] x (  T   3      Uy S =e<u}njPac=R  x    >  &  7   C -n` > 1   =!"a5         G5 4 8 q  S  w   Q     H    y    r  q  y } K    c   4     Z      8  J    k r  t Q  1  3  { h    s     ;  B 3 j J     ;   B d      B 2 J  !      "     9    ;;~iz sr`  wy -jm@y;IzX VF    ?  7@HJFOMKLInHDEIMNQL@8/;Y:+4?'92j3!uo+I4 P\| Z*:b  *r  3 <sJ  e D L  Tuv B   ~      4  K B        <    ]   F e   I  N  I  P E        B a    ;   { J     z + 3   t     s     to   5     :        r   t zm      : q    t            #   $ T  l             c { c  r r m [  %    s    4T  [ B    v V  T  D    5      z * )  "N, |G fI)CV   x  n   i  dN      F N v Ni^      p'o  G = h/ / H_   -  ? v   L    #  Y k  1 i  1 i  x O    J G       z     }   z    a    ?  :  b  I Q  G  * >  1 z  a   3   | * p :    9  p     ;  { _      k  D  :  z {  {      Q :X8j T S @ 1B   =0 9iC4'S g   . - A>EGMFUMI I^GHF3FoI^NOQ Kg@~:9=,^4'(>n!!K/+i|(KrLT ;! M1  <r 2  - B u ~ -  ks~ <     B z 2 B d            n   S      A  {      j $  t  |    ME  * c   } ; k :     :  A    k     { ,     \ 1 n s y M  t*  B 1Qs 3 ! "  $    Z  Z [ K      ; | $  d  : T  : c   d   W         P~   L   V6    /  wF']     =  n     ]   qZ  c8  p x  /hKKx'RX  R \>o  , mUD     F   g      v'Z#    Qj /    =   N  n    ~       p + 1  0  p   8 z I    S U     r  * *   z {    <     ; 9 `   8 ; q   x    z  " ! 1    *    @  , J   N  9 3t )       s  I   i j     5xt z  0 g@{ 5 v w B   z zj:3 N  0    - ;EG^GOJHLIkG)FIJ&QNK=k<8=a*Sl3&!C!aedcKCK k" s -. < E;  { s}  ==Cul e k = < U  C ,   L {     J  !  \     N            e  s   > B J  B 4 =n m  ,  ]  <   K   : 6 D       s *  :        N M k B    2   k Sy#  {1"  f d ]  g  H   L b c; 4 % M d  t S $  R     A  2       #  W ' v s    ~ M     h 05 n p F  v         2   +g|   /  aw rkZ[ RAb{!XXa  iWo       &  Jp !! -  D ofvh    p         u  } [ c   c  2 q     !      2 M  \ D    j y    k  %    ,  t  u J   @ [  % A    $ $ !   y      ; {  s  #   Q  a Y r  t   i  t  r = D < @  J 4 <$p  "I ?1@ x  $ )B   %v+{Q  ;m 3s{uje%   F g  >[FOGFMIKPKcFF`FI-N[OKV===cB/4N/v,#6c;.k  pBc$b kzz =K }FGL  m m 2  T t % ~     < -  +       L , -         $ , #  T            t     c   k    K   = > D  5 W  : r  \    I q ; s  m    L " 4  | B   u  3  m33ste4 ,     W k  E   M k     z   ,  s d     :U)     2# Z    U d   M=v  @/    o 7 oa      o     ~    z  reUS  /a   wpIQZb /!:  o !  : `   rZ WX` u (V a_h        6       ~   ,    6 } ? h 0 j   k b 0  z 1 [ M  K      0 q    Q Q i     i   * 8 I  1 ]   ) 3 y     k p   " j 3 /  z  n   3    r   A  <  *  ! O   u  % 8 1 ` q 2  r   L J D  <  9 ` s=3  5 A , S { J3r _{ X      ^<EWHQMMPOH#HHK_DOOKe=7M:730.~#;lYW/jyTcqk*T0"$J+k = N L N= >   V D l  H 4   =  #     ]   U d S    |  , \  fM  T l >     $   < v  e     S   K   =   ,  { 5   5    J                  ! C D   D S j      c  m  n  ~ lbs  &&O  3      Y       d= }   [s  %U,    l    c          ?@ I  )  o   z a o   }  x  O D >   R    lt    Pz  7   9Ya/C:z+L   Q    !5  Z Y ]G0 =&< o  )' ' !     =  x    7  h  v    6 b J K  H ) 3 9  M  :   j z  U l \     a  [  "   b     j 2         c p      \ l  i   9    I                   x  Y  F      I   a:Bk  4 [ H{{ 9 ,s}[ u  s t  D " z B jx S q Z \\;J@S C u  n -  u  L)?HQH@,ML NOF&EaEH3IQMML?}49qD=0X>5S##Bv"!*ayRLS$ i[{  |  -  dBE DKI  v ? G M C  C J   N U O  -   z O     \ z   U   $ f   g    d  =            Q   *   ( ?   E 6              j ~       b f A "  <  M C <  .     D  + 5 ~  #  ?sV   ` V  n qn| ~ =   n   c t   m    d %  M  t  *        W   " 0  0  > y  i     /N   f %2  _! F 6 / >/  g` b1Sb[ V     2   q  " "ah  k + i wg  x  0a9& ^ n  }       .  ?  .  U Z     D  #  b 8 F    2            c  b    }  x q - S  + K   3 *   S     O   k   R  y  i 3   I L z   A 9   U {     *    @ 4     )     [[Z r  { =3[       I  4q{U= ;Q  C6 k4\ -  n  _  #=FUEEN*IMSOLG{J GF;NOHgAY;>c?0E5+&;`  R!I~]cL'<R ' ) { ~;=L{D }[ M   o  < - 5 t  ~t 6 = } % D  } t    E L  M  E ] L L   e  t          d    5     \    B   -   { n k       5  C ; $        D C     $      3 d ; |   =   1   v<  *   I   d    , $  u   L   5    $ # <  oM   $ ^ ] \   -     $N   /  7 :    R  Y    P `i     ]Z     Dq- Z_Sn`Q}      K  p OZ y w  e S  M   g Q O   Hp'g v  ^  & n .<     jo  6  l    4    < 0c   d 9    p      :    { b )   )    S   A    z 1   i O p ~     " w H  0  9   !    8  3 #      *    y       = 1 {   c :  Cr Y S <  [ $ BE2B[+< D"s` V^ %  9   m @UFIcE$JLMMM,GnHGjFuLMUD>8=$;d10#/#votosk*IZ#+jZ Kc=Qz5 <= ^ M>  Z u   _  M  O  6         V  T  U M   U  =  D L  ^C ^  \ S  '   n   U      ]       T        6 4    E      $ F     " R B    D 4  L  L    D  ?   N       C  s     ^   F  A /       v u n 4     %  X  ,  <   F l   K e      H  P   W  @Y* h  ( 2 r c \2Zv :f   -& IGc tj[;TTJA6 4 C Y3Q aag  d     XZ  r Yv /   h ZXpPwF   o   {  b D   ?  b  { 0 O   J        :            P  2  {      c { |  K   y   |     a \ * d    4 ,      s       :    *    0   9 S  t-   S W K d   * ) 5   A K4Z 2C ! 8 ICB*`  d  d p  >GHEEIKEIMHIGeCNCKXH]>;?:31-&!|V*p[Ut[`Z% b#:=)tT E  ~ }%u      % v  t  7  D    ^       5             n U  e  =  P o  % ,     O d  N  E   m M   >   E    t 5    L    = T 7    N  L   =         M   D >  ?  fu 7 } d    H T X |     g @-   ~v    6   o       E         `  g   J   2 " Me,+1   3 w*) H4n   8 Zjb23Rq9 CLc|-{I   P!h  E\  . Q pa "w#  w6x    v  >t   j  3     # |  :   A  +  T b   |   ,   R      T 9  Z 2 3  3     [ S  p    I : $   Y     {   + T ,   ' \  A   B  j  c b?     {  0 g      zl   J   +  =  I 3 *3!K;P    {  =SE%EGJHGI6LIIFlEJ$LG=S<7>3#4)   )?   :K=nmK^$-uR:eAM 7  O H  _   P ! & t >   >      0    8 W     6  X & w Q N    X 0  _  `  Q      ^         (  Q I >  &           i  G  9 X   W         x G  {   G"  n   iJra  *99 +lr1;  b  *H  1 l(/pYc"571s4M5 t08*R'DO%\{:\ ^IS | ".g UB )[, q3"Zi~v9O   l :=2z  < 8   H        ,   g % S  3  -   v    $  ul      M   ,   c   u  l  k :    ]    , t   * E     6    ;       -  iuF    %^Bm  ;      ( :  , 4BzE    6| {  [{r Hl  w     ^y? EGKKIG(M#LH*IOFGKKQG;U:|>~<*4 u2x)$G    E ? hbD Y;;Qv   )     c   1  r @             9  [   Q       A   g; =  _   _ f HV ^ `~\X][W|W#qR3 T QKF&%%$%*'"'8-,+N..+&H%y*-(2+/O0-1I1/:.[/103+3C16R/_618C87r;@>,59179:<<=7A<69 @iJ@CE=>?ECNH@IKFiMrQOsKlK_LOKOPT.O-K[KGFEoHJ,JMLJSVPFKPL_Q[T-Qg[SMFMRY W$V TWxRnIcNY?YSKZHIJpV1LOL%I2SZ6SOLuZ \XxUwOUx[AH+?:>?F3ENOH:8>76;67<U7234 77A205+5440S31$18#70005.4{4-1-p0FQ1D413h80p19O77l()&">$1'^))'(2D-K%#&0.+0C};3C<2,)=,s.3#0*o,*(+. ''j0)+*++5*+1 ./-$6*)G)1y+4,.*&0+0+$+2,+1*x/8! $" #("#%L*1M-&0%'#!"((,-,/,.K-((^%!!|$ %('*T/-O,*,.+o,;b -I1W)).{.+*(-O! $a#!*  C!fk]M-"&nb;DaFOESEHI2JZJKIFEmKJFP<K21='2"5}Hm h_P 2J $H B RC E UI Koͣbk$IS, M 5$v&(,0i0]514F<:7<9 ;> xBE = ? > @ @ CC A LB nEF M M L EGDWFmILdPaKS'MMMQ,TXgSQR!SIXYZYV`1TWZ{TS[TfU ^]zVYyZ\]K]1[\_klei0| hnefirdFg|^{kh~n h%fh8fqsoBqf hOnGedlfonzvs8i[RbedFeP_e"@9@Q??FBC.@|ABAA0BDFI#JH,C+@uA8?@??@P@AB@=@@CATC0CCAA\?J==H>X>I>??K?T@? >>>=<<`@D-=bE=<<(;#<S;:9-5K4Q5A66A678S78N77788s767'74689 4i5 55,5y51Y31023n5b6T566s44U5G68_4G4x56;46654448?84X735+4774y3:645=>=CGk</a-0111B11M1Q1G1123M32K2y222D2212222y348521I3231R0B,( *+z+//-::60032H2I0_2#/...,?,++C,b+0,2++:+,-)**01X5*(Z)41+u(''l&y-{')%&'i'h()*N-. *;(*R)** *O+.h1)4_5 1 f1 HQN]F&937< 2j!<W C F BHDE܁EPDeF~FՀYRSU\@F1bE|}|+ORRPSSTUTTT#TeTNzRSIOQQQSQRQRSUU}V)W VtV3QVNPSS$TUTT'XZ[]^]Y^]\\\]\ [__]b_^\[[\^#]^Z_]]^] ^`Zad7bb9c`_^ba`T_`mehgfezdabde;eAcW`e_"caKbOb?dfe9bc\ab cIcebhuf}egydbbffe'fg9glfge gff5e}deb`a*bd bb c eilhi"h-f|fCeede9dcVb@crbcCc?cc`bwbadcPbd!aPedc'a`c _V_\lZYOX[Z[n[bmn\YYSY-W\[ZXYZY[VRRRODQPQMNPWX+WTSTU"SoRQOQNLP9OpLJE]GG E]CEDBA@O@@C>>@FAC8EuG C)Bp@=>BCEA8@A;A;EFA3A@AC/B5BA???5?>=]>>===<X;<=`=<;><<e<^;::n:;<[;f;V;19 :9]978v7)66}566A78}88 78a674775567*527<6666F6734112224=444w4q13j22343 4645)4345 4 4 44w444]32W2L2G11321122[10/21112231102-2T3 122H24137115#53674%2M23010112u33-1z///R0}1t21./174T:o,,/2*./{00/G/K./.`-/,S,.+,7****+{+_+,f+*)())#&&'v&#%'6'(L'_-w('+%$###$G#U$K$&&' B\M]Hh;6384"4}#>Q?D CzDܣD7C~C}EܑF܅aS]eZM5|UVe OSSTBTPU=RUU$SSSTQNO4OQNPP@OQ@QOgOQRDTT~TLVVW:STSTTTWUV!X[W\]^^^_Q]^^$__^\]^k_X^\,]]]2\^^^^]`[^`V`ccdeudf[dcdcb`_g`dacc+d0eld_ncbxccCaPbKad|daJd5`b`d.befhh$fffsfeegpf3g*eeLhefeJh4ffh3ffefed eccc dBcCbba`Ne3g~hf?hi3def~db d3ed0ddd_e\cbeaacbbbd[ca`aa`_f`^^X^_ ]?[_h]B_{`[!Z]ZYYXZZ^*[ZgZGXUQUS5SPQQMR0QRSkU.c^aU:TQRP6VFNON7ML&JJzHOFGOCFHUF=EDB B@J>?WBaA)@ @LBa@AHB"B8CCB@?A@AA@?@5@BB@LB(@??>I?>?m>>>>>>==O>==>>>;<<&<;<<W<<;;C:9W86776*46?8_89289<8987768O7866?71798777T66_8O6565a33r524555565473554N561555-6<654454521a131U12G45I3 42[310011/40m1221!/0/12F0m0121382200111@1K30 2l201M1H0121<.//Q../ 0 /0s--,5./ .^.--U-a.[.R..;/Q/.P--- /T-,.--,j,s,Z,z,,,,+3+*')('=(Y( ''#(2)%'(!('&%$%' &&&'M({' <"OIQ9j8943C%Z5]kf<ޛA݅C#CۮE#CCDEIFܓ$/#R |F   CS RCSUMUlTTU_TTR:R PQDPGOONNOKNOOPSPPRRSCTFTViU|UTVFVKVWX WX_Z\]]^^S\J\\Q]_N`G^__Y`_^^]]q_e_\_```_ObtccacdidebdwddbbacctaGduccuc>?r>>t>2=>>=<A<<<<K<r==3<;9Q8Z99:#;;a::;;/<X9G9G::9z87#77|9<9:q9:M77677666d7556789977/6677#758 568278276G65544A54?4374\4a3'21\221e0.161U00\/ 10/f01a21A0!1_21[1Y2451[222r11111C020./01x0100[...\-0c..%. .I.P--,-,-.P,//-P-%,,,--F,J+j+$,, *,*+,<+D+D+***G*x,d***{,j*^,+r*-*))*()*)'o&&'q(''(()_*,= {QK;4795652p=ޅBB1D,CCDCCTE9G~ERd\\kZL:LTqSNS=TUWoUURSTfSPOQ=R9PPBOO OOP>PP PPTQFT9UISSSSSS>TUGUVUVCVWSX[]^]\]]]]8`_ ]` ^]^]]a]^a=a;^^]_@`@bbbyec,bcc7dd"d2dxd$eQeeclcdd*edoeeefgAepgbgRcfifghVhhiKhgiii@gWg]ghSigg_hi fhiQhiJhOh]ffgWff!edeeefZd%eeedddeeedfgbfeefNfeIfghhghfg9frgexcfjfmgmd}cb abcDcs`bvan_`_\1`^`^'a]k[B[@Z]]^\]{[nY[Y[\[[s[[rXXkTUG[EDbFEDECFjGFFgDEJGVDCaBAHC6BpBF@AEBC@PAAb@}@B#CoAA@AAIAA ????@?aA2@5>==?g>>$>?#==>>&<r<>=>r==;== <K<<T;<O<=<:;<L:c9:::::k::N;V99s9x879 99w9E:d78:{:/9"7 66678764^74889 8/77|625r5B56\5o3336`3315'3x24r22x10X000 1G13w222A4h34l2 24373B322100M12{1B11015121(12X12=0U11m//Z//L.///.P-/F/./ -/o-.c,S-%..-,**,[+M*'*+h+6*w+f*++p**+m+&)|)++9,+,\,[+*)))****)])K''')'')!)[+-= T L"<F7P;)7>1 /n?AC0CdDCCoCEGLJXFTJUc !\R;RTQRTSTSSaQQPPQoOR&PPoQ/PyQQPRsR4QEQzSnU(QT6SRT1T2STU|UVrUV}V4Y1\|\:\\\B[\`)]o^w_``_0^^<__N`_(aa)_`k^_`_b_b!amabbkcSbra.a1c cdNedd`c^eedXde ec)efRg@feg i;fiii9hiiri|hhggWh~hEgZiGjihhigfghf]fggfefeeYdcdfdQcccKdcef5f edff:hefjhifgggh gg/hffee fegdlfefddAccded al`c`bbh_7`8_d`^s\Z]L\] \^|X_][#YZYZJZY3USSNUUeTRjSTTDSxS@XVUSSRPPQPNNXL=JJKjIHIFGGEHeJ,GFFjCBB:BBCE/FF_DD&CC DEBmDBAB%BHABBBBB*BABwC:BBB;BBAp?C@@O@??@B?S??@@R?>>>J>Q>>Q==[==<<=v>+==>=>e=v==x<<<;e;;:M;;89::O:::9_9J:$;:98a79::^98887888z7F3D67899{99S99C987756644552174O5K346!43h4222!2q254\001)001q3!434b326.1222(245 22b2123/032241X000001C.1/0H/-W--.e/^/P,-E10.,,***!))+-x-]/|--Q-S,.),R+"){''****n*$**)H()*?*(**;* *)(R((,))+`++.1> SMY>z456.#1l@C BzC|EEۖCD.CDFc~Q 7$>Dz\VpP%/PQPST TTPSgQP RFSOPJReTTT[TTVTXTVUUS7SSUMTST)TeS~TkTRU6U8UU}UTUWY'Z[6\\1\p];]\\-]d]^^^}^^_}]]``aaea`___aea`bbedZccbccdCef2de7ddAe6dyedCddWcLdggKhhg h4h}ghikijoimighgyi>e$ighh{i9hhhggiFhgggEd-fBdebrceddccIc:cbbdBdveqff?eydde{gdgfNfxeJeddCdf(dd=a9edc7de]edecbbBca`%a`Mb`a^]__^_]\]]Y[[r]^`]g\$ZiZ\Z\ZWVWUTbVRSRVCT SVZ*X-US'S(PP8TPVQVPFNMKKJxK&J IiI]FEAtAAA\ADAAJ@AuAB5ABA@??B@NA0A)? A@@@I@@I?J@?G?A> >>|?>>>F=>>%=(==??(?h>>.==`<<G<;W;P;S:\:S999r:)89889 9:;R98 98887f8/8999:Z9)8/7750679=768l8|937 >}<N7|6{55]56\5_45!67J7554]44475 33X32h221a11211e2612j3/324_4354543]334222U3 433B3G4>201\02u44g2Z2>.P-,1/-],-g.-11./101g0:.8-2-h.-+-B. ....--/--F-++[, ++`*++,O*)*w,W+g*)())*2+-*:*+,+S*,/`1Y> SOQ<u8U<=>/y 3lB4B*C۬D-CۃCBB۔DF{TLrR:$kFL?%uNRQT`SMTSSSiQGPNOQS1TTU TRWXVW,V|TTTSTTTTUTlU^VVU.UUVWXZ^Z}[[\]]+["\2]V]j^8_]&_]]C__ba`aaa^aY` aadff=caIbc>d.cdybzbpclccme}ddcdgfff~g7h-ghhhhhhi_hhh0gh,hYW>WZ[%WVXVWUVVXR!SQV8T}SVX$X$VUSRROSTuP#QWONJMKcKK]KJsJHH7GAJ@k@AABrAw@A9@A@@@q@@8?@ ?@C@q?Ay>x>=>>K=W===b<=>>X??%<<=.<?;;P;: :@;;;;:99:x9N899999:49n99878u9S89)997998889I77}7676777_76655566B7#7K7766U4455K5575433232234_434I22%2^22Q44|43E343 4234q33x434323B2332210/!////00@0M1 /0111%10122f2100.0'1 111`0/-/k-..-i-.-8-J++-+}*5)+&)+S,=,R*+ **c)*3*=(N*V)*x*-h.f/9D VN[>:::6#0nCNB"B;BڿBC:CcBCGEܲ}va-L#q;C[ ?+ ,PdQ9OSSTRRRPHN>=p=>E>A>? >?>?>?>==<=<<v<;;;;;;<3:::w9:9}99:~:9::9:E98#89"8j899o99%8p78879t9488:878q88876677C8 7K6K67S8878z8268:576444H32W12[313V1223M22c1>213e45z4A455>3B35)4c3623201#/:0h/2W11b00I10A/\0000V00.a.z100X/./'/ 0/000H0Q/_0/..//..y.v--+S+,|.!-.z.,-D++S+(X)*],+*^+V*(A*"**o,O+*,,2./2@ WM;:i>I;X3!5MrBXB\BCBۚBCBCD| f^ S:= j=- R$PEPOOQ`RQQQjNENOyRqTTSUSTS"SRTUEVUUV{TTHUT#S_TUTVVJVVXUUUgVV_TVWXv[\\Y[[[]O\]_aUa_Ta``aC```aCbabTaaT`$```d`aa`Vabbaa+`aaas`dcdxddf fdHgvggh'gfgae2gfeeffeefdg"enfcfdMf>dgEfeeeg4ddEdcecde6eye5ebckddpddad%d>ddd6cbaeoeeeg.g0g?ebqeeedd$d0cgeed-baebcbb[beaUaab_]bTa`^E_=_=^C`p__^]\]Z YZ2\^ZZY2Y^ZVZY*YrXSUVtUUNU`XXV4VXVV WVNUTSSR9QrPJI&JwL#IJKKJH3HGHJmFCDE1CEDDcE'DCXBBqBBXA+AAm@@A@A@AA.A~AD@@g@BA@AA@AA@@@h@(A'@@@7@*AC@=>=>>F>>I>0=Ab>?@;?@`>>#>l>Z=n===Z={=1<4<j;;;p;;;<;Y::>::9G89:9:0:9::@:97a8888h8Y8888`9k948c9_8/776S7#7767782866H7;77C78 66c6q6>5r560665q454I4 4F2d322Z1r33223245544323|3:35n54=2221/0/3/202111252013;210/_/./ /\/13001r1w.".m/--g.!.&++/.X.g..../o.--.-=-G-6,C+*M,+y*** *P*+^)+,F,E,0+-=,,,-v/%? BU N?<; :5d"30uBhB,BA۲B B!BjCFDOE||VT$E2}`5D$M x0 YQPNQPQR{S OOSTXRR%TSQtPRSZSTHU?UUUUT RSRRSTUUSTiUT6UTUT+UWVYcZ\]]]\\\^;_bF`br`^^a_`9_S`{`Nb``K`Q``8`L_g_``aaMa`A`^^`^_Dabb@ce[fedDF`DDDCCrBBBA@@qAA-A5B*A6Az@@Av@BAA'B@H@sA5@AAv@p@@0?@@v@p@7?@5@h?@u??CN?>==>== =>?>>>.>]=>e>T=<p<<>A<t9:q::;;;]::*9@8089A9789R9u89u9:098888S7h678(8W68867767y76.6877?79 555<77D7W644x7w57494n35655,65446444n4w1322B22B25 45044r453354H5r44'34A4?1 /00T+,/;1W2,1//2)00K0/0w/01<02=11o0u080//.//A/-/I-b-&-,m-,/../////.e,,F+z+,,)+~)**'*)L)_(?(*^+++,+-?-W,-,/: bUHJf<q;3j;54tCݓAB|CBBۛBBCD|"EZ. K\ * PRwNQ?P+QYXWnXeXXVVST,UTSQJUlTTTP%QKRQ_ONxNKgJJHGHfF:GH~GHqGFE?F=EDDtCwD+CoDDBBtC!B(BdA]@CB)C7A@@@u@o@?@~@@@?q?@ @y@m@@v@p@ABwB ?8>?8?2>>>??T><>=|>7=>=I===L==^<=s=i====?==<;::95:t:::(:J89d:b:8998>8858S878881999O77m64627)5w6788967654556k<55585+477>5458857644434'445P44343,142t3i3q11D1S011=23_45-3374345)5+55k232311,.._/,#,m.i.15M/.--0(03/=..0112.M//g/0//?.B./A/+-H..--.-0/07./z.5v.[.-+,;,+,) )*U**+ ()(#)Q(Q)V+,-/-"-,->-.0O: _TBK9;95-2^vCOBB۳C;C,G?C|C۶D(DJ{T$D})_  $U]31 VOPNQ2RRQRONR RSTTIRRR#QjQRPQ3QQT ShR+QSTSRRTRQQTSUTUTUVOXJXYXZ[]]M^C\\]_cob\X3\v_]T^^ ]N^^_,\__a `dJ`_W_^_^^_``B^_H__`a`ddcb{dhcceldcddCdd dDccscbbAbccL`dUcdDdcdeeLfAecedcbdccecfaca`ZbbG`b{ctbb{accZ cN]acdcld4dBcdc fpd5d5c:bdd"bcb``__|a"bb6b_r`__g^]5[&Z&^k]T]\[kXR\}^}\\\_.\\Y^Y[[jZX-YWVYY#WWdVWUUSSaTVSJRmR5R,Q]QPQQS#SAPN]L\L+KKHHhG|FAEHsGHFEBD:E=D?DECCrDtCDCmCgCBkBA[AAF#C1@A*@7??v?u?@@?l>?@?x???H???{=^>=>G?2=>=\==e>====<<K=W=====,<4<x<7=p>z<=o=>7=> ;<<;;:=:;;:u9t999h;8979:8: 9y98=7777T97_65<3567/5o33a36:7664I46573455645^6F556D955655555c34,324$22=2m2"2210/1)01334"3433333342114012j/C-,x*/>/++,-R/0/C--11E.C..A/p/c/)/{/4-,--.;.0./=,/:.4.z. ..q/|/.@-.5.. .p..D-.-,++*)M')+u(!('(]()'(S)**+g,f-)-./m01G6VL<;+=IAS3u5wE,CCuCDEܹCۦCCܱC܋{)k4#fSD^"JlS1 ^NPPmR6R;QQOjO)SRRQRQ$ROQRPmNsNPPRRRPQQRRaPRQQOSnSfTUVVUMT]UWVWWTZ\]]^t][^s`=b.`_L])_^[][\]Q] ]^^"__` a;__^_`^a ` `H^_{]]`_>`bbcbba>accpe8ccEbbbDcpcw```cFccBb`bczcdeQeffee|e?de3ccc\bc`dcuc3dcGbtac`akceacldWaV]f\cieccBd=bddbYdddzczd&cb4b!ba?a`5bbdcgaa_^_]X_n^r^\\\K^Z^]]2\\\Z[!XYZZvYXhXaXWUWZYWWSQRJRkS\SySQ`ShQfRRRRuRR`PINLLJJIHHFDFIlHHGFED@CFJDDvDnBCzBCCaB5CBBCCBQAB AA]BA/A??6?|????q?l?]?V????@7?:=>C=>>===>H=#=>Z>==D<<<L=<c<= =>U;;p<,<p=s=3<<<<l<;;<-;;x<2;5::;@:;:::r;<:{8899S976D557w6x76X555'57875357t7q6.56+445f664675w5p6n756=5555671675634#4c44c5b544'4 3S01#02#2r144%43433#333r4444l32s23|0A1E1:/R-,*,..-.7./F0n//D-. -.//>/o10/..104-C.u.i../D0/0v///<.Q..5-./?.E.~.7.?.,++*3(&''&*('''(@'''('_)*,, ++,.q/14T9O8;5@=/\0yCB8CDۧCCqDCE&E{.;jK]k lF0 ^LQPRRxQNMOPPR ORPQ,ONRgQkQ[PiPoORQ[NYPOQN@PlPRQ`QS%UVRVUTTUVVWrVWXZH^+[[[Z_{_|_^\] [^^]HZ []N[\^[]_^N__` _@`^&^_^M^`F`M_V^_A^V_`k__babx`axb8bc5dbLba^a`a`@`b^`TbEbaDaJ`baRb dbccdBeCddebbaab_c>bGaa@`^__a'b`cahSRRbb8c4bbAabc}cycbd?u?+>e>>P=>Q>>E>>H?>I><= =Y=<<V====<;<;;<<]<;;;4;;;<<<<<=p;;a:o::z::?;y;;:::;u:@::i99I9988w7q76778567T66 677/6569666A555p5465y4C56z6=68"665668;77`8676\88N9d9R755444433R3332c3'211r234432322)1=0/00//*(+0,-1#0..90p-O./0t. -.G./..7-z./E0-.&/2//1./0/.1///W....?../ .,*y+-()|(()0'\(*&'''#&)+$+U+, -'.0.025SN ;8<8?2i5fffffffmeef(zEVKk/$'. OQRQRR%N%MiNPPdP#O2RPQ+PNPQ(P^OONQdNNNOONOO`RSRSSUTRRUTUUVTW_XY[[ZZH\]_^ Z[^__^UZZ[]U]]^\]^^U^__a__^__O^H^]_E^_|^abbI`aaa`abcKbaaDb`__a^t]`a'a__^_z_acTbba$d9d~cd;c`bc``_h_SaL^`%`_s_^_a)`a_{ASG+^_bc7bbacba`aabba2aq_^^_``wba_`+`"^_j^_]^^^V[&\][]\\]mY[\j[ZZ]YYYhZ&ZYYXXY:YVW=VYTSSSTSPQQaS8OSRQPNLNM!M+LHGIiGjI*HpGIcFFF:F&FDD-DCCBCD0BoBCCCBB=AA@@AA!??@??>>=?=<=====>>@?@>> >=Q==A=I>M=P<=<=;;< =;::;;;::n;h<w=<Z<e<<<<j;;d::;;(:;<:V:;:99999:::9:77)7488:,8766j6`66{668|9c87#5>5 556666655~5G4=4946*7"88.8.976Z6U77'77S77S77 6 644c5544#22222q3622O2 353b23221///1(3/-,-h./.E/./{---.t.0//8.=.6.------}./..80../2./K1...O--/9....A.--Z.G-6*(|*+)*4)''&''')J)++,--..2+37VTOa;7<B1)6lᗐዐɑ A5<᜝.UL.=U%;5|- ^OjRRR0PRMMqM}MO%O8PPQgPP/PZP`Q^Q POtP:O%MdLMNNNQ'P^S|SS S&SnRTTRTRS/UUTU3XWXYi[\ \_\^^ ]]X][]][Z\\__W^^]_^_a^_U_H_a!_`U_L^__`a^a;aFb=ac2`a^baa`a`y_K_aa`IaaLa`bD_b1^Lb:aa_cbb\bd:dcxca`a a `_aaI_^`___^]^8`>_^}Sa` Q al__z`a9b~abbabcbtaa___1^z__l`^a#`__1_`_#]^]\_\]\$^_]>][\Y\:ZrY]b[*YYZZj[[WYBZXX{UXX=UU T}S-SRQPRQPPQT.RWQIOvO MLLK0IHhIsFI7JYH0I*FhEEEEEkG!DCCoCCCCBAB*BAA@a@b@?@0?i???~?+?>?>/=>->=?0>>H>>H>K>?>===><=<<<<<L;< <O::%;;g::;-<<<D =(<t<e;<<;9R:$9:59;x;;?:P::f9888:*:::G:m9#:S9.77:9@8O7756s6(8)987676G6z65s4i5`66l6~7r66O5x4J345557(7v77g666!56e66\6K578a6_6I66W7555^5)4v4~3\3n20/0>021/|/x/e1i.T.O/z/.E-+..x...28-,,-U-.//-|--+,y..0-/ .<--J/.//,//?/z/.:-..y-/--/.... -Y*)+&,p,+_,5)'+)+,*,,++,,,,..04%7SQ=~7c<=2g4ˏߐቑÒထǑᬑố#m*Z ) <*S* NOOPOPOL`LLuLOiPjPvOqPONMOZN!OMOMMLLNpN,MQ{OQ"PQRScRRcSQReR6RSeRSUVVzY^Z/ZF[(ZY[\,\\p\q[[^ZOX[Z\_]P]]`]_]b]__^V^___`P_ _L^`_Q__(`_a``bw]U^a ^`_ba`_c?b aQa`T`[`_``_Za aa_M`bKa`ab8a`aS_^__u_ma`^Q_V`_`h_v]\|^^-^j\cGd_H^v`__{_`ac5bbabraaa;au``u\_]`_^h_k`k___^y^-^c^"\]\l\[l]f\[d\ZMZuZZi[kZZvYZ[J[YhX]XRYY[PXZXUVUUSUTST{QQONNRP$RdPuNLLLJI~J}L2IH8H0HGzH]EDF,FFiF1DxCCC,B`BB|BAAAA7??c?@?@b@@@#??{?s?>?==>1>R>Q> >H?}??}>?q=??x=>>==== =^=;;<G;;;;::;;o< ;;;;z;y<<@\=*=v;;*;`::p:>:1:~:::587888:j:9:8997:&8=89:j:y9z9988888$777>6:4555*4656/6x66?4 4}445y44D535645h45]457666655455(5g4555564202:2t1O18211@01!111../F///e/1]/50d0..05/|-.0>/C.?-.5---9,-5-*-.--q/1///0Y0=/--.2-.O,-----./...=+H-.*C*y+T+h+,a+,-.,++,:*|+C,,-v035*V=P;9:;0}!4ߕ Ƒ|ෑő᳑KᣜKM#+* bQNRPPSQ QNKKKNNNOMOUN_OLO2NNO#OMeM^MmLMNO+PPPRRRXRPRkSSTSSQSS!SS,T4UUW(U[tVYt[[YWYZH[`Y6[\[\Z\Q[_R^_]^^^_g`V]___`O`G``_` a{`A^`__ `avaZ_ b __`bcaaGab`a`a@__ab>bacb8baa-a,aaS`K_`'_&\\A_]^_d]^ ^_^^G_C^Y^Z]\^[[0@e1Ff]^_q^abbbbIaa<`N`_aa^^`~_`6`9^D` __o]^^o]]w\l\p\b\d]$]\\[Z[ZZpYmYWXnY"YYZ\\BY6ZvY[YsYzY[9XUeVmSRRdRSRmPPPO OP&OPMLLYLJ>IKsLsIItG@G8FwEE}CDErF/E{DCDaCB!B{AuAuA6AA/AqAAA @@??@?@@?@?>=>(>?V?Q>>D>G>?~>>=>=L=<==O> =<=l<];; ;;T:/:;i>L;;y::;6;;=<;[<<p;/;a::::9;:T:::9`8B8=8 89:6:<:9:c9@8899.878999,9f9\99288c8Z6n65556a566}57645854~4y23A3~445w5*466!56%4t5655 57b7_56'6756!77 5\4-223!22b2l22r2k1y0/I/ /1b0c10110i0/081i1<0k00+0/./)./z/--v.,--.9.G.@. .r./Y.Q/$..v/I.--Y--]-R..-- -g--M-.),*+C+++;+Y+,,H,-,Q,+*+u,.+,.2023pSS><7?:=4x#R6KfoS9<ბR)##3ULt)L[t*PXPPQQQMJaJfKPOMMMNML?K{N7OOOeOMLM;MyN|MpONOPPQQdRS)RiSS1QRSTTTSU1UnVcWYXm] XvY,[\]%\]W^][ [![Z\j]\^b]*]m\^`]\^Q___~^]^_`{]_M`Cbt`a7`C_V`B\asbD`X`aa`a_aa`$`\_a_`_U\^^ga`aO`Ya`_`O^a^f^_^,_`$_n_$_^b^__] \]\]]][TPH1K?CR]\_aLaL```R``=`=_F_`0]`h```a-^^.^~\\j\\8]|\\y]2[]];[YYRXZYS[[(X6WWZ ZxYW[[XXX5[[XZYV\ST4T1SvTSXRPOO0NQNOP:OPONOMLLKL(MJkJ7H-EDE EsBPEFEpEDgD0C|DvB}BBdB(B6BoCBBC{BB@A@S?@@?Y?2>>{>A=>d>??>Q?I>A=>?5?o>?:?P>>{>N=>=R=P== ;;;;;<<<=;c::;w;;<4;_:< ;<:::9:;<(:C<99::8:=9:h9:<4;;`:p:;;:9977 6d9#<T:998o7887 555a9666t544z444565;4|4455p5!4363565[4"54Q5556)6c6687 7'665 54\4V434$4+221<12-11d211/0110./+0}//10/0I0:/0/%.//Q/..y,.-..-|--C.../..-~,-,. .D.--,S,-D,-!,,++*+$++***,Y,,++*h++,-,,./.133WuS @7< 9O;1$94&F̑ဒJzዐc* HDcEwV  p ++KP8PQPQ8MgLKMPN:NNNNMLJLONO3NOMMMhNM.NNPPMNOOP3Q7RQsQS\RSTSRSrVUVWqXhWiX!XfVYZm[[\b\[[M[[Z]R^]]]^^j^]]^k`^]\^C^;^__]\```__Cax`C_[]_`__^_a __Qab^]^____V\c^!__b`_:_$^^^[^#\]]c]]c\^+^3]]]L\0^L]^B]SZ]]I\Z?DS]qB=J]O^c_g_]`^^____^_v\^^^_m]<]v\]\ZYY\\[|[.[/Z\+[mZYYZZY?9>J=>3>>>><`>>?>2>>v>u>=<=I<<;<;b<;:^9::::;[;d;;';e;;&;;d:;5;(;;;::;::;::99Q:99c9j8889:::|:V<z>6<1;:p:x9x878N9:98897987m67X556#56!44r332333J4335j52565444446,34_4p33456n786X57545m4%332223f33o4322m1111t101n1/y./../I//0---./0../-.N---.{..-F. .P.-.-.0.-.-- ,-X--,-,- ,,P,,,+Y++f+,h,,+2++4*C*K*y,S+)),D-0923*X6RK>:6>0\n4g|$༑໑= IᑏА/=! MkT$!!J "$7%%+!!)5FMPQQPLeLKKNMPfO[ONMLMMbO#NmNkM_MM&LMOL)M0L"ON`LLhMOvOPPRmSRuTSmSSTgUUW"Y-XjYYWXGYOXrYXE[+YlZY[Z"[\\]&]b\*\j]\] ^][\\]E] ^P_^^]^E^`;_|___O`_^_O^^`__`N_b^^]__^^2[^`]^`___&_]o^_ ]%]m\]]\^]^k][]f][\\ZZ)\ [\Of:720Hn[_^^\ ]e]_ ]_N`bM_`_h[A\^\\]]]][YDY[Z\ZZ\$Z\[`ZYU\ZXXYXB[Z7['[KY7XeXkZYxZ:WnX\Z8XXVVWV RRSRRPONP0ONOaMON P,L,LLKJL IJII GNFLGFFEEDD3DE(FED CdCCCbCgAAA???>?b?U@?>?e?v?2>>_=n=>>f<&>>G>?===~=M>?> >> <<<<< ;;W:; ; 9<<S<<;;i:; ;%;::;;<;;::_::e::n:9:9989b9:;q;-;; <T<=G< <F;<;49998C88P887!7766654o445'6Z6a5e443@334455446`7X78764]5f555f54346/567&87/45w65n43$23`3m4$4343-2t122&00:/J100./g/x..//./v/m/:.z. .E.D/..z->-m-,,F-.p-+--+,,,,-d--,,+-,,`,b,_,-,+,,,++,e+4*g*++, ,+,6,0,o*),I,","..o/<C 2\TRH>E>A:0P2`ᦏƑˑདྷVᘐؑb`<}\`7': E/    ILOOPPqLL:MMvNN5N+MMPMLM'M&ONNN-MM$LL1LNLK?LhNjLNM"NwO'OOPQRT+R$SSRSUVHVVWXYWqY^XWA[ZrZ.]\YaZZZZ\[\]Z.[\TZ\]]\!^]] ]T]_^_^Q^``P__^F]^^^^J_a?__^E_`^^]\;`^S^]^\_]h^^^_d^\]\_L\\]j\cZ[,[^"\s\t\\]]]]\ZZZk[XZ]\YDHCI\_X^\]^S\_H^]^__]b_8^gZZ\O^][ \2]\bZ[[`[cZjZZ8Y[+ZZv[)YYZX}YXX}YZZ|Y[YUWMWYYYWZ5ZQYWuWYXXV#SSuS_RRQQ_OKPOxNNNGOMKJKIJIIIH:JwIH4FFGFEFE4DEDE#CwCbAAAAAqCAC0A_@?@@_@e@@f@t??@j>>>>u=>>>P? ===r=s<<D= =V=><<N:I:P::Q:::;9:;;W;:r:%99:f:*:::a::!:Q::$9:_:99a:$99999Z9:6:;/;;a<<P<H<<;<::;=99O999977667b6T5555o57878j6z67:67z666256n9;^899%855`45d4%324b4-4455c5544$3f223l2t2)223 2354Z4+32c12a0-0j// ../..H.H.%.J-.I/ ../0./~./.l-. ,*,M-,-:,4,-v--.o,,.,,,8,+++,/,,+,,,,,,,,P+++*+D+,>+,m,,,-,,6,;--n/842[SSR@5<C90{59UőG֑aA*"$[@V`{iJMEPP\PPN LVMuNmO`N\ONMMKpMMNMkMN3NN5L3MYMMMJJBNMMLN-LMRP|PeQoQRbR,ReRPRTUUVV%XW!V6Y#WY8YY[[Y7]YTYNXZ['[ZYZ'ZiZ\^V]^]&]\J^Z^S^^]_8]_^_z_z__^_^^U__``^a_]_]]_`^_\o]r^^^b`__ _ ^\]]\]V[Z[[XZ][[6\[^[Z\[[Zc[YZYYYITQ>oU]]/\[]^_H_]^__L]^^w\m]1]\H\4\[\[1[+YZ%YsYY|[X<[(\ ZXYXXW;WXL[HZZ[YYb[X@VXaY7Y Y2XSVWWW XpV SSRQQQGQJOOPN1M4NOtKKMwK}IHJJHHHJHGG}GjHG&E4EF"BD2FC"CChCnBBgAD[BCa@>i??X?_@*?#@+@0@?s?o?r>> >4>l?>>G=;<<<<}<;=D=> >?=:J9':;L; 999@9]9::\99,89979t95:::|:d:::::::):.9;::d::::::::;0;= =H<<<:;1<1;;::::98S7888767W6g66s7\78b87o76655716)457726S7767p6i57332&252t2e24&3e3r2322u3d2-11013022%2l21:/l.\/O0*//-.}-Y,4+=-//-m,.-..Q..B.G..0.F.,,,J,--++,,-k--+,--g,.p-),},8,V,K, ,--,,,,+,,,,d**(*c+++++-^-/,,-- +,q,,D/L12F2\R_Q=8h?B<./!3a^ޑΒMϑkF N07y'tuDA + HO1OOuOyP\LK/JMZOO OM`MNMMPLMgLlL=MsLL%JK0KLcLK'LLLLMmNM1O5OQ$PlQRS`RR/QRRTSUUV\UUXWXXWWWXXYYYXVXYW*ZQZf[]'\\^\`X]D\]^^ ^\] ]]_8^q] _]_\ ^^Q^^_]a ^]]f]]^ _]]c]\o\]]R]]]P][a\ZZZo\ZZ,Y\ZY(ZZZZkZYYZZ [UYZXaOP@"ef/==2[Z\[["\]d]S]\^^\]\[z])\s\[:ZrZYGX1YtYVXYnWpZXWYYXTXXXWVX8[nZAZ8YYXXXuWfVX.Z`Z^X}W7X YYX$WV%TWRmS!QRPPFNNNMN;MMOMNqNLoKKIII:IHqJ"GHuG9GG1FdDE*EEJDD"DCCBAB&ArCBA@@?@LA:A"@'??w@>?"?t>>>,>>V=L=D=<=v>O>A=8===}<<<;K;L:J:9: 9y8899#9#:b:g9!8,9/99:::9:&::$:9\99"899:/9;i9: 9999:d: ::; 9 ::9988y87786656567]7667R77l7.7949g8777)655r668%87767c8(78r7.754]23%34b22%112312D1y1r1B1/0/00:0<0x0N../z000p091/,--Z-.-f-^.F.-.f./...,++,,,,++,+,},-m--#,+^,.,n*}+,, +@+,W-]+,),,X,-D-- ,Z+*,+*+N*+,&+w,,-(,-,-E-./ .2r43:S%RM=Z:6;.k!1җ(:[o᠒Qᙑᩑs]jLWEG0&9IHD@ H;.*ILOOSOOMYK5KNQPNMfJ>LMQNTLLKJKL}KIK;JKKKeLeKK3LjM`M`MOPP+Q/QQQOQRQSHSTUUW$VUvUVVtVXXULXWWX(X4WWWWeUU VXyXXZ#XUXXQXX*WY>UXX\VYXVTTUTwQQPPEPHPNM4KJMM5MLK:JIHlHHGGGHuHqGaFFDDD-CD-CC`BBBB$AB2AdA@u@??X?@A>>?0?g??X?`>>>>m>P>>>5==?= =A<L< <J===;== =;c;U::Z99@9H898^9!998e8f8958399r99j9o:g999Q88 888p889<987778v98z89M9U9 :9:897766"6 666.6R7f78587$878m88_9,9,9(76667972687788`8_8n67786-5`442r3=322222822B1y12K0A1 00l00O00y0t000M0T00/018013//B,-p.n,&-!-v-,^-g/./5/ .3-@,&.|-,c,H--C-I-,p-t.=-,,++-;+>+H*+,>,G,9,V,,,[,A+8,+/,S/O,+h*++$*++,,+0*A+,,l,F++h--Q./24?4:RR=+=75,94Yɑ]ᐒᑏXᾝWDTg/*7j0 wE U>'HuMNOP ONLaK)OKPQM!OPML]LMKLLKM*LM+KsKK?LuLJKLKLsMbMkMOjOjMPQPPfQRRRUSWS_S#S7V^UXdX%XX#XVXYWYYYZZYEYXYW[NY[P\]]\[\ X#V"Z[Z\] [\ []^x^^^L^ ]_]^^R___^_^]_ ^^^[^]/\[\\JZh\W[[[[ZdZZZo[[\g]Z[[ZZu[U[XZ\[Y\Z\[THPNvIO*Q[ZZ[] \]^]^]\\[]Q[\@\ZYZ??@9@@_@!?>>>C>u>>{===<<V=?<<I<@;<<;D<<A;;::8888h8a89T99858f89?999999"99i8998f77808688C8~88L8\8m8908u88::99p8888}877Z87A7@66C8U788^8U88889]:99l7/8 67p6n67(6u7"78b88%8k8 8%76665$432c00001;1r1n000/0G./00/K0/T/J/...//110:/00///Q/#---,-.......-@.->-J+,//-,-2.=,t-d,,|,-?--,,S,\-",,,,,g+++-+.^,++,,,**r*))*+1*+x,d,f,--L,-.1N44uQR?r>=<0"40 Ñ}< IeqNS& ()!;!]15-~JbOPDNqN*OfNKK MOUOeLNNLLKLKLL!KKJxJK2KnM/JKJL-KvLrMaMN&NwML3MNONtPRZRRR]RkTTU_WfW WWmWWX"XXXWZW%WjV%WtXSXRYYYRX[\[ZfZZZY_ZZ ZKYZZ]Z[ \\] ^y^][f^H^_^^^^_W^^\]]\\Z^[RZ\ZY[MZZ&YYZ[ZgYZTZ[[ZZ[ [LZ\ Zf[YZZN[QZA[3M D_JHOYY\?*>>>>?g>p> >=<===<<;<;;B;<C<B;;M;L;99:B:99889989Q89]9+99,9989b9 9`899:e88989l9d88889z8889o8867{8{78-88j8:)9}87<78=87<6=6D66 667U67$7u6667]788_6j7&667b67678g98_78)7m542 30x00/./1A00////M/000z/0/-,-/.a///S./T/A//.-..--"-,,- +-K,,-.s.,-.----u-:,},,,@,i+}+,i-o-d,--V-}---]---,],Q,,-:- ,,++,+*+*****e*,,---..//Q025%5OQ9:d?`?d/X2Z⋏Ƒ႒Gԑw⭌IA7CE57 " &8}M=z%MONNtNANLMMLMMNOKONMKKKJJ!L[LuKJJsJ=KKsKKdIJCKL5JKL@N KHKwLN`O6O`PoQ+R_RXSbS7RfS`SUUVVUrWWwVV|ViXiXWXV8W#W[WPXZYYWZr[ZZgZHZ Z[\X[ [YY[]H\[\\\E[^ ]\^`_9`5^a<__C^^^9\[\\Y[f\[/\[ZZYY.X{WY=n=?B<@HQ9XWoYoY|X[,Zj[X\JWHZYZXZYWeW'VWNWUTTTPV TUVVV~V(VWUV\U/XXVXV@YYzVUWDUUTTXlX4TUGSRQRkQQQQNNNONO;NLAJL>MzKMALNlNqMLeKJ3III)GGcEFUEMEdD#CDhCC_BCbCYAkBaAb@??@#@?x??#>?g?n?>>+>>====/='<=>>=I<<G<|<O<<= <J;;J;;:99:::9>:I9 998999`9:a89g8[9'9Y<??C77878Y8c99\9h:r9q9?88777577797y778}8A8z777B779666768X88U78788G767767"7k6f6/666_7f77_66.6,6t443l3221A1w/ /T0/0/W0 0003m0010 .-,,-./V.d/`//U/0T0O00.....'--6-T-&---- ,-,M-z,,,,r,-8,-,-g-,*,+**+<*+,,++--C-t,J+,-,+:*N++Z+**T+* +l+,#+*,+R*;, ,,f-..14,3OjT=9=7c/! 6YĒJၐ$-ǍxMZUL5~81>F|ETA"IKOJN.MqMMyMMNNN;NOMLL\KKKcLK*LLcJKsKKLwKK[KK)LL,JKyKLJWKMeN4N{NpPfOQPnRgR"RUS^TVWXVUcVVW!XYZ YXWWVVXX[YXW[ ZW[ZYWgXmYQ[QYYYXYY[[QYY\ZTY/]\]]R_D\ ]\]^^:^]]\\Q\\Z][Z[-Z%XWY_YZ`XXXYZSZZS[ZZ\KZPZZ[ YYXWR3a,208W;9;7;AbMTXXW1YWWPZZYXmYY X\YWeVWWVEUTTT T USVTUVSWvUpUsVVVVVWVXTTTVTUUVuWWsTSUSJQQ OQ5POONP7OXOZOOMMN,MLmK|MuLLM@MMLLIJeIvGF}EFFgFFDCBDBC-BBoAe@@k@@?@-?>=?n>>???m>m>>|>{==M<<<==x=<<<M;;;;Q;;9:;:W:::::::999999:U:;#;999L9Z9I;N99988U888&8898t9~778Z777d7976678y809|978*887x7777B7788O89G9E78896456h6"6X8!7Z77668 77Q6Z6'7X5/446436///...////00~//0.-...-."--(..`-]-".a/./0...---T.W,,4,,.,,,b-,+,+--,}-+--~-6,=,2--,**++**C+1,+,,`,,,,--K-A,+~*J,P+**k*E*++,-,,+7+,_,[-B,'-/V/q1e33L+R=:<:3p'@ztvuvuttstv,[w&"# <1o j/}(JyLMPpNNON?NMMqOLNMMNHKJILKLKpKYKI}JeJmLLKKLLLLL)KLjM$KpL5M7NLLYNOoPfOR(Q"QRTUV TU]SU UW^X`XY Y WWUUVWcYCYXWWXYZPZW[YX^ZYZZ VU[WZ]RZZZ ZuWX]]^q_/]A\\K\\~]B]]]Z[Z[![Y.\Q[Z}ZX>X6X:WWVVW$WY[ YZNYY"YYZ[Z[Z\\Y VN#2))})'3b2-4<104)1{ANxTSUsW$WLX%XWVZZ@YY WcX?VX3WX VUSTVUCVUSUU$TT2TUUUVWWXT~TSUUVVVBUVTQRIRIU-OxO;PyOPQQOPNMLNMLLKKNLN2MOiMLLKJJ6H2H-FGGEEDBDDBBvA@h@3?@3?2>B>>q>%=>p==>`>>Y=>l>{?>?<<$;==<<<A<<><D<}< ;<L=|=O<; ;;;:::{9:H::::O:::\:'99:999!99W9878888S9X88r8/88656m55656765679688@7&7o898k818h776677O73776'55544z56e77Z766`6'5o56665p6>5o55u4/10/.X./Q00b.----/0y0K1/_--O---#,2+.B.U.-0+---/ -..-"-,d,n,,,, - -#,f,+- -,,-t,.?-A,,,+,+-=-|,p++9)++u*{)|*+z+,<+,,,,H,,,,>,s+F,,+R+X+O*#*+I+++,++,+S,I,z, -.$.1433MnP=x< @F>0:0 nfI c3T1>H)Em7GB% NzPFOPMN)LKM{NNMxNyMMLKKLQKLKKKLkKL$LtKpJoKLLKJ|JJKLxJKMdNZOSO'PvN1OPPbPRHSQSUQUUUUW9VWXW*WWWXQVYWUWWXXWIWYXHXYXNXXYWXWURWIY[[Z[>YV6X[[]L]\\=[L[]\V\\N][RZ/ZZYXcZWY#ZbY:YiXWXfVXW5X%Z\ZXXXTZYZXZHX$VXYXYaSt:73z2C>r>>K>==p>7>)=>0>3=>>=5===0==<<<==K=q<<r<t;;<=< < =y=M=<K<W;:9:N9::F99:M99999:P9:|98b89J9W9e88888[98777656d6#6k7+727n6 578078q8{8666707v76665_5565'4433x3B346&777727755n5,6)65G5A54}4 55(100d02.//B0/00C//01r00-- --K,-a.-V-//.//0/0=//-,#*+o+t,,+,\,,+--,-D-.m.---t,-m-,,;,-w,,,0,m++**M*,-,,B,,,B++, ,T+++++'+****\+,,,++, +,x+]+j,-V-/24LS,>r3A;9- 14[83.ăj '$z+Tu=<j670>\NqMrLMjO!NLlKCKMMMMON)MLKKZKVKK-K KJJmK\KLKK/KMgLtL!JcK`K)KLKL?MfLNaO,O"OON_PPPRSSRUTUVMUW"WX*W_XMVWV]VWUUV]VVUUUWWW]YWVW W WWW9WY[YC\F\YP[XYE[[ \]7[[Z[[@Y\[[Z[Z YZBY(YmYlYjWWXYW>WvWV#WVYVXWQYXXWWXVVUWWRuDv5$ & X8/<+ F1(1+;aF LrPQRSPSxU&UTyU`U[VUUV$U"VTVTTSSRTTSXUVRRSRS8SRSPTUT!SRRxRReRVTUWXPWUTSZTTSmRoQR&PRP6PONMMN?O(LcLLL`MM!LKKKJJ_JJHJHuFF E!DCvB@AAAeAAd@$?@l>@)?o>==?>?===4=\=1<==<<<_<<z<<<<K;;L;K;<;<y<<:::K:I;;::99::::3:::Y:_: 999U8988"8889S99837[7X87*7{6U67b77`7*777~7977:7777+77]8778(;166 55]6g6^66]655e64667 777]7 6m665a4q556i62556q655 5`431000//A0/0?/0y0B00.0H//.--H. .0//.".o00S-!-// .-.-g---M-,,b--,,-/t.t.G.~. .7-,,,?+.+k---s,,f++****+ ,--L--,,,- ,,, +, +*++*++I+G++++Z,+,{+E+,*,-.0282MP=s88<2#a:T\Er `E t 9:0u;J7z39v~ !MANOOMCOM7LALNMNNM6LK]K IJLKK\JKIJXIKVM'LVLL^MfLHMKKLLvLLMvLM`MOOjLN NPPQRT{RSTUUYW!WXWWVVVmVU!UUTTXU/V\UTWVeUVUWUUWUVVY@ZMXZ@ZWY[Z[\[]]<\B[]ZZYZ"[(\JYcZ,YnYYXX WY'YVW|WeV7VV2VxWUWVTUVW_WWYXWiWUVUUQE.  P ( . b  `% !  # 31PhQORQTxSR8QSiRBSUU^UVTVUVT$QQ}R;Q3SSbRSRRRLR4RPRRSTTTUSSSSrRS)TTXoV9WvV-TiTQSS"S7SSP?b>=>?)>>>+====k=k=)===p==;== = <==3<=-;;<< <|<=p;;; ;;;z:C;:;7::q9@:D:@::z: :L:b:: 98888\9`999"88S776}666S788Y8Y888{7778:8(8(7$6t676|5v45>5x5@567=7?65M6555U57]6655(5`465*5432p34555n4443h3%2r11/u0(0/x00z0t0}///W/P0?/////'/T.C/K.--.d.b-...T.-X,?-'-g.'..E.-_-+-V,.-.-Q.-++*s+4+*+a+s))F*++**))*W)+,,S+,+++*++&,@,r*)**++*L+,*+,G,,-,{-B-. -.b033LR=W830.!C<͕ ǁ,g4[M "}IxE#R2Q19'.!0X+MoPPOoNvObNNKMN7MN NJK JJKKKKWKJJJkL4L*L[LSLKL*JYIYJKlLmKvM#MaMN6MfNdMLMIOOPQQRTTTUUVWVUWVUW/W#W)WVWTTV\TUSZTPT TUVVW UVLWWVWZ.VDXEYxX XIY Y|YYY\E[ZE\\[ZYY-YZXYXWXXXX+XVVXWV@UwT:U0XUU\WVXWXXXVW_VS:SPKTG,N*/k >j0 I.W-/.0KLaOPSRSRPT4TRUVT$TUUUVUSSOOPrQRRRRRR)RQ>STTHSTRT_RT|URS#TRUUU,VUURR1SPQ QQ6QQQRSgRPOMK JK?LK;L2JuLMMKLiKIIZGqHGH+GFkFED!DcAACBABrAbA[@@Ae@@???>?i==Z=f=Z=<==>?=<<<<=R=><L;<=;;<t<<;<2=<;;<;G;;~:::9:99:::::9:;{:9S9<9M8M889+87888877255M567a8b8r78 8u8r8o7?67707i7n6e56m535r6l6L6555:5C55D5566P6"665g54!555382233235p5/4v324w43011212+12211<1o/0//0/0//0 /.O.. ..v/0y0://0z0}/0.p,-..,-,+"++-@,,,O,O,,+)*+H*v*R*++3+,++:+*)***j*+"+X++*+M+,T,M,,+)*!***)*,6-C-- ,,-I,*,|--F-~.O0>23MQ=28 ;*;ZjD,[hH) N3HRu6#%.N Q;PO5NaOjOqP2NMNMMMMIKQKJK LYLLKLhKXKMLLoLMiMIrH}IJKK9JM&MmMLLJLKMcN#MOQNS UASRUSVVKUOUWVWVW'WVUMUUTSVUeUVTWSPSTTUUSUTTVXY X9WX WXXZXXYWZ_[[]\FXAZYZYWXXdWWX"XYaXWVzVoVTUlWV.UVWVUnUXVVfWVUUT-PIrD<9=C<9 <\ M 676641]/D..s6,=HQRRPRQIQToS5TT`TqVUUWRbSdSQOOQQQVOQiRSiRSdVS,SSUV>V{V;TR/ULUWKVVUVVSTSTRR5SS RSuSSRQePLMN LKJLJFKbMLL9KJIIHHHI(IrI/FH'FlEBdB1BBBiB)BbAAmA>@??j?'?>?>%=<=x=z=x=?>M>=V=b==W== >C=<2<0;y;,;u;;<;<;0;;;>:::u:}::2::9:m:;?;s;};7;m::::9889988]8777"6`56q6 67Z8!8877878'76656466\56;56f9%87766 556C6A87B7D6J65554 45543I344044322"12a2*23"3t11:2332222z0130/./B/.g//K.b,,,,^,,,^+.J020.A/ --",-A,Y-g.W--.+,h,,-,P+++,},p,z,,L,A+,,++,, +**)++%*'*+&+ +G+c+,-, ,L,*)*+*L+N+,n+,v,-8,-@-B+*%+. /x/.033KcO?:591!4ە v~,t-j7 Xo=S9O8~p($,%K*OO NNOmNiNMMMMaLrLLKIJJ}KKL_LKJLOLLKLMaMMkIHKQL/KLMLfM LLKoJ\LeM`M`NcORZQRSRQTV ULVWVAWX VRWVUVTUUTmU,W^V^SVS]SRUU\S^S-T UUVWXWWVVHW XYWUVXZ=ZAYY[XWXEYYVmW0W7UUV)XHWkYUUxVXbV:UVUUUU!VVUVaV"VXV$UUZQLG@?B::;:=GvTlKb>h;8r50+,W-1101=LQPHRR?RSvSRUXVTTgSUS-QRbSQiNP&PIPPP{QSTUTT"V?RTSSTU!RTNTUUaTURQSSRQlSRQ\R_TRSRQQQQJQUOSMzKL,IJHLL`KvLJKJ J|I/HHGHHI.IGH#GDD"CC&ABBhA@A4BAcA[??j?"<>?>>+<<}<<=@==<<j<$<=J<=<<<6;;;4;x;;;t:L:;z;;:;::;;{<=;;t;:::;s=M:;*::498P899O998L876)56(55Q6667W79F787=76|46z66p6h65556887+4656=576z5H5C45 4a443h25#33s2~13113p3320K222&12t33343d334"2333{01=01<2,1112&1*00//X.P-_,?-..../S/..],)-/9/;-^-,-r,,-,,-Y,+-, ,A*,L+,L,+,+,,**e*x*+.+"+/+++++,R,+*,,,&-V++H,,r,-.,{+,->-8,-2,,,I,./01M4)6-K[OL<7D<7;1&;^,!kʂDŽ5 V_pnNOQ:gB1!g'$LOPPMKO3PuOMLL=K+KGKL~KIGIJJKJ_JWIJLLLKLKZLKK.LLK[KLnLMLLKJMLMMORXQkRTTU{U VVWVgWOUVUaUUNTUfV!VWTUU^TTlWUSTTTTTQUUIVDWWWUVBVVVWW W[WVY8YxZ[4[WUWY@X XXXW%WUVWWUVVV~UNV#T T]RR5UTUVgVXV(VhTTsU R7GD<:z;5X7728E;;t>='=84V-*+;+-d+(,5=OT0RuRmPRcP@SlSURrSRTS#SSQ1O>>u>o>w==z=4<<>9>9>=C=$;:;<;==B;=<y<k<z;;;I<a;;;;:<+<1;;;<E=<(;e;1:;i98I:<9908;k:::>9H8=k9 9878T87j6756H6767b766a77k7n80546v6555577>7!7q8h66 77}8<796676C5H4434d5X2022333933u34,3q2221 1#1224233\2z3r322211a2<2s222`2012=00 /00}0./00/N///%..-!+,-.-..- .F--,S- +c++6+, +,,-|-,,,-G-O,+\+Q++C,1+,+,,,,X-$-Y-,.+h+n+,,,,+z*N,F-],*,~,r-&-,.+,,-.-.\022JqR\=z:<70D$/ޒ%pZ^,< h5?4 }z9"!!;Ko!!-!4!""##Q&57MNPFONO7OhOaNBMKLMGMEMLJGJWIJKJJKKLRLLZLML,L,JJKdLJKeLVLLULZKKLNMNNeO'QHRQXRSRT{TTUKVVjWWUTUTUV]WqWQVVWTTUPUTTTQRbRUTUCTVWWVUVWXUVVVVDV WVXZXEVW WUXJUUW&W'UVVUXSRRSTQF7m- 0 uBRTTTU0TS~TyN7>^?:536Y4 4Y2S0d48=988 1K-)" w(g)d, ! v F! z# '<qNR>RqPJQQRQSsSRSRwTSZRPQPNNQQlThSUUTTVUXUUTT*T4SU V QSQRRUQQQS%TT&Q/QQaSRP{Q%RSPOON3MN%LLK8KAIKKJJJJJIJH^GGFHWFEqFEDCKBTAAAA`AAA_????>>%==8>|=="=0=y=<;R:::;;;V;=;<r;;9;:;;:::;G::;#;;x;;h;(;u;:;l989:~:::n:p:=99E9:89T887&6l877:7 6\7i66?8`777S789)667l555~5w6p778:W67#88j7q67a6A67655332213/22239323d322k322Y2S1n012i4f453342j12r223~2422t112}242s323r400/0-f-..O.././...G/y..a. .,-,,c- +J*,,S,G-9,, --- -- -+,^,,++,,+,9+, ,+T,,W,+,,B,W,,,,, *,+-.p,o,-"-=-f.c,-F-.2.. /0x2B2HRC 6=M;$00Qсb( *+*'*)A)+s*2'U&F+{-c)*,3**F&,l+.%.41277LNPEP>N7OYLqMnLMLiJL.MsMKHHINIIJ%KJJKM_M MMMMNLKLLbL%K`KLKKL#KtLLMSN#NOONOPQRRd$ ( ( (9wPSfST7RzRwNsB;\56U. - :+-x+ .0G6}55z;8d631b. '' '(m! D0M  w  @ s%V3LRPOQPPS5S"T'SThST/RPPQQOOBRkQVTU URSTWUUT4T$SVTPPOPSUSQ|QS-STRwQQ RQR.RQROOGP3P6MmKuKqJHvLJ?GG[IIK3K>HIIHG]HEDC_D`CCZCCAfABAAdA@f??>S>?Z>==w;::F::: ::A::F::;K:;F;z;z;;:;~;;;;(:;*=h<-;<p;x;;;:;v::a9989?908x98F9,9G90999878777j7+67r7E7 75i677 7o767&9,8$77656i6v779k:9888776%6-6+656D65X4Q21|1/0p233g3223222813|3733p221w22,25171u0*1i123a21014223111)00o//~.-+*+,--/ .C.y.J.R-V.-,-,,,+,,-2--,,-,-;-\,,[-,F+,,,-+++?,,,0*)+-+g+,Q,,,,+,V,,-},J,+**-,5.,,,+,,p-x,,,G-W.023IIS>67 ;:^.X4*Ѓh& ).!#)#8U#)?!#1:=#$#LM(Z#D'"3M5NNNgNOiLN)ML6LuKKLLGJIyHILJI K LJJLLMMMLLMLLMKfLK^KKLK"MaL.LM"OPNcOMNO'NQ[STRSZSTKTU"UTTUV"UUTUXW'UUSS^SuSRSUUSS@SU TTSkTST TSSR RS]SeSTUOVVUVIUTU#U^TVVST.TTpSSRS[T%BV?)+DTdRRQ@Q>Iy?c3++t+( p)+-.D3I9u=422 56(21 - ) ! =   " "    2!/PQPPQ~Q{R9T!SRUTSRQRQMQRQ6RRUMTTUDTUMVSX.V>U8UU UU8ROOYSYRUPPRRRTQSQR RzR/QOQQRpRtTSSmSR3QRRP.QPPQlQRSTTT:USeX@VV;VUUVSAUPNQT?SSQPRSbRSRzQRQQQPNZO{OPlPP6NLLHGHI:I5HIJKvJLvJbIGG^GFEZCC!CRBCBBBA>$?f>??k>j=><;;<<;O;:::q9:A<E:X::0::;::|;*;6;E;<k:::;o;+;2;;:;;;:<.<!;h;':</::h:t:t;&?I8999j78r89{8|779r875444345554667 777777*778898+8Q9X8888776646665A644333344h4Y2$3633[3c2f1x22g2c23(2.32`22232221!0113d32Y1o22t11<0/}00z/.J---T,,-!-. /:--,.1-,-y-,.p,+,,H,,,,N,,G-*,,++F,,,-|-,h+,,s,-=,+-x,+,.+--- -,,U++++,++*'-+,>,,- ,,M,- --I-.H/13HS@s8>:.q88909 i[vCdC@h*c!tLzLLM NGON!KLMLL(KKKJFIIIISHJ KM LMLLM LXKLMLL%KKKJJJKLLJLLSNNONMXMNOPgPQQRRSRUTTULTVST/UUVTSTOTTwSS8T-SSTT!TfTUSSSSSTUS!S RSS]ST]SUVTURTSSSTTSS^ShSSRQQBRQFHPb>' .PL9U" L0OPPNEA2}*\+ K& Q$ $ .- 3<>O9<:<8732E-( =(    P L#J y   )FGIQQPPPRnSTVSeR%SRRSTSRR:QESRSTRSTUUX=XiVPUTU{SQOtPcPMQVbPRQfQ3Q{PQQP2RQPJNPOPPPOMKJIqEHIIAJ-JIHI:H-H,HDFFoEDDDMDDEDNCA@?3?> >>k<<y<2<;G<<7;::Z;D::R9:S9k9}::P:;s;s:;3;4;{;p;j:n:F:;6;{:;0;j;;<*;;#:;;:9:39:9e988887O786G8858|77A53W23P2224f3 22G25556(66556`7Z7N78888%7$7I677h677669615533422332:2)012:23[332223&3X272252e3012u10z151710*12Z222$0*02100r/N130~-,-,r,,*+,-R,[-[../+-H.,,,,,-N,+,--,,-,-z,+,,+,++++,++K*B,+G*+C+G*+9,-,.-,,B,,, +5+5,V,O+<,B,<->,+,,, ,D,,----.>.J02HRC@:V;r;6* J;PnFrs+τ ! OU%%oPv zcRbLMKLNO{NpM]LLPLKIL II8HIOIIIIJLJLLML LLDLLLK^J^KK'KKKMKJ3J)KiMON#MMLNgP1PdQRQ)RaR_SSUST[SUTT7TU_T.TRQUTTS)RoSiSTT^U STTULTSTU\UT TeTSUUTSU UUSTTT%TTXST,T\U&StSQRPSVRD>7*)2f<E4-GN PHHu:m*k& " # % +116V@`AEEED?a=815/() * $ ~$1  8 w I w   b7PPPP QyRR}SS/SS$S%SXT[UU%TS.QOTSSTHTVV`S0U>UWUVR-QYRQPOcPQTR,QPS~NQ2QPQ|T6RQxPPOO(O)ONLKjJIIJgJ&HwJI-HnJI\H>FFuEwEEEEDC$BAAk@>?/=8<<=<I<9;I;;<z:;;^<:: :H89089}:_:;@;i;+::;"::::;m;p;'<,;;u;;f;;;m::::4:h:999999h8879(8=889777312U11131<2j3!302|1K12405_56j67^6k767777Q77Z7R7H8l8`9s8"8j67z54~3U33g4C33j3b32)00H12h3l23=3s24k323111f1]/C0v0031-0|0w11020221n000*0/{/6...Z,..P.J..[/y.-.Q-,//4-,i,S+Z+++7**,,+a,H,K,E++T+b+++++}*+y+N,F-,,,,*A+6++G+G**)+**+)(,++**m*++* **M*+q++++,v,},-,,,Z-[-02K.Q; 8>E70 =X5Mt=ƃQ = +kBcN_gq:Ik&LMMBM;N&OwMMM;LM7KL:K:IHIIJHHIRI%HJI2JJ(KLLKL LKKQKKgJ]KSHJqM KJgILMMMMYMMiO"OQQRRQ.R`RS STSSUdSS^TS(SURuTdURRCSRSTUTUPUU SSRSPSUYTTTRQT'STJTUOSTHTSSTQSaRS"R R*RQQ|PLQtQRM:r6w++e'3:S31O2KD=D/& # ? (" +031;5|<@E`HaJRHFB><:81*'$   p ; g   &FaNcOPCQP@Q,RRTTTKUSDTRU$RQTTTBTCSUwV*SaRLSRwV#TRPeQQNPP\PmQPuRORjMNPDNQQRMR8OPOON,NML6M2JHIcIHJ[JcHIsJZHFLHsFIF0DDABpBB$AAr?>>y>*=>;==q=<>;;<;;H;;<; ::I99989o:W:x;{::999;:+:-:::; ;.::;):;::::m::o::h999/899.87z7y9-77G66665504y334334(32244567/777m77Q6667(8g8879 999d7765D5445K4F33Z32332D12345%4Z7,4_44+32m111r/1<01"00o1B2:1y1?151101,1l1*1#0>///R.--,.,c++X,(++-*,a--f,Y*++-,\-,,a,)*>+ +d+,N,- ,+**x**+8,-.-n,}+**+4+++N**)d+Z*f*9*+J**n+p+V++,E+*^*^++L*+@,++*+,-t+,-+-,,.0IQ=59u;,.̂ڃii=9 $g#O=T34V"-JKLgNMKMN.LxM KrKlJAJ?IIvJ=IHOIIRH]HTGIeJKKBJLKWJ_KKKJIIKeJrJb=<<>><>;;<;;:m;;:g:U:99i8899::D::}:;::::w:;5;w:;;n:::::;"::`:2:1=;:c:+99n888v7>7v76855d5M6565k4?544A45533344m5v5P5z66f5q5o5676e7i778'777p8j8%8+65f5-5*5x55;553344 4`4 4(3+234g3b4&4i32322c110/A//0.//000/01$0.0(0)/z/{0/////0D0q/--,-,,+,X,,.--~,- ,$-+w,,, +-,B,, -~-,\,D,+++++|,y,4++++*++y*k*)k*)~*{+Q+*+,+(,X+++L,_-S,*),+m+4++,9++,v+,S,,I*v,K-^,/0J=Q:28=/$3$3687o8 777-7625`aFXWUGN'HLLLELM/KN K>LJIISIHIJVIIIXGHHHIJ]HIkIOJJIJJKISJTLLJJ0JJKLPMLM KJmKKMZNO^OPP[QQPP;QJRSQQRQSRRTS]ShSTZRRT SSVTTTU UUTSTWTSGTGTSUUT STRSSUTSQPLLQMKOONOHPQPPOKAN?:126\;=b;OL?%==>$>(=A;<;<v:::n:;V:9;):999E99:99;E;<;;r;|:;<;;/;:;>::o9;*:::o:'999+9.9g8987~8777t6=6 6G576T54c31]2z33454B2362R4133L44556d5566r67816678#88[787p6u323p4p34323#4@44W33123:22|222<2}22n3w2v10~100/0,050913+2001c/n/1j100L0%'\HJKJLL:LL@KL*IKIKuIHI8IJGJ>IHII HVIIJRJHIIJVJKHHaHfJfJJImHJ`J!JLLLJ*HGIL"KMOO^P_PZPOQXOPQRP]OOQRSRSYSSGSTQTSVWcUVTUUUT&RSSUUWSTSRRRPsROAPNMO2LMI]MqNLOOOQ$QRXOONN0M2LM2LJHGIH;IMGEFFEEDDCCCBBA@A'A'? ><=<=k<<y;::9:::;:_:d: 9*9999: 9:::D:;;<::9:E;;};m:::6:9u9:f9:'9929q8888y888075H6 544s5b54v45d345234823223.3>454|4544456,5663778g877%7888u67z6;54u323:2f234\3]13c3344"5!32}2M12A34=3333220=/../1//222;2>0;/A/../&01-///.- -I-,+-,++,,+m,Q*k*,*+7+$++%,,m,.+d*+,,f+*,-d,G,+,,+++6*|+>+D++,,1,+E+**++**Q*Y*b+++`*++G,^,--,++!+J++ +2,++2+~+- ,,)))*6,-/%2&IR88=@5,?3MDOQ`QLPPOP QP Hr)E.> F!& DKnMKKLKLML>IGJIHHIHIJNJ HHSH]HHHcHHHHVIHJJWH J~JJJKIIJ'L#JL_JvIsHHIL,L$MNgNQ#PPPQXQPkRPP{SiR S\QRRRVSZSRRRRnSgTURU TRSS SOSSTSTMS QSTDSRRRPQSS?:K^U h9L@$ d8B@">IOO PPo r7$ % $ >% +7J45OH9'-$ X# .! " % q* Y2K;Kcwc9 VE@H;3+F&!! X" h l Q& & 6&B ~ 3NMPOPS^TcS*RRSRQQTbSUVUTxTTUSvRQZPuPSRRRSSTSTUpQQwQPOaO#LKKO8OYMPMO`PPQPMM LNM0L#IH@HFGG{EFG(EF>FEJF:DCAAAAAq@~><>=S<<A<<D;:L;z:;;;;::t9{9:r:?999:+:9::::4:::G:C;>;~;p;q::y:9;2:9:0:99:69p959)88766 76@4!2s3{55566Y44{49444434"44525$55y5|3555445{7w677:78'77277726B6+5I443*34333Y1343e3`4432133722E2U34523344201L1g1221z// 01/.r///872.>3OyP5QbQQWPO\PQ PpcLQ0z%5D.oz/ HUIQIqJIJKKLxLIIIxHHAHIISI IHH7GHIHYGGGHEINHHHH^IIIeHI5I2HHI1KJ~IGGDGH-IKKLLoNNOPOOP]OPPPQQRRnQRQSRbRRRXToSSSmSSSSTTNQSSRRSS%SSRRT QQXSQOTDR.KAJFKK2HCCy@^;7:l5qDAD *) +;/e&/w1IA5 -% $ # %',0$9TxǾyw30Dw T`D?'<4*$!  X;]% ,..N" ) *gLLN_O]QzRhR)SSSRRRsSbQ+QRTJRQQRNR;R"SRkRZSTTrSaTISQQ[PbQO4ONMvLLsKNCMaMNNN'NOOGNNOLJMMMJJIHjGFGGBHGhFFp==8<<< <;;;<;:~9:3:l::9:@:C:C;::W;:::@:9:9:v:+9;/;?:@::::w99r9999/98756656o5F334w55 655c5*5$443L444Z5|44s4&5&5+4334e4@4i5:55|565556?6o55y56w66.6h56+5(55*533x54K4Q4g343X2p332331112243!343^3%2x02]211f2,302%1p00]1!/0 01//1/n.5..v/..---.-L,,,*-/j----+-,.-,,*++,,=,,,+,,+,-4+S+3,.++++***G+*+*+++#*j**)***++++*k)*.*++G++H+#*,q*++**G(J)?+-0Z1K N8h7;:32*Cl3INPoQRQQWQPOPO vJ7q ~/+#n.hxA2 FJLLIIIHJJKdIIaJ.J3JIJ~HHI}HI I JMIGGGG#HHHXHKGIIIGHHJnHIJ1IHHKHHH8HJLMM)N7LO,O:OP#OjMQ*PP~RtQRhR7QR.Q3Q#R`RRiScR*SRST)SSZSSQTSoTTSUSYRQSTS^SIJTSROJDB@*???i>=Z4j1O.00z)*2,-:sOB/*36z<K2"'# " " # )(,'0<] hg ) y -e QFj@<4.G'#     $ ( +.3&#  *JMcMNOPIQQRRQWQ\QSRRRTJRRKSTxS5U5RTT$SU UTTU RRYPPNNNcM:M{KM8KLNNDMsNL6N\QNPMM*L{LN>LMK@JEHG6FFDGGG+F>ECBmA>BBhCwBA??.@&>>p===<><<w=i< ;;N;S<:;f;;+;#;i;;;::;=Q: 9:9:8899t9<:x:n::6:;:9:}:9D79-9n8v65Q55P56423,3!3W235H5&65%44112X3Y33`43333t4q33p4b5<5,5-5u5B55A5 5555444z45p56b44444344 3332L1*10232e227153211-0{0050500g1"1q1(1i0.00///s/1000q//.-.*-,x,---+T++U,Q+_*$+i+,,+++,,,,,,,}++A+v*+,l,7+b+++Z+s++3,u,,,n,s,,,,+(,J**+***\*k*+k+c+a******+U+++++,$+K+)**W*C*++k**)+b, ,Q/Z0EL8_5V:<`/0Ap5POBPQQWQQPOWOdMտ ]=k<L4-%MB/ }EIKLBKJLK{IJJIH IIVIIIWHHJHHHIGHHGXG EHGFGWGtIHJQHwJ{KKTJKhJmIHIHH}HuHSJLMmMMmNsNOqO`N-PaPOPWPsR,SSRR2R"QS"RSES RRWSOSSRSWRS@SOQQSPSSP#RJRQYQQS\U,W]\XPDLxHAD@q=:88654*|' +%#  $ _* )}( 1 4DH.? r21#3>N5*& R# ' $ * 16A] K~ Q {h ύ hk k h 6O4FA@=7y3y+'a# ?% $ $ & % ]& + /*)$)+HGNMOQ{Q:QRQR SCSS(QSTSTUTSTSSRSScT%U TT5TRNQ"P(O3I@<CNrN6MMMON7PNNaOnPNONqLKLdJ6IHIHdGDG7FGGFG EGCBGABFBBA?@@A!?><<y<==<<B:;;< ;:;<V;=$<;;b;r::;p;g: ::999F9.89:-:9:}:{99@:y:(:99:::0877F7775_64*322q3`3456O555/43441444 4#3443424f34h4y444}4445p5:5q55I447143a4[4444~4z2234543J333222;210r130120112,2611012Z22\1202Y2Y2j1m00*//.y.,-P.--~-v---^+,--Z-w,,W*+**g*,*,,],w,L,,F++c,+,?+,,v*+|+=+y+)++**Q+1,8+r,f+,,*,,,3++D*++T*b**,E*+U,,Q+++, ,>,.++++;+*6****+@+a*+*h() ,-5.0>DM<8<K>,3lCA4OPPQRQQPON^ 6f1$4W*!f2JJ`I_LLLK=KJJ IJ IJJI}IIIVJHHGUGEFtGbGbFiHFEbDEHcHHjHsGIIHI}GNGHCIFH~I4H8J5KLmM-M1LM(MLNOO1OPSS[R%Q+PQlScPQQQjQdOQPR&RfRcQ!RRSRRQQPQ_R#RWSRSXcrTeWTlVID=9<63h64310-*E+'   E% -0373o2 L+p8<'2?'% v% q& $ & , 4<<N,i I~ v /}  l v aS IC; 3u.& $ + {,) % # # # X' I,,/'()GMMgNR OPR)QQSKRRQrQ$S^QU9SRRRSARTTSQS_SLSLPO-P"PMuDlGG>00/\FOLNPQ]NNxLOMNPONNpM:LKKJ HJ)FcFPFF[GHHDGGDCC9CCrB7CqC*AA?~??@/>i<">>>;>=s<C;;F<<Q;<U<=<w=;;;;<:;$:;:9S9989?9v9:>99~99A99: ;:9877L77665654Q1233696%34566j44343K34K24034s4q4'445^5 544w5t56645245T5554 233e33333J345844221!1Y11y1y1101U011D202)1z2*12m22)1-2]12Z20d/0x0/0./3/{-./=---~,|,F+,,,- +$,+,,V,,{+W*+f*,,G, ,*+f.,J,U++M, ,},@,,s,4+**+e+++++0*+++N+,+*))*:*)*s)+*++O,H+**+,M, ,+,, ,+*+ ))*A*])+*))j*,-h//A/N<6f;;*20bF6O/P,QQQ|P|QPOLNe V%OW#k"+7!!6\JJJ%MLKJvKKJJJuII/I8IKKIBJ1IIIHHGGHJGGEFHaG#H_HSGFHBI>JvH>G!FGGII>HGHGZJ}KLnL8KL;KMaMNuMNNwQ.PPPP{NQnRR"QiQQQ2OxQ.QQ!QtSRR/QTTQRS]QRQ.RQRn{~d;[>OSK CR=9968:4v5`640N/12n1;.,! _" (>k8  4,/5/6-~)B(' '& T% * 0y5:xArLTRx_ mQJ*Gs?8P42,/:..*) %& U$ h$ ( W+11+*C#KiL,MOcNOdOQPRPPPQRR%R PoRQQNRTnSRQRRaIDHFY:8V,27 (:?Q NNtP2N&N8O*MLODONNNsNMHLKK JIIIFH9GHIGGHBC8D}ECD_D"BhBAAAnA*@$@)>)====<=M<==M=d<;j;<<;;9::::992889}99A89 8889F9998 876g5555444 2y13z246545 5%6,56"4444%44g4g4(4_34;432343483{4p454433\3433543n34 334E557 443T12S2[23w12w2.12.1363Z3221s22j2312-22110v/0201//w../:00/.M.+,y,,,-R-x.6,L-,++.|+,, ++-++N,Q+**++&+*^+++R+m++,+=*+++,.+*+c+=***X*+%,,*)i+a+(*1*[)*A*+,+A+*+T, ,,,|,,,N, *()~)**j*(+l+**k*s*+-/1DQ:9!=4=00B_7OBPQQQQP2PP=OD nq"=Y2 6"-IKYK\KKJJKJK:II J~H6IJJRGI5465.+*-G%  <.;' %2/4S/$,&)_( ' ' P+ .\2I9@GPfjfq\QPpHC;6Z33/-S,{1'42,' L" $ y, |' ,@23*Z/68B|O!NOQQR=QOQ"OP QPOQQQbRQQWNgPRR P ON;@#>=7=4P+Awel! ! w1ONzO P-OKLLLLMMNN@MMOIIIGG8GEHHI*ECDEDC{EYC;CB@A@A??:>q>>@?=2>o;;<<=<===$<<.;;;;::9k9:99P99908889889 888L777787B655745 466O5656 6666555g54w5/5844E45 333w34\323u33S4R334s3444x33443794R44C4I5y675434u32[22C12n3P322Z3d2d2n01%2v1`12f12j311_2o12i1(1_1)0$0062&0000?//..,-8,+(@*W++,Z.:*, ,,->+++, ,-U,+^*2,#+,,+],U,t+,G,++H+++ +$*+J*+5+?**++Y*+F+F,,y+*+*)*X)+,'+++ +,*++--k,:+>+++W)*4**++*++++*h*,-/W2F YR>z887d00E;PQ!QPQQQPPzP9O wVzy{~~~}D~܀҄܇͊F51+p)M2LLJ]KHJJJ9IOIJ JJImHHHYI HH$GIG&GiGG|GYFIEEiE(GGWFGGIqHHHHKH3GGHFI2HG?FHJ[KKYJKK%LMOaNO.OQOP/PP*PPRRSTS RRUQRaQ4Q*QQ]RTRR R_R`QRYQSRRUE{L(mXb{V$JTEBA>d=75-4- ) . 23O1/ W1/-0F3:102i.:@3 7$ 53,.41200`,,I0/3K3<QibM[SOID-<I8o6z1{1/004 6 1.y-0p0.Z*5+)(' % =NgNOjQPPBRQkOnO\NR8PPPGQPRrROFOSqRQN@Eu</GC]M@ 8 O  0LNO)OL&LMDL|KJJJLMLKJrKIIJVHiIGFGIHEFFEUECDDDDBBCB7B]AA@k@>=><=~<;;;Y<< <U<<B;;::,:9;s:::989+99Q9O877O88789D7766Y6566 6655Z66 43444]45U54564n4s44q444*4B443`23 334h33#2263123g2w333H2222C3z5(433B443D4K4434l4223p22333 423i311g111252Y2224A13f1122g20./0d000/:-/s.,---h+,p,>+V+ +(++*++)Z**,O-,,Q+*,,*n,+,++)), +I*+|*x**|****@))*,M*+++,+,~++Q+[+$+*,Z,,B,D,},,v,8++-6,,+++E)()*,J+,M,N,,F,,+c+,.b0d1E O;778~,-L;O P-P^PQQP7PyPP:j /HGzB{ACC|<;%dz KEKUKJK JIIIQ~IIK2IxIHrGH$HHHZHNIHII HIHGCF$EFISG3H-IHHHGHGGI7HI8HFGGIIuJ]KfJIJpK*LN^NcN'O OOwO[ONNP>RQQRS RRPSQQRnQQRSR6RQQ*QOQSQTl(oV2TJFEDB =6C+ -Z5<CIKLTL MKI^GZB92;2 4s0/.3D2+/7_7f(=&v(x({&',T+<-2o5+7?SL{"&x^UPMH7EB<:971T1T2/.q-L,+% # q# P% % w' )e?FHIOORhQoQPQPPEQ-R+R*OPRTR-SRSRRSL59[f8:OBCe%CPE9R  2ELNNNO/LML:KMLKJL LMJ!JJKK&JILFGFDDFGEDBEFED$B}BC/DCBB)B*@??{?:>=<<q<y<<<<<E<<<;:f9C:B:;999{9w9r9s89R9%8#8U88H66d5666K6645!56B655b5[528314Y4P5465454544545$545s434h44 4p4`34f22y3a3`323^3V3M2V1a3V1u3{34r32^434355\4+4#444H334p4832232l232013.331112222223210//111320i02-.:-/r.-,A,->,.1-,M--:++*,+B-.<,-,-w++Y,-z,O+*++++*+O+q**)~)*+;+)+,C+ **D*K*,n,,|++*_++,H+*+ ++, ,A+,3,r,,q+,*))P*(**C,3,?+,,,,+*,-..1`B O[= 9:P:,2I9NOPPPMQP}P>CUX^ysl]L'FB??{=d966(5210T//M-Q.-])' }& % =# '    ! % ,4wBJOOQOpPONOQRPT+R'QWR`SRRSD9B`GGPpiM<Y*  ) ^76KINOOTO}ML9LL$L^KMZMMLKLzKKJ,IGUHEWDFH8FDKEEECDDDGCC==p=I==<@;<^;=.;:;p<k;;: :W:C909"9k9r9M98S8K77P7Q7!6.7]66P56!56,5T66P64444544R55 5$5566\6566Y5c5c444C34s474i4'2222q3u232 223y3B2122233E2R23W334444h44a3C33332R2\2222.22<2l3e222(2`232P32h1114"1d10V111q1111`10/%../j......-;--.O..>+*+,F,P----L--.,-,,W,+H+S+V++++,++*+6*, +<*i*-C+**++,/',,,+ +,+ +*N+++++,+T,,,5,y+**K((*'))*++,,+[+b**+,.h0B Nd=7;;05-L:MNOPPIPPOOO8n eKaKZ RYLkGcEBGH@;:73.+B)&)qMFs/ulISKiKLJJJI HHHJJJJ4HHtH}HFFEEF4GIHHHJHCGF/FGHFGGHgGH=H-GHH8IvH GFGGNHJ#IJLLKOPO[NPJQPYPP]O$OgPPPQ'SaRRSKSRRZRQS*QRURRPPRQLPQcQpKWGOGuC,CL= 625IP-POORyPPPpNMOOOOENO>H8812) 4 >Z;<36n44768;[==:K<=h?EZHKKIK'EJBq@>s?v?{>C: 7:;312/U/,-+)e**+V+)+(*)+O0,,b6LPOOP=OOPOPR3NNOQNNOU<7j:KST`y>=<=E=N<\<<;<!;q;k:;:::7989998I888876`77!77V7W686K7767 677<6Q605G6 556 6 566J65d5555!4344[3223373?3>36333_1222C12 29122333B24>4y3u333333l222D23=22!22/1?013"2<2l2&12\11121-01a0///j.02/,0//G1/h0/~-,-.:-8.B.,L.- -,,./.1.0.8++,,S-,x-q-,-x-..x-K,++.+++++*+v++V+*i+++[+,,+x*,+++8-.,n->----z+,,,,-x+,,,++y,~,++D*(2())**++, ,,++,Y*,--5/+1EKd=T58;-l%L9LONPOPPPO O Oy    O  U  #(0Kl\qNrpMqrLVDI KKIIJ5FHIEHIzJ~III9ICIqHTGSGGOFdHJ JGIFH"HGGFGRDxFgGGuFGGHHHGGEH6G~HI!IKKLLMMNNSOPNOOMNnNOQ/QcRQRRR^RR(R.SvR/Q-PlQOPuP9ONxPR'x *w)YDI6EtBB; ^4 - 7M|OONPQ0Q;OTOOOPPPQ:PPBN NML;02P8@F:=>53g/035 5V96414z8716 3//Z2n/ 0$7b,02-t.054b/-R/.U-3+6 1/2}21"077A4<v7N6-?OrLOgPNMgMNQPP>Q>QMVFVFL =s9"<IA;~=mLy48Q<S5[/0>LM(NNMOQeM2KLLKK-N[LLNMKKXJ HFE'FFF FDCEECDD|ClDiC`CBmB?BA7Al@y@(?l>?)>j>:>>n=~==<<&<<<+;;;8n98< :9988c8^888q766[6T77I6W66M565R45!6B666656556C5W5545555h444 4F32632K2342}211222711111l10.12O3m3r2?223`34h44G3x4|433~332232`0/1012s12p223R3212210/1001000/3000W//7./z/+/|/-,N.!.,-k-.?..!-----------9-.-.}.--,,,+`,D-?+,0+<+n+G+3*r+++,s+++y+m+,u,m,,[+-n-,y+A,,4,- ,,A,++,9+4++B+:*+L*]**7*W),(*++-B--O,,,,-/)0CL)<:*:[7*+\MJ9uMNOOO%P OONQO     s []JF "0$X*01=1N1.-4XMIIJIIGG%GQHH5HH GHyHzGHhFE8GGH7HIMIVGGFHPHfHGGHCGFGiFHIHGH{HtGuGI5HsIHJKKKLLMMM0NhON/NMNfNNQRQRSZQSSRbS$QQuRRQQQeR QfOO2^Sh` ?aHBB5A> F6_-8P?PPHQFQPJONZON#OPPNNPNOHNVNQO8L?k=MDqD1>Hf>E:4D7g<<5@583=7:8Ew=6Cm/3U G9BAM E784C";g:620p7548:45453;499;c8C76u.AJMO~MNMML[O1NN,PNRsL4_1b9=L/DET@<<9=9:;3-9EINOMPON"NPOoO3NMJLLLKKMxNJJHGFdDD$D_FCGI=FDE9CD%C]BBBgBBB?@@r???>??.=>=u<<B;L:4;;:::1;p9979x88)8m9!8r8'77B7H5566U66Y5,4349456 5o66 656F6:6566?66W56555o5551444'2e3;2232:3.22#2311=121W01T2{2 11233433t3p3344433I4w33332W1 23X2 2)0s0|22n3.3v33322 2M11&00a060j0f0'0"010/0X0/x/~/U/---.Q.-,0/-/C--.',q-9,--I,-p---,--z-J--++<*,n+L+,3+++v*[+),a,+)*u*++z+ +,h,l,7-,,,-'-?,-9-<+,)***++o* ***K*+;+H)\(s))S*,++(*+'+Q,.-..1$BH>6A<+$Iǩ)à699:: :;a; ::e:$?????????????????????????!H[HIHGHHGHIIDIHH1HHH#GGGF%HNHHHGH]GOGVGHH@GVGG]AGE\FbGGI=GtGGiGH+HpHHI`HIfJJKL$MMMMONL@NbNM%OOOWQQIRRASSSRSPQQR\Q`ST]RPyOiPKcpDFqKD@??;-/15O>RbOOPPVQ3P|ONOOOPsOPPOBNNN OO4L@<23_<?s9[=8;?A<I<?A;[\cXb}_mj\w `Zo ,NM<\5LFLbIA ?A A =+=Z@@=<64416[34x;AIMhM3NN"MNMOoMMKLLNak6 3t>yC|JDt=;9:;=m;:L7KNP`RQR-QtOPNONuKKM?LMLLL M^KJHIOGFEiDDDDFDF&DDWDCCCC"BBBlCMBpAS@@@@2@n>>>`<<;^;V:<;;:x:h998w8888B9/9*9#8e7e7S7 667#6_676+677z6I566W6767D7776A6B6-6L6 567=655544L4J3K2221D1}11u1m123<1l1h2/1r1v111011+23243333;34y33u1222q2}2U3 22211<11 1k2 112221m1j10110I0/.../01G00/0/1W1//6/n0!-/`.//c--..1../a.`.a.+-4-D-,.*.u.-m..D.m,-,@++_+++*+^*,*k*E)****8* )**+W,+,,-`-,{-- ,-(-,b,s,.,*++y+I+,O,*++++,+**<)*'*c,P+$((+,Y,,,.1C K>5^<8G/$I,~+Yj4i5i5j5k5l5l5 j4j4k3v ?????????????????????????JIHIFHHF+E;H GGFDFpG9FFHFFIHGGHHTIHHbHH\IGSGGDaFE$F^G+GH7IvGGGG}HHIrHIIJ[JKJLM"LMPLNfLMMMMaNNPZR!RSQQTSSVRQZR"Q&P!Q(Q(PQbRoPlPaQr\bN^^CA,@>T<2 *PLPRPPQJxMvNNcN#O]NNNN_ML[NO=MNfLPPPkD`kL~W|UA <6^6:<M?;G;ILP+MM`PONGOfP O:O:MM LL8I8MjMMNMJJIGDCeCDTBGE:FFE DsCE/DnCE ELD CCCSBf@@AR@@@,?>><<;<<\<<f;:999899:j:{9D9t:j:9I9E88T878W77O677@77?6L76677F78<7H666645V6@56 5545p432c2%2t21 121231334 322521g2n2&21223H3I3234J33334:334?5<544F4J4223j22>12@1~1'1u2{1101111J11Y1[0S0[/f1`1)11/00///%./w0Y0-.////q..}/ .(.c-g/.----w--b..-.s.,,,,,!***++()*>*=*+4)**+5**{*d*++,d+++-I.-,s,q+,,,s,,4+*+|+++*U*+ *+I+ *V*))*.)+*+^)k*n+,]-X-/0@ eK?9e?:L(#Ky/j6j6lj7k6l6m6l6k6k6l5 ;?????????????????????????2FHbGGHGHFG EEGIHHBFH8H;GGdGGGGHDGHGHHFFgFqGGRGG=GIEGPFF+GG=HnG ;0 >QxQPDO^PPODPOOM%NLO4NPP9OONNONNOLMWMK9$ # 0-#$ N8 <z /  /^ 4    "  v  L   n  K (   p   5&)+o-(&(.GOMbNN1O/NN3NO NMLMWMMN1N6NNNQNzET;QvL?<66a7y9 7KCzMZLNjL4LNkMMDLMMMNOO{NFKJLLFM9KLLL_K#HSGeDFGE5FCCCFFPDCvCED(CCbBBCB/AAB|BAAAQ@w>>u=<;;;;;b::;>99:&9G788S878:k88`8887e666K6'5o56K6P67 7R766E667s7756B6614646:5554n4}4s33R2t1203&2q2122s214&4 3:21Q101e1^22J112i3J321Y2372|22Z334E3L3444433j3Z222)10171=1}1v0u0>0,/10#0s00p01X1m11V/0/,.0'///0o000/00/l0*/t0 0Q/y/".(.^.--<-.,--..A.?---.-..>.x-,A,6*E***L*}*l+*U*N*+o+3*E*)*H*m*n+)+,', -h/:--.$-",,,;+,,u,1,,,,}***V*, ,+ +*K*%))+,,A*3*<,J+-,,e-0,@ fM>5:.B+%oRw1@i6j7Ck7k7l7Cl7k6k6k58l44 W????????????????????????? EHHH'GILH=HjGEGOFGTEVGtHCHHFFGFEGAFF}GHEPFH"IIH FWF9EHFPF F#GoGH HGELH+HJ+II*HII\IkIIKLLLLCL NMNOP PWQPQQQQPQ`QPQP6ONOQoPQQsOmO$O_U[O3QD\D|?4<:5yK PPNINNMNM+NM$NNNQMMNNOzNIONLMN{MyMLD+# 1D1,< B  _  e k ?   ! ! P! g" $ '%:# h& V'-,.(($! # F$ v'#) *(,h-?-/.%(o! '2JO OO"LM0L|NNMLLLNMMNOQPJD;KFcrG@>38Z4V-0VINLOL|MeNRM$MPQKMNNMMN?MSLLKL9LhLfKKJJHmG4FFEE}EGPH:G3E$CDDCCCBCBiBB|ABBBB@@q?E?>>==c<;';Z<*;: 9;D98888Z988889:9T98766c6 6b566Q3556666|6737v7+67D5565645o543433322p232332123201210S2`01223 343H22U13H3r12V123G3x2A3343O34X4\2211t071>/T/|/008../A.0)2!101(1c1a/0.../_/\/g.0g/m./..{.O.////#.`.,,,,,-+-o,-0----.8,-~.4-----W*+*I**+7*z*G*<)*+2**+++m+*3)*++,,D-,,,+,=++q+++B++-+;+=+**+u*C*|***4)**T)**++)>**,H,,.\/@ fKj?56FFGsHHvGH?H.IYI!HzIlIJKJYJJLLAKKLNNTNPWOP[PPOOQP~QPPPPON!O7RPNQ'OmOQ[E[ASyC6FCD::4 GsPNMNgN_MNN^MMmOWMONML}OMMN MMMO/LMCMH3s% ,O2u)%   ;%&    k " &)R1>E>5!+ S*R,K-g) *))~,+,++,-6-D-,(P')++'%j&p1HMLOMpLLLM;LNLLONNuLNvO!MOA?8D[HPH?Aj5,+Q" XFJOAMONM0LLL*MNMNO OMNNDLNOMLzO)N7LML(JXJIHH!FGF FHFEDD6C$BCDBBBB{BC5BZBBBB=B4BAg@;??>=]=Z<a< <Z;;:x988888|888)88F8@8z8z88o7718,7h6`5p6g55f5555V6]66667=66z6<6C656 6646v544z4433P33233933622333Z22272$22224Q333211R2M23212333O3J33^3^45433#0001.1-0t0 / .g/. --$-./&0`1110J0R/.O/h./00/...-)..}/t///..i.q.,-p-t./--0.,,n-.o+-7,-n-3-,--+*L*?))*[**)**x+4**t***+j*a**+-,4,`+-s,-,+,+8*+w++*(+z*+4++**++**E))*+}*=*+O+*Q)_(+#,,`-].w/? L3;06;6A<.'Sw1j6xj7k7 k7 k7l7k7l6l6l5 ????????????????????????? <HHJ"IVJFeEGH:GLGHH GHGGFEEEHFEtF EUDFGG_GEFGGHFKEEhF6G6FtGGHFI{JIIIIIqJVJIfJJK^KLIKM=LLQMNCNN^PTPEO OP@L@RB>+=%=;::9:988998788Q8888A88}8o76E6G6n67^7i6666567 6`677E6K67|85544444v323D3Z4 332p2r3K2z3h2233733a3=20F11223]233]432322"3322c2h22)34B33M33322o201300/-,-(,g-.- ,./s11111Y/0//0/.n0'/N-,-///#//w0,//m.1..-/.3-.:-,-~-,,--+,-p,|,C-*,>+****+>*+***|)(+ *+,*+,v++++,,o,--,?,5,I+,,*)I*A, ++~*,0+A-*,+*)u*N+*))*G)**+ +U+W*g**j*,E,,-l0? 2K? 8=B=/$'V;w1 j69j7Rj7j7k7ak7l7m7l7m53 r?????????????????????????KF)HMJ\JJ=GGjHyH{I@HIHIGGGGGEF~FDE>EJEFFGHGcFgEhFFGEFGGG+FHpHGHJ#HmIbHG:GHlHIIfJcIK"LKLMCLOOTOPP\OOOPRGQQPPOONLO%NMM8OoLM0UjRFKaGxLA>73c0LMNNSO PNLMYLMOGPMNONKNNMNLNNHQ%OhNN9OiN7M|G/^- , )X&X*.~,5*)))0,[->014M8GG`ZBE<77@774\.q+{)1+g.5u42e/0U/,;&(y,6BMMNN*ON(MtMLNNsMNON NMNrMMEL:EWrQW,_kFY;[2  9LOP1NNLMPNMN_PILMPPO0ONRN LZOKKLLENkKIIG6HHGtFEEERBTCCDOCDBAA@APAABNAB AABBAAE@?]?c=<<;;99V:O:89T::f9998788788e7766s668P8A6565555e556J6I66 55%4445?343{3E323+3Z3b3`3r3k33$223923!3g3b4P4&4$4&4T334'4/44$3344X32|232{11{01p1z12Z2123^333.111!1d2 21s//0a000?/x1_121P2=111M1./(/'0a0//b../l. /*//00/..-,-.(.r/*.,-.,-7./,,,8,- ,+*5++)*+++})*?**t))K))*E*)+*=*=*,p+e+n+j,+*++F)N*T+F+++p**l*D++,-;++***K))2*,~*r+p++**L,+*++++p+}-f/;> NK;#36=<<+#uYw0sj6oj7@j7Pj7j7k7l7l7m63m5v ?????????????????????????6FHkLIJbGF(FG;HHHDGGF[EFE~DE8EDDDF0EFHHLFGiFGH HFHGHH2HI'HHIJIIIcI2JQJHJJbJKJKLL\L^LNNOYNNONOPPEQP OaNN5NL~LpM MmLO OLLQE>\ALOI1?:1J.M OCNMMLMMNNMOOO6ONPOO}NNNNzMON8MPMLIX1) *'}  <  k : R" $ + 6 GF@JE?i914+h*w*#! >"     C Q <  i +d:I)KMMNMOOeNOmO.NMMNNMMKO4LLG=\HVpC@?x<9U* ' )ELMMbOMMO8O~O|ONONONPONM>LL&MjKM,IKcKJvI0IGFFFFCF?DCCABC BCABBC ABOAB?AeA'@?>=;9;q::::^99:9:288876(777W667767n6777Y7777j646d6m677766]656*5244344G333d232333e3222111}12v12112o2/2'23j3323:22t1.`0122(282q1213i1i011.1812L1201r0100/000u0%/021Z011V12~1W1/1/*/x/g0./...-,,--.],_,.c...-.&--#-v,-0,?,--,-@->--+D,@,8,~+L*],+++=+G*"*) ()))_))**O*u*9+4*++K*G+,3*J+ ,z++O+8+>+=+,"+:++c+8*K+*P*****X+Q**N*)]*E**)*)(*g**++',\. /> L=;9<=H(%#Zx1k6~j7Nj7j7Jj7k7l7Ql7l6m5* ?????????????????????????EG3FGJDHFEGIGOF DlEF_FRFF{EEEE?E_B?EFGHHGXG\F$HH F`FHIoPPONMMMLMMNMJMMNHLNOzN8MBKN OuNM}O4NMK?4i)n&'" r b"7 m:p   x7K <  ,  9 | 2'3HLLOMN4LLkM)NOMQNMNNVNNN9O1OMNsA9IDbsoE8W44gYS*?DMML_LLLUMMOTMM!N>OCNAN@MLLNMILJ;LJ6JxJGHHEGFDCDCECdBABA]AA@0AAO@AMAN@@M?Q@#A@>=<;;6::::9::#9 9Z8876778888677,7[78787877T67666555%4564z3V4t33W333 3 231m12210100001|012z2z22k33i3}3t233{3C3C3D2100001q0}0v0G2o2322X21p20112h291'0>0:010//0z0s01o1o11220001'//:.s.s.{/.y-s-**,+,,+h,\-.i,,-7..j+,s,-p++ )+y+,+@,,,++,7,u***)+E***8*%)())})*)**+,6+**+++*+,+*E*+<+,+z+?+,+,++***I)`)()*()*R*+***))*+,T,,,-t/,< O<6Y;p7C-8&Zuu2k6k7k7k7l7m7l7l7l6yl5 Z????????????????????????? pDG|DEEHHHEEOFFF|FEEEFEFDED DJE DED^GGHFECFSGHGUFGIHvFHBH.GGGGHaLIJ)IJIK-KeJ8JKMII_KLLL^LM%MMOOOPQPONNNNMuNMLNOOPnM5KV8JV9!9ACH-:;=bF7PnPP~NNNNOANPNMMTNMMPMCOxMMMNvMBONMuMM=MI0'' ?)[" -# n '   ,)9._"{(+T#O  1   t    a   =" 1   ,AHKLRLLMLMLNdMPOYLNMhMMMCMMMK76?i}E91t9A<e:#3LMN MMhN1NLMMNKMOpP-PQ,M&LNOLLLLMLKKJJPHGHG/FeG'FFECCD%BBABBABAAB@@??9?@?-=<;;:: :;7;9S8d88:66X676666x6@76u7667_777777 6_66_655545=44x4n3342322222F2E2222-211}1M014112333d34<334&334c45323!11n18116012p22b271k110112726101%0w00C2-1o2-101Z2152f1o00]00/.//5.l./;.D.:. -N,},M.?-r+,K--. ,-k-./..-,+ *+*(?+(*(}* *))+**++*})K*K*))B))y)+,+?****I)+|**"*H+q+++*++,>,+D++*,|,}*+)*X*) '))+())*P*++C*))*,,,,,/f= M?8;A4N,(Uy0j7j7k7l6,m6il7k7k7l6ll5^ ?????????????????????????  IFnGFHvHSHFE$E&HFEDEfDDEEEFFDODEEEYEGFFQFFGFGG]G^GGxFGAGFI9GlFGz8I155O3MQOFONUNNNJNNMNMNFLNyNNMNMN>LNPMN+M=ML53+)),7! #&d     %  $/r91,+###(&#!      "u&+'&7$Z# "'~:JL&KLLQOvO)L NOMpNNOgMLLdM[MN;MMMM8;=p |+C8(42>jILOOOLxLLULNzM8LLNiONNN0M]NOONN/M_MSNKILKJHHTHSEFGDF9E@ED DCCB BABBNBAB @AXA@@?f?@S?[?(=<;:::::8J9g9.99?9 88_9C877(667i7c77[88>88I8z8x7H7766d665*6k6.5555v45:4;4A43(3)33n363d3T312z2:3j382v1122@130434*333]244R34&34X443433^3d332333332224122(01k121i1/2u2m3.3X25"2\110001 0/.r/0d0e.1-.. .%.t--,,e-/.(./i./k/Q/--,+<,@-N+M+*)*9*+Y++P+X**+**)*)*+ *(((((()*x**))3()))C*D+9***x*J,+**+)*[++J*Y*(')d* *W*))****)***9)+,+R+c++/>: M=9e<8a)&Xt2j6kj6Xj7j6k7Vk7Sk7\k61l6$l5N 1?????????????????????????sGFFKHHGGFGGFEECDEFFRGFFGFEzDDGhFGGHH)HhHI|II2JgIbIbI JIJ&KJJJIKTLKLM|NO|OyPOnNgMMNeLL==;k;e;m;):98888l8o7788777e7+7c78Z9H9G87C77777F6655565'55j55$4e4443333x3322212111O10/00\/101q2A121123345444c2240I110|0}1101181s111/11q2|11w2h011[000171(02'21u101+11/j.}/=///.w..//`.:/a.+/G.C-k-<,0,-5-t-//y../[..R----8-{-,r,,+i+,+,A+*C+++++4**~*F, ,)*=*o)J))O)f)**)'''(u(U()*?)(()***))c)#()*+:+,+N+H*^*W*,)1**N)***+ +*+++*X*9* ,/7; hMAL:,>D*Y+[u1/i6oi6i6i7j6?j7j7j6k6mk5ˤ ????????????????????????? HEFI'GGFEFFOFGEdD?E]FGGBFECCDxE;FEDzCTDEEF$FG GFRFEF`GRHFEGFHiHIeIIKJK\JJIIKJIhIgIIK^L K KMONNNMRMNNMMMMaM*MPNONMM NfLKVP; 8<M<?f<3LCU3POO3ObNNpNMNN,NNrQ:MILNJLH3+.K) > |($  f  )/ .=26.;4D<iE;C9U8r*\&$V%[#! z" ?&38T,$   w.GBJ,K^LN9MNqNONN'NNfNOgNwL2MML@MzN:LSLnI=H5=?3?ZC7 0NMNPPPNNNBLNN7NOMJM[OaR>PPNMMOONdMLNMKKWKIHHH-EVDCDIECBB"C\CPDC AAA@A??@??E>>>I>$>=c;:9979<:99877 6J6#77@8665557#7e778A7873737{7655e445w5.444s4}4|4}33D222V22`11v1141k1181000G/0000 0122h2`3a3434S5Y343w1.-0010001.1182:28/1*22l211k1n1-122a2!2/1i2X122j1111*0///N0/.-+,--,,--}-{-B,,->,,-f-7-x-.o,-;,,+,0+*+G*+^++,O,+,@,u+*+m++*+C*t+?,8,b+** *+t*6*&()*s)),(c())((&&9(((C)-)-(')(((*[+*c+*, +**)*;())I***F+*@(*5*T**+**+: I:>48=+'fz.i6i6.i6wi6j6mj6bi6j6+j6k5 2????????????????????????? EF{GFJ GFFD/EVFGDpEDlHFtFGTFF FETEEED_DDD DXEGEGFEEbFFaG)GDHGGGrH~HHIIJwIIII&IdIIJLJII[K JJKIJ\JMFNM(LM/M!MLM%KML8LMxNMdMdMNOMLPiS;9.89j8:717PhLM}OGNHNONyOO-NMNLLLHLLM)N_M5MOlOMrNML=LEx1.. =,  :# **&" {# )e1020=6.;6?A@ AB 3)$(%G%O%')& .s-x1Q+ #  ;  ; K'LLMWNHLNMnMsMhN7NbONMPM+MZLMMM]N5L~HV;@i:\6;B15N b0YMNOwOPPNLKKN=NrNLLMNgO)POONPPPPNYNMLLLVIIHIKJHGDE@F9DDCBFE:DDD CA@a@@B??>@F@?G>>R<<:::[9D9I:p98766x7788:766667$8#8\8I88z7766666\6M66 6e656;445<4443233O22a2f2-222211011111A1z12w3523-3P34.4455s4q4=0/0P001J/2o2X02"2,20G000}1d01l11a0213*3l32=2g3#21`0t000/..//l/9.;..t.+--:-,,C-3-y-9-.k----,--_.v,.,*++++6*)*,:+,|,;,++~+***m+Q*Q)**+9++>***))<)*+*())())(m((g&'')#((*6)*)])*++, **+S, +A+*+l*)l),(`+***)(V)$*)*h*w*,-E9 YLj@7<;,*o(z.h6i6]i6i6i6j6!i6j6j6k5 u?????????????????????????GHH.GGGDoDCDyFGEfFEFOG7F9FbEEDE EEDDED_DDFFLF DF!G#FHHGFJHOGIzI' O+~,*7m)!   }@OILMK^NNLM|MLMMnNOIOINORMNO0NNMNqNoJr:=o<`:>DCG3!2N,MONNPANNM"LMOONKLNqO8P/NNNNP!OWNOPMMQKLQKJ6HHGGGFFFEDSCCDMCDDEDBAA@@A@?@??@?|? > ==;;];5:N;-;h: 989X85899989)899H9999J98877@6666P6Q66"5656z555:5z4 4B4494C33 2\22*1,1411100101112<23332353g3c3 23s4.4/4i311/0 1~00113&2]322e1100#2112/011d2j3c22d1221b00j1d01\11 0/a./d/,..l-,M,y-"--7-,--.r,)-,--U,,,K+,y+**** )f*g+++++, *S+ +*+*U*K)*e**}*++*+ )*9*m))))*?+9*-))(`)*))*[(j(* )*))*+ *))m*%+*H***+ *%*`*+++)*&*)* )'(*E**-: M:d55}<8-;'_qx.eh5h58h6h6Wh6h6Fi6i5i6j4X 3N= \]TS%FHeFkF!FEBODBCDFFFKFFFHqEEFDEIDDEEMEWEDE EGFFDFOG]EGI}GHIxIIHHI8JIJJ(IJJJIJJJJTKHIJtKNKLILMNQLL%LKLKvLgM(M2LL/M$MLMM]M?J6KZKaPKT99v:k;f;:ND8NM0KOIKNDNL8LMKKKxKpLL7LL{KKQMNONOsOM|Ip80.W0( N `  5B*,)" ! x" z( -.0<-n.zF<B pH ;1-c)*]%   U&T)*(--1'>   @^IHIKLMLLlLjLLMOMMNNLMONLkON)L:G99>d=$;?>8!5N}O{NOP=PONCMNKOP9PML;LNcNOPN.PPQPNNLLMLJHhG G6HHuHHGGpFEEEFEE?DAAK@@[AB5A@ ?J>@@:? ?=];;,99v89n88V8\6778o6788888*777788E78A8r7776T5556556,5655r45r4494r4y3 3|21000)11a1201/0T1 11s111223+223 23Y23$403$2e21111?0j1 1!12 2212/20@/0r1-1^1-0l01223$221w01X0/i/01$1v000-0=/0/c...*,,:-.+.p./.o-_,!--n,!----,t++++,++0+R+K+,,++*++K+*+*F*G))Q++++.*,+)*F((!'(T())'|) ) )(()))(0'(*(()B))&**))B))*+9++)()X))_)6)*V))))+)))Q+.; 0L<O:A;?,# q(}Y2X3X3~X3.X3X3Y3Z2lZ2Z1ՈŲ=_  ]s s q;s=GHGG0GEBECFFUFGyEVFUF F~GtFFF|ECEEFFREEDEEyCDCDPFGHbIGH/GFGGIH@GAGIIuIJ)IuJXJ]IIJiJKVI_JJKLM LLPL\LbLKLLLLpMkLMMFMNhMfN\NRMI?KtL#JT>8S9}::;]6 4 =M5NN.MMLMzJJL~KKJKJK4L0KL1KNNmLM.O*MKP@>44w3m16(E $aE1//<%! ! s# (++/.D>84 6 3,*'# #w$ +  c')'# K  i$zEJILMO1LJLLNlMkNLLMM}LLMLNxNMwOjMzM*G9Y;1Y4^?C!/LMMNMP@NsM8NOiP3P"PO)O2PNNeNOOPQSPOMLLNNN0KJIKIHpI(GHGeG)FKyFEEEuCBLBBCwD8ABGAA@@n@?>>=<<(;;:i99::88h8l78899p98998Z8P93888 87777'766665555}55<564=33333 2222Q12\22I2/1j123111 122123'23332222223I3]332b111l2"0113`2352n21f1!041/11u1q2.2s233332&0|200i1&000s..././>.s/.--a,+--.(.+.---w-$,,=,,m+>*+4**N*M*+*+**+*,,+,R+J,\*)e*)^*+U++*+*,?+*+@)((`&p'c(O''')())*))((''(*)Q))X*+L)((**Y*,*+S,))B))))P)***)**++l,y.q: J<452o<@*+ +2Tll=8l=)l=m=6n=n=n;;}  kT"]+"@>b,- ~rFGGFGDBDsEFEaEEDFHFE?EEDEDDDDEDD&CBEDOCCCEFGuHHHGFG{G2GEWFGIHHI/J,I]JIK%K_JJIJKKL KNL LVMTNUMNLLLLMbMMMMOfNgLMK`JZJjKZQM=L9;><4#8!8<IMMOMLK JHKLgKKAL3LmLvL4KKMrNYMM}KM)JQG=4$2D6{4&.#",1I4;.1z$"  ! % (*.+5'9w0/-,?'$f! ##$% )O+# M ,GiKLM@N9MMpNO+OMMNOOENzMNN:ONuMMM:LxH9;CB@A&+LLONMMLL^LLO>P,OO'PLO NNOPgNOOOUOJROQJNN9N1KJHHGLHtHIJIIHqGkGFDyCrCCBQAACCDBB|AAAi@Ak@?C>?="<<:h:=;!::z9 9J:P999::6999Q9U9H9S8899z8r777Q7866676 6o55r45o5*433333E33A33?23 3N323%33`332`2@1212,3'23 234(343J32322201(01232d123(2w2%2)20/D1121233221[1t00.1P0f0i2'1s1%0r//>.//t//q...{.---;,-n--. .k--m-&++*++>)***)U) **++1*,+++Z)++N+L**)P(())*~+++* *))(())((*l))U)%(e*)*l**R('w)Y*S)))W*_+I+R* )f)++*)*)X() )Y(),()**T**A)*+I+,~/: J:4=/c5*!,?j3xl=k=k>Al=3l=)l=l=m=m=n;9>:bdc][t1 :u ^##GQFGfFFE EDFJF@FDEDQDJEGDCECDCDDECBYBOBH@A[@BCCEdGH=HpHFFEG)FFEEGGGHIImHIJJDKLIHIaIrJKKKKKLLLML-KKqKKKMlMfLM/LNMKHIJjJTaG? BB @ %6 TTj1;<MLsMDN4KIJTKL+JIIK5JGJK8KLKL,L,LMeJ<24p3-4>.%+)F J8c-3~&9  0  " *(/46F92q0P,O'K''~#   !  W C*-%J --ILMN?MN8N5M)LLLMNONOOMMyL8MNfMN5P4K8;d5qƐ:J\+q*LNvMNKM MLMWMOPO}NOjPMONQNPOVORPQPPKKFNNLIHJHzIqIK'JpJHH`GFE ECBACD0Cp@A@??@@@??? ><;;:::}988U9J878j99`:9: 98m::87Q877765|6"6 44555Q5\445@3424533 23K3 322 212123H222v2,2n3/122g2u22112!2_12\33R333421`12#1e2233j2{222933128100//0012`321]00=/0/020///D1?00+/F0y//1.o.n--...-,,--.|./o.b.6-o+z+"+o,;+*:*++**D+H+?+:+!*)**a+4,+#,+^***H)W)*))+5,,7+**))])(((*p((W) ( )*8*|)))**E*+*W)**++S*B)****T)*H)X)((((*)|)`()**C*S*++,+.b: H957=M-(+4l=l=Sk=l=l=m=cm=m=n=jn;?.ER d 4KUc  $/H$DFE:FF`FDhCCCEEDF EFEEDDD^DCCEE^CCBBBAf@@CCEFEFFkGrDaDDFH.E|D{FjHGHpHHJH_IfI`IIHHTIJ KLKKKJKKKL5M(LM^MLL)LMNNOQNMLdLcKJ-KjJiMKXECD F :A K@9KFMmLM-LJ/7}(~$ T# " # #$ # Z)4=9/_1--(("C! #2%   (:,% _ X1ILMFO>MLMLMM#MMcNJOqPN4NnMMxMMMMMMK:c<yJ}c=q9,}$ %ELMLMM9LM9O(OP;RPhOPpM'OOMQ OOPYOOPOO LL>LKKIJJJ1JJJ]GGH]GG6ECCC}EiC+AA|@Ai@A@?@@;>??O=><(;;:<;|:99B999999o9&999:9777777W67665X5454545q5'444t3333 11222%22[233!2 2(222112B22r23P333c23 3J33 3_3=3 2232,22k2v1}211x323g3Y2201r1512Z2f23$31100t02/0000..K---.5-.=-/a/o...).h-w.7,,C,--0.<+{,z++_,*****I*+,8)+d+9**C)*+ +*)+++K+ )))S))))7+D,-*))y)(()<((L))()()*)*6****Z++**++t,w*+D)))*)) ()('((.()_))*((((()*),k.r8 I*<8u68*# ~4~m=Rl=l=l=sl=Lm=m=m=n=pn;ud*e_. tt!Jce  $n p HQFFwFoFEeF(E"EaEF=F FFEFDE=CCBC7E1EbD(CBCaCXBB!B^C%EFnEF6FEDCIDEF~G}EDGeH*GFHHGmGbIGH2HFGHIHJJIJJfImJJJpK(L\LL KjLMM>LL5KM\MjMMYKJJbJNIVE .EaK zA6 NA~NfEBLM7MKKKL7KJIKXK@JIHI9IJIC75a558i4#2(*@1KNM,KB/9~*#   _" E k! (o+1G,?-(=1w+i(_% $ %%#  #$$# 7:]LMyMNPkO4MM7LNMMPP|QP[OO,N$MMO]MMLK:>"`GQtk<C3&8MLKNYLLMNNPQPPO OPNM[OUO MNMOaRYONMJLWK}JHK-IHHHHHGEH_EGmE.DCCrCBmB A?@{@@@H??@ ?><;<k;<<:::;;r;899 :::9b:.:9[9:}99~87777776555Y5i656 565g5&5\444~33v3B3B34A4334L3{3233h3f22~2<1112<122I33f4933223z333211110112M1223e3$22d22333222&11'1r01'/0//?..w.@-H--.y000\//y-,.--0,,G--.-.2-,,o+****+/**>*i+-**9)))e))b)()U)**) ))I(u(((m(D)7))**)(()(():'(M(D(.&((*))*+G**K++*+,,*(z+U+E*!**M*)M)z(('(r((())Y)) )))_*V(+"*+-: IAI;8*;,' 5z7Ul=Pk=l=k=k=l=Rm=!n=)n=Pn;2";y}%   G,E~EEE.CCBYBFDEDKDDDdCBDCD.D,DDDoBAABBYABPAA^BEFFGGcFEkEEFFhEqGGGFGHI+IZGHFHrGsFG^GIIKbKVJJJ?I JJKK2LeL)KnJLCMFLKLsLjMMNNZN LKK*IN JGLU ;i@ LDBOGLLLsK~KJJ JLn-WONHC@E=D7R6q5;642q4c38,0BALLuMLB0;* $ m$ # " :( $',>6D;<-0G/*)$.N/&=# 4 $N$  7LMNNmNvMMPONO=NPOOPjOMLL^M!NNMKL*= 6?!GU=<407.-DKLM LMMMOO;OPQ2P-N3PbRNMMLJKNRNONOLKL+MoKKJrIlIFH)IIHYGGDE D\E"EBBC5B>@@?@A>@V?@><7<(;;k;s:;;;;f:=:9::_::::N::99}99w88777 7:6665444444514404845W3333|443W23Q334323h2)2w111x12}1B212113 33.33d234433E2 1l2$2221Y12/23222o236332101.110"/./U-. .J--..q-Q/00"/s0+/t.'---..b.:..--,,G++h++++!****a+#+f+**L,s+:+?+}+ +,))(*())N)))*C*S)* ()((( ('(p'(('((H(<()**)J*))*S+ ++M++*H*z)*:*+*)N**u)((P(X))Q)*+*Q)))*U*+(**o+N-B; Hr<Y9 8:F(&#v9(k=j=k=k=MkMLLuKJKFL2JIKE+J}H(D.===97227i8163!3!2-0EWNM!MKK=1~C)  }   ;$ /'-c=9H45+, &   ,0'S+K!a y#*c 2 =MM|P%QOXN(MMLOMLNyOP[PON NLMNONGN^L2L>o5`=F_ <) - w1-IHLM NIONMNyNRXQ^OOyNPlONINjMPLKMOOOOOMN8NvLuM$KKPHJJIjHHIHFFlFYGuD$CC6C*BBBA6>>?x>[>\?=;:::; :p9::;:97789z999i:D9999q9{888F7777A655565!6d554445(56/55575 4 4M44 43334L4H333 222102s3[23"3+1F2i2223239333:3@22121o111f22212y22k233222r211c101h120*/.//l-./m./+./-/.r.x--.f.i...--.!-%.-(-&+x**+3+(+k*+$*4)**)***9**D++,** ++*) ))*1*)*J)*.))()))D)O) )'))*(r';&*?****++D+B,z+}*)l))\)c**+ **L*t)V*A)(((^)))(()*Y+***/)8*()+f6 J*<`6L68M'W(u9`k=k= k=Rk=Cj:87 8y2&2R5.76540=/=KMNdM|N*LLR;C1MG--$ " g"  $ q& 725~76B04/*$T ] 59 -2  $/(0  =O+MNoQOrMMYN1MNXNNONMMNfM`LLLLMNLK4@4Y:?C7+ J ! %0IM%MNzMMMxLMwNPO~ONLNO?LPQONMOPQQOOOuNM/KkKJJGIHHHdHG/G4FF2EE5D4D2BAB>@A3@2>? @>L>><;;;%;r:::;+:o:u:9:77)788^8%99:9x9:h:(9h9h88w7776&66V6]5^5V8s5544/4(45!5)4445!337353333423a3t23121112112312a3032/2L2A3u3v393<223O1)21L1100_22 223225\322*212V2/006///..?.?.-C./:...`--./"./+.9../.--X-(,-(,d+m+++l,7,+e*}*j)>*++z*y*+F))U*]+]++*T******O)))))w()9((\(V)))J(()*q)(**++j+3++O,8*+@****M**++****+,)((')")*[)(p(*J+,R++{*)b*4*?+,-,9 MK>A77B8w)'o w8kFKLLMoLmKJ2H<05Y,@$ $ J!   #.525.-?,")$  o7 : K')  ()  /;O'MMNiM|KLN'KL7LO:NM ML{LLNMXLM]OXNaMKrDW38{=d>;0  f! =eMNMOKUJLLNoOP PO6LOOPQIPMM$O'OPNQOONNLM9JITHGHFF HGLFjDEsECDDDCDBB7B~@A??G?<s<;<<:;";b:;h;4:v;;:98X8\878789 9J: 99987}7G6666766W566555j5*5,44245)4v4?33343323G2422222211G0X002p2232223b221 2~222222212&0'0^00133333P33323 2u1u2/110<0//:.B-.@.7. -.-.x-.6. .n.0g///..e/0.^. .$.---%,t,g+,+,-+*++j+k+l+r++*H+ *y*+m+,+*+,,,>+#+x*q)))*)')()) )I(((A)*M){+**+8,:+l+**+ *p) ))*Z***++ +U*-)**+ **"((( (():(@(*U+E++*++**v+H-: A;0;35g,'#z5kAAAcA.BDEDDDDDF/DEG2G$FzGGH"GmG4GGF9G.G#GiGoGGGHI\I7II%HbGHI/IKK|JJJJK;JM2LL$KLLkLMNMMMILQKU5Xk y Y8[0>OELRL]KKLKIKIJIHH'EECC^DEItIxIJAKJJsJK:KIFR;+u2*j# !    #+Z/2e60;0*3&"Q  K8 A %  G  *+?$8 :KDMMN#M@MKDM$NMLKKLQMN}MM}KLyLqLKpMM`JD$86>IR( |" % G<LNaNN LGLLzLoMOPEPOnMxOdP1OQXPNN$NOPNLeJKRLJIHIJJIyHqGLGGH%EECCCEDBD@FBB?BA?@F@@>h??@=;#;;f; ;< ;::*:j9:|888p7[788U89B88978767A666W55555545445(4w4r4q4444s21232X22322222g2210U1Q282~3b33X2`2322p3622 23y3232P22W111u122d333433433'2p10111302/..//r. ./z-.t.A./://////g/----d..S-..J.-o--(,j,d+*+o++`**t+;*)))*=)***~+0+;,,{++++4+*i)9)I)):()0):*>()8*)>((q())*G+++*Z*%))t*));))')e)d+z*+ +*+K*++ +*));('() ())()**|(+*M+*+,,4.;; YC?:92<q+)Īx6k75P675R:9HGGmGFE0CBBD1E CCDED$F`DBAu@~AAAAwAAA0A@@@A!ABCDBCNDENEHEFDCDEEE_G F9F5F'DE]CFG}H2G3HxGG3FGGFGHxHGHIJKKMuL>LbKK;K|LLLM7MMO3O+O,NNNHNYN\Xf v L L661>MKKJKJIIJIMIH{HH~HHtK IIHCIL%IJnIIDH IGJHsF= .P+$ :  %  ?$,2y51&1/-)D#9"!, 4 %! @!,+$ r7aLMMMvM8LLLMaMJLLMLM MMMLM4LyKJM{KJF-<8:B~] < ?(* V# 6hMM6NNMMNoMHOPPOMiO:O+OQOOPPPoP'QQPFN7MKJJJILLhK4KjIHH7GFF,EDDEEF5EECC>BvA:@@??J=<<<o<H<:9:e;;:Z9:69t8 77966$888:689889866m55X56655"55%445/5i4s33F4,4&4333932323F23I3_22^222&1112n2912<3Y22i2!112w2C21111e1122]2i2`02222,233 332332252t1d0o1*0Z/.B/;.G.,-./N/C/M./.y/8//Z//i/0%/]..X/._...--+--f.Y+D+G*+?+,|+>+++d+++)++5* *++O+F+:*+++*+;*{*)x))*E*)*(U(Q)/( ((u)*+++r+5**),()A))J)P)_)***Z***)*)*)(()_)(("(C(n()O)P*)K* +()**O+I+,.)9 J<;B39+,-& x5+k;8j?Aq?@h?C>D:D;BBE?DDEFFEDOEEF=FEF?FF(F6EF?GkFFGG4FGG;FGH?GHHHJKxJ+K.JJIJJKMjOdM#LaNqNOZOPLO N)NNYVb3\hwk  WF:8+$CiMoMM!KKKKLMJK,JJIsJKXJIGJ;MJKeL7IJIJFG8.RC,   x _ ^ ?%!-2401/k,(_  m %7 2 %  *0*  q 45JMLMLLCNfMNNNMMLLLLLLL MzM/L9LJTKhI?69 ?=DB-% L+bL7NnLM+L.KMLyMNOMMNqNPPOePQ_P*OP>O,NYP MLKKK>J?HIHIGCGGGHFEGCCDzD>DBCD2C/BnA@?@? ?=>>K>W<<<;L;Z;;:;!:88V8$886e7889 999:i987K666655Y5"555*5 45,4w3h3~33333L233y33p39333322\2"1512q2622}12|23*32j2122h2j12u232 22L2Q2I202\2[2H.1[2z222333,2.10s/0n06/0/0//:/...>.z..?/i020r00`00c00//.//..----[-w-u,,p,A,w++~*+0*+k+*)*+3*])**+,++**+,*+***J)***=*x))F(R)z()))C(()*p)))('<'S( () ()8**Z**B*+)()\*8*?*~)X)()))(d'@)((((V))++G+*++.9 sNW;W297E)~) w6am:l;l< kHIJGHwE5-;)    2 r%0k/2[30/++&$!  1=1%^!  #3,$ ^1KvLLMCMLDMNNONNMLRLL LJNzNLHNZN$LKLwLKJ5C4K wrA.% & 9JbMMMgM\LMDNN=PO4O4MMOOOwOPQvPP\PQRCQKPMLMLLJUHJtIIHCH0G5H0FEyEDE!CCDBCCCsCAB@x?>>=_>A=>=<':;p;$;k==V;\;:$88X8%8868D89F995888987x76H756 5655_545422p3/353C433;3:33B38224?3C3u222e2&1223W32s2l222X23#3S2222122t12:1112W12222F112 2Z22222m2~1&0l00C./l/i.n0m/./y..s...m--../h/o//f/--.i.,,,-.!.'.-,M++C*++w++**+G+`++5**+p**++,<++M,*, ++**+s+r+k+*+**=(D)*3)*)(~)*(('z)))('';&&\&'(D()**+++D+;*)Q)"*f*))*!*)%(d('()d)J)))*C*_*,)*+*$+/.7 I=<==<<<<=:;;;d:&98]78>8#6789989N9w99@876666555Y554c4 4`3h23444o3334$34;23x23P4333=2232m112222621122a2d222*2c3"22112|2222233}2L22C3223@3332g2$00,/....h--.|/-0:---p-,-.0...j.,...k--Y-!---8,-(,-,o,+*,u+G+,,T,n,,+k+9,,z+1++5,,,u+++,**+3**k*-)))()))E)))L) )N+*D('())*4)(A' (V)W)()))***)**S)*+F*+*)())))+)***,*)W***<**,d.s5 NL>6p99*- d.{0n99k;k==>>=;;<;;c;;:+99,9898!7789E99m989-8s8y7}77@76f665544u444.4/444!44%44)6 33y4(403334=33222,2f2`32252$2#22j22[23322<2r31223k21%1K1K12V222222S233J23Z3!2T10h0r/|//t. / ./..-|--,-n-?,F,-r.4..~,-.a-,-1-@-,-w--"--,+++x,o,-0,+,u+,),0,m,6,++,-++++,,4,2**+?***3*y*)*z*q*(*)*B) ))()* )&H(5)7)("'):)x()*)))x)+**U***#+**))Q))(K)J())**++)P+K**')+'*,h5 EK'?4%76*7o~t$n'o'o'Kn'm'n'Ym(Gk& \   ]}3 c[?(@-8>>\>72FBBGFjFEC9CCCDCFCDDD.B^B3ABAx@AA;A{@AG@@@@A?(?AA@B3CBCDACC4CE|DHED CREAXBDDCF EEEFED EmEFF8E}D>DFIFG7FH6GGjGI5I9JJJKqL.LmKL-M+MLLrMN/N[McMrNNLSIJ*Hr\Ao3#9 M&M\L?LJJiKiJKLJK0J+JJ=H==N><==<]=<L;:Y98|8D89&98 8K899s9>89w9+928767 6\556H6 45544!4-4v4l444i4`4 34C33:333{3333{3C3P3211122%22222223 12'2o21K111111212 22y2F13K3;32221Y011!/3/..0)04./.9.l,,,A,,++, ./.d.$-++,b,,+,t,,x,---a.'-,,t--&,-w-f+,s++++8++++*+=+:+<+s,9,,3,",'+/*** *+3**0*|)6(**)((~))+/-( (P&').(''') (()S))!)*d+7*H*)+++L* )))R))*E* *N***)))))v()L')+)-7 N>48581HA'S-iaT r  #,Z R?Vv6Z68=<'9\:3GoB~EE>DEcECvABBDCCDC5ABA@C@&AlBrB7@?@<>@@AAA$AMAAACrCqBD`BRCC|BBCDPDCADBCEUFDzEDEDEEDEEEEECDFFEF$FFF*GsH?IJI\IIJMYKKoKMVNnLMM4MMiLNLLLwN&PfDL1XZ@0>MLKtJKjJJfIJfJ`JJKL)LJ(IqKLIHHIhGdG@/71 * F B  V )/1_8 330%+('&z% ?1,%8  #2-`% J ;%K?JJ K-JKmKlMLmLKLKMwM~NMLqMNL,KMOQ>MTI8hAFrIF<+,'7LvMM+MbNLNuNsO`PaP!OgN3NORP!QcQOPOPFQQIOOOM|L=JIKKKFJJ7G2FaFEEG#EE;BEYCCBBB@B@??A??>= =z<==M=N=<<;;:;H;H988:99888s7928}91929088y76J76555`55J4S4A4(4a44(3r33331333p324(33323323 2R2'221102/12s2122 32212g2h222<1211122222E1121100|/0f0d0../0q02/q/t/.{-- -w.u-<, ++*,|--m,,,,,030,,,,e-'--,w---++?,?,r-5,D*+,=,+***+,1+++++,?,*+,2+j+j+2+*****)r(G*** *w''(})1(C'(()(O'D&' 'o'(3(()) ()* )+ *)*)Q)((A)=) )))*)))Q))(7(())'h')(*-7 If=54<.7O -'Z%[Y  q  ] # <VZ 3422r:,7Y8EFDDDD*CCt@dA:CD[DCD D"CBC+@p?0?)? @@?W???x>?????@@vAB ABAAACGB@B BkCKC@SCBB[CE E?DCCCDQDCEC&CD_CDEFDFEFEMFzHGJ JKJJJGKL#M]LgKK~N N+MzLMLM/LLaNgNbH8CYݔnLO=3GML/JK|J;IJIJkJnJJuJiHK-JJJuHIHGD<_-V0-l     x! --0X9'340/+*w(*% %:-,$w  " 5 .Q&` 9 ,I@JIK6IK$JIKYLLRMNfNfNPNPNMLLLWLNOLK7_:iC%f)<A0q*0KMNO7OLLNPPNOMMOOP#OlONNNO PIQPMDLGLzKJJ~IIHFGfH6HHFFlEDD CdC,DA(BBA|A@@AdAq>>==?;?*=}=F<<<;<O:L: :9\88p9@98777 79(838 8z808>66J6y55555R5P54344+4433%3333:333(340393J23Q2/2T2[2 221i0112222b222w2X2282p322r2g122E12u12K1z22M11V113y001O//l.B-t.S...M//9-H-H+*-p+--z,,i*+,q++u,o,-l.q---v--+-h,c-i,~,(-,,m++,=,,t,x,G,+w++ * *+i+++++*++M+4*z+*{)**+=***)*)y*+i*(X'((~()(((((;''A&'O''a((X('['( )^)*k((.(\)((@() )(P*9*=)*)))))))f)&(*-)D*-1M?46=g/WǺ gdUYT J j 3 c F J?8 /498:58BFEFEsEE[DrD DDDD\DDCBAA@b?/>?&AACAU@@?}@?t@3@l?@@"AbCaBADB4AACCDBCDBBC BACME=DCDPEPEDDCQD"DID[DCEE>DwEFGFtEBDCG#GH|HHHHIJK)JL%KMTNMMlLLLLKMMeM$NPNrGGcF:5BJMYLdKJI+JKJLL.LaJrGJjJzJKJiJ\IIG)C[8.0 )|     D! .-0294c30)'&&A! ', :K', ) 6 &GJL4KLuIKJKKKLKMOMMDN*M(MNNeN\M[JKP N Kh;5@@FMOE2&)(EwJJMKMJrKBKN7N"NO$NvMPPOO4NM]MOPIOMMN2JK HHI8GG4F1GGHFF%EECD_C^C$A'CBBaAfCB(@4@@(?z>@5>2>s?=G<;<;T::;F:P:V99b9a99H78l67F77z87777E7x6 55545 5_55554334 34%3r3+4h3X3:33z2K22~2L12[111e11)1(081?121s2'22252g22K22;2k2-1|1112p29271H11O11001121"01`10///./j/|...B--,+*+,J->,*,M,++k+,--,-d-u,,-p-$,%-.-Z,-)-.,++++t*+ + *)*+!+c+9*?*:*)* )+w+&+G+v+&**+<***+5*-*w**+ *y*{)p))Z)))'&'(2(A'' &&L%' (_''K'('(('()A)*)'()=()*()*B))E*)(Q'(*(&) ))-l3 La>7A89+5q HMQe 2 m  dI 34`949:>57B4EG F3EmCJDEDhC2DeC&BC4BCB{AAAq@-???@}@8?.@@>?>N>>>?u@ @AC@BABBBC{BBBC9AABABBAA2DBDYCAgBCBFCPBcBBBtB'CXECC D EADDE DDEGGG HHVGHIKJKKK8LM)L>MM=LKpMNVNONNFNHd 6utC:H=bLMeJJI}JJ!I8JJKI9IkJ0JJoJI4EEFGFD574(]     /%/g/ 5#;36540 *(+%# S \+#  -/[&  # LApKkL7KJrJVLNKMHM LCNO2OPOPOOMPLNLKNMO>5J MLLBz4+ )@KJ?NK{KL{JM???*>??=8<<;<F;99: :;98939877z7 767z7{78s87655R544^3e3l3443333333-3n334X223922K2S123132!2111j1*1011111P1h11L11111(1@11111111I2>201000o/0c0e/.N-..,-.I.. -+,***-2,+++,+,r,,7,-,,c,,D+-y-x-,-Z..,,,*,++**+u+e+z+0*+**0+<*******+e)***)***))*H*)+*)()u)(((A(('(}'''R''(('''P(') )('((g()I'd'/(q('++**)H)))@))((+S)]&)*(*,5 ]Na?|65;9M*x1gvR#gfU+e  T 2 3 + w'*8 92U9660rEF*EHF"E?\>???w>?H@ABfC AAUA@1BBBnBAABIBBIAABCACC%AC CA@BB*AAcCCCDIDECEEJE=EF FIHGHI?I}IJ~K9LKLKMNMOeMMyLuMeNSNNOOFLw  ]?8GMcMmKJJJ?K_IKKwJJJtIHGGEDVFsD>40z6 )!  15  ; (/4/Y4/;d6410*,'4!  F'{  o  4$*) _ 3JuK1JJJKK JJYLLMMkON;OkPNMN$LQLLNKNKAE7G NhIZR5+ *I5LJoL=LrMMKNwO'NOcONMNeP#NmO$OP_NODMLpKJHGIHHKGFFGjGFG^F(DOCCABnCC CCB7BBlAx@?????z??g=<= =D<;;W:;D;::T:9k9B877655567:67A7J666 6 432C2334433223)23B33u2222K2O2 2V2241b2f112\2,12l3i2q212/2!2222'101 1111J2}111012C2122110l0{./y/0a0b/).-Y--;-M-Q0-,***'*,+,,-:,++?+,,,,,,B,@-/,--,,,b-!,%,d,++/*u+*)*s*+-++|***++9**8*G*)*u*1*)))*|+v+*t***=))**E*~*?)(*q*))()C((h'*&'(*('''+'&'(((R('&()K)A(()(o*+,K**U))))* )()2)])(W)<(),4 J?t6C93/1yUd% Q |8 t k }  A V(\-/o4u5:::C1GE}E}E8DDAGAABBlCB@A@@ ?@>=??@A>_>??W@I?A>?5=B@?D@|C=@BB ABDCCCrAA0CkDrCBB C4BCBDCABBBADPDDCCCDBDEF-EiF-EBFFGGFFHtH+I.KMeJJcLdLKNMlNeLMkMLLL#NPMOOPwFT TI>9:JKKLwKaKKKoJKUL]K"KJIItIHHuEE<:J:83*)! ,  J  #'13&ALDL@61-,)K m # # o && g %CKI}KJIGHCGFNG;FG-FeFaFEtCBC(CB(AiB\AC)B1A@A@?@e?-?e?>>=;==<=";;L;;I=:N9M9898877T66x667q7z8<818;8"76664444554R45554'4d44348333r3>3 2238222\233I23H3_3322<2n2w2g22 2912>2;2Y10x101|011101 11<11T11R0100/e.!/-$-0-t---=-[++++,A,,+,,--C.-7---u.2.9..z.o-,- ++y+++u+++**q********A**+s**)V))D():)7)y(9)T*G**)* )*))*)Z)*e))))))7) (('O' '&'0'I(()((x'(((D'?())(('('(()m+P*2**)('((*V)'''''(+t,4 LL;4<p5(/w]YH     oq0 m*h616+<A9D7>zF*E E>@@@><o=@M@@=>M<P;>L?@@@B2@@AAABAAs@ASA#B@ @|BRBBCCD:BAMAADDMAbABBBBBBfDD{D{DEFFGFG}GH9I:JJJ@JLKKL?LLLMML_LKLMLYNOCN.Gd  jA<@M)K;L(KrJ%J;LJKKJIIIHvHwIGEA2?u/ #  h R t ^ e  *0>aw^li><R6*009-& #  :I $ Q ! 6LKK$KLLJKNsNKMkN5KKzL>NN?NwNMMLMNwNOPO ONLMLKIGGGFEDCDGnF`FG[FEsCE'DBrBtAAC_AAB(AAf@?@/?>?8@>=t=<<N;<M; ;I;899-8r877755Y45W65667777p6554434R34R334[53n3p4"3Z32330323d222V32@02\2U112C2332a22Y2n111v01}010110 0 0M000O0Z0S0J0b0J//0^102H1P0C.. ,.-+---9,,H,,,,:,.A,,K,,--4.6.u..---.-...#-+++++,q+-<,0*+;***+6*)*+**)))4){)J))))+*J*+))y)))):):)*=***M))(`((V(L'&%3&"%]%'''))(('(()J(()z)O(_'''(& )g+@*_*!))))))*('D'@(}(%(),24 K;948:&0}PQ,  l   PW b (e;7R6a59Q5?HEEYEEiE[CCbAsA@BeB|A@T>U?@E?@?;>==!<p> ??>=I<=>C=?>??@@ABzAA9AAAA@A@@A8AABCCCCTBWA@qA@Bd@BRBBAABDNDCTDDDEPDE@FHHIJJKsKLLiK~KLN+MaMjLK/KoKKLdMWP8OUMP$n  N#>9HK7JJIIIJKKqJJnKH3HHmHVEB7-W0(>     P$ )2eDkB1-*2%   7 =C    (hB}GLH,JK!JJLMNNO)NKNORMNLLOLMKJI?>7udAJ \7*& -6[JM`MKMOaOMN\M6MLLOXO%NNONO4KKnM_MTKJ>IHFF&G HFEMG?F6FFFlECDjC3BC*C"C;BAC9AnA?@@?v?b=>p>&>>1=?/>B<<;; 9T888k788O77T5X666G5M567776{554L333T2_2o3Z3r3b34333d33.3o344Y33332223s22F2N22221111n2&12222h2110000W//00 02100/000Q/o./[00G//.)-..s-,-?,-?+++T,, ,,,,,9,,-z,-+-s-,-",{,-'--.,.a-f-+,0+,;,--,v,5+*o+++m*+ +++:)))(~(\)((**?))&)))>)))E);){*3*)**** )-)''$'y'&'&&f'(((V'l'&(f)E)((@( (!((O()7)L)* **=)()))))* )/)4($'|)'('H(-.5 J<;8?4//b^NK#  2 l  #[$12}178C97:BD_FF&EEBB6BAD!CgBBgA@AaAn@@?.?=>><>>?@@h<@8AsAAACBBABABIAZBAAAMBD:BCDCBCxCC B[BBBAABCKC BBCDDEDEBEEFFGGZH4JJJ:II|K=KKLtLMqM1M"M)L;LMcLLLMVOOQM MJt xnB+<>)LLKK`JJKqKJ|JJJICI:GDo@9w+($ "   n  9 # -W0[Asl(E/12.*       :  1CGJeKL$LKNLL>L KKLLK~JKKI`KKK JI:>C6rF?#A)# P.KL`NJMMLLMtLMLMNMLdLNO NONNQNLmINIIJI;GHHuH2FEFGGUFE DACtB BCZDABCBAAU@[@@>>=>?!?>7?=,<x<J:9878*788G7666%55]5"565766654T422222t3+344\4%3D3333433u33C3=2?23G22L222212111&2e332311111T1100Q00U00/0E/0T000&./0X0?1[000/0/ .m-+++D+ ,,U+*+,5,-{,++,9-"-4--j,,,,/,-y,,,,++*)*++s+E***)**++ ++|++*|))))):)<)r*=*)T)X))P)<)D)B))*))*K**)**)&'''&&-&Z'(q)@))(''(<(')(((()S((()))D((%(()(((('*(Q&&'';'0)'),*4 LI<=<%4,+, J = y j   G6"165e8~5:j@CBEF8EVDCBBBBWBBABv@@}?@d?{>l?>:==?>>y===@>/@@zBATAC"C;DtD>CzABB@L?Ap?@BlBAABBC>CrB BB[BBCICCXBUB?BDzDIDF0DFFFFDFHGHJuIK(KvJ$IK>LL*LML2KKKLXMKM_LM"O MRWHS  Z@n9HLKK*K(JJqKdK`KJ~J0IbHbFQ@>u-*'    :   &, 0<weh [=33.'x#   % e ?n [! :EIwI:KKIJJJL=LCM M5LJGIIIeJ`JKKJJ:8;\+F%1< 7 ) 3rJ-KMKoLL$LMVMZM3KKM;MiM)M&MMQONNMpL'KmK\J5JH3GFEFG,HGZFGGG]EFDDgCB"C,C[CHBhBABb?g>p@i@??_>?>>@?>=<B;;{9898s8`88 7G777Z656706H67w7m7h72654^4S4344345`5Q454R44!4s4]3333443y2223C23-33@222B2_2f22b3#3n2222 2D1101/0001F0100//000]000/U.--/..-,J*+C,|+,?+---,O++,z-,--5-5,,m./3 ,A,G,j,,++z+9+p*)**G*+*}+*)***e**++7*>))~) ('(()()H))G))>)3)}()v*6))*C+*****)('''''%(?)y()@*D))(()D)V)?()) 'B(()() )))+*M((#(#'(L)%'F't''4'&P't()w),l4 RL>8;9+- ,VSX\]HE  !\ i  j U ku5C3$1. 8!99<5>C@EEEWDCoAe@@BC]AAAhA1??H>>=?t<?>@?l<J>G=<B=<<8<d=/>0@BBABB=BB@BAI@@;@?@A@9?@AB|CBA@@@BAA]?B_BACDCCECCEFE:EFyFGpGH5HBIHtHIIM&LJMLLpL?^?>5>6<E;98$8%8837b78977V65i5a666465P766.5{55{8<&34555545U5N44444!334c44~3t23q3O3>22s2 23112102i2b3-1111{241{0a/000111000I1@10 0011/100////---1++, +++,+,,,,,A,-----E-.-,L,q*+r+,*++@+|+,8+}++,)++,~++0+**m*+G+*E*:((z) (( )m())((()J))(()())v) )@)J*_* )('''"'' 'E&''(*')*(''u( (){()P((J)))*))y)F)N))()(I(((L(''{'1''t&(' ')8+5 LMAA5;X:x(2 U$ ` )     j  d K%2%9;;676J>lF DADE.E DBzB@AAC-BA@@A:??o?>2>>?C?5=>k>=O=>==<>2<>@@?@AJ@=@GA@?U>D??M@x@A7AB@?CB;AB;@L@a@@ A,ALAABCBCDPCD:DEyEGEFFHHmHIuHHJJKRKKeJ/KKKL&I0I$JSJKJKMMKNLM* \>:ILK!MJIIIIlGuGED=\,t% }' t [Z  ," q%.49752 264 4Z5Y,t$[ _  u   Jp *?GIJiL,KN5@JB{.6! [) e% EMLMRMVJL LiL0L:JJKL9MeLnKMMKKyKKK}M_K5I|FEPFFG%FHGGFFGEFPBCCB"CiDgCBB@Ao@@A\@@?A?V?^??>===;@::9\8p6676\76^6555T65[656666555 44 323j4!443c334334333333i3.392223n22N1001s1>010112/11>1w2<10$/h0 /0///./B.//!.o/f1000/y0F///..-/-,1,A++++,z++,N,,-->-.d..--0,-->,-9,-x+++,,s,+T,,-5, ,+y**++0+ ***+W*O) *~))))*)X)))9)C))** *3)~))x*B)****)'&( )(^(^) (X&''^'))() ((A()?)z(((((****(\)L)U)D)))U)t(x('''('i()E(o)u)_)x(S+5 RN<6;$3,s0 VS#      | Le469<>59I CD2BCBBABmBb@B@BA@@`Ak?>>/>v?@9?>d=<$==>~>4<<<%;>?bA@B<@@@>?>?@@B*@@AAAB@B9@@AB(AAC @bAAYABCCxCDCCCDDDEE;EDFG2GGiGHHsGIpJsJKL"LL$LdKK_KhH1KJgI"KbKLPMZLP^K e zC;BrLKLKJbJJIGEEH9-$ # 1 Gn  $ h+2/S2 E3665/2m3~0I-:+<+Q"  g # dja C #-7DEGK]LM5MCLLuKI)FB>);HGHIGB 6?WSN- ( "?& EILZKIMLLLKYKL%LM.JKLMLKMJLLDKJ:KyL~J>X=>z==v;<:*9U77@77 6%677O66^5545S67770566;54J333c3-3444]4d433\45443h362222222331V1P111`1+1.00 011212~110///0K0M/0y/.+--../"//_/00//..V.]...[-,+++,|+,r,-:--:,-}--9.#-;,-;.s-,-7,,-?,i++,,,,k-2-t,---t-0,x,>+,>+++++I*_**@**)O)) )D))))**L*)*B)*())*/)*+I*')(5''('(V))-&&'(('*)^))*)()')(*))I)Q(U(5)#'x)))(C''f&&'5(%)(s&'(C('J)>+7 CM<6m:4?'x9 %WMV  A ;   `  {OjZ*9+43:W;9 9MI ABAAB`BBkBB,A A@@c@@t??>>o=><<=<<<<?:;:(>?A+BBA@A)@>?8>@H@M@#AB2BAIB@@@AAAEB\B\@ABBBJCACCB@BD0DDDE7DEyFqEFHfGH6FFHwHII JJ6K,KKbJ0K!H,HOJH4J^KKK#MNXL`LR\ U>v:JJKHaHIcHH-E[C7) M  ( % 4   U M( +0T21&1^5c40T-l. +[*b' f   T Y  C -? FIJL|JKIJbG?4)3GcGGFHD:?;>PG.+# X-8EK_KMKgKKzK KLLJKJKmJLJKNsMJL MM4K:K+JKjLVI/JIGFFGHII0IuH8FHFFD>DCWBfC>CCCB1A&C BA B@ @U?>?=>2===<G<H:77+7O8y8K8:88|877X6R666{777786545x4@33b33434I3434m33Z333e3s33333+211011`2S221a0111{1200000 000/O//..d,,./O/...../00...-..e--,**++O+,-u-0-~,n,,-j,-h,,-r,,-O-,,+,t+++|,,,+,D,,6,,A,r++++5++*D+*J*+H+*O* * *)))*h)}(*?)**)}))r)S)*z**B+8*B)((3')Y('(X''I&''&))((( ')g))K('':() )I))((/('w)R)(B('' &%&&)&)&~&^'Q&'')5 M=278+AC ?ty<Ba H    R   Q b73AW.K577857I ABCfC]@nA0DB@mBB A@@?@@@/>?7=~>K@r>===?t===x;;<;"=@a@@AvArA@A@A?@AAB@ABB}A@A?@A/@@ACBBBC:CB BC=CEDDDF.EF}F`FrG*G?FDGGGHHGHIJMIK.HGHIDGGK_LKIK]LLMPWss@; FI-HH.IbJbH+E,A2&  G % $  C  g  (  & !+1*/1+ /J0 . {/c/+ , ' % U  \  z g     ');FnKLKKLMK-ICf1% :.EFGnHG>l@8d>eJwG /b) a 7\9!3KRMMWLJKIJICJvJ.IIJKKVLKMJKOJMNNtLKIIJ3KbHG HIMGH&HGGFEFDICCBBCDDBBAABtA@@R@A@"A>=>l>={<<:9V8l788O788j93877777x78%7666O5t5B5G4334544O4344443334 43h3n3h291R12E23}32z3211001101110.00[0E0M10/.1s--q....-.////J--H,-.--,+))]*+,b,-u,---6-/-4,---,,,M, +++T++**+ +++K,4,l,,j,?++ +,6+*A*+F++*y*)**) +))))E)**6){)D) )5()))*{))G*y*<*()g(((((Y(:'|&'(W)r))'(4(* *(d($, )U(S')(()(D((((()F(L'&&c(&''z&&S%&V()''(+86 O>8:56.J0HKJI'HIJL'KLMKtL>     k) |e:.:0<870;i;E BmBqAn@@A@1@dBAB@R@A"@@(?6>>=>3?r>>>? >?~=0=5>3<r<2<c<i>-??>BCBAkA8?> @A1@GA@A}@@ABN@B4A0@@?@ @?@LASBBBKBBBCBB.CDE.DF!E1EEEXEF(FBFG{GI-HHHJKK/KkHI4I1IJfIIhJK]JKLfM]LPUiπJ<@IH/GHbH2DB+4v$ V &  @&  j z mm?-  $ ) -B0s/++* . O+ , -* z* ' O' o#  M Q *tpo &   ] yE"f7-CKLM|M>KnVD5+7FF'FIF3B8<:FC0* " <n- 8LMKwKQJJJKMIgHIbIIJrKfK'KMJIL;LML1IJ;JJHHIgIIHGHGZH;H;HkFEQBBB/B"CCDDDFBBXBsBqAI@A@@'>>?6>=s<<;N;G99c8n788I88G78882768767>6672655v4433344@444J444]34Y3433g33)3822w3223}233222'2e2%2210171`01B11D19000/0/0+/00/////s/./O/...M..,,+*g*)*G*+&+8,t,-<,}-=,,-h-,.--,I, ,V+,,W+,++,,,-t-j-",+q**++++j+***+)*))(())**))))N)()x)p(*))D()P()e(''y'X()&''&$%&'(_(Q'&'''$&8(H(&')>('('')) ((P))_''n'\'/'|'=$9&(0'((({(((+s4 #NS=6m72&PS<;:9:;<;;<9oh.  "     hkzLA)/p<:5*:7SG rBhCiAk@AA}@/>@?AB??A @@@1>?=>={=6=w=<>?s=9;8;H;1<5=<;y=>B0AB3@=>@V?R@p?v@*AAA@BGAC=AwAqAA=@?ABC9BCC:BLCBCDBzBSCzDuDEEFFcFaE5DELDFE FHGHIHBJFK"GHIIIgHII+JKJL(LJNpawtP:E;wIHHaEsC@0# 5 $ q 1'  S V $ -( ,.00,0S- J* W+ + - +-x' '~ > y" 8#L6s= K    J *d@jJLAMJNdI:>)' 3=EaC:-89/8 CcC&2P*  2&/eI6LMLOLLIIIHJ)IH%IKKLL@KIaIJKKJIJII=IHIuJIJuIIIGGGxF FHDB_C DBBBBDC6CB6BAA?[>@@?=v>=>0<<N<;L988k77898888:76O778666665544{3]3Q3448433333!4"23&3T2:22221222C1M2 11323831n01b141111E00100u000/.../).i.0////../00 //..I-,-++P++=+e+s+,p,+-'-2,--/-,-.6.,-<,.--,O++,,5,w,,-5,,,z+*j*+5**{*~*+}**T* ))Q)(Y()))E)M)C()|))))(((()))W)[)*(j''''6&m'&&&o&n&J'&'('-'&(*O'''x)#('a&''Y(()'((W(k(''f&%'Z'k'u&G&&&D'7%f';((*4 M<87f:,3mu;f;C99r:::&:&:<27*w c I d> $O8*3S><a678ZG ?AA@??]A??@ARA:?Z@^A@A.?>y>=>{<<i<=>=;<'<2:;=<;=t>&@k@H@AnA?G?M>>?>?=N@@D>@p?A@ADA6@@?`@@BBEAC8BBTCB{BmAABD=CDlDE-ED1CCCEEPFEFEFHHH*IlHHHxHnGHgGHHvJLLMJL\zkUJ:8QF|G^ErC?1! x [ " +% s  E I   ! ( * f& -1+' q)8$ ' ") - .+,( d! 7  h VE 0 |  ;  ,'(>?JKDN&LDnS?+' ') +P.a7H/89 >A71q* n! +K8YFLII^KJHI@II?GwFIJKaKFJJJSJKTJHHHYIOIII@JhJJJHJII0HHGEG7DDDDECDlCCwBDdCwAAABBAU@>?k??#>/?_=A==;:98t8877[78 7777665569656C5E4322334 3334N43322u2}2]23+3322L11011 22{23 10&01$1)0001131010000///0/X/000:/X...Y.0////K. ,+,,+++E+,o++9,,,c-,.[-..o-...-..F.-,,-,-}-E-|,-,-8-},++*+++*+++v*=)*)((]( ()* ()t()2)>))u)))m)J))q)K))((!((Y'>' '0''(&%\$$%'((&9&C%')'R'_'($%'a'c(('N'M''(((L'((&&_&a%& &{&~&0'(0'(t('s(*3 qPH>74{96n)i;9b8*8 929889:6` E b [UOX0p::68f5s3H SBBM@O?0?*@+=}?#? @@?@"?@1A(@6>><>;<==j;p=D=<=;;F<==.<<=p>?A?@@>?G>|>==|>%>?U>?D@@@@I@xA?A@I?@AAFAAPAJBABB@>@V@CyCD7DCDD@BGCCFEEFE FHI{H{GHI1G*GjFGG/H/JIILJK"Te.P:'5nE8F+D|:{/$ h  '  " +#    *s  $ <% B), /,0,01j. * )X)*) {/-M.) ' $ q  P0   &   @  8 ) ;] }  :JtMdKHZZMA143W88/878 G==1,   73V( FcL$IKKJGI[IQI'IzFHKKJ*JnKK[JIHJKGG@L@C@WA@D?@z>>b>=r:<?>p<;999988U78?78887 747;7z6s67e6w7?55514z444B443Q4 3G343"23%3*3o332312213u23>223>220111{1112*1011E1//V//Y11?001!00;/.--,,.b/!.-. --,+a,8,6,,d+,,,-o--'.g-.-.d-..$--.".i-,, -,,<,,F,3,,,B,-,,,,+,.+#***9))*0**@)))(K((K(((p(@)F);((}(C)*))(((E()* )(m('w(Q(( ''(''(#&'%%&L&'t&((m&x'&'''&''''' &'''x(;&<&'&&&'E((&%&(l+5 Q>758.*=qX;7878X8789;6p u{  2 J2LZ #  dG7-a8E6:= 8z3G |BBBF@?>=?$?a?@@"@@a@??z@%>;==s=p<:;<<|<E<5;x<=r<o;<=l=>H@T@@?>>>?#>[<>??Q>@7AtA@??{B6????A6A@B BB B A@~@ABCBCD9CCCBCACD_FIE EWE^D_G0HsHzHHGIkI^GHrHnGGImJoHJIKLJ[L91AC=n1)T) ,+ ' %+%  (1  F ~" ' % '(,~353.K*( )0+ * S2/- ?* <% $ Q  ~=I5 C # N&+ S1Yt$ 9I8Ke7Q:]r mgySAH;e1!8C45 <#9. ) ! &+.JJJJEJJHGGcGvHH-GII}HFIJ I'HaII$JIJIIIJK-JkGHHHGFGOGHH/FKG3DDEFDE;E+ECED,BB2C5B@A@@>@>>>=;}<}<=3<9988!78%77888|77736L66=6z66165r55o5(44N4H44u433423J4O4V4&4333&23(33)2236332s2J22F21c1#1=1z111^21P0119/0=/0?0140000(00//--.6V00.M,0(,v--,,-..--b-7-<-.m-.'--.---,-.k.>---x-,-|-h--s--F--,,-f,l+++~++?***C*6*)(V((W)(((\(|((<(@(()=) *)((()((((**()6'(b))(''Y(P'(&d&&u%M'h'*@('(&&(Y('''O&''(''&2'p,T&&&&%'&&%&''D'+3 ~N=:4@-h{ 1O;J88878177H895uSK & !c 5 #D 3_.5855:8I BCB/?q?==>?@FAo@S@>I>>>>>0<}=<>===%<i;=y==<<=s<k<<<>]?@A?@>=J?O>?>T>K@?B@3@Aw@:@????7??@9?BABHBOBBBM@@'A/@ABC*BCBDrCDCCEEEIFFXD FIGGrI}HhIfI%J_GyHHIdIJKKL$MIJiSFa83 A;7/>-L07*%  / I T  ' =(( -35T66q. - +)m+!*@/,' 'b)% :  M   n @(NrBd`? *p9 XIW<7;9(834P@!DE34 9[;0 /, % ('2P,85KJ JUJHoFF3HGHGuGIIJ8H8HJGG)GHYGHHHHHHJmHGHHHHGGGI)H}FFpGhGsFhDkCYBCDCClCB6BrBAA7A@@]?=?b=<>j>=;;9899988@77 7|7877G76E766>6u5A54555o56554555~443V44}444444@43'332334`434<4v322 212"2315122210///M/1l00;009/0;0I0B/T/C//00/..&.-,./._-,..e-i-."...-,.5.---./l//i//w..v..}--.,---,-l--,,p-1,,,i*+**()I(''a(X+F''(''(((@)<)o)W(k(())()(#)*H))'')^)(F'&']&T&&&&$$$'k()('W(F&%'Y''&'Y(h'&&%o&R&&7&'i'''w&''u'q'1&&&(K+4 P@p6/::!0mvϢr;I78797?767b7:O6&AR Z <T&\k QWu,.;2/38I >@C{B?@,?G?<>@?@6?>><>==w=<<5?5=b=;<::<=>=8<=z=|<<<==p>x@@>??@@?A@??j>??3>B!@G@?>@??E?@AIABABAA_@GAAA,ABCBCCD2DqD;EQDD D{EFEF-GH.HHH/IHoG;HnGHIoKiJyIJuIJNA.64:3,& # j& "   ;N@  = 5  % ' +.v/8=?7E60 %-0-*w11P-.M-c,"$ #    5P NI>4n+74ZL 6g9F10e1598<@FEFUD14 {59. * " 2|o6-HGHeGGHGF5FGGGI^G~FFG6GjF9GFGGeHHH?GGI.IGGdGH&ItGGGLFFFiFEDFECC}AC?BxAA@AA@B=AAw@??>><z=?0>;:9989I89{87778778795655566+55l55i5 5a445455~7A644C434}33425+333444.3i33{23122&1111E11j100/1001[01h00//000K0/00)}()((F( (K))5)>(((((V))('(A****)')()e('f&'F'&l&%&$\'))(?''&'&'(B'0'c&'y('W&i&&'&E&&''%%&%&%c&&I%&)6 sP@;T:;5pu;78;866728.7:7}(8: #2 " c3dem.o1057`;$=uI HABA @,@R?E=>>@??,@?>?>-==<=<o<;:<=A;=<!<1;=:=e=;:;=n>@1? ??{@A?S@s?x@w?@?1?y=={<J>N>?>????_?@J?@BtB4A}?@}?@@BB}BACDhDqBCCIE CD=DEsGEDFwFEFHIIIIH1KnJ d  ! & w) -0_5'57 532 0-^-... 1!1r) & % $      HJD1\TQV$b>, '  /^BF{DCEPFgCEGD4O4 67. + 4# 6U4* F~GGHZG'GFGpFLF}EEEUGHHGGwGHGEGHMH@J5HGH{IJJII IHHvHGHHEGEEF EoCBBB=j>k====q;;9v99L88 8B7K876777 76C65q6:6s55588@5545444/4w45p4=44M34;4C43333443_333332239222R2Q2Y1'111C10K1100D///00r00}0//0z//07 :947rH @M@?>A*@?=@>?@?B=]=>=>,=q<8=:<2<&<#=<&<2;{<<<h=s=>6>j>c=a>#>^>?A@]@@G@AO@AxAABLBk?>?s?>>;>J>L? ?>>b@?@@?>K=?FA ?G@9A=AkBuB2CDDDxDDDFbD{DEFxEFFF2IlHGGH EFI}GI IDYAGG:C266,$J  *Rm=S 2    T& +23566:< 8 D7512g1 140.A. +) ^#  ! "  A (  k   M  ( 8Y- ," $ y z/>DDDECFTGGJ9e3 7R6. ( ! +?65U' ^FGUHGH&HFEFFGFEGGH0H+GlFGFGFlEwFFFHIIIIRIfIH5FHHzI.GkG1EE:FF4FaB6AB:AA2BAAiAcArA3@@?@U@??>/>u>=D=;:::9L8877777w7665665J56c5555G544?34v4v4474=44?4~4n43323Y3X333[3!3)3433-3n212&101i1)1001=/0J/0090F//0/N//I0H0// 05/000>0 ///9./ 0 //C././.--|--,-y.. .{,,-./7..---a,-:+-E..+.p-.f...p,,---,x++++.>**}*/))(_(q)|)(X(())(((((|(']'T'(]((* +'('()(2)() )1(T(''[',&(((()>('h'(()''5()(&'&&'&&''&('{&9%Y$&2&&%e&{(7 gO9f37 83 ȟ ?A>@>V=|==<B<m:%:<b=f<P<<*:<b;x=>a===<n=>d<>@r@AAMAB@BAaClBBBABGAG>?6@D<;= =><X<?@a@A@??>@AB@@?@AAB|CEDCCDCEDEBF{F4FEG:H;IXHGGZFHHFHF=6-4F9//&?! ] A* Z  3 O   ;  9(*B0#/04I5 68Y8 8 952 3'.q/ o,+Z) K) '"    8 } Y   \9@[  J E  (  = ~ 1?:BFvEF"HLGGG64 484 . &  -8o2"' EGFFFFECDEEEEF~GEFFH!EsFGeFFZGFQFGFGFEGoFHKGGGLFGMFDDEEKDC@A AA~AA3B9A@A2A@A@AJ>?>>@ ?2<=?;l<3;k:Q98879889766766u67l5G564555w455v514~4.344N4C4x34144G3[33333a3I2223322a21|2G211110000/00/0>00>05/./////J0 //0+/.//0;///q..f..M.--,---..f.s.---G-.*.w.].-u--`--/.h.?.---J...-f,,,,++?*++y**)*?)((T()(((((F)(()((U''''''()(()I)[)>(*D)I(''('(u'}'''&''''P((('V'O'&'c'(#(`''8&&&&e%%'(''e'='''((''B&(*8 SQ;Z5:69ߠ |:z77c6$768278r9q8 * lk > -  2^fR((314*5549w9E@Q?ABA]@@&> ?=>?A@?K@H?9;<h<<;:W;;;<;99%;<&<n<[<r=*<<>=>>=>@vA AB@@ABJABAA{Ah=<O?F<= <M<V;;a=>?H?@@A}A<@@@@v?3???ABBCEDCD}DCCDEEEIFKFG-GFFGDDuGvG}A>6I+.')Y6.5*(Y#0 s8  9G: M  o! d' H,-1P3757D8w; : `< h; ; :97 >6 652b- , `+ M) ' F# >    &  U >   a  # b ? T&a) )g  /DCCGHDFSE\8q2 51 , #  672'+rG#FEF`EoGGF%EFFIGAFG2GDE?EvFhEjDFoFEFYFFEYDDJDEEDDDRED]FDEQE-EDLEL@AOABBOAu@}AD@I???????>>>=>=<<@;::"987788:66666L6|446|56)5!45545u5433434D4x44p334B333\233323&3R223&2102~21]22,111c00B1001800/x/u/////x//0//01<0/0c/v/././/5.C.-^,,-a-i---d.?--u,,t++-,,,d+,o+|,-8-,-H.?--"-7.4,-h,*A,#++,0+z++,***)))(X()A)))((('(P((='((''''(}(()O)R*)\* ))C''A' '_'&&E&'n((S((W&'(F('')L(('(U((((E''j''&'((Q((7(l'%!&'I&&%'&)7 cP<B597MQ976666M7.77789ĹWR3   R ce  <Is? -3352; 56FE@P>hC @B@!?=??=@>>V=><1;= :;;#;Z::::$8:!::h;<;9:d<<=<R;= >?;??>CAEAAA^@>=>>>>U=;V<K<<<d=?N?>?@@?A?@@CA2?v@4@}AyB6BBCvCC9C$CD.BwACDBCCRDEBFEC]BXPIX20.!.,S,.''4$ 6  *=k6 1 " ( {( ( g0248; ;";= @ g< > R> c; 9 8 96i2"0 - , ) ( # " N" {      J   P  ? g  !#  xbZ Q6 : z   d$ ;{DrEtEE!GCd>9 3 6G. * ! l&DX32.CESFGEF EFFNFtE EEEFDDDDFEEF=EE4DEEFFWFEE EEED2EEEEFLDe=l=>>q>|>8=;,:>:%:L:98I8767=7u755C5M5G56L6m7i5p555y555?4554z44444453C3{3R32c45U3333P3P33`36251121R21100k181;002000B080505//u000///05/170t0=0t0A0{1-0k/0y/0|.A. --.. /..--,<,p,5++,s+,1,w,?+,,9-|->--@.>.}-.,,-,,- ,q,3,+++*+{,.+**y)))H))I)P))F)})(((^(((?(((=(((' ())+N*_*P(+))''&4&q'&_%&o'{'({'Z('(((k(u(d(S((L''''((W'$'a'z&&n&p'Y''((&'u'(E&G%&'+7 CNP<867F ʘ:7Q67!7.677P78`9{ #[z?j.M074625,GiAM>As@A??>>M==<?===r<@k<.9i;*;<;99:9;:;3;<+<u;;;S<\;;!:a:;q><=>>>@MA@@@>=c>'>=>><9<[>=<<~?"?>?A@?@?A@E???@@@KABC)BCCCsDBC6BBDCBDFEUE CBBE B>M9n6{4}1s+2%'  "   #_     " # 7$ , // 01 G5+8 = dA B E 4E gD 'B ? < ; 7 5 32* X' 2( m$ # !  n       I  K "k [! '  ] ,Pd  0 8  *C4DEDFFb833t- &  # 9>>*-+GEG GBFEEkDFuFDDECCE:DEDEtEmFFDD-D%CCFG2ECCCEEEZDDEBABCDCB:CCoCBjA8@@>@:@u?r>?@?^>>!=)=f>l===I;::::;98Q76R7?6766 54U45656t545p5j5q44v495v4q494433L3E3M3;3S43333 4P33 333323q272B22H12b12b1^11112%1q1*1w0q0?/}/060u0=0o09//0001*0k00c//0/E/{.//H.--.^-u,,z,0++8**,2,,&-$-f,,-a-u--O--- ,----~,,-0,,++I+++**F*)***)<))* )y))(((()))I)?(E(G((N(P()I*)(*)T+H)B((2&m&'&' 'H&'( '(O(()?(((Z*%(U((((I''''d(!'&p'&&f&(('f'&$g&x%&&%o%&,a6 YQ>W4\7z4DdE-777766767`7:D +Z$QJ@*?}tG .*332@48Fm@>?>@1?>=>->e?Y?k>n>(;z;Q;;(;2:<4:h<$:o9;%:p9;a<s;.;=3<>=<=o:8;<w>#>>?AAAIBI@??;>?>=?? ==<%=;>?@#AyA@B1A@ABL@@W@??@z@?BCA@ BC1Cw???AD3BAAXCPCCAF=4 2121,,*]($)L+ .     | -.   Q! 0$ '' 3+0n2<2>3E8 A E I 9I K /H I .F C B ?><|8K5 1+ ) ( _% d% s# U# !  i     ~      t   '_,! r ]} @J.B 0 z0   !4DDFcFaa[530 + ( j ! /(! /G!EDeDjDE*F4EEMCDgC)CCC D{D:CD}EkDDjE)CBALBCBYCD,DyD0ECFWCCCCVA-BD'E]FCLDJCCAWAB@?%@@?6=??>==3=s=6=v== <;^9:g99I9;9K8N777C672544466{6n6'5^5w5 444444h5733363J3M33E232[3333x3<23332023%22102J111011q2.1k11*001"160l006/0/000(0[1S111'01Y00h0%/<@@3A>??>>\?)<$; ;W<:8:;::;;q<;:;j;k:;X;c:u:y;<3<+;;=<f:;F=3;><@]AA@@A??>><;9*303a6:== >v>h?rAjABB?@xA@M@@ @}??@@@BBB=@A ?@@>@UB)DAZBAAU@Au@A.5%('&i'%&!J(g0'g , *   7 # 2:  " ! # 0)/ 124.8 @ .C %J rP tS O cL L J H D D 8@ :@9<3 >1 ;, * ( $ # !  E     M r   "  rf  84.   I% E , # !  m ! %>#CCDsQ5 41A, X) !  !y;" +ACB@B$BD+DrE`DBCCCCTDCDDCCECE_DC;C,A@BCVDDEEE`EEeFIECNC,CBC@D>EC@CCC5ABAB3@AF@2?>?>=>c>g<C;<=<@= ;;:;c:S88K87778D66654f4655T6u545051444y349334525)5<44333313332211m123d3r200 /0%1X0/00@000a1`10v00x0/0301c00s00101\1y00a0)0_1{0"/b/.-.D----H.,^,h,v,),,w+,b,e-",--(-.t.3/+.C.}....~.n-.m.X---z--+,-"+f+8*++u+w*G*=)})W(O(H((X'((M()H()( ''''''[&P'''((()K('&&''''' '(8((I'(G((I''^('((((@'(U((J(' &''S'''')'&''C&'''%%]')6 T:W3>739MN5-+**+d+*+,E4p #2K"lO??z.e31-2B,4\CJ=<?>@?j>y>;?g>><<<;;:;:<:+9}::+::*;:69+9999:@;:;+9;a<?;8;{=(<?=?K@?A?>?@?><:.$"  ; X ! }.U:;>t>l@BCKABtB BICq@BD/B7B|CEBC}BB A~@ ??=>N>=<<5=5;<<==`<H;(:H8988 787C6L6576566s6 6%55.5t445i4555,4455+45i4@44A333I383B3332232m233-210V111'011,1:0n01q0~0/0001./q07//h/0i0Y001(10//0>0v00d/D/?.x.~..N.S-.R,,~-,,,++,-5-d,,-h---\-i.---.F--.q---,,,-,,,/++m+0****)()*))*L)((')((E((('''((r(F(''((()2)p''&''(C'&&'.('('(T((C((J'(E)3((C(!($(T('('&&&&&&(('(W''q&'d((<%%'*8 R?367)6Mm3->%%D$U$$D$$&&s7i"#zZI??"#2d14u126Dr<k>>>:>t@@6=<?V==>%>M<s:;:897698:::8;689I:8:?:4;99:;k;5:;G;:><?LAA@R@>AG><<W/ f !    (U;<@A@?B7AC8?@ABAA@?[?>>H@?@}A1@@Aw?@AA@?C>CBD;B@S=o@D}E~@'!  _ D #--<         U   " & -G1g22T5>A wI L X g | q {r b Y Q H 'A < : 8 X4 ~- .%+ *!)a' % Z" $@$ # j"      ;  ~f  #?; %  " "  w  O 3  +@MFQL2-/3) ." # " F,4bA6CjE CgB]Ac@BDEZDEDDODDD8D;D2DgDCCoCBDCCD CC(BC9CC'CBE]CB C5BAABABrBxBB!ABCCtCBB@@7@??3>S>^<w<<t<;<<T<2;;:_9:N<]8W77 56V5L5444G6N4556/455&5(5'514h45*4p44445444.4?5/3q3x23A223233333t21211121000j00u/O/0s0,////090///0,/y030//////1/..-P---\,.--L+,0, ,+-;-.#-,*-i,,,,../0.q.+.l...e.,,e,,4+,4++*S)E),c*4))9(()6)~)A*)))((''('('''D(~(,'(W((J''( ((K''Y(((@(B''d'(F()z('('&) )9')Z(S'((((('''N&' 'H'&&&&''( &(^'a''&&')7 R;P563A%,%&$E#,#$K%&'AU5 "c??C6%0--553_4wB;:A>=T>r>}=>1<u=?f?>i<;p;;;8G9278@8{97987v569H87:8:<z;*89988C89:<?%>?@u>f>>?2=;8t#! _*87 C  G3=<??;?ABA???A@A%?@??@ABA:AC]@BD#BA?BB}CCAA@ @?^Ac,     p)-.&$"     8 { q $ * '(D% {- 0e182=ABcJ V h  ޝoʔ o s Z N ;B ? u> : 3 , * 5)( N% % # # @# b&'( # ! / f       @ i#4 + h! ,! $ "  % T =  X T &2LC$J^>O+B,J4!2&  u! ![&I;B8DbCZCBAAoC^CpBDCDDCE?EDE%BC_CCmBBCCJBSBAQB~BB9BBC&CCcDQCBD>>}>9=><;<;;;;;;{;H;p:&999776K56\55L7c535566665x555594444444A44i3F40323x3922~2222_2L22X332:3m322\2$2k1k11111n1u000 0s00001/0-0)/0001<00u/t../|//0 /q/>//---Z,--g,,v,-&,,,,-=,*,,-++t+,,--.x-------,,,e-$-+,,,)+++**|**6(()))))('(('S' ''&' &''''''(a''L'(>(''/(()))'1'()<)B)[)()F()c)G()K'(e(*))((K( '!'''\&&&'&'h&]&'("''%%'*J7 O;6v77,!sz*% &$$M#%T%n'D,gBb r| ??E#)20467N9g25@<R=d<#<P=~= >=>h=,>>=;;;;N:8986989?886K7I9878;2:89<64]395$::;><?#@A?u>9>E?g<0 I(8: .gV/  v k(><?>?Y@ A@?@?>>@A@A>BA@AABBCB+CD.BB@B{BBD?7[96-F$!!   k +6-,'$g#    m   ! $ y) ( ' .e:169;B ]H T ] Ml Q§Ѓ 7mP pE ,C > N; 63 A4S*) ( u$ >$ ! # :$ $ '%! !x       h-y<^ >#')$`.& " ]!    e R  ,+EG3),1-H$  #`#0>zBPCCrB-1-.3--i-d,,-+-d,,`,8-h-,c,-u--->--,-=--l+,},4,6,,k+a+6+o+*+$+/**x**o*i*{+;)*u)8)>((('( '&&&&%&q&&y''''''U''b'')((){'((z(():)J((x(K()h(@(( )()&**5)y);(B(2'`''O'a'''((("'(Y'((&'4&(s+ 6 XN<0"65,oX*$%$"#$$&+V> KZDy???V4a$54744&47nA<<>O;<z;>?h==>8<=<<;;=J99 :Z9T6:t9v8s867H8:88~8;E904*E'$ q (7:<4<?*?u>R>@=I>;?*&+9= F*t0 $%<;>=>A @?7A A???q?? @B7@6C+AqB BTACaDPBAbAdCAA@C DCG<4('$ o"  / F'+&/(%)$E# J U    ! # # ( ( 2 c.W7>2M8I T P W f n  ͭ 3k*waW J A < D; 8 2 2 S. 0 g& z% %T&P& % $ 2*r(A%$! !  9      5 %&*5"4(?&f   n  "" /F>,) * 3,4#" $+)>A+@iC'B_CA+B!C4B2D-CDDCCBBKC{DyCrBCaB;A@E@@5@AaAa@BD@J?)@[@D@:@;@@@o@Z@e@)?@@?@A@>?M@:??C=>?>T=R=<<=d=,=e=l;:<= <;?::k::T::@987&7W65e33a2346736 5t546444444:4*345k44445>44m4z414433435 544'22z2[112&11c110000m/v0h10o00//0031"00{1b12322*01(000/;/2///@/>/N/._--]----.l.,-,,-.d,!,,b--..--y-.>-.s-Y,,,B,h,n---,,,+**+1)))u*;)*=*~)))z(((;'( ''''q(y&%%A&%%&}&&d&\''''d'(@(F(( '''&T''(@((((((R((V(())F())9(9('"'a&&!&Y&''&( ''V'(J('''(+6 PS<2K3{6y+'q)&%$}$$e%]%&)APa???-=K"928233B=<>G=<<A?-==>>'=[>k=]<z<r::::::8:h9887?8849099p: 81w*+p&t" v  %8]8<?==>???;:*''+9\U?& '%8<?a>@R@R?<@bA?4++* 2=??IAOB?A4AlBC?|AwC!DuD"AABE+E7DE5~$  x  %** *'++m% #W"   z 0 0 O " $ -. + .3A5 8 > < E T a Wz '4Ҹv ^] [H B *= 9 6 B4 / e* & *#,,/   #)4 CE &.'"Y! " O 4 v h_ vS B&'H(=(o$G"" " | w  -5</t) y+K64|&! #$,zA{A@.@AAv@l?ABABC:BCC B@?=<!<::6C2/,,./-,+,,,)'v()o*)+-7+-+./1J01124z667Z8M9J9<^<b;<g=+<3;|;::; ;Z::998898768\67J44d4M34556l6d6655%5.5h5w4544k44l434r4333s3333@3443333332(22y221R2R322$01 2-00d/010/0h///0t00r//00t00:0{0}0A.//+..// /B/D0 -.P..^--"-$--r-k-+--.-z.- -.#..j.5.(...q....4.6-/p--.F-%,,l**?))))K))K*9))*4)((M''(<'''L&'&&$ #V%$M% &^& & &Y&&N' &W''(}('1(x'}'''T(();)((('') ('(((E(( ''''Q'&j&&&]'&''''('''#'&)+6 M@412'*x<+&%#Z$%^%%(B(BbABc$?? ?!V5{2+;:3/@><===;>>t==h<O<=<<-<;:@<N::99B:/89z87e8G68|:+:;6/-5 F*^  '17w:=D>=??L@{?=-+7+3@>r26!p #+(i9>4?>@?@Ay< -   (<?@B@AfACWD'CiCCCE%C-ABBDD6*0035") *_3 8+#!1 F ]  , <  A  %'' ' +; 10 6mC 9H TX 5a [} 4WLP~ $u gX lJ )D = V9 7 4 t. , X. 2 $  / u'  # g%@)@*O3 (I*6&F%  D = e MI ?  l!  !  c e I # 70l' F' -YE7;8|6R443467776p67674545D55A6'555555w56#5e555b44s44j45"4424$344g3~4v4432F1c2d1112I112232210I2'10&/011+0h100d///0'//00p0>0G//0n.N.D.-----Q---\,---,,,,,,,b,-'-- .6--1-.-~-.o.d.^..s.t....4-.(.0-,~,{+j+*)*H*(* )=)?)N() */)) )'(?(''&&&&%$$$&8'%%%]%%&z%&%W&&&'M&&'S'F&'( (())(''(N( (J(''(' '&'&b(!'&&F'@'P&Q&''2'b(\(\'{',(j)0,i6 NQ=2h46%-:t+%&#\#,%$%%'D5K  { Z +????Q !00 6<3 1<><<==<o=?> <R;=.<=?;D9:<;::T:y8789/877e8n88u9/1,0]U AA S)7;;<>?E? >@3=1{/g2.0-" +/-=>?>A0@7B;0- ##  R -?ABB@/A,B CDBAsC DC@@B>CBBBAB5@@~;U1)9-8.(6$!      0  }! ! &% e) ). . 2V5 ? VDO ,X [ ~ E b   g O G D M i< 8 - ) <8# f' w$  #  % G$ $ f%!%-a*t0 +h(#"   y    !"= \ %X G 4  6M/# )% *<>''   "&?8@/@i@5@BA@{Ao@@6@@1?J;D,$w-4.13q43g2T2f2c1m1/O-+*n*./)-{2455>20w0j.,,,>.1-/-,i,-j.).B-134Q8?j@YF_mxgGktP1>732W-\+H*+(.))*j+155676695F555b6`555'5o5o55454m4t4*44i424+34y5!44)344x35A332c2j2n2o22$111W11f03011*1*1q0//0b./0/.//0/01{01"150 ///...///.M0 .&...W..--h---.%-.)-]---k..-f-;-h,,++*,m+,,,-,l-4--i,,>-5,3++)**H*y)*x)))*)))=(B(y'('}'&&&'~'%&v&&'O&&W&P&&C&Y''<&'~'('z&&&&N&''(c(){'(T(((=)9('%%&2' ''''Z&&'&P&g%&'8&'&''(s''(o)7 P?6644&u(7r:+%$"E"%_%W&%%DdJOCb7Z???? c(.726>9>;6;;O<<7<>?t>0==E?=.<v;w;;T;:P:V:8679<7;8-7w8?8A69o9&/,2 eAf )k!8 ;>=0<?@>T<>>/3'1,91\--&$-d2,{>B@@<>C?@E?5c2m34:)  50  9@>?a? AY@AkCC{?DZC_DC-BBCBD>AEBp@?@H8$-H(37+*4'z$"  `  #! " $$ ' W8504e2 > CDC6J T ] Ӂ ܏ pl 9 4F zp X Y H E < L[5 1 -* )# " "   , " $ %#y$&~',8 P.-H*#  c J4  1 #% !  .11$ " *x2D0.%!`  #v0A/AK@@jB @@????:?>z=" X R.11C37L8=5 4L44J3Q10,+)D(B),,J117011.,+,(,^,V,.u-(+G+,,.4.j/13M2p8S@AFTYt &X? ?wr[G<83d+R+./H,R,0/z/*%0")#+ 7755G4535m5555*444444334+4%33t34(4!34k3344A33W44E22222212 22112]1211{113//0x/r./e/.//G///00001t01207/D0v0&/..U/V/W..//%.Q./].---...-s--_-d-,,*w,#,--,-,,-0-N--i-+,j+*+.*z()W()B(((B)D)*u)x)N('t'''('J'G''E'(~'v&%''':&&&&&z'4''5(&(5'x&'G&&]&s&&&()) ())((:'(A( '&=%I%''((S&g%%%%%%(% %e%%&&(t('D&I'E*6 Q>r089)m.bv)%###E%=$% $u&FCI % HF???GE$75H68#5p8]B5=<<=;y>[=t==u;U;=<;;<:U98;9Z8986766@6777i9381g.i0 ^ z9 | 7  !59<=?'??>F>>>85/WI1=/'5(**1P>?>=H?6?F=126^K@ N ~ 4?a@aA??lB&AAtB:ABBCXCiCAAkDcDDCA=>5*"'/1'G+#! D  I  $&,n&& (* A.77 4;B1M dU c t I| X_ 4 2t @b Q H E A 7 2 )0 - |+ ' 'j$" 1# !  " m " &/' Y's,- 3 -3)!J N?GH  /  ;/" "  Z*"% X  $ u-61#Q b! U! %|8B@A@`@@&??@??>?r?g=O( # 'f0t061e333"0C4I4320,-&++y+,+P.++M12h3_32r0. --.y,+[+-,*,T-./0 --?/p5<@I?EOGe QI#@+86a2/.!13N4220v0-,)s$ +t6@5B5B5D554t55y444t4455*44-33335334,3^3k3|22373M2Z2211x11111%.0111j1c00191h11000z00901X0h001<00D0131o1;1q00r..../~.-..^.. ..L..j.'--,,a-,-+-4,,,+!+#,+r,$----$,-l,h-7,,$---!,*,**))V)I))))*{)** )(( ('((''<&Q'?&O''6'&%$|$&&'%&%%'''K'M(,&&&T&&&Q%'')R(R(((9'((E((b'&%%K')E)&&)&m%%&q%6%0%&@&&''x('Y&&*6 O;W4674p&k,Gx)%$k##$%&%&H R(????{b7: 1763?7b3e@>A9]:9; <p<=>>%;R;:S999Z::;:::P9:7R58;8E7K6L99s8581*/ yB U 8 k  ~ t ,+$;>>?@>>=?E@;19NB17*U$}#"8r@=>=?>:14!7lD + ( !0>???>?A!BZBB?YBCF^BB$BCCE3EnB@?06v+-)h),+ &!0     D  # % -# :(( - X. f0:8?8BK DX ;b j p c \ Fn o Ze 5S8VD E < I< 2 . , + ' ]% F#  &   !  $ $ ^$'H()14.& ' # ^ nl  C 8 -""  " & v  ! 8+$/.c$    " *Ar@(??6@(?>>3>?@>:|'!! )*',//.5,-B.,.u. -..+*L*6-K03=33q2.}-.&.%.00B--[-.`.L/0m/0^../ 4:~;/<f@eEIySPAZ;975$21/0..7022l0|.X)h&#  -45 5D44505p565545j445y44c3C4C334;41333}33|3;2222Z1f1100,10j1m0M0111'060o0^01010w0;/01+0/O0P/v/0m/0001t1;0N1,00//E/p...^...+.^...---k->,,6,!+-),~,,++u,5++,d-0-h-,,---a,,,.l./-m,#*+>* *2)(*B)*K*@* * )J)K)a(()B()('' 'Q( 'O'8''q&h%%&C%~$$F$% &<&&1' '&&J%%%%&&B&P&\'H''@''V((t(<( ('%&'&( &%%%&%&&$%(%&'k&~(((h(()v*7 WO<9361%[.n~,&%$O#&]&]&&V&J#S    Z ????ljkmE-1;:N78 8iC9=:#;K;<{:i;=<);<A:Q8:R::g:]9G9:O::8J5 77I754B8'9*7p7-*c* 5 7 +  %[-0,S':<5=@@???@ @+@y=uEUR _ G n@`(&}.? ?=>>=s<:323Oy-8  W ,}<?Z??>??Y@a@BVBC?CAB)BAD$D$D)B?>Q2(_-v/)+,i'   C"    ! 8$ z$ +L-' 4%339s:0<D M O W W GZ kT W \ \ b #wHA M < 5 :4 1 k.) ' $ " " T +  D Z  " &G& '3-0.,'y    )   $4 # _ k$ "# ! ,/"+& A #  4"8A?>>?>?0>?@h?c?#>>AT>;<.Z$4);-m0/-+K'0)T&&?(,-S,^/{-U,,-1o35H2101/1/--F.|1f0.-y./.161/105q8:7<;MCQHC=865'3 320^1N.d.0-+#+U)]&\%F%+z335A435k47404515(504}45'44444]44u4,33{3r3|222221112;1C11r001+1.111\1!0a01130//D//0|01#0-//06/-////r./00x10////.]/H.3!/Z/ /m/.L.&.,.2.#-,-q---)->-(,,-,,,?,u-i,,,,,r,i,,,,,,;****F)))E))8)~((|*1*,)*m)*8*);)(t'x))l)0('y'<%':'0'2&&5&%%C& &&{%& &&&&'1& %&&&' 'A'~&s'I'8(''('&&&&[&&%%&R&6%7%$% %&&%''('b'x'){6 NX<\/7"4!+3@'!&%L%<&&&D&(LKѿIJ 2;  zEH????Ne4a4.9;66B1?&;&<;:99= ;;"<.;<<;;i99<:099:959h89z67J767!61,*) %+ , $) 32]+S+p>F@7@ @@9>??>]D\RM f _ VS ?6618;:?'=>7>=8W2T.,:Bg, `'$5$/<h>>??@8@8A%AB7C@#@,BABC!CYDDuBwC@<0D)$*')1'Z)" E I  W O ! / ! +f(@(.. 2D75 *; S> /F 2L N YO nR S R HV N\ShLaE @ = > %<=. 7 )) O% ^$ !  ""  1    ? (''j-S,M-+@'! '   @*  q    j L"  " Q" )\/I% # I U   1! *4@@?@R@?2>C?+?r@?0?>>w@@><6<"A$'./ 0f.(11u.-/!00@1H6K5S18AJ1]^UQ<%833S52/-1{424%0s.|./.I/+1J+**+(.22753323114b3F16<346y454 /@-+~(.$5_6X5J444444E4}44574444434(4 3333v33i2233211123A2C11211-222h2-2w1+01000{0|0;/0t00k/s/0008///0t0C///.l/m////-./@/......\-.a.+-+-e,-X..-G,-,,0,`-n./--,&-/-+-W--,!,-&+,e,0**x))A)I))(''(H(r)p'())(q) ),((('y(((5''D&%$%'/&'i'%'e&&''&&&%'''C&'<&&r&&'''''m&&'&('''''S&R''Z'&&]'&&*$%%&&&;&'((d'%M&X(6 Q:472'+4+'%%&&& &M'M z " `?????b8126|72 ;@? ;<y<)98:k:b;@;N;V:=O<:K;9:;::r:=9}869M8Q87B74776}---v+T-U+n//h,&.@t>@b?D >A?=^ { q\ K K ?> A =:>s8>?&@@-?83d0v+43*!+,,-F3Z<h><n?????A'AC%C!CC@BBD&CDEkBvA:-(%z$$5!+&( P   {  f "! B('# Q( #, . 05h8;~= fB J J oM Gbf [Q U@NLIC ? : 8 3 4 7 ) ) {( l#   < i 6     Q'&'){+'$Q%   gg 8F     # q  # & )'" k   F  '#M6@?@ ??@j=X???*=??3>=?>J=9'!$p)).?/0g,e+"*c+-L19 9.9};d;<m>+CDvFhEgEDGC:m7;666525M2/024552I5:9<@B$@GVYKEB=;p653346 5 4448/*#(")456 6H55B5?444B4M5,555:434r443{33w323A23222T21100122B11i11111r2m2"2211U17110q1 0/001400//0//00?/02/6./0/// /B...../....'.n--!-i-*,-+-*-#---*,6+++,p-?,~+c,,%,!,o,++,,,j++*p****+,:+***)**u)(()D(((r()J('J)v):((;'x'%&7&'''l''+&D&&'D&%&'x'u'''<&%&''G''}'q'>&''&' ''&&8'\((W&%&&W'&%&l''&%C%'(('=&F()9 &P9K66k0$%+ۜ@11+e*)('L'M''N X YSE ?????~Z_--1'9Y6Y69?;;I; :v::::<::Y=w8:;U::9:q:s9w777 85O539S6h56U5L,(,./-%(Y#n#1^=<w=AHlM R ~S K l` t k eFM D !C =B `H =C =62M9??<@e:800.]4:,$)W7B06>M?N=?@~=?>>?AC A@@kCPABCDDsBA;;.&&$%#$$}!!!!!!   %;$ /" %' '' - 1 1 3>">.;Z> fE L NH d]J XU ]WS HLT ? = L9 gDb; , ' ) " D    *      G! " " '),&7!J!`"  0 .   Q       @ % &m)#    O 7 'B?A?<>l>0>>?>>a?1>?=>X>=<L/ # $L& +#,-*f)'+-18989;<X<W>n::<*>B8:7E3<10-r,&+)m*i()0,+,,/8:<Z>?>FD:>O=Q:B420262885$641-*U(/@544555444 445-5s5:5f24$444!423)33w223C2A2Z21001O1111/1.016000q001.00_0%///?/./=//l0w//k/t/-/0}/0~/?/../~/.//..///.../).Y.-..7.^----,,-,,-,,,w,r++3*+(+,3+*,+)****{**s)**z*|))) )J)))())(()h))){((A(('(2'7'o&&&u&'z('''|&D%&t&T' &&&A'D'&&&' &''-&K&&%%&'''(&&']('&%j&&&F&%v%&Q'&%%&b'''}&&)5 P9^154$)x=O536<R:8h87^YkL C  a9J?????f 51.@2-|48@n?r:::98-859::K:;9);c;!98i8,878B577f5>3c5F458v7/53/'%*-],J![%")44;#:@I a ,\ l ^l x _ Z r[+AD ,J w?!C 8M ?P9+4;4.5b>=J>a924)/Y3>t'(~0@A83;=>=> >@>=m<?@"B!AA@@@AAB@[>:-B'%$#D"@#("l # /$!  w  X# (2) ) *..05 FA981< C E H pH G cI ONF B y> = 74142( X' , ( # }!   n# ,! S  # v"# G$:$$) "~!"$  X  A      !  , |" (# b    9 F#:@@o??i??x>0@ ??|?.>;>? === =:;5G \"(])!'I,|,h)d,v+*F//56*6a8H;k<;=87:=::`7331-,',\,)>'),-$.;03F49;;=f;HDXCw>->b950/1r/446a64B1,(9&6'13L4555w444F44 345544444444333p24|3H3>2H1111.12c10100f1s2112'11100000000//x/N////,//0:0m006/0./00//0w0//N//T//]0 /_./...&.'-,-.---y,-}--0-7,,,$+++,,,I++,3*)))**+i*()))*{)K((H((I'))2(N(()()))}((0''&'&'8%&&&$$%%%H%%&&&& &E'@'&c&'&&&s&&q&&&F'B'h(;'&&&&''B'&&'&w&K&%&'')&,&%'('&&a(4 R :098* 'Z%F&bSq[N!%$%0:0S  e 2K?????nm+d34r8ZBh61B>;f:;>99(99*:(9;;<:979!8c7998q886m7"58:767m6~424%.Q""$ ]"f"*#%*E;<P:"J;S f _ | Hn p o c ^ oZKN Ge!W R E B6:3418u92;:12/l/j-(*15 <;T:;:8=<>>k>>?@/?ABi@@2?AAAA??i:i,%&%%$##!(   !    &)$ & -,b/+17(9 :I@ "@ b@ C yB G oI D C > o: 5 0 / j- >( 8]( [' !  A     # '$X     " "  "#[      t E < '$F  p'!  C N    2~>?<<?8@">?*>?[>>>>g=w<D<~<=}<:' 3$+'#,/**(*)+D.2T478;=;=76;<;9)52D1K//#-.`,i*( )g+L+I,/258:;m<=C'?_@=9p4/-.0465s541"*'$+66D656@4444<4F4|55k5;5q5344r4o3322|33(2@2V211151l1>001 /i0s0100*0s01 01'00021n10//0z/ ./:.0$/00/0121)00x///v////L/0p//?/E07/.000O0/..l.9.-.c.\..-.--%.o-0-1-1-/--Z-$-,,-m,+e+@*;**)))z))))*0*(X){)?)G))R))O)-){*-=)v((q)G)j(,'''p&v&%%'('%%%%%%%,&X%&%&%A$%%&'L&%C$%%$% %&k&i&'>''&x&'&' &&Z%&&&%'3&%$H$'c(T('q& %(4 R;N0:84&y+`      Z = T ; d %?????^-S,68 946= @1<><9M98998:i;e:];<$:x987_7+7677F87567 45D334(5742&}"G<1A%(P6:@:;T b xV V sX Q l ^ `O J h/^ vL TF X M K=A>@#@@BmA~?D>@B;CA??:i-y'z%$$""! q![  Z   k!Q!  N" # z1+/ -23A: 8558 = P> 8 ::N=Be?>64 3/ / -/ p0 5- 6;% # > J  C) ) "  K  U"   m  @  e  ![!t!#"        U ( -)A I  4    <  +;@9> = = =@>>L? =>q?>>==< ;<=8;";2! ?!.#$^&Q))&(='*401n3I43}6T;::6T58u:o9:74 1/v+*#+p*&%+u+B---e,l/35;:2::>?=<;L70-/-24413;0o-*(a%%4Y8v6 5554F4434y4454444w44494q47353?22h112L1"111b00y00U001a1/001]1[1000B//q0*00//M//8/x/{030'092/9/01<0/./L////00r//e/300l//[///#...,-----w-}-"-&-X-/-(,,x,!,,f,-c-,,`+,4+++*A*t)*1*)G***) **9)))(););)J)h)))+)})~)))()v(2( ''(5'h&v'&&%%%%&M&/&&2&2%%$% %%v%&x&_&&U%&%&%$&3'@''&&'&'&&&F'&&&'J&&[&3%%$%&''%%X*6 TD=y3W<Z9@*)#)  |S( [    {?????eA*7O87554<@:;:c9m8(8879T;;;:9966566+68864^4211k34X5D430o) j:.f,:<<-<<WI T Q zb Q_ u i V a ~} t Z HW V T M !Ah@54!324D27m:=1z(B "#9)-4d;<=b;<>W>@?A@@?F>'@6?@A*A0BBDCG@A>/Y)(g%Y#\$ ""%""U"! # f# $ &$ <#)$-*,l2 336[9x; w:58u=46<N5 6 801 , ( + , # !   " -!  x& v/ "   v   =    ! #X"  v V O     +" u    h 4W  y w8=?F?v>@q=>s<?:>>>h=<<@==<z=>w>]<6 " +"["$(+)(/(){+0.T00347898z5a2698Q5w4//r-,-<)%&(*d***+/267:Y9i;<q9:83)'v%c*F1h4E2x.l/+)K&n",)66=6O554Z5_544e4345{5t44C48333>3o22@2C1111110071E0$/0c00e/0r004020r00/8./0+0?0// ///>/w/0C0///00./ .////|/F.0:/h/w//////a./Z.).$--+----,-F,-2,-*-,,,,,x,,++Z+++***+9***m)**{*9)(') )K([''((()~)))) (|)5()c**s((7(>("'\''F&o%& '&& %$$&&%&&%%%7%c%q&'&T&''K''&&&%'5'&''L&'&8' &f%%9&\&''%%&#&y&)''&&%%+:6 |TK?)33+2&&@8 o77!!! r h  JzbZ??????d'-G=:;9:<?9;4:86N8879Z9::9:"8S8\545779:8U665533h22200'12>2>1:,54'7E8;AIM G V b hw c Qh z [ nzXt w k `T X Q K nAM<<;>E89e0[.*+j&w!$#}%[%,R889;%=>w>?IAA?:>K>=2<?:>2>x?@AB??>c?<0'&$!E!!"O"O$.#V$(%k% " 3'&% 7$ '' m(z*. 70 2*59!;745 3i6f6U2 H0 2 44z2+2, ' .% G% % #  ! N# " n g" %    ~  )  8  =# "!   O @  :    nY| M  ['<Q<P=>V??;>>w<=T=N><<=?===<>y><8)Q Q~!s&,,)x(2((q,i-80/2168]8G7S1389=62B1Q/.>,,(U)!()0+.z-n.w-p358;<??e?;:<:S2,{').3220?/f,(('$076A66]5W544?34Z3C494z5;4L33333 3r222:112 201/1+0;00 011T00000060f/t0+//f/`0k0//V.l./L//08//~//?/}/L/ ..p..a./@/}//v///v/~./C//A/.R.Q..-j..q..--.,,,-+,?,?,,;,3,,,,a+++i+1+@***<****))*~)*8*q))e)>)x((((W(()F))*)**.)y*((E'&''9'2&&&B$%%%%I%[&&T&&&&r%%'(&!%'&Q&X&&&@%&&'B&M&<&y&s%x'v&&&&%'&&&&&`&q%l%%&k( ((('(.(+24 T=3l30)u(1 v8x"'(D*e..~91Q H A  !??????^o-2s13648<?4::98=66s87789:]898n98A608k88:7_546Q73B2f4\20/ +'! ,)09'O: c> M l vjq hq mX Q ez ]~4t %o f S |X Q P CLAEU I 7928*)$ # 2u2 !:$%(.L6:=>@@7==u>Ac=>9?2==F=>=?>> ?g>Y;2( #>>?C==>z=>>><=?0=;==9b0  %*:-?)(')',.K-e/K/2/176512296Y473Z1.U,)c('E%2&*,+.<-6+b25:87=J<:o9184*$ #&,2 0!./`($`$$Y)15]6V6P55455A44437)74}4 33414w333i2221Z0/00`0*0>///g001Y////0.0//@/0v0\//|..././C/I/0x/0{// .-/./X/.//x/C/./;/>./.|.M..&--._.----7-b,,5,+G,x,,w,,~,++,z-*,,0++)+z+1,+y)*)A)*4))*x*)*;)A)r)1()V')?)u(())w)))))})*p))*''m'G'q&&w&w%%K%>&1%&4&C&& &S&&&N&T%' '<'&&&O&&'r&'&' '&b'%$&w&z%&'B'{&&&&g&'x&O&$&&&&w'%%(!''',3 \u>273& &6{B>6z5&  " d  b SrS??????n33\926565 ;@*<;:~9r767:8S8:s:9t98>79o9;r;r87766%54(0//." u K # 'S 'B<{` V b e Xb jW ^ T Zr m puo r  x j w` 1^ K H3CH S Z F >r9L2'!^!"j'/ r  ;   )*9m>=>>>P=?+>G?>:>@==U=?AN??H=3j*$[   "!  ! v !K"%7&)#  %& ( #+ M+ }. /1;22/-* ,0.- %,-)& *U+& ?    e   G ! + w9|&G    *         r$'H%$'' M  'w 7  " :Y77B9;;:>5>P?:>>M<;;<2=>>=&=0<z>I=:t5s#@ <!S&)(&*n(n(*,.0/1654;2Y5a99p83C40+-.d+)&)e-.//2-{+3$9;|><H>0<<V<D:t7N0))*"/3).-S%^M!%D!-6g5775e54J445\5D4333334=434:3x2E2221Q0Z//...///0 000.///000>/&@%&&'(&&&&-&'W(J(((O)&- f6 ^c{=2"1=2(C+3(L8ݷĬԬ]*$T [  a -RU{y??????^ Q1151C4N8;Z@c<r;;h;88m9X9U689^8 8)88(8f7:;q:9u99=67 4I0w1/")!    &,0*j%.PF ZK I G J [ d z ^l tr N{ h a m @g o _ O E(?[ N QN :8:!8*2x)"S j,&#" / o     w "1<?`? ==>=<==>K>?q>@$?@==A<8-L% T   }  #E  " ' .&n'3" *# " " %& <( P+, /+-h1&0"0* ' + 2d.|1>.+A*'z*&& # ! l!  i 9  0  @#)' < G  a   j 1    J) |   $$%'W ( lgR  K /8 680:v:9;<`===<P<<>><L==G<==t<<;7- "$% )G(L&()_)*..--1+4207069320v.,/*&6'$'(n/T/,0w/>.5S;=h=w<@AJ??#=4/*(d*++W0S/*r+"U !u%45o5v5i55b5d6N5 45T43!23344I333@322210t0-/9/?///M.//f/010000:00D//00///0-/?/0o0i0Y// /0//0]0S...$//..---.e...t...j.m---3-}-s,-<,,,I,J,,,|-=,,,,,C,,,z+J,x++++{+ *+9)*R*+2**2)))7)N)((V(r)((())F+{)))+0*****u)**g)x('w'0&'(x'i''9%%N&R&&&&%%%$&&%&'?&7&%&&% %&'t((P'(a''_&%%;%&'''&z&%''((D'%$&(''(>('(+8 _@5_4:()2lKHby_YX e\Z??????u1D5345l0C8@W;2>;!:^89887Y796k5Z87d9`9:89o99|7h7t53-.'P )  ?   #+''# ^%X3N P I GH G O v d [ q p O] ÄoW~ Vg $f E3?8>EO L XBG<=8.,& !""&+.@!ig   U +-:><= <Z=> =>>?@=D=@><><3&) *  E  Q Y!  y % 2($(*" |! l$ & l( )m1-N,04U/, ) , .- +r( ' & m$ # V" ! Q   q I  1 ~! f! N""  G    q ;  M  @ I  D Z       S ' bo  ;   # 6769:;;u;.<:a<;>G?>==D=?=>l=<<<t=<z72 q W!a!%%%l&z&'-(+,)*-37M4.4?|73W0t-,v)-%&u'+,,).3-Z/&69+<@?G*HCJ?q8,I'y('-D/G)'( K d.q5 646t5}5=5t5%544#323234432H3_3223b1=1i1?1,/E/./ /V//0d/00/00000000600//1121'2"0///0v0../,.h....e.-.-~-,---..--i--0,,r-|-,z,9,,=,E,;+,C-,,K,A---q-0-,,,+,+***>**+~)))5((((((''D(( (()A)))*{*r*i*)))))9((('w'':&&&&0%%%& ''&%%~%%&E&''&s&&'&4&&:&t&''U'(((P'("('& &'5(:''&T&&J&'x'(z'&&''(%'&''4),5 Fbu>164*(90N>Wu/Dh^%k"[+??????e 6867c25:>:<:88i7/8[87777888,9a;9q8:t:p9863/,<%! A   1L-p# %A JR G ^B)F R (j W *S ;F q[ >Zem p R |N zT Dz;1&= A>I 0M >F 75.,# %"c  r /j   ,:::<+<K<==Y=???@?BjJ?8-%  B }  e# J? h )K E * y  ! % & &  m#% % '+,2<6U;h2--1_-f,*E(+|$ #  A #  :  K  "  k#    `  {  ? F      :  ?O T  _G +^66v7o9J8u;<,:;<:<?D=U;::U:"<S=?!=n<W<=>h;(4)( 2!#%~()&(m'(+].T.+?+,5>3.-&1^;\9!4//J+&+(&&)-615914$2F8(?bHPP!CeTM,C7(%!(8(7.O/-(|!s  "24W5655244655S54343c3X34l543233222900R00/^.../p0s0@0q0/0y//J/@//02/0f00o/ 0-0/00X0/'./,/s.../.....`-z,-,,,,-.. .--v-~,.<-~,S++*+\+,-:-,-,++,, ,H,G++++]+T,}+A))z) ***))=))()x)()(V'(*^(() ''U(W() ))(){('(x)7)<((,''&&J&&5$$$%%&%%%&?%O%$$i$%w&>&;%%%'v'z('?')R('&(c'&'&&z&&'A&&&&R'('''&'I(('(_(Q(),5 bw<3809"!*3U oP˟-.,%U |???????0527*8N7@;;::c6777717d78U8c887m69i89g<$:=:i8?53v0%"#1 x} ! D  + 9 55>G CH =? ;bI [ e zZ 3P K A7c<4C-Y1p>3^6H9 I;h4$+ %Z  !A   r eO{=5S l 2<O=E<Z<;:;><> ?8?CU:6GA5})-    O d#& :% $ N# l" 6 # ! ! b$ %  " " & v)()+16b23720++~*)+F) $ !  L 4   V   $2.   U o  U 5 T   H! j8  <6^3L2W49X? lB 7 ~$ 8W7 h H  37856'649I9:<:;;;;<;:V:`;n<k<<<<$<d=R<950  &(C)$&%(a**+*a***23.[--e121,p,-+)(,/1V5)78Q34V:LK X^vY 1f hWFc8.' )+O0h1-x) -6z5z544345g55344P33W33333"3(232110///.-c.v./i/w01+0"/=/~030///C/00;010//9/00a0_0/./C..=.6-.1.--y----9-,-F- --&-Q-.0.--S.,+, ,B++e,+-,,W,H,+,K+G, +*+,,,,S-:+**+W+*)))) ((()))W)J)))(B))Q()H*8)))))M)?)({(C(''B&&&&%$$$F$$$%%$>%L%$$$$$9$$&%&'&N&''W'X(((M&''''M&('&''' &<(&F&Y''(:''T'K' 'Y(K'( (((,3 a6</26!=&2Xs+9r $#C[B???????#+-1Q-1358@t; ::9k6668"8776~7c7&76c8-:79@98 64510*Z%%#^ < R,  2/c  ' `& ) t4 /22 /25 1= F < : 6 m)#n)&($v I      # $$&"$ ,t( di d  $7M;9h;<#<<=Z?>>>@G?1+/)#       m !   I     5 "  ! " q$ '4((*.'31C/G19,g';&'R'P& "   o ^  /    I 1.51*E M & I q b>  [    B4E ,6},)%{  ;%,4JQXB f* q u&  D# y6:8777 5789;;:;<><<;I;<=<6=8:<a<<R;; 2[$ "&)Y(g%'d(,g.7-P-..2#32j6/342k--}.k,@-&*-b.f/313C546>SZ@xuPDw XEo<8,q(,1n1f.&NEr 4I45.44454544N43233^33a4%3\3 2/3a20011}000N/0W00b/0+011000|02=151-0=1?0/0c1:01#00q0Z0/c/u//H/p./8./x.-.v..-.--,- .,[+,,?,-b-,,+u**1***,Y*+ *g*f+,,M-++N+,+,F,G,,,A-,+g+t++:))))M))8(())S(() (()a((()?)))()W)))) );)t'''C'L'' &Q%r$E%$$$$$P$?$$P%Q% %D%:$%~%%%&''''''P'''V&'&&e&'S'((''''' %&'G' '&&b''W''~()')- 6 e: 734&'&o5Wp6jNb-b{+z*???????? @+05=408Y>:[<;6928w7m778d586/6$55.66r99; 8577310d-'(!`  P z   f#12)!y#Q"M&t,)"Z%%&&)# $)   <  \ S u      m*+AI'3  2   k L  "+-h9:W89:;|<?=r= >S=g?>=DE<J4C&! , 1 % 1    ~ 8  # 4  ~! " ' Z" r   &&x'3),U0_6 2]/-/+*'.< (e(m&!   { 9   r  -/A+!C      J+4  -/<;u3(V%  |  8 ! /567139, |  c+6628&655c6998#<F;;;<<;::;m::\<;~:b<K<;9_:D5* !$ (*/)X*+-V/132;2=0/C/$-*5*&$""$0$#"o$$',q-|- /5?eǍe}ϟ _rF>8B+Q(-3S,*  E*46!5@5}55$45K555 24322R2.33X223i382010/P/0./0///e031p00100n00s0~00000t004/0///[.../4.---/}..n.+,-->-=--=.E.5,-P-,,+E+,i+-+,%+7*{*+++."+$)*++,,,,^,/,+, ,,-<,,,+}*++*B))=)())O))J)()(Q(((Y'()())J)))))=(L((U'''I&&' &&J%H%%E%$%6%%u%D%%x&q&}&%R%&&%%s&'(('('('&&'R&&'T(2'''''n''(2&&'&''K'R'&'&(`'c'(w+4 c=f8*9)7%n%3%YGԳ hyl=rJ"ha???????yg A)F1H5557I7R@;;:n87t8599&8 686f57o6j867:@86E444+&"! t  c &$  !^#A   D&x" $<0=t. *'" !  _   ( %b7 i$V0    F)-3;'  F  v `B   4P )Q8:b;S<<<;>R=W=?<>=?L>-&) /E  ! & &   <+ '   e % r  # ;# (,051/.E,*+(-d< *#c$&$ "  X    q &$     ! Y C  " 695+"     &@+t%<$$H%(:3I.  | 25k789 97989L9:9g;><<;<<;R=<;:]<f<;/:870v O6 $(.++<(M#"   X ^  0   . p    ~  < M   +K..Jaj` /JD=7N2.o7kIk0*gp #5q586"55;4444545I5 33322X32322i22151200?100[00Z01^2i1a11_0`0l0u000011111150|01/.-/..2.y.+-p-F---=,,----1,,-;-------&,,-,+,Z+++'*v+*+Y+++,+,,H,%,s,`--^-,,+,++n+y+Y**))))))())T)T(())V('s(())A)) )W)+>)L((((1'y&&&L%&$&&A%O%?%9$$v$$[#$%O%&&&H&z&?%&(&o&'['(_(G''' &'m&'S(W(>'D(:'(''''J'B&&[&&'O'''1&&H&I-'h') ,%6 `@M3D3G6o+,I1iZOe!jrjtnhC2/ l! M????????BB -{113026A :N<:,9_938o8 7i7q6<7h665p68+65 68o6352/'$R    | q   x"$(-&'&! U%.+,-)s(*'/&C%! V %   } *2)*) I h     M N v  &4;<<=!<=`=>====Q<;ASI5i%     %$   * 0  B q    M" U% 'Q(.3%3%.B-))((-0,)&'%E%N%$\  -"8%&" h   o`O;z -62-y&" |   v D # Z! #   ! " ' ).7:375k6m7899W9R9:Q:J; :;<<<N<:.;<<::;:<<:;::4*&'N(qe  e  z5 ?8# & $ i6s U     4  f C    Z#$;$`#',IGA#(!  +566r4504555 4555C5@43211123[22(112j1p0001r00/012Z1t110l011|0,11101n1(1p10/./c...g.-...?--),,|,,,,,-.,,-=,,J, ,,,)+,,,g,+^+n+g*+.+$*_***++p++*+F+*+U+,-U--,,+++J+**P)*P)@(((((_(X(g((((())=)<))*F*F))H))()((;'&G&&'3%%&{&%$$$%Z$h##$x$%Q%%&@&-&Q%&&&'(T'f'P&'j' &8%u%u&6&u&&&(r&&B&&%&l&%&&H'' &%% &V&N&'Q'](_+&4 o]A7{48(J-5^enf]~qC90S k????????&.2*;X11j75u@;;;978k78l845|67.7*565u761665236w17.'E"9 z     t V#' +.--p*y'(!  $g$1' *,,./.-{-)'&  6  [ 9QR L )6R   S=/9&  /  K  ' Y   'w3;<=<:;<=W>B>)>*=;m:;kOo;}& E ~ 4 5 /" J 5- ( o Y   v _  ! f%)..8/3+N)())'|)-)&))(&+$B$h%   !$,)$  L "  c"  " /G/+'($ v"       l    ;$ 4' v) O+4e=;887L839D:::F99:;;:U<:`;:</;9:?9:<9:W::98<0u G K yh   b P y       J | f 1#  "\%u)*# ?%!c%'5,'925r6!5415(56Z55M45455x333W2W1^11$1f2b111o1:00I011;0100f1 2$111a080)0i0@/O0501-1l0(////<-.u.-,j,------++,t,*+++,+-5-,-;---9- -,--,++-+2**-*e+,f**,",",],++W,,,- ,---,V,,++*+K*W**[*!((((h)Q)*(())P(O)j'))B(''()R) ()({);(O(T&%&U& %&%&&&&%%&{%6$$$a$%8& &&&&B&^'&e&<''&'!&X&&9%&e%&%%&' ''&&]&I&&f&&'&(&&%%*%I%&P%&Y'5*3 oS7 7*66 "#4^m|ٚ"6o [" a?????????t ' 273E2z:7J@ Z:;~:8h7h78888j8(78\645.673765654-( '    Z <  #R' 0S26 /0.+% ! $%)-/2|;D<;763E1#-{-:(-"! ^ 5  ! $ S a WdY}I.+j   M  l !e%$ T   %72;=g<<<====T==s==:< EB(!l , :m 9  <  ' !   # V  l  ,  &, +-,2*&+)))(a(t''&(']%%& #  c ]$,'  /  ` UG 7 " ','&"   I s l s 0 L    " ! ! & ( g)t,3\:=[867 99~9:999:99; 89;&<:6::;:Z::H8;:9v3!w E  t 0 b (;42m& !O XP.; { _ [ I   M  & *#'22'.-*-'^!Y"%J&  = !  &57)76O45j676C5_4I545 34Z21Q2#101'11)0311)1o11000000U0Z0C0010/w0000)0900//0/x.----.+q-.d-w-- ,q-/--,,4,4,l,s,,.k--<,.|,,,-- --+++c+3**x+2**+,S, ,++***+],U,,+,++e+***5*+$** *)(((*Y)))$(b((((_'(P(O''o'))\'((W'((&'&&&&&>%%%% %%%%%?$|$|$%5%y)s&%%%&&&s'O(M(^(&&&;'8&&?&]%'/'Y''&&&&U&&&l&]&'{&& &%%&%&|&&A&Y&&+7 Z06324"%)2O\dD߰W8\`r*?????????} //:4378 @ ::u;:*7777h6565w7k665b6!666444v.~,0) N 8 ~   /$) 4 @tCL :4>s"!"'G*>=>?<e;:;I )!-  I X 3 I  W(     % Y B    #' $%&&*$$]%&%';'Q&$>$Y$%O! " q .' )    ]P h$f,?(]" H    i X  E   k l f   W" |# " =# +W06B9d7N7F88:y:8::S9::_8J9%9;::;;: :;L;:;d:94, D = @ | $#, ! . 2^$(-=o  - p } X 8 |' t ׀D|V~>()B&)G.+*, ,  267"6716676W76 6L55443 2W3P1111123R3e1,000/R000Q0]1E110U1000010l/?/../0v/0-...9.)-a-[-%-,,--',,t,+,t,5,|,,-n,:+,+,,,j,i--G--",,Y,[++)+++6++, +,,+, **++c*++ *+d**+f*)))*)))O)R) ) ) *Q))))))P)H('(S(((((''((X((((0'C'2('@(%&&&=$%y%%z%% %%V%e%&=&I%%%T&|&&&&'$&R&f%*%&%%%%&( ''{'&&@&&%%& %&@&&A%%n%%:%%$&;%&D*f3 VS48P57#4\_sM{| 5nՂ{K #3@????????~ ,6;941e6A :B:;b97w77766*77.6a5 4343l644k52-n*'     a# +h3 X ua J r@=  " (R-=4?>risXJ @71-[**Q%E#  V a+o  , LS6% G G ?S$,3e9 /,W)7+# %i5;;<=K<<>$>R>M=<==;<i9H6 n   ,  !  ""($Y  u  D ! Z 1      ! ! v %Y'!('&&['&$$#$ "    $ # _ j |  Q }   C%T&G!  G  T!  T  V      & E  " /% L( ,..6Fa;^77 88899:;<<K:78:/989;3;[:<<99u896/ =< at<*  %f=#\ N   R  %D$ $ = K X jt 9V 3h57qBUA@8*[   % 5 '"657777l666654455~33Q43W22L2 1d32j2/00./ 000J001 0000S1T01Y07///../p/{//./0.0-.).-----U-,-`,,,+,8,l,5+,u,,@,s,,-e-j,-*--,,-++k****++6+*++++ *+C+,|,{,+++-+!+,***P)Q)V))I)N(z(((d))()#))(d)Z)( ( )()'('a( (((('(>''/&&&&&"%&|%R%%G$$%8$%4$%2%F&&%]%I%&S&&G'&&[%%%&&w$%E$%&'('(&' &&J%%&%%%Q%%.%%E%G%s$"%$@$) f2 W>W351*5ZGQ6L\3yk????????l &3;I337P5? ;;J:i6J766A866~4765S5f4444554h5M4/*-#U B  K X ' 2 =B u>}] H rdF !#`*3> T k nxAWI <R40t16*&$4         MB2&#9"y#@$f*,.''-*$+7:C<<<Q:%==H==;'<<;<=O:B=$T$ t    M {# !     x v T   \    o u $d(R'&%%%&$$1$!4  n   !$F"%  | 8  s Y  7 &C' j  $n "       u b    v  D ;  u! % g/12, -0@B=7I6]8~8:;<#<;88 9];.;a9:19:;j;A;9;918:}81W$O:  2=%U= 1 4 0 t  !< l0 k -   3  ! 3PC EOg=gR>7 8a;[^lfF-,']&S` 25a78&677T677A65444446222 1C1@1g2'10.00&.j/9//10/Q0/S0 //I0P01R//M016/h/d/9///0/.}-|--k,J--R-P-.,$,,--O+,,-7+-,2,k+,~+-,,-c,.5/-y- -M,M,+,,,*+++*)*b**K*\+ ******$)+)k* )**)*@))5((((((U)Y'u(((h())n()'(f((()((C(E' (|(y'F'A'9'q' '2'9&'/&*&=%Q$%>%D$$%-%C%&=%S%&%&A&&&y&&&%&'a%%%&m&"'(''('M&%%u&&~'0%%O$$%%E%%$##d'$|%& U0 Z<0p1 3&2XXfll.}Q}y!@SR?????????D j2n;9W2P855^C =<5<Z8l9"6788677[7545+45.65*44L4/-J3( c  ! ' 0 a> R*cKM >Y0 !&,<9J b /~&o ~e KN D ?3/-G*$&!S!X l O  0|   7< 0%!($"%(-* f0 * ,/--A39;;;;99;;L:<@<<=)<0;;9>"A:,^&  H      I     G o 5  9   S  o ! !"%&&Z%$#U$z$\%"  { U  z 5  2 8! ,  ' " + 62 &02# f(      : D   V     +% & ))/k,82 MG ?D7777:;Y89r758:599'93:::;V<:A:89H84,<  T a_ +w  h+ f  y \h   N ;  .3F<L;G5DT1E<:9-(n%$M(W*@&%^57k677j7$667K76 55y44444222Q2X0^11j0/@/0|0(0/s000%&m&]')j&&'&M&%&G&&%%$% $%U%%$##$'&$E$' 5 Y;<w/21K*@5 \[z9 ~l??????????|{)a317<:W7K0o5%A =:>/;:678*8e77c7 566555@44_355:413=2(#"n"7$ , 5 F h&}V H 8Y"  \!u&s0? O m "@nkr MY N 5-+,(h!   ( k  2  F #,\.)$#). &#'*F. 5 0/0_3489;:9K9I::: 888 9;#=;;o;99Bf-'`&q     * l H I!     !    : M  ! !%x'&&&"" 7""e!  k   U   F   1& ? k5 --Y)>{F(6Kt@I3W/  M $ T   j    %  s  $ " $ & f) D* , W2ED8568N:;:9$899:999@::i;g;N9788?78i8'/#6 M bq!# %'$t "8nP:hS    "&/"0q*g,b7 :95230//7]-'0J8l8 7^8^877567755y5I4344 2111Q0R0111`2p2R01.0v/0q../0t0///0^1Q0/.././0/.//|---E-4--,,,,-M--x---,+,Q,-%- ,-w--w-d-+,+,),-6,-C,|,+d+a+^**l)+.**Z)*Y)+)((())*7+()*)*Q)&(((P((I)(''#($))@(*)))S)(()')S)) ())((X((((''&;%&'%%$$R$$%$$L$%v%i%%|&&%$&& &A&&^'V'[&&m&%%&&'''%&'C&%%%%$%r%:$$I$W#$%a%$"#$% '&0*6 [y8.4>7n,42*Yz i4lb  d?????????{ \(6Z1:6;6C S=<:9*8477867Z55607/6h423#133A5<5H44[,%%(,}. 8 M | xc X fH C<_!  ! )1D 8T mߠ3Qhu '_ I w;2.*' !   n  S   $"j%(-'E%#.M*&(-15326E5Y77:8I:88678778999;/;:7BT/'+#2 n a p         f   "  ?     !$%% %0$#S" ! !        u l +48tA2/~Ik}*T)aD   '  " " y"  g !    +  (    q" Y' )0Q15IB66U89:M:=W;Q<;$9d999:::9987B6M7x8-3* /W -=q"v# '   " 32/ . D1 ',T3I5J;.>Ng{R tIkXYC<a3./0)%#Q678#77\666766D545332K23D220200012311f1-1./j./8.G//0...0!..>/(..q/1///...---J-}.0-N-W-^,,S,,-N--V,,,.-H,- ,--.e--<,c,/,,&-,,w,++U*++*+ *+*b**+*-***&V))))&((()')Q(n(k)U((@'(('( '9 %'()(''X''''2''r(^))P(((((('('&&&%%[%& %%%C$$%%%n%%p%4%&%I%%&%%&&&&%'H'&e'' '''&'E''D$%Z%&f%%t$$B$$$K$%n%#$$%O$P'&*7 U90+2k3}!'3\K- o;`YZ L ?????????u&U3)6#=2v65D <;E:2998d7}877i7276r5)4m3330112G5M6331z.Q,3(g+m._2rU yr h j^ ~N @@d<   ! ,7T 9V xx \S|*o ^ #I B 9 93 -+n%&&`%%$!    -)p%}( E)'()*'e  %+w1\254765_5i87777M57_7]769:88<"99,6@/.++" h G d     =   O  {! N "    Q Y  ! $ W&6#   U      9 wq %   ^7 *Es"D'&B f)4/0 0 < dS$ & 1 " !    t  \    " $ e" $ e)2-03K8ZS >7899G9:;;S89R:9:S:::U;:T978=89o7/X]s2fl Q" + A, .)+-12#3;HQyP]0cl][gDR :3.++)$0.68 766567J8;76655432b2W22_0222b2H012s///10/./m//./00+-000G/.x././.-,,--t,,p,,-,----Y--J,,d,-,.-g--*,t,~,,B--?,-+,r,,)+"**)**+,F+*)i))+9+*a)*+*c)*))())))R)(X(O''((''%Y (^)O(X''&&' '&'*'|'((!(('(9'(G''%&'(=%%O%$%*$w$%%%%%&%E$T$%q%%&6&&.&%k&D&&&&&p&m'`''%'''''<'E&'M&&v%t%=$$$K$%%%n%$$#$>#$Q'|$':'*3 PS;>/5,3"+4[nÙ@D}[Mj@?????????? *P3p46946W8B ;C;M88987$8777'5R6&43Z32i2356/43433 4O43% l   t.-I p6/ $ & ! %0 67 3 ) 7lD  4[~r  _ ! 3 O%m- = d ys}  .W558'87946:;8793947889899879;%567J@q5-2&)  "  e r      N!   \) q   !#"! F        :Yw   e % I1+?/am6$(< [K .D3w3  $ z\ ^ ( 2T      # % # w' p% 4( |-.439 ST ^+?78}:m9z:;J:9M99G8770899:}9977(873y)\  " -r   g D fP( ! H' +' , u+ .t4 @2/<5;">3>ZD(HMM)Y5VFZnA2u. +*9+X'M!J"Z5n68"6X55767K77545J5 443212R02W1g110Q/0?12;222A0-,5,>..000/0"0/09...--|.G-}-,,,,8+,,,z-u,,.--E--,-R--,-",,+,,+++ +P+++;***+ *P*)*O)!)))((+W) *+N))!(*Y(()s)*@*z*P*((U((N''((('&% j&~+'>)''V&'"'3'#&'((("(_) )(('&'(%%%%(&L&^%Q%2&%I%[% %&%%$$$$$B$%9$%%Y%\%%&n'Q'*((((~(''N&&%%%$y$%$$%Z%M%e%$$$$$m$H%$' g&*25 SPR=/81t#~'S1"Z%ƗW?y ?????????u b(6]6;>997B =;::{777966[65^6201b25339u2283z6O6755 10!X  fQ  I)  9 !v q  ? &  "=2OYrr"x  K2GIFa0f557G7i78i57T986H7d5V6708?A@>=77Q7757?7-m1%% - % Q :U  a=  G   5 F  dO a   }   U + 7'  m1G+\,*; N l,&' G.3 -1-F " )P A *qx 7NR>   +     h  ! 2! ! & '1/ 9 I [ g=819<7:r::L:#;i:9r99h99969:/8567+996-/v    WF3q  + ! " #*0.~-s02n7O;==>@I FLMZCO<2+(-*.  ,6467m7H5567 6545 45555D22f2(112_11.347p8:w8N5V/y0/{'~&%K(\,"//W0@/./0"00$/k./..,-----. -r,,,,+,\-C.!---E---^,,- .&-7,,+, +++I*~***M*%*))))*+5*$0   W b+877-))i((()c'~'M((g''P( (O(;({(''(I(y''&)-)') 'f&&&'h'((K'''(((([([' 'J''%&&&^&%&r&%%$%%%$P$$J$$ #$Z%%K%%%&.&&4&&''_''''2'I'&&/%%%#$$@$z$$###s##$b%$$%%' &* 2 T=1757*Fp3ZJ&jkwx0qf~:???????????WC&;L39A<v7:B =9:9<7D8k8\89`5663 2133*34234)3|4578936}621j0T&c - / x K K 8  b  H   :.M q M fCE{w=f d |M v -)78H6@7:6,8v6q66547\67>/(:=/"/T09+8778M8@;.b1'$*: 27  1  *4 6 ;   ];  )  D   R2Z Bq  * |9Ue2% & }- MA R*  #b,<+,0+ ',8!2A1YI2P &  ;e) v f g   # ! " " ! " % ) *n1:3; L =dvz<899999:Y:8769 9i9K8888089N:x:686v3f' 9 w#   {T q(; Y# _!!G'-*%}*+2;55=:A BEA?:5]0P,&C$!   47T86h55566606;45565Q4644221425J5?=C;==;8$5L7w4////..]/O010./%./5...)-.---C---,.7,,-$,+,-e-_.--X----)-b-,a-h.4,,},+,+D+#,I+?****L*+**+G+ +*++((.,0)4/+)l)))R))((''U('(&'Q'N''' ' 'N,R.=*=%(''e(&'()/((Z(W('(V'd'e'R'#'''&&K&G&K%$$k$$$$%O%${%$%>%$$%$%%&'M'&&'$&'['(3({('(<''E&'|&%<% %%% #$:$\#P"$#"#% $s%) ''*i6 NPR@k27*8&(:5([W  .Q:$?????????88VI%4m9 8l8o2:C T=l;::977)98q8o5%36U455#222{3s402m23J566755554+/  _ !<      V 4 !  &  4 ]   P<RBfX/  (2453474.5c57%6S3366d7;248,31,);.2A7797?<424($D4= 0   }M t l oF  j d     l /$u'MCW/0x/Nl$ " $ 1 K)!  r,,(**  '+0065!13  P/ u:0  v! # O$ ?' ' , c' & ) 6),-c2P9S uMr99|9:O:}:\8L799099:88889C8 9I:928075b/  V   Z/h L;j ^ !" G# W' F& !  n!&-4<6:=DEwC762D-%*#1  2 '267!7l56A6S667677666g8Z8{8;c8>/.g/:*@=?G4FBH>r?9m11<2z110x/-/y0M/.../..--,-J,-----+G-9-8---.4--\-W--,,,b,,\,++,b, ,1,,+,@,*+Z,{,I+ *]**+A+C*))*++++M,.h02.,/. *(h))O))C(N(M'((I(<(<(9'' ) ('@(.,1(''](' &%&k&x&((_(^(()j)*)9( ({''&'&&~%%%R& %%'%@%%A$I$#$#%$P$%=$&<&c&&Q&&&'''''(C((E'(R'& %%y$%%$$$$a#$V"###$B%4%Q')#*5 RC27r5&).hW X xsA=?????????????.537_66F9A Z;k987:j9^8 6753V4`230|211?132p34n434331P440, , @   T "  ) r  F   l  j  \ `  \ 9 y `:/ /a45123365Z432-203n4Z4f42b2455]342/405[96p67>7<S4C3+%6sI 9 'y s  l.o   ? d!  ,   v '  a8\d" >6, d/T! " *B'# &g&'*'!g%l($-+m1+1%! 9 >gHV ,  O2 & " I% $$ ( 7( j' ) + . ..5/I o z =.e`:c9 98:U99j:9:88c9B9 88 778E78785}1F p D R 4    :  X *`= W" b( i" &    W " & n-s5r6R9k@;422/9%X%<   3776666676557<Z?K>;W;4:1 +%Y+.:BH22;00.0/////S/..a.,.h.;--D. -,,,-D-,---4,-z..;---(h+X----+,,|+|++,+,,+W+U, +*++O*,*L++ ++*+B++F+]*)+&/41l.K,1/$''('(((K((L'( '''p'(')//)..%)'($'0&x%|&+%&&'g&|'(]''(A( (k'&F&&r%%%%& &q%%$%%D%$$ $$%7$$%M%x&B&&'&&X'D&(''''A'''''N'B%$$%%#$$% %C#S## $6#$%%V%'*5 @V>3%86i"'a4XP j#rr9R?????????????B)H0/2:8@:\B ::9875887763333&4213h235313b24244!1f03301*2   ;  p  q" G% )%'&k#1!!  8[     ` E    ~'s Is a @*3K4312f3442442n12]31m2]345&56 754|0.V8555=g97^7-#/m>U7|,)%~  D   H8 )  t  X 6     /  * # ` ^ CP G4& HB / ! &&&$ #&'$)( <%j'*k(%(),{ # ; X_aI+:i2 $ A' c) Q' p& ) }( 9- 0- G3 E0 ?6 D I 9R *pQ767S9:U89#908:999;9p8~8::x9s755t+q I,q \ h @ao  T  y V [    " n0 <: 8 6CO6]3-*" $  (7J87 6:8667@78.>D>4>k5.-,-6p<?.@L "LC@bEtF????????????? ?0h*0m13=6;AA ;::89887&63k3u22e3312j3/02{2<02944w5z403%2X000/c'  v t s 0.I--***($"T%#! !0 *   #(N6@48LO G!0?32{14444F633131n13v6Y5446]6c6m5Q8=2f0@/096$=-9551)/48F5{.i.1 d*!      ?, U   q | 5    d   1 >  >2% 2Y19  ]#^&% ''''!&'],@(S(+V&O L# 8"Mr3,u4j$1 & ' |$ # _$ # ( +: 9 }3 E8;I $tQ=U7b88?9 77{789-9989}9r8989(9(6v53+ `!# ^QTK o 7 N { 2 c } @ E B o+D5 FE sEI990C-*  H"  3876_666I67_9_?EsEx?6 2 , + ) /<DX?K$IaI BAB:3G22\23<2B122}240:0z.//W/./ .C/./d.+..-{-{-- -{,,-0,,,,-F-----J-,M,,-,,,Y,,O,\++++V++f*'++ ******K****+++*+{*)()O)*+-6UI; Q42,#)t/Y*&)E((\((u((:&'''J''Q)4c.."*#'&&5&&&'l' (x'(((()?)~)8( (x''y'%%%%%A%&$$V$$#$$ #$Q$%P%%%&W&& ''L'V&(Q'O('&%C&&&&&&x%u#$%%%Q%%Q'D& $"t#$O$8%%X%%&); K>K1z:q5d$2 T "maN{G??????????????)15{-r27.7C ;; ::u8n77551F3t4222192(1k110/14233102t/.-,*   t  P,:0://6-=,.-5++(*b))D%m! l"$w&, '*`R)I5  Y(0J4334I1S374430<0}1f1224854_7Q65 5641V)J4r7 <v:45`4a-13G -C4,6&2/!  T = q e  4(c   9          %  , 8 ( " ( m0!   +##+  $($z&!% ,')'('!  % 4 9.3STiwR #  ! G $  G  ) 3 E>cIgAG up0zs9 7 8|8S788N7c8(879J889&87J898Q5a5)qo j r7J ]+l m X  O y &,j)I= ;@z:E5 0/ ~? m0 " O$887(766+6b8AoDCH>9 0-a%]$ |* 4|@NdQI;?gE"B< 43c1G2E333D3422t2=20/./00D0/R./.--z,A,,-->,-H-9,,I-,,-,-=.<.-B,,J,y, ++,9+++4,h++,e,e-h-j,,I,S*,+**X*S))))d* *D+***))))()U),GI `7 g1q-.(&c(Q(])(('&(q'((')'7  4}/)$U(Q'%%$%&&]&V&&n''U'Q'(():(@'&&p'O& %B%%Q&$$%%$%&$C$ $$H$G$$%%F%%%%P%&4'''''(&&Q&H&S%&&%A#$%|%1$%%z$%J%;$ #~#x$)#%8$%q%(d)5 sL958]7 !4VUg6.6G???????????????*B+z,2-09b9 B ;;9M:78t9j754d2L14D22101<00E0/S1//01T21 /1//.,,)=D     + vT i?6-.N/{./2p/100<.-E.[+++,*%"!!4 (H )>Y  n ,26u2X403464200L3~40252546X64264,5Q9 3E(R-i6_<81m5> d+.LG D ;6\542X0'k=)6`  < kcdY   <   *  | R " %! $R+B#   ##  t#&#a%F!$ %'(&%*$  % R*/W*139N*    - ( ]+ @G_X _QLg G\}'K]19898d8j657n7/777s7:7r876}865$51< E   &]B3  = c  s G & # % + v% ,Y48936!2*t.) !196Q7"7^7t7>6JrIA> :5/>, ?'( T/|4;ZPRasf%@8:M84211E2N2322J23{3i3<10C010D0.c/M.!...#--,-----,-G--8,-e,-.>---y-- -8,:+,Q,++++,++,,t,-p--,J+,@*_**)***+(*W*,*)))*)) ))g)-F;a>  72,+F1$#^'U))* ('' ((((() 6S8 2 ,& ;%('%% $%&n%& &<&&&0'( '''J&%%%Q$%$$$6$ $$$E&#$D#I$[$%%/&/%&9&/&%C%%%A''U' '''t&&&&&%%%T$$$$$$%%%V$"z#|#u$F#N$$%&O'\)4 ;L=2588!(3T2D^a@???????????????D&/^8t504=22z10/P001a1|23l2..-G-& U       6>T/--/271Q245u; 6+0]*5((')x&O%"!8mh TT P$/4564N527e4823701F22~44P34j4$46b55p676&69D3+(5=935 8 '074 q0:*:36\6.5Q ,  ~\LL -   $ W   e #24'  #%R$   $\  "&W#$ "#E&9$4&g%R w V$ , _'+g1z44)/=0  G (( v& n% N`dOhXasn}AT98|7H:877k798F88788899y8654v(   '  2dUB X  ^= f  g!$ , '6 !)(.z2-) +/I&)79R79%7-6GzThI@< 33-+ , / 6597Ja aQ]TJ<h33C3<10/070j112222g222?0B0?//K.../._-g-.,,,-,--}-z-1--6-p,-P--.8-C-I-z-?, -,,,+*+%*+A+i+++,2,*+**P++y**+:+q***+,.?)()V((I!  & 0  ;+*)).[2$0," s!l))) )C'''(((N(('28 59/5)"'o%%;%~$&%%%&%%&'(I('B&K& &%$%###$)#$$&H#O$ $ #$$$Q%~%'}&%& %&&'p'K&'''&&&%%%%&G%M%U%C$$$$%=$$!!"5###v$$&&*4 O :4'77!"$3RuֻnWU????????????????b)'617:;A <?<D:88;6Y6Q54V3:{1%10/00I100|111p///122 1P033R..,,t-x"u U m !?,A0--*+,-!+*P/93)$$"R$~ !#  d     i )186255@45553/202N1125W535577 6h6n6w779 6/&2-6#:6,8/*|76/(5,$2p8H \@ J< # 8 L ]W&z   D k 7  ""M,C.+j!  "\& ` g " %" %$$B  $#"#    # z$ &.20.  )S Y^ " zF- K) ' I[BYg)kw+weT۪|Y9s768887M866<57/88(9(9r9>96g6P6T0 % % 3 &R q m  ) > l   7 f   1" ' $%*+)d(/&(2Q9:I:S8'7=ND= 74/ - m1 1 325m;QhMuqP I;/32Z1////10&2221D22010//H.v.-.&.h,-@-.9--T/9-,,, --,,-,,+-J--U.--?,--z,,, ,+,*4*&++++r+**e**`*)`+,*+B++++ )))* )))S'X" %z$!9->;6p0-,C(%+  q |()((('I( ('('b'-6 )77[-#''v&&l$%&&{&u%&2&o'H'('Q'&&I&$$f'$#0#p##a#j#%[#L##$$y$$R$%%%%& &%%&'&#&L&&e&&%$$%%%% %%%C%%?%$$#!"9#D$#$%%%'b*6 ;P<37A9r%h7RY%byp|rh????????????????s#+2f34r54T?B <<:97776`5(4o22 00A11/1x1/.-h-./1W1[0P/100.V-.,G-I!  &  '#7/>( $%'&%)(*[)f'o#! 6 , 1_   N 0? =O  Z,05f455 76d24o4o000X3%2285T23&4)4z36c4775;@70b$%n21H00_/0.)x/ .Y"M0Z8<= 0 5$'c%P  0 UN>Rw  N hG  z!** &8$'/UW/W" "  f  &# $ f!|$%M'!z"I$:$" # G # " $ =**, *<'g3EHύ UL %  3) ;* ZZMZ]msתӧV9 78J89B8L88?7867898o9m9n86664'\  N '( ];0 ^ 9v4 s R d  r  M , !  $ _ %-.0v&=+#+7K:8 9g76RWjT,52#0 G1 3 1 2=339P^x jv\7s34t320/S/0^01?123z4+4468q441//.---:,C+,J,,L,-. -[,,---w----D-J. ,,,,,F,-,,++,,,c,b,,/+*++*#*"**+***+ ++** *+ )*$* )E(Y) )T(/)/QE3Jm=R10-c*"  &L()(X(((R''(a'&+j4 n2 R0& $5'h&5'm'P&&(&$&:':''('&&&%%%###?$n$'$k###G#k"##'###$ % $%%%E%O&&%%>$@%%&%%&.%%$$$$$%T%J&%%$$@#9#$"#$%B%{$&2%%'*8 OQ92r67! 3QSk8\ies]D|H????????????????|,%02R24S27VC <<:E:49*8i7,6c422~2/00Y0.,0//Q/.V/^-.#//./"2/0/./v.;-) 4  | ( ;    -/0$    x        # :   4 +!/265523N60e5363/W/^.3/Z13}2223S4G203n2t3w4:72&+*+**W+*L**+O()))U)(((),1)8IJ>2m,t/).#$'('((^(((/( &)6 Y3 qU8)"%&=&v%&'^&&e'(r(&"&'|''Q&%O%&e$!$$$o#$#"m"##'#g#$$$&%C& %% $%%H%%%H%$$%H%%$%%%%$%$%%%%%S%?$$ #"#6"#G%E&q$%M%&U&'h)8 UE72=/7k2S*o{W????????????????u%164..8AA <;:98836Z7(432/4w211N01C1 .0>1~0./,,y0-/02W21I2./.,g$I$! %)!@        0      _ J G 38 "T.13:2y24+3 4z0\-2012334$3111233225(43960("10L20~;v3w0A3;Q41D6W6-5%!0y=9 95G)"    '3s (  d v$'! %&$"(@26&  ,  r   f$ #  %" Z !P#" !  n 1! 2# " % & $ ).2\1]60e O4 - i* ) 8 _E ~VbeuYit2y}Y98E8]7z87C68788?9y9p97]7866550g j  f A1>  j sQ    k [ *   E    ( ~;:8B.840.Y989477E6D? B<9520 O2 1Y5t56<IUP VcaXPF<1.232o2=32259FLMH[ACB?9G3+ )f*,,-z,*+,z.5--,,,w,++L-,,Z,f,,--A-T--J,+*++L+-F,d+++3*v,.-M,,,,l++++N-*****R*L))R*T)))*))(()-NV ><|J LB6&2#0!&!'()('((( &(4 7 B +B-$ $$$$%%(&&A%_#%j%&[&&A'%$%b%$%%$$!$Y$$ $V#$Z% % $%%&Q&%%%%%5%Y%X%%$$%j$%%&%m%$L%%$d%V%%%I$$#Y# #""z#8#%~%F&q&&&R&*8 {S7T2v3;^!"5 T m-|qwҡl:~n{???????????????@t)|.t103"/56@ ;::>9)99@7j8j5a1,0m11Z0.000//..S.-{+-/j/00/2000.-+!7"#)*k($#!'I f < K    b . \JR    J 1 p $1D12i0t3b34d20/P36=44w4?4436464y3Y3433665;G8 0% /0X2/0B /-'/y/-5#3/& l#;989m9r8_3-V% >u X ]x     "")#p%J(V1"  B ^ 0# ` e# @#   O$#  "y#!   a! %#y" # " \%! ! *1H30/i>Vc~H + ( + . 3.Q=X|o}uh_ih~D9s8676@7D788'98878776^55!-9  4  6V2 \       < ' ")4.O> CAq<6 3j,0Q687N7#=S_96 8=:%1 y, .475<C+H5O XSQWWJ?3/5-4a3e2n3|13g9LTJH ^? > ;95Q2m1-.0//*--,,+e-+-U-N,.,,R+-- ,,m,,,V+,T,,+,&-Z-,- -",d,-Y+1*~+-,c+|,1, *,$+,9, ,+, ,+*)***))R))e)*)*0+`cH(5?!CD%;4s-%  !&())E'((W)X)4J6 G@ D*t" "'%%$p%&~&%/%i&&%%$$$##$$$$$$$$Q###$Z%%$e%$$%%%%6%%%%Y$%&%$%)%=$%%%P$%$b$Q$$$$M#$:$=""V#"##%&&=&z&#%&)7 Q;367r3q0)R}4TG)]6e???????????????D(!.+66<3< @ 988D88,7767Z360{0w///10?./..-,-e.-1///.0M01//.:-$"$ +$-+&5!hz&j   >  "k  $K B 1 !9     ( 02]115c1y2F54-4j5524;4644#5U13313X2X45554<-83x($130k2:1(,0-)5492/ 0<779r88z819l61-Q%t    j   + Aj, G%  !"$$)l&p  *  V  2!# O  r ! # ! " ! N  b  # # ##0$ $* +J*6.57;CT /_ .*   ?/ e< 0Uahqo\[Q[[alkl:7665z6D7778T8m6577555K42%   |  >  8TGL   = d l `  "*033<1)v" "+m77;8F7U6`H>M7h7994/ [*(568tA`AR UPTOCw</1 7S4X4c53]3r8LgJ A; ;  96 4431e/.11j000R0/0.>+---.-,,",_++*,+,,+,+-,,,++,d--,-V-\,,d,+,`,-,m,,t++-),+++,,;***y**Q)+ ))) ()c)))-a-n N9g? a77MAGmA&5%   ;%i(V(T'X'()&*3.5 (>$+$ "'&%#$$$N$$%$$'#$r$j#$ #$a$$$$$$)###""$Z$9#$$% %Q%P%G%%O%O$$$%%B$$%i%d#&~%$%F%U$%$$$t$##@!"#}$~'u%%t%&>&%&&b&)7 3R755o/#4Q&t&ӗ7u???????????????0#20 7 52^;{? e8:.::#:+775u44%2p0/x./01O10,/-,,-0*/2-/0`/-2.051.1'.-<" %+)'$ w#u   H %  w  . E U1|]  ! !e    \,4432?29/13334a3B1233+5#2t23n2O2g32V5,454;52'#=53e/=0/52h,f4!-G't6~GA v5'3876798489%898a754R0N&" N2 u k"  $$b##&O$$!s" ~ g ) #3  !   x  k g ! N U m! %" ! #:  ," % W%-R-k2Y07;"  * 1  - 934*[W mhd ZIHON`{zJ7655876f78377:67!7k6544V2'#c g z G ?@1* 8-0 J$  A Y   }d   ".3p6>:65V7868SK}H19 ; = 59 D0 0/ ) 57;CLgY !9^!Y>T_OE:045Q33S4@6OBH PH ?545~5 2 I/"//0Z01e.000S//)/.!..1-,,,,,,,+U+,,c,+,,,,,],g-,^-,---.-i,5,,`,v,r-Y,c--,+++G+,*+,=+ *+M*)))\()(((f(*)*-)PnOC= BE34?K3J<;$*  ')((P(+9? ?l;1' !'m'%M%%%=&&&$%$@$%`%\$p$k""#$%%]$c$l#$3#i"i#b#/#$X$$%%T%%%%N$$$%$$$$$$%%%;$$%O%\&_%y%$K$###v"$W$&&{&~&'&&z&I&'* 9 QQ2536s4l"n4*RnܢQrQ{I???????????????'H/ 1785)35e? 8:;B:O8?86{521/ /..00r00N00/N-,- -+-?/7......1H20n,'!$)<+*f($ /"$   -  7 . ! &  w   "  ` '   k  za.4<2c402K3D31r334|42142433#2*1L43544<5q46910+ #4a1,].74.$L/A+%48. s5*G:62*4k89[6876s587h7!5,319/+`% K    $ ( + ^(%%*'"$L%#    Z" B   "   d  . ! -! $  &#"(! w  =  9" % g&(/+-=**-" $ A4 mg-y: +/M#gpT9[L B5I+Q\kcR967x668h87q78o6<568 6$._-52 (,{+n ` $  x  +'    e  .-5hAgJmdHL;4 3H5n6>69LNCD6: ,; M=6 q2 1 s) 4a7x@hBP\!] RwWEMB91,345Q6X5AT 'M %? %;_;100,-0)0$//0/0]0^..k/-...c---.s---,m,,!,+-.,++,0,c+,$, +E,m,,,-O,$,-*,,k+o+++K+ *****H,, ,3+J++Z,+D)***))A))&())*{,K{RE{9q?N<2 m.1f9HBJ_5# T%9)&((")?V/X\  G{31 /4$%L%%3%&'&&H%$$%%g$##$#j##$$(#$Q$$###$O%G$<$$$%K%&:%$$$$w$$$$$%%$$%$$%a%H&%%D%y%?$$C$$;#$$$}%%&%%&&%&')!9 O88U3613\PQؘVq???????????????_?',-F.294_9A [;:98s6 5>348111w0x./F/./1:/z.-.7-=.q,?*/,..A../.@.u0.,H*GM!'=+'(6#u -"#b   p   d )i \ Q$<&   e    v,/`1y3c04 /21:34q4z52222433%43C44W334;42T694)3+#0S3+.5.$M/c+! n/.-+,?27, ,N5%7j56766430w///011. v  ^  % / B2,z!" ! k  H   6    !  " U  Y  +$%   t    h'),.31 )R  # ?, Vur8  6 ( N[-D M B ?@AK4[Ii7F7<7R7 666777<666751 !# w m  &+*   ( )w 0  L  m t ? V!);<]= R;CGA*$ u)\(+'1hSfD_:U V 30g) %L$ $$&?$w$&S$##$#$$0$$$#{"##+#%%#$*$c#$E$V%#$%%@%%%M%/$r$k%$E$e$T%'%%&%%s%%%)$%O%%s%%A%%H$$L$####v#$%$%A%j%}$D$& 'A N46.243"!62Peho"EЫF???????????????m")//s02C6-7B J<;K9s94c5-2D433V1//04....J,).0I..x-,-. .m0a0q.//1(2261m/9..l,O !%s-&#r" "'~#!! "*""6#" v"B !1## #&    } _ /  q+/12j3'31y3213'54223_23433F63b1244v3=6t8Y63*((+-b*1R:-%!J(&,2,(-'*2R0,&'U6"566f5020/1m.q00r0p/0,-9! O +w-F#L 30=N"!5 ! S C  . ?       O   ! ]  '#+#!    !  (*~)<0._*B! ! !( c7 R ?Z93%% Q J @ m8;18M32p1 2 0900[1211358h< :CCH EIHE@<|;:66 7624d3120/2,-",,(,,c+v+`+++,i,p,,m++T+F,C+,*++++-+L+***I*))*)))((4(]))+DCME@D=8 2 / 1YPEI:-4*v"=$',IV`q\\:AA.1#r$Q%$s$R$%%h%i$%%p&&$$%h%"$%7$%%%{%%S$$c$ $R%y$%%$$%& &:%%&%V%%h$$_%&$F% %X%&L%%%E%{&5%{%>$%8$ $##"J#B"#####$H##$$%'; Dl.9320A"3AP_obĉkIm???????????????_$'14?54Q7B < ;99s8676L76g3_3&0/Z0%.-z..O-//-,-.!,,r-,/1Y0343[02/0,+!A$((4$  L A&%h$$#%#g  U$$p!=$F#%L$>"' /  E   a  #./'1e43O422y3455b4"56L4^7F44,4>443K2236547<!B&<9,z)>,'**: G / % $ &  !  I  %@'+')4*(*26b6F35K3c32Z001d2/01/-i+"(l' L )5`-g 9, $    @  ;  u   " * 6 &*$!    i h% &'& (/)#X# <# $ T. q7JAR*1x?2<9VlT Q> ? e> :=65 EKc Zm G,76666F5657660565s+(N1 t \_p   `xHI6 - "    Q(4 =/2hD n  `( (>/5:6pD<7<<&=<e96 S0, ; J )Y >^ ZoTYJC99)2+5#606/36|CX H $; T66310/f0^/-24^9/8V:<AdDHHUMSSTUWbQRJpHXF9D>|=<b@;@BCDCE?>A:7//7-,4,7+++3++z)*+,},4+ **++H*Z++@,E++,v++B***)*)))!)()*I18GOG;K9 8 15,F0^m<B7/:*j!")3:rFTIL/431)#C&1%X$$&&3&&k&&&Z$%$n#g##$$4%+%3%$$$%%%$O$g$$#$d%% %x%%4%n% %%`$]%&&&&%%%%q%%%%%8%B%%8% $$3$""#$#"#$#"#$|$%'&7 vKg4>9J0*2O {&bL??????????????I4$y,-3S3024%D <;{9\7/6p443@111/-...Q.A.10-+-,. ,@,y.Y00v0+1)0g//o02c.w* z!$q }!Z"I h%&%&'%%>#%%r#%o#u&>$ &$&  6  .    +"_.L/D/01K31d0R2234y565{4p5$45}111123118FFi?A'+%-`)Q) /20 - ( 'r"  l  E + F f$+-R355232{52u21Q2 /1/x+4# '$ ` &:,*  #.1y$ 5  B   I V 5  g & v ] ( a & W"#      ~# $a# ' *J*# & % $ % 0S[5 G UY/M gFE G9 d48<2'9PFJIT@^ dW^:7545556i7b6!7r7)6657]50LLT? 6'j 35   > $t&P*9.)9  gD4675C>9G=!:n?,<7664>/ ^C K W 4fD\VTLC847]87R4:G sH e9~85!22129ACT%NkCxACLQX,W5YEZXHWSQ;NaOnRRTM;L+NKCKZSaUCLMI3BA:5253 .+%)*+++*++x+B**U**(*h+C+,+, ***S*)))a)_((h))Y**/:Q/B=4 26S1RkNDi>?1A*#!1FE'?;@62^103.%p$&D%$%&&,%&*&$$$$$###B$##C####?#$#%$$N#$H$$$ %%%A%%%%O%$%%%%%& %%z%b%%%&&%$$$Z$$J$K$#<""J##L"p"##"#T#m$%&e7 Dy2 4'.r3P l%ts̗8???????????????^{%).D3Z01<D D;;x875z5335t521v/3.y/s.,-V.U--,,5+n*+--/_0//w///p0.0"0-*S    2 C!%'*&1$-"~! %&(%"%8%3''<%(x{     -  0/.4s02p26323A5445/5j5"4334M32;11t11503=GdRFPe))1' !Y)V+))$( #    . "%   -/422323f43R1^1<+)%&'  { v %k*v)   u 6'('g b "<   ( %         d .  " ?   !)#& V" )M(  .$& w%0NDdO]47PzY34G200 / W< 5U2b5E< ? >K Y C64495B6u66855i56k6%57J44 BD`=  eUkio { j r"&&2/D I u =4Z585bC:4j98;<4.5 3. B V K TAladXYLIy95665V6Y>UOpG %; :76h8@18<MdaRkXLhMHEFTVX}]Ybf_x[TUSKN*HLiV'_c_YnORma\"]XZYxQLE%AP<<7750/Y.-7++T****)+<**+N+U,,z,-,,D+*+ ***)o*)()*+))Q+8;? =u=5 C>0U]GIp>[;2*$H 52@=Q937;332w0:##&&;&d$^%&M%&&'%&%&0&#%1$x#$$$%%+%\%$$%U%$F$%9$$$Y$)I%%%& %g%$G%%$$&%%Y$$$%$%&O%%%$$$$ $&##F#>"#M$"! "#D#$y%%'/9 E|:321"(0/L[{RK??????????????eC +1e3438B ;A:?77(662l5o22341.E.{-,-,+,_.,*+.0-.;150t10u0t1/20.1,1 d 8 C  . ##)%)$)&\"$L%H$U$''V'&^##&@&) O    4  //V013133135+5@343=13%5G3542z20024HaF_RP"&  '/f6m.-''*40*      S" 8/<:S13423f00.!&[!\   #"* ' #p; + 1  $%#d!`  F  M  1  + T ]  @  "} M !  |#(+(Y% /$'% #=&f*%187../1*3+OiEh/)+' ' *2 B16 448946? I K74457+75p5446y4537!53 F \E1)NM, y &%$" c $!#6p5)6_65=b:2g8|8;=5044N- h?"RFL ME |un`mR(HK87Y4R44R5BPVnH q9q7"@4SYjKK_ UMLSRdGW?rCOW]=`g^b7[`;5{225;2/ ,*+*)a))*>)X*a*+,-A,y+****5)**)(m*)(**c,&9B@>>>E055Y ]J=7;3g,S% f2>#877E92/) z"%b$j$^$%&j%X&!&b&c%%X%%X$$`$.$r$#$%"%,$%%%%%$$%%@%\$P%%8%%%%n%}$$%0% %q%$%$%%%&$%&<%%I%$$D$$M$%"""I"J"#4# "`"#|$@$%% '6 xGw.=,12s(.OLg.!ϙW??????????????n(*1142 /A ;;96664l45L411\//q.z.,+l+|,+,r,;.31_--00d0a210g0A1-1c20-     @ M F%+'&)8#S$&%%e"&$%))*=))X,JY A      s.,/K4O425F33435l305X:3$23233B4q3q1C22%= N Q U d V$!   B&9+D=@6B4'(+--'!  z  # C# /33y/04350/(*  o y  +"+ q   "!6`  s  !  QQ)*0[35% g   >   "%K$H# " :% 'U&z%(623.I/36;6-4 =B*% ' 7**+,.w/,/1244< H<O451555H3344I44556e3<!q) /ZAs R&/  L"$$ N)'2367M75K<;C0 b7#8;> 4439-6Y.es HR WSEK)E67Z44#3(6$A\kL 7DISnV\uS!VT[OGRE&8r9=GTxYhaa cgiqwl,ioIj0jofBa!YIXI=IVUR7OOKGS5J@H:4~24=<<'5j1H4k3&1q.-,+****,9+, , +*R)*))*^*)()X)(*T))2;KCEO:Go;8U?VEHd>N94*`)!x7~;Z8j7431.# #$$$&$i$&%-%%&'%g%&%%%:$$##$%&%&]%%$&%%%$$%J%%Q%$$$%0$$$t$$*%y$%g% %V&%!%Z%%%D%%@%%O$ $O$u%%6$$;## "#0"" # "##%{%]&E''4 G60~9%4+ )$2LW)MԎ#xu8??????????????eJ(|&)/22= 9:66935n5d43]41//5-,+,./.G-_*H--,+,.%//.o-7./O1.2?/,< L     F  ! *-&&+&#&&$&(%Q&&',(O*D,"  0 d n   \.-.3~2M023M4@22B342312L/00Z2T/273a1t3C aD T H\ w4*! t '#%*E4.6 0j(X%&)++(&mD 45 445V4334;3455t4444 %H   Q%t^ 7  m  eH E" $**5&5v6 7849Ql=6 O:<A763+-w+ Vm.rkMVED?8r775f58)@OPOjP7Mb|z]nɏlwnYNC91.247;@KP\bkfj$n mqxpXil g_ \5UrSJAHJoKK!HaLK@g<>67]96JE8O6x?94272542J1000-,****G+&))*"*')))u)Y*K)o*)54BNPWK(BK8e@ FLj?=80)*'A;8A177z2T0+w !)%&%X$L$ $%$%&W&&&%o&W&%&&%&W&%&',&%&%%$%Q&&&&R&%& %%G$%%%&%%%\%&%%&& &%%%%R$W%H%%#$%<$$ $E$$E###B"$%$#% &''6 Dv37};/9+0TKe,Ρ˖[FKҺ??????????????%)90301= :;Q96}4434552t/..<.@,,,,l++9,,++x,,/0)//+.2/0300~1n.}( &   R 0  $)+(c'(){*&*=)J(('i')***# Y     -  D,\./3-0~.2M11213|414722330&1~5^8*01 =B :AD K =&= ' $')+,J--')13?33 3-/D-#%o   "'*{#%44/l+Y$ V  .W r   E  %- +7'(&'&%%!) 3!Z   (2z1{/&( "    ! " ~#!B## \  0$# ,! l$ $832.E(..2/t,K2)" u  . {Y j  , ._&?+#*:*+ *-.-3 E84447}3Q44n3-3L345?41&o# &{  B O-  p      UJ$|%R+:4 6_7 856+LQ8@[4 ; A7 3/+ N- NU ibn7pGf:JC75Y67%56{;4PIexim7Mbr}~n x7qYqkgVJC;15/17:=FXO]Qfio~nAehY]EfdqY_]]sR4O_MoD?BIGKGD(=60\47<C;6<At;50C/B:=B}DBo=Y6_440t,T*)o)())*+"*a),)))2BP+FB9?6 <cDNY>?90('*Do:u= +5%6;0.$|%}#$+$$$$$o$&'&%%`%W%&&&$$"$Z%&[%&%%&!%%%& %%& &8%L%&Y%%F%&%&&&% %& %&[&B&%$~%A%A%K&%$$=##A$=$ %&}$ $$E$N%~% $#%}$$&* i8 F)7O8;j1%&2(K, ( dx:???????????????f!|*-6C+@/@ ;:V8544,4:44/320u/E.A. --;+,*4+z,,-{.>-l-.".//i./z0x210.S&  d Q    e%-)_(a**h*+m*+p+;))A*)`)$&*$ :!   a  9,&./2D/1226/238312:4s43L210G5<z7928A =h98t? ?2  <%7''--,++0#3W. + % % r' ' * + , + }"    !>"&+24-r*&:! k b I  #]-+7~szrKZ/c)$r# F J =   wJ.4 .])%O     y 0" W& o)W*/%-( G! p# ]! X  h%3N0<(x'/'*+'0"e  ) F h X ^S$%3.r#)D+,-)j)X()k* ;<==33 35h6w43444}675513( }] x Z  , : W  # R o 1     )'D(.4i7D5546 FK{K? ; s: 6 /J- n,Q, !]-be _ _T4N8;3667>N5^rid ara]San9ej1_wd1SQL@6Q5'4@2a139@5ENXchok=\YPdaZ[UQLRG&BN>:F;>8|54831O0Y8r7"5r3;~;;741397<I6PTvJ:?WA>50-g+b*4*$**Q++_)*k,+*a,<%B@@C 8<FFAAQ:04*|$,C>5 573/,3&#$$K#$L%$$$%(%%{$$$$~&&%%$#a#:$&&'&&%%%&&N%a%%%%&&u'&x%& $$$$%%A&&&]&&$~$%%~&|%%E##B##{#$^$;$E$Y##I%p$%<#"%%z%W&p' ; VHa3c4)61j#t2)Jt}Ao?V???????????????f_#I&,//+5@ P9:7U653w344r33///C.-,b.:,,c-!-d-.$.--.1-,-w-m-s/1?00.$  M  h&   " o/,-9,+*+*++G+8,-+)-)/( T  "   > *t0/2k/1e1z25d3w3i34}5455w35225C;8~3fD[A 756A A* = ();+Y.01+-5 8) g  $  L k k {$ * K- <. p&   o 2 #(+ +F$# z  I   W 5$)^;6JLR,3*)$#""  M  d y f1 2 L,&!! ! $ |%!# ( A>83G-F(#' $(w,V+*C-/*+)},&c'! ' >( :5 6 />0%  T3,b%()k(+()U's&% 0?1322l23h33E4845.5o5&2(G  _~ gft  }] (b k R  ;k k '2v,@(V  '(1256656)BhD4? n; A ? > 6 4 X1. X SY W K,F976>KThUS][babccgiGg!cnde[:SO~RK=4984456 9";7BHXdfkBbcf_VYT]OF%@=975J4=/,B++155G2O1:65h8=;59]< ?}?>@?uBQ-UJV@9654`.X,,++Q*Z+U+_**e)5>SC D F n8h==CQE|AD;1)N(6B 8 }4 )55G1& 3%%$$%H$$-$.$$% #$ $$$%'%m%%#"!$/%&\&%&@%%F&&{%%&p&I&&&%P%&%%%%W%$%&&`&7&&R%%{$$%&:%3$$#$#%%w%>$M$V$P#$E$$#$m#$%@&"'9 F351:t1@5'd/I$u@$?>????????????????fN-,..(t2< :9853T2}31364f4i1/./!.[-+w--V-----,,-,@//.-..010-   C  x  . 51<-J-01b/b+,G.;/V0/-,,.o($%#%O#)   &/0 2 2510r2.6.64-4o466&3221J7K :7O6I B L6k4N3tW 3HK &/-0-0~2b05.42( j  c   : H    !) p, - +  R   _$;(!  o EF  !{ !$$!tFgy !   i Y  s2s-)$ !+!!&0*$( ;l0<X:q&" +.M'<-9+c'9(+)'Y! "~&_$ 4$ '++&+x1r'+')&(F('% &## . =54516l323V5w5559430*\   a   y   t Y& 6 ) i, &  M"J!Y X06/%-65>zC j8 7 ^6 7 );4 4]33 Y J :E C:C@;!?ELPRY[&Z]"_cfgb^\SXRTMGC>.<$>c=88 545375S8? EVafba]7Z]XBNK@=g;'8%7S2O-Y++.<=52j3=n=7:8S>lhSHDA$<-:870,++,,*9)*{07q> C D <=G'D>x<>1)=#9: 3 /3 56a-  )#%$%:&>&+&c%$%x&*%=$J%%&m&k%&%%#$$g$9$$%''9&%%%%%&@&L%%G&&&&P&z%&%&(%y%s&/&V&`&<'9'J'z'&~%%%$$###$%?$$$$$#$$$#$v# 8$ $$'8 GG37,3}5%?2JqQ|h:????????????????f..k.*}.4A@ "9885333b3h43431/0..-N.-.---++-----.w0)/'/'./w1=1G0>* X      8 ;C > 76 }5 4M3X02012300/81,"'$$%`! s  4#./2//?.J2m433545422R02FJ>5@v@ ?Q2-1Tj FC: D04540.:/369- ' . " l   c#%$r$w#V!@  5' S. :$    z S  Z'J #  V        A  * 9 N  -  ]   )5,)%'"" "f5>6"+(8 To~C_dTEG3" #%(+ %a&:+j.' $(''JI0;4tj,)*''&%#! v!" " # m( 6a=32X35}3333340& C M* }^ 8)  z SUK +D  v 2n V z )"6  _--!*>949!B= 9 8;<|:5/ 7? 97Q;0?BG0K/QSQV3XYga!dhl d%cZQKM#KzIBDHIOKPD@@A=>76t314.<AxASc [c`qVXXPHBL<b7G4p0--(A*;?C@K54=A <:GecsYRk!,p rg H_b7bXQAE8J!U+_EgYIKE>D>DD;44G2y3*781.V0@6A B 9 :7AN)GDtB=]/*$>8 l/ 1 1R0# (%%C$$ %,'K%%'$$&5&c$&n&c&a&&&H&O%$%/%&%&'''8'&&z&R& &&K%%%%&s&& &&L'O&R&3&'N&'I'G''''I&{&3%B$$%%%p$$.$$$$$#"#$J$2$p# " $#$&6 H9+0:/5!/Ga pp_ &fIQ??????????????^J.(V4!/2-2@G:9E85F3q22223210.-- .U*r.e-,,`+z,j./-/#.2-p-i.%./2f0s.)   } Q   %  O< K J {E OA <*;98j4876 53x644/$B k"C  ^ o,._/M0 0{04344215r4350C3GB^A76D ;90.4 Dg @+4k<=83 434 $ # " !   ! %'&>%%#4 i  $ $- %  1   z !` ~  : C ,   4        R" 0")+&%&m #7t2^JR>!,1 )B uJ UBYTB)@$+N(C&'0}/8$$<'v-2~78A8BMmcLx+/,F'*(%Y$! 9  6! $ $ 0VC32X3434O212@3Q qR,h)@ S\   Q & '  j   z  %  "$F/\5646D> > < ?A=6(+X455 g2 7n?QDjO4StOPFU X],_Qcfe_ZWpP QHDBD@ AB,XTT:V ZLFDHFJ>u74D47p7N_dRdq]0ZDPH>@843).6)w',K,:0?5C7^=<8O39@Xg Tt]o"r vq"Bo$e! gbC[R)BATGEIVcj_UdOJ7=>KLY@~=CMIG7;F '> 4  8<<GHAZ;?;n.*%(;2 48 5 1",/ N %%u$$$%$$$%:$0$/$%a%&%f&!&X&%%%r%%%&R&E&&&H%%%%&:& %%%&w%&%U&I&8'&' &''C'6%&&'&a&<%J$%%`&?&G%$$%y$$$$E$#C##Q$1$##I"#%%&6 8F8/39.{6(W.G XzTr t???????????????^K#-1>30(.5A98762330122p0.---.L-,,-c,-t,.,,,-/-,-.o->-/\/- f1     }  }  nLMO O KEDA>7DC<:=kA:o@}8O"     $ )."//0N1823q4b55k3 424F22C5?C54C c83)0m02MR i3R":m $k }U sV D6/  &~#  j  ""Y&&&=')'"| > ! o-+   x  1# 3 x   8  $3#8W("   !&   )r)t)I%&*.^  HxQKlSw7, X4 ]Mw t*:59-! # (y)-)X(#*4.02.+~2W127(>b8+({)(&'     %  % d,dC724l43L111-3\3,y" N  N = _4 6)vHP  C  % 9H' [ C36636763C:CF XJ J8F: 2 -,4 m3 0 3 >HOTUTHZWX\^jeF_X"RL!DF0GD>ADBX/3776WFR9F>>_b4SKLH;3[4+4F9qW7a-`C\N$BF>z41/-I+A-27d<>~9:`;422w11; MMP>YZi]f^d_ecamWLsKV]M:E@NG_S>Z\W0S&D;q?EBD$G4O!7m>A ,; 2 c7#AJ(B : : A3 + *.<6 - --)!;&3& %%{$$$$%<$[#!#$$%$%&&g%%%&"%&&I&\%%&'%%%H%&&&%%$$%&8%%%%%&&&U&@'y(''&`&&N&>%A%%;$%`%h$F$%y$$@#G%#$&%$C#+"# "y# _$'= Ha53:0p'/J `rruæ֖sVM???????????????nQ )N(<.(Z./A=9 9M8:4W35323$4 1/...-,-.[*+,(,t),++,+z,--.8/0.)]K S Y ] 9 @   ' l {U -j 5v7w\F H A_?q@EBR?o:<>8L Ig$      #,.31124n425221 2326S;.744<53/,--^ \9l'O?) /}Mn Ά +T :+ $ )&$!   $q$'&%%*&+ _) "_ D c 1i2   w    f    i!  = w  @  9#x %&%'y&$X 4"!<cAI|r G?7 / Q< V M: 0{/<U''+(i$'*R..#,))*y*+-.-1KJe?-*C&<$ f"    F   &# v' <@5G4@2#2T3r2Y344534;1+ z  5S U  0 w > ?(p\ M$y "Y#"6q58U756569fDM@V?RL=< 0 +. 5  6DN7SUWUUVTW0]\XZPR IGEA>>WBU@CBK,*.A1258XB<%Pi[ZTMR94348@LYnVFE9g6v72B3$319SN K@e:S835o7]9t::406a?QAF{HCFK\MMI{JMJN:IUfy^XaHB=FRhX\ZRMXBm9:;9Q8BQ699V8 92n/9FD884 4 - -+/HXI:2# )'Z''$%&%%%%x%p$#l#H$~$%)%&"%&t&' &&&%%f%g&&&&%%'&&&O%%%%%@%L$T$$X$%%%%%%&R'g'#'&&&%%% $##$$<$$#$H#=%\#9"#q" w! " 7"$=$'& 6&&; bI52E7-L%26I& (ܝ0t YL?????????????t)],+11.}D;M:8 443112D32.--.8,N,,m+)),*I*+++,,-?-.3./8..&!H c  G     V0 V f Z Y YLDII+D5D@4?G<(?XF Ai Rn) s   2   -s/1343_5424t4121O4q/7 7326 84;g2s1-2@ 5$)&Aj /Z U N_ iE9" &%$  i$# W' &+$#"$4"%$ ;  6Q4   e     D   7 H!"J $    8"%($$@#1  %.;SIur{c@ + - < o? >#`)-E-"'&$*.C+(,2\/)({+++-,.%,Z&' &&r    q  n  # r& 3H934G468>6r33341* Q   D 6d Sb y o    v!  "#)55l7^5[5^5\4H2LBGNXXhNI< .-*6FLm;b<:=@BCG:4S+*/124J\CU9Ew]=SLP<;I016;:R5Y011g3"6:NiwUl=-635<'BHJiGG=N:98U<p<i8N9>ED(B+CEEXgy^`OfPZxROE D@@MTXZ,TJzC=Z774V6'0-r-u<B;;y97y9%3&)F073- t#&d%& $$%%%%&l%^%%7%h$k%& &')&d'"&''&&a%%&"&&&&%%'e&8&8%%%%U%&O%Q$$#$$$$$%&#&d''D&'3&&%%K$##%9#$}$$#"p#""!  ""}#"$E$&'9 Oi21>60"'#/zGT Y uЏocB?????????????l(+1-1B4YCu8:7411:/1120..{,.|-.,+().*Q*)+u,o+,l-,,s,z-.9/I/-$!"_  2 [ *a!#B Ӄ9X -M I!EB}C G mN Q Q yR R zQ Q X gG 6V-8  p  f   %S.Y013~03-422x3J2421278B/02Z555<"..~,46'5.C CsCSI=8! ,%&^  #$' %' &% #!!$& #f! f  :62  #    a)$(   GK0t%|% $W  W " +H)X$M%A! !*@*1wPf{vx1W@: 1 ) 0 *1 ' ')/##C',,W'%,T(+('A*-G.<(+ >q2<\ ! I   w  % ,wAHCBnI:QRS]LE:43' ;       a *e k  'Y""  u") 04<54 4 4Q4e429H Q \ hO = -990AKIKjN:NP S T V _ROHm@;448;BTCHBEAC17...1R1p56cELA95IUZVHCE584Y362~1G1V1877l>EM->7412>INS-OGIDI8JIFB> 83.347->K^ce `_[]$VPySKO/NIE?FKLY`YL`A:5=0-6R8 @GWEAxB@2&l48 0!*M$%%%$o#$%V&% %)&##$$e$&7$5%Z&!&&&_&&R&&+%$&(&&&&M&{&V%&w&z&A&x$$$%}$#$$#$$#}$#%N$m%''D&&F%&O&%%$$$k$$ $%y$#$%9$#!! }":#"" "$%(< XI5 3$<1@:%1Ce ٝN5???????????| O"'&)133u/kE: 9Q8q513334342,0.. .U.,,c-]+8*+()+r++++++,X--g---*Z'T"r b$ $[ 3~q mOkf i 5e rh r q (o zp u Ё ҈ =̒ O: 6 Y x .01d1}2100/2Z02n1+1.0w.-, 2N22-#.-0,10).-12 8M<292D! 5 *-)>  y  e$#' W' + B& A%S 9 H   #"   . G5 u   & 3    $ )'.&C$r# E#+,"&5$#"" '+, 9 P` ^vxh[NE94%( !, D.  .B,@()++7++/%&9'() '"&S&(g+8 nn<  _ ) G! ? !    y 3# ' )9K{MPSQ5UWOUU3LCWAm7@ ;r l w t c ?7ry2  f *! & % $ , ~. 4 2678 7 W3 C30c23? FJjNFI : >=LQ?YIFI>JhP V T R  KI=A=S;<V;-<I>CCsH}FB@>B9.32;1267n>D_?q3~. =sd[fI/=9=;]6u48;7t44?><81y064;dLUcBbHOLPiQ RT U6V3x6-#v($1xC3 K թK???????????s<pnE,04//{2hC9R9<75O22/012!2X0G/,e-/:+,a+/*\)(j(*,h*++,l++i-0.T-2J57/!$;"J"u 3"!&L uKs ?y} y | { { Ly s } }   \Y (  % C &.01]1C2w0 2d0C0T3]2100402*+ 1U1m///0+,2++.0R-4}87. # : 2 *6 #U##a& h) *& $!      !  " N8 :>AsBCC'CLCASB BBDDBA4B;53699:@LDo>041BWMGEA@}=::696R2336451/.87V<3[>U]/d[RS{\#gveje^nSB@P-TPKFFDI>:Y79=CIUHYJVLXWUpYW[YQ*JVA%<)IHRTQ@l5;hBBB<65O1&+ b4b.# s&%$#6#k#c"j""s$$ #"%:$##$%0%%j%v%($%$% %%T%f&&%&&%%%%$%%S$$%%=#$"$j$%Z$##@$%p%j%& &R&>&x%&4%%B%$$%%J%J& %%%%%?$|#3"$## $ &h##$,* OE $UO85S20 )3C* ھ bpEo@ԿuIgNJ"V?????????8]-27v/"0/D9973111N1112"0.--*)***+7*5+u)))))++,(-x*/9;.6-("#E!$b$!# /*  Or o*ti g h n l m m n s   G  n al 0      (   ,,E+/10./R/V01R0N1F/M0,I((+.+b*$.$,,,f+q*)PG5:i9-'q< 1* -+'o$'~) u/ &6$ !      )! i!  +cb-) + ( $.x, I21H238749;-7v' " /$ ''+%\## -303FJ\FN&Rp>95/.G+&'i% !  E)S+`'(M(q.r/s26<@=62*v')(%"#  8 G [$  T  M { s ! # ,(+x=g@6JO8T_XQNTV~RI@"    T  (!    lj; ]    q $ y( 5 ([- )8( Y$  K  $%*)).0q5 : 9 w<=? @tC9CE ]C A AP?<@B?CDErDDxDDCCCDBDDkCDD5E{@P=;=>)>?;7. E@|<9=<(AJH;~:a66246q<+?@:1^,.8A53=MR_gbXuKw{)FunW*BU[_\UXsPEMG0B;46J8?FL^S^HW9RQV2XVUOQND@DhNL4BtB:1/-/..<*#1 Q/})W"+ &%%%##r"!#"#"##$#$c$&]$$$$$/$%)$w$%$%h%%%$v%%=%@%_%%t$#"$f$i##v$^$[$`$w##$@%g%%%&&?%$%f%%<$%$$%-%C$}$D$$%h$$#%#l## % % $$$]) ? hQ7^-,/{")1 Ar ~ xVc(w y ????????8\(12r/@2/A896322012@1s10~.@-. ,*)'%* ((*R(())()+,7*))-0241a/*( %x%4#$f$w$|P  m bx] Y I\ M_ e@_ [ ` ^ #^ f h p u Lw ʎ n Yv&  ?    U0 V ^-+3.-*.01H..X1 .J111+ (`&%-@+()A('g,)$h&(&7?d1G4a, & g8 '0*  $ #0$,-* = s( 0}2 "    Z" $"z   !?4SF$"-)(  $81 -z&(*e,42.' ' 8 0> Z-P(''"|#..,t( '*+= U>(A*<6 5{-./+)'\& & & *U#%(*.+/x/4(5/-'%B#w#1'm.?5U&H-6)g+h*e%(& " y# 9! ' (-*A.J <@_Cg>=p@DnNgO$JIKJI8IKKKJHFCETE{CCLDCDDE@DBJAv@@:>>X;~8D9648>>:N9=6864=H;MJHI@2P+/3H.*.=DNT:OZdm;oz(rqK5Up rqk^`j^ \XQpHA803j279QFOW4\X'VT[RlQmOlRL8 4{8:DEt=x5,)x' Q h.*!b &Y'%''%$$+$($r#(##("`#"#a$$d$v%$$-$%-%4%1%'&%%`%)$$n%_%p%0$$I$_$###.##6"=#c#$'$o$$#$W%f%%o%D%%M$$%f%O% $%K$#$ $ $$V$V$$$#E##}##"# -#@%#$( = N:K4)2*0".O4+? VtHKe}JVe??????????@Cs^-410;N4/6@:R974D31L0\02/u0>-.. +,,q)))(`)g)>*+)(*,?*A*)+/*(')[(#!%%"U$%c r _Z J\ W S X XX 5RhYPR gSQ+RiW^` do w {m 2 ]       % +- +&,w.-//10/140)&U(],R)X&7%)?(6*c)J*(_&)v9 /2P*' A 7 -  y+;## ' I& %$K)#($2#  & - m    T   YFc 4+ 7P  '"+z)h " " ) MOY (H \6 0-&3+ w$C)$x$ % w- , 1 L. R+    w  ,,8))O(*W -{ ")-')(G(6+))(0(('X!"Z$&+79<4m0,,[) &%# _& ''H' o(+/<2KN ?FKfP6Ca= 6K/-i+(!4 Atsi S   k J"A    # 9  D    P K  U# %2%)/44334#3>lDFiO@YeUSONvMMOQ>PQ[QRCOMJJMFEEDEEEKCC|@?@>i=4>\<95W9A[Cm@?V656XS57 B9>;B??C;3F3A3C2.'/a;vCgGSg]cybkJunSQUzhvsppigcMb]5WRKG<.07?DJH'NV)Yk]s^`]CTLL;46BDIAEJ9|-.&# "*!  " H$ $# $ b$ & % # " # #[$f##`#["p#"$$P$$&h#3%c$$$$$.$V%%&%!%%$$#$ #i##|#X#U#$e##$$#C#$$x%%%i%o$%$$$%!$$$$##$P%$$=#$%=$$<$2##{#"  %$$& ) 9 oP82,0-B2x; ^6y~'Kxp%Z݆fCq??????????NC[00;-*10'>:973E202G22D100.F//)-,R-+y)+:)@*,?))*K)**)((*'&\*$$M"H$!!%'%&C0c} d [ T Q jR O UL NBHNgGuHHOFKjNU_bjf? Dn&     h x 'N**+*-,--1H4 3^/}1j1%& l&&*W$$%*(u&&""&W&'30+;*~# < s7 C0  !!#& D' %l#"  #Y"$B  "@ W 4! >##, j>j M6  F,4 Y(".D4_6;(C G 6<1)f%,$$^' & ' ' i( % " D! )$ &1'('.o')w%! (" #4#Q()*0'*!%+e+*$!#6&+0/H o { :/M-6,h(++.*!)*./6kJ`6 7 2d0':'k%% E% & o!  g N  n.5   5 wU  h L i   I  ]   $   }$ & x+ d/ ,, 2+ . ., D>Y]WVR~RTRUU UY!WyWU/WWUQWeV(PLHGFvF EEEeDBD=@?k<=i=7;L9M OFAe>:~9"9i<5 : := DzIF?5 5r9;9r.,,O3<FMXWfa[]&YHg _w+vpqzlppmf[Y8PfK I>0.6:@GJEO0X\ e[Yb;XBNVF8CD ?C..'!u)!  % # # # # @" <# o# U      # l   2!h  "#$%#%%Q%$%'$$e$$$$#$%'$ #%#$c###h#$$%%_$$h###$$A$$$n%$$$$$$$R$A$[$#$$%|$$$F# #@$:""!! ~"K#"%$# &) ; M<16=1g2 Y-~+I:F vǕ՗T)U??????????V_m@-{3-3)C)$;P::}72E/[0123333`0z0l.---+*+ )_+**T+*++u+@(&I)6%#$" k! \!z$%J$%R %jV.RGEDCHCGE*AE}B`>f<@pBU S TrSPxB") = @ 8   x    I)|-,-/h.J.r/4*20p.}/$! ,! *%B)$&)%+( "_!%)',q0*# %6 1,/#  #%% - % @$ @!#c#;$$'`#$/ 5 o"*j)G%5Gv0# G'$+}+*^,V6L4a =  21/>(&%@$" # "  _ z  P" $*6- >+ +-s.2)&0%'  # T!! )I*&& !T$'z(&&w)''13M689BL'4i,_,*-3m01+D*48>Ohjw3 "( % f$ % #')]) %   _Fi  ! F eK{/   >  '   F       5   ' - . 0 0 17FSSPSWZ{[ZD[YY\q^^beq`^bb)ZY^+VTMJHG1H 2B/1W7?`BDAHV~[^p]+m BQRcN>=4-)X0%C   =! ! y" #  d    > G  3Z    ["_$&.&%$$$-$$W$&#f#n##$$$t##$3#$% %D%%$$X%(&%%%u%c%h%(%e%%%N$$X$h$?$J$M#F$T$$Z$$$ #K"##!! ! !@#V##m$#$'D(P9 hL#7/i1- h*2:J bJ8HA6U?????????;|(-32/O0)B9:88x3/~037292+3-3/F..--5,,;+)+,w*z*2*L++?*')a%B&%"  6!L !D""!*^QH G E qC@ C YB 5B <<T<<;;8=7:?KKXNiJA%  Z          u!&, - /{- --/G-V,.0'$A&-*(\&'(43m$()f /!0(u2`54-,o! b3 (*&%+E%"- + N' ( &0$%$$A! F$ &$'-*%KY8il#. +S  f +-$y,-09W7 7 5 /)|%F#! '  Z  ! % ( S* ,.-g+Y-/3.* $'.a " \#";$)0V-D521,'V%%5'%+/4;a .\ D5 ,*R+>-;-A2,,699@I ` {) ) $ a% ?$ % " h!  '  i   h*ZT4 s   <%@u { L  9 V v 7  L  " ' "( 53 9e=?B9GHLJM>RVQ.T'VpTVWYYZ`bnTo5mcbebYfTQLL NYLLzLJIFB@~=DF$?Y|UoT L]B>90 4 t9 ? =S VG-DD@<8B9s65<>?=<9j8<dEyLN OQ,QJv[IaZb2fl_ca1av``(`,aq`|\XQKC;6;3556:1=@AEBE(NTa_JB(MZiM74//0)o!~  # # !  \ E 2 I    r s&;`  !$I$####a"####`#""m#9#$*$$%%G%%%R&%$%a$$V$%%%I%H$#$W##$]$B$$$Y$$$E#A##!  !A! "#G#$##%&(!6 BJ 9@1;$1$/J7@ ,_Rx |Bz?????????? ,)V.+.*/0i-e?787210U212s32240Q..9.V.+,;-7+i**+q*h)*0(')&'9##`!5"M  m $+/-F#T &E "E !k@:> W: 9 : 9< x; 7 1 81 5p21346?8G7?5>b+          !R)%%'*-*r*++-.t.+_(#9$$&$X% (< 2!+%E$u$)w($)" D0)M'/)&%,&#- 1 /$~$&C$$$#$2# . &&&'+)+} F{ F7# A #3 q( )+/5932)&7!  S p v ! K&8**1*(&&% */+. ++H))p6 +"  5"%&%?&+h48=X4M.Z'&o&Z'*T/H/ND/7$  %)+O1t826-1/f6ARm/ W& I& A% # _  J  R '=  :C|  *   n D  U/9 @ ) - 1 Z S ?    H  $ G, u2;@[ABDE GMRnOPOP6UUVXMX6W^^2afmBtvnnygaXZ@VUOoNQQU#PPLHE2F/AWAJWT VIpC?O9D+ 9 C BR dSRK%B@v9AH:7:CEEBA=;9=AFI LNN,YUeg\\?Z^YYYZu\]aaO][YWTLqG.@<V<8;:; ;%<@G6Q~a`z]TLA8s/-2_1%X y  & C" ! D       G M  UNYU f !H#$$$~$#I$-##)"""###_##%&$$Q$%$$U$U$9$%$$$_#$S###$%#$$$%p$*#""E"!H!""#>${#%J%&W'=*4 L54#3*_c&M,{8 {u:hD&`XǍ[?M?????????Cm,%@*O4d.2/^B986H42241~1215001///-,i+6*) *)('6('P')) %$ #(!% !B#!%5v;C !0J "F !sBAQ;999< G9 > g8 S6 3 1 - +//Y..8.K.6F5/= =     c K "+V/0+%r$''))\(1+C,.*Z,'-*'$T#@"P,p1N/P('*1&#") * %*$ 8, 7 2 ? 0%*#)- , & '(%%U##s"%( . *c+~2G4291I~/ L/+ D r k8 =8 #&*K,)'! T : " V# &%!%&^)(&'!* (% [%$ % %4~ c%  !$&,- ))'$*((%'r)0]E lwD L'0 : '+/652,.1t9M[qw7% $ % "  o s!  W ; w   w   P         +Y    L 4  _ P   ;! # w$ N% / S=E CvC=CDDG1JEOTWVUTV_SY_a"edf:g3byvpue^PT0d\nWWf^jdkf[TRKMICFUBxb[GWOHFBe9 + G !Q >Y ;V RK F @>8.RF0=9CRSNKHC5=A;;<(CI\KLrl`\VUWT>RCSV0UW^c ekilopg2V7J@ c929504438=`IDRX`TU?g/*,2H*  +! ( /( ! ! "   =  K@_"LE~Te $%_$#$##"G"!"u#$a$ %I& &%$$%O$*$0$$o$u$$$Y$%#Y#1#|####$F%2$%$"""!!K!! ?!#$$r&%''(5 J44y./o'|19 AanZ]RzBROawL??????????{L.~-l/w1s6y30@m:97:32014./)03g100/..L+k**l()()++'(+&#:$ !d  "L!%(+9~IJC-J sJ@ >@ ?;;j>?A B >> < G5 1 2p/ ( ,/--U,n-\.03 p  -   R"%-Y/(#-$p*&a&p((*%-W---,m,0A2. &##"?'(("K'8(,t,N+)#' * 59 6 A :#y#%* ( (*  )(&s%&7%#X&c U3 ( +-+z* 2 2q`  ; !Q #-Dh%m$' '" w8"#"  `      '! T$''V(~/d(^&P$ #$#" ! %+n" @ $'$'A+ *(**($$C'%#~'V)9jNUe=# ( %+3)+-:/121C8 HtM=}& Y& $ 2"  I   Y     R   L    ?      m F f  }    "  ,! c! k$ ( ) ) EyBW?EIEbCED7KRHQ5PUrVdTO[.[T_UWZ^dcjdklf_SQZXSeWyyUrtY V%TOCHCTR HCSG MG J CF D C 6 I+ ?E xU FR QM qI }F mA @1@cWE< : QR$`zTO[LFD? =I@=>AbIZYROtJHECB}CjC6BFnKSY\_dipdT~I< c7 8 0 -4/7;BGIIJCZ5* ( +  $  ! !  !! " !     KU3V.MBZ'L cZ  #$#"###b!G"#$Q& ' $$%%O%$$"$f$$%%$$%$^$&#$'#$$:%%%$$W#D"#""O"?"""$F$%h%%&R'S([3 Jf54/0+".6: jpX 2G~qV<t??????????l(60//24?<?:i85-2L2116221_0.O-,."-+&**k)../T46.2[/..+q"CV  X"'2b@ D:B BG E "C .C !D OB?F;;;i:<p>?u? 7 I1 31+ *h*)a)*-o2#R  y o&$"{!W#-""$$P >(+.)&%$_#'m(k)***(@({+6)''=(t&o&$=$3D!$$${'&! # 02< !&#%$) z( &+ &"|  q 5#D&%^  _/ ) , .  Kc99@B8? , /";0 '!H  o  $'*p&$  N! O!  # }! t!  !  # d  ! g  "B" :! ,$ g/   <" '],.'#X'$ ! 5 q!."0%.3@g])d G %+76Q32 /X2b3M3a27jKy( t' % $ w T  D  Z # !  ! O! # "    v       | R kQ 0 _  !   " ! " ." Z$ B% # & - =n<\AHDA@ByENPxJJLNYuV&U`QRVXW^hbdfcfgiQipbB]j@w WUovcaaHX X2VSqGwD M AHIC MT !R "L C > 8/ L/2@ CF E fC D D :A @7EUE = `< Zud(WO(MK$HFA@??z>A A?A??A@ ?>>=W? A;=@@RBeBCDEEBJ@a>7 17 &5~) $,35s6B::a63T/% g U     F  *     O+H_ oDI{l ofFXc_ "##"""#$$$%&%&%%%$#1##8#n#$$$N####[#$$d$%%$##F"#%##"M"##U#$%N%&D$%&(_5 L4B.16^1z:&/5 ־ߏ^׎}18/UZ??????????{ <(<2+50r/.@<3:5643+1r1t10./-+F*d)O))w'F(Y*;14g2 H/ - + {* / 3 I728[5/' %y(<CFF D~HD7A@lG KAc<f?28:=BBA=;>%<< 8 . 2 7/ **B((,- )  ^ !T(($[#R_ "'N,^*&]&w$%#$'',((+*%1!Q!"?!&|$ \","&Y' }" +-%4 D,e!.#T' ( ) & "!R  Y! ##" & ,* . ')-.:*9bj,#W# / Z.&+ C !(%" /" 5 ! g  s  `  b         %   K#  ~E  $a  &,+`%%S)e"!   E gb#(99AB(! (*/4 24/12k5D-qpS" w# & #  c g d  H" T   F " X  $ $ 7% $  ' ~   ^ T  C  Z  I B # % % # j" " K$ ' 3e2 * ) q- ;/< `;=E>T=?M WLJ^IFVDE K LMNUTWXYZ}\`JcVa\_"^X]aiW`Y`3aWUW^ST)PJZDG DJF_IwL K E JF F C = ,.?A 9K G F uJE? > @  ID C ]> I NLGB?;\;5=W=>0?nAAFD"@{AbAA C C CC C }D C Av? >0@ @@oB >BY: 34 ;56( I# !s$! y a&s.4-! E v ~ $ F"   ! g   GRO\ PJSNm#MZb ! ###H#"#Y"#$%&%%%%$##$}$y$h% $\###"#\$Y$$$#$$$$b#""# #"p#E##C$$%J%%$%$&; %L=L503 )/4 5i 4MJ0 Me2?????????uYA+x+21-E= 9z64b1A/[-\-b-.-Z*N+V))*(@&29?87632x4 u5  64 E2 w2;3J4^4.")-<F{@L<RR QL>JC2D3;;>?=AiDFF E^Ar>;=:>s9=87:+ *)@())f-   F m!q$%)&," , Y#% 'B&9$$o&u!*$&d% %''+,%; \Fy  #!<" */-8#s% &.& ;' 5. )(( ' R$i"%&M#q '$- \. + F)1[9EDF?D|@slt!:  (: d!   "#(!#_"  s Z  5 D ?  ?!Y#!  # !  5   c I b 'L   ]" D O! &' v/1.9'%%##"!"!"$m(#"  t$+I*?*3I/2+. 2,8 As> = ; q4 ,8%@E:* & &    / g! /%! F  +X# $ B#   s#  P W ,k$UD*a/Q " q"m#$2$G#(#$#($%%%F&&&$ #$#F$4$%%% $ ##)##$&##$7##"##"#$Y#S# ""#$$%%%y&<%#%'K: O5,?/36*-45 +gmav& A!)B9?????????N9b,$12Q0/\0m@;+7l630W/.//o,5-+*))1)(4;<|9<= ; < : R< =; j8 5 <0 S1 3 4 4[41-CANg986B H\;<?? <>@;=b<EEF G!MI"Bb@4A= h>(::/3l( ))@)*-$#    &#W"  %x$M"Z1 v )m   d #&(&J&@(%         UY`! %10c8&*k(o' G& A. @. / jefL  ,s(})''^ " S2 / 6BUxoXEAW;f#(^   '7 - !   A$"  t   ; ' |*'' $ %'Z*Z(&," M cv      " "$J! # # u,60#$#" u#$&*9EL5>,.-`++,%/+R-N*n.01 :ZGV! O" # j$ ! " ( % % u& % % L$ $ ~    # # $ L& ?' ) * F' ' & # $     " ! b  6 8$ * 3z9e4* ( X/3(- # ".# & +07y? < > ? @%=ORJFBBuEFJ\LBN9N|URUWQWVDWW WX_e[^ZXTGTT8OOJIGE AB DD B B FF KH QC A ; m/ *M+B \I<,* ( J#    e([(.5;?dA[C JE F G bG CE F 4G G F G F F G G H G F E dE C B B 6@ 5< < < ? A; L:s8 ]]`P SA 7 4(  R y  ) G[ ";$M  Clb_^kY   .$$$$$&z##`%%N$%&$w#%#f$$b$%$$Q$h#$$^$2##.#$_% $ ##""g"$ ###"""$J$[$%I%C&%B%&&6 L<D4!1\0"K'42y1 {}{nnL9:>Ey????????K}j-/a222f2W@D< 5m33/-+))('m' %%&%-(46; 9o;? !B "o@ !'A "B #D #@ !tA "6? "Q< 9 f4 6 $6 ^9 74 3xF\=b=>@??m=MA<> @AVGCG CE )I!E D @?h?;3>, h& N*`,M,U+* V  w!!H# 6% j  W  ,    #   n  "#$''k  @  H    N  ? Q ~ =   #-+.)"%&% 0- 1 A*^%Q$ m$%a%" F / /:JQBK\OC8m9\<  $  - B, t   S    % / 6 6U4*&' # # =! w&R*c)&# w {   Z o   # $^# #   Q)B00Z*%! $3$(* 69D>E2-M."/,+,)Q*),?-l,1FT" #! " & $  $ ) + ( # % # "  \ t ) "  $ & 5, r, .* C+ :, #( ) a( ' U% P#  !  8" ' - [6"42g+ w) R/M0 ) $$"  ( - -1i58:= f> I F@?@,ACMMJGIKMQW-Y`WVTV UTWWWZ\ZW2VSOI3H)C E A iC @ A B  A ? +9 8 2 ?+ V+ = @ 6; 1d# + "@     )B2"9?D  F nH 3G I jI J K I K FJ K 1K J L MI I F *D B B @ > 1< < x: 9 ; 6( :W<gHXV G \@ ~Cz:+ &zDa$ 2cmM8yB N[hVy    R!  )  !#$g$P#$$#Z#$E%*$%%$$N$n$$F%P$#$$$$%2$% $$$$$$%$##Q#`# #$ ###$e$$v$%B&%%&']9 |Jw:3//K4A!'02½ T7+6;դ*'L \????????? .x)/;2.t1.;<63?/+,(&&V'G'$R$#W&79;?: B: Q= !? !A "F %PH %H %^E $xF $=E ${A #+@ "> }9 k8 s9 5 3  2 =@OL4BCIpG?_?q?ADEJK wF{FK #N "H !CA > > 95 R '  ,B+=+-6 e    v     F     q       B!^'%7%&( 5 d   V    x + m      $'|'-p%&""% X$ (n*U1#,u(%4&*'( *0 F/0Z<Wxc)VgHU X%    '(% u | W  * `7\<; G; : g7/ o' ," V   ~! +  ~"%F#    T E/ `$ .! & v(% )%  $%U*@+)%\(*,=W[^:/|+"-@,.-(R% ' (*k(:(+ A;L ~" " `" ! k! # z) * *. 3. U* 3( m) % l! T# "  $ q" ' )$ ) * ~' ~) * * ^( * * 2) !  *  # ) f0661+ * Z-+ & # $ 73s8j4 0j2i5:< 9 8  89:>"UWMQGUBACgG]8g!YV;SRSPRwRRX[`Z^\[a\SIE D  A A ? ? @ I< [? < > 19 + 0 k'8 9 R< -?( -)# X  }pEtn#z16@J O Q R9N }L O P P P P lP |L M  J I H E C PC @ ? = < +: 8 f7 k8 U9 - U. _= >; > TK O >?7=3/e*%&(()(!   y7<a>?<< !8 @ "A !/E $SG %G %jG %F #CG $G %D #$E #sE $`B %=<:7 5 6 . _3>fH4`WD>=?>?!?EXIGEGGH!H!D]B @A d9$ 6" ',^,,& 1  z  , V     y   @ ) 0 E   M  &'&()+(w  m        a >  `   x$&@$)($$$(q07.4>,(w&~&!&+P" 6&/ !,p4BOhq R?Ee 2b     )H' } N r% 6 @ G E G FA @ '85)" " " r"@     b i Q    p(h+))k*(  j!"&))/BIH?81V..c/a)()r)' M% _$ K%%(}< A $ g$ o" $ c% U% V, - / . - - . b$ # & & <% ' & & >$ % & ( 6' ( , * + '+ ( $ g!  J" * A0,44n1 , + , -+ _' 3! # + 6D~C9 S7 34*3e45 8 = 5E ZFCB?v>N<Q=A`(^UONrLIL@JMNQUWRMK^n!W[NpG$CCCwD C SD =E jKqL JD S> #9 /  7'$: < = L7 4 f02( T';h /iCU h?] X \P T @W  X?UW S R 1L  F lE D A {? _> i> = < = (; D9 7 7 .7 V9 1 M: > @B@9`C L @ : 3 ( +)r ci }^Sb"% 9 *   " # G" G" "   %$%J%$$&%&$$L$D%&&&%%O%&u$E$h$##$$#$%%%%&H&$$$%$$$c$$%\%$$% %%%%&X&&2 `L9Y+0p.", .M0H b$g;nnN{ԗSC*J????????ktv044753$=> W4O5. &$&r('('" z |.3@=:<;<867> !D #pH $H $F #H #DH #F H $YC "G $ G $H #E $C " > b;"7N5 + E1 ?7V>'FAIHDBGD(@?EFK VGH H 2J I G!3B?eB D>+ U ( ,C+**A | n   9    { ' V  *  > l    2 &"%#X$l)(&: g u a t   s {    ) # E&'L%*g&>(9( 6>4J=M2+)~'-%^&)_%3 &0 1#BSp_t?^FK G / !Y%%> 2 ( ? @ = |; = = = g> << 9 , >& ') %B$ " "    Q   Z I  E%'i  *$ *)p){/./   x !$G&*? qo E PJOoD C J\< 8# L+2: : 79 {8 k/'! + w $8?R 8z ,S Y ]iewda^ Q M G ZD dA @ ? < <=!; ; N9 7 7 6 J5 4 6 p7 N> ?#<>;= = $< : c4 Z* x"0+ &%e 9Br' a4$IO;a<L3 Q  T! a# x# $ &$ h$ >#    "$%C&x&%%B%%%$$%&&%&'8&'&5%O$9#E# "$}$%0%&`&$U$%$% $%L$V$U##z$$$s$[$%%%%u$$$%4 #Ji8,|06t$*,1 DZ0L1$6?????????l ,-1):q.*1Z9; 01$-(z&{&*) ''$$ AUDA<;= < ? !D %K &J %J %I $M %I $CJ $+H %G $vE #F $G $G %E $C "B !{<63 2 U0 - :AHL@GHTGC>?yDGFGD J -BI D @xC !D "@1  $ *+9&&[$_        3   k 8  ) %   0! #(&%#,$((&  e  3 U r  h     ;  k%(&O*|&*82d3W?^EA>.D(%(& /Z(+E5 :2#<Ui3rf|ntiS: U 0M 9&X *9 = : F9 8 : : q8 9 9 : i5 +d& %! 3#  -     v    '%'R-f%! # # L# '&&& q  $*5LՍCt6C. %;#$ J"  h g  j" $(o* ;3 # k& w( N+ D, 8. - ;, / + + U+ * ) H) >& 6# 1  # ' p# " $ % % ( w* !* , ,+ , , h, s& r$ ( g% % $ % * , . 2c42 4/ |, k. * $ #g! * 2 554?GB(4- - u-*z* ( ) !) . X4 :<[=@ABCYDfDCuAEEEDXHJCFTRNK??::?>=K~GL4@ @ G0AK'. " `*6 8 : X; 5 34+! 8">I {2Q  d^b bN^XJ I 2G `B a@ ? w@= : R: U9 : : 8 5 7 }6 5 5 3 9 A = ;8 ;5 : n= 8 n6 O-+  (  gJ+Ja=$SeOVa^R  G! " # w$ w& 5' Q' n& # X 9  V#@$k%%%( &K%d&$$\$$%%%&|&A&r&'%$##!Z#$$%%% $$$%%K%B% %%O$J$d$'$*$$l$i%%%%%-$%$"%i6 wJ`Bz./m6"("(/ `-+bTzL8????????]&e E)/9/.o0>F9 V.p., &z$%#$$''#7:EEDA A!? <= C "B #G %E"I $EK"TL#L $G #vI %LH $H $G $H %G $H %F $C #qD ">6  0 / * a06G=BGhIKOO?<O@>B?A"JwDC6@iBD!#9 " " X(/'%E$$      SEK k n     "%))###"%']   N s n  f      ''(-():4>NP+\M@)d#w" '!(9)/^24J(fdq́J9=H _:  K !7# 239: : k= zE F ?F -C A > [9 6 ^1 ' $ y#    " !   E v   !&'M*&"  # `% ?$'*%%&## ) M!%&->j:#1-$  ),% $ ! !   "  & ) -+ ; " 6" \# * {* - , 6* - ( * p) C( ) ( * & % ' ' ^& ' & ( ) ) , * ) * - h+ ) ' T$ ' ,& :$ " 2$ !) - 6- / 1i2 W0 , * %* v"D"!6) 37:EQN-E9y2,0 *$%4   2 g==AA%@8? = @t> ]= ??DFaDCH:IKu5& S&`7< = %<=f=n>< < < N? z 6 : ]*1(3m; 8; 6 e4 5 i# r0GVxP J< J8 7 8 l65o55 6 38 4 23 [D zF : D8 p6|2 8 H7 X0 + ("o Q( O$*7 x`KdjIXE  ! " " " # % ( ) ( & F" E q  " $%%%F%a%%%%%+$$$$$%&%%&P%$$##w"$($%%%%$#$$$$$$$% $%$#$N##{$d%%%O$g%$%&V6 O&?)16)).2seGqdEME8#$)????????na>#/d19T2w4>7 ,<,f,$#g%W&$'%!)BNFBFD @?@ %F #]E!|G "F"jG "LJ"J"N $H #K $G #F #E # G #nF #E $G $D "B "> ; 4 ,. q, p/ b1&5>jBAAHkOvL_Fj5I(     i+.: b; B K I \A H P R @Q K !B 5 ,P% %  # t"9!  D    6 &x&$C(*,A i $@(&^*+((31! | !##d(*(W'0 '2# R# I# + B ]! # m' >** `* . 2! ! # & ' + o4 51* $ g$ ( A( * 5+ * ' % P( * ( >( ' j' + /* * * 8. , a. t- u* + & =% ' ' # & & ) + + :, [. !/ , ,+ ) & i[% >/9RDmEDFC>Q?y=`- , ) " -O" +  4 9 =  = 96 &7 M lA= ??@ 'CE? U ItB 1 ' S#S7= > ?v9 "= < `A  < @ @+ A  ~ 7   D&<e< z> 4> 80 * $ 1" `? CoBF> S Z ] U uL G C A J? = : 9 9 b7 8 -7 5K44 S3 R4 2 0 r0< I 2@ 39 55 q2 *1  7 1 * x U 4 c   oz :^<?P_k3N  ! !     ] Z V  ! b" +" ! " $ % ' ) , ) "   n% -$$ $$$$H%&y& &d%&<$$$$%&&3&/%%]$$ %~%u%.$t$$$u%:%|#y#$ %{%U$%$Q$&%$$##3##$c%&;%S%g$#$M$'5 N=E*t20&|*,33ӕHOO '(%*)m????????^e #0&R2483;7 %,N-B+z(%"#C#& 6:IHDExCC@F!/G "E"I"I"ZJ"N"K!nK#J $rG #G $F $G #FD #D #_F $G $$C " @ !C #=.9H1 Z. ', / 06W8C)FRowGQnNmA@>A ;IF@B?I "I #?&+ % ((+%#%*# . k   Q5  ( Q  J   2"))B*6*a(]#(!!  a | B ] J 3   m B     .++'&(G/ 0'5[;P_H, 1B".q)((0 -XqA,12E^Q,HOH<1cH1SGN  %',. 0 / 2 6 z8 bB 2G M P P B 5,) $  2  %[!"    k  & $<- $(((]*  P% % ('( g)D'}+)   #(#q% $   " /%  A# a# " " & +8+x*   b  ',,;,Z) , 33. 8) q( Q) -( + ') m( & * q) & & & % J% & I) + // , + - q, v' 8' & % & # % 7$ % ) ( ;" + - T) H' !E j +6:<;AA'?>94s-- 3s' 7y F bI  v 6*6e=s>=? = > . .$< 8   ) &6 : '8 6 8 F9 .> > : "> @;> >b) ,=2,4>7 0 1 9<j4C VRU S S 9I D lB != ; J9 7 s6 W66 64b45 33 5 4 ;0 3 O H 8 C4 j4 . 6 8 9, !    > W Z  HZ@KF} d "   '! ! # [# # ## $ % ,& F% ' ( * + * %  R$ & $h$$Y%t%g&&''&&%X&K%$$$|$$%%+%%$$u%8%$&${""7#%}$%%%N%%$$$5$%V%$%$`##%!%e$$$$$$'3 K>-43#(R*W2wAQ BL0????????` B#/1/C1x-j99 /8/@+%%$*$"&.7R=pIpKIQD9GGCF FGHJAK !KHJI ?F!H #J $tH #J $FH %G $E #EB !A B !.< 971 - %0 J0 /18Z;IF=RrLE>F@=K=:;AG!B- f# j$'I"v""%*"!    `  m6f p - g !$H$%%&&b"      c   "%[%!9   ( + j'c%+>34AsXFN4n9edPl/{.B 2GQ3(/r/3??bJR72&<b@   u # &(')E+ 11 ; =A>@ > = = 8 0 % G  " # ' ?" Z V K W l! *@% " e #&'$B # *J)$* 0 })_)u,|,i. t9 f* % ?+3+*&&1# # (('+-]'.,     u j $ +++ ]*++ , - - * ) ) ,* ( % ' ' ) 8+ 3/ - & % # ) ) .+ -- H. - q+ ' ) /' =' $ $ e' & ( ( '! ) 1' ?* r* !! k+ 04889c9720-' #M&g$  2 [| !%"'() # .& p  B' / j1 -7 6 N4 _: T86 lO ; '; 7 < > < 'Oi.K  _n  _464360 _, 4 E CI OQ T J B s; 7 6  6 7 7 5M5*42 3201 0 ^2p1 1 T T= 4 2 . . p< 4 , 4$  z 1  0  P  r/ X (! " " '# 3# h$ # # l# % % ( 4* 3. u+ , * & !   # &R%g$,$$'$$%''P'&%&7&&W&&%{%1$%l$%)%%'5&%%%i%+ 7!!#4$$%0%%"%D%O% &$S$%D%R%/$=#$#$I%A%%S%T$$%<%y&0 KBo/ 5:rL(d14?kܝv7KM|w????????!< %'x61N16;8< //-%c$"R$4#~8HDjGKIPDzH2I2FyI4IJJKIIcJuHHuG H !H "I $L $`J $J $uI %G #G #D !> q<:7}2 / 2g1:v;u>"@? CgYF <BpFpFlD?P>;AYE!D. # $*3"n!s"="2"!;"       ] c(    0  R!"o    qG     , ;0 -      5'd%'05>fHUUPFK G9jL:8NeY FR/0-03p49 6"231T,  @  b G%+'']''\+0+. 3 ;;<[52W23 . % # 6! "$  b" 9!    +)"  ! % N*-)$ $ E,y'', ; t@I2,64I Aa/--s'w+c.+ ,,060e3x1P0'3 P v $  6 #   b  W) c22/C* * ) * , . @+ i, e( * ) s) }, + ( ' ( * C( ( }+ + , G. - t* + /' & $ $ $ 1( #& ( <+ ! ' '( ! J.:%XD% , 28:6?3p2t4{4+!< )+r$o  v "&?%%1    % .1:> !@ A C0A #; 9 < qP R J< N@ U; M> >:: ,  5" V  "u'/e) + 3 7 sRHH PmPCH > D8 6 3 5 3 4 223&32530. b1 .1 4 2 = R6 3 L/ 4 9 N5 5 1 %     ? z Sq/ }* @! )  % ' $ % B& y$ & ' ' ( 5) }) + L, ") ' U$   2% .' s&$^$e#$t$ $l%;%&&&-&i%%&&&L&&%%#$$&6&&&&;%"" "z#""O#E% %:$%E%$%;$$8%~%t%M$##$%%$$$%#%0$$$'K0 F+A*A191%--02if˼ӖX@" ????????o(-.y0O3 1Y8; -{-E-\)(%'$A^F@CMJCFI6FE,KKXJLK KHJKJI5J I "bL #CK #L $iK %nI $ E #s@ !kE ""A = ;:6456o;]8p8_:@sDCF@%=EFFzBECF{F D@2 + G(,%/"""$8!$-P  x   TL&  S ;    C   j l  2rE+ E   ^ n1 F  F 9o2(()=9?VQHWAUfLP'J707{TUCy8./531K12 2i-M=4T x R  " %B&&M%(* *,s.-14:/7?579 x7 )2 + 1 u25B(n"     % -&,#m 8 2('1 0! (=%&(,^6` xg UC4431W.i'/w,'y,W00w3 2  6 B1 }       *  ( " ( . 3-2]0"- 5* E) + b/ ]/ a/ - - c. 2, * * L* ) + 8( ) - ?, 0 7. y/ :. , P- U* #|$ |" " 8' & o% G# g# $ ' n  e$& e- 142243,# ()E&[ H&+- =. . - + Z, + f1+  %  73+:5e6 j; = : +7 ; E= : : ? 3   w1S 6@4!   %' , / 0 3  < eL3C G FE ? t: 5 R1 / 1 0 z31323.4 k4 ]2 $1 O2 < :7 26 V1 b1 1 B7 d4 2 0 '- + ( 8 &   uM?[ l Ts# # $ i$ u% & ( :) * + J- / - + * V' "   +! 4& * &$$###?#%;%%&%%%'6%&%%&&&I$$`$%%&H&&&%2"!##T#L#"##$%%%%L$$$E%T%|%@%$H$K$$$$W% $$%0%~%>%&1 7F@ X1-#v,/3)kٸzXnza3K/D??????W!)5353#8< ,0/.('J'l&o)7>NC?IzH?EUHJTL:KiLKNMlMJKLKI1LK_JJ}G !K #H #iF !6D "E "C!xA??<;:`5489x65:<?AB>\}WwQUMEMKI tH C;2 o- -.)*!/!#5"p zA<, 1 v!J $   3       i  g j   FTv) d ' !  x" nH/)+"5bAd;KEYp*j]u _^OE>4454G0Ho:22526 F: 7 G3 0?-;UE0 K  s&%))H,[,\++,A-09g=> A :; }A O WXVTUOB&j    ~-+,#$" " $,\1 -& (%%,05N Ss ~ K1-P+7(*c)k)|-46 : A Ke# v 3 E . v    W |$H# '*+:.T1u6[9 7 N5 1 $/ / 1 P2 ~2 - \/ O/ , >+ + W) ( :' ) '+ - l- . . . d+ ) ' $ &% ) % $ " ! ! " s  /S / ! x% %)+-/,! L$')Z/ 5 1 3 +0 z17 ^: C<: 6k6s4 51 q) % <    ! &}&$. 44q1$9>4=B |sqX % h! ! # & + . 0A5 4 5 B eauLD D {A z? J9 5 4 1 B. ). . Y, 23 I4 U00076 5 . 1 2 0 g2 e5 3 0 (. 5a4]+ J"  O Yb_f)8G% O% n% & & ) , -/.0]0. |' !  ! % & + )F%#$6$?#n##}##%k&c%%c%s%&'a'&a%&%&~&%m$$#e%m%&&$#%$####]#E# #$_$%%$"## $$%%%%<% % $%M%]%$n$$$&0'1 ErD7!0/#R,/2%]9hЋġpR<y#B3e???????Z'o32/B105= a01a2m)'$#& 2e<ZGB*J^M*GGCKN6PQPgR{MQPILMK@G)IIIoHHJ ]H vI !H "F "E D D4AlAy=6 566:t878{>t>=>xVrKjN/JIFNJ.O GN64`//'vj   70  #"B &  |    G e  Y c     E tw& HkS   7>U.<+/PK=ElPfvoeR,n<98/107k211+2z1q3/,/4d,N$   * ')V*+A*k()r*+/9HF 6 uA 0VbTT\Q'MG U2hRp)  z  & ,&# 4" ! E" (++ N-]$ & G'( +4 : < =>6 $0w83Z(k*(-%37 : B LH ^<_ k  W    ! #'%&+%,T.30h1/46<K=3= ; 77p3 3 4 3 1 . + ) ) (( ( * '* h, O, ./ &/ i0 . E. * f( e$ D"   $ ! B " 9  iP  u  $,j-Y, ( ]%#_$s*[1 6 5 P8  =$;;;<Q>?=< 6871 , #    P   S u  ;+0 33/#4 @ K  )~- {. 1O7< < Y: DTQnR FT K ? < V5 5 / 0h/00 /6 8 30u0 *8 C3 c/ + 2?/ ) 4 %4 &/ *(Z0 61)(=h   + " E ;    \ S  ?(  $ \% & ' * u, /L0.e.+ ' K  *  m& ) *&'$$$v$j######$i$%^$$$&&&%r$%%%~%%%%%,$%%%x$#z%&$##B"C"%E##^$ #####J#$$R$%%%}%N%o$#$$$"$=$$t%t%(*1 5F#@#,&3+/N2L+#???????O'6/2-18@ >0A21*''%N*`3t:WCBXHJFJJ4LHSOPSTDTWZVfS+QOO[JFOHqGHGEG *F!F DDB@C@$:q6$7:;8|58BB;F>IBRL@n?CGRA86n42`(7"6  $S"5 x Q_  h  o 2  G& V ).kB]hKI  G9 E.,6aCnc7YNˆm!SR@6, &))//++((/A.. 'V K0 ], )7H75-u/,/0z2`4<=C l? I V\ XSPQI I \ c k g?(&& & .y.$   s  & % '(*6' % & % #(+D+ =/x+*/w9+*e* 16:=0@(DOq8 T + }    #%**>/13H4b368Y46M6~2. / 1350:\DI2EC> 9 9 8 &8 y8 35 &1 , . / . / J/ `0 t/ 2 56c1 E+ ( ! v H  % )$ # 8" ; b \ 7! "#$ & b% # ) 3 1: 8 FD=Y99N8<L:; 5 N6:9:7 C/ E(            2+ ,# nz > ]( A, 1^6f>FK HD : StM V T OJ @C F> 7 o4 2 0B1,23?4523e013 ; D 1. g' W& N' 1 8 f3 u. + + i- +'u k M <($ ! " # # s    B" & ( * ) ,I,* ' $ "   9 T # =& o&%%&f#}##$###$8$$>#"#$%V&!&g%&%%P$%~%&%%R${##$s%%{%%$v$% %q$|"#"r"8"# # ""$A#####V$$-$$$%$$$J$#$,%*%/%%&C1 Dp>&)&'!&,L6!-zlrLT;b??????? "w3L2(,34> 130,\,';).(-V<NE.@CHJLZN~NN"SS U#VAZYUcP$RMxO*QNEFG#IiGCD8BD yCCd@??;89+:;<,:=cBAA9&@QXxPBIJKKtSF}<85J4/-'##%g fTQ3J,c*   CАH s S  V 2 S   3-M 962lMGJHKZa}^dqbkDxaJ4o(%%(.(R'Q!  %  E"`   b @n9 23 ()`<JmM]SH=7755&6=Q X]J^X'R$KK S [ a e ~g VU U 4Q J dO NP O KAI;I72 *- -c& ' C% '( & $ ( ,,5p0c6b>?)G$M8QTPAR//.-\%y! ',-L-06*:x86999<KKdx X@--49:Y89< @yEE D= : < w@ ? y@ ? ? \9 26 8 4 1 w/ y2 6 G7 G5 A1 * Q& # a"  = y   a   - "H# $ % ( 6 9/866864316100 503`6Z6/* '  O  B       ! +m ( s!  4  _ $ ) . 637?QI &8 7 E D N 1O F d> < 68 5 }/2$/-B213x1;0./K< 84e- Q* $ x- 6 ? 8  0 z. 33 1 # b(u+' &{Y}%a(j&& T$ # !    # Q' i) * k+ o+) 6$  KF  " +# %&!%^$r%>$~$#L###C#r#$t####^#@#}#$-$\%%%Q%&H%%%%%G%_%%$#$ $k$%%$$$$>#$#l"F"="#{"{#%%$@#u""1$$$T&$P%$c$\$R$% $ #0$$$%'3 fEi;0)%P*-$-1) g"r8Df;cSwD%cAs???????E:'.8**-4?= V232^-N,X(&*s+F>H,CoH|IsKPS4RSMVP\3ZYXNYTTXUJSLINR9LCLKMVI6IDF DDoFmDE B%ACCCDDCX<?HBCA@)Tu;pPMDQ_VLBG<;9~3/J.# Sjaar3jJ?h  Gm9  M  \"nprN2  u   C7 `lcsh0dU9T-JW-bPZYZzXNnD?,r1'%'$""i%! (  + g_"n  %1%O.$@DGJtNHILNR W_K^,]WPGJ H dM Y nd lb }b d h 2e "g ug g e qg Vd e *f ` d \l 7g EH 50W-/.A*E" & = \q'̌Z.  @  X E2q_D3&+.3#7u7\9];t>AC8CBU^ W ҋ \46:-;5=d=:763 .5 b8 9 < = = : >8 : > @ fD H RI B E; 8 ^5 4 4 >0 0 2 / * %   H"dc   3$ % ) , /1@123S2-0  %'^*-P/1611/))*+% N       -    !  ! W   @ . Q$ ( ( A+ /d23{5B8EC? = 6: I B =8 7 5 2 1 s0 5*6-61,.4,(/ 2 (& & [% . 5 3 [- ) ,(- @!b !&)" "b)!'$ 5! *   % ) - /c- + [% A  ! W% 3$ %$#F"!" #####"'$B##$;$.$#W"$B$~$$q$?$6##$>$%\%Y%$$%~%%%%}$|$}$*$D%%#|"#$G#="! !|"8#$~$$#L"w"?!"$$;$%%%$L$"$!$$#{"$%V%d$'43 F8 83/-H(-C\z>xC#Gۚa$r'e???????t!.?0)/v2c5TA 453.A-L,U-,/cAVGmDHILPPQS]]`a+[]~^;Z(W[O]kOLI(OUHGYLdNLRIGD"EEHEFqKKIEACUC@=&A?7AASaiJZSqWPMFF>6R# CTtBs ]  o4(=1 ^ ~ !)$ r)Y & 6 $7Rdhr|} xq} Ì  .{ Wg\W[d_qOKOXaIE83+'(F%%9%$B! P  b9( U E" " &/,=e?^@VE8JJKQXR X[ <_\wSJxI H KHT b \ \ W Z 3` i i j d |e f 6e b (b b Ec c uf c ` a ] )Z.^w ;~ wvmjnjbmp~ ; q M U y րjM@?@CEFxFsJuMOUp' | h @u  Pz R 6t:;<*=;;88&75k21 2 p/ }1 3 5 8 Y9 u; = ? (B E %J [JH ZI H LE B ><!847 t6 . ,&   $3 . # "& ( ) g+ U+*|&! %'&%.)-,1A2a0"++(i%! >  : t   "    #}  D H Q   Q! U!n$ <& R+ - / 1 23Q9 `: 9 x0 1 d6 c4 l2 . `. G* .+4742m0. , O) ]- u, a) :( '$( + <* Z) )9%    m~ k  # # ]  h" % & ( ) [( $  k6` % + t+ (( (\'\%#"##""#,#B$""# "##r$<####>#%%o%$$$##$&#$q$$#$$f$$%O%_%$##$2$$$H$%:#!"!E"#z#@# #"##;#8!#i##M$%L%% $$ $[$$#$$5%n&4%%&4 F7.y75\#,"~/8yTThtbbV?????FFC")g./V- 69B675-,*.-b/X=;AEbJ;KSUVZ__behffHaD]^ZULIMJrOSMmPJHF ED9DBFILHEcD?@Bj<==qAB>D_jU$yvje\P+HD[8, [Fkr]Ij   _'2)[   ". va $ .2Qi v S~ Lv z (h)[~X]cD{=stC{cpjiuWZLLabg:-0%''&!  "!8 _2WH  C  &.=6<FOMPLP S W \ a oZM nJ G G K S O^ W Y :T V \ ` c lqh o q j e a d d ca ah#my@t:lLjjj8i8gfca_pp Æ ȇ \Ԍwrpk+gffj x9  Ak Zap +x q|  j@;/=?<:9<?>< <l;M; : 732 1 / - 0 3 4 5 6 8 9 ; r9 = m@ MB G K zI P MVW SSNC8 , & < O bC  ] u      Q Z #$){'x$$##N q  {  V        s " , + :    n (& B' ,( /' + i, / R1 J4 3 :)  / c5 0 / , - + +g3 e2 x-/0 s- + I%H+0,0 ."  W'u++M(# r    \  } " " g  "     HA" $ ) :. }2 . - ~+%$;# ""|"S"#8## #$~$ $u#l#;"S###"J##y###O##$%1$B$$$,$r$$%!%Q$$K$H%+%c$%$$##J##$"%&$S$P"!!""$$###!""###L###$F$'% $P$!#$&-%F% %U&&%&)J5 oG9G"%~3X&΃O=XEm :`??????}-Z2/.0>m/KCJ5P5h4$.+(+,0;;GzLISWX`cb,fllkgJj_UYZQWP1LL$NeUSHHyFmG_ }T T T Z 5] ._][XEX^dbgf h p ptvfss^pm_nmn'nnllnlXg -mrmsF }U_ m   ҈ &v *eC^l l h w u O_6;?A=?A?=AAACCA??>z:962 - + + L+ @* , . 5 .< > B 4B lA $< : ~= `B G U Y d ~}j0m%l_N<l1p. , # @" 3 5   S H } b     N  p   ?   S   \    \  = I( I & ( m' ) * - B- / , -9 9 1 1  . . / 0 z1 0 . , C*])    ` j     <% a   G    I  % .* V1 u6 86Z1Y/X+($##A##K#""R"M!!""Y#/###C!"L#"#######T$##'F#$>$##$5$l%($$#$Z$$$%%%J%#$##[#$(###B! ##y$##8##R"#<"#/###G"##R$&%$#}#$N$$%h$&%%j&(6 H=_-@.b -$fAy66s6/a,',/+5=hIN~KTz]`^``PfmZlhr=r775N7-:>=_> ?VUJVpl^Q HE5 Mhu}TEu1j  ;d v #c%,E(;$O"D#= 4!A    9rW~ } ܦ w s Ff_V|M+M/KJK8V7KLIIcWf| rLHkZ"OBB<6-?)+'  0 Y" #  6JL8   !  y%3DNQ|SS?TuT=X\_ Z(NI FGgKGUb Cd Z [ XV\.\|XYX Y|\)\^_\ \x^#baJbgknrr rqqpUqo owNrmjuG-zf O 9 @ r `a`6ej r p U 38_;n@K?)@BBF 7GG3FGGHGUDA@{> F= V< 6 4 - ) , c/ $. a0 K2 2 2 2 5 d7 < r> ? dABCD uC E P [ {_ [^q \vw t j c ] ZS L C A :< 2 x3 a( 2 E ' % 7Aa _    M~    V E T   "%o$$(P.>./1*2\4u2.*+ $# B      g    3fH  ' 1, / 3 3 . + <+ + ( %#$t#$9$)###""$I#y"" "#y$<$,#*"#@""D"#####$|$%t%=%0$6#%#u$####c% &z&3%$$$%#$$%?%w%$$^$$$$$##$+$##y""#H"E##"##M"q""# ##w$5%.$$##$%*$x$$&&L%[%0'm5 DH=}.2*"N !e?zmpnxwCwRaMUo01??????mF--0,+234$8@8<845F0,(G*,i)/AG5M_PAR)ZaciBiCjZm\rt=vWr2mvl_UTRLUb[XuL_I1HGDABABIYKeNJE ?=;6U78;<;>><zLVRbT_}|6a:LCF -,e]#5 ,@,Z- "*7'.N*$"' 3, &V%6PbH׆ 3 N s sZY slns Fw z y Zn Qo-5;?A6@SA^EGHHiFGHzHHqD^B@ w> {> t< : q7 2 + ( %' ~& ( * }+ , ++ + )( r) ) ) , 1 7 ; = = \A 4> A BACBC D bC #A D D }G dK K iN O L K H B < = 8 3 . I* i( 6$  sAc   : $   }  T? i  G    6   " #( ) ' # I  q   u  [   c      Z 6" # & d& v) + . / . @) "Z  k  9# %# $%6$&${#W####B#U#"""#N#D##o#$+$$l""E""#~#C#:##$3$$j$3##z##[#$%#$q$$$$$#$$C$$$%%% $X$%2%S#s$%f$$#"##J#"#y""###-"!"/##%%?%1%6$8#$$%$#%&&&2&>(a5 KH;*3#7afLipwj{u8&??????f!r-2012 6Dq6a771.',-1,2EHNQW;]_emHn3xlz|dzSzsi^WUSRsi%ebXTNIGJJ%FDnDDGUOPJEVA=: 8 =@^AAFHHOlZ]q w{Mon|X7RKF`-4t{ @ L 8] ?#*2+|$7  &1+) C! WU 8| $u \UTQOPqM@N+KKcKKILZMMLLOlHP^f LDL^SQE6.Q.h*:% ,'7! <S   M j3:<HOR8TRY[wYY P JFEFLP .\  < : ;7 1 a- - ' & & -' R) ) ) * M* ( & % $ $ [$ 0$ o$ ' ) * }* , / 0 4 O8 G: ; < _? B A X? > > B> > ~= < ; T7 L5 *3 N1 -1 !0 u. X- v. , , . M* * ( ' h& B% % $ % # " c! `! Z! ! ! XE 10 `H ! X   ! %" % 3"Y'-'! ! # & _* :  T$ & ' ( ,$ " .% % # * o$ d!    /%?B5 " $ % 3$ ' ' '%&u%%,$|$<"#}##b"""!"""f"""""Z"Q!#C"###l$$$*$$($"####$!##v#$ $%)%%i%F$$7#$^$$x$P%^$##%c%y$$%g%$$ ###0#$y#####z"!"."}#$K%h%-$%m%Q$w$%%S% $`%T&&&8' )g6 J+;+*5w/|f>Mhל6xU1#"9pS w/Hf?????d "23`491'07 D76z6.1S+*N.c,*4zCI4QjNTbFfi}low"|pgi0f'UUR[NZSPL JIFFmFGFHUTL&FD?:;BKBDDM1JmHZwxj~6`_bwM\) TO(Bubur z ": '"%B#X  S &+k% q ?( Lq]K- @ ݟ u bnRSPPMMJJLKKCKJN~LLKK>CWXd =PIP_E O =;2.+'$ 3 6OH! & `c !.A7C?JnR%RRZw_i^MXSMcI+IK$OScX ]cdlrw}x d{ z }   2  ׎ ڌ ' }wwWz~~Uц7k|uwh~ w  7  / w ʐxщH p a t~ (sc"G8 N< A A ? < 9 95 b4 ^3 -0 r- m, 7) ( ) ' ' H) ( x) ) E) ' ' % $ & ' ) ' ) * s( ( ) x+ + {) ' ' + I) ) + . / #1 \1 1 h/ 0 1 o0 0 . 0 / / J- - 0 #/ d. / - - + / )- , ) ( ( O( ' % $ a; B+-  U   , V     ! G'- 3 q2 2 61 1 /1# * b( v) 5 E6 ?: = : : 4 )  Q     # (% % ' S' ( ( ' (9'\%%k%*##r###U$#"""" "#"!"""T""S"#}# #$$$g%%&%$>$##$]$o#"$#N$K$R$0$$#$$%o$#$R$$M$M$$%$$##""!"#E$#"$"""""$4$r$$#6$1$$%c%Q$%$P%R&'')n+6 G8,41t!f~Q3TS^lyW} }F)!1V?????Cr.55&T3/3A?876&0-*+9*,J,DKQ7RTZ_+cowUy֒oa`OZzUQ|STQMJJsH5G\DG*HtHHvMUuPJGA??@B@KJ`HQjS&TnE|xk~xuT@( ^uD  Y   {@ 3% kg   - "n"!S! d%_*b'$0i 3 ʡ9 W ̨ ? ՘ | x nLL=JNlPMJIJ;JIKLNHNKKMG=Gk 2QC ?ND?C G@y99P1X&$0K!   ^F '7m?DQ}R,U_La`]\TQEOpPMVPW[eemfh[qbu2xw 1y { | 1 6 ێ Y a:}} hW0xw{ i φ O }i  چ\ N g u`tZX"Q<7bC@GGNDsGIKLNyMQRG ~K|JLG OH FbE D F B ? RB HB RB A A = 74 - ) @( & & K% ' & & $ $ & =& v& % ( ) , . . I* + + u) W( , "+ ) % & ;$ % O& ) * %* * ( & & & .' ( ' <& ( 5& & % # P# 3" l# !" " i! !   H  I - EP0 1 tv rf  e  / y+  & # , 2 e0 C9 K! M 0+ n ) 3<G I F fOR9O sM 66 4 d1 0 1 ;- k) ) T& & ' ' ,' 3& k% & ' ( ;' ' 0' &&&%%{##T####E""#^#$ #:##\""E""Y# #J#$)$$$###3$#L$I# ###K#A$$$1$$n$$$%i$##$$o&V&M%R%$$o$#"!"!##u$$$G%$;#x#r"~""#@$j$,#"$#%%?$Q$R$%&'z'), 6 jK;I1f84:#yuY{R2~r@}?d ._????? 6&5n6-l/5C:1;o70-V*(|*4ZLIENStSkZd&fpys{"{rHJK6NN3KDA>|?@F?JHOVWXKQ`lUwxjcl4[l`k& `sI E b tq  Z [   4!j$'#}#%h  !=2oC d qg z o \KqIGqIKNJ6KGLBLII:KJLLKEK1KIFnR] MA<?&Bd>>B==90(# 3 nC `48A#B8BJPSX_d^O[YXm^sekps`mhm6ruw $yr v u xz }   > ‘ 9 8 Ň$M} <U|w3tgy ؋ & Q ڂ u U %Ѿ <* * l ѧ W|1:” 5zs,c,cdXt::BIhHD D FG[J ON rLPOPVVOUWWNV$TRPQNPN M NKHwFA8 :0 |, ( f& $ # " " # `! ! " -   i&) % ( , ( T+ - y, + , 7* & J$ % @& -' ' l) ) >* + + l, / F/ C. . \- , $+ + B) 2' & t$ r" " P  H} w% $ %@ I1  W  " , - | )i3 /0P C X< w  > F 5C% k/ #O Q R A, G$HHxC 1@ ]; 1 ~338 2P, ( #( ' ) ' ' & & &%%$O##$%-$#S###Q##""##D##$'P$T##$:$l#"!#'""<##I$z$#$}%j%h$%u$%$o$X$#7#$($%'&&$%!% %$$$#I##8$P##P$$L$<$###I"u"$6#$J$4#$$#%[$$I$J$H%&E&'j)R+8 ~K:167(<TJ g]\qp writ`7qL?????{S*f&-40w4H3B9981/)F)+^(<LSMMKMKOEiGHHKLHKL%C<=P:<+@H"Q`^[f]RJbf\i_TwrR9YNP_     w  \ZVS g     h @mz % ) | fy u ,p | \`MJbJISGzEJIMJMMKJiJK.GKIIWKHKiPTgFhCDNN=A=77j08,## 4 #> Tv[V "+<NaPTjSTXu^Y]&`cf:jkkputOtrv uXtAx 2xq o ;n \qu |  Q Ȉ X i} {{up+pvs,tvpxcxhxYvqFx )  + M ɸ   " H2 GY ~}v-vt rkQ: >F2EPun~   ҏ  h#?wh+?????f}{}Y(j013186A:S:\6?/?.S+'H**EVUJPwNFRT>Wa&gi3vwvgf`]'Y[ARkPLKHAEGqJ%JLO'JgKwHL@:2f9DM7NS5]|afXRVYy^Z]BXN^JG8g =p uHJ KM.ND  c YHap & X ;gz om  ֍ d| VwIgHHIIFILMLNK7PKJRJSJJ_TRSSSSaRJ 72@1 =. * ( % " }$"=& 9& $  ! # " # $ & % & ' ' & * %* M+ * n. . - + &( m% N$ # 0! {5|+   r! A '@ 35E5E9 %G  # f' , O % ^9 4>C Ai Mw  . Y @= ^, 2 R^g V ]d 6 V%[J?' ! ! +AHYW. '' RRH|: =/ . ,0 ,)5&e$%$$V$##R## ###$#"##"#<###O#n#U"#_#$##$#$#$L#$$p$"#l$R###T$##$Y&$%1$%"% $$ #$$$]%V$$ ####2"#v$k##$$s$z#$%I%m$%%&&J&K&("+8Kc:VaM7h&]T oIp%'H?????D "56i31a5FD8w:T80/ , *W-/AR VHTQSuY^]_xj mw){zcd^Z[%U.O!M1KJGFGFJL3UL`KXD=97@MF2CzFrKXRmSPODP]iZn'TBFI?5 0P:jtC%^  + jeBwdp w S | Ku 's v t \ ( { ZTfGtFNHLJH+JLnPOLOdWQLIJTXUl [XXVU X VOH G&FRDA=4$ 2 ( k% 1? v% ,. 0 1 5 /8 :>jFL R]dls?zM~~ ~Ђ } ow { { vw Oy} x 6t t s rpuzx\rxjcdmw v < - ~ \ytvtRw Ĕ E 8 )`l۰ L Ӌ~Hu g  ֌qaPFFnPEVCVSR {OM L M QK ZK XJ ]H I J K I *H H H |F E E F F wF F E D B 3A @ A /@ @ bA ,A z@ = @ = k< : 7 N5 1 0 + W' & V$ b!cl :  qM  P# 3$ y# % ' :* ( n& & 3" )"j8^+C#;4 [J OM |7|.(0DMI*I ;4 h/ , >! ( Z: 8 6 3 v76a(n(" T" q TD' N E v w h GxQ }% H f VF8 " GB3: 9 # S`*V"0 CG0 C G CP96*43/+&<$n%:%${$%q$}%%#"""####`"g"###T####a""`#$@$#$<#""n"s"#]#$V#$#$o$#$%($$N$$l$$w$_$[$]$1##8#"##$%l$#$%$g$w$F%%%R' &|&():Kj9X-`Xmert)OW,?????u &1//-/#5.GW<8:B83a/B+(,v.,5ZKsW_VUQWt]`Qemot|rOgc~\ZTV<; DD<@JSGHLV[]i]ca BP\7!<jY?Cn4l~Vg+Tk [F+ HtQ~<L F ڂ 1y x 7~  { XWHMIIHGH"JzKqKM1K[8ZUKhTgf_Z WY!V/STUxSGoAJGDE Q:>:/ I( ) * u& # $ $ % $ $ # :" ! P$ # # % # % - {39I?DFJNXdj $f mr W{ ր B ӈ  C P ƀ m e x ۞ M  ϧ Ȍ vouu T J  Eyx| f~ ă W  F Û  _ǯ  c !; ? ݓ ~ ۍ yu| v~ ~ /} { w [w vywxMtnrqoGnup^Q D #A f? =; Y: A: V: : 9 9 9 '6 5 4 d2 c2 1 . . a. . + 6+ <+ ]- - - n. / /- y- . 0 0 f- & % \% D$ ! # # $# 2" ! 3    )   N!G k!8z@B \*; `5"7 L nG L I F(>-HsR w[ XY 1K 9 * 0 5" Z  u $  / #   a,=YQ[Ysdox r _ dT ( %4 Jt i d U n U Q2  F" * 5 aM( 5 Bm k HE JG @ 3A P? 7 - % ^#C%&`%%[&$%$%#"""###f$#####"""I!"R"a#$#""!"""#"####$X$$$n$$^$%$$o$8#|$k$b$##:#I$p$|$u$%w#A#$E$\$$$M%%A%y&;&B%&O'*^: M9XY>!g\#cFtf95\O????_ {41%63[23WF9!;e94!/--,-/hGVaVXVnXZ\bcDf;r%rzwywfi$hbM[b[FVNN|KJGJADGHHL[WO!KCEk@1@A;FnG?dCHN6HKgM`(b}_QRJC=>*+ <ex FQ~ >kj 6N\   V@mw5 u` v w `{ * 5^ Щ  a| eCHHuIG%FGLNKLJMIFd>(Bt?A<>*=q.~& t1 N/ '  ?  ! " ?! $ ! % # $ 4' ' ) 0:@1F NTqW.RG>2 M. - >, * 0 2 (; EP]Oc u k? k ̥ n2 T  ~ S U v @ r | { Oyz t D  : ޣ  ߕ ݄ b y x \RYW_t|   + # 5 z } m pxyx tbx&;udZ T $J SF D < : 8 6 6 4 2 0 h1 / / . - ) ( + 1* , (* K( & & % #& ' -% % " f!  " 3" # b$ & /) * 2( 1) ' ' ' ( ) ) ) ) ( P' ' M%$#! 8|KAdEXLr;<- ; V X ([ a^Z U S tZ ^ %^ k a C s2 - ~! 8  O'% Q& . JG< 9ZUabbF- K[z e΁ jht Q D 8 L: @ E R AU v-WI/. L s k l n H? > !"#$""z"u"!" ##b#$&$]$7#$p$>$0$^%6%$$u##$d$S$##$S$#%O$$$$##$/$$%%%%&t&&'+O:J6QZ'_tPGe\????^ )E84 1,/3D 9Y:;42/+r)I,v-<KP QrSjU;VW]afjmrtvGtm=ib^VTSOLHFA@CZDFG;NgNDQJcC?CEFhJOkIJGMMIJSthZ\xB:Z ;4.[D[Q@$E{BXQS c< Ti7r!( | y q[y ( Y  ! Q HmPI/KJ2KJNMOOLTWO_qninf6b`ad\gVROTKG@.F>HJJ J $J[B- 4 N3 %  ve  " $ f& X& y% % $ ! & * 2 L4 g<CFRK^5dZXS{C@8J,( $ $ # h  J     # J$ j. 0 A0 > PP [ Vs  V ċ Ӛ Ϸ I & ^ b} ޑחz  $ V ƙ R ' wzpTz eTKeHW ދ \ )  d  e } OzFr `1R;RG u a R I +? = < s7 6 3 0 0 *. u. \, + + X) _) i' ( & ( # e% ! "  }   | 9 \  ! # & M% $ $ 3$ l$ s$ # H% & 0' ( % ' ' ) D* , . 0 t/ 1 Y8 : i= : 2 M, ' # / %d(@_o? B N S %Z aac )fd^ ^ a e rh n q0mfe['9"  +; )  ?Gb a w0 ?!qS p p n )t l w w gU P` v ?XPl k -h t n !dS9+ E Xr _ I M @Z U !l@ -.D E &: 7(* s" '2%|$S$y$J$3$$% $$$R$&F$$$2##O#""""" "#$g##%c$$$#$$$%i$$f#$h#$"##%8%%6%U$$%$ #q$M%$%%H%%&&&&(8>J6IPӧX'_t&v]  ??Au&)23+\+/ 2G<<<50N.-a,t+(d/@vH1K SUY5Y$]0[`gpl_ngmk^jLe\{YRLI3GRGCACQBDEVFWpabPHBB9GiQUPN1JKHIEOt_XLHX>N ]j@ksv$ciUu/-F h3(RB9   SQki z p o } T{ >q_v .  ԛ ҄ wf.LKNQKIsMLNrP7LLGDWH`3`fioYoir[B\Z%ZNPJ{EmSf qoo5X GKF@ (0 #6 *  U/ l # %& +% # & % Y% ]" % *) / :DzIP`eT\G@<861{/ q, & % H    .    ] n $ w) ( ' * . 6`7~@lT q Ȍ W :   =,E' Y  5 xtllx xe lri`][bq x b #  3 (  u /  u ~Ë+~R\2ۍ- mh e a _ Zm H\ Na /Y N = G4 _/ j, ( & ' "     Q  C!  # 5% # |!   !   ! V" # $ % ' ' ( % % & % ' f( ' * -3W6 J7 < ? @ pB 7 / ' ! /. XJ` ] ~W W Z ]m^M O "` gmopqt r vxzPy_ Y+M>"1=9I>2DH2* FZ/L bmh ~j +g!R8K =G uD[ }o w pb +D } 1}o Y C| {hZd<^" 91-5L 3IN \ Y tM A V<a52;.)J&,%%$~$=$$%n$%,$p#""x""{!""4!""X#m"%#$$#$n$V#$e%%f$m$$##$W$$8%%$%x$%$%%$t$$%&p%%X& %&P([, v;K7O]VgbW;Pt[wnPT.r]????f},6z3L7'31)Ee><;6C1y--,+*/=@B.H.KOR>Sl[I^hWkfn(rxmgcdkWSWNNLOGErD4@BMA @CE_rZ7KCwACEKUJKJEjHK'LhIPJET .W \LbuEaQj|a   , D   M  0X\Unk  hu ~ { o} ? G " / IsST T!DT!:MNMkNN@M8KJNIj*oppxnilUc_Z._Z^YHn=W S| q A2:37D 7 2 1' ~ q # % 1$ a" " # *$ ' & *- 1 h;BHUMj_7O>}<:H514/ , h) & Q#  " $  q% G  G t  # ' % ;* , I. . / k4 _7Iw O  V ^  J Y  Ie a  < ӑ 1|v_rop meq t wKZJUi T d } ŀ   ƛ w n  "   6 v X  ΞƩݟۚ6ɐĕƏ m th z i n g | NyN ?`fSB 5h+ $# !  c 7xSM  " N$ ! T! H    "h "!R! 2  " " # ," # $ # {" # # K# X" # 1# @# % b& , Y2 5 2 0 2 5 53 3 1 / + ' $ [. B 3h r rog _ YF F dUhfdm;mrCu?ypy}p z k w Z} 3  v i V H 7 q2 4 4L.\([=5 JI o5 : E +EK _ 'JUv ^  ) T #fCd >{ $ٌ { 2w h MF,(5/&W 0 O +E>g [R U RL D > W2 #,("$$}%%&f%@$$####R#!!"#w$##$"$$^$#w#$5##$F%m%%$%+$#`##$I$$$N%%^%% % %%$$%%A%%&3%&*E*;K!8Tkk2o/n.p*!!rh'`9g-9????u.P/'-I8n3H>=>92/...$01<=D%EKHwHHbJRTVZzX^fij,l}hbdb7UPM!IHIGFDDB?AwEe|]3GR@@BuETJ,CE[FDLIY]DAGIJ+C `Y|mZd6: %V7  v z     #   9Z3Yw~ w t | x {{   ׈ "  rXXS $V"R7PNLLIZM2MvJHfDq%zutvk[_ZNaXIH BLH l JB456 :< +I 1 '' 0 $ ! e$ /" ! ! " # # !& ' B+ J0 :< @DLOM}I%<I; ;8 3 0 0 0 S* ' # " # ) & % /! h% H& ' S( !+ * ,-!2 68?BT) v ݞ ٟ C Z njR [ P ] s ְ Jz/ztof`ujeVE=KEE[ r e3 cx $u q S v ~ b  E {Y{&  MԌ Z nuQq zv{{ u uc ~ oh{q N c? 3  5Q @!    XVQuF! !$# $ 1"" "      ]$  % D! "   " , 6 52 , @ L9 2 , ) ) r( w) {- , * , < [` p q|~ QK c e [ Z e h D K A a< HY f y s { 7{ ?{  m Jkcc `0Q(+",7 3}2I M=1_ o a 6X T @ ~, # J#H%%$$#"##u#s##l#;#*#$Y#####E##w###$8% %%I%I%#k#_#"#^$a$%%%&C&$%%L&%G%Y% %S%& &[%&&)@K7ZRoPw5>6(p&P`%E????v?-(-1.-0m3HV?_?w:51//.,.*:<j9BFiHIKhLvNUTY]f^c#ddd[[MT>LOMKJP=MIPFB?F3ElZjUzAABAEIEvF GGWUDF??FN l\g\= qq$`d.#5 a*&  i  ? .AWOTxXw}U z M} O| + /  ۋ  d - 3 sWV>UNMwLgMP#NlLFOc:n'pgvtjwi^h5a_[\TIKAr A { ZO @ ^;V9=I@yC+P h5 $  ! q I# M"  R ] m" % & & , 2 : @ wAFPG!I\E> ; : 7 2 4 L1 , ( % ! +$ % # & (% & :' + .0(Z. 122;H8:FDM^ q ) Ц ׭ d  *  v f  и ñ T % ֫ zz!ma}u|v`oV|`bTV g yނ ~ r 7 T ̣ o |       je  ~ y ra o^g{  e} w K`O RRwTP6 ]Kh Xg   {|C>6 |!t! $  ("     9# ! ! 5  ( % ". 2 , )&O% $ & & $ 6$ & $ #& ~* 3 N _ f m ^ o Lr X m yd?apv uUxVs z `jn p zqd ^ R C +B ?? xC G N TQS)TMyK OTH Q oW /O)K X 9Nk ~ bq A ]{ o VCUA#O#R+KG 96 T V L E JU r i f L\ fa H F 3 0 ! @%)$k$0#9#{#`####s##l&h#Z#$k%$-$&$0#$9$O$&%$$#$I$#$$ #$$%`%&&%r$%j%&$$`%8%&1%%&%%&);MY8OR <9~u5|4p.-wq=P???fn/*0211G@><$72/R/->...4g9:]>CDGdJ%MoLPQVXkY`ba4__UhRLLwMS 8U L:IFANEEFm]]c IaLB>ACDtDEJNOB=?tAFDV0K<-K,V n    Hx #     < GIPNu{ { z Մ 7 ȍ , i O R dMZKwJJPQPJKDTiNy};}v{ooDY[^gOCFwi aqNjR wC 8S:>>J 9 V%   " # l$ k! " " S% $ # :% F+ *02 79 T= ?A C A?: : j8 F5 30-,( & ~( ' , Q, $+ 5* .0A22!02 586?A4HJO]  K 2 5 @ | ` ] ɉ Ս , _ V ڬ q ӛ W o{x#zu{>w\ s *n ~ x vm] VQ W @e m z" y u ) Zx|ɍ F ƶ X   V Yo1 /} nLq Ky jY ! x x^&V4X Y Z 8 t, & "  Owo! E  9   q   !" r% !g!L' }# " ' $! ! " S# $ .a7%! }" " r# % H' : AM VW_ Rgu{sVGg mI s T = ;s ubEulvcZ mWN 0F !A B @ @ E VI J M UO O V Y X _ ] S !O "H |F R ^9mjSl OcUg b T ] ` IYJ FR> g w x r lh \ Ue x O 4    Zh=bZNMHGVEDXmjwph#f|_KUP8Fu` %ktQ? S ra H = P<;>A@M O8 % $ # ( ( & ) ( % ' P% "" J% f( - . / 1 2 5 n8 : : < : 8 9 45 4 4 32/-* ' )+ /A- . i- -.475 5=k>?J.H/LLOL\  i p  x C K  G ۣ Z / % R l [w}trxxՆz z y u p pf }e ] qM H V /b p3s%c \r E~$Oy q Mw S K " D  c s } p` | Sy 1^ dwu+} ]{UD ?DA @ = W; K9 : G: v8 7 v5 9 x1 / r. 4' !!- Q % 3. - , g%  q!_!v    " ' w/d: <  $ +     # n1 E<CGRZXF ^ % |  A !  qo8s sT i ` Y .V AM H (D C B 4 C O ?R 0T rT N MN $O 2O N 3E : 7 ~@ F K V \ 2U!S S T X U P N SN eH P8V|W sG i k FZ O X 2WA N I fR '/4 + a%U#n#$$$%$##"^!"A#$ #$5$E$$$#$&$$X$$%$U#Z#$f$&$%Q%%%%$1$&8$$$%#%& &+'&&f'a*R=/N8'R .IPF5F1(>8og???>t-E37&-A-43YG?x@>C:4w/.g/-/}/,0o9^6<m>?7GGK@NO$KQL'LR`NN$TRL:GJQORLJ4IGeCBBGP{XX XLYCA=A@u=GWJO<666V/20.4/3? w-oA &  G FSL j !C Vz|j! HD8?k(Ā , Y  ї + :|  *  H P| sy hNSM JFIEF_EGk]fr%ulvDžni^USLSqjf208 ~U 5T`H <=?P F ; D G 1J K :T b Q O VK ; : ,7 Y6 c3 2 0 1 |2 4 Z1 2 a6 J7 q8 {7 }5 82 6 3201y.",. ...03225.78L8 f8B< ?0AIGBHLJRSR`y  ݝ 8 ] W ~  J  o &  O   6zr:s}} /yy mq Co h a _ Y nG + !< V a i` g +h v yp _{ Lu +u d M  i y |m y 3 8 ̍ W+  i? l? ? B :G M V i\ b f k Mr 8t /wtEfSD 4 * F% L% #$ s  Y!7!       :  +   ! F) 3A1 5 )6 1  ! - :    y + 5AH5GMPT 5d {" 0 ˦ X h L5h kY ] \V P L ? ,? C WE ;/AP Z 0\ ;Y hZ HY SkTbR _R N G 9 ? 8 : < A RB B H P Q R QOIM_KLPU V X UtP ~9? dM XHD qG {> ; 6 3 9 E9 ( F#$W$K$$%% $%$ #""m##L$ $$$l%$$$%($$%$$%@$#""#`#$$F$&$$$p$/%J$$J$%g$%%&M&%&)b<M:X  7vqz oS`6T?8?%-/-//2>FA^?=<7=1Z..1Q/1.M+f-(8:9=2=?*AvHNtJqQ=JOMPNII/DF3JMhHGECL@?@cDF0JGDRJ1E?;9<=?D=j66Q3,%&1s=Z=2%    1,@p  N   h 0< $DG{PGgMr1w - n 2 މ ؈ z z z j |  % m;MHFFEDg]VQhmAz|yDp&p[gSeOQ^aW d Rp 7<EQF_Q:KNJQab cW Y Z BX U ]O K zD xB A < -; 9 8 5 6 1 1 g/ . 0 - K. / J/ 2 G0 4 p4 4%234=0-, /0.,3=466:a>oABGCF1HJ^MPlS/VWjy  U n   ] Ğ ј  N~ C U % N ˑ ё ;  ~z~ }{ i m o n h ^ 6\ M 0 $3 M [ *d ^ _ f Dm s} o  8 m 1  ɫ j 8 %g چ ٗ- u O  `  M D Z=? ; 57 E7 6 77 75 i5 9 r= B G 6N V_ kb l 5s } a ;  4 p m ^ W L = l1 ) ' l' o#  u k  c! ! # ~$ -= B6=7 )5 / =) !       3# k;N`eWYUR Xb)q~ qǍ } p v` +R D[I L Q Q O #: | |D H 1 ' # @ O [D P Z \ \ [ d] \ V B cK^O M M oK *J VE 3 L@ !E !D B= B8AnBGF3EEP>>r< > <> 1@ i? @ GA @ 7 t. ) V$ %%M%g%%$%$$$##""# #Y$O$y$%#%%N%%&%%&Q%%$N# $#""|$'#"##`#"$$$w$%a$%S&'&%&+&B*)9QK[5S* *IJJyZo Au/}d S?Dl&?.0.0/1 FA{Au?[<B5l40.-2v3J.+,8.;> <p:r<e<M@FHJGWHlG GEED)ACDFKDC]>>=n>?@GILmGvFDIFFB.Ao>97;8R/H'*$ & &, 7 :7 0  [ 0= B a z'y;(/  I e   JC v D?=L]B]Pms;m| z {   x M|!r q \y  K 4 0 x=P-DI9GJ`b\_ d ky|.lWKP;P0NOh O f 58<JA6UID0C?FY 1S > > ~> C > 6 6 h4 y3 4 L3 5 1 X1 H1 K2 1 E. * ' %$ Y# Z! V  ;!$ # ( . o/333L/2l15q89<==h@B DFGITLNT XXYZ j ԯ  E - }   ޠ i f ' ^ z  E߆ xkd"a)``d W` r\ 4Q \:  f = O Y b Xf _ WU f t =w? Y 7 e  ׺ ʵ ; - Б  ԝ A N 6 H X >9V35 1 *. 0 / . 1 s/ . / D1 4 d6 X9 ^; ? B E *H M T Z %X Z a \ _ \ ] [ eX DW yO J @ w8 3 ' #& & # 2" # $ u! R82 "- |( G#   ! y  F   ! <) ]3 Mm|TGi ^ zW @Y bldb e a W f ` 3 E< K ; D4M "G I ? +1 F H 1 l" ;1 N rH ' 1=S ] Y\ ^] K] S I MV NV , :1 Q O O D =CJ M P 7T U T TTUCVTU?C@?:;>> AFD8I;FFISJG8DAD:645i1-,+ + )0 0 ).    nq "&; H['  c |e e9Li m1kp|ox v  }D} Zu u u v z7  9  qcr`#WaYUc]cNftnwih_g ^!CVN!p  L v,139)HD?a?qAR O? 2221 &/ o/ 5- k1 a- * * , 0 0 ^. / / 6 m9 2 , R' ,# ^"  u Z"+$ H# + Q0 0[26f8o<BArD:BJ"IPQ`TYWXGYHVU`Vy = \  q  ͠  x j \ n >  ō O ܆@\ko y p}_[Ya ^ [ Q F !- u+ (& # 4 o$ < IQ Y ^  B >F M O Q O L PM O S T M @ "6 "+ $ G" /! ~% !  C  " \   Q ; ?      & * C+ 2 N r ̘ a Cx c R P ZO JQ 4R G H o9 ) F 5 C N GL QL J M 'L N CQ WO 2 7 L X P Z .^ b b,d ` X X T /%& -; O xA : ? D oA B 4D D }; 9 ZC G F 2F 9C LA > *7 2 , C) ( ( -' })!&,$f$$$&T%C%$%$$%/#&S##"$$#$#$$o$%#$N%$%&%%e$!! ##$#$#$%$""$>$e#$3%Z&&L&%&%C%q(>+R;J5V֫ ke_P޾־߾־ +nESSPL 8D6(I/'/w/c-E1hEKBB?7:543b3j21A2,1O/w.**+7!>g;==<:<@?@@cDzBABCADA==??=AAFpGCB~DBOC=h3"/0-j* . . #    G  I<  g Y #(! 0 X!*9P  B  ,FyYd6]mNbu p { n!z ;z yy wxrv >zw y}=}  @ * ȉ '  evmY_cZ9deoeap]aSRjJ@ 1 63 9?EINFFPMwSFCBh?Z=,@ @ fE D ?{B BBIHHaGiCDIV Ո  ܜ H|߳ .Pvה? .Y >8 7 4 4Z2 C0 00U- e( '( +.;& & ' ) *b,7/ f1 7 9 @ ~@<B%E=MUZb\ uW VM qA ; : N8 : > D K O R T U U M < X, +! w  >!       : L   ' + ' E& 3( B3 \D ,Z Gx / t j IZ KO FBD5=14=4F J 6Q T-R S RS U L 6 1[ f g g h &k klhZh_Z ic V M! <T T D I H B . ' , 6 /). 6 4 1 - , y( $ # & b& ( * o. A0/*&%l%%%$#P$%Q%a$$#!"C !.""#'$"$A$##$<$N#^$$H$$d"!v!" "#n${%*%"$$%u%m$$% %%&&%%), ;K;QV ]TԹ\Sѽ_·p% l$L?X|I */./M/*0GDCAj<8^66423+/0)-.,(r) 5; C !7A ? :i: <= B B CE F sDD EAwB@@CCDDIK7JDAClDfA91\. 3:2J0 8*  W s   } R  <## $ _# %4$#'+' |  ?j,N O   & BJBYxM\fq Uq gu v | fH}L~|{ [  < Ʌ g]0bRe_Hbnhf]fTVM  .C+14u8_;=;]9kA Z; h2 3 4 / 0 93 4 8 5 8 4 k7 ^9(A oAFwF`E#BCECBA>:64 0 K/ D) " '^  b v& & Q6 HJLOR)Qdmu, } d^!XT%R ; 8 b7 i: : A H R [ g ^c s^ O . o  8  z 9 py % )+$$ J% |% q( ) ' x( @5 L Wa l s m e a ^ dU F>40^5z;C D H N S ZV Y vT ] e f k fm bq cp n k sb nX a G 3 JZ YU J K I B , . . 1 Q, * ' [( - ) % % 4% K& ! & & * (- 366b935.%'`%%[%%'$g$(##~#$$$"" ""o"$$##!"F#m# #b$W##*"u"". ""!" "^%|'%t$$z%$%d%%%%S&&&&(*:J9WS \d\ջZZ!پ_˷3nu<}{ukaL! 5\?}!&/H5_03!4GFxEB=:85)54f34%20-,**c,3;;=@ ? R> 8 7 O> ? A WA =< <k;N>AyCEdGHhDC A@8>BM>.     J  k   ! )) ^-A+) *1% E&(+% B   S  ;}t%*) -     +HjGHLeQee o s t x v q ~ 9urk rCx{t  l: L q  . `    ] 7 ܔ agZz }2ˏx( l]U]SY Y e] rV G( KL O& e" "  % > T^ e Lj +h s :y^!xw ՚ z {u = ) ' % $ $  G   >"?ev q  " 9$ >$ $ p& ( (* [- f0 g4 1 = @< 7 7 != t< ~=2<y8: 79 : 9 : D: EA [O ^ _ |W R YC $ L E I],U`% -.2+( ( .& ( ) n& J# E# # x% 0 ]6 E T ] ] i_ Y] Y U MN IE8DCC6@ 2B F $H O T T Z _ b d d \ Q [ \M 9 LA M J A /L 9I E l@ ? ^7 ?, / "+ <% )$ I% % % ' - / h3 5 N4 45s:s@bDAA>E7/R(&5&%_$%##p$2$!$r#g"!u"N!!"&#(##"" "!"!#  ""#$%%E%%i$%%%%& %I%Y& &L&&'*:J;ZL "\۹S޽nn;<]U4?_})$\290+246EGHrC>:6543q2L4533-+*' *\-3/2487; > @ A !> < {= x< = ;7o5~:=@?;:;&9e9: &4  l[l   % *.H20.4..'*+-}..+' #   & m   =!' " % ) 5}L}JAFMN%PlQr!q Dvw}}JJo rn o7m JY rX k e ijj X|Q_kda#pgkjhp ZTIԉW   %:%$'.0&/ .) *  d ! & T' , 3 U6 6 5 12 2 0 `= _B Gi QNRO uP zB ; @=;>; 6 8 7 6 6 ^2 |1 5,/ ) # # ' ( ; fk*tpje^KT Q =OfNJTHFKp~ʬ r > N  ^ C 5 Y  P ` z d t ȉ ߂{lXĎ!xxk ^.TW[sY \ Kk5T S _b*      " : U >^ WZ8b } yuw t ύ ، `n &A2! # O" !   " 3 w mM<)crNx< B! i" n$ <% ( * , - 1/ / 7P: s51 6 8 Z9Z739 ; @ QD G F E F + Q 1e"B" * 3/ ], =*+ ^) * + !) 1) /( n) c( . ) ) j/ 2# F)6 5@ ?F dP )P [M M Q T nV Q bO O H C D bB cC B C BF E > C D :@@ 7 / rB ,B = != : 6 1 . ) 2& b% f% *% ) 1 5 6 9: =? >?TAD JRVTPIA8D/* %###>#w#)$,$ #"!#"3 4 ] j"K#Z#5#$#$2",#!E Q{ss !#1#$%*$%Z%4%.%l%%r&%%%&&&(M(*< L:Y­ #cbۺbZ ޽]޾^IBn&bfTD^?g9%u-6?/.4 HEHBd<8^63e2(23.3s22L1/r/Y..1/+(G' ) 18>K?>A=s;y<":Z/) " -$ =( %) ( 4 6 _6 6 / )  7 2,   r & m) D,32120W2h2+H*4'<,5,)F,/-v( # "   $  c   !r\u b  % -3l2<D*EHM Li.mt r v х :oyil rpf .V RQR$X )` ?_ nOUYh^nvm}r plp?geV^Lv|]  )A#w&*V-- f. n.ut <  ( * ]. q. 1 a2 Q6 5 ==AJJCL9 : > DiCBB R@ A ? = < f= $8 8 *6 4 5 W9 = `? 9 7, z( +) ( v< ouyne;[k\ P O LN(LIIE=EQ i  ~ 4 ߶ ˰ @ ;  (c~|8 f\| [X]_DZ@O5 & X    !  P!  B 0# y? R EYM[l t p o E}}km  { 0 Bn ) ? ! & $' % %! t u .4|w*.q! ! " A& ( w* * V(+8. &1 7 99?)<:5@ < ; A &C B 7*  jua! $ , . + ]* - y, . , G. L, . 0 m.2 g1 ?/^4 1 T  & C1 8 A E J O U X V[ &^ \ U 3P O M H G F &H C 9> ; 8 6 6 3 1 / L- ( G$ ! " v$ q& ( + 5 ,9 : :S> mBBE7FHMOX0Y^9` b`VgO7I?/'x%;#""$g#o##U""f"!/\"!"#o#"!!=! f"!!!!"$$%%_, %k$$%"%[$%%&8&&J&&( +<Jc<Z<UUU JOQmBm $LJ ?^i(2804k00IIHC>9O7624p76z53b2l1!1..+(&$(Q'( ),t* )+ $- * )#  2  Ik e D |     l Z& ,//-/+\./E/2/|1K20*--/_3100./-,( s% -" +    x d  [ bBp  # x$ ) 5523=rCDHuNPN_ {ׂΔ<Xn h h e hm] CS;QMMP\U W 8MXT{YPkek2iu y rma](Nl 0|J-  $+45 NC B rA !m G" ) . 3 L: SAC; :>B$L V \ LO A ? CNPMG E iK YK gB @ ? a= W= 4? ? > = H= 6 ) ) - Q :kl-`[ U O eLKhF DCDqDCh g ޻ b  ۾ | ǡ % ˘ V q : :Ɓ ED\!#ڈ~&~& Ѕ \LY`UG9G M w 3#  # " % % " :$ P)% ! 9  Z / = K |X 2g f p yx t  m  w bOV T   sh p$ # u! h , [ vl^   [ 4-M  # % D' + 1- 0 2 j7;;;R9 7 3 6 > C = $   ! *$ , 3 /+- 5 1 1 u0 2 2 3 6 9: I9 : D9 47 I!q B\& * / c5 ; {D I tP VV XNS )P PN ZL H :F bF D A < 7 |4 1 }, $ A" $) 4|5p59,?CEH H%G IHOPS[!]s`gd6faffdaOZVOB0.(%$$##"#"""! #.#@":""!P!  X eS ""#X"_#%%+%u$$$H#%$%&&'&&V'_)N9H!>ZުV^_۩۫\ddl^^;SC#SlL??^<1'31053IIGFB:O5534695q32F211/.1- &.(*$-W/w--T,+.m/g1.-+( h | ! ! & ' F( ( ) .1_2n11/,,o-1.`.h+|.///0}.-009/K/./0 T+ ( x$ " F   !  { W h  A kwC   L" I$ .z654\) /CHD4F_MMxe|zWzMw{ q h ql Aplp h QV $NNLLOMCMMIQcCq=mhm EJ#V!5[!FFC sJ I I SI IG F $E C C B = j< J< M< 9 9. Q+ ; \a[P O MKK I ?F[DCFIGK+ k λ ޾ w * H  ͐ Q w 2^K*~څw(Rjz~֞ ^_Uf;)   )  f $ # ! s% &+!% +)*I( % *I,. -, 7 EIS2e h h l rzoT o 1 #   P z.F 1| g*BUk    b  +  ER    & L, 0 5 6 (5 4 C4 > B 0 Z! m   # % * %7 K3 2-/2s= 47 7 8 l6 7 }< = Y= > = 7> 05 ; B@ # * M- J2 <26n01( W'W  # $ S$ % H& N( , + (, ,. , 0 1 7 6 4 H3 2 1 0 - , h+ (* [, h6CF\HIiLRVhY[OXZ:Y X\_gTjjhyihgilOo k_g7fY\TP>-)%#$R#:#f"#+$$""#\"F"!" e!K "#$"$n%&%,#$e$$$%'%D%%'&&%'(1>p8 V[nee%$\#$m'dhA[?^q-. 1. *y1J}K8KGA:65e355R6k4}2263J000m1~1*,W+/..x---/t.O.^*#)U),1,. *I,M+F,../7322122/2C-;-11/-,.//E/&100//1.@0.1z0 / , Z* n( A% # ~!        {     "  7  % )2[54J* ! " A7BCDE ILGKc9~ xo o r g pph WTK?QNPRoKKKJRoYfzkt f?facbx`aT[yf0~ |^Z?NTV 5E ;ou  ( 2 8 CKS Z Y "XHU \w\ ǁ}xI HGBGO 8L=< @ E F H E eE IG G G E ? "< = @ > %1 65 Q xW VP KL nKI G E DD GSJJLi+Ͽ # q ,p ) ] [  Rݎً ~xwyЇo w b\L0 9S  !  + ^( -- + * /_0-.i) Q.04 94 54%2/3>CNX _ ` [De y րWY h  te d 6 u 2 %  Qr*o   C m%V+ >GC*? mE 18 $ '" $ & ' O* ; <; A4R22)4"= B > ; > < B A ? ? 6D ; 5 ;# 4A@EJhNzOSRO_KLHD.?=BM>`<"<%6 0a1 U5 4 5 [0 - / Y7 |79S9?G4OV[3]_J`dchCo7ojh?ghppn?otur`rscsrsmo lEkfWb'\U M w<d.g*%W$##C$$$.##{#$""F!"| ! .-" !"'#"$n%S$$#$X$% %$%%F&&&H%'U* e;+B@>TƟ^mc#ج+"'lj:N3"?r),S5*4%-'.I9IHOD}>K943u456S41f42 2----//+0@1~01u2C4y5_63$4S13./01w,,--/F0/1122x22m0,/311"./1~211`132'/0l/.I-0K5u-0 |. . J/ U+' ' % % 9"  n -    }  ! ! ! " u# <$ 136|6! U  j#>BRGHFPCTGN^m pYj b[j y i Xd g_ RRSgOpO>RONKGNUW]hq t q dZUMVT}}^i yBGKDUE6 iDj$./ 1& 4<IT ` g dd nk mwZ q] JJ8BFmE>9 ; 8= A ~C E G G G LH vI F E @ C D 4 7 M IT P 8IzJFJ HGGCHJBKIIL ^ h = R ® ޣ 9 } ގ  p ш։F{poqtv|Ɂ rb7   = ! I + , . d0 X1 V0 . 2 h5 1 8- + + 0 n0 0 74;88=7:;S7/= OP] v } X?%u z dn  g g  5s3c.JC 4 ,M`7# dkhJBfze*VG < L4 9 `? $:54h58;C 9D C ? ^> )A F qF zL C 4 9 /  ^) F>LOY 1_ (_ va a b Yd ik j :hbfkcj jzg 5cd` ]_^[x_'^`Xa__r]o_udg"ikon ppm7rv twnwyxwx;x{| uw"|~ 1 p} rzwVpgfd^VP ]L ^;,&%T$## ###  U !N!"/!&!^ *u  ##@#%%$$($%%#~$%%&&&h%&(n;-G:S $dڬ#+joI[=:(L T?}*{/u7,/!1IoGHMFl;H73404 444321a.,-,y,+v.M1r03(24 44m44F4G5H5_24"1/-/.1,1V4'3222-05140]/1l/E2/H-/.W/2110+.//k11U23-2]- %0 ?+ `- 0 . + T, M* R% % # " Q  # 1" $" k# " ! " # % 0/74  La 1=>FIHF^GP_f8e m_ Ra g e X \ X ^X RQP D [F QF I wM oWtL M K G I J : 8: qM V %R KK .I IHKNtPxQ6PRUge o ʮ  # 5 ! 6   ]x^kmlzs_y!|{r KcI6 " " K( &+ F1 b4 6 8:3 05 '0 z. g1/ .+ 4 4 8;? ><<986J1-'% 1H` o Q M ` U.@,s   M   t cvg*    Z d! R"  K  ! !  # n5^B 9'x!T!(!(` <EQեȝƗW{)s2]PC@@? I@ G "G E xD A sD C aB 9 4 >\) ANP,[ >i k i s Ev v w y y z |v x y w x Dv!rXojifHimchi:hadlJpsut"u x z | | ~ } z tuo tfwj q js 'x | xwpq}} |J|    Evt u "s onf_&[JRK :.+u&%#$$#$#r!t" #" 4  "6##f$s%%%@$k#$#$J$$%&T&H&7%&d(?<cHq7Sqޥ{t$۪snQJk+?De%-26-R.kHGE6C:4J12j2T1110/x0b-K+-L-*,.2R342X2m2w2Y1Y43 6E46786;10"10C03324r21)1i/.J.@.B-z.00b-..01e1~026212$/0"1,04f0+ , ) - I, r- p- + u* * ( B' # % $ % $ ~$ % 4# R" # + 56Q lu 9G?=CCG*DQEYP@ah O]b 6^ ON&Z W S&SQ0RQLNFGDLFLsSO^*SY_ X6SEJ|J6I2tsMC - Y  " $ 2 K S :] # ʑȇuxܝ:zF^,P1GD>L?@t>7 U: G< @ F G 8G M `]h\[\;P jO KL > ^? Z Z ZU 7Q :L 3I@I IJN[ Z`!_ Zh_Vs v  , ' s X s 9 m \ ~ Zu wH ofUovb|;3'" ɤnr= 8 O  # M$ R* /* 1 / ~5Q<c5:<; w< <_6R1 3 ?%@Dd>9;<7/034*(*;.}:O &D X   l  f  t 6   c    o { "   -     m {>  5+   s  0& 44 C H 5 p' ' 23' W, ~q?Lu6FSϖr֎ Պ ~ w s Oj\T O 1J F D |E D 9 5 +? + r! 2#FR8\h} y v z y~  ؅ "  r E~   Bz u Wr pcrskvvsnvL}[}~ y x t z  i | z ~ ˁ ~Bs m m j k n qo 'm Lh ] ]qA o X {|  { x By upelcsW :L C 5+&H$v#w###""S""![ V![ Q"2#$$$%%%2$$^$ ##G$R$%I&%%$&&'=bE6YU4q5vk+6,nm'Il<?;*7/2Z27/HGGD>^6,P-.0:0\2V//-..--0.1274641}/0011K46k554000/124[55q7a5*34{1^1r/...00Q/.j/h01Y20w0321'0132P.-+() f* \& 7) + + + y* E, 7( :( ?& & ( ' % ( 4( ' ' +  # *28' 9[%NNGYO?V?CnHcGFFLVb \OPX \ T V PMJnFCD?F!NPN|HLRJ@LKLGgWowiC   $ M* 2 k@ _rvm  %*w/zf Ĥ^h] IDDZAH=;1*/ 08 > E )D G J M Tr)n+ZaS R7D P g a q\ U +N eM K O PbOPT_ Zd a)i r 1 = }  k Ȳ O ڳ Ш  ݌ T t r/vރ ~ Ls.x~nYè ? < i &  N  | A * + + - D- , \1 s0 40 3 $8QEADq?D9 9D!B;S;=9M0 ;>#EONxQ^ % $ B  -( $ ( D+ * $ 0j, / 1 -  F 3 kͬϞ@ A ם X  Q  { hw ^~oqcLTE rB 7 % " N0y9PT_gnwy^ u J ُ Ɏ AC ڌ d W X $  [ ] [  Z > 4 ( u ; sx(v`|l|Iptxp{{  H O  j Z 0~ 6} /| y Q{ v Ok _ R I < 0)}#"c#x$#s!!"  h""F;!s#$%.$$%& %r$$$"#$S$H$$j$%5%,&g'=,E6QR[ -ݪ%d#n[<R#!??Em,24-/A-38H,EESCl@4.s01'//00050/!.q,,.0]344G323M170928266/61323"311z2U/s0]01222f/-.-4/-\/\/.i/1P00%3101p1n/y.,-,.O0..##&N% ' v$ *$ ) * ) * ' A% # $ F& % ( E& 2( e' # " i Z# 592: `)LWR4S\ [ ;PQHCBHLLK&LJDtFCBo@7AA>;I8FN\HIQ}UOQuKEEd qc P+ # % + 3+ >+ _. 1 Vo r}z}y= G;pz - D4 v"zb"PHF>@>G6<% % 7 D E G ]F G !M f9k;[WSP Tf g ` I] X U W 9Z V T[B_ abr`^p  ߷ ~ G Ԡ ȑ b q w lsm~ ^ ws צ[ m T IBp #     o X Z {% , / / N0 F+ / 2 0 5. ' & 2CEF8;6Ir6 7 \0 `6 =FSH 6GUMRWj] d `h+{wH@ 2A' .# % * .42I0V  4~*Y+p-*a-+% 4# & >  b&  1  > ]" % 10) D+ ' 16.x65 3421+ $   , VeRs e0< o Е c {p 5 c ޝ g ؙ  RkN*qgoez\#^ijhsԆϑ L M | " & ȗ ? ' w ] ۚ n v l l 9 Й ) r o j ~ L  6 8 1 { > , 6 y O ڂ }  z v j W oK -? x/ #)##"$$#""w  l!!  #J$%+$%%S%%%,$$###P$$L%%9%&$F$&( W=I5fX ћќXVלPОמ͗n G`  Lyy?~un,G0*122/.IrFD>;41/141Z/-;0.,.^-2423E2200. 01-/1"00>/m.900/!--`-7//.0S//i//0/.6-,t++**,*+)#"=%" q( & # k$ ' ) ) ( % " " % & % & # " W" 9  ! z( 3-  G U )5 ;F P W K] ZSTVOL H2FD@?l:76X:<-=<r?<@\=CQDDJJ/HUGFAaM [T M)E 6 7 8 ; o2 1 lA`9lB҅Ӓ Y  O ܎хx{ ɫ  m!Gg$TKeHD>@F==/ e H. @ D D rF K ln_XW>Uask ,h a X pS 1W _l t Ft s e a L__cur z  ˸q  _  =~ svnshtq x Ɍ > Jٶȹo W t&r33.. '+ ' % " S(A& - / 0 1 , Y2 I/ E- % " " # T0 <8!2z2 6 < P> H FTNZ 6^NWYa3Uj .q fiJhnpd5 * )" ! -( O* -4O2.|(?I' v( - .+ ') 2/v3, & & t&  !     ( * 6( 0@72596 644&5759}70-- g=Sbp{&`?} w 2 . ,  } 8 ͪ@ q & X J ; Í TьYОCؔ 7 . Y ܩ 5 Z f  ܩ  u 7 \ g ۬ m g c X +  ަ У f a b S d q Z t 7  J  % ,  l , 4  ~ *x o b U-@ 0 +|$#$$?#*$!s a! a#I%e$$$$%%%%Q$b$$$###$%]%x$$( 7<F5S̘nk"#b(nP$*k?QA=)??v%97(6|-/V1KFFTA ?4D.C+*-,++,'-++,/*{,`,, ,-.-.,0./l10P/0\0/M-T-.-Z,/s./X/+-v./#./"..../+. -c.(./ /.,^+N*&)'*[)c(''#g. %   " ' b$   ! U& * * U( ' $ 1$ "! # U& H 5 ! ! J" & (2/  " A  t  " (8<!@IAII FFDy={;j535u35:Z=4?> P (QDX{G; < = ; @ PWVx\Jw 5 7O |  ޯ Ò9!te "d#VIHGA=Bq@94  4 < B FRJ I]\XUYl|t i f 0c a Td _ b -c bi f _ z\|Z\`\ _ ܷi Ɯ  xv fvw u bs ҳ c !  ` L:\:F;;>"@O>9S7/ . o, a, - ) {#  ~   & V/ 4 <>8BzMQM K H {` c W kP_ W aiW g e|k h_ M`*p z ; 3 8 R. #. 0, & Y& +( 4,.d**)9.}/(( ( 3s;L* .:/) ) $   $ !) <% +! ) 31 ]6E4 / 1 998q458:?><;:=;T<AfG VbhGs}(uos ]q { J  k : ߰  а 8 5 e o t ͢+N`٢Лpt|$ q q Q  ] c 6 # f 3 \ } 9 k ? k  ٱ %  ڥ   ɥ  ը N   ` ܙ   , w xg FY nF 2 +$O##e##";""" " !"#P$%$%%D$%%%=%%$$$""t#_%%$#U$( <NE6VFw/baZc ߔ`nK~+4Eq??f,-b6.00n5JCV<N;3-{,0)) *)z*S*X((v')Y+*,>+,[./.#+-)*,,..9-+.,p,L,+:-n,g+),+,-Y)A+))V)*,,Q-,.U/N-a+,d+*-/,,'%'d)!&Q%/%"4!*"< l e   U# $ h! W! ! % ( + + L, ( '& "  # # $ ) ) / A0 ' !  # $ x% z' K+;@d<(521}0/.-.-0575:?D=MPAU)Z ;m-_;8>:ACCDA=;iF 9KgtY? +;D 2HB;<E? ?<<I:A5 '/ ;) #   D $ 4+ . 2 4 %GGIOX Z ] d^ i m KUb_ Vd o fh i s4b a ` u gw HF 2 , \0 / 5 / 1 R0 + ,4|1(/1* /% m3% /A13, S00 + 2 - 33 ) y+ o' ) q) , , , {/ v2 \3 /9;97 :=ADHDD@DDD=9998g<D,O[&[adc$r qz 0 G |S 0 / x  ^?έ\ z]T H 4 4 - Q ߶ ֵ X ٵ ݴ  H M s ̺ . ȷ g l ^ / * ׷  ޴  Ѯ  ޮ ȭ ڮ  G Q  v : ڣ Ѧ T ݞ _ z n Y D 2 C(E#s#`##K"!">"[! b#$%,%%% %%N%V$$"$#$$#$$$$$%\'=F5Yf&bjwgmf*seI[tc?m5 1(/93D.&2QH<g6f2.)%&0&_()%(&%%S#%))**))*B+D))Y)])&3&7(('2'((''&%&''0&$'s%&?#&&&J&(+)@(''))c''&(n(f%$X$Y$%D$""#j%"    a ` ! # 5! I  ! " W& * - / 7/ /. - T- , , / 0 +. A0- + t& % $ G& ( % ).B8=G:r;/:AWApINKDD;o3>-y.:! 1j(::?CBBDHJ,FJo )tKxCIC I 1e;ÃԉU˜ Ï KgÎb{"(w #e#4_!QKPJdK`G@?D>$ "  $ z?NOeTEbSz . t )e 6` #a \ ` *^ 0] (Z 0SXE__W EH ]A!> FMs c ˛ І | jw `y !u} ikM` 4 | G  ε mBfDYFcGJHIEjDfB=8c<z;@9 9h86 6 1 4 v6 A IIP ]OHzT a W W \i \P)Ybj o p R] Dd Y W Yzo @u *M 4 . K4 a3 3q.-+ -9) l+ "'N>8N-U-=AD@-2y?80 4 1 /1T- h+ ( + - /R/ 43(5 '69%<>B BIBAC9CECsAF I .G AABBB@= 79nA|HePM[f:nJvz@Ԇ q J 3  Ϧ n b I|JP4ѡo}*kK(O ٴ Q ! ˹  f v F J O I  ! , 4    L     P ԰ E f S VΫ @  9 . ɣ V  l BU t> . %B$##p#X"#?#  ###p$M$$%I% %y%K%\$S$9#"#S#8$#$$&$%a'?G7X&ekak!g!lQtVc\:l_k*#-43G,~/G%6f2^3H0*''%"$$F#$%$$Q'O'*@+%%$%)(U)* '(H(y**I)z(P'((B("&M(7$#E#w##""F$[$Z "~#'e)(\& 'm$&$!  "k!!""" b "!    Z L V~ r  ! ! ! x# -" M% }) u- 1 2 4 3 a2 m3 ]. / q1 ~2/ + ' L' ' !  >     +o8AD3;H8v* QY$4*?K$O\^adhkmʖ - k 2g Kd itx~ T >d(K:%:#_/ aqx "l#U[ RJxLL!H !EHAZ%X $ ;OVy_p}  y o zl Mn tm e W] V U UXj'fXF > ;= 8 Dlu ɵ v Y C & { x { ~ z [jn0 ɜ u Y  ܬ t [QW+! ! *+r.:<7CLP 7MNPJC? ; ?6 5 97 B N FP N N V Z ^DW X !_ cZ ]_+bf k g DY a][\j m L 8 W8H= =W=?>13H27=;B0i0& D@74;?>Q7 ;= 4 r5010 . '.1365.8=@"@@bB,AV>>BM X [ X RK q< [8 6 <4 2 2 x8#;8,BMU\gr{{Yr$   h ,KzEo{sO(8ٖu K s մ " *   K ; } m | * Ĵ s   p ں f \ ʭ U T C H  T ܮ N ή  V I Hͨ e % H k O 9 ( #]#]#""C"" "##)###$?#$$Z###"#$'$$ ##g$&#P#'0?#G(4X|ۛc"ٝ_/lA1LK>Rr?fZ#3!31/3YE1I0<.*&R% %A'(',&&'%C%'I&$)%j#$N$b&^(t&''`#%`'&%p$'''[$%:$$<$$4$#S#$ " ;"b#&$$%'$"l!! vL = ""!&  D u    kS  [# & $ Z# # # ' * t, . 40 g3 3 3 27151. / % S P u gg OA&F ,FV nv!y!|!mJhۣ  ϟ – A q O{xZs}j=Ab 6  $ )   { @  0bm "f")\!sc!U2MKI!I!&E"HE((5K`Gjtnnn#o pm kc Z S >7 4 49K'{ $ e u P Iz v ?x +x r Wr Gcgu  m < k ĸ  M560Z$ #E! o p  " H, g65@ I .Q]\[fV{SLFgE E yC {A PF P~_ T fN en(`gi h _ d Kf c` `^bc^ XT H >IJ{=?\@< 8 < A64;9QEN4!;<9Z79 G798 8<7I9:;?9R<W:;>]<9<=><=h> => =? C > ?; 8 7 W2 l1 k/ 1 1 4 B8 :s=2@ >@= 7 , & + .6>GOZfmp#z$>l X IVxV)ҳM{1y;qbDب e c     U ^ Ҷ  U Z n Q p ] ȵ l He_  V   @  ҩ Y E ٫  ȧ ȥ ֞ [ ٣ V  Ц ͜  ` B _/ 9# W##&##!! !#:$X###$#$%"V"#X#P""$e$W#$$p#F"$3& >F4BVQ? HɖOOM l\"D,[&#h?uh(T207*t1OE/..j(&)H'2$((&&$%&$%'m&t%3$({&#%%&E&Z$''('=&4%$% "$y&&':##$#_#0!  w!#h  !# O     '    C      ? z { "# ( * H* [( $ % % $ b% , 4 7 <;9:60:' u   [ @ 3  ]   [    K  . f 3 !/?PT\v w   g\bsjqxޠ o ӫ 9  Ը  RJ;x4+F ! ! A  Z :  s# S" ' 0 8 ~F xF8U T tV .] Uh l #jCvk\ R L 0I I L ;M 2P dU Q U Z Y X X [ ] ] TW +W Q M =MNLHDBQ@ ^< o; :6 3\8r3(;7 Ax?V=>?n:$8=;:=#9;4z1 / - *) ( , . 0. . S, , , . . / }2 4 5 +6 )8 !; C::~;93+ + ~& 6! & }   ! d% $ M# & "+92;iEOXagto w s~ }} nZ<PϏp|7quoIvP 5 _ & ʦק  ĵɱׯ ۲ c # a w ) / * *  u S ڨ +  ן  U   o  d ܟ Y ږ Y ן Ӝ  v UQ 7 a&$?#="$#/"t"#9$$##$^$$%O$$##E#T#$#."j#%""#&C;F5S Rzl,+ckr*ck gZD]O  BEV?g'07"831G..J.^*'(&#!j%&V&&(%F"#<" %D# ##""%%%>%e#0$%R$%&:"!%\'_%k%+%]((T%;#k$T&#!$J##!  c      l   J ;  5       >  aW-T% ) 1 3 . . ) u( ( M, B0 4x:v>?J<.84R3_+c('+U.9@01+<+*1)$ d R "'g(_)5&$ _ M | T +    _$ ( <% I- |0 / , q( O' ' *4.57 7 67; U:>CG Hv]`Y_!%^!$g"Z!S #S"P $HM &B %= #I $'FkM\W N iJ G ND.AANWcYSJDG= 801g17J6;4;X<r96 7 ;>Igc  m ƨ = Ԗ + *}>uQt | G J Ibhmw Q ݴ T 0 H { b % ZOF?C61,)q%# a(%"T  '$  $ ! ^  m# +0 /&5= E R Nl Im hx 3yijyZsph a Z S YO L I !E fC;DA<C:]:*:772 `42-3/ *+ - }+ ) * a' , 1 . ) ( h& $ $ v$ # ! " m$ % P$ % ) .. *2 !3 35Y8<?>?<95>0K) $ r y9J P B     Q  h  ! & + 17577e:CMU\c l sw;ˠLt!lpL%u C , Q ۡ   M  ܪ + w x  ]  \ Ψ U Z Q o  F 9 Ę 3 $ f m , u R 7 P v ȑw  p B d C *""#$c$7#~#$1$]$g$M$%%%$$r$_##,$)&#f"#1"R"!!_!$ :G7RT-lcm-lmbii km bq Qm +4/0P,3J/,A.g*)&%"$$W'"'( %s#""/ #%"!m #U#&O$_&(%#{$("[ $##$.!#"9! !|! Zc y A!P"H Xe 7 G   W E y  & `  m )   5 #     f 4  ^#&=R x/.K<s<v</9 < = 6 7r5K77;<:<N?DEGNDDlABDBo?692-[-(#9$/B299H7663-5*& 5  N { 1 AN  ] )h)9.6N?b?A#AnFHKQXR\j="l "g "k $hg#d$[ $T$N#F #: =7 4 % ?5 A D oI*P`LtG@5 ,)  " 284567536 7e=:w:89:?In V ѭ d E J ^ |{ut%} } ؉ ncgsmv 2 G Ͳ N ^ YULI@:5/A,c'V+2(''G(.h()"^$E$L!!q !!"$ 3+ 0 0 5 =8 g6 ; W? D K \ p { i a )\ 0] H[ Y X U T }R uP K EQ ;I >> ?U:7;77s6@65765 7*8V98975y8;31256765q33M57k642^,g+*z$ e# S  O [   J L   9     D   C  ! G)0N2:68c56K=6@;?nAoIIU]elt/}IjuOwYil pVJ9   C ғ 1 ) m E 6 ( w ` \ l <  J l ˃ N f +   2 l  u І  } ґ ͘k l ʘq tR 2 $$###($ $&#$e$.$$g$%%+$$##x###$#~"8# """Z#% =?81W̗͊ddia*[ihl pb$M 4?BY -025X2Q0H/+,)'M&q(T%'2&'%5'#$d"w# 'K'*%%$#%&%##!#""v!##"##O"$h%0#K ! X;z "33[ 6 &  6p % u  k      - b Z.   T  z N GZ$> s(8tD K U ^ ` l)^V>RNLIdKmKPN~MGGyG!IECp?<75267l7999G65443 0e00 00, , d.k.13;>E+F=J LMMN\OZSWhYXbee9br m"zi!d!Y RJy?;@ %? =[.I!+YMZ G5+  c    # ;<4>M<@]<<G<-;:;<;=>CRi2|  Q I  D N s~%](@$K    F     b" %%$  <       R!K $1<4D659m>#ARFJHEIMXia dpp|& JOnfyd2V B` R ̍ t @ ˎ # ̒ 0 > " p ͡ L ա  #N m i  X O V W C i Nf ʄ L r H} . j р ى  a  Pv s_ 7 '#$Y%###"0#r$$N%$%D%,%!%#$R##$I$*""""9!"$& lBHq4"W$,,bXa! ЈlSK   ?tLq.422,.+FM/G-$+>)&&^(%v$Q' &$h$ $""-!$X$%o$g#$$&!"!W" w"!_ N!"!!!"Ge1 !!r "<E"l MV&  = M S   < ) ^ 8   5 N 4 9 Y 6   h  J UZ!5F,<t  dG+Q]X"i ` Ɇ ? vyt6i{eXZLKC[AA<h=b@{A+A?$:99 9g:,88@7 7 85 5 K3 4 6 4 j6 6 7 6 3 2 4 1 - * x- @- * C* ?7~nxj Mj!mf V\PB FDDq<$;4   swD>(>  | T'<B|D@@==J=;o:{=S=>BNN[r9z 4 P v !}iw9uRw z A Ry _Gekrzf e  3 ή AjWXUROKIDCBz944j5/1=!8?753=3. 4,-'13m/49C=8M:C73*001///K13o4$21,-*u''m(l)(p)%'r&v"!%- &m)**()(9(+()**(v%%#""7"$'3&%j%M%(*%&&)(++-)$=!  m      "E&1'+*:&$< d = N W 6 t!C",&. 357AAkFyJOU|XbSKELDP\dpvvs1g_ N:X<~ q u "  P ,  ^   I M a b ~  l ް c b ` 1  j ӄ Ћ њnM p ͇  *ԁ { } vz z w  N м ܹ e d > '+ %#$$#$$^$_#7"[#q$0$%*%'$%$$:$$b$9%=% $g##"B m"#"% B G3 XC+bZa؏وmc OtcG)/B50k1Z3C\/-M-2)(&\%% %%%'"#F# !'%$"'$2%"""%%|#    #s"{V! &:\!" g! !"Q (#%/ 5N`\x[y\Lg.avcltb[ pV X MR 7N pJ G > @ = ,> 5> w= 8 7 6 D6 3 2 t2 2 1 0 1 54]1m/0v-K+,(c'"&%xRunklfF^M2FF"<9;7 E ߍ4D# ?$!* E%<&DCA@@<>=>q?DGQ]h:u v  ` R W̃~ y z M} < =mEc grbv~ D 0  d [xY_X1VGSSMWB@:>=??<@g=}7V93234021o4;[=]<=!<(:J;;9 61 48!;;:241+,.?-/)..O,g,-^+0*%*(+(v'#+p+I++*)*-2,+*+ *V)i(())(*9*+ +*N*_,!-D,/./[+(% 5  $ O G&O& 'h)-(M)"&#  0  :   T  }$$(358:)?EKM:SX_ehk@ie ^[Vdi9h`mSPAEuč  c c    ϟ x Q o Q  J  $   =  # N u '' ʐ K  & Js| y w z x ˄L7 mS ٶ R Th ZI . $J$&$)"$%" J #=$:$7$A$<$3$%9$)$%$e$$$$$n#!]"#-% }@F5Vke]#dی#َ َZڏ #l ~LwS->}}z',3c0j41G0,W,*5&v&%%g&'#$! !"":"!6K$9#3  F o !p i!/!ezY{ T#S! C#M   ` i <   [  $      | N | ; ' - g B G Q 6 W  j     > Z ,  ) +.[2JS&kT+  A T  4  xtR7f  | Q   " 0*\T J  ~mJV~h\nd!bYDrE@=@@<-A 'wFQ,  :  (K?HA?Ap?><?H="GJVoa&k O σ . ޣ { ե ] ِ } z {   :j@cj,pt}0 Դ  z . i l Z ^V^[eZYT MYH~G@@^DAFCAo<;774U4j;75V9@">B??> <9O70/5C7D1@}82800o07111K//28 2>222G2122/0/-'&)$   @ %'+(+-*+v% )_$! q"    !$ : 02V7=?ADJQZahpV{lPju*h `]Qatfϔ '   v 7  ̛ 0 Ԋ ܇ Z v щ ܒ : / 3 4 . d e -  \ #  ߃ ہ e p 8 Ȏ ͇ ̆ R ~ >{ x t ~  r b ~ c p 8] 5 &%$##f"l""#$+$$%$$3$% %C$I% $y##$+#{"!##$((AG70vXǕ "YZYى_XXֆXk%$GX?|V()=5`404E3H\/-,}(w%%$!&%%G!' h) "L""!  A  c E  nf"g,C!Q ! "F     A   ? w 3     &     s 1       U  Z  _   w   @  tLc6{2r0'[nO.Vo~ c%~"%*c~WtBxu vmle ]SKG!@E>m<IB!q5h4v$  AjU+ :CGZB7??*?>?=?GJV^7gw  H r ɸ f  y ){ } jic^luw0{G ˽ {  a [ 4 ^X_a|`` ZVRNEHEhHIIFE@=:b97;8=m?B.D~A=;:462E28?+?A:4*,Q();.Z.Y0m/!362,(**H.0220\2P2n2211}34/0]/[1/0/3X6U66:9 8896!4D3j3713m1 1;/6,|*+-#,:( 0 +)2**,0/06.-)')+s+V"0     $+259BFnM[QxY%^doz(  / )  .  i~ -   > v  S  % P , : p ] # } q H  M NΑ  V ] ~ } "} ~ x ~ 3ֵ o tq a B %) #$$##/"A"##$$s$$r$3%"#$$$#$X#$##""e%(ID&Ho/aP t{zz{|+|}k~3~~~!*(|,j}16cJIW ?n=g,?1.~510G0%-,r(%F$"B  ! S n O   -  F3q   *    8   B -!"m D " !!!% W    3   (   2  a   v      w  |        ?   4 Q        bAhv\ S3y8Kltk`9l%`/%x8Q\R) 7`Naon d] ]?IDAC<;?Z5 j)DW+)5  PYz c- ETFB6AV?@@BACEoIbOZbcq ڈ ̏ q l  2 B T /| C| ~ ͋  fdnNsúڧz h $ h e gY)^ccb]Z+TRQN6KwMHkLUGBGDA:?;=;;@,EABEpCB?:87#374Z6<EzA;}4z++I((,-/Y4.3340B1/2.F.02844456=5962Z1/#//113789;<B<:_:T77%54r3`215"2110/v-@.N.I'$ % +n..4540!/0//?,,& $!!!"R'?(-3g6C8=C6HNU]Qdtnu |= ߐ ` B X #r} w 2 2 S , f R ! N D W  r X d } ͋ Y ̆ U X Jk #  ف t t} v y ; 8π 5 n  Tw g QM h- O" $$7### "#2###S# #$7$7$$#("#s$2"##B!!"$(AE F0QJz{sz{k|k|t|r}*~a~~9{jR?=R'33]2.93E0.+'# 4 |!.  |! P Y ,  < N     Z  x  \ bkG !# "! 5C       L    Q / g   |  &   &  7  i  @ / K  i 2 S  | t x   w  T {2?do[" KSGBy'3D3Gq \'G?`&BcYh lX,]IGK69H:\=52TQgR#7#.}%#h C + hCyCB ?/?ACkDNO`S_(lj Z S 0 X ʢ  Հy~ F  я = kafqDsNvϯ G Ƴ  ̫ b ֜ msT9Z@cekebE[VRRRPO'MKqPtK0MISBDD?w@GI=JIB_@w=0=6:8(8M747C2GlB;-'&(,052 56i68E201/34 347I7w7797O5M3+0e1 /-@0n11l46;==<=;;87-842C345h4$3i1611+011,% _' )9*/2O130`3p3=3d2402k,c+,A%% )*+'+b2f8}=ADDMSkY^BfnwW3)ё Y   '    W D ي Ո _ V G 4 a  Ο u 9  ) ( o ͆ f ' / k Q  Ć )  8| x ۑ qׁ  *  3| aj U F6 ##%l#:""H" "##""##$'%$X#q ####%""!""*%) DEF01Xz#o}h ~    E B   =  T     2  b1 r     q        k ]         7 k #  \ ,  W) KuBG3HlGNC)k#lz|[ 2g> n$h!dXq^lMRRQ^N MOFO[QMAIC=C6DJMmMzJG+EBy<><:=vC0IJA91.*-y-/1m65z7)6q5`32147T8658;88z9I540i1^-C.4Y12`5Z7;L=>?<=I>:867554*5}4y62'0D0 002,*&'O).055452/4^4W5]2W10/0/=0k-,-S*.w17:>FDJVNU]eqv~6ڐA!+` o  L f ~  ߂ ` Ж ] [    j c   ͑ ɔ  )  5 ݞ 7  Ԋ1 }  6  Ӆ ~ ~ ?{ x  ˃  / ѷ ] ] p ] A %#%$###a"0"#$ $,#"#$l$`$&$:##/$[##"!!#Q%S) GF6 XLz,zzz|k|||~)~h ih{l ???????????????wm:h)C1/M1j/0IV1.U-%"!jR j l5 a  F          g  ~  +   )   e-fT &K  q ~   &  P   H H  ]  I x  / ~ %   V M N   L  T  w e   Z  + HC y M  C9 { {m<5PLTx\: *Z7SC4SKKVH8ug eSr d __UY&XPX?A,<J5/  n =Q C81++I)a!&*p mAb A{Bn@@-AgC_F KPTZn '  l ی ̒ Ӟ 8 n  : 7 C~  ( ilo7s|ړ s ̴ կ  V מ  8 :V ]`0ege]U>VTVRIQRQ;KJLNU*PL?KHN@SSSoPLGyEEDAVCHLkN JB:1 *(,w0178<<Q7L54 25:9O:999::|55 47b2..u/:419193}549<@?>=@E?:98656:502626p65'11r1o020&)?',g1'34453532 342*12L131132d.y2/3!7<@DIMQT`lt{w_] q U ل # ؓ  d X M - ^ e Ǣ ( _ ߔ ̠ | `  2 ~ > I  ' 3 + 6 ~ { z - ߘЁ b ] ٻ S 0 W ^ "r e lL(2#|##"$!#z$*##$/###$3$$ ##$$$#" """_%M)F>Ha/mSz4z6zz{|k}"}j}~qh`{l??????????????????E(0,/2(.2F`0{-*h&#"*   9 '  N * P  s   ! g !8  } Y & M    w z 1 6h   6  R  /    p N   H   R  R    ) S    )   G   )     !   vo - v /  QI  jzS!ASl*g as:k*N=  $ lj p c '_0az`Ys uSI<<}7J.  U=^ iJn:84t%#2v #CBBS@A2CGOHVY`t O = U l X Ů Ҝ =~   ȑ =jm"rv6T ȫ Ӭ W  [YO\ejaf%_WFZW(V8T>RIQlOOROuYYSPSVYZX,SCNK!HsDDFI#KBR*RrO?8<{3.E,.30-36:=>;7O68:~<8;:<=\<d><;79&8D4I/2.0212-46=DAq@>_?@=Bp@?:7E548e57w55_6(12014v1O+*0+0g35443w43j21533n3Z546.44C26H;@>;6..236s;8>A?J?=<86A=@=>>>-=h>;8`9843?0/8025v9y<>CBBAACA=<X6445K88w67/734-1142k2{0($03L6A5776544Y41344s55c6u87s848;?@F HWKLL%S=V8e pvJz{܆ֆ(  Q  ۔ 0 e ɒ ܌ X } ӑ  K j ś ' s( } % b @ ʍ _ $ I ϐ ˎ [ l ƒ q 0 ! x | | } | d  ѓc z Tx Co G\ 4 $Q#"y!!G!   "####y#$S%"X#P$%.%>$&O#"%M(J~G 1)Z pqqqrrrsst\uuvTvw sj ?????????????????t-081,}..G-(($C! Y  &        " ;     r d Fy    X 4 k G`~H #  C b    G        X   6 c 4    1 O   T *  :  z   \ zT @  w  A          \   } " G 3i`}cHt=m*`lSg ^._W" ]5` r cp !(m WSmt!SB94/!^%?Y ,@&5.6o(N" W$*5$@ ? _CB NDEIPBU\/cPr f j  d n X ۿ  } } ԅ  M FfVfkhw{=ɴ    WW `]e;fyggke[][][XXTVVQT/\`]cmfec]Y~QPODORyVUUUQD=Q?v2-026=BvBA>=1>?(@CBqCYAB AB@<);;:[5o6055z5.49c?A9DDCAB[D)B @<957E61666A97(9&6o53 33+0/.+F.w1$68:987653Y14$55o7\8(8:e99=i?@@ABFKLJP?U\gks>{Dy?~B΃  ى + ܈ -   [r t X J ] ݒ Ș y * З`m U p  _ Ј p ` ҆ Y q j   G}   n~ } z 8t Lw ~~ R {  ˣ ٫ D3u l ^ @ $ # "!!"|!"D!"""1#B" %h%H%$$G%@%:$$$$#$:& )JD1Tʊm#nbn"noop p q qXqr`rsgsok?????????????????|.")3#0.04 Gi.(!%n"qz"k #dH   D    u  2  R ` ,, R   * ^ WcL Q   y       = ,          7 Q V   k D 2  b {   @6  B   -      r    p 3  _  H  i  3tK:[L37W '2:'L?SgZ0E)|OKL ]Zd^i g J:-95+t AZEl91/-&y& $("_k0Q+= CCDHLRCX^k ߂  \ ^  ĺ W < } ߀ χ Swrg?dh zP|rjϦp | ̸ ճ K  d  9 b7[_jbfitg(a^]]I\[_;\+ZZ[a/btdjJkeg<]WUPQSS]ZXV5RC@=20=1j4:N=@CAC#@ACIKGDEFGEEE>i=;K::N7699:9^>D4EGETDCDNDn@<:9-597779a887604?7'33>4#/--"4L9:::m7:-65D77M77s7k8T88}: ;];\>b?@@GDgCOFFxHgKUJ`8eiBmatxg~~c~@ ~ W 0 y   / X ȍ Z  n 0 ``   = N S ܇ ` )~ :} }  n | y | |} @ ~  A  { x =} dQ 9 C 7  T D{ s a ?M &$P"r"2!!"N"O   !$$k$b#%"$&&&#$%6%$')JE*2RWmnnhmnooppq`qrrrsoj?????????????????V:%*2]:C42'4E()'#"" W   Y     P     G  z  ?        9  <l{  8     X     E      E          L   ) S 1 6  . 5 M F  D    1  ) { q ?  X    r  "       H , 4SnY  lh )PS  ~N ZRdLX]9ZSLTuE?:5p+ [ >U67h2.R(>) [*3$"  :C>DERGKPW^ g|    m b ݼ } m )p[`_jauN/4a̱ ^ . П x e\]fchflnbaa_ Z\\ZX\\` fg\mnVihsac]UUUV]c8`_]T*CDJ<.029_=I?CDBBl@DIOLJFGGEGTB??;;9Q:<;x;==pDEFHEtDBE`ESEB@N;;^98:8:v:A660688265652-!05H:;%:(99656778<9`8-8991;*< @B>FDvB}FGHC FAOSZ`elrwyLz|dy}{ }  & ( } w 5 Ӝ Օ h H ˑ J ) L { x  0  = X~ { } P 8 w t} } = q{ j| o v&Nم V  f 0  t| w g X ( $K"!"P  p! V I!9#$b$)#$e#$S%&%s%-%=$%&>)WMF/VGmnjnncnnoppYqr!rXrrsoj?????????????????()7y2+/21U./6 >W%I)%|$X"   T   ] m   2 ^  +c         / . Q   4 )e    Z  W   C  p /  W j   r 8  V   T   -         9Rj !     E c    q        v   Fw' s > + "   z{k]p|8k8lg2G}u JYhTLFM']VA+34*G(v ZNMRo55<;,* =) ODZ55v#/{[   ' AEbFUK OSYqcxq Ƃ ҈  Փ 4  Q  zyф / j7^cfmz4[ G d  U  ߞ К} ]eZX]dekaweb``%aa]][]aj+ln=ppoga+]dTUZY%`Kcwc]`[UZF Gq9t157=B/FGqIGEfGLUUPJIMHcGIWED5B?>==><Z?X@ FJmHHsGGEF-GEBf>@>/5Y68?6:3="<b:8v:99:f8?5A65P39s<987q8-7@6778 909<&=<p?m>d@>GFGIIJLIJJvPSTY^I_Ma^h,tshuTu8yzz ! ߃ ] ! # ِ 2 @ p T N T  ȑ n   k c s~8 } 5{ | d} }}  Z  | 0  D v 1| | ) Y Ó / ) ̅ i1 ĩ x n 4\ . `##!!X!"! ##r#{"$$R#&=%r$$$%&$#'KE1XqminnnonoapYpq"qr`rrrnj????????????????  "859c-J8(Y)) (/'#!"p!i]     ; _ @  P U D e f  @ l   0  ?)   g  y  h FJ T $  - r  3 w @       b H   7    (  U F       m. @   Y  x    _ o    1    x Q   b    C 3   r  ~rw ifvkLzCz @MND>GRVE<y83x)! >_[34F8'S&j" 2RVb9+*B  } % 3< EHNOV]#k z o ɉ ߍ - b 1 г ׿ $ ~Յ ?  a^e_egpyas A ڭ ɡ̚S jYVEc?gnyga[daQ```:`^`dmh^np1tppiBefc;ebcildb]SK*H9628j>=B1IyLKBDiHLVYAZ TNN-KIHFF%GDAp?I@A=.BEGGMK7J|GF2F'FEJEfFB?@"<=969a8;:r:);:}9<O;<4t758:$;"<99+68;9*:99;'<]=D>tB?AILIKJK@J\K%MMPTYX\KbDgWippgrVt !    f w ( e 8 J W  R \ c S  = , zD {  ~ } N~  Ā 9 h ~ |} ~ } c{ 4 Z G ŕ  w He { p sd 6 '$$d"n""[!m! 1 ""#$$#z%P$%D%0%&%$&}MG2W m#nannnnoZpYp`q(qqr rrPoWjS???????????????????? Xv!&% $V#a! c   | }     @ n        Y   w # K E & U   W     N   8        }    {   v    y e    [  y  _ X<    J g Y  &    l      "  6  )  1  2 F f l    p nw"$ #c*6JP T10Z* s5BL!KQKTkM?O6l/-&'!! Xd cP 3~0:+()N!-MM5;o))  %V^( #>FINW^gu J{  & L И Ȓ i + /  ȝ fT b E  r`3cc[dfup؏`t a ` נ n_STPgoiom[b%ed`h^*\bobfhfnsz_usl n,jRpdfm?mnmkd`XNE66[<b? AILIBCDIS\]C[XT3QPP6KIUIHGBD?B@DEFKKJHHJ?FNGFHGGFDBPBUB>9C9c69=<<a<<N;Y9:=<8766;,:k=];;47&:<:;<X<_@?K?]>;BeBHHsKDGMQcOOMXMPU^`B__f-jIlorz}> - $ ߂ `  ' U v \ ݕ Ғ ڒ ώ  ٓۏɊ  c h g ݂ % 6  z  } z c| h|  6 }  n| * b ]ɡI M @ jO ǘo ny l h LA F$$##t"U!  +, >!>#t#%9##$%=$$w%'$#%M'JE/Y}lnbnn"no!opppqZqqqrnk????????????????????????????o#'#$!!*!j^  ?   * < - X $ d 0    g   f  ) R #       *   5    ` & 9     L @ u  U      _ Y  J       .  3  U ? 81:    f   ^ N     =   D      ]  '  %    7  2 A;y@"|d$t_ q89>?FFF^CB`6W1n,G$D]g%L_8-U-3&y $i:>2% %' U, @GLtP;Zbbnz } & u U  k  %  ١ o W t ؍ v} A ] %m` b`:bktDŽ_\ßգU u  آu 3w^&UWblqKxefQab^`acgjjIjp]yZ}wnmxlunttqpkg,c1[HR7E8;RBDHMP=HBHCPZ\>[A\YW'TQuNPMMMIHH/F6FCH FM^FBMgKHJDGDDJIZK IIC,D]B@=a9[5==_@ ;;:L<E=@>;n678: ;p;998:;;<<<dA>>!>(C&GLNQJJKRdRXTOQRSX`Bhignj8inpqwx|s a c Z " " 7 ? O  U    { ى _@Z g Y C l1r ~ p p  8}U}  | B~ q|  | } z wx } ނ A ? Õ  ƅ d 6 Ԏ 6E÷ М^ ~ q Me VK &A%U$#! h!cU  !"#r"$$$:&A%P###"[#c$[&sLF2aUHdaeeeefgggh_i%i.iniig/lC????????????????????????????&'$7"*!z  k  )         u  '      l   |   d  ,       h  f     B ] m e T   %    1  / r      , 2  ` |    u I   q! g   ! V  t    l  z  ]  = 9    3 ~    M  V   -  ` he@iPXmHJX#d@s@\'v/877=<997//-+% UeaJ70_+s*; ?u $]$ 3 ~1 CYHNET_gy ,}  ؐ  : ԣ ; U ΀ v  fRc]_emu[ٛݢ h    z `hXsd;irɉnxi f=aKcce/fiRlPnmiuXxR{rupptttv?yxrhfd[RDD;?D-JMQ,OIGMTY[[[ZYWTtPRR\OP:MGMNFJIIJILGFIyI FFEI1JzKDI_IH"E-DW=~;G9C<*AA>::;=?>9669;; <>91:;k<>>]=>?IA@AA CGULP{P2QV>RSiUXYZX^ adh5mom^jntpVqm{4|b|{ rBr   V ϑ ͗ ԍ i  )  p Ё - !~ : ~ π v } } ~ 3} 2} } | { y 1w +x 2~ f ۉ פVȄ U ԏ 8Դ ȹ| } { i V {' P% %%G""9!8#####$ ###s#$n$#X#%(MF5T߂`6bbc+cd"e*eiejf)fffgig`ck????????????????????????????(%#$# fep X F $         q  I  0 w   e [  :   T         w  p 4 m   '   0    A  ^  1 | t U n       y  n   ej  A G !   * C  $  X (   l K   7    t I 1  q X  P  ]   <  ^  H?|y`9quvHc+W"!*/U01'6131310*(,#6& pt X?*'+f !#%&:*6 .g A m . 7C0JQ[4c\o7~ ~ڃ * ϝ @  = P ! c ְ y S r z aa3^``c-is&'  &  r`[_8lu,^yl&i+f5dEcah6giSlr(y |w2yG{]|v~|x} |v p n eYPF&?@GO~P1RMUM_NRTX]J]W_I^^TZX/VTkT0NNyPNOMMxILM[KIFEBEDEhJLMLNIKF-E@?#=@HiD@?W>?@3@@M934;G<=>c=<=<@@K?BBDDFFFUILPQnVYVY] [_dtikkopoMlmCmmoLyPz~|wY|SGJj ^ V ͊ ψ Q  W ђ ! o `)u!؍d $ ~ | v - 3 69fp{ z H| y ^{ y z ?v =| y hy | g Ԉ r u ( ڴ Rš L| {w i b - u%%g%#y"~!P!! _!#$$5#V%4&/&#%%$}$#d!#&NG74Q%La}cbebcd2e1eeefffqd7bd2k????????????????????????????'$##" Z;A   E g   {    O  '     X    v -L   H     q          (    *   Z  i   < l         q     "! c ") 1      s  | 6   j   N     9 a      ! E b 5 D H  +  0 sbZ@') 4s|76\ '/ .0n2M/-1,&(H#4 m ;F-&='"& %++  '$ a  . . EKT1_j:wЂ j~ | ڝ S  Ȓ z Iٕ  a { xte-_`dsf.nVr:{ ol o Ӵ - _  ay[cnwrQҋtoj6fAaa+h8fh6ktM '}V|z{|| wx n He ZTP E>:ENNSQNKPRLT>XYB\_ax`\]XXTGPPMNNMMNO@QLG7H6E?GkEFFLPP9OPMIADCDYBDcBC>B>CCB;ACB2;28P9):-<7;?@)=i<A@Q@AyB:BGCG HK;KN PRRWYY^]>]`enpisttqsvnk;l nxoBrhtv*y{׀߁oT:~ ? ]  ُ X  }q0w ݌ ߋ L ŏ r : # y & n tx = ~M  rz { w { y y u y ~ ! J   Ƒ * ծ ! m  | )x p ?c w7 %\'J%$i#""  m!$f$+#s$!$;#$"$@###)"""&L+C-jSbtc#bbcdie)eeeffe0cg"elk????????????????????????????Y's&%L&5#_"D!x k  '   U S    *    $ W t    S ]  c%  2 Z    '    J ?   g     e \  # 1 3    A   6   "    > F t  $ L    L   _   }           t         Z V  4   U    W  8c3MAq w2 1fz`>%':(*8-z,+../ 5(#l&"GB E k0%" "%%X*2(r   w  ]m 6 qF&NXblz ~ S}  b י i q : s    veb}bd9fj%ryz:oڞХ =  ] 4 ޖ RaXbpku~  qmeg&hWeg@hto,y v1݄} {~ a | %n @g ]ZWOG@GQ{PP7M!LcL!NPT2TwYWA]c@c;__\]kWSSO LNNBNTKQOLLKMMKFIHOlQSR`RiQ,MJHGKGFCDDECE>DF_EGD@=0<?(<@,=<;<z<z>@OA@BBBA BFEKPQuQ\ZVXY\a5^]halnn"ptvqqnmznnkmrosKuBu2uy{Q#CK s : / +qtr== e ʐ ʇ & ( k y d ,~ ~ G Cz | 7~ %y | wz jz } :} ?  ) N  հ \ PD  T 3t j e A 5&&%##!"!!"P$$j%$+$M$$5#'z$#""!#&LD.Qeabcjbcd"debeiefhfifhg)g`dl{????????????????????????????G'&&F%$!M   | t +        "  & m n  d  f PX  m f F h   ]   D  *   i  D   $ A (   U       b    D  ( u G   =" r !!] 2 o  ~!!      s    ; t  s    ^  *       '     k [  /` .FQ <4abp+Lh4?T_U)+B&F*(* ( A, \& %"&" :x* &" 5&m%%d< K     a -7 (FOWaKr { Հ 7~b e ̙ ʔ  E ɻ Q  v n3ab>cnhjilzsӀPɜӠs Ƴ ʲ L JeY\Pft} O x*nmhgdhhv ̅  Ȍ/VЃd[J? e~ R{ t g ZNEDKP LLeKJLgKNS5TS[*^aa_d`mb}[Y-UPON\KL)LNfLN`MMNNP KJLPVUOgLLKILKKM%J7FGHHrITHH!EA>?1>>s?6@==?X?6BnCBBCBDIEINQVVX[\XX^D_df,i\lloEr opt8nmsSollJmJnt!v7sx}p{~{{'|~ 2 TGMv9E k lj ԉ  ; 5  ~   4 7| z { | w x rv x y y <}  1~ U+ 7ь ,  ٛ Z~ 7v u j fI '&z'd%4$ !"R!? k m!##W#/%%`'0%%m#" "p"!v$Y'KC1aRrbtbccc3cdjde3eekf)f`fgig(d2jI<}~)[   !  ) h  h(;&$1%6!~ D   W  U \  *  t m /  i ^ y    ]  +  O   g n    N  b ,     \ n z u i       0   w        $  z A"5!  #!m? ^ n Q 8  #  T #  .      o  C  *          | e   q  Z [   yfEE8xoeu8bGBrqF" '{&Q))_(**. F)%;%C% )gG "%) #p J R :  |    4 3 = SIRqZ.cu '~ =  \  6 { љ ٶ Ԛ  4 sddhmijaflHp{ޅP Τ D  e\[5Wykt~uB b~]rnjkdeiz ΍ z.݄ц7 K} z Ks c YMwGJKWOKJ HHI2J]OxSUY^fcdae;b^\WTETjTWW4VTVrT=V,WWUTU9TFSEUTdTTRRaOaPSPQO"KKONI(HhGE:CDFE?;<B$C@DDGoIHwG}G1GJjI,LPZTWZYq\kZYB\B`0_mb+kq poppuAtrprv vgr~s-uwH{}߆6Ȁz|m}}~ւυLЈJ ƉHyV/ ډh k d g c  |x Iv v r u w u t s 7u vr Qz B} (  " o  \ . - z o s o X + &W&%%7#D#u#$$###% %p$&"&%#"y"""$' GN#E1.W8`a`aWabbccgcgd%cdeWebj3"54`3344^6s77Z8f89 ;o<=~;Y999+8Z668d6?54771n($%#? T   \       X   ?    4   1 5 ? o `  w uA   ^  ~ j      F  6   {  ? *  | q     G 0        G   B i d* n |  ! l    D  ! N  > N E   ,    S ?  p  .  H b      #  A  'F >1+N ,\ '&;')y*)j)&]&!$ C!K"$/A0 @ +  z r | [ B# h< L>V[ k w}" u ج S A j \ ? d L_ V * ֺ   @riedffrekszٓ Q ֫ L  f_-Wbt8{  Zxoqjgercepz { } } }"~wh | y p b 3Y#J8F)LPNLsJKMZOT=WZ[^di7kll\mk%fb_ZZ\%WTTVVVW-UuU9U S;T&QUUVuUX$XlUSRRHQP'O PPQMNZMOKKKML FAV@CEGZIKLEJI2G+IzJQKLOQUUXEWZ7YwYv\j](cnopsx|-|+zcy<d~yw { | ~| 1<O0 S   ] + \F ? 6 Ԟ ^ ]  U ^ 4 d  |~x} { v ^tv Ov u t Crm m m o px z  4 "e  0 k Z  W қ q Ԃ !t pco b 1 &|&%&#$?"'#{!!"#N$@%h$&%"W""#}""$) S'E>.bY}~YZZZYZjZ[)\j\\c\\]a]]J\j6\&_H' _ P  (#$#!!)   e   O     M t       $ z    E D  ;  f o > &! M  J j q F g c   o      : y    I    (    )  X  `    k   8 5   f  c8   i  '     b $     :      j ] D     =     5?9   TS[bp w p    #+ )*k,I1+*' 8$**=$*"M G J B !    K  >NvZcm x ^g + y H t # پ ҅sCiml~hHi hgnu3;і؜0#   ǰ yf^W]c0vfy > tlqEhcf`bi]l|nqUq(xD,*j \} d 6~ vg f[U'K>H"M>N;MNlMNRVZ]]\_cjp$m]qQnnm#gedb]]\\\cY2XVVVUR/PeQ R*R>ST;UVXX'TR&R`QQQ9P*OPPvO{OP_P=Q-RLEF~EI(KKMLHI!IJkJKUORSSUXZ9VsWX[+_enot]ty}z~Uzz{xwy x x v | ߁ '>Ř V  s ` c ڎ % ۑ  d g  } h 0  <  f S 4 ғ  ~ ~ } } | 2~ | ~ u~ d{ ts Fqom p q v y Jz H u {  a  Ղ dv xu j < =%%%$3"! m#"$#5"#$$%%<&"!##O$$& 'MEp/zXC{YdY[)YZjZ[*\)\c\\]!]Y]]b\ti]f@%#$$"L }      -  1 s  ` B     K   %   &   N '   J  p      A  E  h   0      !   6       3  `  ;    :   Y    ^!E e6  1 r *H!;     F 9         )     m  :  = k Z   <  $     & <    [ i    l 2f   1  \ &*$  j 5U   x W t n  D " g L   " %D N [ Nd q } 0[ % G  ~  b ׅ wmpgfVhPgfHhrp< fd_ b  E r F kt]X{]qyAQxpNjg&cmakqv_x%y F    N z q~ x f ^ nQ HKOP,R!O*ONRXZY`chkHr_prKt t]pmhacc` `abSb`][0[ZWiQOeQ-RmTTtVwVXX;W\RRSQSSRQS(R_QPQRmSMGBGGKMVL?M - e  D  C   ?  B    : 0    J6 7   2* D #fb g I!^ 2  L  9  9  5      t" FR \ g u  k ݇,    6  /  P  xnnejk0jlmkympiͣ ´  ۡ m^ZS^mQy" |~rki$dekx| Ć  v 1  8  k ^ ~PITNN MN5N/PSQVX^^f?ikkq^r w xy{ x!toj5h feeeffeca^]\d^XU*SVvVWVX>XVUoTXVpVVU*VVVOWU R\QbUMRHGAJLKLMMKLNPMNORARY1V$TV|YXxXZ0_)djnu{w{}xxy y zz }5 / ~ ؑ Lʒ g<u J= ; ْ ^ W   v 3 ԛ & [ ˟ Π g u ڍ ˉ \ " 7 ۆ d  ȉ ֈ Ą ;  C} } ?  X  3 Z f E ~ Cv /p fp jM ({%$$" "R!#!!M  !; #A"#T#C$"##m"e#&PB4^V|XY,ZZ"ZrZ[*\+\]!]]]^)^\2jme]_^f]tJQ%#!!<  Z  )  5    W  # h    &  R  z    O  X   >  0 &       5         Q   M   S j  }  Z X g  I V      V  .   z !T *j!\   m  X   7  .   <  G ! <   N  R ' m     N <  >  ! m   G    )     #    .  7R   9  M 4 G \    k 6 S%    q   #@ N 1    ^g |  ` j   w N( rL[b k K{ a  N @  , X ` Ĝ ] |#r.niii{i}gjvjo}ǟ="ѭ  d # y ;q^\]Lt~u+Z vFpkne1fkx  H : q  X x~ шr sa j[IPNnQN}LIKEMS:Z][`agGkoSpuuvvz~zWqo=o8nio'km^nki *~ h גݛ` YQ j Y $\  t{yu!r ] z+ F$y$#"!! !#9 !" "!"!#",$6%o"%B*ARMC/TIY+Y+[*Z+ZrZ["[\] ]]]]]\i^gf^f_`_EIJ"a"?"T#w 6       :  C S R  "     5  s   ? %      = r : V     K Y N r  R  -     8  z {        )  9    $    ~ !#!!Y /  Q      f    ? F  ^ x U &    y   e 5  z   @     Z  A  ?  /  4   <     h {   U Z  6       :  `      b]    ek .N [ Hq ;    '  % |bu "D+ 8M Z d q ^{ 98 I f   S E _Ԙt  h Q v $ urovk8fhxj3il|̙0b 6 s zj`]S[m4U 6wFrq_mknFwJ~ r #  9 ū 2 1 V} }Gl C_sXQQoPP6OhMKPU\]adgl p^pHszt{wz|~ymz)r1oljm,k1nsocrsoo-ljeGb`_`^^^YZY~]/`.`*b`[]_s`&_\8]\$XTgV%[LU(OPQRySuTRQPQGS9TX[&Z1Z4UZeZ\YZ^_dhEnqmwyvxxOzswQvw uZxAz q|  Y  \ ^ $4t@h p + 2 , f a S W 1 Ԙ ? ɑ ` : "~ cy { u o l 7 ` | w v w Mx z z ?} m V c ` - (  e  X. 2 v nr d K6 O%|%y#e!!y!L!! ! b [!"#"!"!#d##% (OC6Q̀"YzY;ZZqZaZ[)[\]!]]]]]\zkuEe^^ffnmtxp?6"#%"    s ? \ h    - | ~  |   ! G k  1  q     ?   $  U :   z    w T   D    "  G  -    b r  o 4  c   < ~ ^  +!c!s i!D n $ t / ^ &      n  f  * n Q    5    S  f }  ! u        j  D     G    E m   A       ; >  T  ,   | 85 9   A    ^ - " c 3 O) M [ f or~   Ĵ D N u n ɝ ܤ _ 4 ؄ tbr,rkhlgl"iCp}&W Ԭ 3 1 4 - ya[[hFy+Aמ <  \}xrqHr?p8x` | q  \  ~  w 5d )^UKLPNM KGKuOV=Y\]bpadjm#ptSwx}X}"z!vvpxqoqo%osRssutWvx;rkhh;eAcUab\\WX_da]^ta4]_b\dc]Y{T[$]ZS ORRVW$VTgSSVZWY[Y|Z[\\\e^ ]%]\5ghlsi{{yHxz| }~>w&wz| aZ[  M Y Q c12   _  % $  O ߚ H < 4  R ~ ~ ~ ~ ' ~ ~ n| { z $y w v r Mw |w }y v z | ={ > ֚ : E ]_U% e y r m f @ k%%N"\""y"#"? !{"#f%o"!!###j$) N"C,,R4{UU-VtVVWtWX4Y5Y-Z4YYZ=YYxk[k".#e$%>%&%J! !%~$!J  p    = u R  ~  M     `   } E    I   4   @        / W  8      f s l A  ,  7   r  i u   b  &    C Q :}cJv Vzip5  q  u  |      s 0      > ! l   d        +      p ]  o    e      X @  {   o } ^     # "      C0  U      r3     Yn +  2 T_ 6k w Ӗ ̣ "  /   x A  ڄ N r>qilkmkk5j#lz`P  õ ' : \c ]\_nx4ǡ < %{z!r]ppDprw ` H c i   σ RGm _[ TyM$P"MJFJIKmQ}W.YZ^\^egj&rruw!}ZR}yvxqq7qmpaqqetvNtzz{y tool>fQ^\YW[[`a@a`^F]_lamdZeb[6Z)^`_J\ZUVXYrXsY3XfXXzVZwWGZ{[j\,ZXZ2[Z\agnq w1zJ{Jx9v{{|wv~Ԃ 33nY P ) !( H Q  . %i j  & Z   Y  w 6 * , r N J | T ' ؀ ~ ~ Z} ~ m z~ | [| m} ?y w s p r Qu z ?v Iy  q - O[ ), L 6   Ыa { ru ;q m J I'|$##!"7# !!!h^`""##"i"b# #e#"#' ObC1TyYOOzQRQR 4       x*: {     F      D  hJ   u P 6-OXm >Xd \q >y  &   \I =     N گ O ) = \Ppnmzo(mnndlnvҕs 5 ' c[_ygMzwE y |uuwurCtwH  5 ج  ' ڍ Ձ Y ee *\YRL?MJFGDK4LjKuPUZ\P_aehkqux{D}R|xs1pnottw{0{|C}}D}}vok{c[t^b__b^a]_ae`c"b[G[aaa]XXQWUZ\[-Z\&\ZYWHYx]\nZXYY8]ab]hBlstWyU}||yI{|yzK{z}Ud  W ӛ  ' i ی 5 y j e n _  ˍ A S  J ې I  B Y !  (  z y{ /| s} t{ y v r s t Nv v | ~ ’ Q & Q  3YX ΂ .x |t Bo j W ) &"!!"!!q?!"#+"""r#e"#$' fORD2sQ{]PKPQ|QQ QKQR{RSS{S|S;SKSSkC X fUvE}gWGp DAGf/+d 2$",   B       +   Z 8     !  J  <      L M  O   }    K   7  8   G f     b N     $    }        ,  v  , 9  T    h   .           _   w   \ S m  +  h !  d     r  E V R 7 f e k  "   e         ) , j r c    ` e TO  e= +   >  0$ aI~     t gA0   D^ g t ~ S   Σ m < Y W # = t L 9 `&nnloipsFqmmvx  ϐ(j ܩ   ; Ϛ f\\J^dw v X _ H}xxvrqy q ƫ ͦ V ns t\YXRDLJM]M;OhLO#RVwZ\ _bfilpsw{y=H}xwtuxxxx N| w;?w~~}vlrnhgd bc`{_dfghfgRda^b_edfc\u[_[\\w[][\[`XZ\[],][]^febhm/ortz|wy wyz wvizc K U ِ T ^  0 0 ǁp i | 9 " 1 ْ ' – ; k ͗ ы S  ف  | { { y | }} z y =y y x w Mz G  ɡ a eٜ h ( D]'  #w pt p Tm uZ0 Q&C#! "n!!!B5t>{ Y!!"$>$ $ "#( PD3V|PPQKQPQTQR RLRSLRSSS  n  L  H  9 G    x 9   e  5   0  \ g etmx  y c !$5 ;  R  @  $ "!    I    <    - h                   2 %  3 O /   \   [ T  O S @    !   6 \ 3   M (  o ;fN  E O    13   W b  F D:\" I _ g | Ј T z ͢ D ܭ Τ - . q  ڦ T t & Ή ~ . z:osnp+rq2sJqnqou| ѓ2  m Q ڮ g]a5fg} ҇ O eA|uRy~wrprb v ͜ A  M s z e ZZLVoO(PO-LLPdOPSVZ[`^cdhDmeovy.yP †M ~~@|Kzz z}|ā n} ~>3}z{Jx&stysoh&ghp qmld$_achhfd#ar^a%]ZY^_X`__[\^![:]3]addin+njryzIxJ{vw{yw'y< vd Θ [  i Z { c / oh  e ; ~ t q + X ، " c 3 + t C ƙ q m ; ׏ 3 Q Ձ  m} y} y Oz ~ 8} 7z qz z Nz { : ׎ эn  ۣ ӥ `%  y s n k ] U8 D( %!!#"* ?z;C$I"D#2"#h#" :#.( _N1D4Q}UPPTQQPPQQRRRRRSST jUmR [I "2k~C`:  !&:!M V     k / = !  Y j .   9   K        U  ] a r  n  _  ;     x  /   1 K y }    t % ? w    J     ~           !,  ) ^ \            t  C   t I c O  o =  G     s J   > `   ]     t  =       5  g  P  $     a j      4   J  h ~eV      E  5cP  y # ?  :q  vL3bk{0 ^ " * կ Υ k Y W W  7 y:qqwnxZxuq^p]s~g א"1 ֪ - w Tg_^Qky r z{NuNvm } u ! X{ zap ZUXZV&SRNzO7N1PPOnT~S\^`Y`ehnmry}OTfƍ8 . c Ez|zyy qI|; n9}}~W{}|"}tpvuqniXhc#dVel4ki:gEd&dUa._2]^^ ^l^^a^]\3bT_febSdejlp)rv{|UyRxv$vy|;~(~ u + ޑ ј > v N _j % ѓ  &  Z v v o Z  ܔ s ي ؎  t k c  B u ΍  + $ d h r} ~ ~  sx | s{ z x ~  ω p   _ a t R Uͣ P  3v Dt [i ] < |$H$!!,","x!R M! #  "!!"z#}! ", 7PXB81uT{P OQDQ{PPQ{QQRRRRS S Si! ]f{  F  %     N  _ 1 + s : ,  O &< )  d o 1      S    { =  : <   o @  q ' $ 9 ?  w r      Y  5 w P  b F      S   :  -    f  n  O    T E   w | n  i) -"  ! O    I F  z '   Q     p b   -   * Z   V     -     ~ [   . *   E   . r     /!x u d  8                +      # Y   qI*  \   # 4  P d6l z] _ V S d ] ( { m e j Gt  wvxSx+{w}wsprQяb w ݫ O 3 t $  TiP_`@i|„ ! 9 y{KxuqZoم [ t  ; ! |  a WuXeVTM>KMNpM,OcRS7UV[^^a\efImq]vzЀV  m  # w g q b @x}}C}}M|_}}-~X~WXzxoy_u2pGlilkn1kjhNdccfdc^p\p]___^$^__(cdfGhkdmjr!r%uy{E}Byuw{[NK3Y y 7 ږ # T  - g! ! , ڏ _ " ܍ V z s Ƣ  V  ؆ f ' 0 E : ~ 4  ~ j{ x u } {} A}Zً 4  ؞ rj ;n  z /  Z Ơ  K | vI{ m+_ 9 %t&^#"!r!]t+\ 1~ "#!"%K, WPB-S zP OPQPBPQ QDQR{R{RSSCSKSj  h  :_}t  /  D X - s n 3 KC ^ $y`   J   O  2 v }      1 !   F    B z   (   T   o  B #         9    d            J  ;    b 2 7 I /  ) { G@  !qW C:  W  k     \ R     E  e         :       &  O * 5    H   {  7       * 3 H     f    n K  T   e   Y    J   T w   (   z R   " x cw s?v  R *an{ L ̤ Ϋ  o Q g } ;  <ǚ t ) wfvxOy}}xAtas+tyz  l K q |  "Bl{aakzŋ '  ֢ <>>~7| yp;o W 1  _} ~ύZn vZVXo[VQLQPUP%MtO`QRS/UY__a_3ceeglrvx~Vi l  q o % a~  m}~||KJ}y}=~f~{gyvtqr = 7} :{Hz ?y x y T} L 4 i| ޓ!bƗ̢ Y M h ޝ q A ~ |Dvn &` [ / -$"| !|!" ! VM  """"%~, BQF`1YP vFOFGGGGNGWGHHIII?I@IVLj l | RR    7;  H      $#UR|  f    [  l  5    C  A    J )    ?  k  ?     ,  O   0   x     " 0     U i S     .  _ m U ^    L     &  *     _C p     3  X    o      J  z  &  -  "  }         _ e  4@    c       6! !  !     O   /   S  @ B   G g   "  "*!P / q       _ J -   H  m S  2"  % P e`rU5 8 h ޥ g  I    F ϩ R E # $  œ d}p}z y$xx"tYru~ΈojD  | 6 uab] . T _vsw ԥ   ݂ a 7YpX^\zSP\OQ^RP`PTRXWO^_Y`bTde[jxnnuz~ЄK:8@ g ڑ ^   ) ~ ;} || | t * x| {|zwwyLz|{|}a{jxmyj}zxx~}́GMF|uq&fgiddjci`ac5d(hidiBh=enkvs|risw|8|\}|~ ~ ·j  W ڔ  .q ~i d ߋ ډ 1 f ܑ / א E ^ В    ֒ [ $ / Ö Q ׏ _  s ) > s } ~ ~ V |{Qz N{y m R T ߜ ' Ξ ߤ ɟ h x  H J y [ {y xe b ; A$}"!"5!!h( 6:A"!f!x""+ QFg/lR$vEEGGFFGHGHHHHHIHLj   $ q  { `h 2 4    {    S f s   | T #!^  S    7   A  ]  B   \    ) 5 y D    Nj  K a        ^ r a    1   `  V @      `      _  M x           M 9   o Y }( '      S   6        + V  q    e c {  %  ] 1 \  V         b   " ! 9" X   '!  4 # 6   x Z  %  K ! 8 !H#!  Z!  e _   p     U!     w  " )!    4$ & sK gYs{ޕ[ = ƞ c s C ] S U L { / ۟ !  {{A{)xzkrru}ԛ ϫ 2 l Έ &cha4\zÇ@ ж v $׋36z|} e ; Q. w q 8ZWY`[ZTN&KIPQ\O}RSeWZZ_acchjjBpu\z~ ;r @  Ȇ /}|{yz} Ă e jx x wtwytx{M};}Dف}+}|&~~- dp xmh^ghhfcyb<`rb]cdhChigknqOp5qwOx~N}}~}!  8 d cy 3     ْ R Ö ʙ  Q t L 5 Ŗ ɕ Г ' Ҏ  ' 5 j ' _ = z 5}f~} Dz :y {Qy { Ē Cԣ\   p q є /[u1c ^[ @K ^# #""k"$! 3f c!u "!'!" * ]LE2^O)wEEGGFFG_GGHHfHHHHLiS s  ;  9  h "H    d =   0 , ; #"  (y     1 u  c b   n C  ~     P R  k $     P  5  c  N    ) u C n        r 4  ,         : F b  t Q    t    * m ]  ] ^  G!      k %   p O /  S  z   S  `  a /  C  " 1          c y   o   H"  ~    ' %  !   j s "  !  ?   R!%f#"T ,!"kza R!n  M     G W  + ]   # I  U   $ |(Ig tą7ė { 0 T ˟ b +x y Ʈ " H ~G.QY|*xw\rvD|-]ݢӦp H ˬ d`=ZsS z X Ŝ ˌރl{Vi B > d c Xc pYkYn^T[VpRL1NPQKQPRSTZ^-]`k_dRgimssZ|Nʅ-Ԏp  ӌ [ ' t~@xsu t| . j | ix x ?wBx y Vty~ vzrD~ }; < Ֆ q w o_juilLgkIc(coehi,fhgejmj`]pD> ;|| @ 3  [TYi\WaZkRP^L:KOP]QQPQQdXIZ_^]aipsxMz͆ d B ɐ p}xGvYst|h } kw zz8xtwx{ 4{ s * ƒ9 : * e  z opljkUjlxi:djhSk|kkkiRlo opuqxj}@U"~R|X+q6 e W aa &7u ga k 1  Y !|@ S  ő  ę = X   [ Q i ̗  ۆ _  ȇ c i . e b ۅ m h } { z x ~ x } K W 7 ' f # ' & g v ΃ ~w pf^ \ 6 /"x"!"~"  AU!^!!="Y y, QmD-1PKuuEEGHFFGUGGH^HHVHOHHLj   <Z' -  Vv v * 2c  G (C   w   V  &$$ V         X    X    =   0   `   Q L F H   |    K ' e T  C   ? u     7     N       r        U     c   5z  5  +  M  e  p Q    Y  :  @    j   p 0 c | y h  A        P   > 3  D y   / n    Y  "   z \  % N     '      X ,R !^`  /X  d %  .   { '" * ]! [        $ |(-Fmz  4 p c " k  [ ¦ ͩ Ϧ E  7}7فzwss,t({Dty ˲  v Ω or0bl]=j, Տ  q͂ 3   u [Y)^J[WxQ.N.O0MPPdPPQQuPSyY]^`]ejFmfs{}7Jzىߒ  T ي b~xs[spv~ { dytYuGvu u } z |  q(s~\уMJ x a $  # okkl4m:km5gihfgik kilOq2qtyvl|}}z}34   dg69 |:  " ӑ ѐ Y ӏ ݏ   ͓ ԓ  # P ] W   b ܃ ف * ?{ { | ~ i m| ~ | y y F{ b /S ܒ  +  ݴ .  tniw` u^ A "]!( !l! N2H %!R X!" ( PeD65bTduqEEFGFFGVGGHHH_H^HHLg r @ m  D0 5   d  in   }   D S | &3$!    S  e   /  - Q    r u m  H    i d    _ $  |  ; l    x       ( ]   = W  :   ^ - ~ q  0   & 9             w  6  U+   &  [  W ^ P  6 D   0   [         !Q ^    c ` 5  u $h * t!T   ~ }  ,  8   V b! >!  Y ^! ! z# ;  6  # Y    $  F! %"!1%"68  x   G! X  ~ ^ .     =  -  }  " ( }/ GoQ{DH ' { ؤ 6 }  ʲ ة 2 z I 9 \  m}H @}NC}xuhuv{ ZҪ˫  S b_whX 0  A avJjۚ ܦ Qg 1[6\_VBRONoMyPJPROPQBQU[8^bdSe{gp.tz ~n y Ҋ ߃ }xtrsvJ~ c j{ wwxxDxzzxz ~} d u}{}S n P  @ ߛ / $sHqbmFjl8gj[h`ggih*i+fgNfhmqHr vhxP|8|b \  )8q+ ڏ` ' Z  Џ  ٍ Ҍ n C Q _ Y { k 6 J \ V   $ & { | { { 0y t ~ J { J{P  \O y М X M & ' [   u/nkE` |] I 6##4"5!/ * ! 7  !N""J % . PF5U/u+AOA ABB AABBCBCCLCCKI j ` A U e  5 t 4 <= > : (  ?  ~ s +$[$% .   q   U  u      O    4 \  q   r n \ ] *" { *     k  U     $   X   w     = : %  &  , 4   i        L E   p "!  S y F  >  l       7 x   &       9 X , ?       u  T D Uh D "    @  m  ;     *! !"   # ! ! V" f ~   W  !   E "$"#%0 C E   q     q l  !    7 2   `  K$ :&"0 "P 2t }~ Ƙ r ݱ ܩ v 1 ' ( A m  Xz#|zwvwV|d'~%y  ջ   m  N d^a{ $ a  q I+ n ӫ  b| [rWaR`SOjN9N0NmM/MmSPNNSoQTY[?]a`dIgjsy~sƌ W N ~ Ə Ԋ ށ|wutQvD~ 1~  y w { | d{ #} yH} n @˄(  ޠ ءV umm}nmQlJhlgzjikh i^fXl3n0m`psBshy{~ X}}Lj4 [ .#vH 5 .je b Gh & W ː ͒  Q u - m + i $  ȋ ݆ Ђ  J w / 2 l| x y P| x hz xZy _  R ߒ ʥ خ w޹  ݳ .  Z 2wpjbC_ Q $$!E)!%" W_ W!! "#- MPG1Swq<>>>??>>??@V??@@@H>i   < z m  t  V  d  }   &   H   !i!#  ;      V  < e   b 1   5  *      z " $     I   $    Q  V  3    n  g   ( M   T G V   [  p 0  #     @    T W 3 >     >   .     1 ]    f  b      p  x     h  +   0 r 7    p   & " r  ?    Q   M      ?       8" l" r!  #  e!      ""d" ql !A! {$R"!  U B !     ! -   >  "  g# .! $ +3W u8}ҔA ! g 3 c H ] a " g ݇ l ߎ „B|,L>{yHww7yx{ t % ^ [ ? 9  E oea;ap  ѿ x `NKݏ 5 n4c&Z;Y_T^&PxP*L(KJMiRLONfNMKPDOBTX`a#ceHh2kkqv i 1 & o|BwtWv|; d { z |  { w z 7} և ]   ~: " ߔ 'cM ! u ljl ikifihfjmi*hmmsmpHu0x}z f ۃ 0ÃL/"tm o  =5z ^ )(J ڊ  " h  d 1 f m ֓ Q _ ] +   * } / $ Y  ~ ~ Wz -w z~   tY\ h \ . Yz ^ tsqjeJ` Z ' %J"bo A!k!# r!  #*- ~PE 4HSHoA>X=>??>>?'?_@O@??@@WGFj 5 !W < y~  2 A > n5 F  ] ' !% K#! Z c 1 o +  u  K  . Z   h  ~ I    .  r      3  2   j      o     >   u      G  h   !  ` m    H f  ,   h D Q     ; Q O V + \   t 8 ? v  Z  ] y A      f    <  c  r  P U    I G ]   & )   !H c    @ B  F      w B  W  ?  m" F!  3! ## :! ! . ^  [ C#"!   !"3 N   " O *  "   !`  %! m   <   3# # ~' )_1 \] y v w \ 7  l  P O N Ѵ b   EȀ  т {ą*zyvzTzzyìn k  " R   fabg΂ 1 Ȫ [ .\T ҆fdl\E[]W`VO>NM,LLsOO#OaOO8RQnRrVV\aa)eOjwlov{5ؐ  I J ك } vux|} } ~ | '} k  _} | { y x| & ]  ʅ i d ^ I 6ф u fpfikijhf5dighmkmmnptrtu { y0H 6DȇA:r-(s<C   4 ڎ l n " , 0 ڗ  d i W  Ɂ ق ؃ ^~ *} y~ ~ A| J n ' j} | \~ j~!| V{~ M ߓZ U  ݬ ض T X m [  +xrkfNa _ G1 }%##}7T$ ?& 6!g!!!` !#`, %ND1YR m>P>>??W>??f?@^@W>?@ @GGj{^ %     K I ^V _   g"!= | .      i  I   0    2   Q  Y J   Q  O K _    9  '   4 K O   y     M  ?   E   N     =   j        H  | M  \ x w    E         l   b       u     , + p   q ( J "!     2  J  v  ! z   H  N    O    r s    S l    ! \!   # R! # r"  O    $-"<  _  !A  J  l  !  <  ! L# E  U  q  (# 7   ' t,:3 a |>FԖ =   K S  o |k ڊ  x|wfuw{PMzBj \  < y hcadz  ؾ 0 ǰ ͦ X _. ч o ^\~[b_PKMUMIMLLLDNOPRRVPRX `@achhhoxz{z͂ , ' ( 3 Ɏ 5  |;ww} n % % ( e } ~ ~ .| ~ % p  j Y  ӏ k ֝ \_ %q /h`jkllf+gdfgpiefRkoipkss6ousbx } = v s =  ojֈ 1̈3}Cs f * DJ / / % ] ݖ  Ȝ 5 *  { ¡ w 5  ; G  l -~   =z ~ Ѓ  Ny]z | y 4y zK u  3 f M 3 ΔR ˚ , c J Nd ʐ  ysl h` , LDn1-Yp>Y>Z?X>?V>>??@@?P?@H@G@j 2XHJi'%aH-zsg^`[  ? b   !     u   G ` A   ` % f     x   % x Z q   ]  O =  b  ' Z  *      % ^ /    k 1 A   D  U q ' y i x q   [    0 n  ; f!  J S \  :  % 7       B    C *  = 4 g  4   e *  F *  [ U   y "     1  t G  V  r /   L   I   '     !  <  ! !  .  g ! l! 3!  "#  U#! ` v ! H      ` # .  <" ! v" " V# " 'V.5 c | - r V Q E ׵ " P N h  е yf m   >xny:zutwOT١I׺ k   T A  lvc8cg{ + \ m Ť ' ΋ ˇ wv Qjx^u[p]d<[O0LKRMKnM'ON{NPOPPQORV[abeimUqt O{m|j) s d # r r { ӄ + ~ ۆ: _ ~ ~ i ۅ  M S N ) J x  U P  # v lihm[k_h]fZgNiJjihfjekotsu|t4s +s ox ~ 4 n o| ȇʊw‰Ey 7 z: >* 3 # [ X e d ˖ 5    t % n Ι   1 ~   D r   ؀ / ~ o b ,{ z Wz z {} ֓ K v! ̘ k i PTH h N ԃ mzQucoj_ b+C D#%_"!MR R" e |   ""S$/ O$F_2Ws!?>>?H???&??@@@@@@Hjxu%o|v@58|6!"*]!M !  N  : l [  9 @   n     @ T  | '  y -    v    U 8   { <    r  $  &  F U  t   o V  9  r   /   = O  " k   7 ? "9! y A =  N   B 5  y = J  A   8  h  ! 5 Z E   (  c  W   ]   w W  " ?  ]      D  b  N  e  R  +  e   S   e" " !  ! *$     !-!%/  ! ""   -! X E     G    > z     "! #" &/Q8 h  ף )  ߢ e ۷ ¹ Ѵ  3~*~ Oz Wvcy}[/z$v8w~߄ߓ\ Sг  ?qcdifQre * ɪ ) . $ ww Lj _\_d UWPNK*N_M.LKNNcPQ}SQPVRJX-^bcefkhptTuJ}{ 7  $ dΣ ̛ ޘ + ̈ T   Z  ׀ a  L ,  H  6 i c  k ҧ  B S ӟ Ys nsnk,kcigfhijmLopqOpPnr0vprss} | ق ʃjkws }  p w ߔ ] ܖ Y c b ^ ; 2  P . Җ Ԛ t I ʈ _ b~ a 0| }  ~ ~ { 8y Qz Nw u | ~  $ ޜ 3$ U q    А  E{vp5l_Y^J }$%F! !5}" " x#F"3![ !$. M@1 Up=><> >C>>E>>>?{?D>???Gitf^V]o^""*  v   = X j    L 9       z   R  +   W  1  ( w  u    B      h    [    J   R a W  e     + r R s a b t   R   0 +   8! ;        q T    1  <  [  Z 4       3 ) , &  d  9 t   & g  w    !X  Y i n     ? J  Y h n  Q   w ,$ " # # # ! ! = p q  "l"' f")% # $ !`   7        k  p" f"! n""#j#(8m z  ̡ ǥ E Ƿ < ψse 3 Y { vvw}-{lyxy|`z. j 4 > '  U u^d@c9ej  s b ( ߒ : = ru g ~]+[be SVLkLKtLMsM-N0PRP*P-QQRKT*W0]_TafhkqSuxy~< / # z t  p . 4 l ̈ ˉ   j ց  s F "  Õ  r 9 + b  u kl ihWlhWg9gff"ln9oDqoqKoUputyw.v|Hx 9X̅q /`zb0 m f  ݖ ' & 2 s ' ߕ   ʗ  p     ۄ {   ) ~  j u~ } | | w u { F f k  ٖ / J ո I Ræ a ` 0~ IwnxldcJS '%E%"N!Q  39"$ >!&""b"9"D$`- MB~3&Xk|66V677_7778!888W89?9Bifm_Xt~ B N"$!o p     a     1   \  >    '  y  K   7  J     A     v ]  y > 2       h 1 $   I       Z Y   Q  2 h 1p 3 w )h!  j  V 7 u  z    j "     p  C    [     " !  1  h   " l  S  4        V    H  ?     _   p  @ !  !   U   +    " J%!#   I   x s    7 }    G! !h "$""(@ u xݙ W & ~ Ǥ ?   ٱ ^ l z9*_ { ~ ~x(ux{*{"zyyφ%( Ż 2 z ` v _ y]erbgj=}  ϧ   k | Ns g_`h b RLLYN;K=LtNQPPSQlOQTxS U:V_aaeigmeq uw | c   + h ؚ h o D d y a ~ | { | p [ X { ڙ '  : Ř * ] 2  | j\jTjjj } } } ~ p 7~ :} `~ ~  } ~ U{|~ ) g ώ  ӝ 'S _ i m 4 _UF L wp@kfc[3 % ## iz ,I!D!  !!"""$N/ O@f-oV^j66 6777788P9 88889BGi~mmf]evf_re^e^\]]GVUW !!!p=q* U Z Z  X    x N @ N    D   M k \  h     ' j  k    c e 4      6    g  ; $  l  {o& = K 9 d K c *  | 2. t   n     y } w   w l   | b     | g      -   8          %   J 1   D 4 '   2  l   E   & < u     !   ! ! ( I . 2  z  "" 5 $!  ] `    w" #m" $     n   g z  ~ !k  _! !$# M" " 5) nF y ӛSg =  ) r ż ɾ E Z .Ȟo*9 < u %~ ywwa|hr y|1 I t Y l Y h h} ec3dfl5u  d \ ` t N .s faai ?\dSPLNeMJMKGOtPSERWT8RUTyX Ze_^aJd4dtgjvnu t z 4 ό g ʌ  đ p O p s ȑ < } x{ jx l| o| 0~ | ^ ו D ̗ / q 2 U ħ  ~ p&ihKiohlfg gjmi7i\nLpssuty}/~ > 4 ޅ8 fbbn0 6 % ڏ1j T &y % $ X { f  W  T t ) 0 0~ )z { x : + ~ }  } ~  } x | w ې ՗ *    t  Y [ ǰ  Ywrki dC] n>%v#t! jF x":##%$"#i"$%>0 !PA/gVLh6R67 767@78O8988E889HBikFE   Z :     0  o (!!# W   7     z _ T   E   ( 5     E M  " _ *   m ;  e P   \ [   w ! d j 8      O 3   v P w  {   g     ]       Q  t y l y! 9 :     q n   $  W    f    y u    9 H I  !  ?  V     4      h '    M       *    F  I!  y     $ ' " !     " X! z #   "}! %    1   >  X B   x ",   $ # G#% + DL } .ږ ͤ ݡ ɧ õ  ٷ  |tKI }Fwv_wtz}sÓ+ʮ L    | hce)bhFo{  K ,  8 ̙ f K  sf|bc g !VSuPNLLM/I_MNN;PRPS=RV2\UZ`aacek'mr9u y % w k ҆ ؇ V ӓ x ւ  { z ~wz iw t{ <} e z Ξ N  } q a J E ځ Oqgi+idi-muhjQi8glmmomsyrVuftx|~  s =݈Y122sxI{$-ِ U K4* & ܑ g t e 4 ͖  ֖ R 1  1 đ s|~ D{ Y}{ ւ w : ,z R 7~ { ~  } | | { π l  u Ř( %Y 3 t ` ة   [ g  zqzkhfN_(G $" !  2$ j%#Y%B!!E"$&1 OZB1UgO6R666677W88?9x8W8F889Bi'6P74Mg o##$   r 7  J j g r        "   Y           a    A g 2    # t R  ?   *    P  u b    G } :  m     ~ h   A H#I  2xQ#U      z  0  ;  / +  ,         { n  1    O   ,      8 L  j        ; h S  M       ! ;" # " c$ " V# #   !   " "  #  v  $  4  U e!   n l!  0   ;  F    !q! $ w! # , M e )60 # d  [ d u q Ԟ VCv   Y utx%}0v p - Ѹ  ~ jdCcejp5 Ѝ i h - Ǡ ь 7 ڈ O tPgcAf fbRQQN%LMqJLL-L0OdSLTSSUW\]_ddPe_ghos v {x j :   ! f + 4 u P t  х  x u v y jx r| k~ j  = Η %  @ ެ ì Ҧ ߪ L  `pfNj1hjikWge(hVi_oqloWq@u3v vx{q~)~ ԁ P3:~Wp}z;l \ [ I  H E { X l ٤ 3 < D * W  ˅ u ~ } 5~ | D{ ׁ + q 9~ y ~ ~  | ȁ 7~ { ~ |   A ܡ b p 9 \ d ת ް ʪ R  zpkgjgjbS$ !<?t#8! ) !L!$, !_"$1 OG.Rg66Q67P667O8 898^889P9BiJno|ArtfnmJLsIBee^]AB}DF{D! ## h  q ~ 6     r    Z -     # /  +   B  l  $      _    p   - }       =  1  t  4 m   i   (         <   !  `"6    %    Q    H       {     e    D z  o     <  |        Z     u   L   3! z i 7   I!  # # ! !! "! Z" (    " ! {" x !^[$ " ] w   }   6     G  #  ! " " C$/ T  d W * +    ס | ^ g P@Ȏ>O  vvy`؃ڐi0 d  l ݷ R X QhecfWq= ت @  N ʏ 1 Z Є s h h kh ac ?VES MMLNLmKuMlOMOSQSS9SBXf]c)`fgijik p0s uy Ʉ . . ӌ ˒ 7 ۏ Ӈ  ԁ } p{ nx ?u r sr tu v zz  + ` m  y o   M~ r%khj>l5liOgeh+gmutnqrqBuy}b ҆ ~TNCՂ njU“9HJ g ۔   j 6 < ̔ x p W  ڌ |z{Rz}yd   V} OJ ~ } } | | Lz }  B P ҙ /  g N 4 Ұ ۯ _/ X | rlgb`Z#- !{  f#I""R! "#2 JQZF51 Tg667_76778@89G88999Bj lDsdk{u|mtedn_mJ"u{l}uuY$$#)    N  j 9 g   +    I    y f    r    ) q & . 5    0    \ h  l K H  y   I 5 :  -  :   / g  ^ 8     k  l 2 Y     ^ G[   E  +    f     ^  u l s o e ?   A   P          P  e   K  @  " >    "  J f   $   K   " "    J  s! q! !   M  k "  s ;     u     P  !   | x!    #  t# # J) A[ [  c U أ ˝  ^ d ʬ ׭ s G ,= =_  K #|y~q"0Lh^<6 w #  h ] ϫ Ģ  |fdicc"to R J S h L  s m j lh =e:UT OM*OTN&LM{O^P]OXPQ N#QRUY^J`adfhkjZo p Orrs iw3{ h % 4 7 ߒ : 5 L ށ T{ qy s Eu 3v (s w 2w n| * ͋ z   ` { O q , *  * ] S ) i~ nmlnhkmmhdRi6ljlrvrrCpsx={,~ЃʅAN:w8WςK[ZW,"y*$ ޛ K y v l 5  Q  j = Ռ a % >  Dž x |L}|~V}ˀ~} } D}c~ | z R| z{ ^{ O i * P ^ ї ? R 5  ԣ Ǩ S ӯ  4  o~ Itpi flbYY6 # P o    $G# {!$]/ OA/Ui}4455~5E55667667>77AiAre_ue}tD}}Do^]m{ {dfvEtF!"#  /  J      :  J  p      / Y U  m     2 2 6   @  I     - N          < X uG  ( R    7   n  E x   _  M s  6  I R"r!!!    6     K    h   m )   w j =     Z     G ~   0        i         \    h  " >   ! # 6"  C    z  _  W } #   !    O    U  ! ; 9 !         " # # ! ! $ && X u % o ^ W p  Ѱ x j܆+ƁI x o ES1G A ^ 0 ^ r %  ޠ Р  geUd(c[gDun V + l X Ȏ 0 Wu p ^i f rd 7VzR$ONK~KOZM&PNN[MPQZUT [ _`_cegcln ss Dq ;x|~ 2 6 # S B W $  I Z v t vq t zu v xx  [  _ i ҙ . + & ! h / t Ӥ Ӛ ݔ ~ {q1oHln3lqplf|j9iGnOiknrtGq swxy $}YP̓ȆA4Ć΂=Ɖ+lh [ ^ ٘ r ͞ n ͝ /      @| z y{XzH} ~ q{t~}]}z}Ձ  |~ Wz | |     J j ۛ B b( m  ޞ ! %` p ф >x rp ksjh^ D t"e"K! w w K {!!!J #G$Q3 }MA4-Zf.}.0/r///0!01(00211= ite}{tdmmuBBtvEfe m^gtfn\ ! "b!G    :    `  F      b     i   q x  & B     q @   + A  -   r  2 .  6  ?          v       q  O k 0  G z   8 ! "<tK I  C o _  h #   L  d k 3  <   n   )   e    >   q   !  x    >   m Q    R   ;   S    R B 7 !  ,  8% &  t" " u        # ! ! o"0   <   /  #   ,!  j E A (   5 # " "   % * '] *f E &  ¤ E j n + k |A {ǂ   "6n +&Z R   ( ^  P ٝ X Q Rddhdevш Y ء I  ޕ ) Vz do h d u_V@QgOcN(NFLtKN$OOXPOQUonqqq uyy}f@KŠ;ń݇V IƇy1 b  &  A D  V h W Ѝ ׍ M I ! Ӟ Ѣ V 1 }  y _zy{y } %~ق ~ yzx| Ux{  @ ~  <}   } 5 ~ | k{ v ; O Жnޞ H ^  ϑ ʙ z ~   Ȱ W   ^ 4 H ؂ ytooymc S % /%A!!O"     ##"I#$A/ L1>A0zT[e.t.01...///i1+0p01s110>isuffvfn}lfuvu$e^m#>#"v  ; * P  =      y   0  ] R  Z          1   | \  U    R [ >  W U  G u   B  B  l v   P t  2  z   l   y  } *  B   i  !6!vX + & 7   / I   c   q  H  o  [   C     t 0          O  :  8 3 v U F g!     c     ]  /   o %    S#   [  e  x  H  '       %    [  !   '# :# + !  _ c! $    D$ " `"(`' ]'% & . g qM lz  C  Ƶ  ̨ w5r Jx݄ w   jhePwg ` v \ 9 ť mc`,a0y S  ڥ ȕ L ks jf mbf sa UQZMNkLWO)OVOPOORRR SY"[!`cf fhhi+lllo qy /|   *H U & } | -u t v u v w ~ 1 ^ ߎ  z k 5  r @ ̍  } rpn*m9kn7otkgg]ilsr utussty}{ljÊ΋x;;ik [ \ _  ? 1 k ^o Z   Ɏ  ҋ ݌ J  ʕ Μ K 2 " _ |  5z M} | L B } {|  m} = { z A| c  YT ]  y  ٙ '+ U  Ҳ ٭ â ؆ zvroqpzfX T) $r!! pMV v!"F!#z"# U/ 7N`Bm3Ue.m.0/*..k.//00001c1?iBCvv^eJtmnee|]ufem"K#s"4s        8   y   t    J  >     > y   ( @ ? '  @ R  /    ;  . t     E +    Q      D   { r      + z / p    ^ :  A*!* e#{       c      q =    F   j r       W      7   H        J  7    w    ^ ,  " Z   %! B!  D ^ N  0  R       f g 2   p!! U# * - ;    i" Y" P#  '# # % ' )% & - o ڈZ A ʣ ܥ ] 2ݨ+ 3G &ѐ s~  q : o luqXY)" % i Ӥ vb(`/_x I  y D d 6w iBed c aaV2UpPdNL7LfNuOfPfRONORRW?]\_dAe htlmoGnqw|vzx|z 6   $  w { z { mz nw st v w x    ے W ߡ 1 V M R F " ٖ vnkiknqmk7egioopHu?vVwvuXsx{`_ووTN@X!%~ & + I  ޕ  "  ܊ ! ׋ V Y   ʕ h n d I        Ł ~ u t | ~  v| 9x Iz ~ ~  5  ٓ  w g s D e  T Ë | y$q>qrl^/ #4""!%y ` |"N!$7##1$z%0 .MA1%YcC.<.0/k.l.*.*/011*0j01y192]>SiJW|tIm^omued^mug t m      3      M i u  e  J  }     q F o    t <   6  3       T   3  <   P y l  g       d F l  K  w $  V  q h      _! o     W      k h { = z  b     l P   J  =   Q    T       d   S  T # :  F Z  3   #   M | ' i"  }$   f  o   8 y   " "  !   [ e" Y    a :  # % %# # $  ! $ # r' & & 2 n؆Vܖ  t c  թ ]  M H ` \5 a ֙ H1 j q " å X ݰ  ٶ ü # 8 ˧ ~ Fa_7`uq L ܻ } ث r > " V Xp c_d `_W*PSAMtLnK$NORQNLOPTX-]_^iskjjp qorLstKt y ~  g Q  f | | #| x { 3x x x wЁ e  є  z d . 0 ! S T  ȣ U ,x r*hgjGjllkdgkppqp qtsuvvqy~ Ȋ͊Q4 & g1 Y  ؚ , M   W ] " Ύ Տ # N t ֦ ة e  Ć Ӆ   } K  ~ w~ ~ z z 8| }  { x { { z| h ' ^ i ܜ j R I K G Λ( o ]  ˪ " " ysrqoh ; C"    J _Q",##""0#D%2 M`A5k^;b.m.0..../0100q0Z0R0=k lfmtKe_elefedem ,   n H    a       4        W z  : -  T  ' J 6 R =    [ ^     :  -  9    B     J ? ! ; G   O {      Y /   y    d .    Y  S E      Q      q  -   \ 5 9  Y      B   Z }   G   3   8      #     P #     k     3 "   x 3     8 N  "  !        ! " ^  $ ! $ " $$ $ # $ $ & ) n3Ut8ƓmC O = 2 \ Z   $ S  H S њ n ` ([l O  f  p K  c `  c^`r  8 ; > H ֚ 8 p x Ej dg c2c9YnUKON0M,LuLwPQUGPYMOsRPV9Wo^ b?c j4ll$oVporpZqrSuvS} 3~ j " \ ӈ R n ˃   k} y zx Ay 8 6y { 1  T r ̒ R 1 a o # Q  ytXljhkkEitiKe{gUgl(nr^p)sq{os=s vy}Iƈ:\Ӎl/o.P.  E  & Cq S H  ٘ & ̉ # ޏ  l , k ˠ * y A ޓ  \  ~  ׀~ Lx | Ay v   } { z ~ v x y || q "ޜ V 4 : ͏ ߟ < | ֥ WQ ݊ ' zZvq;q)mZi 8E $"B  [;y!M!!"""$ W/ K@0_`J**1++6*u**'++,,,,,-;k efemeentve^vugfK" ^6 O  O V  / 3  w   r    > d H  N x i  = c   +  x m m       W  c     a   C  U 3     n 3  >     H    *   \    T M       > _ "#  . K . v            n 4  D 6 >      H U   M     -      S ! d    U p   X        ?    e E p l   e " &   A! 1 ! ," M" ! v! T " "  D  = } q  Z(:$ s! 7" ! " % z% o' . >՗  ͢ ӫ ڪ P # c N  = ؞   ϖ ܑ  j ^ h /jO+U % _ a P K c X $ װ8H xd``'o Ֆ " ګ ϣ p Iz 2m gi g @d fZUOP&OjNdNQNZSORSCTJW0X-`c/clnknfmmpp^s pqu y s| ~  {  *  2 = .  y x x y z |   t ߛ + ̤ ș  H * u O { 7 g ՞ ZϞ{ qlkjPjn.mq|rvx3{ӆȈ@J{)c^ N ގ  ؝  [ѝ ܚ d!#7 ݘ j _ | N ې C 1 1 ̊ o ;    ~ Tz { z z ~ { } 8y | ~ x B} >{ ~{ =  mf S 6 ь j m Ρ ( ; Ԯ   , џ ` | uv _r.ol*g8R &!!J4 Gr  """$ $0 KB3_I`''*g)((?'))*)*t**+w:jitetl^lttf_eeus^m^v^m#" . S ^    : v i    v   ?    4   K  I q      {  `    e  .       /      i  C      h  w 7 q  i      !  3  N 1 I y  y            B  D E   C J          _   K    U" z w  "    8! 3 Q C     a Y  Y  h  ^  d  [ y  2 ^&   ! I  f"  W >  )   *! " " i  A! H  ! % C!     u " *"  ~# ]&   =  8$ /& & % ]% ) E݁W@t K % ܪ  ̲ [ S }p P $ ? P "m)taңʬ w "  ` h  t ( 5 ˬ G gb,^l~ ذ { ӡ Z W t "t i dAe b c XsSRCQQPSJRTSzQRPRV1W,Z_]dhk(i k9jFminqUrPtt x5w} 2~ } #{ ~ i ʊ D | > { wz >y { n{ ?w E~ . # % Ȏ ĕ Ң  V ѡ V Sv qokgmf-iIolkdNj0m2mjutuwbsp~pwvwwAw nރ rƇMI0 ԓ Ӑ ʒ ș   R  | *p, ' ֕ W m L Θ J 3/ & ԕ { z } K  ; |zz{I} z }{ } H f e Ζ Ï  i ؓr  ) V  ͩ æ S) Nx+qnme Z ' >  F  & #!""$%X/ KB7`^( '*)6() )>)*+5)*f+6++:Qi kd^eeemuf_eef\!{#"   !        z V        K        `   t  f  \ o F p   a    >        b Y  k        X ;  n     ? b    G  f }    I  * e    G   c  4  L "  "  & /    i H O /  q T }      Z +   ; B k  !  !     D   !   }! T ! .  ! >  A   @   g >  =   2 Q   R   ! # K# ! f    1    F  D! :!   " N  # & % $ , 'KЌ #  \ ױ ۰ Ɯ! %v5D ` ˑ )> v0Ӥ¨ > ڹ ۸ Ͷ ʳ t 6 § آ id ]g b z   g < r Lb^2ad aJVSU4QNRQFUQPT*QVaV*W*W^aeBfhfhik4moqu rZv5wy @|  #   J  4~ W | { [y { } ~ ~ p e X X  , C  @ ό  ڕ 6 $ i{ rhffimnUicLhl(m1il1otwt tlr uzz~| ̓É2 e E Z  ; 0 R  P ֞  .  Փ V ٕ  Ҏ  ڒ K 2 S' > R ϊ  ; }} '{z @ =z{ }J{vy xx[8k  8 =<b 3 ` P Ҥ % 9 >  ; sw rnkKgR_ , !R  d ' s !"!"# U1 JC9d_V('*)())i*7*+f*h*+,7+;Ri Bln||Bmff^mmffm_dmf##* B   Q G    m    + V      #  + C       a /       { q    9   l   }  * M  C  ^  b    T  3  ) %    4   = z        r w t   " \  M   %      A  k         %    y    7   2 d  $ 1 - (  b!  '   ? H  $     /  U  !  c! %"   l     i!   M!  *  ! -% >!   ! l F v O   B >!  !  # $ )' ]# C) Pۓj5$ˡ ̢ ] C  ^ "Pߡdϔ9t H ; g g)}դԪШ ĵ 6  ԥ  n8e^d`8  = M  6 g } kn aT\aZb:^YV2SQSRSRS~ www v &vayh  V f ? = 7 % R U  A ݇ $| u %mk h_ 4 ! 4    } v L 7!Q !# 3 nN#C5^_(|(9*)((o)p),H-)***+5+;gleuBW}^^ee|umm_!)"/ R             g  %  8  U    l      k  T m      r  e    s (  t  [ N @ |   r  b    _   -  " q     O      /   Z !9 ~  1  _    n Q C   t  W     f t   j      W           * a   !  n  a j  0   j &  [    @ > # S   1  I        i     ! (! e# ! 3" # .  %     W  h   x   .!  "% (# ' Y( ]G=i W W ҫ ; p _ p: I  Qɋ@9Tg/  4 W + ϩ  a  kb_dM~1  9   s @x i F^\^` F\ZWT?TRSRQKPONOPOQW~X]IaJabchi3jkl2l6mm`mosu Ju =y 3 ~ ڀ > r 4  M{  z `z )z | ~ I  M N ^ #Q` + 1 v v z Usjdd$knmLkeciyhzoojrrustyzz,~~Q} Nuh2 * '   j t @ E ɔ  ݔ n g ɗ X . f  ސ  ? Q t 1 = O Ώ  Ї i  Y z| f}({ |  r 5 =y ʀ ~z Uzx z | ?|  M Α P > ? ' ӑ ,  v ı  ͱ ɤ ߖ S w| FuomhZb :@ !F Lt = W  Cn"j3 Mk=5^maK(T'(*'()*~+F,*f**w+0+;gQ^nDtf^^dm{Eeteu"!O! i f   w B u    X .    U   g          }  n v n ) @  ` s c I   _   Z   M B  9         % s    3   w       *  C     '  5  f   "      [ W ` " 9 0 M  A :  ~ x     k  Z  < q       " !  +  o" # W s       7 F!    0& ?   s    I  x      # s  D" !  # O" l 2   N    H  N  # "  Q  # # . n݄I2 ~ Ȫ  s " % u lxH U Ҍ H -Ն͎ آpQu ŷ m " @ Uo lfbc & Ę ΍ k @w i c ] ]] \BYVSUT`SRKSQBQ OOSTU>Y__H^^ad geh>hAkmn m r t v Du pu ' 3 ل Ċ g J % ! b ~ y 2z  Mz Հ H 2 < 4 mג& ܎֙N e Q ȝ f t s8mbgnrn2ii"i=h%kio.suu|tosHrtz&wy wz | ~ ˆ=<5 o ӎ ΋ ܓ ݓ V s ՛ ̗ ϒt   e Z Α U g ; : Y * ^ 2 * W Í `  | } ~  S{byz}   v ~| >{ x w } | z ~ ܏ 9 ӌ )  Q 4 & U `  S \ K { w#p8ljbI#f#  b      K/ K>5ea^(S'(9)(7(**,9+*/***+;heff_}um^mEff~mflEmlv!<h R   M  s K  d     2  A c    ; ; G 7 C Z    ! x  ,   q q E .  K \ Z t  /  _  r c  h     h    f   \ < f  2  ]    Z 9  U m      X g k      2 |   g  f   = m  O    2     o      p  6 D%   ! Q  ` " !  c C     !  !       (  :$ 2     6   q     W# -# T  .   ^  b  S    W    # v% O  2 " ' }2 wcuxթ  ժ Ҭ ) + `  ß ’x+ $ % M܁M˔y=VD ߴ + n ߲ % u  It Re `__ 9 j o _ z h w\]h]]^ZZ W&URRRRQQRNQ[SUX:\`F`cQcQcPfhEiko#pXp q u u w t { * v q q o . , | { | | v  @ ܘ   , c " 3 ,$ + `v okRd,gmiljh$jijnnru"rmtt_xAy M{ }| ${*}H t 3>H{), w  ܗ ֘ ˗ { – ژ kx  Ԗ [ 9F , ] _ Ȑ    A 7 ʃ zz d{ | x =z ~@   0| B|z | { ~RT v|  O ̎   3 υC 1 ^ V ܳ %  ]} ucq1lkb S & "     .u   3 lNt?3c[!! !#D!""$$$2"###z$7ahKut|vlIlCd}J|EsulD}DEnmuv%" 8 o   _ 4   G               ~        4   U       [   I z   /     t | : 9  U   U Z     >  }        H  3 r  l  [ k  J   O f   v  B    i }    _  (  |  d!  P      |     3  " b! "   !  # "    ! r  F!    -  d # n   0   t! 8 [     t   a!   ! # s  ^    ^!   k!  M  c    f# ! $ ! ^" ! b# 2 v}'28 0 X ȫ  آ '^ Z uՄԇB0Fۨ T )   0  #hbcGS [ Ev  ] # { /w -l W^^P^aYo[VjUrSSR SQORERJU;VԄ:Bo  Z ݱ t I ՗  )} Mtnpmm cX - #.  z '   P D   3Lz?:bX  ^!=$"F"#/$%$."5!""$w7hg}}JmmEu|sJmC~vm{|@Euu}'=!P C      :  k    9  }  9   ,  3  J \ `  D   }   [  E  %   n     4        ?  O  { v       S   /   Y   Q 3 E h    q   F#g! !J  w G e e ! 4   R  9 e     3 @   h  3 C  W   # $  X# (   # B!   & 9    ' ,  ^# K$ g! e !  G  i   ! l 2  , !  h  #    M X   g" E' % !    8 ~     ! "   s"    .# Q! T   3$ 5 {– Ȩ  z ] o 0 \ ˒3 # % H~|݁Βgk_F N Q ɶ * p a  m / % h ע ҃ keczk ,  37  T Us p >e a |e `\PZWbUVU0RSSPMQRQU VY\\deOceegjvjjonZux y y :y { ,  7 | | | R| { y | `| } q ҃ Ї o l 1 f . a \ $ 5 e ˗ u /nLjfeejml>nFjk(h loqrjspuUwx ycx | [} |ǂzv2M~c W ɞ O R Y /  ڒ Y ߊ $  ߆M  | y y Wz uu y+yyJ|Cz { 1{ Ez 7y x }  y K{ y y z9zz  !  ~t e m % _ r Y 1 W I -   # ]  # e!     8! #  " ?" I% e#    !  H    o   v " !  !     y   _   !  S  ! 8      }   w# " Z"   } " <uv!66Ԣ 8 I .  j s $ ` \SԖ1 mj|}~`~ }Հ ֧5CE9  5  .   ٣ [ χ nmgEgz Ҳ r 8 / v El 2dC`Pb_[XW#VTpUUS PQLNQTTW Z[^c eRfcg=jmpqrMr x >y ~ G|y| 7 ; } !   ' T  { ~ | } ~ ~ q r , * } ʋ z ʍ y t # " w pkeekm?orji?h8mmsuuvyvH{~ۂ[ }֋~m# Ҡ L }  a Д ӗ M  O   #   g ؈ !R K Ȏ L  J  ݊ 3 z Vsv t x v t Et { x{ ~ ~ ~ | wy r| w z yKz y  (s2 / ԝ I ߨ ٰ u s   8 j > % EwZqo2lg1\ = "  d  O   z! 3 (J>5BcY!""$%"""#"!!$ !'"6"h~fen}CCzB| !G F    T ' 9 K S T  '   D   #  j    ( j  } " q    L  &    \ H      U y f  +   A s    l  C Y  !  '  f ^ P    : c     I {  . $   - i   8  h  Z          3 v    L  @  " m q!   =" =   \   r  m $  ! # # !  $ " ! 2  C  ! <    u  i   $     =! z 6        T  - " J  5  1   !  s ! o  K 5"   o 5 A$ >׀c \ ը ߵ  f Ǩ   ԗ g.+|| qݤ˩ n  4 0    Y d Y mghew 5 S 1 | l +dc >aA_\Y'WcTQgWUSQIN&NPSQS%WY4\\^Wc\cgdaegko!qstwx,|d~{}   ۃ   ( e p ق j ~ ~      ۄ  C “ { Č F  / # | ph7c0fgjn;onjk}h%nVqouwuHz {π:nk R2MF5 ֢ ͡ L t  ( e ݖ M ד [ ϑ J  ؃  q ~ F e ɉˈ J L Б  U } U}v 7su7u !t u s v y S  h~ s~ | w y w Wu W{ z{ v~  0 L  &  d؆ F  W  g @ N "  b x u!pm{f] ]GY$!  0" - @ 8$  4KA>;AaY!q!$7$'."M"~"m#u!U!   6hQJC uECEE}|B|D !a"E+ >         E }         y  c  C   ]  p   c     # [  f M 9  o 4     k | @    ) i    h b        w  w  !@ ?  L  +  6 !  z 0 7 s     I A +   3 |        ?     D l   % L    -   Y Q   W  !   # ! " q  2    8   W   ~      ? > #  {  5! 3  ! # V    >   T    ,   )   M  = 3  ?  `    v ! ~G΀R:0 ե  p p f ] m ( b ܥ f gȂ\)şã#  5 k o / $ ' R I Q Ƨ P J  joh|f t U > X  Ɠ ] O~ q f 0_ab `ZWVjVVTUROOMO[RR#TIW~Z2Z]&cabYbfh@im(oXpsstuwcz {~)| } P ȅ ݂ ~ k 1   ~ | '| ~ _ " X~  P U .   - J (  \ :| nlfubgjolMfkfgqr|v:urpwy{X}̊Ȋ Tr U٣ = ǡ ̟ & 1 + ݐ ג T ] W  щˍ|P   ! g ! 2 s  Fxst s s v y 0w { < }{ sz rx sy ox u { | L>1 7 1x % t R* Ѫ f J ܲ ° 3   7 ' +| ws.jf_(O e%"#7 0  ' tr d   " 4 K?6^Y!!~$%'"!!M"! Nn6gJ".CDLKx+ y  THC   s j  m      n Q               ?   Q   +   " "  ,     T # W     Y  [  p   ;  S  n           \ gC  | [   !    I l E L   ] M E g  " E! w      h  8     # U    Q   |  &  ! ! ! ! # " " " !  S  ? r o  |  \  X , ! # (  a  m  Q  d ! .!    8    B " ! )  " "   9  j 5     a " |   O" H ƢV Ȭ Ѭ ڮ / y 5 % @*TPLy:FeԮ ϲ ڸ 7 P U P ݥ  tohdQsڌ Ы +   o f c ^[a8\Y1VWTSPSSQQQKPLNpOSaV X?Z^$cefh9gk3jkmsxttx"zy~ -z  ˁ $ $  p =| } }   & f } f ! U \  I : f Ύ Ւ e { *o lhcd)iq|mi,eVhElqzy&zvPux}HBI_{fd&^Q K 6 L Ԛ Q o ՙ ј X j   q \ ы  V m $ < t ( ( } vz xs w Ds u v t w y0| | ~~ rz v | 0| /w y z }؀ 1 ͋ f Ł G #  &ԡ` L V S ؈ .| wrrf g^S }'   7 T  A % B   " G4M3?7cUY g! !9#u K#jQ4g:HCB3{CCDKI:! !# $ ? 7 u K  j     ?       E p  9  n   o L    k     , Q   P      9   P  :       Y 7   9 C   h v  : $     #       F   !p!     ]  W   !      a  e  #M : @ 6 K   " "  T    p   i d J!   " " " (" &!  .   % % ! E h! O # u    C B ! 7   2!   !  A  K  >    i  G  @   G E @   o  o K  Y Q% %N''۝=- ة ( m * . fтo~9%m~w+ͨ? p ߻ ʻ  W   # qvfbdw < |   l p Lhpaf_`H^ZUAUPTZSSQQrNFO^NjO2QQVWXZbcTcf:hmoqs(wluv}| Y } M O ˀ  , ;z  2 | { ~ / ؀  Ђ \ " ۇ  H U 7 E ň  Ґ 4  Z v  nhg/eejorzh{hj~iqtwezYy!vz9|o;U;ڑRPQ қ G (  S  K؍   Љ [ U ԍ W \ e z ڕ _ e ( 3~ Cy u nx ys s r x w `v yx h{ (| >y z z x x x Ez { Ճ 4 ɍ   _ { ]~2 h   P LJ U ~tirnj`Z>- e!!~!  u E ! 4iJ1?6cV $|<v1guJuDl &!Y#       !"    ! " / .  ~  (  K 7  &    \     S     e x <    D     \   Z F  [     + g      i  8 q |    3  p  P  1 . % + h  K!  4       x ]   ! " +  x q  k 4 f - C Q S   J   # ! # a!  B  N # K# {#  [" '  " "" H   S  Y  *,# t $  # c# #  -0k    ! T)   h  i&   T U       >      j M   p  n * >  & QNj9" ϩ ۪ * ` t Oȥ V6s|4Xأާҩ ֲ , \ I  $ - ݪ ޣ ^ j tif | 1 3   } v E L p g Gc ^j`Q_\]X{XsV1UTQQOP/N*ON~PUZ[\_bgb cik$mpt(y|}~j} $ d L 3 } ڄ l ~ ~ . !~ t G } Յ ߄ ؅  ӆ ^ L   g  \ !  { v n 6  rf%dfhjUsslhl ό ʏ <  ƅ ^ k " [ Y e =z x{ w Vwsewt s Qu u s x z { z 2w z Ny v v { z y  H + ) * * K ؂#Ҏ-g l k O '~@rqsmka\5#!!g[     C  O7I>70b5VqYU.$@ fRC1iKKJKDuDA{JP %V!HN8    O   {      ! y  3  !  e m < | |  6  q u ;   %    E     P      p  x     L    '       < w G   @   D  _   j    | .      <     Z ,    +  M  $             t  t B 0   !   Q   " /  z    @! ~    ! C! 7   # " *1 , )$ " # ]' !  ]   g%  Y     h M  4  z   k   C { y  i   |  3' {Ve֖ ٩ u  J * 8   Πzx&+sآ  BJ o о M ½ L Ŵ * Z . ۦ ` ?xih ڎ ޛ ʩ @ P  D 7s _g d ]`\ZWXVpTSQSNpORSPZP#QT-W_ae fgAillpSsv|u~,a~ \  ۂ r \ -} 2| } y ` l   ׆  Q  H ~ : I h dh (  " * sifdgXimJqtlhjFjquitssvUuy~<̈΍Upv4$ 2  { ՠ Ü  O F  ]   T  v  T  + ӌ 8 4 L n B ΅ ` 7z *y =w z 1v xx >u u s t Cw Kz v y | y x Ey t v Gx z 6 / Ê I^uݜܣ ī a  i vujn~kf^AW#C#! . b    ' J $ <K*=D3`W2N% 3MhJJB{BLED $n"u w >   X Q   E   J Q     D =   h      U +  =      !  b  P    J  t e    ` p w  *  ? v     B g   , P i    Y       )   |          4       !        C ?     #     !      e! ! I  S! # ! e f ! g  # $ Y" ! ! $  V#  B " " !   r   | 8  c     6  ! N    ,   V G   h         K) X/5ɔ;˘V ? ը ? / § x m U n g*Zgܖś w  M A s  ƺ ¹  ڨ + $ ނ)ikv ɐ ͨ K ֍ 7 ҃ !~ m jbYab\\fZYX(TUsT4RPQPWMiMgPlVZeaZeg'hfi#j\jk m_v yU}؀ g   7 Ą c  I ʄ } ~ r ڈ ݎ q ۊ  R C ̏   3 e_e۠w{ qljRg+kmqqimkmo c x u x (s y ux t p s t Nu u Cu u w {y 4u oy { x }Y 9  ߉ } ~ d{   5    X J ^ Wl m zt:lqm_g%_V ("f a   K   6   Y  K0G=7f[Je+ 6l4vhLD$+G( #$"w#   a    A 6 W   9 D )  '      -  Q     B                 T  x  H   v    {       <    \   p y   x(   M   R r h Z  A   L   w gH   r  )    `       B     } @     F  P   ]  A #  l  d  A D     ! h H  % s    "   N x     y      s    ! ^!   R  ! ; t  s j [  x y !  ' 8[O u( _  k ( , b ٫ S i 6 ʝٔ7Ġbd. ާ P <   ѽ W N Q Ե c b \  b0ڝ ocj  ݧ   Z } {o h d f ~b\YYMVLWUTIQRwPOwM"LNsORY^cefChjhj!jm%ov~u l   ׋ = s  R  ˁ J L Ս O  K ׈ v Vg m S ͊ L ֖ fm"-t - f >shwdginNn\ngJgknEq}s|qtow|vywx}SˉTl ڜѝ W  Z   ̕  ƒ @ j w  Ж U  Ӌ ~ } 4| * 9S _ב ~ 0p -    e Ȣ \ǕEeݖ˜&Bwn ܵ ^ ! m l ]ڛ {jhw w ΰ # ` { p lgcc^]~[WVTTSOLTLMKNhQaU"Z``l_b\eJgjnjjlt/y~X5 g  … O J ц Y q r ח 1  P Ɗ 7 d ӊ , m e [ 2 v  sTgMeHh@i>hhj~he$efh^nrst/vtxz~QU#ԉU͎ώґvT. ]! * ! $ ֎ l Y u p  a a + D  ˏ ]  3w &v Bq u s sq -r Xq %q ow v v Nr p r y Iz vuKv{  )   } 4FNAĥYcۚ ՗ 4  ʃyqqle[08@    8 5 e R   ' ;sK <;7efW)3hhFKK>%A%"Z 3>v}  f 7 " _2  # # %  ~  Q =r19Z , t !     s   l a  %   #   " <$   j ) N$ \"      c ?r!]C w  "9%%& o#!;"F"q&{%""!!X "+!#"%!# # {!   G  [ m  :   S   "!  A ^  C ! =    # O# S    &    G     ) D     Y  F  5 ! }     @ {   1  -  "   ^    #  e  N ^ M    ?     z  H( W˖  Ӫ  ˬ ְ  * . |vzZuYAp , ȸ - 1 @ǥФF7 o{iEe{  \ F V k } ( `|v pgb^ZS\<\nYVUwROOMLMOP4RVZ^^xcfi{ggkkFm npv|~F;| m ځ  '  U Y 2 {   G f Д  Z # d g [ V  _ + ? Λ  pTeb}dfgFjlkhfQlpFq5rtoOs;u$wX{|x~\ڋė5ۘ (h*<~x <ˌ@^K" t , q 0 l ͐ }}z fu +x p rrkp q np4qnk n p t o m w,|axpSx|~ O ݈Y ? i  O 5Xݘ`Lok) - ȉ 9 ;hyxqmmne}T>  \    )  x    <SI;2h \V+1.>9703pi-JD6$&$%d'! O F o P     !t!2"i!  # u Xbg #U"9!    # [ L    A   [         !  <    ! < %   N p   j |!/ !p$ K& |& j'%#j$'L&%$##D!"%'!"$%@! * # '"   " @$  J      E  r    2! F!# :" $ # b$ {  ! # } #     *   !   3 8 ! "   L t  A   d  u!  g u    @  2  h  j % " j  a!  " !  E C  q <~ Ӄ 7 l : b - 8 ɚ  5 oeddXdilmlkYggmCrrrpqKsxCxu|"|g$,,ԔL2٘hp.]n4CpBڅ؊6֊    u `  {4{/{ks6qsrTwuqu nnostl ljlqWqpttx  ؁ } 1 w z {Ɇje٘dٙ Y  ʄ y x tiq kp|zrndedHO8    K   # $ X! / ? G;5eZ,69!s4i+-:=?& %- & !(Y\ g x E 2    H $G , }# , n 6  m!o  m!!W  >  N  a    $ - S       m    A r t L 4 0      I   L V  !"!O!!# $# M%" !$# #% 5( k !#'! "d#C   E u s  } e    ! v   q   $ {4  B ""E  " k$ B'  !   t! K    ]  $ !  )  ,   ] U |  *  *  J    m P \ 9 )$ f$ ;" L   $ ! " U! ! z # }" _  !  "  ! (  x! m >!  $ , !Y XMJyƥ +K 5 D Ƭ #? 4 4:~]= r [_!   ۳q]ş@ܒ5J%&IeVYo! t  b Gw [mmf'_X^^8ZYV_` TROqI MJ0NJLMPV!WeZ\_^ Tb 4dLbfb$\c^l]oww=xont y{ vyt [mi#k n pus %r;s+c\oBvzsDž֋ |Qh~  Q @y oy x l By s A| + 5 h p  Az kb)`bXciwjFikbnapdfhlrCsvo4n.pwx}{{}|̈́"7lg.0+j w4  HZ Ȏ~r   / }   9 wqtb.amcP`Ef1^c fi jituw1nV\ k'm_o?oot5q;xg I{ p 6} {y Fs Em m O  {;d t r p k j Y][ \ ] _]>]XF^) , # &  ,( ' &$D'!@1; >TG1> 6deVUqhyc4hg29+V#" 7 \6 21 + ' :T4!  3 "~!    k  )# iQ ! " [  - !X k! ;(  " $ 1%&,&F# S  $  /  N  ~   h N  ! 0 )  R  !  " v$ y s y  f   w # " {" # u  T #! h!!i "!8# #+"y# "i$ #!! e" #  ! m& (! " !  ! `! ^  i  x  " _$ , 1 P)   .  -$ ' l# 5" R# " " ! @# ! i!  F% "   ]  {! " $ % 0! Z # $ S" x, ;6115P*`c@ 8 O/ 1 ) %' ' - ' * ' 9. 0 / &. 4 6 5 1 ^0 q. (. / + ) f, + *, ( ?+ 3+ & ' ( * - 4 ]   WK p Ī  N ͟ h ޓ   r  ^  ߉ K   :  ͈ a| w N  |2}}HzΊ * GplhUv{yV^mcjb|yOor\`T_G{vmdHEG3ABC ;{8@G7HE;B!C<@FQ?w;A@;ACjAHH4F[KEXKJD@ZBGOgY ]?YY T 'K gX "X S '[ U0RJS ce@da? T Z d W c enKnUo la b` VuX i ` yi in}g Kf e mihsdg{m^ovkZUU J C &> @ F uF R Q J 2< LB nB @ > D {H D 9E H W zU USHMTT/SjVlQL?>GJHADzB9EHn+;;@zD?B;C>@HI<9HTH>-(E-8S:<BA+<@FIwC@DC=710(,-t-#+('p(++ !! _,t^^8$5/[nMxSd! Fo !SJ13 0?B?AqD D?@C9{9=F@;DF93eW EMf5n9Ar4iUV83u30%+,  !  2! ,b31"$_  & 2% $ v 4 3 * 05<)# -f+. ) $ ,B # P),+ + + ( ~- *' # $ ) U( ) + ) ) g+ g) # P( Y& Q& % ' * J()***' !(J(/)- ' K'o+ B' c$ +!"/$! $ )n'&, ( %~2 !)#%((!h$i,[*5$R%%*'?(!",#, 46p6:!!+&$7"e$<4"v&k!!%[## Hj/ O~'*;"['V$c&?%Z#"#*(|+'R&# $&(&7&,01z4|6`96,u/&#*C5$6'3-|043.)!u39 -qjQ),5zK dA q Q Yq  g   P ~ ~     D, 7 + t  {w[  +  3~|` l5u    )   |  6   a l) K   K  {  {   uM{   W X1    t     v     ~   &+)a^ 9 x:qhs/oQ#]m>H'- ,..ecMuj\JL#GB 3?La]kNTD c*?ACv?$A0J@C;@=<N<9;=>vF$E9B2h V_yqQ<2g(%;3;'2,*4>)OzUMPI6!;(o56bwq*M ,DlJ6/;iuJRlQ5`-Rh fF 1bD-HYf#S/_  }]`'Ym0`P#HYzWwG8HxAA%{aq#r(: $n% r  >2 ] o     N 9  &wvS7D ud  =Cw   .D   F <  ;  v s  .   ]      7[ cTU*WQ h 'aBjqT"b9eM=,us @ B  %#    5   c" :-  #b!*$+3t.QWX|wu5[\-*8M:  TI$c1\x stZ2*PUA{C <EK Z+?jC(C)C|CDWF;DQ?:;?<=lKG0;3ddV e S A0 j 9 b\* e   9  //h +PR;2s1C-I>L!( +=}5=+6\M,LD 3;s,Q4Zt!x;93qI<3#DxIi!QW@IO\eGX`PWfNMHQVkvg4n j\   ) ybY+S s `#3 2  ) R]  p q  ."7YNc-ohc)"hY_ !"wsT"9nqxj?Q :Y"` ! Om1 "r**id"T+\ lV$-]KZ;jSK~t <;a,YUDYkj)`^YPIPyw^Xi112'(`xhtBW ul9&J-)@D+GEBu?GC?:9>@MG;:bbXX / e  m |bSbv .   \,-g,>(.6AQH+1APO+00GVd07F2/CT!)Z\S0U/&hoABII3g/<NV>4W!*?< aPqw^/m/'5/v Ue5'~'HW..Q^)`1)u<*m(qxrxY jqPTTtjYY\w_xy4#sa31G:z|qB :iOq'**9ylp:87/p1j0)iq$ g * oz !pXB&c*i9s%>b|[UldY$Q\PBdS aCDAg q{{mNCnZI@jY3QWnZpxf<p:6@p"vro$_n}q#!-CnDhHGD?DiA<<98>2M!F:7__@ 5  B CbQ,k2+fyQ(1a=UH8"NK3!, 174900NMuU!%wFK.!/5.D0!44%%*x/QHFgG5@ U_`Qu'AYWI4qzN'mxK7_n~o'm9cf^&>]OP#!V(_WQcjH v_ZEyT00bR;iZD)gxAY)?' ~pX!( RhyaXXHrqp?olf)5(g)a+2!Z pZn^R"Aui1:aB,2+{I!(Zi RBz1;FQBrRhO{sQZRrRf[/\ G6:+^.woV@V~ mAQ(k z,f@\CxErHA)BDW@;:~87;KcF:}3_6 T f#Nc$ -e3&$58O+B!1I3P7#~N!0WM?iOvM>E2(/-m8U6?sC*%<]E:Kao414_{_ K;H,O~)F13J+6C!%^_W W X^'b'.E^GWH .!x`PCH)gR4Y_4GOUQ6q,(Y4yv`pxc"`|lj%78HPg@x}`olY Z kj9*boRw0TbP'_`.pL$nRQ!qXL)T!jKZR0k9Qh{GG9HA9PFzYZ`x`Ky`A .hcvOxCrCwyy.>CCCjBBmA:A=;77>JG81>sD"!Q{t'01!*%4,1ZO<c87F#F@U+O,F2<_6J},/CB2BWCOJH@QyBhJ.@I<Di?{ a]AA1cUFIO Pn/Z@ I..I/1X6nO%Q8hO/o>V&v!Q(-c&Ivp.q&&QJ 8n@q []) j6bKWQL`|_-   i KA:I c  p1iR[ps0R:r/oIqg0K1IPWYP0Z"H) XZTcI 3:@79AS:*"r`g_0NG9hnp8v.8y4LSVJ)>@>CkA<C@<q<5;NBKYE89U25`$;%9P   g  n<3!6{H@K^3HHI17Nq{F9?=1 pOK;J 1X@N`a1H@aO;IzUo29,H9<&9/R_u]_#ZO}LUV{ 'HGIX> >. H7X8C^0}h(}%_M8/6gO0'/0`Dpac'9v"Yw~Nsx(w1'?&<u"o^ y9Ip6(&?.71O*AO o I_9Qi0aP'yYO!Oc9h'S%MVPI/9_m e/UXkf6@=F.B1EP>A R-D@B@{D+A=DA;<t87yArLD;01-% $f<X  z"-D]QPF->^WD)0LJ6Z8Eg%(E4[=qpD454hGBNf'G"+,9Qn?1+pWF y7qzpgXg> f1HW P]}_/-UeWU7" L^aOl N=fo&} v%uJpgXQ!(6j1(g/ir-/7w0x.rf YaLY7/n"r56u&  w> XF^9^n(W?fY  ^x ?6ka0YF`jHR:Sy@FgzJ:Rx_OXQ,/\NF#gOn|p`n?y7?5WHH1=(3RYI-AADE<@~@CDWB?:98JCJEf<-.:!0>#z&|f HO~\?IH("2O3pD[;'JFL"FEU51I)*19Fv5EZ'NMGCK'^y}S ;SqWi]FAIAP<@W C@&onpWWi@@TC'XY<5gedpm>]Vvp^{f VA__ X@~=f?>uX^."ol ZY9#bN8Jb1 ~_mj_gxp&w'2Z! v6~u0.6A[   G78}Y6X>%6 PkQZB)0  NR G@Y4QXo_1/ F kIN /'9AgcE,Evop( }N`70Zu7q /xBU>};@g<BBAz>5:n8:G/LE<50V3}#8,!-  Z8gz:_Z*0,,?^A<Lf6VBL3_|LZFlF PBh6{HLz!QHH^{mUH}yA,&f!NnU@$:8ZD_ @Xe M Wh&l|LUuW_l'6dWufWO&b7v~/P'_ =&Uw!OPy)7''[#0YIv`! -W7&'?ag[`^& % +Wiafg,e yn?. v  ~X^Gx-HjQkwZOcaR9 #_PHB?W 9>8THG$6b P`E?V8V&Hfp7F6wwuKM"ENLO.-FCp@9BqBMC3CC-<~;97JKG7;21d.#` . 3ics>%;F+Xq~M):{.7*2h+?&='m&H^\AP YF8e4BOg^Z@2OTWON8,$RXM/OOFf'#s"{`o@=wV'wgtDg'$y#L>4%p/lWgoFm%N (j6 Vh(_-<e-w)rb(00/|vf oW.Z Xn/E @7Xf ! ou7>6/'t=WwX<&(?W.|mha_Q HdH*Xh# Kj;zHyyO8kV*+W7HROWQXe+.7OgH@9/t!( ^<<EM. }8BA1P /2DAwAC=BFBB?<w9;JKUG:3l1+'&!/\  \Be+:DTWf.|MCpv D!IzLttyRr@ExiA@XzJM_\8TO  IA!I2UWV>zDN q8~fV,\#'-v,t&Vmt;m<NqP#kdmy7.p6@_QuOd?zHn)`6<iu4nVOg-Oo  glM o f&` o n.%Q7_g'Xf Wa.^Hm" aD3rX( i$WUB9 806zuI/0IW !_nOGvPH0K~@m4E.t'wV?b:uEjRQ1ADaB@A"A?FNA==;M<y@KKE:9t70(E/$!$ U/ <AVNs3.boT8B]DiUF=@MgB-W~e>g-gN @ .J%?w >OopH GkN^e]olnmN'T}efgl%*%$ "4l&L]\$_to7Yh/p)&Xc,+W`=&>W'n=!hg?UoI# u81 +-_N5%P W V= \^gnkWN&~ 064n_6 M F&/djb'c bSB~ 5@5FV_P_[/W^,N&1_m1#^/(fC.S2i=5o4v/@n#^=7A_@;ef0@BABb@Ax>Dt?y=z;~7CNUH#Cw:522#&?J(MwE\V 7<o*ORG[3)DU]pYAjHX66VWW@VO P2zwPSxOpQM&.8n7$/B?A9ff'&oTW\ l$l.u'fuq]d42&=]bSg[gS\EG!HVoL#W]&n(' Et?4t-vOPeg XOVldY8"W1dmtHO(gg& q->%].?\! ' Y n'mo5`eXX[,IiJ\'1OQ)G  $8dV!6._W`'-7Q4zTUVz~~J=m|o,T&s(IyHO?vj"?y$2DCBACdB7DBAx@m;%6ELGF=5(71)m-$`#)Q plV\kv~~'@/#\W3P ^PWP AHBu+\8G N`$'@00G}g&nKsjT$6`PNgd.V2%,t+rdc_ j?tw&R]sug>.h#d_V% wU5P|4\f?u=Xfow6e oQO} W]"\0w6 4{ %lL fh/Y=fx o& / _w7/Xkd7g  D97 s:n5lf|W?[LUvx/^TvD."9CG\gv`_:;= 1?A[A[CjA BBA:<6;6GOI-D<6;5+,|zq?yh+p i4US(/p X2:7 H2%VF8!f%\R '_fI  _xS]TkQCFfW%^ELUF?>TP6?@nV+N[EeU&ld^^.x['KET$5S7u@-U> w lVjU.eO%e]m(_- ] _5n"'ko3pgd_  ue-V# , /]M%U/-% - mo.e(:V)i$agWiXVA^^q-_VRn5]?b ;G!c(H]Wos0Cg%M(UHHUt=F uba78NUZp +6MO 4BsC#AB)BEDA_;6=:zJaOJD=93;7,e1W!$ v + /{rN4iiU"D(*^V`_/VOnQ{=LT|$i_ SxE EG.u|O/}K%o_"@HMV'Hv n3d*,\_<ELFaH]K^X^O@x`=fhg}f/p'sho  nd C%w5_]]g.fW .O$l( +.y]$7| 6 m n.fR'WvY<*h&6m#TQ1c}p e%UbU/ 6H/wO.P h' >!LEVJ}wT0tC DN}_ vH [1BE]@B?uE4FC\=^>}?*JOKE'@s64p28$'{"gJC\KX2yy.LO!=xB!wfj^HfF'Ou-Q0\/pHMgfOHFmV;w? $??|K@s~l,\fbML7M_[\ {%U&\eX1H{6tc~_7^%W@wHog> aDU4Q M   W3Oe]^v->&jg$%&%| Vnlms^$De=o6 ` _E{wN~nVmfy=.^)cgzPafve'-6@>hp y :%J_ -|V$l !ne]DV WK;k7zU!xh@KA1@K@AA@BFLC/= Az=JOLTB@/7!61a5%*}- jGf1"'k0D>2WO, Ywwy `~TBrO)u~|Mev*#ID$m8L~tU| A4)9E  GV@&F pF %]/?N%#LjVrvt7&m^u(D,[#VV=&VNW. &sEJRp%GGSYOJ!AQW.2  c G5-`_>]Ff m/u  mVgS[ [l>/-, ,l p - fe/, rg&xHIXYYQ/s ]FYXq^s  T ?> W _ QP_\&&T~<4V vOv5 E vIGvPNMq: >1AA#?A@BjFB?x@A)JKJD*>356A,#0!  N ,<MS:&ao9.XzT7~9B%n !,y8!(wp'W5uewn;.?pEGw"Gw6mn&! pIn?58w?o> ^?BX7pG6=D@  oN =|R1=^]UN'/UMSw:OOW8B Veu^5 B%eZG7IHEMWOL_~=t \V@l TWIIVWv-2%>F WS6d_ :3w^>p<PW  g p p*$z |UH)?:ZM7`.'x<r}7L/*Gh6?x52yB[CY?Ah?A]Bj@>m<,BIJI]D!@)39}8H/#0/!|W/2Bnip2-8.7.1/share/nip2/data/examples/1_point_mosaic/0000755000175000017500000000000013351443023017003 500000000000000nip2-8.7.1/share/nip2/data/examples/1_point_mosaic/cd4.2.jpg0000644000175000017500000005730113351443023020245 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342 u }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?H\(dU䑊sx6);p* U1L(HS ޹ֹ5I$jͶ]@ɮkF:Uă Z%ĂN=*xI֦eq<N<'9f81U`G7pDSP+ i.Hś'AU[~*- uIZ PA";iۃjؘJtmT\;&*&$o55Š=w$\3yҳ$bp#Ҥ`lqT88PHZlG =ۤV+ 5hV{oRxrH~GSW&`$E wI;2k[0k.|;VY71ݡFPOҸWCkRJW=q\v :T5lx$`L- "o.#ҵpAZASO[WgP5'rgOcKpǝ©]jji5 ,zQ_LF3f-0Y6WrU.7`dOb\#<~TFTZlrne#!pF:Ĩ9I88Ui`c$đ=*ĭ['=2jdF[⪴[vA'UpĎ|q& ®8jKn+|GJk54wJm^ E?UH'ޢӃ c$w=es^G;csZu*#̝5Kx!)$fjƤ\-t@_eJ5KrG3ڬ%r!JtXnؤRf[جַ:85[O"GLPMr+>m#Ul~˨#\2+Լ6 rwVm6ô{E݀Spr@kZܬ9POhFa]1 W+{dq+83ONjK{8v:ӤCT{Nʬz[NS<(s]Gܤfm-xk8z>*{.rf8#3A.XۥE#_M!9,qMfPpF2Is-j@e%r\pzΘ<]-͊|$hopjMV`In5vzs\Hk Y-ÜXmcj 烁S@@Yw6\ XP\B8湻f Q] |ide'?)`k0F}kFɭrZy9[lHmLֶCncWt xZvt%Epkblݸ=+? >#?[4eVWDYAt#l< ϷHڦLwdfԠ=ef1Z nC9 8@$ii靣ʧ8#|6tIȥ01P9%Km+{DũrmZ6:Mim=*0-:ձz H8=sMvEkmO'rciVhyZp9\K1qU/۞jw#ڑjF*O620('WI}jGrȿ2(r$UkJJ`Q.BNje9z~ Cn c#&2  6Gjʞ_@#4#*U2%ќVL akẂkvKXcildTF T ԲK\^{f3Wλ&5'#*hf82ĮhPǭq+5W֦tRd yW-cj>QWxe$-^:G(gjsg[78ZdzԒ87R )5<:ګ{`+h.~_5Z"KBS%lW(łu=hFBF:7Vm۟Cm8=)kLҪO(YsZ>PV=9pWֻkFpv涒\.OS6'sUemiwb#+:BÎ0irUi0RJ&A=ZɆ]Lnrdg!i3j1he0vr7VvXbF=+6y4 gj!1KW9kp-?8CByP6h?#q^  u#m4F@5M8aj+ֵb W#=içjEHNĬyHQ7[j\wCWif;GT1_qVɪ"LW*&86: CzWy!ju@_1Zʭ&FPϡG*Ty%n@aWeqGVr1Ҝ9_j ⣓>_QU2ŶQLg.D n>{s\-jrМdsg#yfF:UE&sӊ˹A\RĂ?:-uA+b-F 楆t#Ar0GN 'U)Y<$W(DLaCXWSܜz.#yxpt$fB8d Y|r8[Y,ٸ?³gWu۩&ڡdjÅZdⓂvϭLS88Tv^:@'sz݇(-6kgcpq"m-s֤ O36$`$],WEb3Om‘YO>',kjη*H(#Ck!n9gGZ=*s 5ra#5R!d =yy@vjĻg,1Z.:ɘ 8g@Wk_6|VjAdjP0@T* l"$xkִͤ`Ҵ AI+B\.[֝mw<ʾ Vœb߅^+R9TF9YW\nc$ՋvfpdS3tY1ێ~ufn,>A$߭\V绒a>+]D腋\T^hW%#3Np8^aac;t%Y11LWsܷo1x,`qwՓEr[Aqw0x 2596qS!$;qS,08 ձکFN=Xuwzdur ]~U\X {Uo^ = Ie&]L&cnqS$bMJ)0$f;eR԰+K3Q`p]*]Jі9^NY܂$k6ᔕ*ǻp 3 չnB ڹy攘x#TXn }0\q]&+@,R$ŝ'ֺ-;G[ۅb t`].<%Fc[$sqg0`6yQaT@;hb`U1mN*[ZU0 1R-zݺ XڴB`qڰ% R5nM#WY.WLՙ8925pLJ5n̴N2:R#%ִmc$'"H d`$AӤL0͐GZCpb8wNUNSO˾NrkZCOSN`Yq撡 RXQ;qYS\`cֳ%9_j%""9*ԷFs{U)5/7ĹZ|Zph@&K*m1ΞCzl c!KuH1'c׌=RHϽSkw.n4 f^dOAlUDIa–MӸO T623՘+K{H4N+*@BG~z]`pj) mF,4xORo.MǏTDZБWibhFV}T;1k7Q͈ZE[[ax4"UA`~GhKA626{ITLո&S Zr@}*#NN3c#Ҥh^N|ez hĐZv!;B?ڠUi $ H⬠- AZڄGݓr0Gҟ)&H$T֮2xxrwO?flK4ȸD֪ [Ă2iaFdfmFaFkMl=JKKD؂]Z(^%Dӟ]ÊM n@Fbi\/p+n~*=2A8*{Y~zd$mqV='DpG5̇N3S>L'ȤOziJ29'v8 ZFR"it 6cwlw6' k^&=jv-!8Wl!I6Ef b#W[qZٸf6j VMx+[]NEvMw:jm- 5RvSQN1;ՄR&F4JA&g^GNÿ=Ef˯@MD8oSxG8S7&y[vJֶ*jn ^pUoqեC5R3$rM]f-W랽dGʢܻy1ǵUgm%ϥ>+GDGP2vxDSE:{Md ~ջUEYmgip+Mi4щԐ7:]7\51W_˂ޭiYrjҺp(;rJ+ d~ϓc8wzՆ"F\{U)R%z zj>0zV۬͞o{կ" @^j܊Ւx[MU<M.HbS:tl*_0u0Sj_ *)gZu !pS&Q#Z\}iʡc)速R#;qңxYU*fuPFi8F=i8&A1*a1VVA⵭1SU..SGΣG*1X+L_֬KJ U2LasޯĖ)k&n1V3j24c=jY zG~9`8N_!h*u< wT7X޹\FB:M})uMa]搥mJKHp:7o$ K'"Ƹ5"V87BLkTDW&bFeWVDgtիnrF;U+tI*LqWvI)LE6NYy#j9cio 9}f-#'V Wd0k&L2RkHv98 0MvUqҸb&ԃ9×F rY*۹\Cj#"FF84%;I=iÐbZl=(̞H$Gf WfcU5F #&ANiҕ/|69vA⹫r? »{8Bcj|6d&89` rW"`UV<$U,0\֧aE?*psOpbvLTH¥TpXc"ѹPuneUJS\&0F [ѮֵۉA\Nk5،w0NEC&8uƼawWT,x9NG ǧ)v2>2MG-r$Sn 0Hⳣ>lu600@dcƳ5O1lؖ\:殛nn5ǁFEbx%ط*QFޕ+NY@[sLٺ^f8,LٸGTwvFeE+ӥVwdYLգ$g䃊r9Zܓ)=ZA8Umްt PkJ,%zW<VR1CӏJϸ8uvnjUnb K/t6MBG<T_lr܊Ig+?ZÝJyY6+MVCZkB튚smi#q -Dn)%BI&sVts{0 *PqI|n*dOrEhK#}xя)]NTV_2Jنq$x81XZ%EcZI $PWIB#535NŸu vVi}Zr2ôCjpFko.w8֤2o',ʂݖU`Ec:\OiAYkjKݸc=k]Fx zUkUʌW=[\˞zŒPQ W#im&ʁn-+]\yTy6 sf"rF'c^*m8A 2C)mI5b鰼O-`k#i+t4YZE'b H^-jp$Pіo1xYkHkkNmmVbbph{2F~$T/Fܠ2W]JƸɨt.}ꮡ?6AD" 5M3NFr L@$na6W7r1RF3\ԁ;zWyv^6gk+ʫ|=#a%w/Oz,OdUexsZKxK^i.f ̓VD0An-Rɯf0cLu&O$-Vt6 q#n=0GR|Ds|G2 v@yWi00 sx>եdg$W瞂[$ɷ8b"idېHɬ;sn\eZM ld+z BU q:d꦳Bk/]~k5A|9 pj}Bo2}zU`+tv%U=uZ"W!&(q] S\z˻U@"I坭ޯj 湯1Hc5%+ZJcz؃NX[ J$8^"w k2K‚1SIie޺ #H1Fd>'۞*!U%85 1\Ϋ3$ĠT,.qm.k,sM<͎* iX68FoZ,dq& XjkoppT 0M3Yr[K$Q溝e,8e.33ZB5c7|VWpdH(#u3O&@J#~3i AiXJFGcҶ$Q鬮Rhc]I=q]L0Xe+b'S$=O<m}w+ ϥ2TG@Ցqryjj( Z$wz#ۜ Wsmm+?-- wb+'UvXlgIGHcBt zfNjs!~P}$J0JfJԭՍObf%/./;xh<Vd9"Lֆ;1Q[/<,/͏jFxcFjQqLe_lde^2=꼌KqZ͂E\.y"uY"3!$qrXQ]~"1j?Aϭ]F6U!T/"]C&\vc"8\i9m( tZَPj+3z~˴ZQiTVv1Z_ EUuKDQ(*8QT<-Ȯ*ɘrj2WWA"g\MG$ !8ݢ<5^QNI]&P=,TsSiZʼnq崵hKmL5p~@zmc9e*9{x9PVn䚇P[ۥ&⺯ "]wUml6 pj}Bt-ҳn7o¬8Q\"Jjyqcۧ# z2-$t|Ye(5ИK`.1bYI=䃎$ 6q֪;Lv fE>jE.Hci=;{pzֲě@\SrLE ԁH}J8!p*NqUUc!@VCotpwfV8s:ֺ|»M -h[13dkЁZv/qZa?'ڠIǥcdjj4LEYr5{t`v20j֗jU(D1p=}RPq~qN''\>B0O_Jo`0KƣuKb3],3P]/-g pc$VޚF Uhg\ckuhȰ@Xe5ܮ kCOTp]UՇ ]f $ =kU\i6Hʊv*p)l-lsRBg"r ua3BTZlUczFR8x.XrjtlGMiNPY@RQ іbB+c~ݴ`V6IԎUN)gpN8J) uSUF9˚aqZsrqqڸ}jiM Zgd"56-o]n[DF+AosWn*&a5t{AҔFxˀ 'n82ܤ%TK5yխ 쫰(Zw :tM[65Ӳȸ+=bT2:W7$1tQS\RXc"'f.mxEp׶o큌-nCgq e;s ъEtuvZnBj`*>ZPڥ-c>]$46~uX]<ō<) ҧD1&g=+N9b8]fG\z!tVR1[Hp"IL_Hǂ {W,$Sty|kxFTW#w esRFfm78fse*ozjǨ5md(b+jA*qZ?Dnj H+T%Aؤ:)\\8C#G$Sd`{Vn:|^݈I~sv(l]&e$ . .m4‡s.doo/Zim2l§ffSOG{{Tu?N]|OZr")}+B6PJ65)lpq\Ui%8 \cphKqo!GsqmjZKĠW7yk)G\ސ@{ x7"X>jS7oq˚P唱=)G5{v7߳bkwiH$v3 X@< bUR0y'ҟ̸e<گP8>a V\4t6EE kJ9SZNx8Ԑ085v6; 5 YCiJ Qgpb鴉7 ގBN3Dқ 䊑R=y4[vF}krU0zSV1RBuwx洖''J˻CmޘDe+Kwr9=*P9T&yf 8ЦB9I뚲T.6CV~%gd,#uF=)'#$dՃڈ@PCfXnw_ !yjj[0MvZF$bٙbw! kBB[8Ē8ۃZQԜ0H(*P6Pz)҃)c S[@W#{ i\7k3SFx5hIj^ߊP[ X3a5KJH]PkJv8EѨ qٰqTIAnn`MbEhyJv;SU|| c\!`[FBx$!0ujis  t\bLc, x*zu2~`\$g(ف՟i:T6RO5I TbHqؚ ]>TPI z3<֝ݪAn +LA![z1n%%[x5I015i$kDWhqη00O9.]c_#>%Z@9gIw >e LL`ZA"͜(=98階S8ȕXd_ݬ)eqګ4e$jY d˨I3rF Ic6tO,6V`GL[ɷ79AѴŷ31ksڬ9XW ۏ\WQi$1Y`&l'bPB.1TrE48⢙0q\yfYOcXL}+ܔGrG.p9RcLrpGҰBW8%S#)LָHD耎9t~+&@2:f4UVђpjhR]^zR&xǵE3/LWaSҫܾ~HH88Ѿ"R%' W֘zۉc+uG Uu9* I$ tr*!Hwֲ Lrj+' PH@.>{@ryRqUuYpqYJ-2@Z=L qwZb!hIRdcX71w{U$/%w]FDHYd49+1Z mAG˜WvsӭI 5rTgP%krˌI>rtTe1Hzu6KqVw,D~uWVUd*N0UsTUfLduTZZׁ*1O ä;sE! Zi.5h_iHcX6ьZ67UȦNZ`MfElZM$=1P,&% I|Z,H [t4 ǭtWiYq&sRGm_ZՂ~d޺-3xo) EajמPdR Ҵֺ͐Oz-[uTUWWVlgw1rEg^ޓ9U--Lt&(Aom\5MՇkpFs[ZlevxZ5fOzGu!$Lur!{NUU 9CW;itҭNgŏLZq}jΈ_@}c&ckMH*@*k+S'o`k'i9=}҃ [{A4%i%abA:sVF\Vm\jk3jqk.Vqvͺ(ǠLr{Q>U@ PhvAZvz&8淄1IlNϦ)e5%śC qNbf]i $zVkm~"l8AZ/!&ga%vRެk-VkrKUVV/ҴcA0*1! 3Q[H.7Enq溸,@jq<'1L  sT/1܂jkoۋh (cZ-ag溽\T-A-Kҵ4(ɻ.A TGoJ.rm>`"aml<{Tږ5WbؑSV;ǭ?F@.kfZ;U>]2*GqĊYGmZ F QSH2S/cGs$Jº+4UŒrU 4Lj򚁐AQHc 嘊lbCTX}k4e6Φ0YsFTUIrkGOx&,zbK_biܩ8kN>`1rkQl$ H} *] y[cQE [mw:Uf15B\8TeǾyPH,c75OH\`i0U;zbSe@'i(W-Hr3Q|ޚR' I<@ j܈w`fyHBH禘 $.d_)<{ ϓcӡl Tsug -RVfLsWGbEqHݕ\ެǞ_MC<;l˓zx!<~5^'8==;*+qu0BFW\yޚ 613T/v]K BY5GS!N0OJ,gs1FM:ֻfшV7\]$8wqARK1WuXC Yitq]NQPO RkŜOT=i<31]|=iyrV+֑ UNUFy5kc+#Vv+'޹&iFMA`NXc=HTi\&*n j-\u'9<դR+@HךڅN.ETn6Xטꓗ^|-`qh6xXO4; N29hS>d}޲/_RPg֫`ajǽQaHѨȼBq_nX ꭮C۶]p*KL\vW ef(9+5P3SDY}*ޡjd\@S{Z geH˳=wHֈb u 1T'/IzWm-=%W gV+85OE\65m2LIrHe3)#7j zW3<-/SҠx .x!~S*#EGd$p)-#)z`Ú,/p? tS\[]Ex2#hKhjEtqި4YcW1ټL{U;1$OJӺbaO8ylkR+O/ 6Fkx=C$+ Uȷ+_ZܓzWcwGխaU%-OJAc3X$"du3kw}~NR\V0PڰUq܊n Pb`qC.r+㠥5,[Z!G+nSlbf;$⧼ qқqy۪Yhr@M`H'^@*%r1WD’Vw#ֹ^rW#,px 6ZS%8^}in&*Ek-u'Zq({^\fCumqr1ұ&j,{qY0FHVKs\pjdă5jB=(X_[3s\*3WfÅ\L/<5x^4&3olCLY^w S.vg;:dqz"Y++;WyJM^:u2X4[VM͌kUE 6Չ#ʜ *F)Z@$e=* M3P=ǯqWSbprjkǜ5~0(U!R`.yy'8U̲1O=ïeiqk[N#ҹR9jѺ^8nփ?X394W4n/s]}[[qQc[ȲZWX7Lf \m.3RH廁BJʻYJ¾$\ *qXHV_6xsT.l BqX-v}:魦gw_#8I%xLlqӮj@c9 M*>񥬄*LJ/[?ѤtiufFWsb`P9SNȩ][%㐜g'<^جϽ7ik,zVuj.^0˾b'V߇)/uC@yo85i; PYAQm@ Uc8U(TÜӥ u~ﰬ˃{8̮N18Wߙ%`hq#Z`$bA{ *66ⱌ@@[s$}={8ZxJFVEb0v2mֹMfѢ609b1=2u" A*:1TnYwS8nrG>b$h)*J7b5j 'wz}ΫV`AVUbm1[Qj9sb'\ϸTBFHt*ǭhGأ"Ij]ab/TMnHjN+|H'oqr ]Sy\UI'NȮ2LjCte7dNX8GҪ ;K `tw38+hj=/W6!B:uP@\9,%0I50d3ޮ*PFHњ`[qY7]jQ\"jܔh.s -e׈ɬ˜ B0nKqIێ2{IqD0nFsc#\},0k>Wd Ⱥ&6 b!~5 ܞS Ыk.pjM57~ta4 5 rF]ұ5P7ȷlO 􋂸WE }jRqTi2W|-h߶]4~]@ Zɚos2E`j0@%@Y-2ckbO0cwgW>[>s\cr1^>DlhA޻% 棼P"FsRC)hT+,GOV:j*63XBR d60+NO.rpڤ'*PyV@{),P4\HLmUU<+q#{-+8# ޛ|ؔ9FЌְﮞ !nq$)lĹ "b|}+&5[@]5N;WdYLrMmع?/lVnHUִZ sTv?*t=T-\ U+lsҷG2`kv+q)n2"k8O+mA#$T/k1"f ڴ0Ag;eN7Zŷ}8FvՏnˎ*wQړD^#5}޸R=Tf J}cb Rx gI\:\ŎqLW`x"$${aa 8殥"aXzܸQ=х)1Pj 1y F MqpIKm :sRdg((1f A1EV=Z>\UQ;Eҕh9Zcl'hhyyiiSh"Rz"&xQ̙ S! Yfi)s qYđe~mBTJƒE jD:ݡ T(뚺R#E F;UV7ovJ5z TڤbWi9U{h,8QUdf ˛u ̘$,ĖYZ$E–=J>iWc^^U(HqCu)>&v Oqxf10?2O?(9ߌm=jzb.Iyt1 ,? P)b+05-x+^C2 ^)B[h08)$3Ude'@:gU:#Q3ҕf}j'jY[2͔=>-H$4# TmAD2$xC!<}k^۞*GqJ@qU9$SGL3.3n *9r@sr[>N՟ۗӊCF=5(kSP@? H c݁D*\,p2k:65`kNےQZ$Fъʒ[gڴ,S2X:{C"oP:t'"G=*YKћJ[\x+e8"&Dp1Y_gkSMa\.AOXyEU,RfDȩ~rD YM6KU$ *Th QJK˄}*CpTtK,3ҷ$\[++SOm݌VݵgZ&ܸFLS!k*y^a"o8Hn*)"e#m= Q9YHRH\TSWGA[_,0c8X1CHsڣ/O£$=ѷN}*sH*Ul5C'rӖMї}I6j/ӭY"3[GR 0]Jc|1o-Յ#R} p!jF1 7qW%a dNqH&%<2+%X6{RءfW 1[@L6:vz85bs"tZǖXsLVqqeq$!fCc5a5Fk;1HT@s N\۰5djܤV6 8aSfS̴f~5YF,t}fdPVlSy lL*R /8Yn8 XHi,2QRG!8ӞF*m##ƭT,IZl}]ET54i#0V"#V 8p'ԫ>I$y*֖22I $g}C+u_sPZ0k]-v#ҳl`I&D9H€*e%HޝDd3jGl"Z%1VgHQvm,_(5Jx.VV5kGh[rTT29+\8֥X:_>foms ʥ5Ӥ`t,8 +C08yg  9"DTE$1dbkݒ´-m+X{X\sT峘< u1*eڱ6WKm,cW[+ҹ) ,xӥd[t5OVO1_<@3Q+[DLF _"Fr1R{T*U@;P6oGYڽA_ʢI<'ֵn1Yv񚑈oLPX`EC#0jžsUZ ֍bi.lFʞ+ >˝߅nO- P跙V6ϥ^7)b%Ӄ]"q[$akY,NV,x>T+xHbq:*?yk"%9RxfҤKe#+N! gޭqcM2D,A뙺Y8ɪĤǵ\[fwWO,#"Y#8bnɦ\/AM`殡eڦ5 N0DkBi#gRЕf ǵ\=굎R#kWr:Ucf E!V&Hhj#d[hW,YO+SNI5,\{UȩMBH!WdFhUcRhjgVNHoP+m &+"ty3U߅YA*ul"8*Ɏ& /9=i)g$bY@Tx+Z1+ K)9mYQ*+^{['5-xU.jxvq'[Nm I+~>LRH7QCr`ʾ0zfyév+q" '+:=4hD Ջ6p2f-a@GſjΨQp*M-wt1D%=+dcbBH+"MVKK$-cq(eb0qZBAZVvI W8@ZѱaKr #)zi,SƯ O\Ŷɲp9vSs)HH$YKLhiZAfW@ X¨{THBRrT TTL6H_jVo']¸9k2KDyem䍂Ga;@5hJS/SdS`fĝLU' Vq@3@n8Ui,ER z}3V"cd!MDUG5)ʊͼ) W5$HϥV]:K51F {G{=nQWeXhr"!xP=ݩa򧹫ٻE5bwUx1TXB}k%"a.AH$;RG8cR5mR),1ZJH?waRݑ9F3SBa35IJXimR.)\AqNhn{UQKKm ӀTomUU}#gHǑ*NI+\OAN%&|rVEoɩ[QZRI ;$~ aOOz%c!AQIZɜ⩽rn =j R9Zi=]xj6WmZ }]jZ{sy2.r@⡒Eעn[q:.EYybG#QF1V80c3H#A8ǽVPX5/*G>~ܣ>$tڙ>ݸ㊧#J؋p:Q|@Qq 'jj($gOnj%m@=aiI8/TlIF=jh#'X`EDrN j&.xR+Xy22qM1m=M*}*2aHGʸ"5eF8d>wF}Xܐ6U>^*1GWk!ϧj r ! !'D>*Qo'Q\>?u1اb+tx>Ab3ɗ8ۏzx|437{OGiL7dUk˜~T4C`u9TdOEQ$m5wҪ3bC0+Ja*¬=zR m]Xf|qOl)wx% TwRV-Qxݮ[q zT4wI}kYWhZnI$b\yhBMeCvkoN vAx^1YʣV1JSuH1IP9\ꔈ szj 81VSx$S 3ڙ ۧ1T)!{WYliYG{U[8 !@ȭ%7 }*̈́l|~4\D`\&n+WS6  #\>Tjki+pxIa2D3("ڑoјE[Oiuh7nÜ(jp~AҡmEK)$N"QjO*J~si,b0"3_ʈm3RKDiW2pqlqL2=i# gVP }i0F SV_r{6[+XU;kLtZ2gmDcU$du? =M#_)e^j#+:0U= ,b=inAgaxMhj))#9UQ,?lzԒ#78&/lӔrN1JbP[B ԛ|$`VE堸{W2Tݩluۘ͠eqTg%裄l 1N(]qg}Tp l*+1h u ` KWv@R㐮Yhe%*Mv$h֪G1WB~DvO{;TU|Yf>bJбEv]cu*8b1$ϭZPlJc5fAd#bA0!(֮D9YxF*d9#ԛۊlܱ8;j-@Fp$T=EXt0˼ZVrorBb8 zk4fL6 ̤+*jo8hSr1l)1M|T%U n/7].*Hb7SmmGc549 B VV0M8ܢF>%m4Z޴Dr{ThF5y7F*}Et֥~Z'=i،PBF+>yqQU2񊙤<*%9fR< =3XmjAډl;W#>1߸MJfw{bwJ:|h rO:H1j$b!a֡xqv;ujr *4XXwCEU%;4c1j'ǽP1ɹX/Y[XB23Q6cUAؔ`?Ka(9#w֬hw ,vn;i]\-㌑,SMq[Y[Dwz1m$ ]*ϸHlؘa>kV"oj<ϥli,%zpww&bx⣔⢀K+,jbXW?5pY{՟@V{"223MoO XJӉFF:Us]-̘9 )w`Am?0&/ouU$ ЋMY~L GZaHkV* ő'lڱVcT%= S˒jRc84b69Vy0#DӨ#c*eROdjC 1=j =j0I1WJ3T 0g9+V qWX-8]wi5n+g 4|b;p~^y8تU]X@b;ӂ4Rpzk dFS%°w󍐳; JD嶃WdSC3dqUPVGX6G˹qn96I62FPD@A>ՙ5݀ rTc4ƴ11w*&TK{rh $TK2sZ .@w { *m20kQy'[sǜiRV#8B?Cn*:t58]U*f ČkV10$շL V6 9D dqjtL^TqA$*?0c[HF=U$ m>Ve@Y{L͇fp3Unb.*7b@b1)b`z$FhIH=f`fwTmq^mq5ud{,j}@mg$w /^i$60jYd TA#FP) Fy …jؒrqI|:QmՐޘ84*JzBGַy˂U9ng][A&-  G{ ʘ|8ۉbFq\Q zջH{_0P&vL-7u$m+ҝ{΅=k8pXg4 9W'+7m V-(@`IJ+SIq66[E6Ip0MJV<9]qzeObhP38T5vHpQ,PJ-$IV (qKy V^%]Je`j@@9dٲC!D?1TVs*,[.Z0@C\m-`MtV~r=*;bw8A#)sY|".2gjyp;/-hAV!/-3Y}1\ܼao$08&67t|ٽER#"nwKgei @X/A]&[Y ֕&|V^R:b,zqS2otj1bPzR\S c1.g8ܑ֭\ ܐ1io#ޫݧT95>­د}kV :`c\B#dJ/5)T0f>yka$S@ n"pҩ'3Z&W1t,u6H00h 5 b&~:W3u,B|կ[#y7A%kJĖX (#'KX5Cֵ6m.F3~9+M-(N74f8{r9QW}9̎ *+9+! q+2IIJ˲=sP$5d;1ֺM4h_62ÑRbH+Mf_@s>Z<ɹ]E0Knfb&*<ҴB4r8G‚03N3۵Yȩ96Mzta ):c ҨJalRe#jNvUTS@*ҧvmҥ}Ees4XMQ' ⥷;[wcv$,:S+*FMPez-`xjad&{b w"PS;y bYͱQ֠hYMl[qeHkJX}N!f#s.lϭ,w2׼R@&[)sڬJv9*;8p[+܍C\]n (K ׊7*Ĥsg8'|͙?ZIXeL8[ [p&]M$lJ-E W>S]=Emdek6O1d#=*H-*PC&i6 WWJ"98֤Qc*8TJՁ0⢸ 85QVc" JشI1Rr1QqJfyZ({Z2;S-YLX,˜ {R˃j3եdP ʭlX5Bb21`P[c5U@4̃p6!IJn jk\LⲁMW3"mU[HkjAι#buh5rPsU&7U#9h\1ڤu ָ,RE w.})YW8e$;UDPd տ/Usp1 ) jϺ6lLeImFBqn$gS0G#eX b(:sVa#P=:5pZ/!H[%Vu&@ՁDeNXڬP ^1r*ŲaKf#Lp&&=+AX.:U{$cV9Hڠɗ%)'زB8*G{Ӛ :Y~Gv8 W[ BJȍU&d$ezqTd5JA uա'8⢞mT`T1*!Oqb VcWA} T@"=[#5l/T. (zw`r1зsKo.ִ,\Q*[AZ9+B$  <"oABpYbq[|X2ek&19AV6S[ʧol:XV)ػT[yL:pn:U}>馻NB\gTuSU檈%+ڬ$.@8pi^be{8&2Ip6E1U~1>ivKnp3R\U$»_0t&pr SdtQdj G6XX֒E$X78kg ye6 jFNxyqaFwK]lKӥ9t1SDH\8Vtc rqDjq92ad rO01H:=ǻ=({mqJ1$qǵB3v泮 N6ݙH~um1҈N$ !aS*D,UwbDč/Ҷt/=Q!}f01yKK9JI+9\(1*B%1 Յh~ȪqU㹂+FVݣ*ƽu8mRiZl\8Uv2h16+6|϶P1Ipc4ȁr?:RqU`'mڮIs bܷjϸ/\{+Z{8g<*6~ ]ڣ*ҲuڞZuy5[ݼVw}_@kjBgWGw" `8/:ы=)f +B29 gHAB{Շj&ca@#D '#b7R_-Zjbg2P(0 x;OTW ՛f&=ǖ֧Y G2lac,ܚߴHdn+|P3Y80l8aⱵGef1Ud3ߥZ Lezfdo6#iS-ǹWֶA 1Vۻ#QH0@Ȭ5dGPqLe k>+R:|(9VQ78ZMEc"(=oܞ9PIDr|sޚoq3k0 M[Y^OT5kiR2IV>[k~R/:0Eqf5ȮZl'Xc O2#~KGtUַPr?*0FӂjJ`NWp@ۊ@<gҪK\*'wcT#}i- $Jh;=kN/ ugdjPeIW0F[n1(vm0k['5Wj8n T0*I(`sUk+/#V="a.)2G:䪑:e[,Bbac4Ǯ+6Hd7~^ǔzG~"'g'#5t*f!bW ݱ*`΍֑XNuQs[Lb ެGsR1j۶Xf,gt)"-j]NYk pW V}͜sQ[(YGO~j3*1 )Ԟj;GR3PJ&T(qb&`3V=9" 2T&Vbf^*מ8 icz%SqT.-rxڪeb1TkDs[FHjNS5~⢾Z.11U`&9r1ڶʅ8ڹ,@|)juN8ufBxɪJFNJ/WP=ON;b̅R1j [90 8?6*LZc/ T:bɩW,nSR"N:B2U2t -\KƑ3Ab<ڳZ-O;U렓ΈJM)j[sX.kv&GJR<{eъQ*Oj$qs)ajHgXe`fi ڤ?j@Hw3U5XjϪ'\tm!:V,DځMt`8͋|<֨,Z9rd%:]Eϖڞ(x3|d5bITު*#6Y)UXɎ &m'8 ($Cc> qNQzw!dҫ\B8#& DւI $dHW1GT!;I%\q+rU=j1\2{$~sVs\ivURNq[cgbY[^n3u:m9mZ#Ҩ1f%  IOsJtCd?Z|$}jϖ [=)XUH#ӥe- ǎڥvZ4NqjյɈ`cޖ䐼48ÞH. w)yQ72Tʦ8?sYRr7P+Fez譡%=3WtzW@ڲu A#p;W%󌖮' #N7w%N3ǥdArRM}jȩqjձx M[:t`*ť}j=CX'Ҳ琺iHBF@=_pf؆p=VLvgVbalҹ\Iubl^ql ]q+5Õ>R qR8|*0PA^O&8U18T K*P-H-rŗڮ|ZRR0r9͜88#Vf&X9@_9H-P%TeNa`t⫪#TH#?Zc1JRwv|OJDv_֝*+ U6Ӗ tZ]@HkbUa!֦in'j[:&pb*T Ib@$Tq*`qVbx u7<xI֐ X9ԑ8SP3ǼI kE92b+Z ag7agNv-Čbpd۞*,),˛2>z49"Pv߱M_jxvu gL& oYփ3Ɍh]SrQ?hMraH6ŐA8H&VDnnI;8Zeڤ`իY$⤱mrEm(OJqR;@Q:u9ޠgYhj$F"$S,18e= F(5vLSBxLvTsҔ#GVr#*%NO>Z^1T.l ʏʲAR; ֶԄPZِEW1/18WlDόw;ܮ9ebނ"_\e'q 8t0{Eʀ&#LD vǹXdV5ƠGQYwyFOJ sR 1c Ԫ@e#.*[u!Gֵ`k4 ?JpK_5Tp})cѳm=kv uK^l ⷣS5h~u}dc#UI|=jl* N٩(ҙy;\[\޳$),$T1F|V ܐ B`G]vO))å>Or*b8)Gh'hAuzS;W54kŞ8, J`RD62FzVE&3.pdXlU5IǽmAӗ]ٻIϭ>/ch֩]x(mk^S_j+)NjX^@cq[@dj72ubp}27'𩐆Pź{rlCjI,`s¶`a [5G-Q[VlrVESY>mT~ٲ@<SH?.8SX і*xV X)o#30c+z+ `pN~k͙HPJl2fH&,@!5~ &Y Ɔ.)A E43 uvFcj޵ A[X2R-H~tHҳn0ִL0Ӛa3ΞZ5[d|`=S*?s3æ+XJӋ$=kU1vP>T3Zs~cPk6؟79v7DiZ?cr}*ر eZxU.QqMyȟ bh6VԒ  U0W"gΠdKiI`Aȩܹ8#eGм8#*c 쐱95<+@n= B)Q!Fj1,`%G! /\ *1TfU}hѱ=)ۘ [RjriMǽ[V,яƺ.A-Ojܻ`-9_-j 9;ҹ=ۨ N)`K51ZoьONv,xni^M޺DHUTrW A2BsYw.IR4fb4g9Ej[8Z Y7yq5+WGi#۷tiiFjE63!}*[]ҭ'sm_8T:j20faOiF!8#mbq @?1=*(سE]D߀1粊%lVjoN*"#;Ck&]t5ca* wV#g"LTEA,WH<-HWj@5.*[I! geR23Yڒ+XiTm* |'Ozi#R7fծ\tf7ĉ5,*B0`_ߋN/^ <`;`FzUTջkhwhˀEO$n8Zs[8.*u)"f+T`VbNz 5?勎Iз3M*JW=YQUɂMq6[+іyT85 ԍg St0b'YquPgZzli <`SJT5$2*v'i&E4q䞕jJBk$haF=]*21Kh"3VQF:)ɎvYߩܖSr*28U.,c@=*č2>VI#I*SqQCn)e#J[u'Tb)9E#sT.&]~ТˡDzW3qcUKo8oAm/7.)lC,PC;ASڦhZDNd9 c`VvX湋"b]}:d/>n)RO<0Mts:)$z'4yG@_AWX j;F8D 'TX+ԓKB d֖maAiDQk%rx{Ƭ+I@s]f x5vpc'ctD&?goquœsZs?+-u*ǵ=S f^\6-:WV+*1ȰœX:ԌĀ QjT dwAf 5P8VNOVL*ǐ3G,{X92@5sd!bF2 dqpz c8(J(#ϭG$Yw$8>_E6P V\0{0o<֥̅P4)2AZwҭ@*N;W:]fܣXpQT bU6Jaj|*Z(>RX՝j[IqtcvZ0( V'rZV0`ֳ5?1 +wEk&qp@#F+[Ovr+&SK>SWD<{8$6ob1Tn&*8hG7'8ojC[<|dtNƳock d5&c+qһPBF\Fb[9q # EzU@ۈ7 ff;*cW-ix&W“zVMƋ%Aҭř+h0C p]v'TB V"ֵbrS$c>qZv"6G"sڵO b4ɎٔU~{Ҳl@V}xIktK~#~;աau4+(+1V2K~j,WZ_F{uPprwOT5[ʭPvq֪Or9:lolGyE{6p+&n Ȭđ>OOJF1OO1=1V8<5_H3]]SAKwA1SƀBj0J {T70)/v@K]/knip2-8.7.1/share/nip2/data/examples/1_point_mosaic/1pt_mosaic.ws0000644000175000017500000004455713351443023021354 00000000000000 nip2-8.7.1/share/nip2/data/examples/1_point_mosaic/cd2.1.jpg0000644000175000017500000005357013351443023020246 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342 u }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?ѹlgn +5yߠch)F9,9>u"! /<* (x O 18͹Zˍ un`W}zfv}k=NZ1'WVg>8iP3R1b[@i& dG$㏥"nS })H8B?irGmF|@p'8~\ t 4gsF៭6p8R޿!A!Fk3S1xܙ=k'F:85Щ N1od *z<1o J merqWBWAd Ҧ}8pTOՉ XcI/Q}@QUgs1Z7Nsb͔.U{r 5oÜ+[=j7C^qd#U-iۖ/O=+r̤5g+F vF*ĘHYs<{}LbloV t=)DqZLNY F6HܞT^bkb0 GEYiu$w*2}\D -1VYW֫ͧ$U$bV8*#)N.NZC Lłқ(dcTI oX1X1~>QTnpG5+6~jD}H*RG77f@] ]fjWs1I5ry8*3+M*I=]}eW5{K5h jb6Ҭg>i"R0sگ[D˃ʼnU>P巙0 Ү! EVqeV,rw?@YGJvMcN"j)qUX^}B5 +cNeY2حnul+eGJ޹riTZZyXҽŲ1XZ|*qJ0)K5,s85c|`2 6$ pVFmgx5RYvͷZBrTʬpZ!A-!ʊ? OQx8E#ѷd]D3(=kbOOJPq2s)KR4HvܝGd&H=Rk~xWq:MpGcz1еZ܂Ԉª+J=9si>9)x"bPgZi;20jv,c[rn=m?Zhv=bY`,qFzw:m#Ҡreɑr sW5 .^kZ%agx0F:ԗ;-=+Z,kN6d+4 _FK8٣P.܊ڂcq=8 x+OȧC偀P1(b01dxϥQ1KA0qړ,)NfxAW9 kN;G/N*o"䊿0 =`Sh[.H]<{X"G X1*HnF9vͶF*H1sLGn%'bv z;I}(8[Pjp=jV &8tZh$zդEPmYh Q/Lj( iO!Vv *V9S2q#'**J)ZI%O:\bvvǼ Jr/jRw9t*985d*Ȧ[zP"EsZ:t!"l`&|{uC5bs]l !fL`bI qU&B6ǺōF AA5 `$회]F[,vg M* ?0\V=b qȪ2Gr/p{TrI#8"x[ڶ$dlc9]zUG8迋8 3Yc^*;NnG".^d}4,Hr=+j6jGLF*=94y;(^\S@x u>)#VvsVbDNPj{{fnLsV1؀Zmn6֣{ta®*Tڵpڧ5BvSUiJ\ozObk^pTuErB99XYlgG 5^Um 9t[I$qDَ 6C W}rf(;Va@l3Һ==J#4^r 9s](p=ʰ8ziK\ۚ;MK 5V,Ht%>[m$@hm,USiP m߭#jQ}ݥTs>Y.L}jz]ÜhQ˥`rGS1qֿّPm =ThN ?T.01P01PK#bH :P˓ j3K5 K`tF!.YHr.LHlXf_6:Wwܱޙaa"tzSFT+Or$l8($%GC\n *A+&=Gi {欋Cc&8No@Vb?j[Y:LV^xbJO#USb:] Fy7(A=)n0ݔ*vÃJSō3\ðNW 2b 8'Z `Z+t˃ dڄ{ٗ QBriW q]{xVEd\J@QRIYprMmZdeq 1H0}82T<-6ߕ'1TsFA Kx$c3\T1YeUn'`,Xs#&DxyT!JdF3jfݺӉqJ M`Upp=j7pW@H5`D#d*3c8⢖bIU7ORӚJa{CV{FnnkacmҸ0]ȧx}9!x s޺G{r7 Ɏᡓc j亂 Y0<[F@4$!xTfB){%[#s]X{ zWeƩEuvRE+m8hC歟 ̪zbQ"jky%s&wbH"v6HVShQMk\bI giTV'$x1ʓXL25oe[1\f.pV9<` IlsY7lKe)\-Ҝ8 @ÚN!1X̱7QV\%1y7)8*H$*E+1SJC(ڪ^<1Ϩo>LƬ׋ phmm5a>#k%pGf=B\P"pLѧH 6q>g. (J+j)L 5N:sVeZdV]{)try52qX~e5iщ ^*)O@w\#'Ur:Rgnj+~.rTa<κ*pkiجkK К`P*+4Qq1&,B1UbU'vݚ gl{Tdvo4"U:@@ږX|˂{UZӴ>^Xqa q]t8T7,{S-0"$Dq 7*:/iґxK偡ۂ{ӌֈу&躨R޷Ҭ#h9dcmHwH$V,0>i(#2HO q *b}+@qR[9[<stRYI RJM?dYG2}j,%Q*)O1i@("+Xڃl}sVR*Rj@ʮ=+q.ChRm /j94H6;fd0˖W &ivkx(†Id k ?I>wY{Ⱞ2*%RLi֕K49R\Oe/"EM*s[z~>5=pJ0#Zaa^YtJglܻy哒~Mj;rFEEoM0,T;Gg>iG'UJ` Y)Q Ȫ,˴tZ.JTG`U) Lp2CcENk43|;fK!'bj1A*iy`J[Yς]95&F`ܪQqt# MXOW^ٔ\=.H5M4 S-g6$]5i UȬKT`/z],*zӭ4ўr:9ۏjjXQ%q֯Aj6(K9? oqozf28Zɛuδ@ 1֮$.8HJ-KFfl& FxXb6マ+Xڻ g` nA 5pm`7EsnH5s%8kD2zsT|Oc!0q\k#+qVT@ HZ@Gi[Zh0M^N5s,U.#q&kxV Dr7;vk@+2A:T V`s09s$.CG 6ՏC:D0HsU=N3U^)$ljDi1L[bnHH62c=DH>eCZ7Iڑq&5;zYh3<})Ҿt'\PQ7»'f\$-*zt ē֝qV8ji*HqT6*9'81b, lB|9J@{;0 gpxkV"cZ|,iɽ@R9.yi,xP\jш*N3Rқgˡr01\LK/ַ;bJ8`9RPѹ;yꥭ ;¶Qh& XWÓ9Z˅^o5hY.!=nB{$/ayP\Wi_-Ū|˹}륆]dU@둶xzO@#P3`ƪH8l$8] 2EZbOqQ8hɸǥ`yrEU`S335[Hf= Z}Dy됾}[4󬔂3Rܐ+[͕񃎕R<[W#+Ҟ bVs޷pi\vo*b;A8kA9=c ǭ@>Z  Zʻ,01UR;zVA'qi"|JwvO2P^+@vj1;8QxtPw1\> s(j"A<"!p+"dy S$Q*R1ҒkGukG@ z$\*Ai.EI"dvǥP>|G7c86 ە]<9hY2&r)8 I\x$rIŽࠀGw ιrb+%1%(NK a<.<556bbZ\5=*LnQ4;@s֢kFANfÁ6qCX9sO`œĘ}qT'ۚm2 .nT*5Rhw*ECurs] B@aOk £ %S\6w=zzUgdU IڴVRjR(c)6MgjS"rwzܰGZDUBܓ˫BSpzV & au<.Qd_i<YyDE] fCi;AȬ^=*'qКthFp *bQ:%_hWOZ|3rz[L dT4'sgTxx=hde][nَYTzOlIf\sZҒGyܓ=xCcWQ{Vs{$1F {]zסJr#dI$ @Yq۰3ҹf-&95jb9ݵ͸Ȫ7P$qY$+ջw2 ݌R.:S$X58o>iyT`֠$[Q[N]Ap:Vɇ ڕlLONXPxPa9T.y$\ ޢ, gnq&8ZUHNzT689D)ȪwR{k;w.ZuiKq-jid$ւEbӮ6lⰤ&BïjX,emes]-B~U.\g$B#5F[RPEmVGrr`#"Px\Q#Y!er V尸RZh&z/#W=AlugHX#NӖdUmxʸ3VM$tKvknHV}iŵޤ[pˆ #qۛ2n+]-Q@j@Lˏ&6%ksI&Iʴ"#cL7T@ӎ*%IEL128C2̝+ԫ8-J<)-O)4ګ/j&eݴPǤb?*r'TG[9%fC 3qUJ8x%3=*fGII#:9&wF)J!1R$m4F mQɼ=*EV79PL+D'h2015׫=(q(uAN9itED]荺溥m&%mUN39=g?8%~fKʬ9ny_zN M4E~Pj$ =xt9}&5O*DqvmǑV木 0~Cq9MXS҆(OZ<>khSDF ň|cҴ-C804 njTAy(|p On8U@i1P51QRǂ(ė1Rɧ^Hޠ8Xc\lEXw DW3Q$cQĺ!.TtH&4fQFd`H 27(h(>bv$A5&NSma15Xp*'yd (  ubP5202zf^- T;V 4ٯp52H8ٙ 浭+( *;F F'tH5zUE)dC1L7A , r@J㚃R'mү±పcvqCkRƬ|V(Լn3YMsӥUĎ2KcJbRN:*ϵq҈!O[y+V88z c]^b A5nRM=u*OB3HzS!t qL>bpisFySbG5d]De4ֽST&V*]F"'k(}jݸĜjӀTJ@URwH3 :`6Z%UY/,jC\zUIC犣+*y=q3-q - 'O x(4 Umq@V7@'.UX tV9-g%FUm5Z HTҧ{X: Y,2"]>ʈ e,TR9N`ÏJӋU?T1PTJ15^bű#"\Dz*_2"jEh`2 SI)I"Kb)Gܤ$1R1T0VT2]DlgAdSҪ"9sS&;H9bXpGzT"tW9=ix0r҅p_x?ҚK!b\c֥c@ 5W qj<[@$ Ԣ8H#!z)V[$ uO kR.NR %z{)xQ5sTlqg>+mtJFwuUyrCքw*:Q׺{W:FmDXXP$]$.j;XtnO3\`3W 1y#5] kS% k-^|* T`OWlsU|YE5ەj&0R pT徕C œ\*FGJ9a eˁEFbX[Vܴx[Oxn+F_6?:*)Z(3Ӱ"R"2Wm 7bHKj*>^䑊H5"<ꠎ(L3۹db^7dsX:'ܸ=jkT!#r3>^翵h#V9)SSUGf0Y{Oβ@N+DAp9}kGx!GFz;=9W8>j m $}EG8jR2*K&m%dwbzV-$$Q >_zqc`uO׊ǖy!U^Lr{7/SZG=i# ֥ P`yqK@pqRMx"F)~!\.=ރ P$*-[ d-Vu2:j{FghZj V4oPTmN(Ē1An+)*tYyP(6O Tbq OAYZlD;Î%!lgLBpFkB&#<ӯQV``խ+r4g w̼p?6FN=j#/XrˎqVfI!ۅ *>̌vZx8{ N/n00<楌Z捻Ҩv@2=+LIuky+E\2`Ң6ՙsch/B ˘Póc ͛}1T<~ .sMrڜ%sq,)%yǵ^hx*T8;i6esZU֬ejv)lsEMEfA cAݑQɭLqQ6pGT~Aw.&A1MٳֻTH:GQ79V$qXWQܾ@p24Zv,|v~b=+Pgy:MfUq?N*9t*03JpK nMnE05Z| ӴdTqҚ8w9_mK>|V:T%AqLK=dZ$7P=jF= =a+q ¤m8zQ6rxMCO˄ ~tӡ )ӡWǷ.)Q"Ձ,a;iPNsJ s>ZbOcy+㏥3L[iE)5f>\U>@jE`C#aep)%Z\x r蛒mC1pn#PJqrqj{8`UAY0l'Lp1ON cd -A~iYN* ͽVl)4[CH< m1 F7"кoCZ6~(`ڷiokAkYv}jD:O[V SOMQhp@E׆(=i1hdd(BtsiHTo  B~›/[`jTiN5 [Qp=jXHDr)"#c#L$CE1ED.i&lS̠x`pz,LJOE2qN{gކb"ۏjK=*CWDP R#S$]r 3X]-%ccҵ OvҨ]MJKRJniY8ǭO m+B8QcxhBv JW#s}v9# v99tfDŸՋ OjK>թ[yq1ڭtak)zU,6F` o,R;Q/!Җ-f~s!<@Z 94Kw {՘Em1֭Qۿx=*xn 'ZB'G:Qí@e= }۪mbYmaSoG^*t.E| ԩ=1x{UPbpjO(A.n'ڪ@]3*#OQ^X݁GT$+>kXSxˎdRdkAb?:igmr#uc˼Zt%ڡ;u` Z]cҬAxci!ަDSb/L28bÃTcΥZ[U+HՋ4HV.:V(X{Vn*yrN.2 q[LxST< V\8Utćdd} e-oCCXMAKYvG:;92zT7ʄӚlm3@6pO͓V`L Ƭzm\?1=髮\s t7 TvP3ץU 998n}Sm;8mLrGցuvђv[y֡]Bv#$}kwӍO0 j~*2z6H>vE1 isuɓ fM3M.vP*ŀI"dfǽVj~ӂ;ssT#V˔L0ju)FVy ڥKHc[2"@1NM>.vRyS[ܑ*Yai/)YpY" GJ8~uTcRD=jͬ{%$n~& TiJ1k4;ǭFwzر#ei\]/Tf%) <Ȳ9SY(2zuI Nj1w Ӄ],qXL`~muj2@ X[0ݞՍs[WUʞAbQacH#v3% lX\UiJ  +)hTyvIT"d8>7K䪀4C+d;1ӵa C1ZV!gIv P UnSåYXqV>R W<Z` b!.=)0xqa!IĊAbʧRrzK!U*1Z*Z1n٩TF3U]S 1n~t"#hڳX犷 0NõaX`v+[M#F Ocޫr 2=MXfmk@Če3px 5si$Mj62 {c/![$TvB67_z ա /a+*JqҘd<J9=d mXcP9?VYIFxZmҩ WH wν0kcL1_Mh'zRc * |ڌT˷$tW`M:f$Y;pj0*+Dt<Ջ0xM{0 \dd /m#"'6z{dkVR t)=1[M0+.K3Ȼ&^@S Ra4XuOtf Ik& +QUt8Π:p JKi-xv)ɡԜ\I$q\mE8EPqq4iYmWtqһ_6#ֹkO"Mg:{n%WhAzdžǧ41 u D]} Pñ2cypGӥ9[>4-)g4sD,۾v6jWr 9)u$``֚9 rFNrF)E8#Jjd.ҿ:>2ITU V;3x l8;#٩7f8U t 2 `jSkU-!GFojۀ=TFG[#']]-`*C4Nk,L 㚖C#(S@siL31W XwBc8+h*YZi#7dtX&Ge]M:i$dz2x1X>cY,ڝG}[ܲ`b}/q%$ǧ5sew+Ԋ,qYsR:cjoĸ 2G>A\UXࢂ;ԖfTz5PecU GtZG1XΞeGrӣF;Zl`H")6 |E:A=Y 3j[$FܥsԊvkRd)gaӽ[Y?Uk@٩%~3)ٓm `Ϭ ^ 8jTbz[Ke[V-^0砫ex]d.J1R4{8=ڒ.mT<{QpBH$Pu8* QHTF,~bb0=AySQ,E2yvxkCKc#߭k:d~l qSŻ9Sp A85fSBT+>ùޠqiA cV eki407H.`ps޴[/#T-`5]CGcQо1HS"QRΠ lȽmzUZ2N֩_N#pzƹ=b]Uyr[Cc_u` @=)+ƸqS !FPf!dB[˃ #)PMA e,v =R{#֦L5bO4why* }*;,۶z֚Z+lmo Շ\sa4)\֜W_ZY gTqZV:[JzՑDs  tf?c gҢoZVYMFtI@Z.21PysEF)|hk@ 1TdB'H1;!$k2z+.Ӛ$85vATpaMps)Nb O$s$ :V1=2{+ Bs =$PF{A  vFj݌Qk?\.}#GiiޣD"lQ"jլӆwi, V=7t#6>1w2$jEeY85~I26>㓚ՆPsި^iiSAc W3NG 3mVdRARk*uYx Y˾P8h1S[i8淠6cجˉ7ZlH{gҴؑU$Y€=N+J4Fp^x(Jt\(^;;GIX3w>",VhFӚP|cԅ@`3 ֟*Say{&AQKA;tK>CҲ9JSW{qV"rBSȁZrEQ9 U-8R[ZݑqRg^B+ECYS,O5==FzEM'G4,$WbE;G1gk`J4΀棋Qc85~ٔKr##5j=ꭝ]ZWQ`\ٱ٬Y$#9ɧZ 7maQQ\6LJTp^Jj[ve#q[@{VQ%ZZ֊4E]uURp swtN1Va"6PqTG Ցq fnip2-8.7.1/share/nip2/data/examples/1_point_mosaic/cd1.2.jpg0000644000175000017500000005365113351443023020246 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342 u }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?.Fv歳GA r>($0>2=B꼬ZFcZg02jy. 9^f2[%klXcV'4k{w*dPH?S,F1LJ?ֳoڽsVa|¡ =k"IsTR3Q$DW'ZPjݥ7*[5B.ySDة)Vn~_ݨѓ&idVVE=eΤ7Z›O9Z]+b=z]xQYZ,X ;{AзlAE<< N޹VLeVr864p{SSA#xj(-ɢ䠕qZJ|divց&sƝ3.~fnEgjЙXoQs,Nu2XzܪZH\͌]^9RjtP#I0#<]1B.]#G4\})}*&B3UY~lӓO:Ta-^##2TJ28zb Ԧ)Ni`'̌+ƫUFcA+yZ\f.'pf#,JЖ]ќ}*IqjN3[FUi! rsq]^IH8/ɬm!.AxZQO2sz4- ~9a_Ù˙Ժ/pTW=wi%ȧܔ]ýmӨ=}=Kt\2Kjd/3~-8D>p)Pp VҩJɚY9850ՄD1e'@pGJt)UIʏ:/ԃ֭Z%9͎9!BH'UK'9z;(pET5īkD b'Tr rPL8Ϸңu#iQ8⡺W8z,ztS ҆HT9=EU9S8U?[Qf T0kn8ȵjƸjv楂uP#sZ!6*z2#Va}ch3!boY[8eXqx& X$) ȟ\3;N>}J# 31#>fU@U}SLBkdխ݅utlx-Ræ; {[۩=Ma_x"0f~ZRBY̙ޕsS`p)`r96T2*ĬU?GnGҭCpx绎u;qTl JW`V->J=G^@@GZVm|4 H}HIRjT;R9cEWPCM#w+N8 sT vĕҮ*-ʣJ9+˥~Va>Զ܍U|}֩##T:3X OXM?6{\4ШNqV-"m#=_;L35Y Tuu~ Ɇ5^=sfܒvE=*XT&/>x89kk3'Xl]ǯJbjޡ(T^kȥJ͒h׊m"$"|c\ֹytN\XrVqڝg֔=@~5"?;Zl[iBqTu'&?Z%$z]Fd*`xP^v0xzsWR ׭TԐy`jPI[+ 8+WOAt\֯߮6˻Z",Ft:]OLK 1qpX ¹+|㿥>+tVwg`{R*`BVUq~jOD?==Mi#FGZ|g޲.d'NrJЃ o5aۅ=0 g:Wc<}(;T._?>61fH#w8O}i3)fQK \U)qMvB9TfqM4UݞMeai"Ubq޲no0p:ӴنVHaDIB7K5,STګÌ[5[:x)c[OjNoώMXJ8ZYWtM늯jXcz6Qzl'ۼ/sܐTFkvn[$VZҍ#f_ͽXA#2䚚 Nh2jYvtGs[.b{}*v 2+&H2;0A=)HD,KA?He?Z-eH9%".GTUb >بHz)T +>k_ޒCV&xWq{QzS\X]Mجrm&\8@޳, #3B_E-oo }qXӪ(^s6[$ AmfK;H4˷3\~+@?Z%RҒr1Ty3mJ"ps޷W  ֔z TW6 \>(?P ԯ(=)wvJn{V&ElBq 8TBۿҰ`^,`Z}+6a\{un$BFBI`Ұom N+< F եZ|yZ6ZD sNVM>BQ倣8@ȧ֯CppNDj&3*A'` ǐ+ڭ'S62kQS ]O Rǥ;<ةڪ'#e FjB.cZDOJ [HZ T[YNN* ;J*AVeکC>8k3rz%ہ&tᔋU ֟mjMylEJtvk ={Tڿt:AnLmm;?sI6nZ/cu!Q7@+E@yb&Iyi|+40d>+ JƧPGQZg?V%FU̲7sҚ-D(d;EG%+t?Z f3ɩmC$nG4mWBj2F?:k9#F%\.@Q-cb 7cp9HۘX;>yx3w'Y~O\lbUaXr!*]` k\<=UdH@5z @Xdrk ;m&hdϩ}vצj'x;6-XB@)o$@!v{SuT\kseaZVqE>իzF2a;+,'[@# 3VfeU Ʋ.) ipsS`/=EmicWɹ\f|W=L溻WgvWL֥0ְZvKv":[JTFdӦr(2|dxxP^)\FSMu+.qN9 WmbB0T$Ͻ^F8L<To(ݜߊe)dRj7eVp]îzԭp%HǥUjRPʒIwrXֆ`t RzbHid9kmB6Z޵7C[H;H[\ET [͎{>?=Gڼe[eRXaҩAlĂz[ : Б8I.2_zB8 *(P-p3[@k@)nVU]5e\~۠ k+M 5bLiC; gn$XCJ̪Fp+ћP7dWaz``ԣWK d>|A,y3On J*;5#=8SW,j;8VՕz#i׋p?xqZk+Vl _唃hZNՏ#*ԮpxU"F,*5V88[{akl>c4G?β5 <$ UxSde<Ո,o*+RM3LqB?jʷqۭ3UrH jh̤UI3N pf;]\`\0ȓ%$kwnkXQީYj|**8!n̜( w`Z+=A<{HeqOAdIȦ_,3iӽTj̞9Nil|_ҳ{zh2zՔ0^ /.Oz uL2sz9Q"՝6wʒEkzoը]ߍFQ *jƟ{HxUir:VEF"r99P=k@lyPdW9 \H%}yw6LHՂ`k nqW·zhP\I*s]F+FR0qUf#$VȃvVsV$NO?ut9ǵiiVљcO[D.YVc&5,@v|1ߊF9XoCFt<@qU ^ZFDbHX;vfPK|kùA}fmd'Ȼۭhmֱt1Z: 5 뚣\݋$I) t&q֧Pq+:6zIRs[*0+3sVmZ6G5P;{u2Q6|'kOZnIځ̣*jhе=u- W~bJUH9'O|DʣEKl2;EEQԔ`Id5^k-i`55{}4Fm'Q`J.#$zՖx< S~cz!Y=N+yPk,v4kDMEݹN*ͫy4ΐ:cõuc&5'ϯjƾ庿L7|bԃoZv ڠiZFjɬICjnEmXy1L++P( d:U{91TwL܁Ckz*ԭ$biSs}ilU;y3f1֧%AÄ$'Ֆ0{z!/ZϿDNeAWiZgXɴf!Pq޹FBAk"'~:Jbf9Lɔƙ/X݀"ա?elUh3kFPPXzA#$TZS vm;ZOJ0yҳM?r2[ yM3yc<d"Gm;U VuVH9lv’)*ar}+J) FVN8:uKSa%ZTO% ִ*ģcS5+Y7,ODcw&o gWx֜yoVQK;us{͒Y>Xh[ne8vZgyǁ֭-nKh@:JƎIl#i:/<_rE\wpk'Q`J[HaA䊌؟n)!&FI椸pʠ`)0^n`sVJٹ<{W6$On[I֬s'YW'"lmF\}kJ}0{Yy7,簬|A⺭%B85&]9].:)MXL=wPՙŹgew5xa#=EcNbV.I jE2T4?޴tiTMž2V*[ hd8l;M6e#[+Ȫh*:l)TXiCV?oJf޹0e^t"FO+,*ނ,dTM.$Љކ@NCP$dg^9-K'{N3Ϛki BN*^`Ӵ's[Ywo` F%o=j1W2*bk.8yv'a5Nv~6@Gu\=h JMNQcy;Y6ܮr\I#97AMXsaI'u#3X3*EKAk=d>kggݓWBK%\?~v2:ص\]/n{ի#9ֱ&Chw~J1Zs׊3]­=f7SU`O ݑv9\ Pc$Vew 4Vnd$3c͵z-fqڊXqV55uuHqVO6"25t@D@MȮ9 I&N8 E Z=$ҹF+&8乗pjGT@֛kh>rzSl|#t]xS.=ZqVh$E(D`zfE+# ҧ[%ۖ=jYjVXYW:U3ۭ1wz{S܀3T(Tڂ>}},m$.e dM2"diEy+OsSZ@7Vrwc9pn/97aݘP'=)_VtǕ8 uKKp=DF tgwE!p:#|ĞO"`m)oJ(v"'zzҸ`-s8W6cCUSlQId>j~) k*CN ňkl9j}l܋TAlո(88/kh1Su}1M g>( G5i!5#XX/"jյ`5@9 d !ž"$^TgYExAWaǵgߤ*kreZufgL/7Gm>ag~4$7<BF*Xרq8<#sża$[{2;U$W(ygqJ8yu T. ?³1 ˟³g槵$9Zs׽>FڼUBԂ?+%Yn(ޮ61xFQ҂y ^w{>by}z VB*ID5V(*ӟZt}i-+ewZ@/Ys(i6YH}x|BQ[5%~9[DVPAfj W1F}kӄ3YRSGr:U-#;Us,p3]Wۓ֒_^ [>Xt\F;JG|Qq ~лh8<3swr-0)=qϽNrH֜4fbxyxClCɪg=iJڲFMҵmmDz1)b7 HNu؜qC9m@Er߻8⥳Rb`x[2X֫ۉ$ A?Tox>H258[iUpQLA#BX* 9i[2>W=>E8 ^q 6'onگy+FUd8EcL)s]4P*J:tB}L>LxЇǽoƃ;tLgBI|{T4YYϷZ״|sS[#G#91 #ʼhB:/Z9#NI'5[ĹU\qC,`qd\ݼϲ>[kHgXR6tXʄ_jTeI~T[9#i6, W`>)Lr2Z{)XS A'jX9'cbdNM{TVySݪ-8c瓞[ G\~ >ӑ~ ɓ5emϩhS^B$ ~;Qy)oʹ;Jay[szZun$Le|`5clA Z.@QzUin 8,v.@urO 0! M%I<R##o?ATه U :=?:M1LbY0;t踛qPܻ<v:3R$^0 vBFީ&}݇K=M:R]53d=)BsT|ֵdg ැƮd#.pꖒU90HQ0u0Hx ֫\$:uK,A<6S+ |oZlze检UNON*G- ,",p?ZPF9BqQi g jB:Lm#~u)ڛ>ⵥP՝u"ľEnlSrN2k:F "94۬Dg?K;Zr&C,îsD.0WiU{S1ȧ$5j4,8t^]NAjZd"P6=d$U[և˪& k~XdjzbюqYz>v'Ժ?fUM5ÃNܸg+Vz"6xF=޳/8V&&`M)^Aɩt_/Q]&fbXcV&ۃ.<8K%1[MU_w}XOB8ɴ~i(Qךɽi֢isP,kCV zH<}j Or=*U\<.XzTR)y"'*`˲*ZNNqs+q> Kp9p̠c֭!i65vRy>`UVt}p+JDpd*EgjpyA RXR6~oj|3&3Uy 8]@&q:t7 f^ڴY3 [H>IyTR6>Rk1*Opfndp={k]3~UNd'i`;uRx TA=i9ai0hPOF[==h\{fKgVRʹ~uˈY*ƦR0sQw?uy[bg3ZP}"XrE,O֩NE֥,g&&!<x?=T CP89gzs6mî>Y+P#/U+]J5fVU\&/5K3Ӛp#c\HF =괲p㊵dcQO%aL}*LB`jR\gݍRojM9] vH %ۄ8rkZ!nʸUk0KQjL};psҹqȸIUB=1Zu*G$5TM[z󙡒 J}*{I95i-Wy֧-oqIR{-e;2Vp&)UaT/̐{/`U!O+W}*doOzԧ2V[5-d3\ zffIV֠<\1ozװƐ!<+Pzn rw&UY# ~&#Lzm&qktv_J@J̲#ѱQ[wd}my.$wmEq\yT.x’+-ۆ+V lU ׊]P?`m#mX\lLu7# s֯Zޟ;lܩ0#gٜodSp+峞zS$1@H9H+L~3F:TrJQyS$}FHT$H8U&enX,6](K?Z=l+?Z_\nڥ3q2 ++u>/.879Z"*㵝/%AߚԴV؆8. ՛:22,qK{U &+e*|u5!W?ځUVx{צ)=zGC׎`JK֫9* Q|J*N]*.mSU8N;SlqR#?JN0?7K&{uK&Tcɺ' Vd"6-Z37Jeqr{Q(j_9SE3Se sY1ggDy5ۦPy&jl>PXN*J|TZ@5flE p*t0:W&k8YXqU}ibp t:^&,sZ_:JgJ`e}ZڑTbn1oyߞ3mVa2Q|}:U KOz+Eo6f|VYaMF~8Vp#*ykBX0cVMnzֆne3]L#+-zڃb;ݮ}=)!0d[9zr?–Vc嫶"O'o^j\pQU)?lR INi1*c4Qq_XqTU uC)3SoPic1Wd}+>i H ŻXB3T;c\qvG^qO>8ۉ1R>f j 1uIڃ`Z4d{]Y6WDPtQsWQڸwqqyy@&3kf%/͎&*WiH~R nJۿ9*H#z ͔޵fkGWMag!B2y [LnpzTwKVX g*nqjم6=;ԲlۃKXX3k4-ش`ڒ6AWV-taP@kBpə'ǩD6qZL5ŷg#56y 8隬_ %CMyyP-Ԝ+B[eV̊7ǭhAWCk{[pLӃVqOڭV ݫ/CSjۼ8Mؤ`59d.IN-rB䃌֌t2NkBDYKCc<dsΩ'Zy$kJ@Ǒ^Կ6yUT~u,ISZ/m|Sڝ vyniyV1Aܕ&k&?6BOjBn+*5-3qQ nWlzTs3Wm~ \ *+vvsKg9\VUN17> ZrF@8y+o݂G*6IvTg^1i Ddd+WϜS[۬Qj;2Y6n9-ڹ-JVW, ֤[^i Yf^ީ-\uV9kyܶy=sjRMp:H~ g[;UM80OJ$fu8*]X1MOmZhqҬj#lTKedU%NkZ'Ӕ,=hDI^D3H>juKgvYǎG", $8`F}1195wJb7(b5 L<"J8KDj>BWtK- 8Ty #2x[?4g4#/ bZDKƝsqzI=&nxǭ^[y~C0 ]>69ҩ\:\V\pɪ3Kk6 XXV7#Iu=R ŶJ^S}Mts'\ y-~GC֫\`$iA2O#uIK3֛e=:N3#5gSԖ#ZLs#sw !TRnn5{xy⸽bm YjuoԚ jds[vSysrH@y?z>>|j[OĒ86>;2Ǒ)4R),o׊׺rM+"dvo.$E=C$`2W^>^Ңa 9D۟¢A1f^OU4 |fŚ_"`RejI'kY-.I5K1+g'ҙN:}FèN|U#TAB'zΗGp}ipHT*ӢnaHw1)aG5rW`)犾5XFN0HqRaX:Ʃ]ڬ3>1{%΋̥UGQ԰01Ho[*wxNF[\ zRDc bۥq\=Qctt>TcK5Vՙ8U"w3ۆU}9gy.W .tĀ/]$(v˖$IbRHҞb,*7g\OIbѩ yjiF9GsQG9;ӈbiEcȭbۃ2&1[9wi._R ,:d{=D̃w8D=7gqqly*;Y6>nQrx>b"ZTncPN+_MS*ex֟)oXj[`)PRjΠ-AY@uZ.q׮j9lj5;N==@*})O$H7EBHjvdL Jp$yF)I* Zm;GF]6UdUIVGW*jѝăIMb֔)W'֠{h ՋwD~ApzR-Ѵ%_CV.uV_,=&g ŏ$15Vz+?Uh#^l >*&,j@[RXם_]5Ys)0sR5i?sҢ6b''j.U1Um f?^`7Ue>cK wF<2{bn=j .xӗlYZ7Σ#Ҧ ~ʛKQ+`֮$tW-.[in9Mp=ۉYb'sk$t"@ɴ ҿvX+fqΤqVxY8ZHc⻀"㧥9aުOZ 󚍾yFG+BPrIt:Qȩ-DZ˸Z6g]TO߯4|j{>Vh0Z}dr1TqRꍐb'6ę&o\Ջ`ہs#2@n5ܘ\sur H7){I˨WK9?Zp<:9[F 9銻JXw6Lǽnڀ->~!GjŪKp7#ҳMx.-fLvg䍡bfk|ҵ4=3)S/9nE-m\0: ѵ$J!`=*܁U.o#$Gz1VZbOB vRE Lјͻ+" YOGm2@ >Nzִedk،m]ƂGKyۍ*R]8:zf8S%9Z1!?N1U&V'wQF++ReNu9f `["R`pxI38R]HB3ֲc֝`UIWɐ-W"ֺPpq\^ڊ/=h$ ZjY> lsҙlZu@WKL 昰2.'#'+>6,N{W!rf'v4?x=Moqܰ}p= fLT0yms# K=լtb+dUP ^L`UAq7cKzBNv%]58 ZG<Ĺ̐{p,vN+vFB1?h*Ri5#,j(9\u,En7^l-V52ҺD.-Y?-e[Voǵtk<# Z4a52ƕ U}F>ׄ,ԯ04FjPU80 PΠu6,5Y 3uQj>e $֞2(#qu!ϵq ^suVv (JLjqMd%ȉ x3,t4Zi ?\PZ$+n:5 BqWɖU< |VB$iBj ՘-C۰ar*WF$Xi7L.HoKlAqU#,ID{]O)R'94H @8 9imʌoE;Ƅ*~-,:InqgHV p9w%fBoBN(̪EA<.N쳐xGew#үGlC#N+V*~/T.IW'e!ZݮeLTk\E ;92`l "M#A=)4DjżE<5^"IoUb!gnOS+YIQ0f3X\GV8Y&ۖ⠾̔jklqOIs'ңŪeVt;Ufc7+6xGj7VTdָ"Ⱥ ȮM[q=ſjpj398RiZjٹlv5dfϜӵ6xlF8Z&B:U:>4{Ƌ4 VêH>j{PaJ_Z݇"14 *{r=;Tn"㏥Z]7߭h nj҆p<~8  dަ *ZJsuJX\Pt WlfaV&ӭWT"+uElY) (1.<49ozcԴ 3ք@ьQ5n$KҺ+mÌ`shXBZEP_*r|3+Ylf`s.Z%bM@HWm/ܳP1Yb\qYG1I11L{Tz["9Uigy0āJr;u-&T)g=EOfAbMe,Y8I?3pn M$ =&ݦ~UoN҂[|k>]c0=jx]XkN@UUoW99HN1QX*UH-+s]$]NشēҮæZBkϾkZc2'ZrOX ̊T=qR<ڔ}G& m~)݌*y&23Q3IEpC`W|ᷓHgU֟j$#P'z L\OZ G$HmF{ gpHX3A)Ѿ'RsTZc8* r)6R3|n8N ^0f,݀>Aץif4>1R ;UYFeL?v3ک\Y^im,eKކqp9ZsU9^O4'[Sq*d0TټY hYGECr88ְzTZ2WFz8rr Zü 8ߎ)7yLEV#(qLAZW܃ՅpGJ7=MX#H9u9TŒޙtpJ#bp?BAC+(rGZIW#p^xS?w5YWq$@"GTV%T= ÑR)dxJ棕^8z\%6FWvR3`ơڧ&MYӧ-7Jr:UKo򞣚elb\hsE*p{ c3(ޢ9ϽoZZ`qW 'v5nj[\֤6ddVku5v& 1^GJs{{VU˪:v_~8[ҵ$e\zS'ĀJκNitXƧbky8aO9ʟ,p=ǥGA;A~EC nI s[1Mr}oBu0OzUus{J c8t|i2(58 C I=hf %S̊Ap,q!>CgEـn{~ 8*'*`(8ZI5$Ce.ڐǜTqS4O5~P'9IYq'- + ׉tOp14AM*ƳٌڭGў+ ^I}9@ < rRl:WSmK1cҴ&_cҡgұ̼U Ͼe`HRx5=XdWXJйd q;;@\AUՑtDFO\C UR:ZyQe+,MVxٔrĞ-kbv+I~#z$#hћ/!l]L9<jLq׽=d846ȥE'R[p# ښ֡mO=jأM]N\ֺO (]7t28{ vVȏ,޹YM6xb8rz]Ear3QZc:Z܆91]G9)WvZPNE9 #6œRF0i@ 8'5.#K d 銍#Oҝ^}~h=z(洄1!1=)cU9_'5^.x+hH ֵGvi+޵%g7PTos*t Tlz0Ibݸ9)TdzTWT,JTTN=);Zy|dqC$0^$# G{1V5҆y5]#=*Ffw qYR^j&iF"\yá7qM$Aje((P=}d秽Wi6y tFw毢,i*'cRCS/6=ELHT )Zl$ Ÿ-6jͲe-oYXӚvcfoڨ ɉY)!naI0HA5u_4K{A4ԆIYVX`> pI&OL4"N3ҫɬ"58cY}NZqL46x27I4Ѣ}ggʃXNVn;M) .~mv҅lGajd >OOC);HT.ZV]3ܰxS&})=*v`ڦ"A)'ֳ!̔5"bAҕā`jd X:Z7&PTJKum$*jE$Nj(2qZ29r"1RnHcҳAcLVg9楔nPm1Ȏf$=)y|:tK+PG,GZձMIW&N5Gy|ۈ䑁I`bb@+27WOlKcJ&hx +ެ˴?JOqS~`s"}Tp=y4֑qPHʧK(6P=955y;\m\E8508bprƞ⮥-X]7ނ|԰̊e`A(iebP9LXfpŀ'ڬn%ۿJe(UGwÚHYTTRCUfr*ic] { [ۃk3VTfܴEzq RD^( ƹ! !*"+{HQeI@mʟu(ri xNFlgjrvim5i:|qNBS'h*AaXK5h:݉ba'ڸUY T.oi5c#Շw$O$wEkA0$VJLH!z3(7'TWI/9-#6y3LFkFyV0XdN K85j% ֯Qz{Uicr* )GQ5QXdUw T_Wf#5$,:?J>c}*JS+WhwxD,ς?2*Gҟ,O !9cY~ۻ-N*܉ck1gKhNHkcҖ/ޱ兼CT58W'qZZ'6Ue{rjMWEL!7~S~W8f\qՍP2MKmq#D*͖#uf NRKݪLei.zx#SOj5:޵C%펴 *I]y.1}v-c+.Y9p'YbrM5iuCPT[wZvF'M溝=!'n_рb՛,mYDqAYC'W^uXWA;YT5&m<\(f9Zqcm{lG4l#S3n=ZC<lUͼ٧氮ujk.s 4ŐSq4*OE SB!5o j PGV`,s]$v:rEW<|Uˆcַ\ L>uWҲLR I,t&+MV8qi0,61],jTCgx V`Gֹٖ .鱳]!EuHrOcQf2}kdB3]yG"&ၫ~|8DRy\`@֝-+*> rMr̸DDI?vAU;*NjҦ@: (o^fpH8S5jHn$1M|v,*ǿ51 T4ȣ۽j3˱zT5V-'ŻD4妔3sc ˦UQ QaPL3'ۭhi1n:~@{J󧓱 HcJXf巙H͝4'wgϿHblpz񺘎zTXgwCQIcֶ|9/~i̒kqrPsڙ.vgȁg5[[`8't1Mϥ4Jgl@\ʓִO5AU8qڜDkRdڣ޽zRZK!R Fp=i'b'a77>٭)b8+̲jn25 qjj5F܃M}F@;}(YڲKy0USºZጏJ9ݺ/l~!=+=.- J8 L*7zqqVnchZ1W ösXsIGc[e#'i&m$k]!,rk['[ۇd=0=+mNѷݪ03RN|Vk(<if5MlT|HqZrԲh̷.Ѳ^TU=NL.zS,!ځllTҗqbjț|جT}j\6EGBH$POR5j#bN*EB}E$)% "p_95>;xj&M6WpzTxDNÚAZ!29=6G*?05cZ6:s׫ u$52"L[Äj'5ӮN{V=|Ji9f=kn28#5p6HV!WH^^jo̸ȸ ؚЀar&oشJnʠj8k׽O!XA$ gU BeRBCNPfЭivdܑ[vZFHiMl1Yp:Jaj kke5XTNG"56HOoD'ۤKt4p&kY/xPqV]6w_w^rF0khdbI Rk4X =*ݍ?UR3FBXvH&HY,XIeQ:J(V*>3ךI%;BUh"vr:Ui]Ws`p1YMzg=j VmJ1kuBqsRC/L͘"ӚӢ,ナ#XWa<$jq%2D[1>ښ9$z;F[sNldylBH>BB^Z+t*r*CWrI uizUy8im%px#M.qL/?Y(Os]=>TC*)9.)鈁#> /CGWPޣ3V6x8m ܏JaR=ZuJu&pA'򪷗k 6=+[;Z"$5RMY~5eN~.T)PfuPWAI\ hZp`L ~pK1d;lTr:j _'x܉Fz})`;+M$zNCX\ƽG&٤3ҸSvs\4|psFeq+С$ۈ¥GAO7F'ҵ|Gzl Rk!t$^(@qY1-9]a\7ƧJ}j, ⴔ Tl%ϾkN#ڞ%5#;9]O4Dvg5d.FE2OO=j rPStNH*?AZFHNg+PY$v1乸f H'ַtVH7E'9^I}nj|Pw&'ֶXj7jj FMY^q 6^c 5mB=jsUCwp`xQI%Vݫ ӟ²ؙ*4[P#Eqt"M`y5qZK9hOE9ip:TF9u $c#Zꣀ!Bcxh1qJESk`䎵=nqW|=w?t (TTk&qبE^q֌ip>P}*MįJ{pP|f3gg8 ayTp g{S #N@`ri{%]JIqaB ԒI@RoX{p= f^_b}(,fZ[m*(S[sH#lqU  8ɤ 'J 0wd4ˈǰvҠ,t[E$ɢ2qY(L6G=T9WN-3P͝Cz6PWM)BǽGGWm!IS ѧ%*z6#VGx 0nt|PjgdR}qU&lDXZ^d{&p֨\9/z͸S9$֭F+BwqZNTS_ޯڝ(K}+:2^iZq`iOnTfl`sRvs H#V#bGJ\MܬRz{QqԆ3nv嶌=*ZT 0ǭ9 2zq@8r:уYV *FG&Y4f {T䞂3=iLqT785F`Ԋpr iq8櫈~J;TfA c^r-I j񥐍ՋsIϽ(j[3BCYb&x5薉/Xp*QҢ@'jUz-a3} 2٭8=*^jb6y*4p $ֵ8 AS8$`T@rsZ<=>wK ]SNXz`TQFA9 qۦirO: 1#R4G;x+AAҲU%|ضHS8>B0VV1dZ̓犭)`n Ԁg˻YbDؓRFv?N6w̼[G tnN'5MLnz&)JB;yRu>,:~C<Ӯ?~*|qv~x\ Ì`T6|gZh'0e7WI)e@jhԄjPs9yLPO=jbsIvڣtҦ :ԂtMWcS\LZn;Ry9,sbzcҞCdTe 沝Fv柏* 4n?v|.+"cSޒ2΃5b8@v!>d)=Mg]Q{tk\wPȯ) yaZ֌g֏j15#F+}4gR81U={ԗјq\=oPOMkx1X K1l:>(Dw Uoma |nzWFaUsڱ%1#9ry ^lY_$m/c8Wc}ΧUZ:j|RЂ1)e$V,ŇjZެ0~*S!#qR$kM|)ṁsεcPvvFޕu䓁)ǧz!8☭ǥ5XTu5 NFEWmI7'Xߤi{V fGN5Ӝ fֽAcMO11Z1&Ʀ{u{ O5ֲeRT`Jc5}CnI< JƜF$dg &֬[!K k Tᱚ59M[{ԈX+ֲ=zb3YdG3S(98'5@K4#'ҩS"Y m2}؏k*ґ533:dmFcJo9@yP#d{w^-Ԙg+<lssWp 'U&OJuh +EjQ_9-m¯ke=Θ>k~aԷnitPq129Ԍ =Cq4e8aY8$ahWMs,@BȰSV-n$}k^J W8G?!+RB.rA TI sQH*j7 #S?ZBO[iOSQZaNzqT3.r'ʞvTaxjj#'t0yj&f=MGgjVf@JT,E:|Z 4+n)SlF=Zxy q\lnr*5AuukfEJkPfi Ю?YaN:sXZm5`.A~rXkjP9)FGAOX``sF9N@ϭu0ϵU|159]c=jkv\I$Yz`‘ҸqN3;Vaqww7AS!M-ޤۃ*)w9\b1ˁWapF$#˳j˗Rv7rKzֶuQe-'i<ՈM"Y*rhբ@=+N/<;C?Zv(WjfEI ۸ $P~$z$ΫOEo3f5n2*QjfT9{tK;s*ۑmݎANGlRk%ܨ-(;9V*{T@Jiszn/}h/ߕU=~ ē[.pFX|amYxr=9h5(]뚻Ê S,*E0Qq׮x=wN݀xb5ҥ3Z U;Q jhƃI8'ξQ#=kֵ5JFlZ +r53EpiLdc]cnSM8'NgK"O, & JMضPb(U$s f]`Sd*qsn⥸8|F 2\LO106gO3`S>zȥrjDbmגOZ[k3hmzdl95ie#zgU$l>ŵZv6'TfAbxrܶJ֔~p9隩?bW,+6O L犯j\Jeա86 aԶܐv\YZ ٲ'5YyXsZ1V*$9&JrzfG=N쑃N4|!%D¸kRAcךu+4:G3ylߥVrb8$n$.nm$^MtmFN` 23ˁ T. ۓV"{rp);)^i<7zM1a9lS`2WWLVVxJBgy]&q+@zBWn 뚳bJcoDc[]wAA=(ALWE&8A@gi *G4*PBoڒ{8D2zTV8GZHepsJֳ֚mdnvTi X&OCU9ӤgyR+ɵ%JVᑀ>TXƯC4[FkJyQVFUZ =&R@fpHQUIҲn/3Yx_&=Gzt[pKItb㊞(GN;OZH vKlsڡ`wvc-|YZݜל$\2:f\9T)j]">ՠhVrւi#<JrO8S/!hѐ95 Rz֕=i/u;[b@VFo6j]dQW+ޖ6 i:l$}ɑ0zlĄ0M=AsVL#l"K沯H=*(-h%vդ\Ub?Mo;皕3UEo)QVV($¶:SFpOK`a :7XI>Z}֥G\V\SPbK]r+WAeJr8&ڲ݀ygGj[lx2|]:`[VOJFN=j(:dI!'vk.X]*I荂5s͎eï=єZV +2'ڑ|!=?:!HG EC93~8R"G,ȧq'p3S$T*ؒKmllYt؞BFPt* 5'-Pw;=*3\) <%t;h27V'N`$Tr=+Q;qUs/W1Ik8Qֹ Op(= GgbN})&i1J,=R5;r0sNzm=:WGo;JבUh!H2c=Di+Vd*գVXRFE5a9FlO#&ciKٍvArt~_SR$&atP~.RiyJ~E {Wk7:5A q&l8f#bxn݁ ؎bQ<}M'5h[&̑RV"1ڷFT M+~uYNтAO\zT9cp~r+f&p;{-N,r(lcP8 u4w LxpOw.mPQhҴG# ׸yk! ^Z#-!}HFTK?p}ijȶYȻFeH #2]XXJ,SҢ*ʼnګZɇk=yE;rO2Uޢ. eG#f:V\tL˻>8cbG*:V1iå*WȊmTR`Ȥ1PKWVR<$dr*dD$UR$b-B` s:$b2*k? dGf dYS8MMqH-F!=Z5j}6${ǚ5xD=P4Z(u^qkv<C u Q5)1Rީk`u c5SFjg#i!YLODW`'=$IRdB 0^I2pn[2j 3IsrCzX$X#oZW3p{T[|#Y{UF1TL?Ҹ)̕;|vRS;xi Aܷ֩Jԛf@YCSѸYd5%lVvFˀ1V8QRBʹv~ٺ}ιu}x>\JӂOJ#ӥiC0(9)L(4縊nՍu˃y.uS\Zc{S[ؼ5|RdH1ެIkZrxyΞ1"[qVv>K)MlRtf Y gVNbw3⴬A(EM 9N Čcgn:tpO iBɭ;7{KВ$U#hImpUKdNqZ+9|9R(}+jQirQHF[fⷭ- Rw3SVu%Vcs^G"ZzۜcMLyӛsJ[ү 1NE0q^m'H]Zڝ9<ӂ~T}8J|Z#yMU,Y:֥lm'ZG*Zo3sޙpgz hj|qTUiٜC`!;J5&۩tyr3* U"1[Vuن`;VV1eo6 Ƿ5 /UMq7ٞVJF÷sy*s+6v7HFNxItA|YT{y8Jgpr3:|Jy$~iP*!a*w-aǓzַ0;73Y7chx$kD-"&G{VUǿXu)KGEFPQ*UF!Tj /&$R[w;IelyDYq&Jf֭b*7*b Qsߥf0_1W-J0MLd4{Tw-p)\[A>$aP֩7 %TV[vp*qw*!U亖Ls@^=>A9$ϳFaE9ck&+;@1OqYHRHWaj Њ=cV}m;g֧f,kEt@SH3ZQRV<6;W939ǫ~ف" ng]]? A |HD[{'&S Fޣ5$0IQײhAb2 [뵕,&#jݭL|?*" pG#Rqlۋ*J+ j4sտ\cQ #1>d9 p4VV]&R[[3tVB 5}+:b4)2IJk.eksN eyUjc,: ȑ$w|^&DȐXFCn&G^K>軕J͸9Nˇ&}>o+&{o|뀸sLqZɋM8ge As]q,QYڙZ4ʋA͌$Aہڪ0AϭI8zG$zVPz!Es}0EaY^LZ*6R~FiwNrUi]::B* jUUI?$RUn$ݜ{Uyf ?ɽ sָZLlm@:ofا=G89ڱ9Pzs?Js7{P VlAw"jڴX@ju+O rG$b };#HcO>yu&p=kS,'4ʁ:2X*հ2>hV#*Ӭ@ՆX lfk[yk}Y[oz$Gymy<֚Y@U\j#'9ݞhx-pDI,sXM4qɭ[{sV#ԄXE|(d8YGϹFkPՕ]䚆?jE*ӊ{sҲľl$֜aQ8ޜd ohA4 1Op>YH\Ո\5x'֗RŸ6i1$0ooEXyc 88Y21E6`֌NN+7TKoOXs"y8OA{SO{\ بbiēlH8n/CUeuVr+ 5Xrm,{ـB߅G s|#`q[Ix`sL5k~G$UӢ>$,q+.i;wT9&Q X)5hjJha%PYfPToAL}Jg9'N9 niuR;,Is.ՌtA sH!dbH;0YҺQ8隧w|*J`Wl7b2qvU1R\sqY!uݍz]RۚVTo0Afď;qַ,(oZԶsYvTpL) ҫJBrygb v{ ykR)#?-f9"-ӶjҁRr#YWY'[ʻ?uhQF=+:QFGT^W$ Tn ܧ&&µ!XI]&UM 5s)P S5pj$#z :}*[+_׵i-A[< skI:Pders[ SS۱ǭc vN5$P1R>T"D#޳YrGji n_7ǂ+TqicEG=2: {b!u2[ǂ9mSl78$dzܢAXwI&(Hmf=i|ݼ{Tz)rzζS<ǒ+s4AU2\|Zک]%ƟMInpQZ9p8&[g 8ɍO\W=5v,LQ%בVvBoj֝J P{^}).@ Ҭ;cڍq˻(9z/-28oR͹oz\}iMgֹfʶ'qLW}6 n5Dq >ԁ~lsTz֥ylOJ/a_(!JY(Uy;Fq@&늦ZLjWmіnNNMKk>+_⳦ؓư '5 9vm$uvߜS.h*{Vt&0KsWmw拍lcQƛkGï9"'P@76jXQ8Bp*;VM,J82({vG8':(E|zl-bK)DK9,kJ"Gp} kI<>Qc;V֋gPu ]U$-c5FMD{UCy,Gj!n9sH7r*,6:VhNA"{DUjšE8}i0D֫Aך}?N 5g! lцG fsOt a=J Ipު"&T2ې<֘ԌHWRlN TmoOZ1=>i9LVމ+8?OzxxϽf31}Nb.j=ASivL{ =*O:| c=+n k^qQ jbT֫ܳ1 y^^ZV89aϽkG vJ1½wrҀ0'6@7vpsE{88r*D.Ó9T`֕[cU•ՋkGU88N9*& ՐukomnKب~r͍Q }iAEFF <+rMB|N3v*Kb:ր ʨ{$  >&rU#cJx֬cye $[7j9'- RFzm)&*!9~mwQǜ+C$ .1JՠMTMrj׵[cr3oQј³0SsZ6)\,x8sSI֥aOݎ+^ħ>]G&c=8#%:PߎjшyY15#[ph*&[aH>Wm6ż43O른VWQ)6)oGdvbr_tLV`bIo"1qL$@(V[:|)'ֶHa tđ\Ěc] -Yzeœ [b>.XR t= .t bv(I4xGkӢ晩MgQ=GҮ͎ilfH%GnJ}19![{pߚy9M>Զq,+UXTd.@=U !<֥f֬q*ެF5+L('D̤sQϐ:n9U :\EAҵ$wy#Y#85Tc?ZKY- #ڬ5ɦI9pDTJ%6JDI8)]¹ j*Q[N0s+ZO*0 sZ+{ 2188mU?n>a=Y|=iҐGQܹbX:1I{VuD|\V+;F\n,yk7=i[#Ƥ4<%y5*xAbZٵqۺ`R7dv]Vkv%Y3})`u&T3jZZ\ܖ2=*jO<˸t=0*[m/;?riNze]% $e˒sֺ]>bw>0:dq\Zo yc 4v?5w(.N+͓{9TU+4簭]ZʔgճO.)rsqJ(zŻh[<~5p<|)9P$&JI+B>ZUXn /]I:T˰@q~$ԣǖqG-I>ϜR=sS(E+Va5Bol*SkF'm \r+/[Kun n6I&{KuyVW[=_1H2>ԱaA-ؿm}*톗!W fhGjydC\9Pj ]EtҴN &w޹v8R$dOбʷPzk;VƩ۫pJh⦂ 0qO}2U`]8kBiB#OZOFҬ[Y_T @YU*bhPzK3Qp Y5Rn\ fvg^[@?68"vF$L~5jݭ2U9IV܆a֏@zwx8qYi8,;W#UH3\яCu4Q~6$H$1BƝ$MwNǒƪO3(=xI.qigv><VlcX\FniFAɮIS5z(ЌlT,v@ Ƴ-YWe^H;SmdYn:+H#نKՉ _- #ڛb) AZev7fs RX!>Sf]sk 甙\q5 *8y=|֦4wq8r `bvV{S$EqZF#0Ǹ䞸W4)<H~犮'<ڴ,4 z_i)hܚԁ@ p*y@g,P1!ZC_N8׵x gOrskUezU9a`;U{Wtۨ0@DrK(ȫ6޵me,1$jmLrOZc$E3+FV'Rힹ4{!RZ&XCwܗ#'2jeb7ݲyp"9rT~thI9!duL{UME=cZ ڸ=*XT-PUK/e|cӌr4w qk#M>pMUPX*J45ۤ1sJbrjLrsW|p*QA,.|ZԪW߭RfyS:>1$wV*ź<~Гa<}j\'<mFe}kv͖+rLVm@=k CI)%U>eR8MbG5MpW$,7J3dS|HZS :E%kK`0U9T1ҦyQT;sG!NS)2R'~)';,Q[|?ڸlsH5^/czJIfy[8#OS>cQT56(Zl EuvBV\*jrT\n}O*Y U ֱ=u>`^Dɂ u ̓ީj >ҳ+0^‌` g}ڣlVt٢s1ҵ=6%i7A 2qץm4+1܁5s'mn5;Tpk?ipp*h#=G]8r!cߥ#M&E^భhJxRI8۳T1eܷ83K&zT'rx5`L6gUsUjF*VxҹklMR[?/qjYؤ@*6[ F=V%UqDsRỷ!i?w0}*zQJ-‘&g*I!rEsP`:U'H[sO’{M皧h)|U_hTYi5g\ȥsRXV\&c>-[O5g@coZeގ\&?xPGjl`pHYKfFd*QRI*U֪3y<֭p-ҽ@fXcf=U[i̒st6Uʥ\J N`T.f1vҭyrA'ZfVbc\JM'jl?N#ܻ@-VU,ju*iq9,<)R3S9MWSVIkC-kgM@Z | hPMSi#8֥ġ2OJS΢i[nK8$B3\N}HF mZi!,kVy\UF[Pc=OoAg5wnj6*oV#iUʒ=皹%e0PgqE&H\fn&8;GqV佩BNGSRTT5HG< T*jz'&VA u7dvSp18"qqR--XV^EL{s\Sby5aj~qWդp[.;գoj8V8-+pg`kX Fj&Z%95zI1J MY:R$;VN'&fÑ["y|ibS;;xLAO \f?QPy O4W 1#8P],yȮ;RF :h>krUR"Zϵ(!'>Ϯ)#r3 (n{3Xҏ?Z 4*w~T8i Y9ݦJuO?iAYn7.ǭV('ӊu2=RkuIb%޳tRXs[h )ڢՕBh) cm.w:~=dVs*4|M>+ۚ@Cg_Mf` R өRu?N41$vYҵD1 %琎BT7@z֖J')c"FM3ZVF`g`jнNz5j$j$)f tHa.SOcLUXWڋr[5#sȭύ=O󩡼q{,GvxU Ƭ-؋$NKTá4+*ӢIlNdH緐o޺{ E.#RҨrE_1ڪIW|sR"2k6K75N =5]\l'&0kNS(6N=*ƗmA't6J<4˻13dt"SMt{Ygj7k.rVWRJ⡂;`kD^dq H%`ii+T,zջhpI{$ k>Hpzn2m>n'=Y/AS xU9"ބ1KM_8ոbVp=MFx=EW{WZwBsV,݀Gvۥ1zT v ޢtܸYWP֨ʏaTePN*Ja/S4;8N[<^{VE!1 AVj:$Jw4& ˂XkTZMS-JI`(N[ڋ( e,ASNF*:ս?RSրsfqF^28Y4@ŋҪ\%&im$VBZh 8 ʢvWF V34$*kzX"UTb2\}kN=8"&n )Cv^HyFsZ5Xuv`F $VkO$Va\|Zm[lx&N8#œj͵,^TӡbT\~TJ< G8dQ sץ`I}_<0=2R4"۟zT=u+zF/CP .IRO`) }bۀ.IjDx@E+@"~LvWWSBdRFr3KbZ1x7vw6ҁҪͤ6F9%sr.zza%sRTEoMIxGv_rĒk@yǥqF.sj TT~3k{M14ۛ!m8\_V@%N>܋p\ֶE> _Yhb:vH9u$+y=mi,rHR:(r+&;!G:}ӓ59Y!@Vai.Ch^TnnVKe}j¸15$°ڭ}=jxdym_"8mhtuInpM`'gZ20I5Cy03[<Ҩ\ET${{'VeוOY3I&,)n%TA2 0>׮0E[Pbn^T.Ip=)2{SDGdU=OY{ nِӭ:;)["mUspqOt!2442輚IN Kۅr s/XڤIHYʐkץ*'4)=VE^}2d|dg )KU8Koly\>\MmXp RjDJDkFzӗOIǥ2cB۱Tai=E[k)"WeFpEE=Ă=IaQ̣q9oE<@o655:qӥdܽvvGVd-A mƒ曂0Z]pZ#F*9 ^ݪX8xvhw|ZEۀ?Ju0 UӮ±ܹ )o*@'i2$KtBP-ӊf]8D;Osڠ!ϵHVbS#pqZhg9I1SDTZ"14zjtnŒX& PP:R@ @@q6 V\jMy v51b٤He8qi,D:־vʢ2O =kUUN7UkA4dā屹*AlEwk&?"e#ϿD9BHWީ2$ZӴ(OJ}J)9OU7XE=+JBCݫ[A*%K,qӊ_Y~ucpxXlE'Jf:d -.H<={b$/ !+F HH8:o>Ȩ| +mvd!u8Qy=kBjI-g-jEZC60ib[ 2ke du)&\.׏9sqH)V@.O &[-QM XcmD< ~p$ T܀HG}i$R{TI&82\g]s]d0X4DX9id"b3ЛM5SNHw}Ue ]@dj/ZH'-5 zR*EԦRyj+ْUv"n|ujO ÌvL݃Q,~bQc 3qz|bk&<ZPtM}n88T7A/?][<xr;A7֝(\E1\ {V^v(hT&P8WHU\BVVVO]:I[8JnknUGJ&Uv}gI*w֜򞧭'5ch( *~qn?(V^#SBcqL_vMG!qҖS _j$˖];I#ssWR\z<0Aork=ct\µ"gc 7;H6c"+!\V0Sҳna(M-i})Sa'Q%tW:Ĺ=OJĸҬ[Yp8?hWWL*ڲ8yY$˰zÜsKy''[0Q|Ո[kQO$5Kmek"Km%ʝos% {{^\JTu sqKZ;U*ފaSyjS>W)_rs^!PTֺh41 R{Ԣ%`S5zVmVc 1ҳ1 buvELYV\:Č x qwzf0c32޳zcЊFBbsz#{R@BgXY:E8%Þ⦐78\,ZE26U ع )T3W'z|=W#|0:p y7zȼ$UhM*Ԟp@fMYŌVӣ ̧ǥc,oc`rEL2"IXLaA$k 4VCZ:|w1TIr$b<.kؕ;Mcb]T6JLܑRi']5dYUzԡJ+ׁL c5=0D6HÜc xy2k:B?J˒PyP #ܘeKp*x. KyXVmq! T+|$Q$gjp'|2ӜR!gsCp?‘ P?N'+Vx0y`ZĠ^+O9PVbt ^(XzO;ű`cU (,Ԣj'ךX<դm \<C-ҫHR4y$ [L{7,N*EH)šКeZabXTvhyJ9vK ~lsQ\&CUO>TGqڿ28 jF}@mL5mQ5Byi7,h!.y$Ӷg*rCƫKze|YO>]ǰ1Z& ?<)y 0##`VE'ZT=;y sSWڸkXyP^l{aPΧr5ocqZ̒9SLfcu8ʳ ױNzkGd+(! ߭ '{Ew;>lW2A1T^-F9m*FJY .}kJȀ׭j$A87,Hn>3^byj`+\9U6۟MDr9ǽJPk~5,+zBCmkB&߃*F0NF)i£x*YqtHoZ RnOV׎TtCQLlp8*H$Ti$sZtn@Wehԑ+r5cˌ=i<[ad$o!Fs=j`V4$Ա**ZkȴEnj#qIcNG1:2*ոHrJJX7q7"L1L_Z,Zܜģ 2ݍ +ي!wTIiϤh/! p+J$kP(E :tMg UN?&ϓ7ԡAwe5,\4w8G5c~Ǵ1W+T!qi oټr<\^/2>jgmc*! P gh̑`Ҩ@o4`upY޹&ޙݚq7}*78\f]˴5Tb=OlSfUA* 6Xmǽ?R3U[ <31˧H\Ʉ.zm{V]|IK17׫X-cX@p( 1U BBG$+QAio=V!uLMK~2z~F\85;К* 1ّQ gls>qM`^/je~+r}jK&T-%a k,c<9sZ<+2|ÜT(F9ZKn 0>A a]Jޭi׬M5dZEN+Wy5LE\G c܍Yr0'.`bƷm5yU~uctO֟$H>h0دD]nֲm0cT8^*Uo@XUGWyYZJnO6"*z _nip2-8.7.1/share/nip2/data/examples/1_point_mosaic/cd4.1.jpg0000644000175000017500000005312013351443023020237 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342 u }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?#G50F+678W?wb1VO͊F<+v;`bd UFf%kXE=UHɐhC<]*67SD G*O#˜4Dql%Ș*?Jz)݁80r $Qlqea:ŏCQK *KCs51_j=ĐHzRLv㎢np ϻ G=MHœO4Nܜ{~U]H"`)ҡ%UnڻRȪwq=A5jb\`#23a֚=1L]Jڜur7 ڔaqSA[[̎a9uڂ91LjA78^jhaS.MhAn.@QUe3D*s~RWLZk^*K4!&H@ nnbM 3{ 0pFi0JΙ}9! [ u(+4Xy1[[$K @HzUqTqm@ 6B:i/wW}wdQ4ڠ3 峀*lvj>*q6ÌPI_Li2OJm `5*94Q17ݧI`ڴHdY5NFڲ"%⋓pF~N5 Uc<{EIYd2 ynjXZHq]n VzLxVj2} «k:][͓ #r\cg_kۡZd&aRd9vwN1nY[U 9qV% (qO²ЃUYdf|G*A#"\4d d،SFM>䆃+>_( 69 L2.e+d ϖ >46nXRhr*CQUkoݗN->knr: I܆qUٙ]ҵ,* $1Qq3C[Qc`*L|q\M3WEc0j+$qI>YAK94f#T;#.V(I/&qگ QJEqemrxKܒcN⣛Gq̣Thn'm6M*2? EHڳlV᰼`/JݸG'R&pȧln.]ZT9ջ=9W[r[Ҧۅp IP]rk`,i)ǡwEaȌNkUc$0sˉ9T`xL bȯ=jTq>uhUYi6T4OǽClG=L3E]i:W95݂Oj޴0EkA<{@Yc5o QQR 9sRl'*NFdF9g=jE9L7zi҅~@!F1$q$`V{ξiq^EWU*qU1;5< ʀ244Gn%e:RB܎Ս -w+3}R(%Ғ+eF:T ``Uc#'Go X5,Ui` i#Z /N, V[ƧJ [( Lp PTM(#gᐤlL 1o{:TѪ#&$.WKd s^~\ga  zukfg1\uWYS)C _',V4w!74kVB e`5MnǭYXe 5( 5RdZ݈̚ܠsYnZT@r0k[0dmR$dU8wTeYEhJHsYr>g< XUBmPG: XԌffHip3W3_ 3XC5q{f .2 *z G/'=bQm3Beup>̠8[#G gO6k*TbmԨFIc)&=EB[rW)GTv:?gt:a1q>t:e?8"x'+PEH6H5J{$qYS%=)E@=+Lx,$zRF*ӌ{5hcrˌVcUZ! @ Nwn#`7*nFU[+E? r*َ&W9td[ϔg+YOl7.}{߉0PXUYpv%8Ojւ,FiK ʒo$ ⥑VHCXԣ9^|e皎X(lcoSZVڬW.E^KÚ UmqU՛;6ҧ# { f\B|03M tqe31ލ"C#>ZOd$p3MSZqҕqҹ;ccTʪ@CC8Ys"9VyZ.I*I& U(P͊xjaHy@늧q{ &8)<O1\qD6*xj+ӓLI$CⳞ#oePvPޫ 2{Ö 0Ӑ+{uP8AlqQ-ٿJ:M95d-p@t(6AA$USpz@=<ԿdU^5V[V/cNH#Ps&j֭{K#9*ንo] >xS9zm~uHcZ>rmF9U皶(6Xd89jQ dw>FɩFAA $ʠw*7OL5jSnި&UPg/ҠX.7+ S}"(L5v DG%QFRF<•P:VsޥQ.ӓZ'o>nJW1Sd1⮉*#O+Ǒ)'W#s)CtuJ1e噂Os]F>dVĿ!n1T`&I2qZon\j xɧ)za3o$^b ,{s׭6aKNY12* |#*O3MTs@SڪK̈Q=ngf0ˎ2*aji.ثi'*=iVUsE8Q+ϽX ]X©Haˀ*%UL& [6y=M@"vFqUd +L^ȸUpHii1 y4%oE},M#j0j#ƍg5bR7?1SWLh6{\W- |20=GLa3K%ʌssQC.sVjq&rq8X;l䶀(k6]R4$UcbemG j75D0ǥ>E Fd"ESߊpGLU;XW)ejv5>vV@&܀dcޟj@c}j BFF~Lÿ51U;k;J9*xZP#ȓu5bʵ*begTX cљVLFﴸ+ pVu֢oUKSp)D7 &xW=}]fd Pic#x*wˑ{֜S+cMHӵe<[Wp b`aTq6FJ`ǧJ͖׀*#L`P7(튪!{`OJd\EW0ŝ8ܦ2j\ճS}"UfLÊS83QeqZ6F0Fjn*kt1"s)kVhmnm߷U3_D m" BRm~gQ`sB3 lsK8[HXxBȻhQm+WO ҒFW)FO)\T>(Yzո{=|񞵶I#5v)VBI/jżn LؤTžC#k0T|A&sުW'5v;,u>NьuIiC2WKjPXZIJpcqM0@ V6**槷P\> V{u'`犢JI |֍JʼJ{KV=Ҵ 9ܡsz0 gF9v qC8EkF[o} #}i$ه}jsR e֑#r)ɧ͂LNv4n@LPВ8ۂ PG@ѤIVR*FSrI{(G*Ԉd~U61i$QҪא*OUUdQJȼrȬ{!d~̗̄9+Uހdb-X%@I 1TFkLY@*QԦұQhe`ijQ!SJcm V*VdAtcY}q8)pWX0Vtټ܎2) C֚yY-ҩ3ܐʇK$y}3[P+ HU$@qh&3ڴѼ d {P-K ;f ZE&s"!95Cd?ݦ+Ndb٬cT-pW".GnˊɚLQ,Lj{yvbK: eۿީ4 V:%xmf*q*'ԣXq\I$ j \8䊰8`v)>BF*17AJqsPL~B? iv`4+qˮ&=85d!5#)=>@U${"TBp* fĖ)*R4dWOZcq#:}fW9WthzƵ&8\&5i@xUƶᔏsXgQbTB2RwIS&MV3rS:AM>w++ZR<`ll"x tI'U2r7/VӞZH˸QOCsɂ=*H⨢:p>_QU)#!Y3pS.$Ӛ׷GZ1߲*<ӟS018D9v,SfC %⧒J+\~O v+,6;R*aɩ&8ZǗۚB2:1x=+*dɪr"='2G1֯i3v+PWV0F=I"@ M^4*ݭ]kNA*xhFc#$8?9n*O)G< u5W sTo] ʦ9k^ɝ'U8[0>9{U$Xr*h1Ҩ_Yt> Z-Pc5AX1r03ֶ| d*PsҥYOpaNŁ\,>6 \VwgPteunvs6u7ҭjyv3ғEȨ<@G=9'qX1$gs8ԘZ 6f<`3yqdseek6Eo0x`#ޢuLTP3p{ 27ˑ)Qԫp _cr6m:#_ʛ,V/aT.ҫ@r(W,zTrI#ӡiy}+n 6_:DpGMol|i.<6VH<ͼ c1Qُ݁R8lHWSXwWGNT %d5{ +YCiڳ}ֺ8 Jpz`VEv X2EhnfFrSme }}+KM%b,Jc&#gMт1Ylґ\ɪ2E< q@@S&«JBqpʜ2M#m?[~w=qYڬdꀌ{BBC7KČL U4,ﵫ3"9ڷJF;O %qK%qDS ҪMDp+{Ukr`OD95wd#4ZŰ}*aZ@_b(PUXS'޳bPG u(B{ #EAS'i6qެfQki&o4Ō Au2Kdb%2Yӭ0Ɇ qQ'зBڤ7oe{ n:zn.}*TjA H8.#t$(j5!-]@ \e63eے"fUvĠYB.*2rqϭ]i@g56Ӛ{inVr$f @n*am·ʸK[Z5ݽMhj +x,5`l.*AkAuiߖE.*"=GyU?Vgwp)4"0*Q $g$`֣+MTOjٶӝVp`412jX@ O=x+:l ݊úeWnX qV m Acj>_- 3`իkFf,@jtH1j ST6ta˞9 UN;SQ4|ݪ6eI]yR.H'2.qR4ѐqҡH7̸椑IK G[BʁAQX̠քsFfT`UsL^ -;q4!ǨV@i?6:vsS}(=5id%>ԾW15zI2^ydhr;SB=jQh6ntd mOJ=f[5֛r*d#@_Z)XjҤЇB@|z6vQkZ UhBj'Ck'N ~xǭI䓎;Wr8eەF+Wzu(c3ZVJ5*iw)pU &6*b95j\3[Tq(+{}̮3alF*Ec)DYfH G(Gݡx\@wc#57CW3XMlns3Pr@'T,PH ҹ V*>o%XlUb+J#ǓW$.G$b_T.61^+GKoֵ9"*?*5=x*\֝n?t9h7qi,1{QqC'5\@)UrGN(u n,%NUgI17 `zVϞIBlֶW\f,b * 8UKQ8\e͛elv0Xf"dA%uW8 ]. DU#Zxcڠ;Z%hՉt@{V[f>sLc6ں ) ˓Ҧx65^K9Aj}sVd)ڡmI $ sY7WCn*9$dD_6L&8{eETߊcNj?*z3b@"`N=)Ht昃`NEB[(0FF$bB(?=9H )g* 8ʝȪJj)fOYMIKSZx\`Ͻ5HrHM\Ӯژ܏jsqZTN+lQzhop=GMD2-Hq2cJg)sjGG:nDO-b0G5W4Y=*V; ؔgT6ϭg&vsI,$UJH$3~m4T5qޭ@8}Cz~u*qhi>Tr1ҡLgl68xR_Ӡ\;k23Ҵ5@2L` pU gE?{qJ8(P89@|0H3XRͧB"=*խǽt}`R_"BWÆ*D8s֌  \^MqqNb0:UINIZ irȥE{tB>hm:R\Ѹg<~u#}1a1LU8%V(X4.Z3⠒0YwV;fOk28Uiɻt劎BSh(@Z cU#cO%,rsO- 88м?Vm#JI tѷqɮ-U #ˏ9Ρ2FjպUN:ʠ<☓ǐա@ɩ(,X«ps{3SKdcM~Qޭb =kR*Ƌ6N:bNk@qҚ3BAlG4+!}H㎵$oc~ _2k7CyžpS!d_qZrpƯ%;HjH^Cdb'ݷ֭C ^T1' qTR8q$a*+6ךu1 ԭ(/OCdvϥ2GAP\}։̫4,DGPf$H 285it6:m(kZk3Rٞ@(P]<"Pm=+GPsSX5H>I>\.+:wvƝ֣9=(FsЀzW "\*++ N0m_pxխJ ~b1k*GZѭw%Ee!Ԃz[z[4bPһ8f4@'UzLS- V\-',3ZŹՙlӌ"Eڸի[ 0! ~UքqR3Q%tL*X#SyCS%n! )T ֆ Ywr4Rz՛KzV;S^UFUFI\?t{ \[dJRTZpjiMtzr,-1[Q2ǀ1T;W+p^mQktն@ Ss5mΞg$fE<9 ?:*ff ^N1Vp3Ұ/eF}j 1TnwK`})+CY\JFj{}@ym2=j8 %x溍9㊸@m=fCIĊXՃ,kk/XmQs%K(:VtU%x.*j%HǭV{r"78 = g5瑊1SlsrkJ G' hBiB1'$AHOS=1NV 䑚r7aQJ\9e|tr`ξzXKi=_i꠷Ea_j˖;Gjf;,~c3ZzGZ׆5V;sg$WDj"-F@sw2^ϵy]+IT_1# 0~5vU'hqRdde\bA'* R#NVmʓg#?Z[Es5 L7~P2GsZY$  Own,c(a[dGopM8c+NxEW@b8+$YƐ*c'+6ʑȭ d(㌊ش(Ig5Kp`08FZZ6:fQXc+c5ey4pLGZÿsOr@iM^9B{bmlJph !Qڠ­?8&mJ zTOc0LO1OEPF;ydA U-Mha=*W̟+8Y94]Gႌ":@\^X5PS`gw5~!Bc5z,%;q5mnn0x Zkl,|t"nlW5ߵT}*敦Q#=6B j[!8SfJ7U+j%%3`ă[쏔Jʹg9O#N 5f-gLȣ˽ܖLmVݛlzT|Z,.[G7S /Pv%GXI@ A>(`3V#~3MB2 a1~9>`3C+ NiI\ _\@ Zvp֛ ccZR>ncoAvKq#Z* IیZ[ii2Hֵ;VVM ڞj:~m 1/;vH=Uc#*&LS;, cU [CTfTǽC"j- YqFjEی}.Tɼ#dj"3X҂K zuvFIm68dhx Jz: tm,*Vd $:&I3Jws]2@(P8 )n:42[ `3Wcw;3ۂW ja;UIKZm'cu }3#"q˻" 02xVXmֹMJ̡e 2gӽGQTOzǀsJM+ZkLa* Vq?Z+8#`ĜdzոbAey tQ.ŜS!O)ǭ^F=ڭ@&&U Œԩc5a#UJrPn'jah$F9J3I0^3S-? ;ux4}gւ*?;$?0'Y7\bkݮNa]yҩgU bW ]* "6֮[F`zmb]-ZH$f$2SY *1GZmI ,+T 5^xBj%`T:ԢN93HҴfSjɐL|+{eXbX0D`@4BJnX#C=T޲;2+o@`m22=z 4*iQWZ֘tȆ?v1QM@¢T>Pb6 ⡓A~TD!tenڴV(.*=mKaUjTqHRn)7qxbY\1D0Mg[9a\Z1UƸa;r1VUqRތZȖVUq6y\ՋXᐟ0*ٍb0cZQ~FLg=SV(@c,ca7F(}jHֺ[Ac8WrpnS$^1YPxAX{ i"P:z=wp F6mzԶFNr8ynOniAq9YU@.nl*i8vڐv{:1PͨG%Z Ee40߀j <r 0V_}),g@7j3vnXlJڵJ:b$1iʦ4+21Uiq孰cMi* 1*@4f]el[At2Go!tߵ@$9=ͮ} hDwAյ?R g=Ts)R M34ࣦˁR83 TRD8.1)JRAJXP)pzTB1JMvxc) \)"WT4F84ܐ8R '1P^/`Fj3**ݘ1+cj튣"1|Nʕ#Ҫ|dqګ 8$ RfӊX4{eOA]-4`ʣ=h%ypVE jƝ$T6v~C: Iq"_*c&[ڴ ޷XcN:VE , 6Fd\KI)TG.)D ⳮ˞5HY9#WqTB*pc$c89*99F:{Y=ҍ=@Aק8q&cң K:zԪǦE4}qQHİNڜzl㊍ 1vHJHQ(]3  N) b0rr*LUf8HFLV#RF9a+OԼ6b,nZ¸tN{=}$x"ϙ dGڤ?Kkg##lAG\ Ͷ5ZџN!ÑRKʁEqCOja(ك[D`c{ךٳHf|S5BAG9bc$xݞ1U/1E8jTøʓ [Nb+J@L{R8Ed8r~Q0)9-j u=5G=H"NB0>\ve89 :Pp |R$Q69B})sMf,q:1=F1P9|:zT&SfLB+G#jdHl]FҴUZd xis`v@$qWEc*1$cXmV%D8`~t dM0:: D'ʲ̘p[ ^8krHYS{We8Hjee 47\jtR!JԣLQʖgi3)>7̀O÷aTʬ*9)$' Ul.n) 9qT hH7,կk95uh><`r08>S_M28HqX313ZQ5[X Er;#5nip2-8.7.1/share/nip2/data/examples/1_point_mosaic/cd2.2.jpg0000644000175000017500000005653713351443023020255 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342 u }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz?DZQN UK)0>^ %$ޜDjE 4ܲp*+.;# UuRTo$VQd5RM># \UixnQkQ#OaɠIU&]Fհ7Wt|V^0[Tmjy+kdrS.7dm0JlI+z/|ۇbG\ Fdle \w#U5U"o*{զ,YQ2sYwQIr6_'q{H@5<# Vx_ 9Ybe ի=}+xp1* I|pEYZfr9f-iܪ9jKvXo5f7]ijV jw~k*YX_j؂ !rv5<W;9Ͽu:F,Fj=Q԰ ڌ^&t #tIJѴD g4ˉQ$"1`\Ucp.PF1YI2僯$RO)!* )N6֬ `vI(V Mqʩ4I8}U=jtYԖۏ@,e ##s܀Vt{ f3N}`˨f,M T",9l W 3]픜t栻#fxoVc!U\c5oOR- TT^5i'¡ X!uprzjlSP4~U edy$qZ;8F1XWw頃j"p+gE1$b40cun룘F0jWy32IWfVn* @3^/B+XpvGNZ}ʁ/lҹ)mnjGYdqP]NP9ڶts \ + QYZ`dj l63Ri܌>б#W׆WՅʁK3)278*HK&sRMwWXtEF}\`bjx XMcV^xfr8{Sm]bF4ՊFe^>ՁJaBqB0:DL3ҷc0,c¼ݕ< hKd Ѣi ld]I eq}!\VW⻍ l[Irsvsbq0xF0i?{TY"=jԲ}QFza݊S `^K7.kJ-1$c[P0Fz9ZWA"Q p@5SL$\dKrm[F3KU `V *{覺Fwl,v]pF:茫+)iA V$B MD0e#"pۀv10ʢ203S@1Uːv2ǸUl". *0Ѥm'*!$5Q#8沴C$kUWL@| ծ!ok5fw]HoXXCg Mi 8UҘA굑][ڡa8/M r*1ycT$18K;S/k`z+V=db$t5nՂہ'cVm{|G9Fɶa]v[*?3}txVYrwf#3=q+np82}k#XRks`1ZV~1Wp%eHz?j1gԚа$`5 ve*p=kXekյ%rN:m-ˀGz֕)XH)zqQEKqhRR!VZ@ai}Xҫ7ԨMOD=kEN?#cؒLB~J̶cU} 8֒g94 aUm$/_kfe2#UF{GW3(#9k?iIRܡF3JgXO,gku=逬sYNX8. 8f\ ׷6N9KGz~.%-y]N"KkKdRBl֘`UV܀{;Hm)O`V6ɸ9T$4o. wg%&Rݼɩ5eHP'+9H"vہԶc55ֲ<1ӭsM09K|5niJ[``qQi?95&x!k|> 9zct[{FjBĞ2Ԓn$Q"˶'Z3]EѩN8YMqzkVbXCy;`e@Q@v]"hd*:fN!jwsژPR*[m78Y]7KҲ+)vͨ8\;f[`B0N:UZ!G6mݜfߐ?ZKqW|1ǯzΜ)PΡOLc0Yv). H楈|ێ9Vjy dۗFk" Vi姘sޡq,q֬nk\dGZixoo&bRV]67B ӭ+Dޢ[eg*pid?JƺVu`1\r(AǥJ)9e.? >P3n82K~5an#8W-9bJрJK+ }*h"A8uw fK``q\jKo)J\j7vLWE`I$>ЫRDQ͸W8P1YPGm31\xe< "rk48`o#t$rjvǸ`dV=Rp)U[ ZPAwOYS,Gs Uϥb%T{Uϯ^@MQxp\msam*]TTqPƻ-Xҫ@O+БPۍrjxT}kq Sx\NzY jyZ@s*C8*Ŕ|U[-v5m;Z܊5* 9UEgi/lR08☖$ {qti:ҺkfInaǭNJ㎝7d`R^JꌮdIʞ1ٵn\բS'ژbU [:<|(榴r1֩귪+i!;^ VT V½ϗxA05조=-x%F*XCU}WjJVE7Y&r#5w&8'U1M"bAz Ҭ_5皞bT-|}"'#wpi/.D(UqYv%#<[KnJh_`dֿ`#iF@IXt9Unt!w. a^!/GjrɓR 8@oAH@N8;@7-Hɹk71SZ} -y8jGf+{Gn5ӥ\c}d}iǖ1ԗJv{VUqF ^+4f)3X/q,2zGC6qfgYIy`VXB v\>c4g<Oy oND̅Qsڠ?7i4RWcӒS(IJLdiиvW3Q8+ bW֮ #ިIpa `U-n#&L*}Br$b jqҫnMkN`#ڙ),IQT3*)"b ֥[3JHqP$Vmä{yK 8hٴYDlXN?iYDr0?(EdsҬ3hݻ*? CN#V%ď{1ݩҵlo8]L@Qޯsw YtO=TX5\LT$coZ295qە|`[뻐 b1VVH.)G5mNinXRHCj'ڸ&kbIs%QnS[p^nry(\}*;2Y}sĀHې\>e×5u`i5k4M$ƭܘ[ddycUHz`2kZ9bexvglAmB{SؘϵP@}K.ЭU쀌Tur1QDΌ61Њ۰'k!C.ڵ77iic2EID#=jw [rYnj2]եy!,iBbk UmiZڎ߲\30z鴻62}VS@bx"Bve34dMYqdvA}ji1Uʀ(&PAS.cݸXfN6.OҲHNxں i89uy\sڢa1D.ch]1l0dk6 ~`k-7!JԱ&{ԎخX pSu\L,IAȪLv#[>=G^sO01<[VF@:WWiPžl@<ԗz>QL[v?@ǫ"p*Kv+֯#drڸA$*(PLHOBk\/ =̾UX ].g 75C<*ԓך#qg3ے#֚ob#rK!ǻاZFr0e$qd;yEx<֪9TظW9y:]0>ӊξAc-Y6Gq5 sKZ2 M%jHgt~U dDBǭXF1ob $,F ;QK$1 Y0⺋k5 j r<рpjtCu{TH7-s79"6%S8\{֞g$~u^m1as)'xt0Tu1i"`u{H|*ulhQYC帮cBi 85XR|@B(b2* dATO27 kYjeV`POo~ c#H,V6HFTj.o%($vmҳ/HUK&-l2{ Y Hchk=DGwҦ:jS\8$g+V]ƒ҇gpv;+E]xDDn> \#մՃFrVgK]F#QTҹbEblȣ@5hZ$pe^+ǎ=)zTZЃQ8nu,rVJ(SF~JMo2rj|]rO5uhCcS"6JcOcN8>j?cG9cҮۂbP}*3LSi8U;GfKtLs޻ 4;M6)01vEWӂxٵITBjP M6|#nR6ޕ^^`Tq[{ "mŁ`2{жX9T7 c ǒ5xǖ ޱrIzTpٙWCgE'+aa[Xw*10$kh8þVVR@ͨ,`޲u7OjM4ZkBNsXoIJɮX2_A1} t*D*Ʊ}%rsvv3+NJaNLn!Y$=Vc\=[1+C8Z>borVeژN*Ο(&/jr1YwA Zm\[2ol5OI;7SKn8RQE̬OCqŒϖIS=hMsڕ Ur?JѦ +;AJ 2kFGp==랹qkjbp=麅؁2#I5 s5mG⣸2 ={yUи q$}V9ż_J Ziђǵ"8@zP159=Eg.PI<-<}j2c5qv/b"kj#n}*e5ux0^@Lj>-|q*Ͷ1 >o*vnSLAUi!7e,'t!kw`#\q/xr1$IAֶY9Z7*W!x\ޡ.ҧDBj[քqk>a!GU 3N3#jHZ\2"(@PU.9r|9֍ĶhO56A SYZFbɧi/v6\Jn3VŽ勂q5n)ێgNG"MJEY/+H V6w!gJ[hʩڱͱq^-wK˵p1Ր*GֵT\w#CaGjI.0561ӊ# kt=3P)35jĠI&S|<{sQ4 T|J!sYhKTPNGxs-$7*8P BwlPu I4D1Yp=kNJq {޳=TbM$ u x–= bip1։ÆQtb\_p.ڪl ę >cV0]4ӤCӌinK)%HP;i`Q&3]M6pg_B7E!ǘkYm4%j=n8_ \[ڶm-"y`و W:_;D+*I.Z! $Aڴuk.POpzN .Vqu LI !0+ dւ@1ֶ`Bh^ݔh#qX.=nĻ"qCspA31}jk{ ?4<1Sqb3TR3W z|B6?sɭ(pJ0M5ݷ88F.¢jIST'H ݫ!.N_Zײ>HTk6T˃"Q֬l?/4bE1зњ\c]ȸ<8RUsg'NOիتqS!W0>a}Wm7Cu)MGjuUZd`Zpfvb[X*BFbYGJ4pnWjrtIxcn#55٣*1E!?zg &F>B563ڭ9cO+4Ogn]0ZsIFFIghF8(;jRlqL#1NAv,< +'ۥ$ʮGUEsJn֡6/ճu</wT Q h~p Xٲ SyثՏ:?:(5^[evBj[iLCčD#ޭkJM=]ҹMyi* ]1r A!bJhH#%y9h/ ـTsUoT+ҹYv|c>HXm`1RlSp 2D SIV+whp=ET*6Ff82s~Y]V@ zS| O=kLÂ8FbcS72(8ՙ,k{gkU5;9'V$ٻӢR82ϓVN:(Vu s+"iIGZ`@0= DҤؤiZ4.G,aZdhwpG4 çZRgPA9wD|w$XVS0P^D PvQɎ+R8b1 C60 `z-n0xM# SGs+aJ󌪁RDJ '*qU5 I l /)osVy\WcפHʐ3*2$+D8unk&Ho[KyA] mU:/yt2F=hY&u-MjǧLdQxh*xg fmM7ߑV$P6 {+dեD.q]^ʽj \zRLRy9\T A<@# 3ڮہ`zS.A0!,֟#72MK+l\)R@dԃ%OJ[21U8u!*8xn Vsb>\f4q)m" k2}*7T pjH]*\leIi MrJ=.%Oj/$,Axf(䑸թ9Y81J7,vAܫ`Z͗/FkcKZ@akqљI=6$.092m[ w?<~t5hv>\*v\q\љT''JֱQN= gmޭ 6&FMS$.JD;w`V]f(loo®3FZrM$,-<0>IH)# V 3Eʄk*Ku0<RXn;ch\O倊FjBF3N}˖z  fNF&!;He$YB aҹnzZO l)Ȥ1PA"mM!s{kRK@2Lq.) a=BawAOY'cb;id9nn(#5idP0qMi2r}[ڡҹ[n[%FjƸy#]:5%H=E1N3W8 {U[Me8 Icl5xaI\b0 :Y{&*1 L*+qgjSkbX0Jm_"E=yTm4pL˛hW%ҧ[PJ޺E ҿS5d~Uiiy'7ұʋZV,H[# AhđT/m 8-CTi:?<\l<Ŵ@WZԩ7PLT>G"gLNͣyC{su#/+5j->ga~Oa[Me[V9@ifڵ#V Toc+d}6=9$c'giǭ*7pz{w:ڠs<֠dHV^=˷,1TCc>' ^e9Ҫ uzNaEUkN r3ns$͎onCOX[ot{rX d]r3QZI#e[A sU*hEGw7TciI. tj@4lsZIZy qRz."R3  і/p+Jaˁ5b?*YbrqY7ZۊMrRT쩐4T.I EV8k'ldwK&##:{o#!hnjd=(p t:uS_Ϲ0Jghnfh[f@ϔ +A#F= ;\n.EсTfb`cq@ fiFݑT3ao|n]zTPUE']N)y*<֖ RX,J8֨HL aW+.]Ɽ*Ӓ1NZ;-Jn'O8iY:j9SYwzGZ-3J:2k6 s8=j%_ 63M+qƢRՋfQ0W#[:t/i.3hFք$ jIaY=: tU֫[DsQٯ?zڦ#ic8?COw`ֶ adQ}֣n3 $F?]%ppXS: T7`{K-9n<{> @jVg5 zVm#R]] QV@QqJ8[tp+& +hUu a &Xk@O+ν6ҙhpbZjc&1UqRjM-dop*ij)~͌`S ne*ݽ}9c@jNh5|+.5FI+TԐ.gaKަcVN.Wf5T O|7̋;P[׍ZʬHtVdgir*;Kζi'.sִӜB0ұ!7gy-DԱꏻI&6 =+QoHnk#f Yԙ= hcjt]PImNG ` kkaJn7I`j[Ґ2 v;h)?;<k`Jy3JJ5%AKs/ VAc3֚+lT~9&_.,/Z#yXckjD´v@UrpLI=qUedI wb=BഇK#5" TgVldHPnnjI0km5P={u]mj J>aʻsՑ܎BHRv54P6Î~^#'w2H|>7q%Ű7,Vϐ=F C#%;ZR͇8AtuBn#5u؀˜W'ʳK }\ ;U. b"O@<)&-3jҠX5$u?x-^=XE@ A>s |h|zWUչpP+[I/.z0Mc70Ug Veԍ<cREtJ\qU.ŘkAHPnj Ƽ9QIXPH4 e =RF<qև1R ,k[pڲ\.p~s3ٵeظX?h:V<ִTLajq1Ցyqэpy2hcf,@"lLsVx,U/]4 *@ׂ=>8.X?B>[xHp+6|Zk8\ئG΃Q]̲ FH k[)#ٞD3ŸRID]6c^*Yڪ}7VN W[98RGc%ġ+#e˅Wm@o)pҬK4*fxwtx㹴q;1pWOoK%Tw#.̽3SiG3n?@FϸeBGv$"cMaHfMɀk"dXp͗kRXVh͌ f-"h"*{mR{6 #"V=sE6j kJ6V 2k^O*3XRiɭ8 nG8}Ǜ'tTB6@V}2J3ҵ+>l Qek,}8i*1ؠS3U.e01FI0zׅWp1ʍ-:$)2y5T"Rm=ywb\YjP X6̓Cv$g5$r*!+DiҐta h2ܚwVS,f2³eR5F*ͮ3GӢA0f,|ʏju(ҧMN2?LTw:Msky8A[qBW-a`I^+[Oc#:shk#OJeIx_ͱz{+hی1645T`}(RE`5#N =1e+2R42H s޺<V.me r^9G<(V4#$ggU Nr#5J0+Js8-#2ɖO;˾B]=p8szcfB ֵт:b+.2FMSՏoۊq(G#VkKZ \O,PFҷ#@#3FG9Z#I㚫"s\6f8rOJ&Mn8E=kѬ @򕱅8dhȘ?*:n!Y|d{u uD#E>O8xٙ[yj OzkEzͅS·>ΈcFfێ{z;7zkyXNm ?=KFQ}%ĹdQ]>sn.Ol#u#*}a9+N7W I܄UB0?quLG5bX,@XVw y|z5]nbPXھi`7Ce*^=j+BZF->,Tɬt)'殴`j݄= ⵈ j¾6W5kN.GZaḥnZ[V.mH2) &.1Y壜9 sYڅik5UNOziI$Qr2sVpz@ *`iҠWc% _`$5pl' YwȬA[ګ՘tImh5䮓4evfkeP1R<'.>r[c#piΤջ;v=@A:p j5y#]e=T7$X,5W u&=q֣ N4)\B.F=K3q[m($}jܳ#g+Ef=z֜RS!2kA T ۂv <Ӯe '"LZM OBg4T8Qֱa[ֈ#8zZڶg6Q+6F*kd$ vV`aO˜S s+9cLxڝ*59;Ey!ikL)^)2V DhE[[8ʂMnip2-8.7.1/share/nip2/data/examples/registering/0000755000175000017500000000000013351443023016421 500000000000000nip2-8.7.1/share/nip2/data/examples/registering/example_im_4.jpg0000644000175000017500000001355013351443023021412 00000000000000JFIFHHExifMM*C  #!!!$'$ & ! C  " <!1"AQa2q#BR3S$4bcCT2!1A2Qaq"BR#% ?zĀ/{wp( >c1| `=)SurSp%Ќ2Ubd92``Lb>C /"ydIa爷%nʹWqT,.:,3[t9No ηۗ07!{vhmи)mx==#|5φ}|cC5%r2PV,ܺtעÆ'V2FNU(>Y)~V}>JO:w锵^sM|ϛ[t='lΛ3ĥIZkF{3G=XS/8*R]2J!8 MNg7ضj>KiϫE4G9RrOͣڢ췈IjUW} m_Bu:OS$n=]1>Q+UKZCbp6{o>hZEݳYU_KZb?Om$-2M,(zǢl GnLNRM-7m2#Z?ɢ*:Z_u[O%W􎛗u/_!ΕW)8iE3K`8jRԬi U.96*k+$ 2m,*ayV1tK{<"Q*NC~>z%~.\'~I,ŮҸb#K >q84Ϛk;|IEF 4w:v}ADΛCTwLJS(5GN.&Tc 5`Xrߗ'XR>)hQyk$: 5)JoY&+/n{^5g ԲդUY=ߡ6La0ɓ䤏WWvB&&S&SQ~PhItet.^D\lS%V&Ҡ]O"e%"([N?L-KGZh[H]&^D.8JMe==TI 0̶~jrCXp1wKhH}[.W-c/=ԱI)G<>jA<mKsμqµ?Z8թvG; ~]H xdиn,߂7E|G06kCܙ^vVu?C!)wdgo8$e6;u)>ݪMWR܎qR=YRʒKJV|`x!9%xpxfbNcOG^FF3)˃= dy M}Eɔ2"SB]7R:r$9M lMEF;dmM$J/R"dyKn:r%ӒEɰĩ8}0K|kex#,2]\,EAlcx2)jbό]9ե//ڭ.t˛i,ƬZhwt=嫋SxGL>ܯs;xjf=ЀZЋ%Γ$9Z5"nI%M(M7=D߸P6N^ъxF֝7z?'S50K<D0oi>!]J[#^*q\2̙oS=hpZSjx?LO ~ԩ\GFӭ:/G+f0z.dgf[%I7ߩ*Skt$ib=r@_[X)&uzSԬfДF2d_6_z&Wq4^QWOe{I+*\<'â;Is{St #ʖ^JrTV"ήc4ڨ?ɉi6ty ij6X!՜s#< s*{vнӈS ݥ՟UVwVOQን Γ} τuC/IpsY̥|*>BՇtJoBs5>Njp٣ahΔcu,T[s%7}sE WtڌN9cT;YdW74~ezȾE)i/ո1^(,ɷ)W.;ISy^.5t-"n_a:?۩XN#]{w)ROBJQOiIK]OBvGDhUț Y=UoŖj˩pdEW1ݬ|ƬsԒpOw |:2{ЕamwF>jxkz) OƸM#Sm#/k<=po3z~*wW]{ _:F=]kQ? UyvR\(فJ4!8*OZ}WIG˸'ㆎullR9aـgOM7 >2s;:ր= Yh&\A#$*mUJqr{zD~F\utm#خ}J~zȁ_5?ß}^/ GUWf7~_DVeIMG$Ȟ?CS(E'>~mVѲmڄV[fӧ\wl'/%\J3{K}V¹_stt˼5.6:)Ź2Fru"7,Jq8!gIO (TN+sR^fo%ԓFr-e{]=]AWPi|̽4z f Rx9Q^Q*¦!YʞV+UWMn0^ ;p8/hOYg*:)̛miܭ1_WeR_<%6~eiF:PKcNL,y 2p[@##TdP>foJ8sqyF'Dum7ކ-]鞟S(R+4Xc *njt?Rqqluf_9m/^?k8Z5vUZř}ɋTOkm4"u=Socv7k\Mo< ڭ:Pz {"sHǔe'=\SnRTx9hqV(rr<7ay^e·#=e` #сڅKjMUsowgl/Yz1fs֮>$T&XU%ЏmsF-fNctFuuVUIRymJJ>קQHRNy ɖ#рXn7>33WX)Iu:^h뵩F%W>&##%\dr9686s"j u)LFM\M$$3ci>H9K֮f"fP2it ̟\o2Q y0nip2-8.7.1/share/nip2/data/examples/registering/example_im_1.jpg0000644000175000017500000001521113351443023021403 00000000000000JFIFHHExifMM*C  #!!!$'$ & ! C  "? !1Qs45ATa"Bq23CSb#R$Dr6!1Q2ARq"3a#BCSb ?Ttg&tMoT~L"M -)L!OuGBa0m>a?Q~G!: #i*? Ш$>L!OuGBa0c~ Ct*? FmOT~L*]5004FuTοQw"^M7)eΦ7L%{:t0ˋ*jyB4B!B!B!B!Byn7_>ű:j3)Pۚa~*_rǰ,(h"oSY[}'sK\Zb Su {5ޟiӎ*́B>o\>oIŗgjEM zΦ7L&%ŕ}!I!B!B!B!B!M`cIX JES}AJUs*׮: ?x&L&1r N#'3]||mZF55rQj(EM!g8wҒQ!P;*}g_;*}g_;C.4ԋEgSn&=MoLK+*yB4B$Գ骦v@] F*\ꩯ7^GLOvkoaSTTdDSc,{q 궶r}VqSdy)ߔZ/Et ?>c_1#deO»]O:0!Z&?[D2O a kLqKZm,[ Z[~0ڜZ^? "0 y\սoO-'M$cpG?E?Ewfo07V܍)U]( J4؂]2B.揉.~RwM2Y4UˡX3rSF,JV4ԣ8|`j ^ Ck]]%⽞+"i#R8&1U۴i4z[E{ֵ8(^ŗ>A\dB$>o\>oIŗgjEM zΦ7L&%ŕ}!II0rLN[WZѯ7qSx/Z{>У)"rf(\DžpW;cNM䚎6'#6/96Qۧb&CVI鼓Q̓Fۀuy'#MćDiu5=grr8ْF%29p j69mFܗx![[ur\+%Y>>GZ 8#.OSrXlh|owu*Dc*qLz꼜("}+HՑ\JQ>-U*+/^Zu$cn'J)z 'dy Qޖ~Y)oB`ʂu㸫u㸩48LHPu6a/Cۦ ĸ! #GzØ^;lX4[ΌKU#XG9'r6OlLbHFBv7YGF|ӑ6ؽF''##%'"v$nԝ>7d[ F7w'#rܐl0Q;Rr34aHIܣucm C=o5=ĝ^)- 4KcaV1'`.{\nI7$d'pPOXHuVC̕o* ۸\h7`cPm}XW胚摑Tc? C Hꕆ [/p?^x*}g_;*}g_;C.4ԋEgSn&=MoLK+*yB4xudY2aϣR>_VSpRFD z"bϚr7(Ϛr2lV ܜڔ|G Hl0HFY"rv'&[ 19|nܐ`NFuf2-ސ$[7LvjIBeʊXtwGm NessH 57Atm]ҏ04.+` 8?¨b}-S՛UkVPȮT.0U+cU+X]k5ޯՌ?dj6*9B?Ч4/!R,u㸫u㸩48LHPu6a/Cۦ ĸ)WG6ɟe`кPnL! {t[-mEb<dnpq=A7}ن4p6j8b`5(o٧$1>J !:hƍm}J~([TJM>EHG٨>0^rPIYZnM$#QoF5_u9-=F p2jL!Fֆ+*FD| gz@kjW+{gO#nHy=X$Rj En[O^|жND=+Z5eBό[O>o\>oHŖ:gjEM԰ÐiΦ7RDG#\{yeivqqeeSrelc@. 9.#V6u h+wz0i\k@a5:Fu<FE%񺉞IKUwK,\JE4klgh,>{ ]K'_25JMӚτvn6 c6S^pOhx$hV9ezUxQhOjof>229c[$nԝ ʍ.ă$bMעo5Ø%kF7MԄytj4LWoZo5O 56J7ao*=R/9 R ;[U;qõ5Q( ?/m *[BԲV P,֡)x|p<_H)j+5Aq[V+$O_?sy$#6mFKM'QQew0IiעQFL hҍ6zn3GO[_0I{.9 jo⃓VFk-0ڬXgTbbe~gVX=DKFfʥ 2ٝeП *k*9ΘmJTJ Yex4LSFۨ jU@*{BFH͡@_Q斸9J;)JXS:FUS:FTzYgjEM zΦ7L&%ŕ}ٱj)d$4^\TKcʒJ\*7'AzI{X֍&0,fcOnˢad!N#WԚKN@BFYbx+,t{%k>DnzmXkQP5,j́KMy?Ldm^5׺e $hlfY9n֕V̕ik;䬘=qtp{e0:5;"nƍj06yu}V_ܖ]ƍqye `6REZ N&dmm]ieX5 !a-#%ƽ-p*ERbԵTE(!+j%FR}rb u|>ki!Rˑ|Ë\Ua v>+}蹳eQܫXë&QBVWIep66_RIrJZt< dVQKAvUNOQ!MRWMX1<~x*~x*xڑhmx^M qee_y/6BFGbHeR)zsUJCI BiQR ˂cd4\cʚ,~;>z0i]B_YbդŴez&;Jgy]Bv ~?OYK/;JL|dK}/8SDwY[ɗ(TߡG~?YOnakM26f@*FHi<9X ,>v\ B4o es\2qjTۚ^Q Fjfp}PpE6Q"d5K[I8"&/$h)j)I{fo&T򮑀s]]} n;yZI v{G9_GK[PGn 6uBT/WeҷykC.u8p LԬm? ʴ8PƆcG5zجO[TF R2i ,<.udT-P]8b{o~>o\>o7C(tԋEgSn&=MoLK+*yB4B!B!B1~R4UTlGcoZjk';Zmr_B3W :W} XmTvU)o fWz1:a4rqkg׵(lm[kUJL[`]u*8kZժRS/^W)۵ku[-3wʬpv01{[E3@$~+}LBNbO1M'8sn9+l,t|NO1=*x(!_pBOqWOqRhqeƙڑhmx^M qee_y/6BFB B BmLd6 mYo=|O{/f)\ -w[FGepRF3QW3VZD{\X)1,ji1B-)m^؝)XOܫgELŽ߼v*-~r7-UXPD$5$Uo$Y(7%&[MXt@__Jo.!gv ʄZJE%5yt܁BR*}g_;*}g_;C.4ԋEgSn&=MoLK+*yB4B!B!BkMRtXi0H7ml>.<ՏH)Tϳ.}\曂6*4H޽ $J o-TYk HŌH4jrԻ.HfkEfuнጹZj#B[P>X)ЄW볹NB3!B~x*~x*M,;R-=MoJQu61s1.,/6f\I;Qs4,.vjhX\E аڋ as;P3Bj.v0f\@` ڀ;Qs4,.vjhX\E аڋ as;P3TοQwmڪ5zx*M,#nip2-8.7.1/share/nip2/data/examples/registering/example_im_3.jpg0000644000175000017500000001053613351443023021412 00000000000000JFIFHHExifMM*C  #!!!$'$ & ! C  "7!1Q"Aa2Bq#R3Cb$%r!1"AQ ?8PvHmܒ6 0`07 # pI. 3h#?$e F H0#rzZ80B$I `1$w6]NVqéE<wooKi N+iz";,o@G #ܒ=#0jtMG=qER/2U 2@ Tᓔ$$ےk R@nK4q|_Kͣ(-;WYlIAJ _ǔedg=HHDKp1QSHuK){"ƿUia66zi va[?fv;ohɺ6սmN0&HmoԾo귫ZTM=vF~/:?UuNӿgC\fNiMӶGpmQTjY;5Թ,/ܶ? ڜpXOԲ3(RK'z/1+XީwE{H$  ,ǯd20Ou4 `-6mPۂiorFmxX n6m1K B1Mx[| Ӷϰ8@n8^2>c PE6OETtR5 ~Ӓ;7Ї]VN ҜSӋOuZ U o,]M ]lİ6osطqjꜙiD(s>:<8{2]}9~V~(. ##2H5uzFvKu|/t;IMxcɡLr)7MEaO#tF9ME{dr)9MalrҐ6E{R|nX"7ٍFE|j$<;šN$bmYj_Q*$IF_hT#_)*v+u&[hI˓}cR*_;k՞ά)ݒB$A>!P>6 ;Yqf3 _n;MP9piKorÔ7OlXv)Kq rӗT~)I%_M7MMC!M-Ealr!NFW1e ]ʵYpYY$Ϲq]ܪz䜱m$yGkN{ͤ{~M^Ir]v;6J;pznzR)#/*mA/xF9r:1gSx9n9ݬlrC/ǻG61btIXScɔzVsGsӴ;ԔRZMzBѵnYktpLX]r 2:E8lJo19Tu}¬V|l˯& 9=f{/XZVĩMNC$ -*C21Sg1r nKܮElIUs?;ULo8Ţ%VoܭULmU9'+U]ߑe>%Rmly%VS̺' tuzQxu"6-mI~伹x7{2e-yEve5vl\}X֜~Yj=f+{{%gs\(U)3YxSXXJ(ҌNnME$Ĺؼ>Sʜf=@rYRgG) !Q5lͱel/[qIZ];=V=Ċ1YϯYǺC1pI|ai5,y׍(OA=V׮˵RMS f<FUjJIIln௤G]R2[3|jUM<>r2WrVߓ/4 5w2UrU2UwpY*&JW*1F-*uFT)=&-i -I)l#RNy#*o>Ipkw'YQO[,4X.N}-b0R]\gV\-OqpX]^EgejVU?خ{l?Wͦf hԀB{62M20H4Ky}qӍV09ƿSFMF䯄VەZD&]jtdlOfJɚ܇ULeܬUQ>wɜjɾƕ"⪥ө[4'#W)諨Io~=OGѬimKQijUaM(qa浊;K)_XR(weSJk&[©eNsP\;kV<,ѽX_75 Q.S<Qu7pwG^56au~wW}n~Q2ӗWTԺrr!ZS; iRٳW;,)F]\ h^[Ww%riBrΕd ^dyGOҟ$8AbM*:4;KwӪ8U^v4CkGaWƫIn>HʎN5%6^ZFT&ת[s3jGs~]5LGiRt˅ҖN-gA!{*Mn[sT"eMMk7? h9} QFt(aƮoH唕KkCΧG8Wߓvu24~JY!B:2/7/tm^xئ 5eGU7%\0\$ }$O>y:]2烖MgrκѴcs.r_awf|9ukMO%\FjV6W|2 "@ w{ ~T Bxy$ŀ~&6e`wewӍΦ>2FojMuZv["$rrq` HI@84ɠ`k B,SjI`:vlԖޣO96¼&ШoW7R"]ƛhgzvtԥJ nip2-8.7.1/share/nip2/data/examples/registering/example_im_2.jpg0000644000175000017500000001127613351443023021413 00000000000000JFIFHHExifMM*C  #!!!$'$ & ! C  " =!14r"AQTa2#BSq5Cb$%3Rsc31!Q2q"ARa3BC ?UUB{TnxzWQUiV֫{y}nK)/\{y}nK)#v.[R:WS(G*\;!Uu5/PU%NbueOB ˍ:nK&y9OcSG 7SX|}NFKC whIV:%ȢGi$tB)ȸ"o4&lܫjڎ7sLڎ7sLc'^¡J: Wtt{ fmx3e)ЮeBϢ$.?JBH}d [Tw>R?8B&$vF&߈_cITOƜ6=x~&o[QiO$SQݏ?~4/򡿩H|T +Y`>.VAdvS#ip*ݐYϤRHOz:_)8YߪƜS繳e|Ve.:?0~rJenlŖ;-jO5m Tx9MEhE6y3f^_ Wqe=Wqe;>BA)l`R$UX yueo!W7ɳVzjTK;%3ǒMAnj WM;by$MhT)+69WM;@w9eTG>U_4.g"L[Y1oY٦vj 1cќF$ڀK=0aYO54HfpA_%U'?4`5w. G:t'bdfK#v.򺮖=~k;S6˹ǒDu&Bm.[HrtqV_`xw-OlJ9MEhE6y3ff_ Wqe=Wqe;>B 2p)~c̍AgP*\iG)t*n_3nUڠJGbf(ZJf'"UtV7"jy *hP&jNTWЭfi; T2~ÍSjut 1칱6'^o%Δ[Dua=аY]Su٠]m9jo,dwqfI>WN!dSoqMEhLٹYBnOUnNdOнBEcOmῙCZ{m%ԙ#{͊tm7IHǖ&25VYau_+Ry*neWlHAUݪPei@䃘mP%mլ'+]Et$RЗUW)uRӮ`u4_?o9F\O.lR:d]=8\Vs 6q[|vq,#zUwu4l YX8#0t YArV3Mb;Ŧtf5"҇%fw-ȩ}Zh>h}2㙇VLvS"o4"|Лs_ WTjULTΞwjLgSI)"4C,,hn0Z[#Z,( Hc%Vkf{]I\m\u~^5qߓ>kf 3K0PSMJv[w Av:dɚ~CoES9X,,'ih7:gj3E`V5sˇVdËZ㛣?-+Yt)[XLIa*'71d~\ګnJVP%mQ$S4HrV]2iAP`rniܼDʃOoVƜ$=j.OA%ƒ`֜zWQ0GҦsbg=8z]2'Z v-ʴ{Bݍصo6 CH\ R6,HϡVfpy*}idezFNs'*^ۡm.6B)ȸ 77~-^?:vT@j6w5VIOє scɱ[_.GZ=6e5tu,64oX;+2\0Gl>a \+b( ʩ$LFM'?sKb%4ҌBP [;w[loΉ$vV8ZjTt:y=2輘2|A^z%? F c{GVƊA&ETűU<':U6ƭ9[fNZƬ ~u3挴}V\NKCWL`[Z'0rq}?2 'l[iYUĜCEX{PKsY.AGm`Tz 4Pa;*T DEdx3Zfx_c@X1|9i.SKYwbiW6y\m:Bn b2OUnNdMc:dZ HO虒H|`Ϲ{ՙ;c ĨnCi=ʃDp>Q<3wفۑHV?qLd_F=rVOWiTѢ輚EriOiOMEH4yمsՏZ> ҭdBVPI3':YZSU3ҺHcrr|iU˪pU 6޵0GN;]uVjy,곳Y+ϥE±C :w08^! o$֨y-e5qɤ|~^n>_(T>7qk#h+J*IT4`Fw9V(|N?HWc1pkJ 3geih XvnZYKcjc쫝bUNc>^_2fIk)eM3i_ s*m]~oqMEhWn}BnOUnNdOнH GK,&xQ+A2U?gfR\VM6xr?gbY(?TjOgg$?Ob*h:jKϪj#8?~ M65oBAӉ)'CD^H\.kF\'[%ƞ5zCM>-Ceq41jW3*|4BEf46D|] ڧD5>n#:MH'KZnd.dk]sZ[ Q1dp+~NinBBQB!B0Dݤ #P]%fq,>-az$dYIVrr|O X\['u16!'_{5\Ӑ8}n I ݆Ә]v \S.MrѬ"z!`mЌ\ U>8ťaR\R|)LǖND+sSti Qm.6B)ȸ 7*hZ))B!@!@22z)^v{ n;B G *vh NMBrNWљ cU~ q~˧Pr7X4}/& shfwt|>:Zvj>)51 /Cfj5¡_Y?%B!@\mSoq6nUе{G'c>B "BQBȲ,! BȲ,! BȲ,!,!P, 5 "BP, 5o4! 7*hnip2-8.7.1/share/nip2/data/AdobeRGB1998.icc0000644000175000017500000000110413351443023014555 00000000000000Dargl mntrRGB XYZ /acspMSFTnone-argl desc{cprtx5wtptbkptrXYZgXYZbXYZrTRCgTRC$bTRC4desc!Compatible with Adobe RGB (1998)textPublic Domain. No Warranty, Use at own risk.XYZ QXYZ XYZ OXYZ 4,XYZ &1/curv3curv3curv3nip2-8.7.1/share/nip2/data/stock-tool-move-22.png0000644000175000017500000000077613351443023016204 00000000000000PNG  IHDRĴl;bKGDCIDATxݕOKBA'RZiţXA`" )pY W]{TmZHD*J(M  gfν;?y$XB7H<3bш| )`I& 8|^.C o@-A{օ{-YUnӡ7 ue<\ D0HL&PV`7y7P+JT*Vҷ0h X];&&lضX:{O80mvzցs`_F=j@O,v}7@ hO!ݴR)Lְ!h,[{}Ft}Z'fL"0Tj;J njG txSP+Ew$۷= w;#/bͦtvP+RΈ޹JoB,|^sPPZ}~3gvQʧW\Ոluwr+ǺSP@U[Dl} 36~+u-};1B C~ BKʓks9{Wسz+GTk!dƾ:f|iu"\'xly3V:Zv::t0;/@Qn>KT!9F)ly3)X`U֐k]ܒA=p|& m&MjS">UYKi xz*#IENDB`nip2-8.7.1/share/nip2/data/stock-led-yellow-18.png0000644000175000017500000000101713351443023016332 00000000000000PNG  IHDRVΎWIDAT8N@?쀈!FUʻ'QB#"2B$je{m\1gCaю;;;Im;114e̮_b$ ;B@Cq _OOznoC۬U%Pků*z5btgG Aoo+b BƊ/=> М! M݅-P]#砮%Psbԯk1tCkYI!,sSP>lAiJ_Gr~s-Pa>ZvTb͉Ns1c~Y.M#sh>$MEomn-i #{øە>ϏBʒY[=>f(8Ԣ2Ueb,PZˆ#wW7Mu(촨¦5 3.9MW&U-jo85+ca:;_,ۭL2oyW x$RR%)Au9Md~ =3{&)Jk-A]7K=IENDB`nip2-8.7.1/share/nip2/data/stock-tool-bucket-fill-22.png0000644000175000017500000000227313351443023017431 00000000000000PNG  IHDRĴl;bKGDCpIDATxڭLu_q߻C@Kجp01BAV[NZEs9dcl58bC a/=gdZgz>|-h7)9`P|d6XSN1sӀ 0?)x gffF'\^^Du}Ccccׯ7[=dlE}ml*&&Μ9D̈**2>>.RXX(UWƏVυ~S8ɶ y@N˵kdllL&''% J4X,&;vX,&G~ HOOtwwKnn|]#w2''S lv4M#%%Պ\.GDDQ{eQǻGҞ㝵W~{Q%vX,V+( D2:::BuE!//KCC?~< YUd.6YZZBUXp8L(nٳgillG"w1 j6P-I1&Bcppazz]u`0H(tvioo)D7[-ŬL]& }#GpB   p8h9yd" 6@ %Rͪ2xGGGIKKcdd͆itttܜ: LF.;8EEEr%N8x tH.lf5m36*L(uknne@2dzmOkxQmiV@W[u*{ϗ2g9/` KIAEa$t'On,"g_,_YY M IENDB`nip2-8.7.1/share/nip2/data/stock-tool-text-22.png0000644000175000017500000000103313351443023016205 00000000000000PNG  IHDRĴl;bKGDIDATxջjTAHbIc#l|NS DMbB" !Fssg,2 pfoY2_RXKJp:<r/_Z^j5iOדZI<{r;E<|p+`WazME"fQA_2D^ ҥ˸DAnW#c= aߖao._}0O_,` ׇ4gfo>JqWϐgʨ, \e8nGөK<w cl5q>kNȱy,S8fΕ'IUV/4o'abOs%3-p1yRµp}6\2&۵u+?{ióV(ocq$:QU? Va\7 #:ǿ n"IENDB`nip2-8.7.1/share/nip2/data/nip2-icon.ico0000644000175000017500000021401213351443023014473 00000000000000{ ({ PPCUODA>6;92HHADA:! +--32-JJA "8,">UUUU::3%%% ''%    "1$>**972%(',-2>;AQQ[QQ[333  <<<      "(?.E\HDD%%%78;UUU[[H /.0C<<?  :46IFL(%,    ! +"?U00-,/1PP]#!! ^\^:::1  wqqqmpVQU506      % 6OOO%'$479&&$KJH222! zuv[V[:4;     (#4WUUBB> ##=@C&&%<=;.+. #ztw\TY838   .)F*;]533(-.IIO+)(HIL303  E==|sx[QW606  " ' <'N,**/35PPP-+*NOM++.!X  h_`ypsZQU903!!'2!3UU-,*147UUU--,-341161  vmoUMN5-0#&&&336 1J.,*ORRmjh MKGripNFM($+  !-*A$H=  wt<^7Z:\=_rpn,01dc`^]Zz_X^83;    #3>>ZYWMJH $ C88:`$7\9[8\yfhghu@hhhjJh}V $qEn¶MKN[ZZ 1? l^]ikkl~;ƽXtC?`(/<#)++Y?&bgllE51bU'Nk-Ql0Sg5Oh2Ig.hP3)'( "28'gja53u1D]!Aa"B`!CZ$C_#F_#N7khg156! """ VJH8ENYiuAd,Cd$@c!?d"iwiv~jmjz7kjkikc{N@^"A^!>^@^9J' )*#C5,iK34[?;Z9[7X8S8YL4r^Kf@_\\ #%dgh  UUU.M{mm[k$#%;Y/Fh%Ef(Be%wx4=sxþo'mlv2Mljlmq&vb>^!@^!A^ B` @^ =P)$,.'4".+mV%aJdFr>AJ8W8X5T5QAP5F-r|eRQQ!$%z}}wjj  ""/0B##%9U0Df%Df'Eg*/Gp%/#-,/lp¿s/mls,ú½jkklmYDa'D^#B_$B`"C`"B`"BZ**2,5$+$-"*!'.+5>*DJ'OO&8P7X7X7Q6Ng@3I4yqYsQ\^[ %&nppYKK $%%!$*###7R1Cf%De'Fg),Fl (%egxAB <<;  DDD3fgZ[_p$###/FBBa(Eg'Hh,6RV##$#&,G8aioq&ƿý¿s9mmlmnGb%F`$A^!B_&C`$Ga%Fb"gf,/1/!%! )(3%,.IKK'''   */1(E}7G$$#$,CPBa)Ih*Ih,<[H$$$#$ !oZrr*¼klnmnoz6ÿHd%C`&C_#C_%D`#Da$Mf3{iR!! !!' -8%1>"(('..'((1,*=42@518=31?0-<*.?,->,W_]begPTW),.CCB}nm"$'(???$¿,%$$$%8]=\*Jj,Jj-Ec:&$%%%!Y sp&~xmonmnolIe'Fc)E`$D_#C`%F`'=E7$+, "&:EJ")&*8E9L`3Mb/N`+?<>cN E\$>\:[8Z!yroqq/46%')LLLddcgfdNLL&&'#*CCC !2))ý'&&%%$5pGe/Nn/Nl/Lj50%&%%!Q sr&wp'nooon}@½Je*Gd)Fc&Fb%FY),/+#(*"&)6>A$,.53I[7Rg0Rj,Tk0kW(> AYW$Kb)Eb&?`!=^"piXY\:=@*.0-/1!"$  YJI¾¾¾y'''%Mi2Pn2Qm3Om3)?%&&&"rI#uu$S>o6nkonqE}¾½If*Jf(Kf'>N.#&(""511Qc1Ri0Ui3Sm0Zj1F$C XY)Nf+Od.Ke)Ab$TsF "*U |mk»üýÿ¿Tf'''&',F`5Ro3On2Pn44Nn&&''$wM)uu o.u s qqpv2qñþþJg,Hc,29-"&# !!" &(8=1Ri1Vi/Rj1Tk1m^*D#Z`+Ng/Oh,Qg2Mg*Jk5 -5½ýþ½¿4F('''&(?X?Sq6Rp5So3?]R(''&&vN>t!u t"tstrp/{KP\a¶ľFY0(-)      (,"3;4Qk2Si3Tl2Wl1M%^`-Qj.Oi-Rk.Sg3Qn9}mm $H '!¼¼¿þĿ"1((('((6JZSp7Sq4Qp4Kl;.((' 'YAXp vvutsp.T@(,$(^c¿ADe $$   !(&$+42Rk0Rg2Rl1Xb.bc,Tk/Sk/Ql.Qj/Ue1[KK  @53½ý¾ĿĿ+)))(((+:}Tq8Sq6Sp5Oo5,A'((( !ng!u ut$s*m3P?%*")$(g_55JIP!&'   ;1&  $%'0/Rj.Qg0Oj/Pj0Sk.Qk/Pj+Pj-Th0vJ$Ľ6*)gZV¼½ĽľĿſ¿ *))()((!.Lh;Pq3Qp2Qo3;WZ(()(%[8t3sSWq{Ap;G#*%*%+'+e]//&(4$$  F4!b`& ##+/Pk.Qi0Rh2Sj.Rk-Ni.Qg.Rf+|K";ƸƴEjG{x½½¾Ľžſÿ[j)((()() )B[NQq5Qq3Oo3Jk8#2)) +='R-k$k#l"n'o$T"9%-+1\MM #%     (++}lki'&,/Rj1Tg2Ug3Rk/Si,Ph,Sc-|M$>F|;qx)z4i/''!½ýľžſý9K*))()) )*6IyQp6Qq2Rq2Qo01Lu"*"*#1FC @#8#@&g%q(s,p,Z)/O   8G.mll$ #' $'Tg3Uc2Vc4Wf3Ue3Wc.M$DVqopN}ll-R 4+)¼ļĿſ(7!* )))) *!*)(4Qm8Sp4Sp3Ro2HfB$/#+%,$,#+$+$*#*#4#Z&p,f$,7  ,4(Qh5hU~onp#)*,"'Qe4Tf2Rb1Rb1\Y-p;FftuoY[KJ  !TGFü¼ýÿĿƿ+"* * *)* *"**#,3HNNj4Sq5Sr5Rq31I#,%,$-$+&,$+%*$+#--C"' $"J[:Xs5Wt8¾cmqt#43/$Tb8Wk4Ve0dO%w6Inutt\¿7,+ U$ }ml½½þľſƿ¿fv!+ *+ * * +!*"*!+"+/?Uq9Ur5Ss4Us7IjF'4*/'.(.(-',&+',./r  DO;izIg|F[t<|kĿľFo t!u&C9/#]]8jW.I&?atuvsp9ÿ #5)$#ýľľĿſƿǿƿÿ3D!+ ,!*!+ + *!+"+"+#,'1MiLVt9Xu8Xt6Xt:CZh-2+0+/*/(-).,-] :B5ewNkNnMlNbtZs+u v$w&M]x@_zCb|HQfe6?25&'A" &+'_iMcu[sSwVtUu]KXrwzzs"s$y)f*U8.#\"qxyw f B<; r¿Ŀÿ¾½¿]LK %" m]Zľ¿ľĿET%.#,","-#,$,',%,%-$-&-&.)/0:UpO\yA`{Bd}Fc}Ge|H`rR(*0$"S_GqUvW{^y]{]|^yeW}BrDVYs v&z*V*c=0#m%x!z"w"Z><> >"Ŀÿÿ¿¾»:-- $!}¾¾ÿſ(5(-$,$,#-&,&-&-'/(-%.'.(.*0+0?L`yFd}Fe~FgHduJ-/) JU=nRrSuSxZ|adbm^JO@e[^z B#?!þý¿#" !)$"¾Ľÿƿľÿ)1).(.'-'.%-).).).(.'/)/'/+/,0.3J]f~IhIf|I/2*CN;j{RoQrSuSvUa}b}b{xWPOTEg57DBt6})|,{*{,g1 !'x*h.zCRB5>-<$A#B#A%ùÿþ¿¿8 K96ýÿſƿdq*/+/(.'.(/(.*/(0+/*/*0+1*0,1-1/1/5JXf}S=C4EN:k{PnRrQsSsRvU~]ffrRNPXV;I7:6:t>,|/|-z+o0%$'U,F'D/E*w99:0?/B/L6ĿÿĿ¿ml N # faþÿƿCN-0+0,0*/*/*/+/,1+0+1,1,1,1-1.2/2.303?JO^_i~RpPqSoPqPsSxU|YfweMORWbOj@A;>=@mḰ0~..}-w. $,%(I,F'F'G&=?"C.?+tL`ſĿľþ[IH*&#}ſÿ/523.1,1-1+0+1.1,1,1-0,1,1.2-2.2130404356=KXbujo\qTqUv\vgmxyj_NOW\afSfFFHLwj|5˂2ɀ23|2&')6)+J+H(G(E%=!?#B'=#tiÿ¿Ž8+* -'# ýþĿǿy24460402/1-1/1.1/2/3.1/2.2.204.3/304254648698<@GFPJOIMJKHJZw\[]_iskU_NOHK~mp>y=x?yW1+,D/-K.H(H)F'>"B"@!?ADELJSRtgjnrztdr[ZSSRUvs]LHz[MkXs`@325,.F.H)H'F)?#E$@%=%ÿ¿& 5 9-,ý¿fo89865436351535352314131526154546593637479::=9>CCHJHIOOZXognRSRQKKUSgeqrsxlsde|qi\TLSNGYSMPJBT:\=43013.*G-K+C'?$G)I+aK^LJ U {liþ¾ľGCB;@:=:?;=:=:;999:9;::8::8=6979:;9>=><@C=@<@<@<=;;;=;?=<>;>8;:;<=AA@BADCEFGJILMURNGAAMKc^poaVUTPPWEr:yC=}H^lc^b[V^UPb[U\UPUMF`GD=D>C>A=B>F?B@BB>?@??@DBDCCEFHJJMNQR[V?@DBDCh_vf\OMPNS\q:z:z<{M]fthdeg`YdXR`XQaXQULCgOFN>M4,X8S5P1Q2L-K,Q1Q7ǿÿ¿<3/3 ;1.Ŀ½þĿniPEODPDNEMCJAJAIAG@HBF?H?FAFCEAD@GCIFHHHJKLOQRRSTZXPJIFTMh[vaRKuNGEVNLUUXElBr5yYosxqe_k_VcXRdYRbNBYHTNtG9X9U4R3Q2P2P0T5X>¿ÿon80+ \NL¾¿Ŀƿf[YGVGVGUGQFODPCPDOEMCKCKDKDJEHCFCFCLGMKMKOMwWSUYWVYWz[ZXThWj_|mrMFBRKFUOJUPL\UP`WSDsEyOufvpd}_SobcMaBWPS;\;Q2T4T4T4V3U5X=¿ÿcRO3-)"U}om»þſſaS\J[I[IZIXGVGVGTHTGSFPFQGNFJCFBECFCMJMFhNGEVNLXQK\WRc[Zc_b\kXf`uGAFOLFUNJTLIZSM\SR[_n;{:zVw`ΟrZylRbC\@"7,-L0P0J-T5V4W5Y8Z6R6»½ľĽH;7,%! =¾ÿſƿľbPaNaMaKaL^J]I[J[JYJVIJ?>7O739;55=76D?QNEHDMFBRKFUOJUPL\UP`WSe\_hbjWj\{yeJC|MGEOIDPKFUNLTNNRU`GnL|e~xuuY˕nSĕnPfDcE)*-qI<\p^IdLbK_L_LSF94K812932722;42=73@::TJNFGAFOLFUNJTLIZSM\SR`WWial`k[uj\bUTLFCTJIOONSNO[RPgayxzkuZ˛iOkJgDaA[LHcIfCO/M.`:`9]6d?`=K)fMĿ¿@;7" 7  6?? `RPþſǿo}{50.50+61,61-60,7/.J<]`IfQfOG?~4/-71/81.931:41;50>:5NCuaRbSMFEBOJIOONSNO[PPyb^f`uqaiXhYcXiYiXk\mZiXiZheqVȍvlGgA]6]6`=f@a=S.[5\5^6Y3]9R,sXÿÿs][>61*ur¿ſſƿĿ31650,5/,6/-6/.50,4/,8/1:2AF:\NAr5//61.70.:43<51:60?:5UEdRdTdU[RUNTP]Ue\d]ja{vr`mYjWeUjZmYm\tfm^fmWS]Lrkmn~akHf?^7^8mFnGf@R,W/X2U-]3jOR1rþſĿ_LH6/, " $¾žſ¿:5Q3/,3-,2/*5.,5.+2/*4.-3/,4//5/.4/,5/.71-;31:40>73@96WHiUhVgViZhXfUfXfYf\l_~vireq^kYgWgZqcriosa\NFO=zE{ytsjFe@`:a;mGiCboEhAa8b9Χu\T0Y6D:5O ?32þľĿſyhFjjWoYpZmYkXmXl[l\j[k]izocqdncmbmbodmcZ~URQA~:zH?I@~VtjH`6`8i@nGh@Z6pWȠüzsw~5/* cUS¾ÿĿĿ¿tWYD0,:1+)0-(1-*3-,H9WqRrSsSqSrTuTpT\H\KjUqZr[p[q\qZm[pZmZn\m]n^roqcrcoboboaoalaU{OLF8}:{>|<}E|SneYdI_7_8jDnHh@W1\SƈtïĿq[V.(& &wuüÿĿsTsS:3Z-'3/*,.*2.*9N:{tRrSsTsUuUsUtUsVtYsYsZt[s[s[rZo[p[p\o[n^p_zs~eranao`oaoapanbfeQvH=2~9z2s3vByx\mZd^8`6h@mDf>Y0d?z]ɾÿȾTB>)#!* ¾Ŀľ¿¿sSsReJeL7/IcHkNtStStSuUtTuUvVtVuZuYtYtZtZt[s[r[s[q\q]r]mw_{ls`r`qap_o_q`o]n`o`gaKp<|0{9~(s2tiqQdF{Ra];_4ei@b;_4Ɨ·ĿĿ}92. 3f F9;½¾¿vZtSuRsRtQuRuRwSwSuTyUwUxVwVvWw[v\u\v[v\u\t[u\v[u\u]s]t]u_vlq\s_q\r\r]q_p_q_o]p]m_~T{X{xkrmFb:Y5NA`9jAf>]5Y4ÿr[Y1-* n^^¼½¿ÿsVsRtRtRuRuRwSvTxUvUwTwUwUwVxYv[y\w[w[v]w\w\v]v]v]u\t]v^x`{i}ct_s`s_s^s_q^r_t_p]q^wj|urwhƊqlGa9X2Q6\WmEdAV1V9z_I:7+&# %-}¿ÿ¿tRtSuRuRuSvRuSvTvUxTxTvUxVwVv[u\x[w[w\x]w\w\v]v^v]u^t\v^dxpy^x_w_v^s_t^r`tat^r^r\|cl[saeE`:Y4Y?WziR]DR)eB¿¾4+'$' yatRtStStRuRuSvTtTtUxTvTxUuTvWv[x\y]z]w\w\w\w]w^w^w^x^v^x^pou^v]v^u_s`u_t`t`u^s_r]ºniyifTdqczodq[H[;Vh_b[1R'½+&#9 %qSrRsRsRvStRtSvSvTwUvTwUwUvVwXw\v\y]y_v^x^x_x_x_x_x_w_x^{`zlft^u_v^v]u_v_x_w]t\s]}ppZlYgW-l)p%l7i`a]PSmZ4V-ͻĿľþ~kh'# *U I<>¾qQqQrPsQuRuSuRuSvTwTwTxTxTxUw[u]x]z\x^z`y_x`w_u`w_x`u`y_dxsyaw_w_w_u^u_x`x`v_v]s^vgl]xo*v&s'p-q&k,kkl|QpTDW1ſÿ¿ľ[HE$ * j__nPmLfIlLqOsRtRuQuSwSwTwTwTvUu[t\v\w]w^y_x`x_y_y_y`wavay_lny`x`w_v`v_x`w`v_xav]u_Pxstlm+v&v"pg!h%f'n/sjSNH_>ÿþ¾ƾ6)'" )pmNqOhKqPnNpOtRsRrQvSuTvTxTwTuYw]w^{dqzby`y`{cx`yau`w`z`wweu`w`xau_uav`vav`x`uavdB~*x*y,x'v*x(t'p(o)p(r)sa]{JN^Bx¿Ŀ¾(!% pToOpNlKpNsOpPrOsQfIvRnOuSvTuTwyeq|xh|vswz{zbv_vawaw_w`w`vaw`|hv~kf1z*y*v"v(x)v)q*p)q%p'q]\{KLgQſĿÿ¿¿}$!< %oNoMpLoMlKqNpOnNoNkMrPgJsSoNrRk}le|}wrvbuat`u_s^u^t`t_w`}d~xx}Un-u'w+x*u(p'p#p'oJgW5L5rlÿ¿¿o^[!U J>?mRmQlLjIeFnMoMqOpNqQuQlMpNmNmMrVx\v^sZqYu^u]ly~zs}cvbvauat`s`savasavbrwob{oia}hqVq@r7n8i?hyekV1O'K#^þ¿½M==# D lbb~uyiYeOjMpNoPrQtQtQsRsRrPuXuYsZnXpZt_mXnXxbl}hjsubxawas`t_taububtb|upcvjjb•n`dZ\`hZh]ZpobyefU2M%H!iĿĿ¿4)(+~uhoYrQsQtQsQqQuWt[uZrZiSs]oYsauataxaxdvhtauasctdsauau_va}s~ock_qkYcm*iij m,nMjTGL){ÿ¿)#!+rOsQrPsOqQsWr[q[u\r[r_q]nYu_ucue|i~xszvŽqfsgiZkWaQPgjhjmm!n>ltgkyaÿ¿wu" $H .&'qQoRpQrPrQrPtVp`q`r`r]rascrdsj¤ohwj_ˆ}m^`ZFfhgkll m'p3tl¿¿cSR  RGI}qx|j\l]h]m_iZSIC_cgi`f#n'p+r^v^ÿý>/2 : uii{nwtd\[RcTgS]HL0[Jcbbfj$o,r/v¾¿($& \ZUL]LbPR9N(S04fihhh4kjp{¿¿< abQIRHJ9?S)S*fYa"hij4gR<|h¿¿tfh /O  2)*txPMLFA(=P'N%L'xYTZc~l\ir]leXhREE U  VKMaXR9=X.T.K$U/aWHd!fg jVº.#% ? ukmtc?Z/S+K$V/`bgeegfW) % H)[2Q(N%^6^G#cdeedj|| K  V3O)O'_8`lccd d b d}iYZ $H  D88i[Z]EF!N([5Pbcba c acC56 "    5,+`RRvu~zI3]FyLtcbcdd^! % ([>, !  +"#SFD{klR4u2wV 6?A0+# &H98s_^|mn "UUO 8)""6++aPOvuXIJ HA5- & !.$%PBDxgg»1&( UP8-%  *!#A56iXVzz ?5,' !! $!!,$&6+,UEEzih ,? <70 *"! $##/),;12M<>l[]||ŷƿjZ] ?&fF7 0 )# &#$*&*)&(5-0G77gRRxtD67 US>5 -)$#!%'#'-')6,.I45bKI~e`~{! UD7+ &$# "&"%,%'5)-L:=n[Zzx  G :2* % % "'!"4()L;@8> ~xp>><8?8?|p>8xp88 `p 0 8pp8x|p>?8?|p<8pp8@8  `p0 88`p8|~p~<8?xpnip2-8.7.1/share/nip2/data/stock-led-green-18.png0000644000175000017500000000071513351443023016123 00000000000000PNG  IHDRVΎWIDAT8?A)`6`q v+O2v6cƗ wE beHfsnؙFln<3;w}ڍ TFJC-23+S/}?7*XcU/2;wL'\xQt";8FBT?]+<{ayn.nڮkϱgͰ2RaDvb.2qD s)P.7Ke{w1'q6(O"Q-TNZH@6pLDV *X`y 8#V-3Tl itiPϕۄ>:mb7ؚ{˟Ws]g_4UK CW>y羞~Uhmbizyl!f֦>\[ X#cIENDB`nip2-8.7.1/share/nip2/data/macbeth_lab_d65.mat0000644000175000017500000000110313351443023015576 000000000000003 24 1 0 37.7758 13.122 13.2705 65.0651 13.6974 16.1079 51.125 -3.3471 -20.6654 42.9236 -12.4326 19.1425 56.0801 7.2918 -23.6413 70.8371 -30.663 2.5131 61.0209 34.1118 57.0494 42.4442 9.1559 -40.9195 50.2147 41.9414 12.8438 31.1403 21.5385 -23.1365 70.9067 -20.5043 57.9149 69.6498 20.8271 64.4978 32.4864 15.9125 -48.5415 54.1624 -34.1277 32.8876 40.4646 48.7723 24.0303 80.0696 4.3066 79.2876 50.847 42.549 -16.3102 52.5361 -28.7633 -23.2291 94.8303 -0.536 0.3512 80.3002 0.0736 -0.3646 65.3137 0.2192 -0.4743 50.7737 -0.2655 -0.546 36.005 0.2655 -0.5395 22.1402 0.6357 -0.219 nip2-8.7.1/share/nip2/data/stock-tool-path-22.png0000644000175000017500000000146413351443023016165 00000000000000PNG  IHDRĴl;bKGDIDATxڭKHQ3LRT*z9aQ=-,$۸kArѦ\X +(Z ^%i' ?^,<:wn}{ў ЭHaAj0@\OLz ™i xp QCFJ`\' 씁WEW\kd[.D! U&§`#_Zl3@(rǺ$`1n߲ Hߍ@.*cNWZ^^>c{ŧmRVsScӥ/v 2z{J/EL)---?3DESI`p[ %C#|ެ e7eM~p.aSSC<wzoutUMY?V Ȳ;HJ 薍%4B]iɩL mz9ŕ+Bi1ƘW&&F>Lv\hط+`s/ӭ4unлc뚏oX/|3۳[j'@udKlASYYil7P\H!!'N5mmmYT 7p|,hF/9lSArנRy,NuP&Dxd{) s觸T|k3oZfIENDB`nip2-8.7.1/share/nip2/data/vips-128.png0000644000175000017500000006137413351443023014213 00000000000000PNG  IHDR{ { IDATxi%u;^U{wu-ݳa0LxH h-CtRH )O()J\MIlf'fkyKf{?ܛ{g@A23{/_sι)&yt{=7[+4{տ?ɿXٕ;1('Ge?/}P g0|b'L-:q)qDt8?ֶ{HGo1hu&5&w/qڂg~fY$+ j0bAG;ۃSN*+O7=Jc >ldfbOEefv U cEPBaj z<ڟWrWІ{חQ~r3>8Iڡ$6xDϠ~w AՌ?LK> ]g7O452bmXgˬ|e/envQ2(iiQ"'фZc#{C *`$j{b0TO6f!(*%6M4bPr +_72lE~5g+SL D\fY=Nrbi#PGBaP:kYImƦ+HxdQPDN:!j# >ЄX$,.M/5GyO;`(],<͍8#mu&ݎƏ}6|vٵmzF^ 0fZlx9c˜:˫'XZZdnn $S+4p-j xaE+T@F U RD!V O"BuH!SC̤]V h'w_-Fk%%NDeX]]ŗF˝sn}}eڣc/nʝٷoOT cJ>VѓrbeGv,AG$y *!y[JQ阤OŌ#aZmT U0yAFH7D?17#E0_EFEa&eqb3jR} Ž{hɕiDͷnbщB28tGN=)VNpb}$-"Ҁ6HAh Ш &@ yZ %XDXJ8LPL'K!` v*'jKo_[cn~O=~6~z"gK'^3v(Ǘgsl6< ;n?-th[M,N}啓\]SS]V30tK>8#4PDdH'Z A#] z 5:lB1<7&dI 1xX i) knEz[]6_`aEf8|> > (6Ϩ Pׇztn: )-tRXm9!U k06Oǫ(:ͯ_s7 h6W' l($7iC?KHHy m'U01>Bߙgy_?R~j§Ϟ;5:VfH6HsSΗs\^T`$|KSWEh,+;D *:.k1A&K\]QQ!"2 c ~kQ0|olXV]B8Nf/kU$+O=BV1&Eknk)̓~_}Dž/ ίl1Z9#uR kaw " )s k&eVbM,-rt2;\D$&QJ.`@0] 7z!bN]:a6_cX=MPdLewX1_ Aa؏*gb@Pk&ZY3®<$𑰿uUΟ;f${eRlf11ZV{T R-ugH 9w6oS~歳tiξܸ7ά_ zY~x$'jqɷ P[4fr):3Pt[& ˾igLnמp9 jas9c ]B⭠tM`nf?0S}?7ũRskgb|Y$#A%`B !2X)p>P9ýy}2J57 Ya1'f.Ј A&oqu`eާlG23V0x=qfl Ǐ\R3;9ta3=5t Otz1d`=CSs 2~!&fUsm!$)pb$6b=ܻ͇(=0ÿso}t')w YԢy8 ʆ;NXCngq^SSy[,TR(!^Yy$ˡE 2ϱ)q.;U4Z {M6v Ξ9y|v"H bsB5cؤtd<^#Bwȧ}djeoxMqPR%1.;`6j·ަ߄Ǐ.< 3}mS܀TK*`X 9`Hgf2ֱO#$eD݌C{ʮ~##Whfxŵ'I[$(P7 ΐkJdJabchL5X+Ta[R7J[}C^yy , :]L8m87}Ċ*Ac`L!dɽҜ?C^KC& =d!JeǪ sAYN{O@ b2/F `烓+ʌJ{!67Is*iRcbD5?@(<`dٌk1 ݢc,Do`'J|cx U*JP Y +j4])XvByt?gOy11PEȰ ^*t+=ZqiRh2QWVk õAHE"C޼ 3J%|vXZcçFak`@2&޷I&ɩvt#IQW nw򃴚+V-7QΞ;jRQ*j)Te6<;\4d֦!7=LDʡ=GTTֆ}Qew|,3?KgLyH(-1i Aw*.ւ:3[ 4m%UZ KW'>%ϛǫ|{@FfLwǙN`ra|I}b?;Cõ[=bJA5AN"GYHT!/Iؽ ή asU}ÁS:!R! }mK~,$\Ht(WȄiH ~oZBk65!Mn哑! B[ ޼~%?ى;Uu3|s4ޔ)p0=5k1>cl ZҖM'k+++"&狏3Ƀ5aBPvȥyAUc (ãw4 P;ThKw%kڒM5i!jM @ = c x.JDOP8j@C/^p^3nxWv~׆ȟmSj`Nob/ ?8{kx-K/-1z%WLrLwj~lsUGkFmUeĄ`Q jRXmsƶi2R%'vop17FSFe!Yvwze[ g%s~[a,T]3g _ze7ijO 0Ԑ]߭idy,]ӝ?V4wW!raRL z7XSb(?BZ-G.'!ЍHQHAF@ۨ!ۦ<<Ј~ Ji9 Q-fቧ9'p`L91j 79b'×d-^a3o^iA;k"&^ /K){p,h½7pFWA48j !F?YMIH^S: К䶤8 D[x xbYp \q#z4[\CVއkBz}t{c<4KsF@ъ2o,Y9NcY8X]|uwz[χ@jC&eYЄ {H|ou-/Q ]ZS3i+oe,Gsi*zFeb4ˍBh}y{d4+8}ɕk"w4ҳ2jhyrr4"gəo3[1zLOҨ;ECүjlIFM #^֗ӾJ` Yޡ=|2Y׼Pfף>CM5WJP.uCZZCbB}$uѲ8XBpر#[*fL,qbl!!C}c ũfϔz31 IDATkꆯq- MJwOOE{(,/-bl.n'iJi}!.vv-"rڼ˂lU]x W_= v-F@5 c vfxP\XUANE[xROb5 |@gaμGsku#7ydfGo`; x)0MX`P5J}HSRʲĻXF#cLMQMpi?!HfM} nZʹs6lB16'~-pa*>,Yah-;6FtdCPǥm_I'i !xV18<ɭY0vF# Zߤ/ 6C.c .Ưs+ci%$!3&6,Ag~6J6j`fD]l塒7nr1<玷O<@)H,=@xsk b F[K]1Fȓve-i1wanrcp :}[|o!pW=Fin!K5cF8:N'־ ɪ6V1f@.K3Ha~NSBnl~c ]8싯 ?+ѥx;NQ.%mx'yoN>@} |ᯆ}kVLL#D7:S܄ 0P5~(w)H'6/r2lcD㓃I!ZZ 'FX;'Vz;&.4v|TBrPCZLLYmjBщZ[Nqq{˂E>s)ȇp"K'f3g7 $~tM3ūS DfKo8Uưim-c7UF&9(Z]l )2%v'ך&/ch 4BpBprc}.@lz!WOM-cY5_z_B]>4|ߋ'@Kc#7`{AVasE[&2:{0R`xW2[1_+5<59s9)(|΅m-{7TQ훼PdyN9Su7:uFeb|C[Ap膅!zoݤwOE_n8q&-qClȺ JVtM`}g*Q)gy#GhscCA2 GFzxΪ*ϞACR-i3JJИԔ Dn;og~yQVn0XٶD0cR$53޹WzSPQoK `pӇ"ʜ1\v+nAS.Y.M}fb01;6Q]r3>>C;$`nnRT+"LcVhA޵ 9'n޺ƝRkvmSϡ;p*B7,|j|}"ɱu9n-׼. cnj`Gts2 6h.ʥWzTՐsm6ئ)h rJ2~fvla rg;Tnsa|ܔdTݬ[BasoAǦQ,>$rG M=d,y쵫'%.>q1K!P>t=X+kי߷D{[4Kiʁ GWjdL Ѭ糂pwya˺p 3ָ Ӹk b2:y>Q~V1Two_; E.9*kEOg7mu Y^ b)n 3ʕs2OSBݿ&QW{T~Qb&,ԸPdUPc8z 5~e{{_v շu… k<ok"Ud&EQ)jMhVJɸ*ϖOwRmQ"aeg,o,K60V{.57pI^<-Ԙ25y;A;$zh\f|Rf~ )݅Kړ8?7Dk@a80hI)HYVઞؼK*yz+٭G΁iQDa5' h-B1PH'Gwꖴt&9` -`+ oՊs9lQ[9=|v2a̍)fh%n4CN0Ӭsq9]`Eh\Sdq RDG) G޾Pt~9߫٭UdۃF O.^Z$dGmF}0ՉzY>]4L0 i%XJ P|,>;S7)C'l`M545;*m بHCbB Q8zh׳OMrƨ+UW4Kyj 梓Ma1sq^Ѐ:4~K1 5 jރzƻHӀ14NՆ6MNϘ/4tSawif47 1@XQ׻qzk<4{AeX lljTU"q"Ç%2w^m}`aCǶ9k}k"wI^Xgɏl@Bq5\JDx2`!W`]G1#A\umz>f!LLbP{o"N[Sb2\.bYFo՝h- FL\ܹ!uSޞ&I=O,!/J*͟yP$0a epڨLvuU`| 98"9P_#!Crt[$iMA]GviR wbC l99誏u5Kh)#ORc °Uc' nCQM+6hDrI >CkESڮN2z19rY,WWzl 1G"w^O ǡX2+`8 EUb'+K>O a?sSMAK}? Jp]ζgnRXzmleLF\e'NoK4OA6/vLps}bn7.޺XĐܠL$By®v=nSBd R{ĘQB!H;tD\ [%n Xt=: Xkb(B{1*^9|3Khwmu@= P;Ҙm5mGʙ ?XukZ ϻ"=v!CLm3v/N?T_nwnZ;1ROD۲ \=xˌ) i24NdMJH*;Qnny;$^S37`ys<4H@!"&2`Lwy~ozi$#ymڛbDU0^m'._S*(vIbdA`~a)5r ALڏ \]S./]oF[` m9$_xJhђVswҮp o.L/+suf'vf8?3K"?_ >w9;oS4M5@W]MM$n!Pc`0*m8S WeOP 6p ضaa o5ᅣC{e>hc.d^,͓O=Wno!/VZl{ g Ύ'$[j#UWOy$tp)q!.ȧ<.sQ!6-V0QJ' Baw*j2[4 cE6Y:~Τ-vsID, _c~O _qv4s}<;z'!GQPMb0i2Uе͉t MڪJc|_=u~fXx1&xk/¿xud0$bs it?tcS (|`ЙbH> Sdx'bI aery=˸ﱛ`̳kJvg{blFh(/:qx%g=>G'z탘q =\ :hkuOKk sK1'ç0 9L;=|,>=j?Xd?6/_ǭヘQ*_ņ;hm"hö9ž(,UO84 ؽXcs=AO"dNH(.ty'zH=Zgj0xݛv]Uo襀^ [oҶ7X6tTic9.CRWhp6IUn|eu? h„Rxg>CeAo}vߺ o^ic{Tj3XcAQG6nĸؠgE>!x\Y+GPQ|pɧS'a$ls и35^y ͷk Hj}ĄXhJ,9Vs|ch n/xrW-c<1"7l|E0dHsWvɖ>ٷl,Ĉ nc4)PMg9v 6NDXU%s5Ik^ZsW|l|@ZJBl֭w $&mGSiv /F 3眻e3\p)J.ٔE-GHZ7ANhMRH-&Ab7i$,˖eŤ$jeHξq3-sN8yF$RNqq߼w߽{~mj26$n^"QĿ׽r"]a|xۜo43K4*go͙ gߥ}dOg-gZa {?Z-FEj2 q^Lk# .uNP5f6v @ӳLWq1ãJV]BO>IKQz(O$%Ni":;M!֮ꢦ)Qn x{\8QoG_"Z'Q’k#Kd_<3A!JkMLʳؓ6B!H|*ҙ`Ls3  CI$Npr3 x>A;3KHX1A:a6 sٹX%/MD,/ӝRR?P$~H}4ֳfTqoQXD\dav,%eDs:Ӝ^ 0vU%Wf cF2&a;YYfvo1MK2={_ A&Д# m۪zeŕe. \L<߷UHYtT4od!E–=Y:Z0 v,Ֆz+ȺvZuw&:uX IDATBu*OS})A݁A:Х6䪉H6.,RjQL4oC!ҀqaK,q"޿˔ov/Dޛhjo#МOZ!ςo{iuJxyCezz%"Vl)5?4C~[yY!1:v-mJhE\|RAas‰-m lSǁbŠKKY5Lc(EڻV e43dx?_9|lVxo"iAds!l ,zCHi"! }%$xΠ/S U!Y$|'F[cX~Ʊ;vZx1{f>}`_,hﷅiFh+u%Ү`<ɠrַ,8SU +=W e8!*$Zc`*IEZ%C)3$doE+ˆ3=4؇J bfgFhĖN]2))PIA Zӳ쌔#P6HtV~{O|)™7Nrlcc#/#G{kRET¯F?OgV-0== r\XR$*q!7lAj j'KETb" EMZl-y$d`c;t=NMYX^،A+V$Hy[m킠\ eZkWJggYz 2SFQ"O4 A*J[N),?ۿ旖ٽlٶ@'Z;yPGHNSD_dӦ۫Օdkwʲ-ddr- Ƕֲ &ڦƵK:5:N(fv%4K[g?S aJyXژja[i5Bl=ǿACTWHI%x%`.^if" >'-`Jr" =c&.slã}ϽeZV%ZS/G7 zlkpY̨i@y`_!lϾ!b0w?p{hmw6eRcep&A K@PsI 335:Lss׍1$ʪ Keلϱm..\̄mr\|DSr6DqB[[_ߠ"v^ErQty]VNU/⑜Οv4050*5kMҹ51b6@r\I/T}̢(F|PR*#}emz+b[7wЙ xL6ZG6"bIĊ|-='+1bd dձc C6~b'Yӳe#ac~aLgvv~Ç7.e0;yqbBwN@)g:m;'U\dJST -\zr1Ɩٴ>2vPXkXJDNhB!O\R٦ QK~, {aC]`cHF(O|F3|fybM9K;MGπ(Gfg~}VF@c+}є*EF/:Y]u̶Jf̦b)0[J(fȆ,)<|b/M"eШj=Uky2z[%ϏB=-G#0Q̥Ax!ZAWhliw/\,A1S^(BV4b>jDCmV-K}@ˀṚg( 3VFІcNB#%g.&8_Z)[>Q"MNsbR+^҆d ѺҚ=##:tl)g8&S? Y?$f+?0*gk/^5Рxq?Gӧk]Q+^PuY++Xbd?o-CiXyi366`y^/)asֵ7SsN`sl&'UTV* nޜ#')+)}Byy _=K|+xWΒVbT,C <73"7lDNAKrSx o.?! ٌ\1B"󟧩PGW^9g>ynڿ!lt\LSh8ra-nk m٩osi._}ڥZ G "qeZH`ˆYaK=c4ŊB)e=F[΢2xs f8=k7[ \ s3sLWb^|87m">ٽXl "B{ 7 (DN2"v,F٢%?sL)===ؽr)L.E14wBٵ@f&IT7J.r]-$:AguK5hM$%/8mm{cj Jd,F94i+|l1(-@Z|fXfg{!wmϝned>'/>b Ɋ6۾hii$;\!Z[ؾzփFG&h2stJQD(&癝_ •|?$ev`FY#/zGi }>q Axm6v_/Z<> N4ڷZi})$k -!ܹ-=LBM4OUڙqiJut7upgdh7S8}*7}fM{-4w#{2:-Q.=[1ɸ k\:FOwEgG'/<K+svtu#;SQ]RvÔ63 ?Fak.j&4YlV m$BC \j`0dC"D(XRZ >{˼"s 8>qߎ,҅Mܿ?9Beaٱaplܚ#+z1I. V$LC l{?=5CgDC?8B3JkF/pX;jC-Q*CGziIVbpMJ1(x tWAz;7"#=x_[#HxhOںp}K1ъcte @|ni>A X`׆^~3,rQ.G{&7%N<oѦJB@jƪ54YYMٷكVCds9zriz2Ҵ_^Ic!Gnئ|u 2㣓2[){ն[PG.rf>jBsZ/i:M3V oͅ"<1I46LU Om6Rs62 hnQBkcc1/d{8N'hhgw/ډ)2\N^̤c )\vP̆<̧@KcYs{(xx-q.kٳ ^p-@%{JAs>i.1NT hz I9q_ RByB+MqV8=hUla=ܳlh[>- HspPs X[7y[pXc"i[wC٢LDZ]gqa0J 7'|R^I i0JF IK wb1td yϐ vtt7^2.XuNdB GJPLOMq̛|ӿ@[{~e|low'ҕHYu taƑ"FJE'`%R7Rdq*m̚eMD s{hꇃ@Ķ3P&gx>$^0ez::-5hkM!:-!2BHb VE5V%~$廬 _1vra-jR- ]x-4jhw}cD-Y+gD0ct|r!;{Ɛ|Fs)|f_o㧦GHWZҳt_9-ؾB[E@ WʩK"IJ4yYtn/Zj2HJ{ĈanogjܱػN_)7_{;wE{ڽ4m䈣VtA-N#(&&0@1;?G%0Vг,GQ}BOR]3h/P$'Fb{] B׏ s2 HgU)WHCjdٿ6vl`àtd_/Rm6P1N`үbj #P\*255=Szդeabai2SB,_^Ο;+hb6"#@B;{kCX0SR Gm_?=С0njc#ĮsN կ} L nL!"𰝵n9!d%MCڅ:Iչ VNl`"IblZqȳ& &'ad`s}瘞Hc15(ZCA(FŧOiyX1SQfe=|ה i48X%6#H-ejE J |9XoefU~u:1u"\UD,HifՒgq$M<]WU&􃐾%6~3p6 c㣔 mt @p1#9֞Kcwrkڛ/K{!ͭV Rr5^WnAKi4k"mxg9$CL]&R)x PR{ŮcNi\[;޳i={./QhiZʮg@SvLW53޿eގBƁ#642#Wk6x3ڮbIDATGQh%7噙Ey;:8w uP4b6l ϕf9t 2E_/`!=8V%6vw27 '6mv#V 75*ൠT]rmk,~s -ͼ?G~gձ Z=?Qw=jF[5Nx=Ө@[Qzj{NpzX*֧gwx=mQz ~{paFV'34zp'k)FI@='Uw#I=lr?L'+#/六Tj9U=ݻ7q#(^V5zk o_gұuQuZNY&ݯ?{-'{mv}q(`=nv:RPQf#@|76FX}~)pc)ۆr^)_Qi`e4}|hzٍ]Կ^oW֏{Q`.4@ÍeVK4xDWۡ1d׎IWz6X;~Nz2=Qn#Nzt?BMFIENDB`nip2-8.7.1/share/nip2/data/stock-led-blue-18.png0000644000175000017500000000071013351443023015745 00000000000000PNG  IHDRVΎWIDAT8KP?Z(5PBc 1uu PZqr\&MLux/wy}]~{Bֆ 1!@7P@@O W翀zPmAICLZ}>b%'T1OCi.{=8=,S\s|KЁ3WB1ɜB6fE¶Hl*{7(t*?L-LCSGbl{bE%S1db5(\M@(QH``93/Dl ij Fڠ6]'rуrx|j}D`I#j. Ouchâ 8t͛Im!ƌzRtIIWW>-0DH)[؁:*%2pf(ɤc!~vU5{!r|GY.ϥNy.s()qkNF~V~$v=?Qsܕ5-NΣ}99cz zNx|\F>LX̭(IENDB`nip2-8.7.1/share/nip2/data/nip-slider-16.png0000644000175000017500000000106513351443023015203 00000000000000PNG  IHDRabKGDCIDATxڕ=Q{ 34aYuLFH0؅b-'XVKH72aaع3I wd /rs=k ?OG@|\.,F&f ^ZoAd&q\^^&n7zeY7J)*ʳf1aV\.GE 6Z y)@aPJ!"LS& Z<0do6"B>T*Q(hc.5"BTu]-"ZR0 ](PJQVi4OE8Sm;(HhRvctƯWWWe=ömADPJ1L l>^\\|f#q||uLoiF)u6^^^+V,~SIENDB`nip2-8.7.1/share/nip2/data/macbeth_lab_d50.mat0000644000175000017500000000065213351443023015600 000000000000003 24 38.82 14.52 14.86 65.97 16.84 16.71 50.25 -4.56 -21.94 43.69 -14.21 19.17 55.13 9.02 -24.66 70.1 -31.71 -0.78 64.17 34.77 62.36 40.28 10.55 -44.65 51.82 47.11 15.64 31 22.5 -21.72 72.3 -23.44 57.12 72.4 20.15 68.15 29.15 20.65 -55.37 54.78 -38.84 31.54 42.5 55.62 27.17 82.4 3.54 79.73 51.61 48.8 -14 50.03 -27.58 -29.2 94.27 -0.25 0.35 80.3 0.05 -0.38 65.41 0.09 -0.44 50.82 -0.37 -0.59 36.1 0.09 -0.49 23.8 0.54 -0.18 nip2-8.7.1/share/nip2/data/Makefile.am0000644000175000017500000000200413351443023014231 00000000000000nipdatadir = $(pkgdatadir)/data nipdata_DATA = \ rachel.con \ AdobeRGB1998.icc \ sRGB.icm \ macbeth_lab_d65.mat \ macbeth_lab_d50.mat \ vips-128.png \ nip2-icon.ico \ cmyk.icm \ stock-tool-ink-22.png \ stock-tool-path-22.png \ stock-tool-text-22.png \ stock-tool-smudge-22.png \ stock-tool-bucket-fill-22.png \ stock-tool-rect-select-22.png \ stock-tool-select-22.png \ stock-padlock-closed-22.png \ stock-alert-22.png \ nip-slider-16.png \ stock-tool-move-22.png \ stock-led-red-18.png \ stock-led-green-18.png \ stock-led-blue-18.png \ stock-led-cyan-18.png \ stock-led-yellow-18.png \ stock-led-off-18.png EXTRA_DIST = \ $(nipdata_DATA) \ examples install-exec-hook: rm -rf $(DESTDIR)$(nipdatadir)/examples $(mkinstalldirs) $(DESTDIR)$(nipdatadir)/examples cp -r ${top_srcdir}/share/nip2/data/examples/* $(DESTDIR)$(nipdatadir)/examples uninstall-hook: # make sure we have write permission for 'rm' chmod -R u+w ${DESTDIR}$(nipdatadir)/examples ${RM} -rf ${DESTDIR}$(nipdatadir)/examples nip2-8.7.1/share/nip2/data/rachel.con0000644000175000017500000000011413351443023014134 000000000000005 5 21 0 1 -4 -4 -4 1 -4 6 8 6 -4 -4 8 9 8 -4 -4 6 8 6 -4 1 -4 -4 -4 1 nip2-8.7.1/share/nip2/data/Makefile.in0000644000175000017500000004064613417043242014262 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2/data ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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)$(nipdatadir)" DATA = $(nipdata_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ nipdatadir = $(pkgdatadir)/data nipdata_DATA = \ rachel.con \ AdobeRGB1998.icc \ sRGB.icm \ macbeth_lab_d65.mat \ macbeth_lab_d50.mat \ vips-128.png \ nip2-icon.ico \ cmyk.icm \ stock-tool-ink-22.png \ stock-tool-path-22.png \ stock-tool-text-22.png \ stock-tool-smudge-22.png \ stock-tool-bucket-fill-22.png \ stock-tool-rect-select-22.png \ stock-tool-select-22.png \ stock-padlock-closed-22.png \ stock-alert-22.png \ nip-slider-16.png \ stock-tool-move-22.png \ stock-led-red-18.png \ stock-led-green-18.png \ stock-led-blue-18.png \ stock-led-cyan-18.png \ stock-led-yellow-18.png \ stock-led-off-18.png EXTRA_DIST = \ $(nipdata_DATA) \ examples all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/data/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/data/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nipdataDATA: $(nipdata_DATA) @$(NORMAL_INSTALL) @list='$(nipdata_DATA)'; test -n "$(nipdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(nipdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(nipdatadir)" || 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)$(nipdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(nipdatadir)" || exit $$?; \ done uninstall-nipdataDATA: @$(NORMAL_UNINSTALL) @list='$(nipdata_DATA)'; test -n "$(nipdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(nipdatadir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(nipdatadir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-nipdataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nipdataDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: install-am install-exec-am install-strip uninstall-am .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-exec-hook \ install-html install-html-am install-info install-info-am \ install-man install-nipdataDATA install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-hook uninstall-nipdataDATA .PRECIOUS: Makefile install-exec-hook: rm -rf $(DESTDIR)$(nipdatadir)/examples $(mkinstalldirs) $(DESTDIR)$(nipdatadir)/examples cp -r ${top_srcdir}/share/nip2/data/examples/* $(DESTDIR)$(nipdatadir)/examples uninstall-hook: # make sure we have write permission for 'rm' chmod -R u+w ${DESTDIR}$(nipdatadir)/examples ${RM} -rf ${DESTDIR}$(nipdatadir)/examples # 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: nip2-8.7.1/share/nip2/data/sRGB.icm0000644000175000017500000001541213351443023013473 00000000000000 lcms0mntrRGB XYZ  acspMSFTlcms-lcms dmndjdeschdmddhwtptPrXYZdbXYZxgXYZrTRC gTRC  bTRC chrm$cprt!desclcms generated descsRGBdescsRGBXYZ =XYZ o8XYZ $XYZ bcurv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmcurv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmcurv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmchrmT{L&f\textno copyright, use freely nip2-8.7.1/share/nip2/data/stock-led-off-18.png0000644000175000017500000000103313351443023015567 00000000000000PNG  IHDRVΎWIDAT81ƿ !!!:$"* .Y hK]^,صgi֎;)Y;=rȂD4$"hOZ}]n<ϟR+3"BUU0vpz~ɲ1MSi"n֓~,7<ϟ,{lZHQZ!nOP&JR J)mq8|nucWxA"wꕄi:kv Xk "RC4.Mc=Hk=t^f1BXX3fzSt"Ӂ]ΆN")_kYk"l`g"Bw)6cDJþqꚺm}C?̓jk}:u]9?Wwm6DQ%L-TںE{wʲ|t:=f_ZMQwh49aIDZry| v:ZIENDB`nip2-8.7.1/share/nip2/data/cmyk.icm0000644000175000017500000352615413351443023013656 00000000000000largl prtrCMYKLab  (5acspMSFT-argldesc8icprtgwtpt bkpt clrt4A2B1A2B0A2B2B2A1ѼB2A0ѼB2A2xLѼgamtJ.targx 3DevDx 3CIEDx 3descChemical prooftextCreated by Graeme W. Gill. Released into the public domain. No Warranty, Use at your own risk.XYZ QXYZ $:clrtCyanx[7KMagenta#͒|Yellow|&Black%o{mft2 Z gt(5BN[h  t ' 3 ? K W cn z,7BMX cmx*4?IS] L !!T!!""[""# #b##$'$h$$%-%o%%&4&v&&':'|''(A(())G))* *M**++R++,,W,,--]--. .a../%/f//0)0j001-1n11212r22343u33484x445:5{556=6}667?7788A8899B99::D::;;E;;<>E>>??D??@@=@w@@A%A_AAB BFBBBC,CfCCDDLDDDE2EkEEFFPFFFG5GnGGHHRHHHI6IoIIJJRJJJK5KnKKLLPLLLM2MjMMNNLNNNO-OeOOP PEP}PPQ%Q]QQRR=RuRRSSTSSST2TjTTUUHUUUV&V]VVWW:WrWWXXNXXXY+YbYYZZ>ZuZZ[[Q[[[\-\d\\] ]@]w]]^^S^^^_._e__` `H```a9avaab+bgbbccYccddJddde;exeef,fiffggZgghhJhhhi;iwiij+jgjjkkXkkl lHlllm9mummn)nfnnooVoop pGpppq7qtqqr(rdrrssUsst tEtttu6uruuv&vcvvwwSwwxxDxxxy4ypyyz$z`zz{{Q{{||A|}||}2}n}}~"~^~~Nƀ?|3p'dރXӄMDžB7t,j"`ۉVъMȋD;y3q+i#aސZבTВMʓ GĔB<{8v3r/n,k)h&f$d"b!a `XΡ D0kXϤ E3n \ӧJ8s&b٪Qɫ@|0l[ӮKî;w*fޱVβ E5q%`صPȶ?{/jZѹ I8s&bڼQȽ?{.iX Bz#\=u®VÏ7oĨPň1iơIǁǹ*bȚ Bzɲ"Zʒ:r˪R̊2jͣK΃λ+cϛ C|д$\є>O>>??R??@@W@@AAaAAB'BjBBC0CrCCD9D{DDEAEEFFJFFGGRGGHHYHHIIaIIJ&JhJJK.KoKKL4LvLLM;M}MNNBNNOOHOOP PNPPQQTQQRRZRRSS_SST#TdTTU(UiUUV-VnVVW1WrWWX5XvXXY9YzYYZ=Z~Z[[@[[\\D\\]]G]]^ ^I^^_ _L__``S``aacaab0btbbcAccddSdde!eeeef3fxfggFgghhZhhi)iniij=jjk kRkkl"lgllm7m|mnnMnnoocoop3pypqqJqqrrarrs2sxsttJttuubuuv4vzvwwMwwxxfxxy9yyz zRzz{%{l{{|@||}}Z}}~.~u~J׀\܁]ނ_ a#c%f)j,m1r5v:{?ŒEȍ KώR֏Yݐa'j0r:|Dɕ NԖYߗ"e.q;~šHϛVݜ!e0t@ȟ PؠP3lޢO3lߤQä6oTǧ9sY̩?y%_ӫ F-gۭN­6pX̰@z(bײK4nW̵@{)dطL5oW˺?y&`ԼG.h۾N¾5nJ|FxBt§ >pâ9kĝ4fŘ.`ƒ)[Ǎǿ#UȆȸNɀɲGyʫ@rˤ9k̜1c͔)[Όξ!RσϵI{Ь@qѣ6hҙ-^ӏ"TԅԶIzի >o֠3dו(Y؊ػM~ٯBrڣ6fۗ)Z܋ܻM~ݮ@pޡ2cߓ6| O#i<U'm?W(n?V'l< R!f6{J],q? Qc0uBRc/s> M\'j5xDR`*n8{FS`*n 8 {  E  Q  ^ ( k 4wA MY"e.q:}FQ]&i1t<HS^&h1s 5 p !"!]!!""J"""#7#r##$#$^$$%%K%%%&7&r&&'#'^''((J((()6)q))*"*]**++H+++,4,o,,--Z--. .E.../1/l//00W0011B1}112.2i2233T3344@4{445+5f5566R6677=7x778(8c8899N999:::t::;%;_;;<>Z>>? ?D???@0@m@@A#A`AABBSBBCCECCCD7DtDDE)EfEEFFWFFG GIGGGH:HvHHI*IgIIJJWJJK KGKKKL7LsLLM'McMMNNRNNOOAO}OOP0PlPPQQZQQR RHRRRS6SrSST$T`TTUUMUUUV:VuVVW(WcWWXXQXXYY?YzYYZ-ZiZZ[[X[[\ \G\\\]6]r]]^&^b^^__R__``F``aaBaaab?b~bbc;c{ccd9dxdde6eueef4fsffg2gqggh0hphhi/ioiij.jnjjk.knkkl.lnllm/mommn0nqnno2oroop4puppq7qxqqr:r{rrs>ssttBttuuGuuv vLvvwwRwwxxXxxyy^yyz#zezz{*{l{{|2|t||}:}|}~~B~~ KπNˁ GÂ@~9x3r.l)h%d!`߉]܊[ڋZٌYٍYَYڏZې\ޑ_"c&g+l0r7y>˜Fʙ OԚXݛ c+m6yBȟ NՠTѡMʢGģA;z6u1p-l*i'f$c!`߬]ۭY׮TүO̰ JDZD={6t/m'e\طSθ IĹ?}5r)g[սOȾB5q+o9}GŠSÖ_Ģ(kŮ3vƸ>ǀHȊQɓZʜ!c˥)k̭1s͵9{ν@ςGЉ NяTҖZӛ`ԡ$eէ)j֬.oױ3tص8yٺ<}ھ@ہD܅G݈ Kދ NߎZ3| T-uN&nFe<[2z P&nDa6~ S(oD_3zN"h<V)oBZ-sE\.tGa4zN!g: R%k=  U ' m ?  V ( m >U&k< R"h8}Mb1wFZ)n= Q e3xF  H !&!^!!""<"t""##Q###$/$f$$% %D%{%%&!&X&&&'5'm''((I((()&)]))**:*q**++M+++,),`,,--<-s--..O.../*/a//00<0s0011N1112)2`2233:3q3344K4445%5\556676m6677H7778$8[888969m99::I:::;&;];;<<:,>c>>? ?A?x??@@V@@@A4AkAABBIBBBC&C]CCDD:DqDDEENEEEF+FbFFGG?GvGGHHRHHHI.IeIIJ JAJxJJKKTKKKL/LfLLM MAMxMMNNSNNNO.OdOOPP?PuPPQQOQQQR)R`RRSS9SpSSTTITTTU#UZUUUV5VlVVWWHWWWX%X]XXYY;YrYYZZRZZZ[2[j[[\\K\\\],]e]]^^H^^^_+_d__``C`w``aaHa}aabbObbbc"cWcccd+d`ddde3eheeff=frffggFg{gghhPhhhi%i[iiij0jfjjkkj€Frʁ"Nz҂+W܄5a?lŅJwІ*V݈ 6cCpʉ$Q~؋3`Cp̌'Uߎ ;iŎ"P~ې 8gŐ"Qޒ rۢDyKQ"V&Z¦*^ŧ-`Ȩ/bɩ0cʪ0cʫ0cɬ.aǭ,^î(Z"TM~Duس :k̳.^ QBrѷ1aN~ܹ :iǹ%T߻|'{}ю~}YVm5jgB.ih~"%}I|h}}~͍/gCF-%~|6J||}ΕE~gZMCAx.2Q%1u{@b{ϭ | 6[|0}蕃g~ȎtDE.ʁ%Y{^3x{߷TH{||+(}V{K\0- h|,'|;$f | І:؂ uҀYxc @z ؄fЖ]Nw5~'|R v{tȜ݌zH|f<N 5SC&}} 0L{ѪkڜĚǘ?GxFdGtyMʇg5,&;}L{۪Rѥ*査w Lqb/KG4)&1} 8p{Ĩ R[>sv-abi`LӐ?4ڄr&~P ʆ{hNtș墈a.Lq=5څ']~!{Lԟ/s䙺a+J5'K"P|2R||{T~!Bzp y_kDyI˗z&2nz'|jy"+yϝûʂ2մ ~o}^|ItE|u2 {&"z zd<۲}rcnCf\qbG%2(@}%~{rtz|rl٣[Ʌ.H7V1~$y1|59{"g1C̱|Mɑk.lZG3;1荙)$S |{0؜={/1ojZ FG<1q_l$~} {(ȪZSzꞺj#2)ZBGj2/v%. }p+{ױͱ!zTEi{X~G쎊2&@} ]{=3ycYhW ֚aDQx3 &~W!{wI}jsZ{p,zdb)y=T|xCIqy4/Cy^$uyH+y7ƾrM}c|[T{VC{=..z#.ycyƚ:څpq!bS7HB}-ۑ{"Oz zh{O4p0aI)QUxA6-}J!{'fhz94jpbZ`ͫQfGA_-Ð~!{s)zHXo`#]P4 A|N$.$#"5h{zFðoٚR_9.Q͏AO.ď#3`|W>zP ·I|n.J^PǢzhAO/?^>$n|ˈQz\8"~7Ql`TO\>q/k;%ċZ}l!wz釆B|yziLy\}x:LRxr<x,ǔx"xɊ3xqx_h̽]}6\3{lMyz<šzJ*y IJy؊xՅ@x6?hؼ| \H]Lܪj~ vv޵wdz ~yV38zHe|oB"~5.?f%́ =u*І̱v4|w#x豮zUHc|3XA~\.& c]u=˵vvz>w0Bx0zKa|? 1.,&r*Cxz5xzG{'V|cÂ}@ۂp}-|:$΃.{ٿʂfOցǂxc끧)@V%~,}>$Y|YVǁ!İǀUŁꆳc'@z,e,~`$[}xc9ᘊ/e4a퀐?^,sq$%~דh)|~O~ma@6,Z$U~uԺc~ڬ~k~~}~З`P?І,!$~=U~~M20~|~^_6%>倨 ,$Á~w~ɀ~Wf}巗}̮e{+~^f~>h%,% - p~$ʪ}!}a1z}֪ ]|~ϝ>,Ł׃\%rf7w*ynzX{5z{^%|>?|,|$/{˸'\ w:ڈˀu!~z$̀$^lp> }+|#ȃ|YҌ̼W ԈyFy؅9g^&K=+>a}#mE|=ژ[ᥗx \؃=;Y+ -~#O}Yǿ좻وLcˆ@uwŐ\N<*q#R }ɊwȇԧУɡoIvmJ[IW(n;+[V$p&~dHxI x֟z zr֋5{VZ{<5N{+{#τ{r1bÈPr%XՈQ~;J}C*k|Q#Ec{0 ٯUZ3*bquXׁ:~)ᄨ}""„.|YԕJCĆao0 VJ:X)}"y|Vޚbъo>V=]9DžT)\t~"b|˹?̐b9םɄhOn 1uUT80Z)r"e$|ظwIJ𪁏ߖw0 Km,oT^=8C)j"-|QU֏ܵǖ[ncl5T&8)WQi"߄}&aȩ9T:{jև_Ru헰8)8#p}s9w ux)%yPzkzT[z9di{!* [{#zz0Va~‘~A~lj~>Sa}83|)4{"7{hܑ+L~mi҂RƋ8*~2(|!{Я/iiv`f}Ց3h@SE[8(S}:!|z4&>|ڐhy"Q7j|'}!q|#w0ڍ퓨S{4@fӍ!AP^^_6nY1'~=!v|t{څ4Qрu&B} E{i%vݛ{tq; 5_KsvP3&}n Q{~3ہup _ZYݳ ݭ/yaNFjqOY gFĔ~1|@${>z $@wҥajޅfX'hFq1}$?X{†zʑlȫ퐕vХNhXpE֓0U$-|$jzْԱQ 4=vfȟ(WAEG0Ox$ |ц]zґ;&хkՠu=/tewgVE֊Z0$q |=`zŏp%u@~eWUD 0ڌ$}ItzЏd,tre8ŠpTeC20&%>} zXwz̹wlw_vPwM?x'-Yx#yLy8 }@{,Q|/lgz_zzMPԢz@\z-y"8yy~΃zIgkk^$~O֢}?ښ|,{!zTz(yʊy[Ljf]y{N\?7aA,@|c! zAyベ+xֶ j]PN,>Ԙȁ, J}!{HoyܼxfpjՐt\vNq >cd,/~!Y{^GyѼ(x5iw[N5]?#|,̎"x{=yQwŵhխtZצFMv >Ή-OЁ2#|$_zͻޮEwhYK[ dLΟjH=ė-$ |z.|x%s~vvcںKvWduIv:v*w G^xUVx{|q3{scxz!V{yIWx:Zx(uxIx׉=xzyooc*!Vl}4H6| 9{2(0yy0ȉx{oԿdb&VkuGc9 @}'{(yWx{Ҏnᾣ0bz(UІGʦ׃)90'Q|8݋yxy애n/Bap UrvHu 9J(}};z-YPxy2n̼әaε;:UHD؊9.)0Y~`z.xxWn@ԟQaU.HEQ:DH)Sl!'{ oTy1wJĚlm6TaT&pr擡uJzw\7^{zm>}- ݂% LmΌp er=Ptxw60\yy=}^-Q&bpFM!s.iu&w}yn_€3{0>?{, {R$1g{0;||M}|*u}}I@~B}|c~}_}>b}+|V# {sz{R|`꒠}z4~^a*=΀+Y}p#ǁ|y<rzYc{)8|Ox}j]S~='+~v#߁~}OXxyYz&F{jw|}]}>̃?+ǀU$d}wxh}y~ zv{d\d}=G+΀Հ$5^}svow=xzRu{m2[}<e+Ѐ$ek~ vw>x7~y©tO{Z-|<{C+ׁ$~U1vfwRxWyd+szǦ.Y|o<$+{+w$ց~IpJWsuMwuyYg#z;{I*.z#҃HzϾy {;|G[|uI}%[#}kgt*UZ0";ՂW~*}#-|R#ܯނQGމŕXȁ;/*VQ}#2r|»ӂ#5ڗځ(q\ڍX.:ǂY*?4~#Gc}kAQq*֚;A^o׀FuW2:v8*8!E#X^})B"u58֟1nFU݀W:aP*-#i\}RnD)9g6mymUR9ځ2N*%#zZ}5Zg߼S*m'EiTØj9 @*5x#X}ӑq|rΗ،-tlBvpo[YxU[xzm9z)̈́Rz##z3zxҧz({J݈{mt|bUˆ|9|2){"ǃ{I Ѥ/܀lfā!U 9k[})^||"|{ٯ/+F΋ْ"5$kBT9))M}="`|+./j:`M:~LjCduSp8k)9}"Z|PJq{}&%h QԄG7)u~g"S|hWLYS^|х2gLLP7t(T"o@| ۯCn |Qf.P7%N(6"Y.|9lFʈnތ ze݄ O݃^7"X(E"X|Цqrt{4NvgkxfQry~7z@(jzp"Jzfx皥yinzx{,e͌{Pjr{7 {(K!{("vzŖ|N~jwd㋁O6c}.({!΄>{bjsǒj:v㆞dK̄P_7~(5|!%{(=֎ˎvCc(NЈ56h(0}!ۄ!{4PrC*,tɌtb Mmu5с'τ}!{8ې&$=sԋka M *5$'Nq~+!n{͞Дms`Li?V4]9' V~!J{ޞÒÒ 0r._K] 4ȉݘᦀy&iÑYfGL1󇔃%y|} 5{si.Rz/0jCGX2mF&;12%\v} V{j3qbrs:t9d{uPTʘvwBw/x$y1yҊr_wavxsHxod뜸xU6yCݒQy/y$JzOz k}׀$}r蠘}od}fT;]}=C|z/H{>$mzz>9~.r3]dś+TC )/|#:{ ޅz`>A}4R2p6^6cŇSBE.}#{vЅzm@s}MBnО܏yaҚT?S>A.r9#{Ņpzf &{XGmpY`aޒzRoB%.֊'#|8ƅ_zS {0m`2_YQqΒ Aҏ.#|TzFy /md_P!ᕢ?.R#ㆹ|jLzBz_q*oճrf@ys[sL*t~cy,Oz$bzmsʺ puԥsxvWyxxz\{${B=}{v+{~$*y{jjmCno^q΀ʏtFviw Yz~~<}x}K+ik|$B|5)iOsm5p`g^s}tvgYy<}r+Y0}#|gי$kd#osrspu#Zx=3|Ɂ+ ~$ }&;gjˠnXq rtWgxd=~|+~`$>}ge_i誽Lmepr t6Vw=,|Ld+~A$~}?ezISi(nl1UpHCrsX3w\<|+%I}eàqhHalPJ|oŬqsDW wz;{l,p%Ҁ~RbygykUzo9{sVu|uY}xO<y+z$zFLv=sjvwu y w:z,xt{zZ}F{<d{_*{>#M{*tbud)wP։xrzX|~;@~}G*i|\#w{xrPtLOu$Qw݆py҄W|u:~E*u0}Q#m|zpprytŏvFoy:W{bp:~OD*z~ #w|ȷ1oؠl2qLs˜vsnx?@V*z׊:~L*~#|nڬ Aqs,uamwUMzQ:\}؅*#€}*nv=pXŖr=tڣlw'Uy⓭9}*w$ }gnt o㹄*qɱځtVlqv¡Ty79}g*8$m} hQHl"Np ڀrmruT xY:ny*cZy#yrat”~wjxpngyV z:;{:)z# 6zҬ}~,}~i}~~-m~d~oT p~$9})|"ׁ{|ڡ|a|nU}Sk}̓Rk~8j~)Z|"|zJ"{#xs{mr~D|3xj}S~Z8')g@}"|Ryޠqzz\|p{`h|WNQ}^8.y)O-~C"|vxmyz2n|?zךg_{PX}j8 )R~"|w92p&"} {NoU(yAϦPjE|Yu(Gm2L% ~! E{OZj~]mVw6HohrXR#t\E v2{xR%vYys܄`yǘuq2#rwth~vX?uwF|x1y%Nz :z3A;xzu>zfW\{\W{F2{1z%sz LzyWMہÁCśeV?E;~q2|K%ф{% zqO@^r\eqЅUDu^2t}%儨{ z6~ȒBqf_dq6U4D ˄1I%w| pzX}$\pǕHcɑTDFC0J$ȄP|u⃸zߡ}Kpib2T /Ca/{$56|pz`|Rr#Ϣc˜jSB.G‚#0|-z{xjuJDliۜos^瘓qPɔksV?ŏu.$w#yC y}tptr%jsm^tPkv\@2w-쉓x#Pyyny{wD|-{D#jz`݄yy=q;fb0c[SMׁ=ʍ-|#Sz焔zy1qelPZ3@M=zr,{}"{{yvGGo[Qc x,$-"}{oU`yvp!dLYSLwr=,T3"[a{ Dyv""p`5eY8˗K;},?)"PU{'yoְjfk]nSdoGq9)s)4v׈xb߅yn'oflpy]'qSsTG,!t9u)Yw xyk߮UueѪIvM[-vQ}DwtF3wx9xy)n"x $y8yl*|dѩi|}Z;|QP-d{E{8ܓAz) y y_Nylc `ZYPEE2#7r}A(o{ SyTylBdl>ZWE^PV;D_6'( Q|҇#yN`y jo bȧ_Y#'OΝ2HDƆ7(N}Rنz9K4xifjb"WF&|2{[#oIyMxjxcx\"R4H4=6`1&}# zxhxaGڎZׯWR8H>1 ̀G$ { gyw_ܲYmBfQdH󣖋0>O2q$i|͈y8ʅw_XUYb?OQFǣ]8z*~S9$Ӏ} Ks_ytdWv2jewnmqyPrBUp{^u9;~w+ y#ڀyJplrotpqvTtl#x5~C'߀T}8"6{~p5'~'?}!4{ҝojq}w2}^oS~.K]~b~IsC~4(|'@{!{| |RB|=| m}![}ÃI~4:q~8'G|(!{EhzÐz?z{jDly|\|I:~<3-' o|!{Tysfyz`z4k{KZ|5jH}3e灮&P};!4{UyynVy8znizZ{HP}>3B&n/}! {Wxxyyjoj"z9Y{V3HI|܏l46e& ~- {^ԋXd7gykjVnYqGEt27vwZ%u#x y~Tk݄Lmxtpcj\yrY^u FŃv1(x%y QzWs?tu,vhrx4Xփy(E(y1nzU%zn zv|U%}+u}~gc~+W}D}51{&{!zsVejV;d{^|aQ9|bA{/{$ăz 3zN|ujH]ɁO@"~0){|l$z )'zZ{Ssi]^i]GÆO'Ä@/`+}$l{]zLy݋ד1r/f\χ6iOԅ?A.'1#L{@z,xgpЉØfC [ϒN셬W>,烺="4{zxfn쟊ețO[$L|=l+ŃÁD"D&|-ys3el g|b_4jXmwL9p#=s<,v!>xv%yNrjkQulb=1nX&pKtr=#u++ۇw!xyzq0pi#rasWOuK'v<ۋ_w+;x"Pyd9yp5owhy_yU~:zYIaWz;݊z,Jz"Äyyn"kgȖ*^_WNV'~Hw~; y}D,3{S"ׄz4Ƀym#@gg 6]i~6T H; +|"ozyj:B5c K[SI L:*9}!fz胣yujdϓ[(SFTGڊ9X=#)~!Lz_yDksc"#.ZYՖcQ9RGݍ7_z)_ ˄:zqye$eO^ fnUiL kBn5q'muΆwxdi]YjTm/KkoMA'qY6LZs'uvOx6„xc7nk[죸pIT*qK"Ns?A|^t6ev'֊wʆexqxauvZHv;SI{vJ} w@ޕTxQ5̏x'x @xxau|Yq|nP|>I<| @x{5X{'qkyy0Kxa\XY7pPԜځH\逯?{*y4}',$zyqx^{XbkQH +>ԓq4#-&ψ|ayAWx^X|8PmPH (>Ԓ3jU'&Lj|By +xg^٠8XBPtH<>Pb1ێJ($}R[yx:Z d1SeKhCj:2l0Vo"tY=w8xqZ@h{SZiJvkBuCm9 o/r#Jsu[wixJ[^mSɬenJtoBA)q49ԝr/tQ"vSwͅxYHs!RmsJ9tBuO:ƛu/cv!Čw<wfwXCxPy'HyAy:Ty60x"V(x|xwX Png,H?~@}9tY|/^n{H"yvMxZmwWcaQEIA-ς8/z.7}#z`xwVqPV)H8`@3{7s*%-6r#IJ{(Ux˄wW`P(ĐsH1@uƊ'6S-3E#Њ{mxw_hAZsj^mgdxhp9ij*s=nLRVvrz8{Hv*~8x)$@xy#ceUCgSi %k l~nohVqryPuu7zx)~yV#_y_r@cshv*{GlvofypdwxO+ty7z^z ) }zt"Pz]-}a9}fx~,yj}fo}3Pht|7^z{(}{O"<O{[q_d8z3iPf|mȃNs`k7Zy}(}{!Y{(oYΜ[^%bygdlLVr5yr'}||!q{EWBJ\;ĉ0awf]gd kLqq4y,'}}m!{zVƗz[8`jFv^ezc/jʕLq 5Nx߄'}~.",{nVZb`uebGjKq6x_(g}~"{Ǫn\oa6{qeyQsj)evnNxr7h|v)n0x#<9y kuf&VmIiom1xrodtrNxu^6|Iw(~y@"yΦmg/pjXr܈mu[vp`vxc6s^wN>wx6b{y(!~zS" z~pd| 3g|~kX|uPn}bcr |Mv2|q6&{s{'~{-! zbuؕeÅ6itm%yapLuo/5c{3}'k~{!s{ 7`ԏŔCdBÄh,tkފ`oK]t;4@z^&~|u!F*{:H_LWb߄ffsynxomr'at'Ru@܀Bw3.ˁ@x$Cy.z~TvAx~&w'm;~zx`~yQ7z<@z`/Mzv$za 'zT{}0~vO|~k;}!~^}P{~o~uA6}0| $ׁz (zr|W{Xt!{[iE{][|>Py}{Ba~/o}${[Â.zj|dz5Oszlh?zݍ[{vO|A}/ .~#{Q2zJy yA}"-uQ#Aa|A݂zx,w^pbfgPZ{9jwLem?"&q,u"-wyvɋCe=oÉge^Ik-Z4n7Lp=s,^v"qx8yguw/m mndpZ[rMt<v[,T6xS"yXقyt"3tplkuc w|XԄx;LVy|al}GV}vI惇|=ق|r.{G#₣zkXz pj_$RTyhIo=W-{|#rzypchmŒ^;T(̈I큤`<䂂,)D}"zvynĂf;^LҐTсnIY8;j'*~!{ӂylԜfS ]ajTV[H2ۍ9|)!h{Ogygi0^cbD[~Pf"PiEl: q*(uH e2wL`xhVdbؓpfYiNlE:o8r)vT ȄxOUy&h`kamHXxo(NepEvs08c[uO)Åxw!XxFyegHr`1FssWd]u'Nr`vCD}w7x**['x!y_K6ydݐoyD_yVǍ>z*N)=zCf{{#7Iz*z6"2y+ydl^^?oUhBLNcC 8}*!{Y!ԃyE'yjaR\3ꇚT7gKLB`G7]M(|\ 郒z,y(a%OUZDSҌ7K؊AۇP5օ~'g},ꃍz'-xa!<[iҔR}K&B35}&L~drzHAxZӢ7_=T͟aPO^dk1o%ڈt {wg x[#cDTڞeM;5hNDk K6vBU8l03}%ÆzZy4x~S%,O88JKqBS9`/${y5x9Q˘^rOۏHIBE0u7z-3$R|f~y6ăyxPn^OKX`Dc>*fZ4j#,nN"VwsvxVO~bpJdCf<_is4lp,Dvo"#ktswDxCO6gdIixD"k <)m5oT+ϒr'!#uaņwQx,O|lIdn Co<'q4җr+Oqt vLgwtBxO>vrit:u!4u,w""_wvRwJx MxGơy.@Rye:; yc3ܕy4,.yD#-Ux8x2/xN3(HYA'j:u~1ߔ|*{+"͉@ymxU؄2wMG{ A=i79Șq1=)O|">MyxRwM:Ez@Z9F91)~c"EzpkxAwUcSSeYh_HtkdaoGjULsoQ5;ytb(T}nwH" x9^^`abYegDuij`mnKs!rY5y[v?'}GxQ"U~y/_Yj]l$bos=gIq_ol-sfK2qu5 xxC'}y_!~yϟVvCZv`8xpeGx^jxJpy4x]z5'&}z8!Az28SNX3GD]ocA3^i ~JJo}4w|&}z ZxW__ivdl:Xj Epe0wy{$~{π>zTYv^hdcJWi$Dp/02xځ2$~|WzT xWu\ٞVgbUWhECo90px%~ } RizpoVp[xzra}k{sfYujDxo0|t%[kw^ }|xl_/mcwogim.5zN$ |%z\[|>^ncb`Fg{R'l@mrÊ/zQ$| ,zdLwNW{+wY]InCwbbxlfXSyk+B${o.~t#rwO 3x}tB_xtcmugaw jRxnxB$zr.~Qu#€[x! :y qhxrkmsn `?uMpQwHrBzt.}w#Dy@Dynqwo~slqot_svAQuw^Ay,xD.}yO#7yZTy|Kkzeumbzkzo{\^q{P^t{@x{.\}]z#̀4ziJiz)ziskin/w]BpOs@Qw4.}(|#6zz,{Zgr'ri͌gblr5[SoY,Nr?xwD-[|~#,1{Hށzxfyrh唿g&kYYnuLr*H~oa,e_t?"([w2ԁxuy{_o{1cfR{fZ|jL|n$=m~q,9u"_Gx1xuy&gn^y j emylYzcoK{r<}Ntf,@wI"0xytkupmvqcwsXyuKvzv@<|w,kx"yځyrt@x9kty bJvyWwzAJfyz={z,.zs#z!߁ypr5isd`GtEUev6IWx1={b},~{"ځzyq+pcgqT^s_YaQ .dHh5?TlD4"pO'".t/wUx]5eWgP jG?l?o3Qr'kvR : xI+y\؉l3V$mNioFچqx>8su3ᄲuu(~w xւyXZrVgsNGu Ev7=w63x(U5x!@yD.ycT'yjUzKMŅJzDz;фZz3Iz( z ! yy@TtlSsLV Aj7m.qqb$Exu|:wHxNiIQOkmCc!lMl?Ŝm9ՙ'o,4p0xr})ȌNt"vwxiCќr?fs86s3t.Ju*Yw(#wȄx@xZD@x?lz69y3yG,x(Bx#LxdxXɃSx0Bo=ܗ#:4S~3}{,]f{&za"!yexB=wAхp;570>g3<.~D(S{!Iy]\xx>w^yMv`S~cZmg`\XkfFHpl;2Ox;r%|vK ~wњ-Y*XH~[\|`0amdf"ZiyjGoo[24wtY%|w& ~xTSdcWlgy\~jtjalXgoFSnr1w!vN%|_x a~x֒OoSpdw)Yrg"_GsVetEm0v1hvxR%S|ax ~y3KCyBPy uVzhf\z/UczODkz0vBz7$|y.ymG̓RMrtTRdZЀTbA.Cj~0v|$0|zV!yEkՀ+K#KsRdYRTt`ņCj-.u~ #M|{_yCq~I q]P)dWvT_ˌ)Bil.]u"|{yΉBA}GRrNVcUnR^@ hӉ-u8"||yݓcOZeWTxrg[ghj;aXImfzCrl/yr$}vBcw_DXr9aH]cudb[gchHfVljDroZ0dy1tY$}w]xIZd&]ftaLiecelU|joDpr0Hxv.$}fxlxۉUn8YpZq^}qcc[s?T8htCo}v`/x8x$G}hx^yAiQx}4Vjxpc[yba/yS0g6yBnjz$/=wy#}yyyN2{So&Y'ax_RXe@Am}.w{#j}z8(y"Kqz-Qp} ,y{9"~z 4y{ S߉qXF f] ZbLhӃ=p",Kyi|"%~zׁyyjRHSpVe[Ya)Llg=o>+yA~`!~z?yxwPnsTaYXh_ӑ>Lf=oR+y !~{IJXyqzNpSqqPX fr1\[6saMug=^yl+}=r"vwxwmPZon]eobWZVqf.Ltijh=(xo+|t/!wx4uiac2mjedim4hXokJrnaY7>d)\ZM`ÑQeRFk9:r*Zz~!zy$owTOhwwXd^w]jSxb%G@z(g$9h|6lt)~r vowntZKgtv]7^puaySyveFxj<8{Hn)r~s vyx.iqqacqd#]zp4}3s'v QWxz4y.^syosXGtpOvUrnGws=yt3|v'x% XxwyMZpwQV`rwNdtx3Fgvxo@Sp\?LrCYt~<w}2{|&.z tyu'ixXlSo"zKqmHD's;uvށ2#zt&{~{}yxWkRmJzp7Cs :uӅ,2yځ &~|orzyWxV6~SQdWK [Dх`:e/k#rmuNwTχYP\%I\` Bd69Ѓh/,m$jsa^vv@x0RńD_M߃bHRve(A%hW8ւKk/Yo$Et8wW3xRfKLIgFBj}?7l7(oc/kr%ev?x?0yRVlL;~mE`Co>qr6Qs2.u?%w~ xijF9ωl4ވn.;ap(ys#Uvςx_FXyC1p%=pq9gq4 }r-Wt:)6v #݃>w 9x^xAzv> w98ww3jw|-x(x~#x !xwx?ƅ|Z/Qv;T_4*Y^.](ScZ"ti6quCw=V9HX4o\}/`*Ze#kvHrnhvsx(<\9Y^4]u`R0s d*׏h~#$mv~ swmx9{aB6kb3d-d/k?h(k!o]tw6x9fm6h2wj5-l9(ьn$UrV" {v \x9wx9єl6#m1>n,pC(r9(St%w[!:xgax9r/5֐s1f't,vt'܊nu~&v$7w!_x{ !_x8x95x2iy?-3x&x0!ɇw" x@ /xc Hzxm93~G4 }1S|-|)uz$ym!+x lxI xZI&\Qw_WVg6b\WgrbEni0,wp#|^u(@~w/T^SIWYYth[^g`bTVegLDdll0urS#{u~Mwc~NH`RUcUt W[ed@\hfSc=lB2kpb.u?tO#{v~=wˆHk,MkoSnT`YogQaLq@kjstE.7tv#m{w~x Cu}Igtwn Pzv_b1WvP_kw>hiw.tux#T|xi{ xG@g~yF~ kM~}_T}XP#]|?g@{-tzo"|{y7xZ=x,CilJvW^R\gE[gMNW捀>d@+r{z<x_IJo~"`xPnbW`e]Rjjc@pj-xjq"}t %vYT{w\Xm_X]`'cbQWhgk@o&l.pwr\"|uwNS_y.WHbfl[eC^`hlOf~l?mo-Evt@"|v wNvj0wDS3k jXl]E]nN^dEq>qlDs},vv<"n|wgxG~JQsuYOqsIiUZto\W[fu{Mbzv>=kw7,vEx"K|xkx|F|sK|whR-|QZ9X{L,`{=[jQ{2,$v)y!}ByiHx{GCErtHeOgY2V:L,_=\ip+kv { }sygxy@$oFs?cMCXTK]n=hq*u}O}z"xw>phnWC`J+UfRC}J'\e<{g{*:u~}qzۀxReMeteR+gh X>ZUj^Mngczq!~(tvD|f`Urbb7YRfd]Yh!bxKlgTt"6Oru*zDw2 0xGHxiVx#aZxnV^UxLcGxuBJiux7px*myx Txxg1S_V́nVg[VMa-~BPg}5o|u(yzgy yje4xdfMMC\nQTWqqI]?eh5o'2zH|>yyix@ggqQaqTVsYLt^XAvcw3yi(}hp'tGvJfnV`2o YVpZ]Lar/b@5tf37xl&}Wr>Bu Aw>e jR^]fk`/TmkcKHof?s8j2wn&:|sv Pxbf e[gh"Sjj)I.mlR>qfn30vsq&|u_w7{x`blZd o QgpSGkkqx=or3uyt'W|Avx3fx`^uRXa1vHOe=vxGiLv>?n0w 3t{w'!| x*6x}x][~X-^[~,Ob?}Gf|=Ll{0=sz%{yH`xXCx[Y3Vw[N`9\Fe^;kZ0s}%{zyxPYUύvU_YzM$^C;d@:jÃ2Zr€8%2{{ɀy)‚x\yP0WRyeT"MynY|Fy^;;{'cT1}ei%pt݁v}ZvV:UvY MBw:]VDx4a:yf60$|Zk$|=qu3w\Xjr]Tns_+LtbCmv!f: x-i/{>n$|~s;vx,WndRp~eLrYh$Bt(j97vmY/zNp$~xu-wxVPk|j}Oml_I1onArMo9?uiqg0Eys$~Kv|x_xTh r5NjsZG?met@pst9su.xv$j~*wxnxT'e{FNgzFljz>mzx8r;z0,xay#}xڀxSxQb삚MeuEh>li5Rqn~"-*w'|J$}yzxbxQO`;LcnFhTr>#lJ5>ptq0uvq~e%}NzpxxMOK SD́W>]75b*'i1 Ap\tȁvMYUEI#EXB\*<|`5 Fe[+j!BquwK}a[dH-}1]A}aS:}d4"~h+m5"ysKuqv`xNJzCalGxzcBC{e:t|7h2}*l+U~p"yt/Xw8xIYwHhAEhx$i?VySk9zfm1|o+\~@r"8vVxxJt&o4D>uo=lwCp7y r50zis)}uL"w`x\pxIq5vDrw*z|$ yށwxłx1AOgwx<(:d*7܄eo2;h?.j(omS$q!0u~x2y,<>k7pl@3hmy/Oo )p%hsr!ā~vx_-y$;q7^s3fs.s($t$ƀiu"w xx7~w6 ~xD2D~x=-a w'w$>w"xa!$x lx86}|58{|1j|{- }z)z$y$-8y::; ;M;;<<]<<=*=n==><>>? ?O??@@b@@A0AtAABBBBCCSCCDDcDDE/EsEEF>FFG GMGGHHZHHI$IgIIJ0JsJJK;K~KLLELLM MOMMNNXNNOO`OOP%PgPPQ,QmQQR1RsRRS6SwSST:T{TTU>U~UVV@VVWWCWWXXDXXYYFYYZZFZZ[[G[[\\G\\]]F]]^^E^^__D__``B``aa@aaab=b|bbc:cyccd7dvdde3eqeef.fmffg)ghggh#hbhhii[iijjTjjkkLkkllClllm9mwmmn/nmnno$obooppVppq qJqqrr=rzrrs/slsst!t^ttuuOuuvv?v{vvw/wjwwxxYxxy yGyyyz5zpzz{"{]{{||I|||}5}o}}~~Z~~ D~.h݁RȂ=x)dڄPƅ=x*f݇TˈC2n"_׋PȌA~3p&cݏWѐKƑ@~6s,j#aݕYՖQΗ KǘD?}:y6u3r1q0p0p0q2s5u8y=~BƦIͧQըYީ c*m5xAȭ Nծ\(k7{HѲZ(m;ŵ P۶ e6|¸Nڹ g:ǻU*qGվe<[2yO—%lôBĉ^ť2yMǔ!gȮ;ɁTʚ'm˳?̅V͜'mβ=ς RЗ!eѪ4xҽFӊWԛ$hլ3wֻBׅ Oؒ[ٞ$gک/q۳8zܼ@݂Gމ NߏRVY[[[YWSN HA9w0n&cXL>{0l!]L:v(cO:u$_H0jQ7pUBIQX`%g,n4v;} B  I  Q  X  _ $f+m2t9z@F MTZ`%g+m1s7y=CI O  T !!Z!!""_""###d##$($i$$%-%n%%&2&s&&'7'x''(<(}())A))**G**+ +L++,,R,,--X--..]../!/c//0'0h001,1m11212r22363w334:4{445>5~566A6677C7788D8899E99::E::;;D;;<>?>>>?D LT\#f-p8zC O[%i3wB Qa-q> Pc1vEZ*o?V(n@X,rDRa,o:~HV!d.r <   I  V c - p 9|FR^'j3v>JU`(j2u<F PY b(k 1 s !9!{!!"A""##I##$$Q$$%%Y%%&&a&&'''i''(.(p(()6)x))*>**++E++, ,L,,--S--..Y..//`//0$0e001)1j112.2o22323s33464w445:5{556=6~677@7788C8899E99::G::; ;I;;< >M>>??N??@@O@@AAOAABBOBBCCNCCD DMDDE EKEEF FHFFGGEGGHHAHHHI=I|IIJ8JwJJK2KqKKL,LjLLM%McMMNN[NNOOSOOP PIPPQQ@Q}QQR5RrRRS*SgSSTT[TTUUNUUVVAV}VVW4WpWWX'XcXXYYWYYZ ZJZZ[[>[{[[\1\n\\]%]b]]^^V^^__K__``?`}``a4aqaab)bgbbcc]ccddSdde eIeeff@f}ffg7guggh.hlhhi&iciijj[jjkkSkkl lLllmmDmmmnBijFȴ J̵ OѶSַX۸^"c(i.o4v;|BſIPX_¡%gé,nİ3uŷ;|ƾBǃIȊOɑVʘ]˟"d̥(jͬ/pβ5wϸ;|оAтF҈ LӍQԓV՘[֜`ס#dؤ&g٨)jڪ,lۭ.nܮ/oݯ/oޯ/o߯/n-m,k*i'f$c!`\XTO JD>}8v1p*h#aYP H?|5s+i!^T I=z2o&bV Imft2@BCDEGH I J L M  N  O  Q RSTVWXY[\]^_ a"b#c$d%f'g ( h !)!i!!"*"k""#,#l##$-$m$$%.%n%%&/&p&&'1'q''(2(r(()3)s))*4*u**+6+v++,7,w,,-8-x--.9.z../;/{//0<0|001=1}112>2223@3344A4455B5566C6677E7788F8899G99::H::; ;J;;< >M>>??O??@@P@@AAQAABBRBBCCTCCDDUDDEEVEEFFWFFGGYGGHHZHHII[IIJJ\JJKK^KKLL_LLM M`MMN!NaNNO"OcOOP#PdPPQ%QeQQR&RfRRS'ShSST(TiTTU*UjUUV+VkVVW,WmWWX-XnXXY/YoYYZ0ZpZZ[1[r[[\2\s\\]4]t]]^5^u^^_6_v__`7`x``a9ayaab:bzbbc;c{ccde~eef?ffgg@gghhAhhiiCiijjDjjkkEkkllFllmmHmmn nInno oJoop pKppq qMqqrrNrrssOssttPttuuRuuvvSvvwwTwwxxUxxyyWyyzzXzz{{Y{{||Z||}}\}}~~]~~^߀_ a"b#c$d%f'g(h)i*k,l-m.n/p0q2r3s4u5v7w8x9z:{<|=}>?ABÝCĞDşFƠGȡHɢ Iʣ Kˤ Lͥ MΦNϧPШQҩRӪSԫUլV׭WخXٯZڰ[ܱ\ݲ]޳_ߴ `!a"b#d%e&f'g(i*j+k,l-n/o0p1q²2só4tĴ5uŵ6vƷ7xǸ9yȹ:zɺ;{ʼ<}˽>~̾?Ϳ@΀AςCЃDфE҅FӇGԈIՉ J֊ K׌ L؍ NَOڏPۑQܒSݓTޔUߖVXYZ[]^_ `!b#c$d%e&g(h)i*j+l-m.n/o0q2r3s4t5v7w8x9y:{<|=}??@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~????@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~??`@2 OdJ@``LI- 1S60G4X;*```f:@4 SEi@``Y<#i'VFX`eMfdnnnwgFXFX `st``^F_2V @\xelmSusvJJ1+`YRibKbK@ [+(i u uğ}\Be*YDYD@~llS?9@nn̄~\s)]` $_s_s_hbCCnOgZܞ<ˀɀmTHp'p'@0`v9^^TQb;K2hK ō &Kx`xy=(']H]D "::nm utlk~˕ @Xd@A`@ P  z[&) V£HRY7l z}sz@ { A d&3v 8PS@-Z q(8 9d\Tb<[oCoY@_+o+I0gE@@%bqqW5@(A t ֣((]Rw(W ݲv*wlHe%e7Xqhzj|jQ5O7`Rdl˔o]p?3qk2e["p5EsV2\O؋abjVc`.=?`#e#^Q7 3DV6^8``Zl@ ="fWo<Saqo=9! E%EV_cFcDmds&7E<^vjAgXT`;b/B\dżkwjPu|rvlIxPNoFq`(_w09<A=P['gsÞrǝ}zuCTsMAH\\%[$emmg\8Jma~٘A~}H&@/7Rc_PD"8͐bz~RVdWG:$vdj W0`sҬs^vQ0bdb0 +)Kljb,oā؋iďs =43:Ŭ͒ /3W >5/t$݌$®܊-xW`$ &X(& ҂RUN)#@u;d~W2r>d8!:(qx@l\<)Z]hys,.=?K; Ź:KHwt"X{v ;,UCezֲy}O)u});Oi 83GX6S=gbUtzr8{yK}w4]Tg \~q4.V dWܗi2҈k1m2`mMJ݁:,+KlRZf8N(`9Ue= 2=EogHK WT@( F`;[`D2 RR H.@MY\'^aN7[n#:-=aF"]^`E!N4A\Pnb`$c_cQmewCfA#_krbQ`X@bAq8U `h:gGrџorTmz{on%{~ST:]#C7 -0@gjgf Kap1=%`۰-灃#2tZUGMbCXqw y {"{h!k&L?[;bu*Mc\`l gdhiEހ7`'\|="RP GRGIiMPium'vQ.,<@CA%u~< -p9qGW0]\a5|N]%_A(2XAQF WXƶZmAN_UA/!"PUuY_dprTe'BJ>@rVD2^``֬`CQi`t|}ZV{p>tnvwV)]PTbb.4cn(jFTWjyS.FT8o <_Q_ k9jĝu{pyIUs/KWwwˏoDFCet2uP}Y}{t}}Lna ;m\&UUFǕ7߼Hz@Ҁ9~LyYQSw*se`].:,Pviʈ+ (Fm_ YqS!ON=^ܛ6_؛&{ 7u|:oq .۹.%KkqԗY\ۋ_:V4K "M i nY-z )@ @|S8di=Iw!%r5xC(h`~< =euy0y<|E6\(>Cx %_OGLM6E@S_fSmʭefha]QA6'-@JXO IkY XX(n-D9@<@vJ`=!~aj''z4h-#R.+S %>+>K>\FAF4*!I_)`~0>Q&2&9:)c'=4I[P^BEU&n:=8$QQ04A޿C(5H,&o&B0cH#b b2d.0\$+B> GRku18FwIԹK+90H@ I)eH__k"emXaV\-:ҒK2BP?QHS.<KiuOjEh!jDok s*[b?8fxQW2X;[3]z2hC8Oh>9G"_(~fc|]݂s*[2`Ҽ_&!_etd$7|G\Tu5YZRX>͆ÈhѢ v frz~}zOx.x.=Ks|Im{$-$0Lky){2NFt,ZMeH>(2;?'8 NW٩S|QKg@N< 23 8_;9rAj^nY*W{~gDˠ6"k'!f&W_}u i&](egg\h j9M²tuvVT UBJ5D B/0?HIHPXWYRg-"ǻQsXUS?4' j Z*4>A<?v&SuM">u>)''}Qg>۾aY T 6%6UTp4p1l1k <)< k6w 3)=Z38;<-'8FO H*'4{ ?-W2;bv?E|D 10DAز- !-E"%0 $#A=FOGtBN,7=$Y 43 !P–3ݿ4 m2'$86\7\_^\d-DM6#*,,A<ڼA#@ $};W'n:c6c&fh<nr7(aS!BWF Jت?MoP= -F]mI5Eh-X= ofjy¬e\2``] ^`D&:WO`t/-eh CF&:W{x7wuYy|tG~0zEGx)~Nz* x+E|{GôN[+=7f9ꆆz,T b?4 P59V xJc QS0۵ki7սIUڵ9~rm|y}w"{unMub/@m`/|KQ0slg#TGhVlX8]Hs]@!Ͼp#F:5FL2@K9=&<l;Vi1mp+iv_iBɞJH"DPBYHg&tANNkVJY۴v$}tlnnmq|i^teidg 5Lw#v*8Vh{C+="r"98u+@GVݴg:yzc}$՝mM~1|~+MQN( <* ⬒A]ɹdS"Ne9L|Er›n df],_S^i}keFt|enbĴ-CZ>5K?c7VN[X Dw<>kC`G8LFv]MTNcHy/BM.@4$L&r*ַ. 1Vhp}[=.!gH syrvUZ31 v\~.'}3`0(:XY}j:XznrܿL~<:SV8x RK k "U-TOwr{۽ Фb/)zAz& v)'(!o#2"iʧMfi234_9hU:E<V@\A}2¨ s (?S'A,>SۚNS)XAZ@[ߨNx6@۠d136ĕ[7%81K=nn7GGGLExXdNwIyzya{ uHph"gx^au_`,[`_Q_e 6FWvsMXQ#_Zi".l-w8ڢV Q.j| 14?o|]qmUQ&nm}zMyU}Bw#t]rglV{~>}{ vh*<$惛ҌH %ï_#<4~*i~`_\7YWQL&NN{Qw<kw9fd)m\S#XW1M DpAn.;;2r-S05v8Bì}UKjTM4*}6 (S+(fիp'#:}ZkPV1 5 /8=oMT%fLs^N|jwIOJy0S~xX.Q}VIx.,Ny>վɸ*K u|(? I5*GIqCp"&T)6ݥT%2Ah" '#%*7V":M8G'=;|A#DʧDW=P70q ̐P#Ћ&' Y4 PV7S6OeLX`cuRWgm&ggjc\B]VOR)R~NSOOp/SLerYznsNWP y!fԌD2@srqnkN)]A}`p`[@0`s(pIshpcBdpb\b~\"AS}`lk g` :mq:RAsVctUxKLMHJFfAH~<1{@y,?fst@;Ox߀?j([(TQϖŎ%5:iw2;ֻ-- $$yl -!w&w5-.6dY<;=0_J#!r쎺ے%L¿ WEc g}ȸT 8%  jZ2EQ4dϡVt4oOjpZ1Gw{w0]k`1Wh P&M*sx׬Ѣv"JZ\S7gћ8 G}?"Ϩ8Cx m͘xX";sew)ٻ M@9`~Ȳ .+ c!I# y$O"D(ӭrm-ߥ/lК.nv/#̊y !s9D). $jQOvNOjRaR\SVS.ONiEI@PEBE@&g?Wbif#AER{tV Hoqwgbc_WI.cnqr|m}<XI|,jU3`bGbUcPrcwNZKBGWW U 2quNYfJ7pyV`KSp/|Bgh9&z5h3o1u*|w)iz+f3 *PkkqxÆ_vHj99kb) g t$}d2| y zɱyanmcqy`Q7FL)Uac$__䤖r!e7:n,q |Ոha0,Љ"dcPp]ra0!j5d`i2Զoo{?>`72` F%Ix2 ͏+4Ϧhΐ&`!3hf<$ #1}>Ҏ#]2z0ӅRgǗ"Ç&/+t oP+*cNwon!Gbwе!7;@i-N̏O||y~ѓ$y=jDX}AS߿BLm@dE9fU"S$@-?(D:O]SZ`94RoqGmi;a \Z]R"R&Nˎ52O|WiYeRoBLe MWXBY=Y/ʚ:Wq9E9BA\A @=J5RM3z8YfeP{eAzJJ2^Xi'7ʚ$K"{KmkfXv#:,3PxZdfMO2W eɔ/d2u:{N{Px[eGfCPIjhúOUs^%ƮDptQpz*ZgeQO>_ũ̅`xXWrӏː{N[Nk'cT 96%`0fDEYOzLbC 1=%NEO2N{,)O޷*PB(B(%1z0 .4b&C5*e4FgWTJCOd-yq yKx|=y y! sU hWT y)&wB~c5HYFU>lnzlIpz|x7vA)vBc`I]V01rMLlnIQ vB)dJ`Vi nLzэڜ=ѬbgJc|WV5cm}A^\vBre #*_YYԭZ;mrpX$ŭ TItŃW^ncb _>SU:qgWX3Jf8(SMu Vtj\RLRa ]0Kc|pyKqտmMaVLL̫O{&vVGqokwiIȒe./ZOP7DEmm|KevHX9Po];H.DBCJD%D@ΕQ| x#_(wJ.( H8yCSo> 8y6?69*,F,(,и~ur\V2J>!"aS1_]b>J^B/Y}o4.{s ;xѣymWXC _4_@NC;gc!:%Z*wcvNc)6a@<QDl`h g :6ȣlU `@SFv4;Qj7O:M7SRcc3` у ˜8PܴٙPhshsYT9zX7E8i}gA~s<kJ\rSjN9)5Ifhmd4WMH5FtE/Cs:Pfrq offYQ[GBD9E& 'rv@$n}LiWc]\SJ=:ao!Hj ?4d)PVBZ=VLC95v|~ wd^E:XS/PP: KE<830'˙7~ }g\R4)fKOSb3C{$ *?{ F<̑=T<1.*ΝXj~qY ]R@$I90d3 (_v.*F'%]!'#;^5~WT|N* e:+*(847]<}3: Sk6 z[tK{*81DKVjV Re5uNgM`fJN ;01:-$Ky$^tN-;4[dBf=f_#Y5RhŔ`SiS88(x _#P%1O98jqwlz={3x2Xfzd}oqWSC`'RF3:H:ku|iM+ AT" Sw>S51<\:|]44ǪZgZy;@_NU`ZOPT/j@ZsguZQG9GTd+@ji"HihG<\_TL,;#4R xsf nE;dEf`@V~N+E60_~Nnf$g9a;MGJVJQGv9"2X*U|~ e3[5U\?8I{OMJ:4;- %~|rQ-Q0 P9D~DCi:'5.'> | cyRwK7 Gl(=|E;}80Cɽ16)6!{~ZRL-D=#J8C89k4,*9%l{RLE1'A)0$ =Tj:ݰp+ ,p Q0J gA ,+63F~V2f12[+j1+)SԦ$!IDNwB:b,#"E:?>\>78(W7hW$1tG2h/Ȥ,"1\MoQ:-z&1GJQL LQK CTuH\c;OJ5x4,%#>VU ;|,<6NsQU\VWWTAPoPZJ`ATu2/ U<"uOS{Xns@v=wpwmq{!t'lOZD&SV8p{#WPR\ bjyOPmy'#iQm~j`502k3\bU@TZ:IPEF7*/(M~m#b2`^AMRuKw71*#ObY}NW-$[5,AJ:}3Y,% %| xJSOb)qT);|;5.0'M ~) KFF`BLH'V5t4x*~(!*~AL0F@;4$.yl+"¢# z~FLH?<40|)0l%eb; ~bH @8A1' 1)ZG?( ϡ H@@5%Xz() LqMqp y I7@H@8!"v$Hgxh G;?@6 `!)6*6*!&4 ""G%aPzCSiF / #/1221+Bq*]%'ī UI! !Iz1u 04t79:::5XH3U`-/?v&&zG@2t#4S8hHKN9P PPMCnpNh]u2g.W-(/( 7?FNMRmSprt tipF[|bopwq\Oh9KQGpy{M{W&_p!9MX:w\=`m~NOUS738/(FEDt\75PJE@@15 =TfHF@@3 Qe [ N7VH@@5dn  4kSdـl%S :h!O}6dKy2aHvA;y4s.m(g"a[UO J !!E!!""@"""#;#z##$7$v$$%3%r%%&/&n&&'+'j''(((g(()$)d))*"*a**++^++,,\,,--[--..Y..//X//00W0011V1122V2233V3344W4455X5566Y667)7p778E8899a99:7:~:; ;T;;<* >h>>????@@_@@A8AABBYBBC2CzCD DTDDE.EwEFFQFFG,GuGHHPHHI,IuIJJQJJK-KwKL LTLLM1M{MNNXNNO6OOPP_PPQ>QQRRgRRSGSST&TqTUUQUUV1V{VWW[WWX;XXYYfYYZFZZ[$[g[[\3\w\\]C]]^^S^^__c__`/`s``a?aab bPbbccaccd-dqdde>eef fOffgg`ggh-hqhhi>iij jOjjkk`kkl-lqllm>mmn nOnnoo_oop,ppppq=qqr rNrrss_sst,tpttu=uuv vNvvww_wwx,xpxxy=yyz zNzz{{`{{|-|q||}=}}~~K~~Xހ"e.r;~G̈́R؅^&h0s:}DɊ MҋVڌ_%g-n4v;}BŒH˓ MДSՕXږ\ޗ`"c&f(i*k,m.n2xIӠ^.tDΣX(m<Ʀ Pڧc2vDΪW$i6{HѮZ(l:~ñLղ^,p>ǵ Pٶb0uB̹Uߺ#h6{Iӽ]+p? S,uO˜*süNė)rŻMƖ(qǺMȖ(qɺMʖ(r˻M̗)rͼNΗ*sϼOИ*tѽOҘ+tӽOԘ+tսO֘*s׼Oؘ*sټNژ*sۼNܗ*sݼNޗ)r߻N)rM)rMN%[3i AwN&\5k CyQ*`8oG} V/e>tM&]6lF|V/f ?vO)`:pJ%[4h9m >rCxI}N T&Z,` 2 f  8 l > s  E z  L S%Z,a4i;pCxKS&[.c7k ?tI@~7u.l%c[  R ! !J!!""C"""#;#y##$4$r$$%-%k%%&&&d&&''^''((W(())Q))* *K**++F++,,@,,,-;-y--.6.t../1/o//0,0k001'1f112#2b2233^3344Z4455V5566S6677P7788M889 9J99::C:::;:;x;;<2">a>>??Y??@@R@@A AKAABBDBBBC=C{CCD6DuDDE0EoEEF*FiFFG$GcGGHH]HHIIXIIJJRJJKKMKKL LHLLMMDMMNN?N~NNO;OzOOP8PwPPQ4QsQQR1RpRRS-SmSST*TjTTU(UgUUV%VeVVW#WcWWX!XaXXYYWYYZ ZHZZZ[8[t[[\(\d\\]]T]]^^C^^^_2_n__` `\``aaJaaab8bsbbc%c`ccddMddde:eueef&fbffggNgggh9hthhi%i`iijjKjjjk6kqkkl!l\llm mFmmmn0njnnooToopp>pxppq'qaqqrrJrrrs3smssttUttuu=uwuuv%vavvw!wawwx x_xxyy^yyzz\zz{{Z{{||W||}}T}}~~P~~ Lʀ HƁC>}9w3q,j%c\؈Tω KƊB8v.k#`ێUϏ IÐ˲Y.uJصf;ʷX.v ]QF:ݽ/Ҿ$vǿkaVMŸCÕ9Č0Ń'zqiȻaɳYʬQˤJ̝C͖<ΐ6ω0Ѓ*}$xrmhռcַ _׳ZخV٪RڦNۣKܟHݜEޙBߖ?=;y(bK5oY C~.iS?y*eQ=x*eR@{.iW F5q$`P@|1m"^OA~3p&bU H=z0m#`S G:w.k"^R F ; x / l # `  U  I>{3p(eZOD:w/l%bXMC9v/l%bY"g 7 | !!L!!""a""#2#w#$$G$$%%]%%&.&s&&'D''((Z(()+)q))*B**++X++,*,o,,-A--..X../)/o//0@0011W112(2n223?3344U445&5l556=6677T778%8k889=99::T::;%;k;;<=<<==T==>&>l>>?>??@@V@@A)AnAAB9B|BCCGCCDDVDDE!EeEEF0FtFFG@GGH HPHHII`IIJ,JpJJK=KKL LNLLMM_MMN,NqNNO>OOP PPPPQQcQQR1RvRRSDSSTTXTTU'UlUUV;VVW WOWWXXdXXY3YxYZZHZZ[[\[[\+\p\\]>]]^ ^Q^^__d__`2`v``aDaabbUbbc"cfccd,dmdde0eqeef4fuffg8gxggh;h|hhi>iijjAjjkkCkkllEllmmFmmnnGnnooHooppHppqqGqqrrFrrssEssttCttuuAuuuv>v}vvw:wywwx6xuxxy2yqyyz-zlzz{({g{{|#|a||}}[}}~~U~~Nˀ Gā@~8v0p6x>†Fɇ MЈS։Yۊ]!b%e(h*k,l-m.n.m-l+j)h%d!`ޘ[ٙVӚP̛ IŜA8v/m&cޠYԡNɢC:|BƥIͦPӧV٨\ީ a$f)j,m0p3t7x;}@òFɳ LϴRֵYݶa'i/q8zBǻ LѼWܽb+n7zDQ_£*nò4qĮ'dšXƕMNJBȼ7tɲ-kʨ#a˟X̖P͎ HΆ@~ϼ8vе1oѮ*iҧ$bӡ\ԛVՕQ֐ L׊G؆Bف=|ڻ9x۷5tܳ1pݯ.mެ*iߩ'f$d"aYw#\Az'` F,eL3lS;u"\ D~,gO8r!\ E/iT>y)cN:t#] F/jS=x'aL6q ! [ F 1 l  W  C ~ .iUB}.iVC~0kX E3n!\J8t'bQ@[8  ` !>!!""f""#E##$#$m$%%L%%&+&u&' 'U''(4(~())^))*=**++h++,G,,-'-r-..R../3/~/00^001?112 2k233L334-4y455Z556<6677h778I889*9u9: :U::;5;;<<_<<=>==>>h>>?G??@%@o@AAMAAB+BuBC CSCCD2D|DEEZEEF9FFGGbGGH@HHIIjIIJIJJK(KsKLLRLLM2M}MNN]NNO=OOPPhPPQHQQR)RtRS SUSST6TTUUcUUVDVVW&WrWXXTXXY6YYZZdZZ[F[[\'\r\]]R]]^1^{^__Y__`7``aa]aab9bbcc]ccd8ddeeZeef3f{fg gSggh3hhiimij jWjjkAkkl*lwlmm`mmnHnno1o~oppfpqqMqqr4rrsshsttOttu5uuvvgvwwMwwx2x~xyycyyzGzz{+{w{||[||}>}}~!~m~P2}Ɂ_A׃"mO0{Ɔ\=ӈhH݊(rQ0zōYTlɐ'>Ukǔ$ݕ9Nbuљ-@RduО*ߟ:HT`jät̥$|Ӧ+ڧ16:=?@ACDFHJLNQSVY] [E/~̽hS>)xdQ >Í,{jź ZƩIǚ:Ȋ+{mʾ`˱S̥H͚>Α6ψ.Ё'{"vrpnopr v$|+ۂ2܊;ݔFޟR߫_n#~5?_@`!Bb%Ef )Jk0Qq7XzAb *Km6Xy"De1SuAd1Tv"Eg7Z}+Ic}2I`w.D[r*AXo(?Vm'>Um'?Vm)AXp,D\s1Iax7Og&>Womft2@BCDEGH I J L M  N  O  Q RSTVWXY[\]^_ a"b#c$d%f'g ( h !)!i!!"*"k""#,#l##$-$m$$%.%n%%&/&p&&'1'q''(2(r(()3)s))*4*u**+6+v++,7,w,,-8-x--.9.z../;/{//0<0|001=1}112>2223@3344A4455B5566C6677E7788F8899G99::H::; ;J;;< >M>>??O??@@P@@AAQAABBRBBCCTCCDDUDDEEVEEFFWFFGGYGGHHZHHII[IIJJ\JJKK^KKLL_LLM M`MMN!NaNNO"OcOOP#PdPPQ%QeQQR&RfRRS'ShSST(TiTTU*UjUUV+VkVVW,WmWWX-XnXXY/YoYYZ0ZpZZ[1[r[[\2\s\\]4]t]]^5^u^^_6_v__`7`x``a9ayaab:bzbbc;c{ccde~eef?ffgg@gghhAhhiiCiijjDjjkkEkkllFllmmHmmn nInno oJoop pKppq qMqqrrNrrssOssttPttuuRuuvvSvvwwTwwxxUxxyyWyyzzXzz{{Y{{||Z||}}\}}~~]~~^߀_ a"b#c$d%f'g(h)i*k,l-m.n/p0q2r3s4u5v7w8x9z:{<|=}>?ABÝCĞDşFƠGȡHɢ Iʣ Kˤ Lͥ MΦNϧPШQҩRӪSԫUլV׭WخXٯZڰ[ܱ\ݲ]޳_ߴ `!a"b#d%e&f'g(i*j+k,l-n/o0p1q²2só4tĴ5uŵ6vƷ7xǸ9yȹ:zɺ;{ʼ<}˽>~̾?Ϳ@΀AςCЃDфE҅FӇGԈIՉ J֊ K׌ L؍ NَOڏPۑQܒSݓTޔUߖVXYZ[]^_ `!b#c$d%e&g(h)i*j+l-m.n/o0q2r3s4t5v7w8x9y:{<|=}??@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~????@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~??QE|2#[t9hdX]j3YqQQWOJ>09Hdq|*j8JFTx*@sTScdZCSnSQ+LF:`#Ar~ x1wTgTg q~Dr7aaBPBVV^SP@=rL_୯2o]i8/=YVL[ydyЅ9x~D`mt]`CX,V&}Rm:!|A_ u+,wI`HaH 2oS on4YX eA/hl8{7%_7s]tL300($\pL[`Rs,TU q ``_0 :`*>(&I:4Rq_JK2ꮕx2Vdj` KA]<%6@1T#y9 R!lsBRQ_S ;.PXyX1wadUj^9iVURtS7Xq-|ם{ȏ#3Eg~4?YYbzLN)w e c{SCfUy?Penuu3:^]] d)7BmLoj[>/+t!9/2zmf?/;[Lkg8#k)`}~*?s @w$@lm]?`,Z%C;beK<>ˢsӫ׹6;݀ }ks ]Yz`=aM$_T)R+>;O`}0`5 X e0vc4yI<872c0}^ O)?D\_|uav;UP0S8c̎-XF(4 .LdY6iU'> FnODIԲrɪ&:z qlub9 f$e-:zFcwWŹYYm=3(thB @0;#Zm z  1<} Juty{TU`o]z] ik `W OS@@\q$\%*5X^x_jNQ~O0mx}j`Y d17T\{|jUkC$Lr<GR*=^>h[yyMOFw/0 mͰ:F OXL8\g"*E2{A=.92h]zTD,}j.1t)a}_h p8 :܃8JUPZ A/<>4: ,,}G]W bkjhqZh ?l8Kt@NAC >O.9\@3wo)*j4KBt JIW'Neh/AMnn5dYkVlXRRQQ3;~>Ay_lĸw3~`v(OK#f'1prS^x`d\QP}RV/$>1@a[VnAmz@>p$/KS4d}Dlhzic[GW5ەnW|6oD{uT#_MR];}h_z-{y}kY?eʪvp |FzNr["7a[0<>}bV~7&!|Ƹ~E*[~q hEa7bbphHfB0z P79"xmlF\u` t#&j37cVBunA'=9n {ܢ@Φ5lu" /[I^`)^7#0PFJqz`j^3&-Y;?V^|^}f je,6<44g1<$lWɅ 5l.B?r~ѣ-Z& `,- jq *d=Airx{4xNǎ`Ⱦ>ǻ=(L."bx#Y#8 "C4L':Y>#S&{9Wy`;al ro \ VS?N@AY72w!u/'& 0E@:^ۑE9 =I<G" 4 E E:+C?E @ 7X+b1;-@'e$eS$Sh#);)(2y4pAlAl %`(^M``YTO9O#P;8z8޿Q/ʗ`jszf~4{! qBG\ jDkahcE" SOoaW[`#0.oIacl>wC~`*[U@3GXv@sK_lvt&s2l5<`"n9z^BT:u%-)QM\i4}^Kxzs~X`oFH|cX)ՏFx (RR?1}My&TztSJ^n=x3 )XU3/2z =~s𺝂ZyXImF~p{bge,hi$F@hK nf,F,f7Q䀧#\̗h s(h,~]\q1W= vm\r1̡>"7? emebYEzyys3pp>d=Y #QU+KëL0g g-:\JqSo`Q&)dڄ|u1k(t~E[,yGm|\Cͩ2Mpo X ZYX{+?18 WwBrfbpz ߜG gـ0jd8B 9H FbB@+"v *Ͱ'B0pO\X8`"h+ 4ַ Lr l2IdBOo"A9<68 c)Z*)Bs9,:@ͣF tM -r'un "'):B,F!C:d.x1>]+d!2$p#" 3U(Z.sɰ=!NA9@:K0J,)9$@ ttF!gig@0s G**nXHZZ<`V MXTPv887$<17)rI6U6_ӮngJmmC5!JfC``^ nQaSW_l=D,+GqVaEip%r5rN2#cO! 'n,@eajbuzml i8,F?zόV/a*GkFWsYwvwu ~8J)nvsP6Ihx~;W+a,K]PY)<H"" KJl _3[ġBqGOM ^ Fά]KΦlr2)? !Q?@+B4a<'>72~'p&8!&ԿV'yABM0l)~(Sv ˙45Ta~pr 8xhv$~g $LX=g$?TLV4z+v;zNRX(3AJ";غLBWin`\inlއX}q =i~~*BB7ELB~`*d7?;UBnM-iZA H<Cg,>A5 $p%n~1O!]#/ v+ܜ. IY eSi$E=A58,9)lH(W B]0\x&Al2 >6,-$@=F =p =Exy}e?QQ6U!L=+uKuIp;'J4bWE^ji&~k"'j4w揣la[ThO@Gh+S9Sbaէw,. %̰. > PSF{n)eª**0=W)?oW6d ܙLtYO\JKF,}@z+le L^X1[G$lRU np{Ly/^!c>.9k-N6$%D!?uf\{`X}!@grdA+k4/f%].L@ Z  q (oKuWA8 "[9-8GMo3a888941fe'mH["HN$ßu%D;i(5 JC$'=K8^=>vI>z< &#@5#/H?,f$N!DfEC`F@jNADDH.S(ɍ%2rc*b+Mdpwjop l!eUa` afl\qqlrw$N:Y0bTWu7wl=\y[X}j%y~<Ewb}oEzqR:ۂz$wfAJLd8߷|#ʏ3u;EMw6caQ[%W#QbYGߐKvt`(h;`Irpx,Рٱ^^q ꨸ a \. ﷔/K\v-0#ydcRJ#GC|??zRnW9+T6ɶ͚ gwK{?{+rtB;z{7{~ tcpvkl*4>Ďˆ2IX<,U;Gd4\KX7W_RaDY.^ d6h*d#˹]jpgi%#+vJ8M24F?7у&ȓ0p6M>EdIfLrQGX-A;,8{ Qim%No!̽$ޕ` Gۣ|Qy :;,09!`te 7~Ҏ q> Dq:5?ٓb]-A3$ 1>S A tW p G }W)O4بkUlF?b3Q5Q'_9:@5E\ENvN M< Z = Ŧ .L.C$'m5(M*PeS-+)%ٝI 1=2/)t+(O0V(I(_.-,'ݭ,e߯ ь [3cX82I 1)M03G-m_3p5j4cL3$Au qǍDd?9$$6= 7>!:Z9x?=Al7,ȼ ŴKtu `.CGNR >wX@]`d|FI5zYp0=_/ ,ё(ן&`a: RqM쏔ᨕD9p~,hÛ"qSMr~iۛwzyg-QYR.GCA߮ JT(~I `6}3h*^;_rfz(lyourvqCtlv:ˮʝIKIY|R%R/OF׽EXjEEDHNR%Vȼ'ǼoB)hz``d1:S}'q+8$\{10BG*`m!(;.)Z4ƣŢc(e0ϦjBOE 5>3~ Lr ~ 7 *joe!2Ƈ<]Sbsz|jS j6$%!Fp "Z, 5J l , Z&r?L'=L}UZ36H+ ;Mqqbr DX̓מYD iy F_$.<< p p 0u@[y O%,vG)![VV [#8 @LYnLL! /DӇ - 6 'L"2!2Wlw #aszcV- p'G?W&&P'6K+ A&^P)'#U!$J K(DX.- I)!$E)S= ++Z ,|,C+oq+&\ 3 `;,$8 7[0F_-/6i3TR1xs65J9Cg45X/4!'i&0.+6BWBJY&&@'c=3HAGIfZ@EيE5̕iDq BIC=ÑFRN܆TMdNK^QKpe%N7h S0PMRewVglPn4PejksOg6oWknlgtpj\g\a8eq V ,B9w|v_!lψ{Yh|yh^gsilYO_KF0B7Wr1t.tx"va iu.,m%EtiQWO=VyaAC!NЅ_ lǒΈ ߋډ`I$Bmr|qh{8etxgdh#k]xP`QOKϓ֦Vf.mxܪU+'UvqJI8OWu_sNb{peWm2gڕ[ѡ?$x+)eH$;t~1ο&0-1_K47w=A*Ey+P-۪/M~{bh:TC9+sg#qWxkCPLF# %wҰjѴzsL^;C-'b mc*Vw Sʟd c!SYXѼ~EƞhًOG6*M 8 z, 6vTI$LUti; ȟs#YN6 `#S  +/KK n$rH }b?6F/*bb 1*E`Xc'*S[@ XVTk6 6Oy̋M'ޱkhʹvC3 = C#\ ?_)OS g3~,=ITp/4 8 Lmb{,gIC !) %O>"a{jR?p&Ӣ"95Y)*,Y$# 4&!$'\cJs*#'&#7 å#[ e'4!4z8L , .'**A+zޱ`t)/,I)"RF. 59';:"@}GcAA"NBB !(=.fը 9rԲ5*HIh_Mj!aca^udYh=OQ2PkPfQzձI 3:=H^WyN[SnJQaŪTUg@G}6uY-( e4fZeOdv`Ʃ]DŎ7Z eBEezôs}{s'R ِw԰z0z4vmrxy U[u 5Z_jvpRhöNaHS@^^WUmVrqOtLRti(s M@(|u{hlI;B|rF6Z47]?HvHSptNk~RiTʖ4$1+#$ylg6 TbDA).j,0!';,4{/33B/Cp[A'L ڙ`Ƴ  BOƛ4;*|~gP.2J~r[ae'^ةɄNr'\fDh* U.X%M-a'-|gQN5f F-QoL=149] ss֠YPW@6m'-L0` 4 Wi 1TASS e9}+ Hhexw -"SF  D J,2AtA7L5D5&E7Հ~A'$`$>$b ' $+9)zLxbYP^uN_L`6ߌEaD؄DNA\>,627m"ueBjA@Zbwf%4z( ~T`7XJhVKSM(AJWz)I;Ym:43CoTi>3_]&of$ssy^zy vj ʴmgjie`VZ:uZe`Ka&M:jM[Na?\Σ9[;YVkESTTa(SsaPD`r{\F$G- *! g2}Yo`~ i O5~A`<4SdLhw!2w.<.L]-sP1ۃz7%i1j@)6HYrtHФjdKib!8L"0B4Vq݈3?3Vkdg)2:OoFcV}pɎH@L  +y40,תDMXn:SۊvO,anmAmK   4Lc<MR$ր'q5nK9i;*]j(h'w%Hū Ty* n\7] 7Sz VzsE3^L+ITFuUAeV<<+ 81,M#b:h+I\N8. Vj.P^3/QJ9δ2?SD;tf&ttoHdH#H2@:~o:hG9JO13"Z/9GSRK!"GI & Vf&YbOfY czZ^."XdO}mJNbYFZSKs@zQAm<OrS/O(=R( PA,cM!7MEKRKKIIm!qd[jtTURF$\6r:oN zbIy؈ zҽ 7x5 dqf#3[,"[,Ž}\}pwf^`bMe3nwdNKT~>!x w Ķx7"{ltGX*w @"b \#Rzz&mcA4gtzΆdIwN2կ8Ɛ0M[׾ܼؠ N7p癉[EB-)kѩVE`Gkն}gQ0:w"DR!qD]'pvTGi-ɬ>t|^qYE*UF9<'DDX)gj{{ U'^O4AԚPҿb6qw{Ƭyw}j~6aޓ!]/>#QN(Ұ^ϫw}ESYN<(Rݼ(ڪ9~pJ9]R4x65/>8T t7 b1sBQvT/h.bƯfN!oӠN(d579I[Gq |wAui e ic+F2+R=a7Mhu~E3r &x Fm&c~/_!1ْ מ54'A5Z++s#C\n al,jQg$J[9BBChCi? E@Ҥ-0*& Uit 7\Yw P/bJ4WM!D#*B? >A% RGay`O\&Ș?S$@W:1/on,Y.D(E:[@vK;-m6J3l#61(.A!OHx HNMRI#IBpY2=U2_ NbW{NR^GyJ[B8I`#Za- mk>h-pTiuh,l_QQ mn&bmYUWSZBnU'q*dpEz*DEQq0}bǠt]kij'zpyV|@lbigRNjj`4xR)IjtΩW@v|`uRpzY,{A|?& Zkj4;\\KJDʫǁM E~VfOE,6Gx7J'JO@^W/W׎EGs=\4F0HEm.K=^vMZh0E9jTó: {2547IE`u ђ  J++r6BQTcz"+bjx NihӨ̴ jBJ=',2j?OcCr{,O?w~;Cj}l<͇Wˣ d.W=BwNT@d~G9ۆuwիѓ?Mº'W6yEX!mDR[QtxxJ)Ɵ o C+P;I7}]C}.~ubljJ'PYf}/p? kQThxw5ipCp:Էkcb_bY"W#8ЧO' |'i!]T6mZPYIv X(WPi#W@-DZ,@.?^"bi e!&[zicrnO U ]E(>?#Gl;q)I:xh6ɖ/ *QBF @ z?a3r5}0(+|&`!M!z:J3 e//na_)?&D$"E %l-/BE{(;%8e1N.%9+*4+6k@@B@$:~/1$m.PVvMqCCDV/G X g+i~6LB.TgYDܬz 1'3@SiiwM֝Zxzr=ǁ^h'T#@"0q?`T lM^ +Txo^n!O/ k)&7-E}Z~{yRwmlmkCx(Anyo-m;hMQi]k3i"o.Omo#iRd8`=`Z5) wuf.$jZR2V)C'U+`RTZ]6G[Y TUOjmĥ~nRyd$T;`nIi()Eh=BsZXD=CD BF\@;s+|GPalhA R?8v4:r1r\/*r"##){,&&n. VZA.b! )N<.WwG:^% 5L Q8Q:4x/\(ME#k0!F7%1W 1O12`.qX1,(v'% 6DJDg~:YO39.$1;w<&.@wKQ O$P<MEfNftPKƹMHpLU6T37a{bIjX8QR;T"]ggjkX#voEp;ox wyu=dLpyk^$i\, Z"Q: Xqul@HE1{׉-a5I4E ăMRǽ.ˤEV[nΉs޳C}ao2WIB1V om $Dn5KIη[j-jAy രte[[o>>  l)^4@s}Sl>>0Wj6}oЈw2߰r91 '}J&2}>;|TrcPx~,wۢr:kqkb> #1;}?F{X[~yق<A$xzqj*d0#[v*k7gAK{iWhi@mjޗh`\-ŁC q5c"X.wT>}UsZU?X8ZT \[WS(3t`cR hG#$4B~4@NC|B"INN&JG[1,l~,XfQhA 5j2-1Fe2w/3cم98o4 ;"J[ _r @VD.'U&+$Mi!| pڸxG 6a" l #Q!}!G`L 6 ! 8 ) h[TJ= 0 ֭9/f2=.n'T J=3'n +@-X bo5ҳ5j;. B}:S_d28H-+h1&X(2lR+'5(k]#wX&i$p!KPEnET=<6%8PApA :Ni9VA*8Lb2s63C3)! Y5~Y^`OII:2KUK[XXG'WOAPQ5j`TKmeT1P,iO3}gqbV\?\%iU@rzd$"5!V]pԣap[?u%dnL p1| KXKr)=|rSidնjkq@vsMWā@=,v8&D9/N8`;okg'H9RB]f5N9 s}9.~l=Q `lk~ߧS8@ xMrk'f2 jdBM hjXGlRt6opq;nBlc -y sj%e 2I cJC g\k|npQnulkug}{ s>1ja#c1 aF e|api.m9gnk~e O[[#x|m*_~UM*FR.;]UXV ~,X$$\Ϧ`Vo`OP1nz]s ObkEz B2AmMCuE+E&M,F @GxaP? 5/42+/E1Iq 03 0~96~20zten'UB01(%"$Bzqse} e} aJS-6!::" IO |<t d6qU#@ +e" $;IK|*? }(;+)f M6M7H^r)SkJ9Zx 馄ʂll7:v4Zc,A% * "#tX3XQx GJ^h+@VOS8r73 3:p5z .*@(_K$,q$Ъ $% UyU]%L"EE-GQORjOM?)yJDCG"g"Hqp D3PEO:7v'5dm`7S'Zs;[!d^l7 q r" uJ2vYRxx))!nxO| sa#nHo/zM*ewCwOS/wit(zB#pVM=Ɏ'. ['J:`Q\yƘr**&AgF2d}BLg7xA(D0sBS[şo:DΕ8uEEF.[@n%R 7eJx/]Bp(V ;i ! O }  5 c  I w  / ]  C q )X>l%S :h!O}6dKy2aHvA;y4s.m(g"a[UO J !!E!!""@"""#;#z##$7$v$$%3%r%%&/&n&&'+'j''(((g(()$)d))*"*a**++^++,,\,,--[--..Y..//X//00W0011V1122V2233V3344W4455X5566Y667)7p778E8899a99:7:~:; ;T;;<* >h>>????@@_@@A8AABBYBBC2CzCD DTDDE.EwEFFQFFG,GuGHHPHHI,IuIJJQJJK-KwKL LTLLM1M{MNNXNNO6OOPP_PPQ>QQRRgRRSGSST&TqTUUQUUV1V{VWW[WWX;XXYYfYYZFZZ[$[g[[\3\w\\]C]]^^S^^__c__`/`s``a?aab bPbbccaccd-dqdde>eef fOffgg`ggh-hqhhi>iij jOjjkk`kkl-lqllm>mmn nOnnoo_oop,ppppq=qqr rNrrss_sst,tpttu=uuv vNvvww_wwx,xpxxy=yyz zNzz{{`{{|-|q||}=}}~~K~~Xހ"e.r;~G̈́R؅^&h0s:}DɊ MҋVڌ_%g-n4v;}BŒH˓ MДSՕXږ\ޗ`"c&f(i*k,m.n2xIӠ^.tDΣX(m<Ʀ Pڧc2vDΪW$i6{HѮZ(l:~ñLղ^,p>ǵ Pٶb0uB̹Uߺ#h6{Iӽ]+p? S,uO˜*süNė)rŻMƖ(qǺMȖ(qɺMʖ(r˻M̗)rͼNΗ*sϼOИ*tѽOҘ+tӽOԘ+tսO֘*s׼Oؘ*sټNژ*sۼNܗ*sݼNޗ)r߻N)rM)rMN%[3i AwN&\5k CyQ*`8oG} V/e>tM&]6lF|V/f ?vO)`:pJ%[4h9m >rCxI}N T&Z,` 2 f  8 l > s  E z  L S%Z,a4i;pCxKS&[.c7k ?tI@~7u.l%c[  R ! !J!!""C"""#;#y##$4$r$$%-%k%%&&&d&&''^''((W(())Q))* *K**++F++,,@,,,-;-y--.6.t../1/o//0,0k001'1f112#2b2233^3344Z4455V5566S6677P7788M889 9J99::C:::;:;x;;<2">a>>??Y??@@R@@A AKAABBDBBBC=C{CCD6DuDDE0EoEEF*FiFFG$GcGGHH]HHIIXIIJJRJJKKMKKL LHLLMMDMMNN?N~NNO;OzOOP8PwPPQ4QsQQR1RpRRS-SmSST*TjTTU(UgUUV%VeVVW#WcWWX!XaXXYYWYYZ ZHZZZ[8[t[[\(\d\\]]T]]^^C^^^_2_n__` `\``aaJaaab8bsbbc%c`ccddMddde:eueef&fbffggNgggh9hthhi%i`iijjKjjjk6kqkkl!l\llm mFmmmn0njnnooToopp>pxppq'qaqqrrJrrrs3smssttUttuu=uwuuv%vavvw!wawwx x_xxyy^yyzz\zz{{Z{{||W||}}T}}~~P~~ Lʀ HƁC>}9w3q,j%c\؈Tω KƊB8v.k#`ێUϏ IÐ˲Y.uJصf;ʷX.v ]QF:ݽ/Ҿ$vǿkaVMŸCÕ9Č0Ń'zqiȻaɳYʬQˤJ̝C͖<ΐ6ω0Ѓ*}$xrmhռcַ _׳ZخV٪RڦNۣKܟHݜEޙBߖ?=;y(bK5oY C~.iS?y*eQ=x*eR@{.iW F5q$`P@|1m"^OA~3p&bU H=z0m#`S G:w.k"^R F ; x / l # `  U  I>{3p(eZOD:w/l%bXMC9v/l%bY"g 7 | !!L!!""a""#2#w#$$G$$%%]%%&.&s&&'D''((Z(()+)q))*B**++X++,*,o,,-A--..X../)/o//0@0011W112(2n223?3344U445&5l556=6677T778%8k889=99::T::;%;k;;<=<<==T==>&>l>>?>??@@V@@A)AnAAB9B|BCCGCCDDVDDE!EeEEF0FtFFG@GGH HPHHII`IIJ,JpJJK=KKL LNLLMM_MMN,NqNNO>OOP PPPPQQcQQR1RvRRSDSSTTXTTU'UlUUV;VVW WOWWXXdXXY3YxYZZHZZ[[\[[\+\p\\]>]]^ ^Q^^__d__`2`v``aDaabbUbbc"cfccd,dmdde0eqeef4fuffg8gxggh;h|hhi>iijjAjjkkCkkllEllmmFmmnnGnnooHooppHppqqGqqrrFrrssEssttCttuuAuuuv>v}vvw:wywwx6xuxxy2yqyyz-zlzz{({g{{|#|a||}}[}}~~U~~Nˀ Gā@~8v0p6x>†Fɇ MЈS։Yۊ]!b%e(h*k,l-m.n.m-l+j)h%d!`ޘ[ٙVӚP̛ IŜA8v/m&cޠYԡNɢC:|BƥIͦPӧV٨\ީ a$f)j,m0p3t7x;}@òFɳ LϴRֵYݶa'i/q8zBǻ LѼWܽb+n7zDQ_£*nò4qĮ'dšXƕMNJBȼ7tɲ-kʨ#a˟X̖P͎ HΆ@~ϼ8vе1oѮ*iҧ$bӡ\ԛVՕQ֐ L׊G؆Bف=|ڻ9x۷5tܳ1pݯ.mެ*iߩ'f$d"aYw#\Az'` F,eL3lS;u"\ D~,gO8r!\ E/iT>y)cN:t#] F/jS=x'aL6q ! [ F 1 l  W  C ~ .iUB}.iVC~0kX E3n!\J8t'bQ@[8  ` !>!!""f""#E##$#$m$%%L%%&+&u&' 'U''(4(~())^))*=**++h++,G,,-'-r-..R../3/~/00^001?112 2k233L334-4y455Z556<6677h778I889*9u9: :U::;5;;<<_<<=>==>>h>>?G??@%@o@AAMAAB+BuBC CSCCD2D|DEEZEEF9FFGGbGGH@HHIIjIIJIJJK(KsKLLRLLM2M}MNN]NNO=OOPPhPPQHQQR)RtRS SUSST6TTUUcUUVDVVW&WrWXXTXXY6YYZZdZZ[F[[\'\r\]]R]]^1^{^__Y__`7``aa]aab9bbcc]ccd8ddeeZeef3f{fg gSggh3hhiimij jWjjkAkkl*lwlmm`mmnHnno1o~oppfpqqMqqr4rrsshsttOttu5uuvvgvwwMwwx2x~xyycyyzGzz{+{w{||[||}>}}~!~m~P2}Ɂ_A׃"mO0{Ɔ\=ӈhH݊(rQ0zōYTlɐ'>Ukǔ$ݕ9Nbuљ-@RduО*ߟ:HT`jät̥$|Ӧ+ڧ16:=?@ACDFHJLNQSVY] [E/~̽hS>)xdQ >Í,{jź ZƩIǚ:Ȋ+{mʾ`˱S̥H͚>Α6ψ.Ё'{"vrpnopr v$|+ۂ2܊;ݔFޟR߫_n#~5?_@`!Bb%Ef )Jk0Qq7XzAb *Km6Xy"De1SuAd1Tv"Eg7Z}+Ic}2I`w.D[r*AXo(?Vm'>Um'?Vm)AXp,D\s1Iax7Og&>Womft2@BCDEGH I J L M  N  O  Q RSTVWXY[\]^_ a"b#c$d%f'g ( h !)!i!!"*"k""#,#l##$-$m$$%.%n%%&/&p&&'1'q''(2(r(()3)s))*4*u**+6+v++,7,w,,-8-x--.9.z../;/{//0<0|001=1}112>2223@3344A4455B5566C6677E7788F8899G99::H::; ;J;;< >M>>??O??@@P@@AAQAABBRBBCCTCCDDUDDEEVEEFFWFFGGYGGHHZHHII[IIJJ\JJKK^KKLL_LLM M`MMN!NaNNO"OcOOP#PdPPQ%QeQQR&RfRRS'ShSST(TiTTU*UjUUV+VkVVW,WmWWX-XnXXY/YoYYZ0ZpZZ[1[r[[\2\s\\]4]t]]^5^u^^_6_v__`7`x``a9ayaab:bzbbc;c{ccde~eef?ffgg@gghhAhhiiCiijjDjjkkEkkllFllmmHmmn nInno oJoop pKppq qMqqrrNrrssOssttPttuuRuuvvSvvwwTwwxxUxxyyWyyzzXzz{{Y{{||Z||}}\}}~~]~~^߀_ a"b#c$d%f'g(h)i*k,l-m.n/p0q2r3s4u5v7w8x9z:{<|=}>?ABÝCĞDşFƠGȡHɢ Iʣ Kˤ Lͥ MΦNϧPШQҩRӪSԫUլV׭WخXٯZڰ[ܱ\ݲ]޳_ߴ `!a"b#d%e&f'g(i*j+k,l-n/o0p1q²2só4tĴ5uŵ6vƷ7xǸ9yȹ:zɺ;{ʼ<}˽>~̾?Ϳ@΀AςCЃDфE҅FӇGԈIՉ J֊ K׌ L؍ NَOڏPۑQܒSݓTޔUߖVXYZ[]^_ `!b#c$d%e&g(h)i*j+l-m.n/o0q2r3s4t5v7w8x9y:{<|=}??@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~????@@@@AAA  A  B  B  B  B CCCCDDDDEEEEFFFFGG  G !!G!!""H""##H##$$H$$%%H%%& &I&&' 'I''( (I(() )I))* *J**+ +J++, ,J,,- -J--. .K../ /K//0 0K001 1K112 2L223 3L334 4L445 5L556 6M667 7M778 8M889 9M99::N::;;N;;<>O>>??O??@@O@@AAOAABBPBBCCPCCDDPDDEEPEEFFQFFGGQGGHHQHHIIQIIJJRJJKKRKKLLRLLMMRMMNNSNNOOSOOPPSPPQQSQQRRTRRSSTSSTTTTTUUTUUVVUVVWWUWWXXUXXYYUYYZZVZZ[[V[[\\V\\]]V]]^^W^^__W__``W``aaWaabbXbbccXccddXddeeXeeffYffggYgghhYhhiiYiijjZjjkkZkkllZllmmZmmnn[nnoo[oopp[ppqq[qqrr\rrss\sstt\ttuu\uuvv]vvww]wwxx]xxyy]yyzz^zz{{^{{||^||}}^}}~~_~~_߀_߁_߂ ` ` ` `!a!a!a!a"b"b"b"b#c#c#c#c$d$d$d$d%e%e%e%e&f&f&f&f'g'g'g'g(h(h(h(h)i)i)i)i*j*j*j*j+k+k+k+k,l,l,l,l-m-m-m-m.n.n.n.n/o/o/o/o0p°0pð0pİ0pŰ1qƱ1qDZ1qȱ1qɱ2rʲ2r˲2r̲2rͲ3sγ3sϳ3sг3sѳ4tҴ4tӴ4tԴ4tմ5uֵ5u׵5uص5uٵ6vڶ6v۶6vܶ6vݶ7w޷7w߷7w7w8x8x8x8x9y9y9y9y:z:z:z:z;{;{;{;{<|<|<|<|=}=}=}=}>~>~>~>~??F={rP`ii&8֒@?JjrLL}Qf `pp5oup'83Zll`s@Ilٍ,xs[vo.>P`uQF*tetpul6OZzNi}b}O@XHqkoz {Э5yxyioUzw::{ >7$Hrivy'2[Z9:EKkً c|jz"dJVr{:^5If|t|tW_ y y-NyAX3laa~t񁇦ٻ"I9vÆ /ɀ<KEt4#@p`}`53Ο@mXwBI$ u0ix]D/@<^vT`Z@Tm΍ћh[/󥕼uAcN9WNfBEeOs,O@b JCs|@=a>rW G|Gꅝ<~딛533쩙+1$w*7;#NHNh#G{ȡ;.)qM󚴺!J]^鍥]^6a9蝚  }S*:+YDX͹ZSinr sؒ:%4_(y2çP? [5C0(,쳖(푓|&p퍑0(KF4@'LNTm`%PfYXuNZF=.?;# 8(9?0?g9xk@XLvǖ k~1E "zGT&yt[kSgs]qV PIЂ ().>ϻt_^EZ f "vRʗ;w(uMFk{dK"_*.y@b{@*;m^Xl4sHwxxzzxFV^/BaY{)aF{ ,Yq ,n|T >WVdF>`h ej0lzn O%0.~%GT\!@+]<+nZcyfcA-46 CIR{T1X<\tS_,"*/kOMG 2F3OE3^l8u8Rh-dq|/VX]Ӎhu0bג{W O'J#EFR0 1>ia~z5ee; ԹQ^r.<3W褠GaTM4`Twإk:X?쏫YkrM*jla̙ W虗& K/? He՚h{ÖĀwDOQ$@C7EdJ1S뗘r-6-*}(*  K+ 6$? Os >IUdž] zsD`0W>gP+HqCɢ) Ν*ش-4G OHQ~v\aZT*c`j*stE$xyхJmzeL,^hsiXA4ļ[]>~)>h(#z4%F,mdźnegtx`yd$xy9w $.@fcw?)p]=n8NUIj_c6"hEkbMlY MԻ/"A[R"-7D Y9M_l_x=~wH Ec]OTqX[  1 0*H0.UBYNZzk!t}<c1Xj:M9W?DY~Il$W,@=%9FKTY[g[pz][5ӣ(%m$:(6n17M60Oebeb[ oln))@Ymddr鋄|3a`^&m%ϛlO*l{g-~&TodntjY :>r䉨xB&Uv$]*p][Ttpּpױ%qf.t =E^dnt"S?vt{*e9rBZZ{u׽utvEwIh06✚|Ltց`|ټ{Rg5|ך}_|C.I>azw>\|3'!;'%'ލ,~,G!D,/xoF)>TwC^S;#<ǵֱ,<Ss1\vƊ4xVpClɇcs((=WprDTUu9>;˼jg & 6z=9{jz[XDR hKH';E#?Ttx|s2A 8zHc짜S칚AEki31B^) q ɪi~Iz< GNĖ eړfČ1ʉ?k\fb=iӦ"-|Xᯉm[[MQ~B>gx$Mp@}*p9gpq]eW5`ҜK%t=QeJCN * ^`oAb nux:xBwv wA 1aKmoX/l^&q*l$ 8P9Sϫ\[l`refhj<(5S{Mb E("cm+2C? uIRZP,aSQW.-Z8CG`D +rT j8v~H<*yF1ie9> tC'# 'Sq"+4@Dm+TdnGx E,0, ] ]~>>{%g#g%90&@LSv]tjr #|"o<__^0b0@o}zDŽ`` SZene5e|P8`cfcnbDw|f}͍w`a?mRmii"Bi3>@7_h9dl1h`CҞQBzClZZ_'j\.MoY mCm5_o21~XpWn=0G >?ʟb<x`1[Au>rAj4rsϞ8LtdZ-1Zjssc1<٫ jܜ\?p}%]w͹4w٧>yAVy=y C3>~hs^F;à8*Diӂ:JJ~/dh (xS8d41GHDWJs-_3 !{O񩆌 ڇ(wWgkE`DIu%|+/R;zm%@/n # WoΛ{󖑘h bZ^ߐ_Q0 F&m<X|Z&R>e|3@q g>Ah ؿM iL뇫g(〢(ߞ ;0% I_P]:Ĉ'ǧ;K}L9.vDr?pBl8ju]T|`M#FW^@7Ă Dؖ-5!k$X\FHdnrG $"#x6Ly:|{5y,zocIzug yΑMخI2o.R)e)LgJoExmNq-Ypee8TSօZ_HNdoh80jtkkyl ` P2wv(9ZJFU+9!#69޷BKdO7T 5WC s[ !+!}H,P<(bc;]-)Op2Mg7:C<~@O R# ꄣ-gA60#NfyBZ7=ն}~">)ޛ-Y ""_#/GPBOK?[mz+ѻ+%>  99kE? >/$Z :@MXdnx]g݂.-UU\6`?9o摛|H` @ A?T&W)X#-N_QlU^* GH5}|1eWU$Ao&BV\ /]β]dvPJ'Pecie' C?}z)A?N$Ha^ma Ha<`K%|``ki'F;Ġ|u 'GcnedTnc׵eU#ZINlnoWmtdBNF6)Nig#g}filKj>"{VtnDa3?6CbēnC%msmopДqK5v=lK|M'+rIu5~Ӓygta+yztz4OzuBztA?`{'vɨˢe^G=s zfYb[[ SGRI>ۅ3EC@? .DgjqmvС/%%LH_` 㩜 Ț u ?ݒŽ4T46p hGhmᘆpOڃfk\`yV 삚PVZJWƀOʧ;GUHXY+lzQ+x$fT2lqo!o|Bnt0nno dCS*Y]|Rwm`ode_kCɥaM4QVYZT s  S!p,6^C?D6,w"*}V$y3)l62;\?=gDK #e ! 8r%}Dn0X(Rn\#3~h R&|*v/ # Z b y"?>\)^@Zwsq*; 1 ; ; j هOH  \!g8=G;Y-nxzڪg v^n$ k9MI0V]d'pŝyY&PPL]` ;U>|Xy`<3r4?8B `MW0^K[ ^D?y;~WZe3n4@IC}H ~OY`]w$ÒCczJ|-vȗe6F9E@KRLY1pO_a_G@R{]|c Ud<9KjNPepQ*7Oeaba2Q{Hw_@QaT'VVPZX$|)Kitcdv 8}[=^uNt`-as|a5 &<"k7coK\zj@ cVY D;2?DH@J ɻt /h# DX7@-s- ^*kB #z',Ɋ0w3 ++< Pgh!8'& UPyUs1?ܟ lK sp <IeX(@)Tq;W ׿ 籫{E^ [z-5ATjP3Z~ Rm 90bBR9`sZñZzrpII)(`| /`zxRc`nm>1(''~ s } NK-`Zz 7<]}{*Q=x`k82d a,$'m(+w NN5aMOQ*@#irht~-tH}tfS9,%,L-0Qw NSQ[! :?x|GO͒f &11|N6߃;F'L![\ZM5zO%T,ʂc4:MAC:Dnb{A_d_RgX [d,*yƘRG𜅚jݵEJûK޹XNsWQ={ix8edjFlP:l]zYd|Qr̳"|W\^Va)b3C(.8^?cs&2mOzX##{<nćvq1nj`)rarz[jrS*sZW`'", /F&Ը XK' Hxb9| ꮈ ˅'<~Piq qབྷ*8#Нj` XAu|Weg`Qi\ iXoiTD|i\ Ӌ7p~-'{@6i-Jwẑz8Kmjz]1JEMOTQ R25 חk(ڞ֊ߨq2KP EbP\'eO >a,1 5 8y\;%f aJޛU h2 4.G> ; l@,ɠw,ў*Y%<<!>A$wU&e ml/c?8AE\% A p[7 h%:h2/hv -49 5Nj g"  U U"pc >Hz) $7M]<LOonYj{jj{G  &8UK`r 6Vqigi@6}AA `x j```|'`dKts0t )"mpe;=c(e%VN0M|)wr^d-"yrFJG'aq$ki:Vo~{/̕b 6*FoM 0{sx DP,UP;s7qZAz)C6d &+]e0bF- O-uVV(dV\B+7ioI{d]LE̫58%f|`w dwrce2]6fWggOHh0 aܜ|$E9v| D*\~U#w pvu-aq4{o=v$Q%)x gH|y1u pf)bv^YK\ wZ^Y9O[?Uyp[_/ƥM(.'n #q*d_aoFSNE<>`&@+ fAh 2ɊaKk*?^'V 9 MbFR<4G+%Z%x(}+-bs +/=mb@D_ . 2YB)%%(̊"jThM'nǐL6 ؽGG ` H8w>bX7ܓ{>d_u V(JJLxa3=N+G7^B948|::%ez5M.,F[a0y-78zn>:o[.EXnH=֥ިZ`@3R M Zv%```vqvq]ĮL /,/&j"Xba:68= NW(]```ktvzV7i%I!r =][7 7$9< ZU.(Z!@zso"0XzH+D.&jtgs?<XC%D^w4R~~}rV c(Ssq|,9H/MF2]2_~‚'\o$;8. |֝?}UJRNQX +փdVzhJgO;5%Q+"/~jquT8T \n[aNrt [&DtEXQ.9>BHFM G$1-u9%pcYqx`fojsWnTkZXsT[O\,H_]:N/So6 G "e L}$ofxcg6f?dh٦EŖЕ+wems^*apX LbX(Jo&F:*-~/{G2(Є M\9I\й\PuҕY>ڙ N05։".$N)ɞ/'#!PF#e /eiyfT9jv%ZJ KU 6 Gf! 7 HJ[ ζx{~L S._c^r&H7T/;&iIL_v ) UCX'j<:8bdtU ULqqZ( ;XhuT B~Rya(.9'<Ul#s8V^@"4747 F0 R b#$<```ppWMGX(!FGT`!A):&@: N(\J```d$rgOP;'"z2RY;)-}:6J_(FLDosoeGQ^ (o]XZWgC<,2l?#)YvH}zs"v$_PՉI$Nݳfe@ik; 7@Q>d5^wcpVpcZ1"7")5sqhqs;<%GJPGe#g9{ckRicQbcH6ԛ;.,)/"L!zz EQ9`)/_^ֱgTXkJB71V-':SAF=846~98 8"oe`:DMZ6zz[Rh~UUZD^VITHODNP<Rd/wwr g{Y*< 2}9 w q?q 'D:^+U;'lR( gR%CtRըn_[Pz1,d& KZz(as"Ths}QljQ];DdX88UQ5T6R8'`ţ@}yaS᪙1 9?v4J<%2U3xk-(!nywMBt![bҭUǵreH5*( Ruu<hgFR#!; A :p(jD-ۡ&( =9|拵P)XGt{z7 ^Y0ocE?4;@N~''yplCЉ autG<gH4Xzȡ67aW}MK47gVsV8x?U$(T'%]X./bHbUOD !w#*2>]yuEsrq?,=@9H]*Nda4ٳ%N ۆ!ۊ`5242z 1u5?o6{uYN bJvE=k;`ل>SE< J6iN5HI2WK,,Kdm+ PkPfF^qhjyfcgTE_l$EN}-u?:,(=*,=n(? 4]95taj mxXsN4L`kj>kc9lb;"Z3M5bRG+sN#NJ$L&dȾsѪ&r&SxR>x,`VV/#V9|e<op no lOԮɂKݼBz=UL3EtY6 +0bw _ iגܛg.?Ϡ[ ѥ3|\1lL;iЉp%7R@@m8#_f5o./]yeiMS,{0gϵړз:eΗSg?:ED6ZWiZpAIE;Yt<N:zI@s-lE7XmbGUH4. - 6 @]jy@}``OfCg1 % F5%}-^"@3 >f&SDlfE@w'bZ'O^Dh'i6EzK,i"j[/2 9%@c8cf:Jb GxHD<"3# |M.JFP:;K.U+T=(Cdx[M>G:~@""3 iqx峘BY.TWZ?_"l+1&>K*Jk0T],Ә̐)-cpkha]="E*2jw2D^tKȴ|W vO-"e0`24]22}t)ehިNj2 t#%eA!d^C%We(gPN.<#2$A8DpDBs0󹊢ltIYsCA W:*]VSLzKt٘E!5;0%.',$/V#/`!ϠVxjeZ]G^E:hSX2*V%Zk۸%U#L"rC"@>@~ $1#.~:deD)}fxBMʛ^f~9v f_]FԘ ה4kUF) F&XfρDz,V8~|z/S4BrM>Ki$k §<e8h٧e| Rbֲ)Bp'DZM7suɝB'1%ۗgfcY7/Y %<cbfbc6hV.IbvƳm->2^ "6YL`pGtGrV1 K d $D , 7 @^cB}``Y}D87h# ;=*)!(l 2$>X^c>zah]'[>_5)lNdjWX;z'% l5 0 Iz.qxs0se@@Q*&UM-'lJ'h0| thRW=s"p^KY< .TmAaMHq>>*:8 V4CM{}gMf6-J".J[ G?':7/1s') 7u 6F2FSu:lZb|LOw5L>i'I JJSP˜O CP .95;4WFHw兮Uj2j/ph")n?djrfmo$Bl!SCDE ОDFҦ[5ܨF šh6-QsB&,{yg\ffݣĄ'OcC=N1v*4lC?\wl|rμb-oEijҢԾ_5׆Pֿoiafˉ[{@MN"%7ސh)yKgaE#!&VGH- XPo7P^w6 "a5XJ/E'T`sBûz*Z nEE ! +(696R _6;V`G76% ` w2^!sm a&!2TPd6ZXIa3`~6- Wp3N-u !E!N-Pc7]-eCU+6) 6ك43+z /!%5C >=R/~#MaD@#=:><?/pD3GJ9*& W ->g]Qky=En!nEdG[,Z7^TcVcU Ty;3.-]! uLLf&ÖP .)3Hw\lyrCjuSjNOHd$Wz/\[ |{+FqXYdlvEm{r[b\U8ƭȏ,~=6f{Vhn ʍ)տ`KiAp\C tVF0R_~dcq~YKR%D19HdX\yһV[~-y , 8sM ``vL/!-QQ.: @M/8d28(m9ʒ %UYb.`) + , <Y?P6e9#2` Z> *Q& LL l=>!P8{0"o O q(‹m-*(&q]] 3.NC'GUDи@Q%k4,-.*<| Z[+Z5{ʜk;+FXzD>>.:3 *GF B֢(hH]gj}RcuUNOWST:OI>,dد[qL2}cqNZuSYRDP.I+( dq+oXN=L&vUD<%86B7p/a)1C!OB oP|zWgO>;W(g/9%5 o2QeK ܸ3Bwуzl^iWI3754*//2 _.㒳1;'c 7o42_k9^c]U(IKX;D7OAc:*=8i- S|jiAdX._v3 k#.gCXfY/VZUS68n0GЦK xM;#D>T,@;Vd"ɤX,UpCT׉!W.Wz6ș(:Xƅi_Qxߎe b8ӑ v;Xb-†Э_cw sjARg)z9&OQbzkB|5TͪnVkLx^&w=yy/DSv`jzL+&bE  Ac%I%<-+J*rf%y 2ȓ޽?z T v<  }$#&Y-H/x6& ";7 jh  !  m d "!-vH_1n~'3{q %e%! l ) )*H%Q OYx= 1ėؿ!Mţ-& $." p F =T3DRlul/vbq&_>07:1( ۫xW$"E.g`#zbd-NsAs;xNzJuB48 .ʼn go-\B3Rd|Kf=d23"ii2Q\ݛE92c |7Uc2*F/&U_4av Q~TP='Fq\DttP3M(Y O/ [qe YXF*ȋ=m\vUNp>f*.-" o+[trx /Qm۾_xyV`p06SacQWDm^5[.;-Ma&**2% Hj ]ڹk`}5z w>n)aU$O?kGkDs7AXB7- rźf;nt.CX̛"[-31Txx{vɨAtt]B:`<}">No%r *CDYjep왹Fuox~[Ѓ/T X`Ԋ"(*EJBWdֆTp$ggʀgiP+8[_aQ'BVT`o{:۳@C /#6dIX`oP} ɞ4GkAQ)yyJJ 2 e?0 eXxuBCdVW ܛ gx Wjjqq ~=HXwopy  _Mm_[~ yr:rY={i O߻ ; ՜ ࣅ 7mm_ ) {6U}]p,OAc}2x$*J"H2-ԍJ"shX XvJ]N9.2) ޖ,M 08IPiv8ngp\SMo>3,HD9*u 3<f"P8?Z5/)7!W}$ZXME?H,'!o|N91C*Yn/h}}}uh;RJ<gS+EQ.#$ _)Sϖ5clsLsF6#R':!d k-0O#D'XxjpOYX(K9E4\%'8VR0!= {̸'cZ30Xs(l^S#F.+;iGP5`.x/r6."_-$s #hu<)G䔍|Y n&ox>/rqOYkl%S :h!O}6dKy2aHvA;y4s.m(g"a[UO J !!E!!""@"""#;#z##$7$v$$%3%r%%&/&n&&'+'j''(((g(()$)d))*"*a**++^++,,\,,--[--..Y..//X//00W0011V1122V2233V3344W4455X5566Y667)7p778E8899a99:7:~:; ;T;;<* >h>>????@@_@@A8AABBYBBC2CzCD DTDDE.EwEFFQFFG,GuGHHPHHI,IuIJJQJJK-KwKL LTLLM1M{MNNXNNO6OOPP_PPQ>QQRRgRRSGSST&TqTUUQUUV1V{VWW[WWX;XXYYfYYZFZZ[$[g[[\3\w\\]C]]^^S^^__c__`/`s``a?aab bPbbccaccd-dqdde>eef fOffgg`ggh-hqhhi>iij jOjjkk`kkl-lqllm>mmn nOnnoo_oop,ppppq=qqr rNrrss_sst,tpttu=uuv vNvvww_wwx,xpxxy=yyz zNzz{{`{{|-|q||}=}}~~K~~Xހ"e.r;~G̈́R؅^&h0s:}DɊ MҋVڌ_%g-n4v;}BŒH˓ MДSՕXږ\ޗ`"c&f(i*k,m.n2xIӠ^.tDΣX(m<Ʀ Pڧc2vDΪW$i6{HѮZ(l:~ñLղ^,p>ǵ Pٶb0uB̹Uߺ#h6{Iӽ]+p? S,uO˜*süNė)rŻMƖ(qǺMȖ(qɺMʖ(r˻M̗)rͼNΗ*sϼOИ*tѽOҘ+tӽOԘ+tսO֘*s׼Oؘ*sټNژ*sۼNܗ*sݼNޗ)r߻N)rM)rMN%[3i AwN&\5k CyQ*`8oG} V/e>tM&]6lF|V/f ?vO)`:pJ%[4h9m >rCxI}N T&Z,` 2 f  8 l > s  E z  L S%Z,a4i;pCxKS&[.c7k ?tI@~7u.l%c[  R ! !J!!""C"""#;#y##$4$r$$%-%k%%&&&d&&''^''((W(())Q))* *K**++F++,,@,,,-;-y--.6.t../1/o//0,0k001'1f112#2b2233^3344Z4455V5566S6677P7788M889 9J99::C:::;:;x;;<2">a>>??Y??@@R@@A AKAABBDBBBC=C{CCD6DuDDE0EoEEF*FiFFG$GcGGHH]HHIIXIIJJRJJKKMKKL LHLLMMDMMNN?N~NNO;OzOOP8PwPPQ4QsQQR1RpRRS-SmSST*TjTTU(UgUUV%VeVVW#WcWWX!XaXXYYWYYZ ZHZZZ[8[t[[\(\d\\]]T]]^^C^^^_2_n__` `\``aaJaaab8bsbbc%c`ccddMddde:eueef&fbffggNgggh9hthhi%i`iijjKjjjk6kqkkl!l\llm mFmmmn0njnnooToopp>pxppq'qaqqrrJrrrs3smssttUttuu=uwuuv%vavvw!wawwx x_xxyy^yyzz\zz{{Z{{||W||}}T}}~~P~~ Lʀ HƁC>}9w3q,j%c\؈Tω KƊB8v.k#`ێUϏ IÐ˲Y.uJصf;ʷX.v ]QF:ݽ/Ҿ$vǿkaVMŸCÕ9Č0Ń'zqiȻaɳYʬQˤJ̝C͖<ΐ6ω0Ѓ*}$xrmhռcַ _׳ZخV٪RڦNۣKܟHݜEޙBߖ?=;y(bK5oY C~.iS?y*eQ=x*eR@{.iW F5q$`P@|1m"^OA~3p&bU H=z0m#`S G:w.k"^R F ; x / l # `  U  I>{3p(eZOD:w/l%bXMC9v/l%bY"g 7 | !!L!!""a""#2#w#$$G$$%%]%%&.&s&&'D''((Z(()+)q))*B**++X++,*,o,,-A--..X../)/o//0@0011W112(2n223?3344U445&5l556=6677T778%8k889=99::T::;%;k;;<=<<==T==>&>l>>?>??@@V@@A)AnAAB9B|BCCGCCDDVDDE!EeEEF0FtFFG@GGH HPHHII`IIJ,JpJJK=KKL LNLLMM_MMN,NqNNO>OOP PPPPQQcQQR1RvRRSDSSTTXTTU'UlUUV;VVW WOWWXXdXXY3YxYZZHZZ[[\[[\+\p\\]>]]^ ^Q^^__d__`2`v``aDaabbUbbc"cfccd,dmdde0eqeef4fuffg8gxggh;h|hhi>iijjAjjkkCkkllEllmmFmmnnGnnooHooppHppqqGqqrrFrrssEssttCttuuAuuuv>v}vvw:wywwx6xuxxy2yqyyz-zlzz{({g{{|#|a||}}[}}~~U~~Nˀ Gā@~8v0p6x>†Fɇ MЈS։Yۊ]!b%e(h*k,l-m.n.m-l+j)h%d!`ޘ[ٙVӚP̛ IŜA8v/m&cޠYԡNɢC:|BƥIͦPӧV٨\ީ a$f)j,m0p3t7x;}@òFɳ LϴRֵYݶa'i/q8zBǻ LѼWܽb+n7zDQ_£*nò4qĮ'dšXƕMNJBȼ7tɲ-kʨ#a˟X̖P͎ HΆ@~ϼ8vе1oѮ*iҧ$bӡ\ԛVՕQ֐ L׊G؆Bف=|ڻ9x۷5tܳ1pݯ.mެ*iߩ'f$d"aYw#\Az'` F,eL3lS;u"\ D~,gO8r!\ E/iT>y)cN:t#] F/jS=x'aL6q ! [ F 1 l  W  C ~ .iUB}.iVC~0kX E3n!\J8t'bQ@[8  ` !>!!""f""#E##$#$m$%%L%%&+&u&' 'U''(4(~())^))*=**++h++,G,,-'-r-..R../3/~/00^001?112 2k233L334-4y455Z556<6677h778I889*9u9: :U::;5;;<<_<<=>==>>h>>?G??@%@o@AAMAAB+BuBC CSCCD2D|DEEZEEF9FFGGbGGH@HHIIjIIJIJJK(KsKLLRLLM2M}MNN]NNO=OOPPhPPQHQQR)RtRS SUSST6TTUUcUUVDVVW&WrWXXTXXY6YYZZdZZ[F[[\'\r\]]R]]^1^{^__Y__`7``aa]aab9bbcc]ccd8ddeeZeef3f{fg gSggh3hhiimij jWjjkAkkl*lwlmm`mmnHnno1o~oppfpqqMqqr4rrsshsttOttu5uuvvgvwwMwwx2x~xyycyyzGzz{+{w{||[||}>}}~!~m~P2}Ɂ_A׃"mO0{Ɔ\=ӈhH݊(rQ0zōYTlɐ'>Ukǔ$ݕ9Nbuљ-@RduО*ߟ:HT`jät̥$|Ӧ+ڧ16:=?@ACDFHJLNQSVY] [E/~̽hS>)xdQ >Í,{jź ZƩIǚ:Ȋ+{mʾ`˱S̥H͚>Α6ψ.Ё'{"vrpnopr v$|+ۂ2܊;ݔFޟR߫_n#~5?_@`!Bb%Ef )Jk0Qq7XzAb *Km6Xy"De1SuAd1Tv"Eg7Z}+Ic}2I`w.D[r*AXo(?Vm'>Um'?Vm)AXp,D\s1Iax7Og&>Womft29Up   ,@Tgy ) 2!:"A#H$N%T&X'\(_)b*c+d,d-c.b/`0]1Z2V3Q4L5F6@78809':;<<=>?@ABCDEyFlG`HUIJJ@K6L.M&NOPQR STUVWXYZ[\] ^ _`abc d&e,f2g9hAiIjRk\lgmrnopqrstuvxy$z9{N|e}|~ǁ0Iawˍގ#2@NZfr|vk^QC4%޻ʼqY@& ƬǕ~hS>)ѺҪӚԌ~qeZPG?81,(%#""#%(-39AJT`lz,Fa~ }xsojea\XS O!K"G#D$@%=&9'5(1)-*)+%, -./01 2 3456789:;< = >?@A!B&C+D0E5F:G?HDIIJOKTLZM`NfOlPrQxRSTUVWXYZ[\]^_`abcefgh i)j1k:lBmInQoXp_qfrlsrtwu{vwxyz{|}~}zvrnid_YTNHB<60*$  &/9DO\jx²ҳ&8J[m (6DQ]iuЉђҚӡԧի֯ײشٶڶ۶ܵݳް߮~vmdZOD8,}iU@+ z o d YND9/% !"#$%&'|(v)p*j+e,`-[.V/S0O1L2I3G4E5C6B7A8@9?:?;???@@BADBGCJDNERFWG]HcIkJrK{LMNOPQRSTUW XY&Z4[C\Q]^^l_y`abcdefghijkmnopq'r0s8t?uGvNwUx[yazg{l|q}v~z}}xsmhb[UOJD>83-("  &-5>GPZdoz9$x=RNNK ԠV'$תyga)bØAH4:"y+ y<^%^";c\eL 7Ѳݍ[Ҁݠgi;PtYdz =?7܈3O3AHϋoko݌fdN0A޻_GQltL0ރV!8Nr TblD SQ ,d9QECLZjy7Ӂ5?-u@۟tSMPa24dMYg$Gۃ՘M]8'/ _d htrN}ܥ2l2;uI 6UvOMT[̳z#dQ gS&)t+9|EO͍gl7ܵș {d. ilvpES#>=k ȗ7YU,v#>CPGEvǻ6]k伔.zpqr~Cz<85F .2΂GbnH;)J8ZKI2}?3$.11twׄ(хQ,҆|C0~png_TJ=jH(+(x J@6\tr("C*!8)VTapf]mmr޻̋ݏ֢JDߦo,%}؎Ѡ+fGeCr3pѡ'=o돾[ uubBLѤ໶!0(i^|wʦ}3[ +O=ߑ$X,lF!`x*8r䀷2ZN/=˥:r]=O? Ku:u84-!$ *Y)TxܜϬ!xtpO<߮ihb(ܡ&'>^Z1) |ܡi9׿i:2~ÀZ/@'pfzPbIN)e=\ЂR`!~ >L܆[),,w~faQ`%i.t(*ҘkMd/ozng7LUU5wqQTK >qFJhz`! "//JK˫9| p-`i @z< &Әpx Z6nxyjʟ ~jz>gq$p8k&* X*}@_wniS~__.W1*9wIENDB`nip2-8.7.1/share/nip2/Makefile.am0000644000175000017500000000003713351443023013324 00000000000000SUBDIRS = rc data start compat nip2-8.7.1/share/nip2/Makefile.in0000644000175000017500000004646213417043241013352 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share/nip2 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ SUBDIRS = rc data start compat all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/nip2/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/nip2/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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: 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-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # 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: nip2-8.7.1/share/Makefile.am0000644000175000017500000000002013351443023012444 00000000000000SUBDIRS = nip2 nip2-8.7.1/share/Makefile.in0000644000175000017500000004642413417043241012500 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = share ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ SUBDIRS = nip2 all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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: 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-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # 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: nip2-8.7.1/TODO0000644000175000017500000007527113351443023010022 00000000000000- add tests for new stuff - seeing occasional "rewind image with active regions" message - should parse_float / _int etc. allow leading and trailing spaces? (split is_space x)?0 - how about adding zip2 10 [1..5] == [[10, 1], [10, 2], [10, 3], .. should be harmless, and quite useful same for zip3 etc. as well check zip use, we probably have this code there already, in various places - sharpen should use new interface? - can we call affine from nip2 vips_call? do we need a double array? - hough_circle etc. don't get cached ... they use the vips8 API and the vips cache only works for vips8 we can't turn on the vips8 cache since it does not know about invalidate - columns can move about on load in large workspaces - hide tabs if only one tab in window, though we'd need to allow tab drop anywhere in window for that - Matrix / New / Laplacian edit a cell, turns into a plain matrix need to override edit method same for gaussian rather tricky, compared to square / circle etc. - breadcrumb trail for prog window, so you can get back to where you were? - lambdas don't pattern match? (\[a, b] a + b) - load jpg, ^Q, no leaks load jpg, paint bar, paint one dot, ^Q, no leaks load jpg, extract area, paint bar, paint one dot, ^Q, leaks load jpg, extract area, paint bar, paint one dot, ^Z, ^Q, leaks load jpg, extract area, paint bar, paint one dot, close window, ^Q, leaks seems to leak: original image, one large regions on that image (full width) extract area operation extracted image region a bit bigger than paint action on that image 0) VipsRegion (0x8b052a0) VipsRegion (object), base class VipsRegion: 0x8b052a0, im = 0x887aad0, left = 192, top = 128, width = 45, height = 2 VipsRegion (0x8b052a0) 1) VipsImage (0x887aad0) VipsImage (image), image class 237x202 uchar, 3 bands, srgb, partial VipsImage (0x887aad0) 2) VipsImage (0x8016b30) VipsImage (image), image class 972x1296 uchar, 3 bands, srgb, openin VipsImage (0x8016b30) 3) VipsRegion (0x8b05340) VipsRegion (object), base class VipsRegion: 0x8b05340, im = 0x8016b30, left = 0, top = 30, width = 972, height = 283 VipsRegion (0x8b05340) 4) VipsExtractArea (0x882a910) VipsExtractArea (extract_area), extract an area from an image - extract_area ((VipsImage*) 0x8016b30) 142 158 237 202 VipsExtractArea (0x882a910) something to do with vips_image_wio_input() and the way it rewinds a PARTIAL image? called from im_rwcheck() - os x build reports missing jasper dylib? - draw_circle could extract, draw and insert for huge memuse reduction - section on compat mode for the docs see mail to MvGulick for some notes - expose more of the tone funcs in nip2 - quite a few hist operations have no GUI ... histspec, for example? - nip2 should use zooming support, if possible - the windows setup .exe install a bazillion .png icons we will never use, then installs them all again as .svg, which we will certainly never use - add extract_volume, cf. "grid" record tile_size in meta somewhere? grid could set it, save a parameter off extract_volume also extract_sequence to get volume over time - image + complex constant would be nice - ban parameters which are built-ins, eg. "im", "re" etc., you get nasty crashes see also notes below: a new parser could fix this can only ban for new code? do we have duff code in compat? argh yes there are at least 15 like this, fix them or fix the parser? also need to disable this check for compat defs better to fix the parser, it can't be that hard need to fix up the list comp compiler too, sigh - we can't define local superclasses at the moment eg. consider: Fred = class { Jim a = class { value = a + 12; } Jennie x = class Jim x { value = 99; } } you can't do (Fred.Jennie 12) since Jim will have a secret 'this' param (because it is a class member) and superclass constructors can't have secrets don't automatically give all members 'this' as a secret, check that they make references to other class members that do need secrets first - turn on GM in prefs, have to restart before _stdenv.def:magick sees the change - try this: Workspaces.untitled has_member "A1" A1 doesn't seem to work? - matrix_gaussian_blur could have an 'accuracy' or 'max error' param? expose in custom blur etc. - oo_binary etc. needs revising, we don't search down branches as we should for example, Matrix does: // compound ... don't do iteration [this.Matrix_base (op.fn this.value x.value), (is_Matrix x || is_Real x || is_Vector x) && op.type == Operator_type.COMPOUND_REWRAP], which is stupid, we should not wire Real and Vector in there, it ought to be something like: [this.Matrix_base (op.fn this.value x), op.type == Operator_type.COMPOUND_REWRAP], ie. don't strip the .value off x and rely on op.fn to do that, but this breaks in various ways remove all of _Object and redo it, thinking about what we want operators to look like and what we want types to look like. Have a base class for operators that does most of the standard stuff get rid of the operator types rewrap / arithmetic / relational etc. etc. - try point re = x { (x, y) = re; } it's the 're' param, it stops x being bound to the get-real-part-of-complex builtin expands to point re = x { $$x = re; x = re $$x, is_complex $$x = error "bad match"; } add secrets point point.re = x point.re { $$1 $$1.re = point.re; x x.re = x.re ($$x point.re), is_complex ($$x point.re) = error "bad match"; } x compiles to if_then_else ( ( )) ( ) abstracting point.re after var abstract ((S ((Sr (if_then_else )) ((Sl ((Sr (&& )) ((Sr ) ))) true))) ((Sl ((Sr SHARE0[(: )]) ((Sr ) ))) ((REF0 ( )) [ ]))) reduce and get reduce_spine: ( ( (I (1,2)))) reduce_spine: ( ( (I (1,2)))) sym-param found, argh: point.re maybe fix this when we revise the parser would be a good time to add multiple definitions as well - redo name resolution in parser ... scrap the patch thing, instead have a separate 'resolve' step that runs after parsing a top-level don't create ZOMBIE symbols, instead make REF nodes in the tree this binds local references, but leaves external refs dangling we do a final link at load time when we copy into the heap do we need zombies at all now? make a fork for this - we have ws->window_width, can we use the one on Model now instead? - new inplace stuff needs a test suite - 'don't show this dialog again' on delete row dialog, also in prefs box_yesno() could take a string which is the name of a pref to check for ask-or-not - how about something that does: im' = operation_list [a, b, c, d] im it does a fold: im' = d (c (b (a im))) but the intermediate images are reused, so you can do in-place stuff with it we could get rid of lineset! - mac binary has a broken im_text() argh - do we allow [r, g, b] = Image_file "babe.jpg" since ? is band index and list index, it seems to make sense we have image ++ image image ++ [] == image for bandjoin, so that lines up too, I guess hmm reverse image to swap the bands over? heh need to be able to override hd and tl - Ackermann http://shootout.alioth.debian.org/great/benchmark.php?test=ackermann&lang=all&sort=cpu A x y = y + 1, x == 0 = A (x - 1) 1, y == 0 = A (x - 1) (A x (y - 1)); correct test result: A 3 4 == 125 A 3 10 is benchmark test ... we fail with a "C stack overflow" error A 3 9 == 4093 works OK we could make this a lot quicker with some arithmetic streamlining could we do tail-recursion elimination? strictness analysis would help too - Fib http://shootout.alioth.debian.org/great/benchmark.php?test=fibo&lang=all&sort=cpu F x = 1, x == 0 = 1, x == 1 = F (x - 2) + F (x - 1); correct output F 32 == 3524578 cima is ~370s for this (!!) work machine is about 50s dell vostro laptop is 45s without optimiser - turn on DEBUG in heap.c, run the fibonacci benchmark we heap_copy F every time it recurses! because when we heap_copy we don't link recursive references try fixing this ... but remember the problems we had with shared classes when we did link-to-value rather than link-to-copy we also have a huge amount of stuff in the heap, could we trim this down? how does it all get pulled in? is it preferences? in nip1, F is about 4x faster WONTFIX for 7.20 ================ - look at: http://www.eggheadcafe.com/software/aspnet/35467981/programmatic-console-appl.aspx possibly better than nip2-cli.exe - turning a column from Many Stats into a vector for doing arithmetic is very tricky argh add a matrix->vector converter? or maybe a one column or 1 row matrix should also be a vector - try: nip2 Workspaces.uniformshapes2.A1.start_line=21 uniformshapes2.ws --set does not work for non-toplevels - try: A1 = [1] A2 = [x :: x <- A1] change A1, A2 does not update, argh we get: link_expr_new: expr A2.$$lcomp0 references link->child = A1 so perhaps we are updating the local of A2, but not A2? A2 is certainly being marked dirty ... on change of A1 we get: row_dirty_set_single: A1 clear_error = true symbol_dirty_set: A1 (0x1a59480) symbol_dirty_set: A2 (0x1a595a0) symbol_recalculate_check: untitled.A1 row_dirty_clear: A1 row_recomp_all: done row A1 - 0.000143873s row_dirty_set_single: A1 clear_error = false row_dirty_clear: A1 symbol_dirty_clear: A1 (0x1a59480) success: [2] symbol_recalculate_check: untitled.A2 symbol_dirty_clear: A2 (0x1a595a0) success: [1] so maybe A2.something is being updated, but the row is not we now mark a row dirty if a sub-expr is dirty. but in row_renerate(), we don't build subexprs should we mark the subexpr dirty? (or maybe we do?) or should we always copy all subexprs when we copy an expr or only subexprs with no row? do we calc rows outside-in or inside-out? does this affect copying subrows? when do we copy now, the first time a row is made? - we destroy and rebuild all links during recomp (eg. turn on DEBUG in link.c), why is this? can't we only rebuild on a change of source text? - fix the FIXME in itext_clear_edited() or wherever it is - try: start nip2 dir untitled create A2, A3, etc. A1 does not update when we add/remove a def to workspace, should we mark the ws dirty? - lambdas should allow patterns? eg.: map (\[x, y] x + y) [[1, 2], [3, 4]] == [3, 7] - OS X bundler: http://sourceforge.net/apps/trac/gtk-osx/wiki/Bundle test? - imageinfo_make_paintable() no longer copies to a file, since this used to cause problems with dangling pointers because of the im_close()s we had to do however, this means we now do all painting in memory :-( do we need to add API to change a memory image (eg. a "p") into a file? - test Joe's layout thing, compare to the thing we do in study2 to make the diagnostic image - im_blend(), im_ifthenelse(), im_add() etc. now do bandalike/formatalike where do we use our bandalike/formatalike stuff? remove our stuff, though make sure we have equivalents in vips now - outline text example - needs a custom convol menu item which can loop over a group of matricies with a single image actually, we need to nail this down, otherwise when we pass in a list of sample texts the loops don't nest - right-click menu on row button should have items for "Jump to referrer / WC1 / JC1 ..." and "Jump to referred / ..." - why didn't im_copy_file() work? mysterious - line colours are wrong, argh, very mysterious, see plot_new_gplot() - gtk3.0 tests: build with #define G_DISABLE_DEPRECATED #define G_DISABLE_SINGLE_INCLUDES #define GDK_DISABLE_DEPRECATED #define GTK_DISABLE_DEPRECATED #define GDK_DISABLE_SINGLE_INCLUDES #define GTK_DISABLE_SINGLE_INCLUDES paste into config.h, somehow need to remove: GtkType gtk_type_new gtk_signal_connect GTK_SIGNAL_FUNC gtk_signal_handler_block_by_data ` gtk_signal_connect_object GTK_CHECK_CAST GTK_CHECK_TYPE GtkSignalFunc - add Set menu to Math with mkset/union/intersection/difference ? could do bit operations on images? - lcomps like: argh = [x :: x <- poop] the 'x' gets copied inside the lcomp, leaving a zombie 'x' attached to argh, which Program / View / Errors then reports fix: don't resolve names as we parse and junk the ugly patch list thing instead, have a separate resolve stage that runs after we've moved scraps of graph to their final home - if we want full VipsObject introspection we will need a lot more vips_object_arguments (name2gtype "VipsInterpolateYafrsmooth") -> ["sharpness"] need some equivalent for GParamSpec / VipsArgument VipsArgument name type .... = class {} return a list of these from vips_object_arguments()? - heap_map_dict() should be reduce_map_dict(), since it does reduction, argh redo heap_map_dict() in terms of reduce_map_dict() actually, remove all the reduce_ stuff, it's daft to have a distinction something to do when we break Snip out into libsnip - Plot window should have image header menu item? not trivial, image header needs a conversion to watch we'd need to make a conversion in plotmodel - filesel guess-file-type-from-suffix needs fixing copy the vips model of having a user_name which is just "Workspace" or somesuch, and making "Workspace file (*.ws)" string at runtime use this to identity file types in util.c as well: get_image_info() needs it - for rows made by typing stuff, always show the formula as well as the value by default anyway? we'd need to always show the up/down arrows, not just for classes - drag from an image thumbnail to the ws background and you get a new column with "A2" or whgatever in does not work for plot thumbnails! how annoying - right-click on image background to get a context menu with save/replace/header? same as row thumbnail context? - look at using goffice instead of gtkplot for graphs http://ftp.gnome.org/pub/gnome/sources/goffice/ also in synaptic there's also a new cairo-based gtkplot in SVN, apparently - try last [1..] then CTRL-W ... we can quit the app, but it's still evaling and the prompt never comes back - Math / Cluster is a bit useless, will it work for complex numbers? vectors? colours? groups? what would we have to do to get it to work for these other types? - toolkit load is where compiled code would go in need to make load / parse / compile self-contained ... the only output is a list of symbols, each with code and sub-symbols; there are no toolkits or whatever made after load / parse / compile, we need to walk the symbol list building tools and all that stuff we do: load toolkit: get filesize, date last modified, md5sum look in ~/.nip2-7.x.x/cache for a file named with that md5sum if present, open and check first two fields: filesize and date if match, load compiled code if no match, load / parse / compile toolkit, then save compiled code to ~/.nip2-7.x.x./cache walk symbol list building tools and all that stuff how much time will this really save? can we easily get an estimate? steps to follow: 1. make load / parse / compile self-contained, with separate pass to build tools etc. this is a useful cleanup whatever else we do 2. now we know exactly what the output of load / parse / compile is, we should be able to write to a file make our own binary format, don't use XML ... we want speed 3. try loading and benchmarking 4. if the benchmarks look promising, harden and polish - numbering of group of group save seems to skip one at end of line? - Math / Cluster is a bit useless, will it work for complex numbers? vectors? colours? groups? what would we have to do to get it to work for these other types? - segv in test_toolkits on laptop (inside fftw3) ???!? valgrinds cleanly on work machine - try last [1..] then CTRL-W ... we can quit the app, but it's still evaling and the prompt never comes back - configure no longers sets GMSGFMT, is this OK? test on OS X - for rows made by typing stuff, always show the formula as well as the value by default anyway? we'd need to always show the up/down arrows, not just for classes - drag from an image thumbnail to the ws background and you get a new column with "A2" or whgatever in does not work for plot thumbnails! how annoying - right-click on image background to get a context menu with save/replace/header? same as row thumbnail context? - look at using goffice instead of gtkplot for graphs http://ftp.gnome.org/pub/gnome/sources/goffice/ also in synaptic WONTFIX for 7.14 ================ - quit while a thumbnail is painting: IMAGEs are leaked? seems esp. bad with greyc, perhaps just because it's so slow - do we enforce no-args-to-LHS-pattern anywhere? try [a,b] a b = 12; - use destroy_if_destroyed() in more places? grep destroy_ *.h - after pressing "Process" in the edit window, we always select last_sym, which is often not what we want make it jump less after a process ... eg. try editing something in the middle of Image/Transform, very annoying - use compile->last_sym to spot chains of defs multiple definitions of the same function are allowed, provided they all multiple definitions of the same function are allowed, provided they all have the same number of arguments, and provided only one of them has no argument pattern matching example: fred [a, b, 1] = a * b; fred (Image x) = rot90 x; fred z = error "what"; any of these can have locals, those locals just apply to that one definition this compiles to: fred $$a4 = $$fred1, is_list $$a4 && len $$a4 == 2 && $$a4?2 == 1 = $$fred2, is_instance_of "Image" $$a4 = $$fred3 { $$fred1 = a * b { a = $$a4?0; b = $$a4?1; } $$fred2 = rot90 x { x = $$a4; } $$fred3 = error "what"; { z = $$a4; } } so each pattern-matching definition generates a condition and an action constants in patterns become part of the condition test the action goes into a private function, the conditions are joined together in the function wrapper the no-pattern case (if present) becomes the action for the "otherwise" clause in the wrapper if not present, we generate (error "pattern match failed") or somesuch for the default case we will need to regenerate the wrapper function every time a definition of fred is added or removed ... can we do this easily? when are two definitions considered equal? should we warn about this? "fred x" could occur in two files, for example process: * we see a "fred arg-list" incoming * does the arg list contain any patterns? yes: * do we already have a fred in this scope? yes: * the existing fred must be the wrapper, this must be a new possible RHS * check that the number of args matches no: * generate a fred to act as the wrapper * add args called $$arg1 etc. to the main fred * add this new fred as a $$fredn local to the current fred * expand the patterns as local references to the main fred's arguments * parse the rest of the def in that context * keep the pattern list around, we'll need it to generate the ifs for the wrapper later no: * do we have a fred in this scope? yes: * check the previous fred was a pattern matcher * check the number of args matches * check there isn't already a default case * add as above no: * add as a regular non-pattern definition issues: * where do we store the pattern lists? we can't expand them at parse-time, since we need them to make the wrapper (which we can't make until we've seen all the candidate RHS) * when one of the RHS is changed, we need to regenerate the wrapper, how do we do this? (could nuke the generated code in the compile when we see a new RHS, then rebuild the wrapper in compile on the next heap_copy?) * our current condition generator won't work ... we need to test consts as well, and it'll be rather inefficient as we'll repeatedly test the trunk as we loop over the leaves --- instead, walk the pattern recursively top-down testing each node process: * see "fred" (as opposed to simple_pattern) * is there already a fred in scope? yes: * was current_compile->last_sym also a "fred"? yes: * another definition yes: * this must be an alternative definition - we put the 2nd fred in as a local of the first, but then the 2nd can see all the stuff the first has as locals z = 42; fred 1 = 12 { z = 99; } fred 2 = z; "fred 2" will return 99 :( we need to make "fred 2 = z" into another fred at the same level, eg $$alternate42$fred 2 = z; Nope, then how do we link the freds together for remove etc.? Better: see a new sym (fred), create it parse args with simple names becoming params, patterns becoming $$arg42 plus a local $$patt42 holding the pattern source expand the pattern to an access def as well, so our children can bind to it at the = sign, test for any pattern args present .. if there are none, carry on as before otherwise, make a new local called $$alternate42 or whatever and parse the RHS into that at the end of parse, need to resolve outwards twice, since we nest in twice now if we see another fred, check that the number of args matches and then parse in as $$alternate99 what abut fred 2 a = 12; fred 1 b = 32; the first fred will make a top-level with fred $$arg12 a = { $$alernate42 = 12; $$patt12 = 2; } then when we parse the 2nd fred the name of the 2nd param is wrong :( Even betterer: use GLR to split off the four cases for us ident = pattern = ident ident_list = ident pattern_list = change pattern syntax so that ident is not part of simple_pattern need to change lcomp as well so we need to check why PARSE_PARAMS gets used: can we do without the params part? yes, it's used so we can edit functions, but we no longer do this these days all we need is expr I think, but we'd need a small action wrapper around it to wipe out any existing tree and locals Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class Transform b reference.width reference.height { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [a,b,c] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image a; final_error = c; } } fails with Bad superclass. Superclass constructor "Image_transform_item.Image_rubber_item.Transform" should have no secret arguments. but this: Find_item = class Menuaction "_Find" ("find a transform which will map sample image onto " ++ "reference") { action reference sample = class _t { _vislevel = 3; // controls order = rubber_order; interp = rubber_interp; wrap = rubber_wrap; max_err = Expression "Maximum error" 0.3; max_iter = Expression "Maximum iterations" 10; // transform [a,b,c] = transform_search max_err max_iter order interp wrap sample reference; transformed_image = Image a; _t = Transform b reference.width reference.height; final_error = c; } } (ie. make the superclass constructor into a member) works fine - try using bison's location system http://www.gnu.org/software/bison/manual/html_mono/bison.html#Locations - add something to Symbol: Symbol *access_for; links generated access def to the $$thing4 which holds the RHS handy for the program window, also maybe for lcomp code gen? also for row edits - don't offer to clear temps if there's been a crash need to be able to test for process-still-running by PID try http://msdn2.microsoft.com/en-us/library/ms886766.aspx gboolean process_running( int pid ) { HANDLE handle; if( (handle = OpenProcess( 0, FALSE, pid )) ) { CloseHandle( handle ); return( TRUE ); } return( FALSE ); } - autoarrange after every column resize or move animate movement, so columns slither out of the way and in to place when you drop duplicate column placement would be odd: maybe place duplicate below? also new column? what about dropping an image on to the ws background? - there's some left-recursion in the parser, eg. comma_list, is this easily fixable? - add (*) (operator sections) ... need a binup / uop production? can't do this without losing precedence stuff, it'll need a separate production for sections - magic definition maker could make a workspace-local def, rather cool - test classmodel_dict_new() ... part of classmodel member automation need to implement member edit for OPTION groups classmodel_done_member() ... read widget set -> model classmodel_buildedit_member( ... model -> build widget set part of the [["key",value]] arg type - can we get VIPS errors reported in Error too? we'd need to add logging to vips I think - toolkits / find doesn't find builtins on their name ... eg. search for "im_add" too hard to fix with the way searching is done now - turn on update regions during drag, fix the x pos, try dragging, horrible flickering as we update twice, once after the drag motion and once after the recomp if you comment out the explicit vobject_refresh() in regionview_model_update() the flickering goes, but region dragging is then very unresponsive fix this when we get fast recomp back again - have a test_types.ws ... test arithmetic on all combinations of _types? - panner would be cool - tooltips on Expression rows always show unedited formula could special-case formula for things with expression RHS? - what about iimage, iregion, iarrow ... can we member automate these? why are they different? - can't see error indications in noedit mode should set a red background for display area as well as for rowview button? - need to be able to override cons to be able to make a List class :-( see reduce.c:1710 this will change the strictness of cons ... how much breakage will this cause? very unclear try this as a quick hack need to do this before we can finish List need List to make gamma easy - unselected column headers are too like the bg colour on windows? - python uses z.real and z.imag to extract real/image, should we add this too? we don't really have complex as a true class, so it would be rather odd need to add "[a].head" etc as well - python blocks complex->real with casts ... insists you use .imag/.real or abs() - if nip sees a IM_RW_IMAGE argument, it could automatically do this: int im_flood_blob_copy( IMAGE *in, IMAGE *out, int x, int y, PEL *ink ) { IMAGE *t; if( !(t = im_open_local( out, "im_flood_blob_copy", "t" )) || im_copy( in, t ) || im_flood_blob( t, x, y, ink, NULL ) || im_copy( t, out ) ) return( -1 ); return( 0 ); } so it would turn a single IM_RW_IMAGE arg into a paired input and output arg could make im_lineset() into a regular inplace func and rely on nip to wrap and unwrap junk flood_blob_copy nip could do this lazilly ... if we see the user doing im_line (im_line ...) ... then we could make one memory image and call im_line twice on it destructively ... cool! we'd need to check refcounts to make sure the intermediate wasn't being used anywhere else hmm! might actually be very hard, we don't have true refcounts for things in the heap need to do it on read instead: - for image i - use as an IM_RW_IMAGE arg ... copy to a memory area and pass in memory handle - return memory area IMAGE j, and set a flag saying "can operate on destructively" - if we use j as an IM_RW_IMAGE arg, skip the copy and just pass memory area in destructively ... we now have two ImageInfo sharing a single IMAGE - !!!! - does ImageInfo allow IMAGE sharing? not sure it does - maybe this needs to be a vips8 feature when we'll have refcounts on IMAGE - tooltip on column says which other columns items in this column refer to, and which columns refer to items in this column - how about a nip start folder common to all versions so nip2-7.11.14 tries .nip2-7.11.14/start .nip2-7.11/start .nip2-7/start .nip2/start or maybe .nip2/7.11.14/start .nip2/7.11/start .nip2/7/start .nip2/start bit less cluttered also, we could have .nip2/tmp and not have multiple nip2 tmp areas workspace recover after crash could break though ... maybe keep ws saves in .nip2/7.11.4/tmp? - think again about class arg checks is there some way we can avoid the _check overhead? or at least check less often - plotpresent/imagepresent could have a common base class with the focus stuff in? also kb nav, zoom, drag-scroll a bit difficult, because we want two different policies on window resize: plot should change the object to match the window - photographic negative should also be in image/levels ? no, it does ->sRGB, (255-) etc., so it's better as a filter - gtk+ 2.12 has a treeview widget with rectangular select and grid lines use instead of gtksheet? - stop image flickering on clock recomp? want background pattern to be a property of the image display widget, not the image? so we fade in tiles when that section of the image has never been displayed before (eg. on scroll or zoom) we don't fade when that section has been painted and we are just changing the image (eg. on recalc) if fadesteps == 1, only paint the sections of the tile for which mask == 255 this way we will never paint the bg pattern need some hack for scroll/zoom ; test for mask == 255 would be slow :( nip2-8.7.1/AUTHORS0000644000175000017500000000021413351443023010363 00000000000000Authors of nip2 John Cupitt Joe Padfield Hans Breuer Rich Lott Leo Davidson Plus helpful comments and suggestions from many others. nip2-8.7.1/ltmain.sh0000644000175000017500000120467713417042641011163 00000000000000#! /bin/sh ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in ## by inline-source v2014-01-03.01 # libtool (GNU libtool) 2.4.6 # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.6 Debian-2.4.6-4" package_revision=2.4.6 ## ------ ## ## Usage. ## ## ------ ## # Run './libtool --help' for help with using this script from the # command line. ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # After configure completes, it has a better idea of some of the # shell tools we need than the defaults used by the functions shared # with bootstrap, so set those here where they can still be over- # ridden by the user, but otherwise take precedence. : ${AUTOCONF="autoconf"} : ${AUTOMAKE="automake"} ## -------------------------- ## ## Source external libraries. ## ## -------------------------- ## # Much of our low-level functionality needs to be sourced from external # libraries, which are installed to $pkgauxdir. # Set a version string for this script. scriptversion=2015-10-12.13; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 # Copyright (C) 2004-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # As a special exception to the GNU General Public License, if you distribute # this file as part of a program or library that is built using GNU Libtool, # you may include this file under the same distribution terms that you use # for the rest of that program. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # Evaluate this file near the top of your script to gain access to # the functions and variables defined here: # # . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh # # If you need to override any of the default environment variable # settings, do that before evaluating this file. ## -------------------- ## ## Shell normalisation. ## ## -------------------- ## # Some shells need a little help to be as Bourne compatible as possible. # Before doing anything else, make sure all that help has been provided! 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 # NLS nuisances: We save the old values in case they are required later. _G_user_locale= _G_safe_locale= for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test set = \"\${$_G_var+set}\"; then save_$_G_var=\$$_G_var $_G_var=C export $_G_var _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\" _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Make sure IFS has a sensible default sp=' ' nl=' ' IFS="$sp $nl" # There are apparently some retarded systems that use ';' as a PATH separator! 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 ## ------------------------- ## ## Locate command utilities. ## ## ------------------------- ## # func_executable_p FILE # ---------------------- # Check that FILE is an executable regular file. func_executable_p () { test -f "$1" && test -x "$1" } # func_path_progs PROGS_LIST CHECK_FUNC [PATH] # -------------------------------------------- # Search for either a program that responds to --version with output # containing "GNU", or else returned by CHECK_FUNC otherwise, by # trying all the directories in PATH with each of the elements of # PROGS_LIST. # # CHECK_FUNC should accept the path to a candidate program, and # set $func_check_prog_result if it truncates its output less than # $_G_path_prog_max characters. func_path_progs () { _G_progs_list=$1 _G_check_func=$2 _G_PATH=${3-"$PATH"} _G_path_prog_max=0 _G_path_prog_found=false _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:} for _G_dir in $_G_PATH; do IFS=$_G_save_IFS test -z "$_G_dir" && _G_dir=. for _G_prog_name in $_G_progs_list; do for _exeext in '' .EXE; do _G_path_prog=$_G_dir/$_G_prog_name$_exeext func_executable_p "$_G_path_prog" || continue case `"$_G_path_prog" --version 2>&1` in *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;; *) $_G_check_func $_G_path_prog func_path_progs_result=$func_check_prog_result ;; esac $_G_path_prog_found && break 3 done done done IFS=$_G_save_IFS test -z "$func_path_progs_result" && { echo "no acceptable sed could be found in \$PATH" >&2 exit 1 } } # We want to be able to use the functions in this file before configure # has figured out where the best binaries are kept, which means we have # to search for them ourselves - except when the results are already set # where we skip the searches. # Unless the user overrides by setting SED, search the path for either GNU # sed, or the sed that truncates its output the least. test -z "$SED" && { _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for _G_i in 1 2 3 4 5 6 7; do _G_sed_script=$_G_sed_script$nl$_G_sed_script done echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed _G_sed_script= func_check_prog_sed () { _G_path_prog=$1 _G_count=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo '' >> conftest.nl "$_G_path_prog" -f conftest.sed conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin rm -f conftest.sed SED=$func_path_progs_result } # Unless the user overrides by setting GREP, search the path for either GNU # grep, or the grep that truncates its output the least. test -z "$GREP" && { func_check_prog_grep () { _G_path_prog=$1 _G_count=0 _G_path_prog_max=0 printf 0123456789 >conftest.in while : do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo 'GREP' >> conftest.nl "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' conftest.out 2>/dev/null || break diff conftest.out conftest.nl >/dev/null 2>&1 || break _G_count=`expr $_G_count + 1` if test "$_G_count" -gt "$_G_path_prog_max"; then # Best one so far, save it but keep looking for a better one func_check_prog_result=$_G_path_prog _G_path_prog_max=$_G_count fi # 10*(2^10) chars as input seems more than enough test 10 -lt "$_G_count" && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out } func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin GREP=$func_path_progs_result } ## ------------------------------- ## ## User overridable command paths. ## ## ------------------------------- ## # All uppercase variable names are used for environment variables. These # variables can be overridden by the user before calling a script that # uses them if a suitable command of that name is not already available # in the command search PATH. : ${CP="cp -f"} : ${ECHO="printf %s\n"} : ${EGREP="$GREP -E"} : ${FGREP="$GREP -F"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} ## -------------------- ## ## Useful sed snippets. ## ## -------------------- ## sed_dirname='s|/[^/]*$||' sed_basename='s|^.*/||' # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='s|\([`"$\\]\)|\\\1|g' # Same as above, but do not quote variable references. sed_double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g' # Sed substitution that converts a w32 file name or path # that contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-'\' parameter expansions in output of sed_double_quote_subst that # were '\'-ed in input to the same. If an odd number of '\' preceded a # '$' in input to sed_double_quote_subst, that '$' was protected from # expansion. Since each input '\' is now two '\'s, look for any number # of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'. _G_bs='\\' _G_bs2='\\\\' _G_bs4='\\\\\\\\' _G_dollar='\$' sed_double_backslash="\ s/$_G_bs4/&\\ /g s/^$_G_bs2$_G_dollar/$_G_bs&/ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" ## ----------------- ## ## Global variables. ## ## ----------------- ## # Except for the global variables explicitly listed below, the following # functions in the '^func_' namespace, and the '^require_' namespace # variables initialised in the 'Resource management' section, sourcing # this file will not pollute your global namespace with anything # else. There's no portable way to scope variables in Bourne shell # though, so actually running these functions will sometimes place # results into a variable named after the function, and often use # temporary variables in the '^_G_' namespace. If you are careful to # avoid using those namespaces casually in your sourcing script, things # should continue to work as you expect. And, of course, you can freely # overwrite any of the functions or variables defined here before # calling anything to customize them. EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. # Allow overriding, eg assuming that you follow the convention of # putting '$debug_cmd' at the start of all your functions, you can get # bash to show function call trace with: # # debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name debug_cmd=${debug_cmd-":"} exit_cmd=: # By convention, finish your script with: # # exit $exit_status # # so that you can set exit_status to non-zero if you want to indicate # something went wrong during execution without actually bailing out at # the point of failure. exit_status=$EXIT_SUCCESS # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath=$0 # The name of this program. progname=`$ECHO "$progpath" |$SED "$sed_basename"` # Make sure we have an absolute progpath for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=`$ECHO "$progpath" |$SED "$sed_dirname"` progdir=`cd "$progdir" && pwd` progpath=$progdir/$progname ;; *) _G_IFS=$IFS IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS=$_G_IFS test -x "$progdir/$progname" && break done IFS=$_G_IFS test -n "$progdir" || progdir=`pwd` progpath=$progdir/$progname ;; esac ## ----------------- ## ## Standard options. ## ## ----------------- ## # The following options affect the operation of the functions defined # below, and should be set appropriately depending on run-time para- # meters passed on the command line. opt_dry_run=false opt_quiet=false opt_verbose=false # Categories 'all' and 'none' are always available. Append any others # you will pass as the first argument to func_warning from your own # code. warning_categories= # By default, display warnings according to 'opt_warning_types'. Set # 'warning_func' to ':' to elide all warnings, or func_fatal_error to # treat the next displayed warning as a fatal error. warning_func=func_warn_and_continue # Set to 'all' to display all warnings, 'none' to suppress all # warnings, or a space delimited list of some subset of # 'warning_categories' to display only the listed warnings. opt_warning_types=all ## -------------------- ## ## Resource management. ## ## -------------------- ## # This section contains definitions for functions that each ensure a # particular resource (a file, or a non-empty configuration variable for # example) is available, and if appropriate to extract default values # from pertinent package files. Call them using their associated # 'require_*' variable to ensure that they are executed, at most, once. # # It's entirely deliberate that calling these functions can set # variables that don't obey the namespace limitations obeyed by the rest # of this file, in order that that they be as useful as possible to # callers. # require_term_colors # ------------------- # Allow display of bold text on terminals that support it. require_term_colors=func_require_term_colors func_require_term_colors () { $debug_cmd test -t 1 && { # COLORTERM and USE_ANSI_COLORS environment variables take # precedence, because most terminfo databases neglect to describe # whether color sequences are supported. test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"} if test 1 = "$USE_ANSI_COLORS"; then # Standard ANSI escape sequences tc_reset='' tc_bold=''; tc_standout='' tc_red=''; tc_green='' tc_blue=''; tc_cyan='' else # Otherwise trust the terminfo database after all. test -n "`tput sgr0 2>/dev/null`" && { tc_reset=`tput sgr0` test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold` tc_standout=$tc_bold test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso` test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1` test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2` test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4` test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5` } fi } require_term_colors=: } ## ----------------- ## ## Function library. ## ## ----------------- ## # This section contains a variety of useful functions to call in your # scripts. Take note of the portable wrappers for features provided by # some modern shells, which will fall back to slower equivalents on # less featureful shells. # func_append VAR VALUE # --------------------- # Append VALUE onto the existing contents of VAR. # We should try to minimise forks, especially on Windows where they are # unreasonably slow, so skip the feature probes when bash or zsh are # being used: if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then : ${_G_HAVE_ARITH_OP="yes"} : ${_G_HAVE_XSI_OPS="yes"} # The += operator was introduced in bash 3.1 case $BASH_VERSION in [12].* | 3.0 | 3.0*) ;; *) : ${_G_HAVE_PLUSEQ_OP="yes"} ;; esac fi # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is # useable or anything else if it does not work. test -z "$_G_HAVE_PLUSEQ_OP" \ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ && _G_HAVE_PLUSEQ_OP=yes if test yes = "$_G_HAVE_PLUSEQ_OP" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_append () { $debug_cmd eval "$1+=\$2" }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_append () { $debug_cmd eval "$1=\$$1\$2" } fi # func_append_quoted VAR VALUE # ---------------------------- # Quote VALUE and append to the end of shell variable VAR, separated # by a space. if test yes = "$_G_HAVE_PLUSEQ_OP"; then eval 'func_append_quoted () { $debug_cmd func_quote_arg pretty "$2" eval "$1+=\\ \$func_quote_arg_result" }' else func_append_quoted () { $debug_cmd func_quote_arg pretty "$2" eval "$1=\$$1\\ \$func_quote_arg_result" } fi # func_append_uniq VAR VALUE # -------------------------- # Append unique VALUE onto the existing contents of VAR, assuming # entries are delimited by the first character of VALUE. For example: # # func_append_uniq options " --another-option option-argument" # # will only append to $options if " --another-option option-argument " # is not already present somewhere in $options already (note spaces at # each end implied by leading space in second argument). func_append_uniq () { $debug_cmd eval _G_current_value='`$ECHO $'$1'`' _G_delim=`expr "$2" : '\(.\)'` case $_G_delim$_G_current_value$_G_delim in *"$2$_G_delim"*) ;; *) func_append "$@" ;; esac } # func_arith TERM... # ------------------ # Set func_arith_result to the result of evaluating TERMs. test -z "$_G_HAVE_ARITH_OP" \ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \ && _G_HAVE_ARITH_OP=yes if test yes = "$_G_HAVE_ARITH_OP"; then eval 'func_arith () { $debug_cmd func_arith_result=$(( $* )) }' else func_arith () { $debug_cmd func_arith_result=`expr "$@"` } fi # func_basename FILE # ------------------ # Set func_basename_result to FILE with everything up to and including # the last / stripped. if test yes = "$_G_HAVE_XSI_OPS"; then # If this shell supports suffix pattern removal, then use it to avoid # forking. Hide the definitions single quotes in case the shell chokes # on unsupported syntax... _b='func_basename_result=${1##*/}' _d='case $1 in */*) func_dirname_result=${1%/*}$2 ;; * ) func_dirname_result=$3 ;; esac' else # ...otherwise fall back to using sed. _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`' _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"` if test "X$func_dirname_result" = "X$1"; then func_dirname_result=$3 else func_append func_dirname_result "$2" fi' fi eval 'func_basename () { $debug_cmd '"$_b"' }' # func_dirname FILE APPEND NONDIR_REPLACEMENT # ------------------------------------------- # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. eval 'func_dirname () { $debug_cmd '"$_d"' }' # func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT # -------------------------------------------------------- # Perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () { $debug_cmd '"$_b"' '"$_d"' }' # func_echo ARG... # ---------------- # Echo program name prefixed message. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname: $_G_line" done IFS=$func_echo_IFS } # func_echo_all ARG... # -------------------- # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_echo_infix_1 INFIX ARG... # ------------------------------ # Echo program name, followed by INFIX on the first line, with any # additional lines not showing INFIX. func_echo_infix_1 () { $debug_cmd $require_term_colors _G_infix=$1; shift _G_indent=$_G_infix _G_prefix="$progname: $_G_infix: " _G_message=$* # Strip color escape sequences before counting printable length for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan" do test -n "$_G_tc" && { _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"` _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"` } done _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes func_echo_infix_1_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_infix_1_IFS $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2 _G_prefix=$_G_indent done IFS=$func_echo_infix_1_IFS } # func_error ARG... # ----------------- # Echo program name prefixed message to standard error. func_error () { $debug_cmd $require_term_colors func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2 } # func_fatal_error ARG... # ----------------------- # Echo program name prefixed message to standard error, and exit. func_fatal_error () { $debug_cmd func_error "$*" exit $EXIT_FAILURE } # func_grep EXPRESSION FILENAME # ----------------------------- # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $debug_cmd $GREP "$1" "$2" >/dev/null 2>&1 } # func_len STRING # --------------- # Set func_len_result to the length of STRING. STRING may not # start with a hyphen. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_len () { $debug_cmd func_len_result=${#1} }' else func_len () { $debug_cmd func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` } fi # func_mkdir_p DIRECTORY-PATH # --------------------------- # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { $debug_cmd _G_directory_path=$1 _G_dir_list= if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then # Protect directory names starting with '-' case $_G_directory_path in -*) _G_directory_path=./$_G_directory_path ;; esac # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done case $_G_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"` done _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'` func_mkdir_p_IFS=$IFS; IFS=: for _G_dir in $_G_dir_list; do IFS=$func_mkdir_p_IFS # mkdir can fail with a 'File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$_G_dir" 2>/dev/null || : done IFS=$func_mkdir_p_IFS # Bail out if we (or some other process) failed to create a directory. test -d "$_G_directory_path" || \ func_fatal_error "Failed to create '$1'" fi } # func_mktempdir [BASENAME] # ------------------------- # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, BASENAME is the basename for that directory. func_mktempdir () { $debug_cmd _G_template=${TMPDIR-/tmp}/${1-$progname} if test : = "$opt_dry_run"; then # Return a directory name, but don't create it in dry-run mode _G_tmpdir=$_G_template-$$ else # If mktemp works, use that first and foremost _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null` if test ! -d "$_G_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race _G_tmpdir=$_G_template-${RANDOM-0}$$ func_mktempdir_umask=`umask` umask 0077 $MKDIR "$_G_tmpdir" umask $func_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$_G_tmpdir" || \ func_fatal_error "cannot create temporary directory '$_G_tmpdir'" fi $ECHO "$_G_tmpdir" } # func_normal_abspath PATH # ------------------------ # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. func_normal_abspath () { $debug_cmd # These SED scripts presuppose an absolute path with a trailing slash. _G_pathcar='s|^/\([^/]*\).*$|\1|' _G_pathcdr='s|^/[^/]*||' _G_removedotparts=':dotsl s|/\./|/|g t dotsl s|/\.$|/|' _G_collapseslashes='s|/\{1,\}|/|g' _G_finalslash='s|/*$|/|' # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"` while :; do # Processed it all yet? if test / = "$func_normal_abspath_tpath"; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result"; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$_G_pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent" ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_notquiet ARG... # -------------------- # Echo program name prefixed message only when not in quiet mode. func_notquiet () { $debug_cmd $opt_quiet || func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_relative_path SRCDIR DSTDIR # -------------------------------- # Set func_relative_path_result to the relative path from SRCDIR to DSTDIR. func_relative_path () { $debug_cmd func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=$func_dirname_result if test -z "$func_relative_path_tlibdir"; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test -n "$func_stripname_result"; then func_append func_relative_path_result "/$func_stripname_result" fi # Normalisation. If bindir is libdir, return '.' else relative path. if test -n "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result" func_relative_path_result=$func_stripname_result fi test -n "$func_relative_path_result" || func_relative_path_result=. : } # func_quote_portable EVAL ARG # ---------------------------- # Internal function to portably implement func_quote_arg. Note that we still # keep attention to performance here so we as much as possible try to avoid # calling sed binary (so far O(N) complexity as long as func_append is O(1)). func_quote_portable () { $debug_cmd func_quote_portable_result=$2 # one-time-loop (easy break) while true do if $1; then func_quote_portable_result=`$ECHO "$2" | $SED \ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` break fi # Quote for eval. case $func_quote_portable_result in *[\\\`\"\$]*) case $func_quote_portable_result in *[\[\*\?]*) func_quote_portable_result=`$ECHO "$func_quote_portable_result" | $SED "$sed_quote_subst"` break ;; esac func_quote_portable_old_IFS=$IFS for _G_char in '\' '`' '"' '$' do # STATE($1) PREV($2) SEPARATOR($3) set start "" "" func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy IFS=$_G_char for _G_part in $func_quote_portable_result do case $1 in quote) func_append func_quote_portable_result "$3$2" set quote "$_G_part" "\\$_G_char" ;; start) set first "" "" func_quote_portable_result= ;; first) set quote "$_G_part" "" ;; esac done done IFS=$func_quote_portable_old_IFS ;; *) ;; esac break done func_quote_portable_unquoted_result=$func_quote_portable_result case $func_quote_portable_result in # double-quote args containing shell metacharacters to delay # word splitting, command substitution and variable expansion # for a subsequent eval. # many bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_portable_result=\"$func_quote_portable_result\" ;; esac } # func_quotefast_eval ARG # ----------------------- # Quote one ARG (internal). This is equivalent to 'func_quote_arg eval ARG', # but optimized for speed. Result is stored in $func_quotefast_eval. if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then func_quotefast_eval () { printf -v func_quotefast_eval_result %q "$1" } else func_quotefast_eval () { func_quote_portable false "$1" func_quotefast_eval_result=$func_quote_portable_result } fi # func_quote_arg MODEs ARG # ------------------------ # Quote one ARG to be evaled later. MODEs argument may contain zero ore more # specifiers listed below separated by ',' character. This function returns two # values: # i) func_quote_arg_result # double-quoted (when needed), suitable for a subsequent eval # ii) func_quote_arg_unquoted_result # has all characters that are still active within double # quotes backslashified. Available only if 'unquoted' is specified. # # Available modes: # ---------------- # 'eval' (default) # - escape shell special characters # 'expand' # - the same as 'eval'; but do not quote variable references # 'pretty' # - request aesthetic output, i.e. '"a b"' instead of 'a\ b'. This might # later used in func_quote to get output like: 'echo "a b"' instead of # 'echo a\ b'. This is slower than default on some shells. # 'unquoted' # - produce also $func_quote_arg_unquoted_result which does not contain # wrapping double-quotes. # # Examples for 'func_quote_arg pretty,unquoted string': # # string | *_result | *_unquoted_result # ------------+-----------------------+------------------- # " | \" | \" # a b | "a b" | a b # "a b" | "\"a b\"" | \"a b\" # * | "*" | * # z="${x-$y}" | "z=\"\${x-\$y}\"" | z=\"\${x-\$y}\" # # Examples for 'func_quote_arg pretty,unquoted,expand string': # # string | *_result | *_unquoted_result # --------------+---------------------+-------------------- # z="${x-$y}" | "z=\"${x-$y}\"" | z=\"${x-$y}\" func_quote_arg () { _G_quote_expand=false case ,$1, in *,expand,*) _G_quote_expand=: ;; esac case ,$1, in *,pretty,*|*,expand,*|*,unquoted,*) func_quote_portable $_G_quote_expand "$2" func_quote_arg_result=$func_quote_portable_result func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result ;; *) # Faster quote-for-eval for some shells. func_quotefast_eval "$2" func_quote_arg_result=$func_quotefast_eval_result ;; esac } # func_quote MODEs ARGs... # ------------------------ # Quote all ARGs to be evaled later and join them into single command. See # func_quote_arg's description for more info. func_quote () { $debug_cmd _G_func_quote_mode=$1 ; shift func_quote_result= while test 0 -lt $#; do func_quote_arg "$_G_func_quote_mode" "$1" if test -n "$func_quote_result"; then func_append func_quote_result " $func_quote_arg_result" else func_append func_quote_result "$func_quote_arg_result" fi shift done } # func_stripname PREFIX SUFFIX NAME # --------------------------------- # strip PREFIX and SUFFIX from NAME, and store in func_stripname_result. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_stripname () { $debug_cmd # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary variable first. func_stripname_result=$3 func_stripname_result=${func_stripname_result#"$1"} func_stripname_result=${func_stripname_result%"$2"} }' else func_stripname () { $debug_cmd case $2 in .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;; *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;; esac } fi # func_show_eval CMD [FAIL_EXP] # ----------------------------- # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} func_quote_arg pretty,expand "$_G_cmd" eval "func_notquiet $func_quote_arg_result" $opt_dry_run || { eval "$_G_cmd" _G_status=$? if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_show_eval_locale CMD [FAIL_EXP] # ------------------------------------ # Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { $debug_cmd _G_cmd=$1 _G_fail_exp=${2-':'} $opt_quiet || { func_quote_arg expand,pretty "$_G_cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || { eval "$_G_user_locale $_G_cmd" _G_status=$? eval "$_G_safe_locale" if test 0 -ne "$_G_status"; then eval "(exit $_G_status); $_G_fail_exp" fi } } # func_tr_sh # ---------- # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { $debug_cmd case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_verbose ARG... # ------------------- # Echo program name prefixed message in verbose mode only. func_verbose () { $debug_cmd $opt_verbose && func_echo "$*" : } # func_warn_and_continue ARG... # ----------------------------- # Echo program name prefixed warning message to standard error. func_warn_and_continue () { $debug_cmd $require_term_colors func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2 } # func_warning CATEGORY ARG... # ---------------------------- # Echo program name prefixed warning message to standard error. Warning # messages can be filtered according to CATEGORY, where this function # elides messages where CATEGORY is not listed in the global variable # 'opt_warning_types'. func_warning () { $debug_cmd # CATEGORY must be in the warning_categories list! case " $warning_categories " in *" $1 "*) ;; *) func_internal_error "invalid warning category '$1'" ;; esac _G_category=$1 shift case " $opt_warning_types " in *" $_G_category "*) $warning_func ${1+"$@"} ;; esac } # func_sort_ver VER1 VER2 # ----------------------- # 'sort -V' is not generally available. # Note this deviates from the version comparison in automake # in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a # but this should suffice as we won't be specifying old # version formats or redundant trailing .0 in bootstrap.conf. # If we did want full compatibility then we should probably # use m4_version_compare from autoconf. func_sort_ver () { $debug_cmd printf '%s\n%s\n' "$1" "$2" \ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n } # func_lt_ver PREV CURR # --------------------- # Return true if PREV and CURR are in the correct order according to # func_sort_ver, otherwise false. Use it like this: # # func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..." func_lt_ver () { $debug_cmd test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q` } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: #! /bin/sh # Set a version string for this script. scriptversion=2015-10-12.13; # UTC # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 # Copyright (C) 2010-2015 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Please report bugs or propose patches to gary@gnu.org. ## ------ ## ## Usage. ## ## ------ ## # This file is a library for parsing options in your shell scripts along # with assorted other useful supporting features that you can make use # of too. # # For the simplest scripts you might need only: # # #!/bin/sh # . relative/path/to/funclib.sh # . relative/path/to/options-parser # scriptversion=1.0 # func_options ${1+"$@"} # eval set dummy "$func_options_result"; shift # ...rest of your script... # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file # starting with '# Written by ' and ending with '# warranty; '. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the # '# Written by ' line, like the one at the top of this file. # # The default options also support '--debug', which will turn on shell # execution tracing (see the comment above debug_cmd below for another # use), and '--verbose' and the func_verbose function to allow your script # to display verbose messages only when your user has specified # '--verbose'. # # After sourcing this file, you can plug processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. ## -------------- ## ## Configuration. ## ## -------------- ## # You should override these variables in your script after sourcing this # file so that they reflect the customisations you have added to the # option parser. # The usage line for option parsing errors and the start of '-h' and # '--help' output messages. You can embed shell variables for delayed # expansion at the time the message is displayed, but you will need to # quote other shell meta-characters carefully to prevent them being # expanded when the contents are evaled. usage='$progpath [OPTION]...' # Short help message in response to '-h' and '--help'. Add to this or # override it after sourcing this library to reflect the full set of # options your script accepts. usage_message="\ --debug enable verbose shell tracing -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -v, --verbose verbosely report processing --version print version information and exit -h, --help print short or long help message and exit " # Additional text appended to 'usage_message' in response to '--help'. long_help_message=" Warning categories include: 'all' show all warnings 'none' turn off all the warnings 'error' warnings are treated as fatal errors" # Help message printed before fatal option parsing errors. fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## ## Hook function management. ## ## ------------------------- ## # This section contains functions for adding, removing, and running hooks # to the main code. A hook is just a named list of of function, that can # be run in order later on. # func_hookable FUNC_NAME # ----------------------- # Declare that FUNC_NAME will run hooks added with # 'func_add_hook FUNC_NAME ...'. func_hookable () { $debug_cmd func_append hookable_fns " $1" } # func_add_hook FUNC_NAME HOOK_FUNC # --------------------------------- # Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must # first have been declared "hookable" by a call to 'func_hookable'. func_add_hook () { $debug_cmd case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not accept hook functions." ;; esac eval func_append ${1}_hooks '" $2"' } # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ # Remove HOOK_FUNC from the list of functions called by FUNC_NAME. func_remove_hook () { $debug_cmd eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`' } # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. # It is assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. func_run_hooks () { $debug_cmd _G_rc_run_hooks=false case " $hookable_fns " in *" $1 "*) ;; *) func_fatal_error "'$1' does not support hook funcions.n" ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do if eval $_G_hook '"$@"'; then # store returned options list back into positional # parameters for next 'cmd' execution. eval _G_hook_result=\$${_G_hook}_result eval set dummy "$_G_hook_result"; shift _G_rc_run_hooks=: fi done $_G_rc_run_hooks && func_run_hooks_result=$_G_hook_result } ## --------------- ## ## Option parsing. ## ## --------------- ## # In order to add your own option parsing hooks, you must accept the # full positional parameter list in your hook function, you may remove/edit # any options that you action, and then pass back the remaining unprocessed # options in '_result', escaped suitably for # 'eval'. In this case you also must return $EXIT_SUCCESS to let the # hook's caller know that it should pay attention to # '_result'. Returning $EXIT_FAILURE signalizes that # arguments are left untouched by the hook and therefore caller will ignore the # result variable. # # Like this: # # my_options_prep () # { # $debug_cmd # # # Extend the existing usage message. # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' # # No change in '$@' (ignored completely by this hook). There is # # no need to do the equivalent (but slower) action: # # func_quote eval ${1+"$@"} # # my_options_prep_result=$func_quote_result # false # } # func_add_hook func_options_prep my_options_prep # # # my_silent_option () # { # $debug_cmd # # args_changed=false # # # Note that for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in # --silent|-s) opt_silent=: # args_changed=: # ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift # args_changed=: # ;; # *) # Make sure the first unrecognised option "$_G_opt" # # is added back to "$@", we could need that later # # if $args_changed is true. # set dummy "$_G_opt" ${1+"$@"}; shift; break ;; # esac # done # # if $args_changed; then # func_quote eval ${1+"$@"} # my_silent_option_result=$func_quote_result # fi # # $args_changed # } # func_add_hook func_parse_options my_silent_option # # # my_option_validation () # { # $debug_cmd # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." # # false # } # func_add_hook func_validate_options my_option_validation # # You'll also need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. # func_options_finish [ARG]... # ---------------------------- # Finishing the option parse loop (call 'func_options' hooks ATM). func_options_finish () { $debug_cmd _G_func_options_finish_exit=false if func_run_hooks func_options ${1+"$@"}; then func_options_finish_result=$func_run_hooks_result _G_func_options_finish_exit=: fi $_G_func_options_finish_exit } # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the # individual implementations for details. func_hookable func_options func_options () { $debug_cmd _G_rc_options=false for my_func in options_prep parse_options validate_options options_finish do if eval func_$my_func '${1+"$@"}'; then eval _G_res_var='$'"func_${my_func}_result" eval set dummy "$_G_res_var" ; shift _G_rc_options=: fi done # Save modified positional parameters for caller. As a top-level # options-parser function we always need to set the 'func_options_result' # variable (regardless the $_G_rc_options value). if $_G_rc_options; then func_options_result=$_G_res_var else func_quote eval ${1+"$@"} func_options_result=$func_quote_result fi $_G_rc_options } # func_options_prep [ARG]... # -------------------------- # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and # needs to propagate that back to rest of this script, then the complete # modified list must be put in 'func_run_hooks_result' before # returning $EXIT_SUCCESS (otherwise $EXIT_FAILURE is returned). func_hookable func_options_prep func_options_prep () { $debug_cmd # Option defaults: opt_verbose=false opt_warning_types= _G_rc_options_prep=false if func_run_hooks func_options_prep ${1+"$@"}; then _G_rc_options_prep=: # save modified positional parameters for caller func_options_prep_result=$func_run_hooks_result fi $_G_rc_options_prep } # func_parse_options [ARG]... # --------------------------- # The main option parsing loop. func_hookable func_parse_options func_parse_options () { $debug_cmd func_parse_options_result= _G_rc_parse_options=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. if func_run_hooks func_parse_options ${1+"$@"}; then eval set dummy "$func_run_hooks_result"; shift _G_rc_parse_options=: fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' func_echo "enabling shell trace mode" $debug_cmd ;; --no-warnings|--no-warning|--no-warn) set dummy --warnings none ${1+"$@"} shift ;; --warnings|--warning|-W) if test $# = 0 && func_missing_arg $_G_opt; then _G_rc_parse_options=: break fi case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above func_append_uniq opt_warning_types " $1" ;; *all) opt_warning_types=$warning_categories ;; *none) opt_warning_types=none warning_func=: ;; *error) opt_warning_types=$warning_categories warning_func=func_fatal_error ;; *) func_fatal_error \ "unsupported warning category: '$1'" ;; esac shift ;; --verbose|-v) opt_verbose=: ;; --version) func_version ;; -\?|-h) func_usage ;; --help) func_help ;; # Separate optargs to long options (plugins may need this): --*=*) func_split_equals "$_G_opt" set dummy "$func_split_equals_lhs" \ "$func_split_equals_rhs" ${1+"$@"} shift ;; # Separate optargs to short options: -W*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "$func_split_short_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-v*|-x*) func_split_short_opt "$_G_opt" set dummy "$func_split_short_opt_name" \ "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) _G_rc_parse_options=: ; break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; *) set dummy "$_G_opt" ${1+"$@"}; shift _G_match_parse_options=false break ;; esac $_G_match_parse_options && _G_rc_parse_options=: done if $_G_rc_parse_options; then # save modified positional parameters for caller func_quote eval ${1+"$@"} func_parse_options_result=$func_quote_result fi $_G_rc_parse_options } # func_validate_options [ARG]... # ------------------------------ # Perform any sanity checks on option settings and/or unconsumed # arguments. func_hookable func_validate_options func_validate_options () { $debug_cmd _G_rc_validate_options=false # Display all warnings if -W was not given. test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" if func_run_hooks func_validate_options ${1+"$@"}; then # save modified positional parameters for caller func_validate_options_result=$func_run_hooks_result _G_rc_validate_options=: fi # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE $_G_rc_validate_options } ## ----------------- ## ## Helper functions. ## ## ----------------- ## # This section contains the helper functions used by the rest of the # hookable option parser framework in ascii-betical order. # func_fatal_help ARG... # ---------------------- # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { $debug_cmd eval \$ECHO \""Usage: $usage"\" eval \$ECHO \""$fatal_help"\" func_error ${1+"$@"} exit $EXIT_FAILURE } # func_help # --------- # Echo long help message to standard output and exit. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message" exit 0 } # func_missing_arg ARGNAME # ------------------------ # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $debug_cmd func_error "Missing argument for '$1'." exit_cmd=exit } # func_split_equals STRING # ------------------------ # Set func_split_equals_lhs and func_split_equals_rhs shell variables after # splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ && _G_HAVE_XSI_OPS=yes if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_equals () { $debug_cmd func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} test "x$func_split_equals_lhs" = "x$1" \ && func_split_equals_rhs= }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_equals () { $debug_cmd func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= test "x$func_split_equals_lhs" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals # func_split_short_opt SHORTOPT # ----------------------------- # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. if test yes = "$_G_HAVE_XSI_OPS" then # This is an XSI compatible shell, allowing a faster implementation... eval 'func_split_short_opt () { $debug_cmd func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"} }' else # ...otherwise fall back to using expr, which is often a shell builtin. func_split_short_opt () { $debug_cmd func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt # func_usage # ---------- # Echo short help message to standard output and exit. func_usage () { $debug_cmd func_usage_message $ECHO "Run '$progname --help |${PAGER-more}' for full usage" exit 0 } # func_usage_message # ------------------ # Echo short help message to standard output. func_usage_message () { $debug_cmd eval \$ECHO \""Usage: $usage"\" echo $SED -n 's|^# || /^Written by/{ x;p;x } h /^Written by/q' < "$progpath" echo eval \$ECHO \""$usage_message"\" } # func_version # ------------ # Echo version message to standard output and exit. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' /(C)/!b go :more /\./!{ N s|\n# | | b more } :go /^# Written by /,/# warranty; / { s|^# || s|^# *$|| s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| p } /^# Written by / { s|^# || p } /^warranty; /q' < "$progpath" exit $? } # Local variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. scriptversion='(GNU libtool) 2.4.6' # func_echo ARG... # ---------------- # Libtool also displays the current mode in messages, so override # funclib.sh func_echo with this custom definition. func_echo () { $debug_cmd _G_message=$* func_echo_IFS=$IFS IFS=$nl for _G_line in $_G_message; do IFS=$func_echo_IFS $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line" done IFS=$func_echo_IFS } # func_warning ARG... # ------------------- # Libtool warnings are not categorized, so override funclib.sh # func_warning with this simpler definition. func_warning () { $debug_cmd $warning_func ${1+"$@"} } ## ---------------- ## ## Options parsing. ## ## ---------------- ## # Hook in the functions to make sure our own options are parsed during # the option parsing loop. usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --mode=MODE use operation mode MODE --no-warnings equivalent to '-Wnone' --preserve-dup-deps don't remove duplicate dependency libraries --quiet, --silent don't print informational messages --tag=TAG use configuration variables from tag TAG -v, --verbose print more informational messages than default --version print version information -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. func_help () { $debug_cmd func_usage_message $ECHO "$long_help_message MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. When passed as first option, '--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that. Try '$progname --help --mode=MODE' for a more detailed description of MODE. When reporting a bug, please describe a test case to reproduce it and include the following information: host-triplet: $host shell: $SHELL compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) version: $progname $scriptversion Debian-2.4.6-4 automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . GNU libtool home page: . General help using GNU software: ." exit 0 } # func_lo2o OBJECT-NAME # --------------------- # Transform OBJECT-NAME from a '.lo' suffix to the platform specific # object suffix. lo2o=s/\\.lo\$/.$objext/ o2lo=s/\\.$objext\$/.lo/ if test yes = "$_G_HAVE_XSI_OPS"; then eval 'func_lo2o () { case $1 in *.lo) func_lo2o_result=${1%.lo}.$objext ;; * ) func_lo2o_result=$1 ;; esac }' # func_xform LIBOBJ-OR-SOURCE # --------------------------- # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise) # suffix to a '.lo' libtool-object suffix. eval 'func_xform () { func_xform_result=${1%.*}.lo }' else # ...otherwise fall back to using sed. func_lo2o () { func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"` } func_xform () { func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'` } fi # func_fatal_configuration ARG... # ------------------------------- # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func__fatal_error ${1+"$@"} \ "See the $PACKAGE documentation for more information." \ "Fatal configuration error." } # func_config # ----------- # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # ------------- # Display the features supported by this script. func_features () { echo "host: $host" if test yes = "$build_libtool_libs"; then echo "enable shared libraries" else echo "disable shared libraries" fi if test yes = "$build_old_libs"; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag TAGNAME # ----------------------- # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname=$1 re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf=/$re_begincf/,/$re_endcf/p # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # ------------------------ # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # libtool_options_prep [ARG]... # ----------------------------- # Preparation for options parsed by libtool. libtool_options_prep () { $debug_mode # Option defaults: opt_config=false opt_dlopen= opt_dry_run=false opt_help=false opt_mode= opt_preserve_dup_deps=false opt_quiet=false nonopt= preserve_args= _G_rc_lt_options_prep=: # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; *) _G_rc_lt_options_prep=false ;; esac if $_G_rc_lt_options_prep; then # Pass back the list of options. func_quote eval ${1+"$@"} libtool_options_prep_result=$func_quote_result fi $_G_rc_lt_options_prep } func_add_hook func_options_prep libtool_options_prep # libtool_parse_options [ARG]... # --------------------------------- # Provide handling for libtool specific options. libtool_parse_options () { $debug_cmd _G_rc_lt_parse_options=false # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do _G_match_lt_parse_options=: _G_opt=$1 shift case $_G_opt in --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) func_config ;; --dlopen|-dlopen) opt_dlopen="${opt_dlopen+$opt_dlopen }$1" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) func_features ;; --finish) set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $_G_opt && break opt_mode=$1 case $1 in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $_G_opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" ;; --no-warnings|--no-warning|--no-warn) opt_warning=false func_append preserve_args " $_G_opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $_G_opt" ;; --silent|--quiet) opt_quiet=: opt_verbose=false func_append preserve_args " $_G_opt" ;; --tag) test $# = 0 && func_missing_arg $_G_opt && break opt_tag=$1 func_append preserve_args " $_G_opt $1" func_enable_tag "$1" shift ;; --verbose|-v) opt_quiet=false opt_verbose=: func_append preserve_args " $_G_opt" ;; # An option not handled by this hook function: *) set dummy "$_G_opt" ${1+"$@"} ; shift _G_match_lt_parse_options=false break ;; esac $_G_match_lt_parse_options && _G_rc_lt_parse_options=: done if $_G_rc_lt_parse_options; then # save modified positional parameters for caller func_quote eval ${1+"$@"} libtool_parse_options_result=$func_quote_result fi $_G_rc_lt_parse_options } func_add_hook func_parse_options libtool_parse_options # libtool_validate_options [ARG]... # --------------------------------- # Perform any sanity checks on option settings and/or unconsumed # arguments. libtool_validate_options () { # save first non-option argument if test 0 -lt $#; then nonopt=$1 shift fi # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" case $host in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match test yes != "$build_libtool_libs" \ && test yes != "$build_old_libs" \ && func_fatal_configuration "not configured to build any kind of library" # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test execute != "$opt_mode"; then func_error "unrecognized option '-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help=$help help="Try '$progname --help --mode=$opt_mode' for more information." } # Pass back the unparsed argument list func_quote eval ${1+"$@"} libtool_validate_options_result=$func_quote_result } func_add_hook func_validate_options libtool_validate_options # Process options as early as possible so that --help and --version # can return quickly. func_options ${1+"$@"} eval set dummy "$func_options_result"; shift ## ----------- ## ## Main. ## ## ----------- ## magic='%%%MAGIC variable%%%' magic_exe='%%%MAGIC EXE variable%%%' # Global variables. extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # func_generated_by_libtool # True iff stdin has been generated by Libtool. This function is only # a basic sanity check; it will hardly flush out determined imposters. func_generated_by_libtool_p () { $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p } # func_lalib_unsafe_p file # True iff FILE is a libtool '.la' library or '.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if 'file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case $lalib_p_line in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test yes = "$lalib_p" } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { test -f "$1" && $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $debug_cmd save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # 'FILE.' does not work on cygwin managed mounts. func_source () { $debug_cmd case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case $lt_sysroot:$1 in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result='='$func_stripname_result ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $debug_cmd if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with '--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=$1 if test yes = "$build_libtool_libs"; then write_lobj=\'$2\' else write_lobj=none fi if test yes = "$build_old_libs"; then write_oldobj=\'$3\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $debug_cmd # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result= if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result"; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $debug_cmd if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $debug_cmd # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $debug_cmd if test -z "$2" && test -n "$1"; then func_error "Could not determine host file name corresponding to" func_error " '$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result=$1 fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $debug_cmd if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " '$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result=$3 fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $debug_cmd case $4 in $1 ) func_to_host_path_result=$3$func_to_host_path_result ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via '$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $debug_cmd $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $debug_cmd case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result=$1 } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result=$func_convert_core_msys_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result=$func_convert_core_file_wine_to_w32_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $debug_cmd func_to_host_file_result=$1 if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result=$func_cygpath_result fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via '$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $debug_cmd if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd=func_convert_path_$func_stripname_result fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $debug_cmd func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result=$1 } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_msys_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result=$func_convert_core_path_wine_to_w32_result func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $debug_cmd func_to_host_path_result=$1 if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result=$func_cygpath_result func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_dll_def_p FILE # True iff FILE is a Windows DLL '.def' file. # Keep in sync with _LT_DLL_DEF_P in libtool.m4 func_dll_def_p () { $debug_cmd func_dll_def_p_tmp=`$SED -n \ -e 's/^[ ]*//' \ -e '/^\(;.*\)*$/d' \ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \ -e q \ "$1"` test DEF = "$func_dll_def_p_tmp" } # func_mode_compile arg... func_mode_compile () { $debug_cmd # Get the compilation command and the source file. base_compile= srcfile=$nonopt # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg=$arg arg_mode=normal ;; target ) libobj=$arg arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify '-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs=$IFS; IFS=, for arg in $args; do IFS=$save_ifs func_append_quoted lastarg "$arg" done IFS=$save_ifs func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg=$srcfile srcfile=$arg ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with '-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj=$func_basename_result } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from '$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test yes = "$build_libtool_libs" \ || func_fatal_configuration "cannot build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_arg pretty "$libobj" test "X$libobj" != "X$func_quote_arg_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name '$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname=$func_basename_result xdir=$func_dirname_result lobj=$xdir$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test yes = "$build_old_libs"; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test no = "$compiler_c_o"; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext lockfile=$output_obj.lock else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test yes = "$need_locks"; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test warn = "$need_locks"; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_arg pretty "$srcfile" qsrcfile=$func_quote_arg_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test no != "$pic_mode"; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test yes = "$suppress_opt"; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test yes = "$build_old_libs"; then if test yes != "$pic_mode"; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test yes = "$compiler_c_o"; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test warn = "$need_locks" && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support '-c' and '-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test no != "$need_locks"; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test compile = "$opt_mode" && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a '.o' file suitable for static linking -static only build a '.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a 'standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix '.c' with the library object suffix, '.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to '-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the '--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the 'install' or 'cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE use a list of object files found in FILE to specify objects -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes) -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with '-') are ignored. Every other argument is treated as a filename. Files ending in '.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in '.la', then a libtool library is created, only library objects ('.lo' files) may be specified, and '-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created using 'ar' and 'ranlib', or on Windows using 'lib'. If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode '$opt_mode'" ;; esac echo $ECHO "Try '$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test : = "$opt_help"; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | $SED -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | $SED '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $debug_cmd # The first argument is the command name. cmd=$nonopt test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "'$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "'$file' was not linked with '-export-dynamic'" continue fi func_dirname "$file" "" "." dir=$func_dirname_result if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir=$func_dirname_result ;; *) func_warning "'-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir=$absdir # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic=$magic # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file=$progdir/$program elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file=$progdir/$program fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if $opt_dry_run; then # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS else if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd=\$cmd$args fi } test execute = "$opt_mode" && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $debug_cmd libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "'$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument '$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and '=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_quiet && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the '-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the '$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the '$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the '$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test finish = "$opt_mode" && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $debug_cmd # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. func_quote_arg pretty "$nonopt" install_prog="$func_quote_arg_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_arg pretty "$arg" func_append install_prog "$func_quote_arg_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=false stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=: ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test X-m = "X$prev" && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_arg pretty "$arg" func_append install_prog " $func_quote_arg_result" if test -n "$arg2"; then func_quote_arg pretty "$arg2" fi func_append install_shared_prog " $func_quote_arg_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the '$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_arg pretty "$install_override_mode" func_append install_shared_prog " -m $func_quote_arg_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=: if $isdir; then destdir=$dest destname= else func_dirname_and_basename "$dest" "" "." destdir=$func_dirname_result destname=$func_basename_result # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "'$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "'$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "'$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir=$func_dirname_result func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking '$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname=$1 shift srcname=$realname test -n "$relink_command" && srcname=${realname}T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme=$stripme case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= ;; esac ;; os2*) case $realname in *_dll.a) tstripme= ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try 'ln -sf' first, because the 'ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib=$destdir/$realname func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name=$func_basename_result instname=$dir/${name}i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest=$destfile destfile= ;; *) func_fatal_help "cannot copy a libtool object to '$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test yes = "$build_old_libs"; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile=$destdir/$destname else func_basename "$file" destfile=$func_basename_result destfile=$destdir/$destfile fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext= case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=.exe fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script '$wrapper'" finalize=: for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'` if test -n "$libdir" && test ! -f "$libfile"; then func_warning "'$lib' has not been installed in '$libdir'" finalize=false fi done relink_command= func_source "$wrapper" outputname= if test no = "$fast_install" && test -n "$relink_command"; then $opt_dry_run || { if $finalize; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file=$func_basename_result outputname=$tmpdir/$file # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_quiet || { func_quote_arg expand,pretty "$relink_command" eval "func_echo $func_quote_arg_result" } if eval "$relink_command"; then : else func_error "error: relink '$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file=$outputname else func_warning "cannot relink '$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name=$func_basename_result # Set up the ranlib parameters. oldlib=$destdir/$name func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run '$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test install = "$opt_mode" && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $debug_cmd my_outputname=$1 my_originator=$2 my_pic_p=${3-false} my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms=${my_outputname}S.c else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist=$output_objdir/$my_outputname.nm func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* External symbol declarations for the compiler. */\ " if test yes = "$dlself"; then func_verbose "generating symbol list for '$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from '$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols=$output_objdir/$outputname.exp $opt_dry_run || { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from '$dlprefile'" func_basename "$dlprefile" name=$func_basename_result case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename= if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname"; then func_basename "$dlprefile_dlname" dlprefile_dlbasename=$func_basename_result else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename"; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi func_show_eval '$RM "${nlist}I"' if test -n "$global_symbol_to_import"; then eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I' fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[];\ " if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ static void lt_syminit(void) { LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols; for (; symbol->name; ++symbol) {" $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms" echo >> "$output_objdir/$my_dlsyms" "\ } }" fi echo >> "$output_objdir/$my_dlsyms" "\ LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = { {\"$my_originator\", (void *) 0}," if test -s "$nlist"I; then echo >> "$output_objdir/$my_dlsyms" "\ {\"@INIT@\", (void *) <_syminit}," fi case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) $my_pic_p && pic_flag_for_symtable=" $pic_flag" ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"' # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for '$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $debug_cmd func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $debug_cmd win32_libid_type=unknown win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || func_cygming_gnu_implib_p "$1" then win32_nmres=import else win32_nmres= fi ;; *) func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s|.*|import| p q } }'` ;; esac case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $debug_cmd sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $debug_cmd match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive that possess that section. Heuristic: eliminate # all those that have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $debug_cmd if func_cygming_gnu_implib_p "$1"; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1"; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result= fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $debug_cmd f_ex_an_ar_dir=$1; shift f_ex_an_ar_oldlib=$1 if test yes = "$lock_old_archive_extraction"; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test yes = "$lock_old_archive_extraction"; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $debug_cmd my_gentop=$1; shift my_oldlibs=${1+"$@"} my_oldobjs= my_xlib= my_xabs= my_xdir= for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib=$func_basename_result my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir=$my_gentop/$my_xlib_u func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` func_basename "$darwin_archive" darwin_base_archive=$func_basename_result darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches; do func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch" $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive" cd "unfat-$$/$darwin_base_archive-$darwin_arch" func_extract_an_archive "`pwd`" "$darwin_base_archive" cd "$darwin_curdir" $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result=$my_oldobjs } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs 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 BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" func_quote_arg pretty "$ECHO" qECHO=$func_quote_arg_result $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=$qECHO fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ that is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options that match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test yes = "$fast_install"; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else \$ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include #define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0) /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined other_platform || defined ... */ #endif /* portability defines, excluding path handling macros */ #if defined _MSC_VER # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC #elif defined __MINGW32__ # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined __CYGWIN__ # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined other platforms ... */ #endif #if defined PATH_MAX # define LT_PATHMAX PATH_MAX #elif defined MAXPATHLEN # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \ defined __OS2__ # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free (stale); stale = 0; } \ } while (0) #if defined LT_DEBUGWRAPPER static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; size_t tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined HAVE_DOS_BASED_FILE_SYSTEM if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined HAVE_DOS_BASED_FILE_SYSTEM } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = (size_t) (q - p); p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (STREQ (str, pat)) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else size_t len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { size_t orig_value_len = strlen (orig_value); size_t add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ size_t len = strlen (new_value); while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[--len] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $debug_cmd case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_suncc_cstd_abi # !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!! # Several compiler flags select an ABI that is incompatible with the # Cstd library. Avoid specifying it if any are in CXXFLAGS. func_suncc_cstd_abi () { $debug_cmd case " $compile_command " in *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*) suncc_use_cstd_abi=no ;; *) suncc_use_cstd_abi=yes ;; esac } # func_mode_link arg... func_mode_link () { $debug_cmd case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll that has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= os2dllname= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=false prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module=$wl-single_module func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test yes != "$build_libtool_libs" \ && func_fatal_configuration "cannot build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg=$1 shift func_quote_arg pretty,unquoted "$arg" qarg=$func_quote_arg_unquoted_result func_append libtool_args " $func_quote_arg_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir=$arg prev= continue ;; dlfiles|dlprefiles) $preload || { # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=: } case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test no = "$dlself"; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test dlprefiles = "$prev"; then dlself=yes elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test dlfiles = "$prev"; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols=$arg test -f "$arg" \ || func_fatal_error "symbol file '$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex=$arg prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir=$arg prev= continue ;; mllvm) # Clang does not use LLVM to link, so we can simply discard any # '-mllvm $arg' options when doing the link step. prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result if test none != "$pic_object"; then # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object fi # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file '$arg' does not exist" fi arg=$save_arg prev= continue ;; os2dllname) os2dllname=$arg prev= continue ;; precious_regex) precious_files_regex=$arg prev= continue ;; release) release=-$arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test rpath = "$prev"; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds=$arg prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg=$arg case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "'-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test X-export-symbols = "X$arg"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between '-L' and '$1'" else func_fatal_error "need path for '-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of '$dir'" dir=$absdir ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test X-lc = "X$arg" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test X-lc = "X$arg" && continue ;; esac elif test X-lc_r = "X$arg"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -mllvm) prev=mllvm continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module=$wl-multi_module continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "'-no-install' is ignored for $host" func_warning "assuming '-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -os2dllname) prev=os2dllname continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_arg pretty "$flag" func_append arg " $func_quote_arg_result" func_append compiler_flags " $func_quote_arg_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs=$IFS; IFS=, for flag in $args; do IFS=$save_ifs func_quote_arg pretty "$flag" func_append arg " $wl$func_quote_arg_result" func_append compiler_flags " $wl$func_quote_arg_result" func_append linker_flags " $func_quote_arg_result" done IFS=$save_ifs func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_arg pretty "$arg" arg=$func_quote_arg_result ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # -fstack-protector* stack protector flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -specs=* GCC specs files # -stdlib=* select c++ std lib with clang # -fsanitize=* Clang/GCC memory and address sanitizer -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \ -specs=*|-fsanitize=*) func_quote_arg pretty "$arg" arg=$func_quote_arg_result func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; -Z*) if test os2 = "`expr $host : '.*\(os2\)'`"; then # OS/2 uses -Zxxx to specify OS/2-specific options compiler_flags="$compiler_flags $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case $arg in -Zlinker | -Zstack) prev=xcompiler ;; esac continue else # Otherwise treat like 'Some other compiler flag' below func_quote_arg pretty "$arg" arg=$func_quote_arg_result fi ;; # Some other compiler flag. -* | +*) func_quote_arg pretty "$arg" arg=$func_quote_arg_result ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test none = "$pic_object" && test none = "$non_pic_object"; then func_fatal_error "cannot find name of object for '$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result test none = "$pic_object" || { # Prepend the subdirectory the object is found in. pic_object=$xdir$pic_object if test dlfiles = "$prev"; then if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test dlprefiles = "$prev"; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg=$pic_object } # Non-PIC object. if test none != "$non_pic_object"; then # Prepend the subdirectory the object is found in. non_pic_object=$xdir$non_pic_object # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test none = "$pic_object"; then arg=$non_pic_object fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object=$pic_object func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir=$func_dirname_result func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "'$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test dlfiles = "$prev"; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test dlprefiles = "$prev"; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_arg pretty "$arg" arg=$func_quote_arg_result ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the '$prevarg' option requires an argument" if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname=$func_basename_result libobjs_save=$libobjs if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" # Definition is injected by LT_CONFIG during libtool generation. func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH" func_dirname "$output" "/" "" output_objdir=$func_dirname_result$objdir func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test lib = "$linkmode"; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can '-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=false newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test lib,link = "$linkmode,$pass"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs=$tmp_deplibs fi if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass"; then libs=$deplibs deplibs= fi if test prog = "$linkmode"; then case $pass in dlopen) libs=$dlfiles ;; dlpreopen) libs=$dlprefiles ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test lib,dlpreopen = "$linkmode,$pass"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs=$dlprefiles fi if test dlopen = "$pass"; then # Collect dlpreopened libraries save_deplibs=$deplibs deplibs= fi for deplib in $libs; do lib= found=false case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test lib != "$linkmode" && test prog != "$linkmode"; then func_warning "'-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test lib = "$linkmode"; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib=$searchdir/lib$name$search_ext if test -f "$lib"; then if test .la = "$search_ext"; then found=: else found=false fi break 2 fi done done if $found; then # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll=$l done if test "X$ll" = "X$old_library"; then # only static version available found=false func_dirname "$lib" "" "." ladir=$func_dirname_result lib=$ladir/$old_library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi else # deplib doesn't seem to be a libtool library if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs" fi continue fi ;; # -l *.ltframework) if test prog,link = "$linkmode,$pass"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test lib = "$linkmode"; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test conv = "$pass" && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi if test scan = "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "'-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test link = "$pass"; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test conv = "$pass"; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=false case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=: fi ;; pass_all) valid_a_lib=: ;; esac if $valid_a_lib; then echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" else echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." fi ;; esac continue ;; prog) if test link != "$pass"; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test conv = "$pass"; then deplibs="$deplib $deplibs" elif test prog = "$linkmode"; then if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=: continue ;; esac # case $deplib $found || test -f "$lib" \ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'" # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "'$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir=$func_dirname_result dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test lib,link = "$linkmode,$pass" || test prog,scan = "$linkmode,$pass" || { test prog != "$linkmode" && test lib != "$linkmode"; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test conv = "$pass"; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for '$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test prog != "$linkmode" && test lib != "$linkmode"; then func_fatal_error "'$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test yes = "$prefer_static_libs" || test built,no = "$prefer_static_libs,$installed"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib=$l done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for '$lib'" fi # This library was specified with -dlopen. if test dlopen = "$pass"; then test -z "$libdir" \ && func_fatal_error "cannot -dlopen a convenience library: '$lib'" if test -z "$dlname" || test yes != "$dlopen_support" || test no = "$build_libtool_libs" then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of '$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir=$ladir fi ;; esac func_basename "$lib" laname=$func_basename_result # Find the relevant object directory and library name. if test yes = "$installed"; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library '$lib' was moved." dir=$ladir absdir=$abs_ladir libdir=$abs_ladir else dir=$lt_sysroot$libdir absdir=$lt_sysroot$libdir fi test yes = "$hardcode_automatic" && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir=$ladir absdir=$abs_ladir # Remove this search path later func_append notinst_path " $abs_ladir" else dir=$ladir/$objdir absdir=$abs_ladir/$objdir # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test dlpreopen = "$pass"; then if test -z "$libdir" && test prog = "$linkmode"; then func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'" fi case $host in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test lib = "$linkmode"; then deplibs="$dir/$old_library $deplibs" elif test prog,link = "$linkmode,$pass"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test prog = "$linkmode" && test link != "$pass"; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=false if test no != "$link_all_deplibs" || test -z "$library_names" || test no = "$build_libtool_libs"; then linkalldeplibs=: fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if $linkalldeplibs; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test prog,link = "$linkmode,$pass"; then if test -n "$library_names" && { { test no = "$prefer_static_libs" || test built,yes = "$prefer_static_libs,$installed"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then # Make sure the rpath contains only unique directories. case $temp_rpath: in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if $alldeplibs && { test pass_all = "$deplibs_check_method" || { test yes = "$build_libtool_libs" && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test built = "$use_static_libs" && test yes = "$installed"; then use_static_libs=no fi if test -n "$library_names" && { test no = "$use_static_libs" || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc* | *os2*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test no = "$installed"; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule= for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule=$dlpremoduletest break fi done if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then echo if test prog = "$linkmode"; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test lib = "$linkmode" && test yes = "$hardcode_into_libs"; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname=$1 shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname=$dlname elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc* | *os2*) func_arith $current - $age major=$func_arith_result versuffix=-$major ;; esac eval soname=\"$soname_spec\" else soname=$realname fi # Make a new name for the extract_expsyms_cmds to use soroot=$soname func_basename "$soroot" soname=$func_basename_result func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from '$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for '$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test prog = "$linkmode" || test relink != "$opt_mode"; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test no = "$hardcode_direct"; then add=$dir/$linklib case $host in *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;; *-*-sysv4*uw2*) add_dir=-L$dir ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir=-L$dir ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we cannot # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library"; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add=$dir/$old_library fi elif test -n "$old_library"; then add=$dir/$old_library fi fi esac elif test no = "$hardcode_minus_L"; then case $host in *-*-sunos*) add_shlibpath=$dir ;; esac add_dir=-L$dir add=-l$name elif test no = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; relink) if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$dir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$absdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name elif test yes = "$hardcode_shlibpath_var"; then add_shlibpath=$dir add=-l$name else lib_linked=no fi ;; *) lib_linked=no ;; esac if test yes != "$lib_linked"; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test prog = "$linkmode"; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test yes != "$hardcode_direct" && test yes != "$hardcode_minus_L" && test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test prog = "$linkmode" || test relink = "$opt_mode"; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test yes = "$hardcode_direct" && test no = "$hardcode_direct_absolute"; then add=$libdir/$linklib elif test yes = "$hardcode_minus_L"; then add_dir=-L$libdir add=-l$name elif test yes = "$hardcode_shlibpath_var"; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add=-l$name elif test yes = "$hardcode_automatic"; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib"; then add=$inst_prefix_dir$libdir/$linklib else add=$libdir/$linklib fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir=-L$libdir # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add=-l$name fi if test prog = "$linkmode"; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test prog = "$linkmode"; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test unsupported != "$hardcode_direct"; then test -n "$old_library" && linklib=$old_library compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test yes = "$build_libtool_libs"; then # Not a shared library if test pass_all != "$deplibs_check_method"; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system cannot link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test yes = "$module"; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test lib = "$linkmode"; then if test -n "$dependency_libs" && { test yes != "$hardcode_into_libs" || test yes = "$build_old_libs" || test yes = "$link_static"; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs=$temp_deplibs fi func_append newlib_search_path " $absdir" # Link against this library test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test no != "$link_all_deplibs"; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path=$deplib ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of '$dir'" absdir=$dir fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names"; then for tmp in $deplibrary_names; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl"; then depdepl=$absdir/$objdir/$depdepl darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl" func_append linker_flags " -dylib_file $darwin_install_name:$depdepl" path= fi fi ;; *) path=-L$absdir/$objdir ;; esac else eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "'$deplib' seems to be moved" path=-L$absdir fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test link = "$pass"; then if test prog = "$linkmode"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs=$newdependency_libs if test dlpreopen = "$pass"; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test dlopen != "$pass"; then test conv = "$pass" || { # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= } if test prog,link = "$linkmode,$pass"; then vars="compile_deplibs finalize_deplibs" else vars=deplibs fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Add Sun CC postdeps if required: test CXX = "$tagname" && { case $host_os in linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; solaris*) func_cc_basename "$CC" case $func_cc_basename_result in CC* | sunCC*) func_suncc_cstd_abi if test no != "$suncc_use_cstd_abi"; then func_append postdeps ' -library=Cstd -library=Crun' fi ;; esac ;; esac } # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i= ;; esac if test -n "$i"; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test prog = "$linkmode"; then dlfiles=$newdlfiles fi if test prog = "$linkmode" || test lib = "$linkmode"; then dlprefiles=$newdlprefiles fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "'-R' is ignored for archives" test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "'-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "'-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs=$output func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form 'libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test no = "$module" \ && func_fatal_help "libtool library '$output' must begin with 'lib'" if test no != "$need_lib_prefix"; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test pass_all != "$deplibs_check_method"; then func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test no = "$dlself" \ || func_warning "'-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test 1 -lt "$#" \ && func_warning "ignoring multiple '-rpath's for a libtool library" install_libdir=$1 oldlibs= if test -z "$rpath"; then if test yes = "$build_libtool_libs"; then # Building a libtool convenience library. # Some compilers have problems with a '.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "'-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "'-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs=$IFS; IFS=: set dummy $vinfo 0 0 0 shift IFS=$save_ifs test -n "$7" && \ func_fatal_help "too many parameters to '-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major=$1 number_minor=$2 number_revision=$3 # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # that has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|freebsd-elf|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_revision ;; freebsd-aout|qnx|sunos) current=$number_major revision=$number_minor age=0 ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age=$number_minor revision=$number_minor lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type '$version_type'" ;; esac ;; no) current=$1 revision=$2 age=$3 ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT '$current' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION '$revision' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE '$age' must be a nonnegative integer" func_fatal_error "'$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE '$age' is greater than the current interface number '$current'" func_fatal_error "'$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" # On Darwin other compilers case $CC in nagfor*) verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision" ;; *) verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; esac ;; freebsd-aout) major=.$current versuffix=.$current.$revision ;; freebsd-elf) func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; irix | nonstopux) if test no = "$lt_irix_increment"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring=$verstring_prefix$major.$revision # Add in all the interfaces that we are compatible with. loop=$revision while test 0 -ne "$loop"; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring_prefix$major.$iface:$verstring done # Before this point, $major must not contain '.'. major=.$major versuffix=$major.$revision ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix=$major.$age.$revision ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=.$current.$age.$revision verstring=$current.$age.$revision # Add in all the interfaces that we are compatible with. loop=$age while test 0 -ne "$loop"; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring=$verstring:$iface.0 done # Make executables depend on our current version. func_append verstring ":$current.0" ;; qnx) major=.$current versuffix=.$current ;; sco) major=.$current versuffix=.$current ;; sunos) major=.$current versuffix=.$current.$revision ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 file systems. func_arith $current - $age major=$func_arith_result versuffix=-$major ;; *) func_fatal_configuration "unknown library version type '$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring=0.0 ;; esac if test no = "$need_version"; then versuffix= else versuffix=.0.0 fi fi # Remove version info from name if versioning should be avoided if test yes,no = "$avoid_version,$need_version"; then major= versuffix= verstring= fi # Check to see if the archive will have undefined symbols. if test yes = "$allow_undefined"; then if test unsupported = "$allow_undefined_flag"; then if test yes = "$build_old_libs"; then func_warning "undefined symbols not allowed in $host shared libraries; building static only" build_libtool_libs=no else func_fatal_error "can't build $host shared library unless -no-undefined is specified" fi fi else # Don't allow undefined symbols. allow_undefined_flag=$no_undefined_flag fi fi func_generate_dlsyms "$libname" "$libname" : func_append libobjs " $symfileobj" test " " = "$libobjs" && libobjs= if test relink != "$opt_mode"; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*) if test -n "$precious_files_regex"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles=$dlfiles dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles=$dlprefiles dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test yes = "$build_libtool_libs"; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test yes = "$build_libtool_need_lc"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release= versuffix= major= newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib=$potent_lib while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | $SED 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;; *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test yes = "$allow_libtool_libs_with_static_runtimes"; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib= ;; esac fi if test -n "$a_deplib"; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib=$potent_lib # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib= break 2 fi done done fi if test -n "$a_deplib"; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib"; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs= tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test yes = "$allow_libtool_libs_with_static_runtimes"; then for i in $predeps $postdeps; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test none = "$deplibs_check_method"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test yes = "$droppeddeps"; then if test yes = "$module"; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using 'nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** 'nm' from GNU binutils and a full rebuild may help." fi if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test no = "$allow_undefined"; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test no = "$build_old_libs"; then oldlibs=$output_objdir/$libname.$libext build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs=$new_libs # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test yes = "$build_libtool_libs"; then # Remove $wl instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test yes = "$hardcode_into_libs"; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath=$finalize_rpath test relink = "$opt_mode" || rpath=$compile_rpath$rpath for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath=$finalize_shlibpath test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname=$1 shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname=$realname fi if test -z "$dlname"; then dlname=$soname fi lib=$output_objdir/$realname linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols=$output_objdir/$libname.uexp func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile func_dll_def_p "$export_symbols" || { # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols=$export_symbols export_symbols= always_export_symbols=yes } fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs=$IFS; IFS='~' for cmd1 in $cmds; do IFS=$save_ifs # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test yes = "$try_normal_branch" \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=$output_objdir/$output_la.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS=$save_ifs if test -n "$export_symbols_regex" && test : != "$skipped_export"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test : != "$skipped_export" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs=$tmp_deplibs if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test yes = "$compiler_needs_object" && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test : != "$skipped_export" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then output=$output_objdir/$output_la.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then output=$output_objdir/$output_la.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test yes = "$compiler_needs_object"; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-$k.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test -z "$objlist" || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test 1 -eq "$k"; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-$k.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-$k.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi ${skipped_export-false} && { func_verbose "generating symbol list for '$libname.la'" export_symbols=$output_objdir/$libname.exp $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi } test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs=$IFS; IFS='~' for cmd in $concat_cmds; do IFS=$save_ifs $opt_quiet || { func_quote_arg expand,pretty "$cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi ${skipped_export-false} && { if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols=$export_symbols test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for '$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands, which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi } libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test yes = "$module" && test -n "$module_cmds"; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs=$IFS; IFS='~' for cmd in $cmds; do IFS=$sp$nl eval cmd=\"$cmd\" IFS=$save_ifs $opt_quiet || { func_quote_arg expand,pretty "$cmd" eval "func_echo $func_quote_arg_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test relink = "$opt_mode"; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS=$save_ifs # Restore the uninstalled library and exit if test relink = "$opt_mode"; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test yes = "$module" || test yes = "$export_dynamic"; then # On all known operating systems, these are identical. dlname=$soname fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then func_warning "'-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "'-l' and '-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "'-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "'-R' is ignored for objects" test -n "$vinfo" && \ func_warning "'-version-info' is ignored for objects" test -n "$release" && \ func_warning "'-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object '$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj=$output ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # if reload_cmds runs $LD directly, get rid of -Wl from # whole_archive_flag_spec and hope we can get by with turning comma # into space. case $reload_cmds in *\$LD[\ \$]*) wl= ;; esac if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags else gentop=$output_objdir/${obj}x func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test yes = "$build_libtool_libs" || libobjs=$non_pic_objects # Create the old-style object. reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs output=$obj func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi test yes = "$build_libtool_libs" || { if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS } if test -n "$pic_flag" || test default != "$pic_mode"; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output=$libobj func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "'-version-info' is ignored for programs" test -n "$release" && \ func_warning "'-release' is ignored for programs" $preload \ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test CXX = "$tagname"; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " $wl-bind_at_load" func_append finalize_command " $wl-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs=$new_libs func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath=$rpath rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs=$libdir else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir=$hardcode_libdirs eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath=$rpath if test -n "$libobjs" && test yes = "$build_old_libs"; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" false # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=: case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=false ;; *cygwin* | *mingw* ) test yes = "$build_libtool_libs" || wrappers_required=false ;; *) if test no = "$need_relink" || test yes != "$build_libtool_libs"; then wrappers_required=false fi ;; esac $wrappers_required || { # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command=$compile_command$compile_rpath # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.$objext"; then func_show_eval '$RM "$output_objdir/${outputname}S.$objext"' fi exit $exit_status } if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test yes = "$no_install"; then # We don't need to create a wrapper script. link_command=$compile_var$compile_command$compile_rpath # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi case $hardcode_action,$fast_install in relink,*) # Fast installation is not supported link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath func_warning "this platform does not like uninstalled shared libraries" func_warning "'$output' will be relinked during installation" ;; *,yes) link_command=$finalize_var$compile_command$finalize_rpath relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` ;; *,no) link_command=$compile_var$compile_command$compile_rpath relink_command=$finalize_var$finalize_command$finalize_rpath ;; *,needless) link_command=$finalize_var$compile_command$finalize_rpath relink_command= ;; esac # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_arg pretty "$var_value" relink_command="$var=$func_quote_arg_result; export $var; $relink_command" fi done func_quote_arg pretty,unquoted "(cd `pwd`; $relink_command)" relink_command=$func_quote_arg_unquoted_result fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource=$output_path/$objdir/lt-$output_name.c cwrapper=$output_path/$output_name.exe $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host"; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do case $build_libtool_libs in convenience) oldobjs="$libobjs_save $symfileobj" addlibs=$convenience build_libtool_libs=no ;; module) oldobjs=$libobjs_save addlibs=$old_convenience build_libtool_libs=no ;; *) oldobjs="$old_deplibs $non_pic_objects" $preload && test -f "$symfileobj" \ && func_append oldobjs " $symfileobj" addlibs=$old_convenience ;; esac if test -n "$addlibs"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop=$output_objdir/${outputname}x func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase=$func_basename_result case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj"; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test -z "$oldobjs"; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test yes = "$build_old_libs" && old_library=$libname.$libext func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_arg pretty,unquoted "$var_value" relink_command="$var=$func_quote_arg_unquoted_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" func_quote_arg pretty,unquoted "$relink_command" relink_command=$func_quote_arg_unquoted_result if test yes = "$hardcode_automatic"; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test yes = "$installed"; then if test -z "$install_libdir"; then break fi output=$output_objdir/${outputname}i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name=$func_basename_result func_resolve_sysroot "$deplib" eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "'$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs=$newdependency_libs newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name=$func_basename_result eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "'$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles=$newdlprefiles else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles=$newdlfiles newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles=$newdlprefiles fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test -n "$bindir"; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result/$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that cannot go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test no,yes = "$installed,$need_relink"; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } if test link = "$opt_mode" || test relink = "$opt_mode"; then func_mode_link ${1+"$@"} fi # func_mode_uninstall arg... func_mode_uninstall () { $debug_cmd RM=$nonopt files= rmforce=false exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic=$magic for arg do case $arg in -f) func_append RM " $arg"; rmforce=: ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir=$func_dirname_result if test . = "$dir"; then odir=$objdir else odir=$dir/$objdir fi func_basename "$file" name=$func_basename_result test uninstall = "$opt_mode" && odir=$dir # Remember odir for removal later, being careful to avoid duplicates if test clean = "$opt_mode"; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif $rmforce; then continue fi rmfiles=$file case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case $opt_mode in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test none != "$pic_object"; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test none != "$non_pic_object"; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test clean = "$opt_mode"; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.$objext" if test yes = "$fast_install" && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name"; then func_append rmfiles " $odir/lt-$noexename.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the $objdir's in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then func_mode_uninstall ${1+"$@"} fi test -z "$opt_mode" && { help=$generic_help func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode '$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # where we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: nip2-8.7.1/NEWS0000644000175000017500000000000113351443023010004 00000000000000 nip2-8.7.1/config.guess0000755000175000017500000012637313417042641011656 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2018 Free Software Foundation, Inc. timestamp='2018-02-24' # 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; 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 Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > "$dummy.c" ; for c in cc gcc c89 c99 ; do if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval "$set_cc_for_build" cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" # If ldd exists, use it to detect musl libc. if command -v ldd >/dev/null && \ ldd --version 2>&1 | grep -q ^musl then LIBC=musl fi ;; esac # Note: order is significant - the case branches are not exclusive. case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ "/sbin/$sysctl" 2>/dev/null || \ "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` case "$UNAME_MACHINE_ARCH" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine="${arch}${endian}"-unknown ;; *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval "$set_cc_for_build" if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "$machine-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" exit ;; *:MidnightBSD:*:*) echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) echo "$UNAME_MACHINE"-unknown-sortix exit ;; *:Redox:*:*) echo "$UNAME_MACHINE"-unknown-redox exit ;; mips:OSF1:*.*) echo mips-dec-osf1 exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval "$set_cc_for_build" SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] then if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ [ "$TARGET_BINARY_INTERFACE"x = x ] then echo m88k-dg-dgux"$UNAME_RELEASE" else echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` case "$UNAME_MACHINE" in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "$sc_kernel_bits" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "$HP_ARCH" = "" ]; then eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ "$HP_ARCH" = hppa2.0w ] then eval "$set_cc_for_build" # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo "$UNAME_MACHINE"-unknown-osf1mk else echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) case "$UNAME_MACHINE" in x86) echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; i*:UWIN*:*) echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; i*86:Minix:*:*) echo "$UNAME_MACHINE"-pc-minix exit ;; aarch64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) eval "$set_cc_for_build" if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } ;; mips64el:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-"$LIBC" exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) if objdump -f /bin/sh | grep -q elf32-x86-64; then echo "$UNAME_MACHINE"-pc-linux-"$LIBC"x32 else echo "$UNAME_MACHINE"-pc-linux-"$LIBC" fi exit ;; xtensa*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv"$UNAME_RELEASE" else echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval "$set_cc_for_build" if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-*:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; NSR-*:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; NSV-*:NONSTOP_KERNEL:*:*) echo nsv-tandem-nsk"$UNAME_RELEASE" exit ;; NSX-*:NONSTOP_KERNEL:*:*) echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac echo "$0: unable to guess system type" >&2 case "$UNAME_MACHINE:$UNAME_SYSTEM" in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&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` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF exit 1 # Local variables: # eval: (add-hook 'write-file-functions 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nip2-8.7.1/nip2.spec.in0000644000175000017500000001100513351443023011444 00000000000000Name: @PACKAGE@ Version: @VERSION@ Release: 1%{?dist} Summary: Interactive tool for working with large images Group: Applications/Multimedia License: GPLv2+ URL: https://github.com/jcupitt/nip2 Source0: https://github.com/jcupitt/nip2/releases BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: vips-devel = %{version} BuildRequires: gtk2-devel shared-mime-info gnome-icon-theme BuildRequires: flex bison intltool fftw-devel libxml2-devel gettext BuildRequires: desktop-file-utils #Requires: # description taken from Debian package %description nip2 is a graphical front end to the VIPS package. With nip2, rather than directly editing images, you build relationships between objects in a spreadsheet-like fashion. When you make a change somewhere, nip2 recalculates the objects affected by that change. Since it is demand-driven this update is very fast, even for very, very large images. nip2 is very good at creating pipelines of image manipulation operations. It is not very good for image editing tasks like touching up photographs. For that, a tool like the GIMP should be used instead. %prep %setup -q %build %configure make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT # delete doc (we will get it later with %doc) rm -rf $RPM_BUILD_ROOT%{_datadir}/doc/nip2 # malkovich?? rm -rf $RPM_BUILD_ROOT%{_datadir}/locale/malkovich # the nip2 post install hook seems to run update-mime-database, but we # need to run it in post rm -rf $RPM_BUILD_ROOT%{_datadir}/mime mkdir -p $RPM_BUILD_ROOT%{_datadir}/mime/packages cp -a nip2.xml $RPM_BUILD_ROOT%{_datadir}/mime/packages # same with desktop file rm -rf $RPM_BUILD_ROOT%{_datadir}/applications # locale stuff %find_lang nip2 # icon install -d $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/128x128/apps cp -a share/nip2/data/vips-128.png \ $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/128x128/apps/nip2.png # desktop file desktop-file-install --vendor fedora \ --dir $RPM_BUILD_ROOT%{_datadir}/applications \ nip2.desktop %post # scriptlet for icons touch --no-create %{_datadir}/icons/hicolor || : if [ -x %{_bindir}/gtk-update-icon-cache ]; then %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || : fi # scriptlet for desktop database update-desktop-database &> /dev/null || : # MIME update-mime-database %{_datadir}/mime &> /dev/null || : %postun # scriptlet for icons touch --no-create %{_datadir}/icons/hicolor || : if [ -x %{_bindir}/gtk-update-icon-cache ]; then %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || : fi # scriptlet for desktop database update-desktop-database &> /dev/null || : # MIME update-mime-database %{_datadir}/mime &> /dev/null || : %clean rm -rf $RPM_BUILD_ROOT %files -f nip2.lang %defattr(-,root,root,-) %doc doc/html doc/pdf AUTHORS ChangeLog COPYING NEWS THANKS TODO %{_bindir}/nip2 %{_bindir}/run-nip2.sh %{_datadir}/nip2 %{_mandir}/man1/nip2.1.gz %{_datadir}/icons/hicolor/*/apps/* %{_datadir}/applications/* %{_datadir}/mime/packages/nip2.xml %changelog * Sat Jun 10 2008 John Cupitt - 8.7.0 - Update URLs * Sat Jul 19 2008 Jesper Friis - 7.15.0-1 - Added this spec file from the Fedora source rpm * Sat Mar 15 2008 Adam Goode - 7.14.1-1 - New release * Mon Mar 10 2008 Adam Goode - 7.14.0-1 - New release * Sat Feb 9 2008 Adam Goode - 7.12.5-4 - GCC 4.3 mass rebuild * Wed Dec 5 2007 Adam Goode - 7.12.5-3 - Fix desktop file validation * Tue Oct 16 2007 Adam Goode - 7.12.5-2 - Rebuild for OpenEXR soname change * Fri Sep 21 2007 Adam Goode - 7.12.5-1 - New upstream release * Thu Aug 16 2007 Adam Goode - 7.12.4-1 - New upstream release - Update License tag * Wed Jul 25 2007 Adam Goode - 7.12.2-1 - New stable release 7.12 * Sat May 5 2007 Adam Goode - 7.12.0-1 - New upstream release - Update desktop file - Remove X-Fedora category * Thu Aug 31 2006 Adam Goode - 7.10.21-1 - New upstream release * Sun Aug 13 2006 Adam Goode - 7.10.20-2 - Fix location of documentation in program so help works - Semicolon-terminate Category entry in desktop file * Sat Jul 22 2006 Adam Goode - 7.10.20-1 - New upstream release - Updated for FC5 * Thu Jan 30 2003 John Cupitt 7.8.6-1 - first stab at an rpm package for nip nip2-8.7.1/ylwrap0000755000175000017500000001531313351443337010575 00000000000000#! /bin/sh # ylwrap - wrapper for lex/yacc invocations. scriptversion=2016-01-11.22; # UTC # Copyright (C) 1996-2017 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 # . get_dirname () { case $1 in */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';; # Otherwise, we want the empty string (not "."). esac } # guard FILE # ---------- # The CPP macro used to guard inclusion of FILE. guard () { printf '%s\n' "$1" \ | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \ -e 's/__*/_/g' } # quote_for_sed [STRING] # ---------------------- # Return STRING (or stdin) quoted to be used as a sed pattern. quote_for_sed () { case $# in 0) cat;; 1) printf '%s\n' "$1";; esac \ | sed -e 's|[][\\.*]|\\&|g' } case "$1" in '') echo "$0: No files given. Try '$0 --help' for more information." 1>&2 exit 1 ;; --basedir) basedir=$2 shift 2 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . EOF exit $? ;; -v|--v*) echo "ylwrap $scriptversion" exit $? ;; esac # The input. input=$1 shift # We'll later need for a correct munging of "#line" directives. input_sub_rx=`get_dirname "$input" | quote_for_sed` case $input in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. input=`pwd`/$input ;; esac input_rx=`get_dirname "$input" | quote_for_sed` # Since DOS filename conventions don't allow two dots, # the DOS version of Bison writes out y_tab.c instead of y.tab.c # and y_tab.h instead of y.tab.h. Test to see if this is the case. y_tab_nodot=false if test -f y_tab.c || test -f y_tab.h; then y_tab_nodot=true fi # The parser itself, the first file, is the destination of the .y.c # rule in the Makefile. parser=$1 # A sed program to s/FROM/TO/g for all the FROM/TO so that, for # instance, we rename #include "y.tab.h" into #include "parse.h" # during the conversion from y.tab.c to parse.c. sed_fix_filenames= # Also rename header guards, as Bison 2.7 for instance uses its header # guard in its implementation file. sed_fix_header_guards= while test $# -ne 0; do if test x"$1" = x"--"; then shift break fi from=$1 # Handle y_tab.c and y_tab.h output by DOS if $y_tab_nodot; then case $from in "y.tab.c") from=y_tab.c;; "y.tab.h") from=y_tab.h;; esac fi shift to=$1 shift sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;" sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;" done # The program to run. prog=$1 shift # Make any relative path in $prog absolute. case $prog in [\\/]* | ?:[\\/]*) ;; *[\\/]*) prog=`pwd`/$prog ;; esac dirname=ylwrap$$ do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (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 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then for from in * do to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"` if test -f "$from"; then # If $2 is an absolute path name, then just use that, # otherwise prepend '../'. case $to in [\\/]* | ?:[\\/]*) target=$to;; *) target=../$to;; esac # Do not overwrite unchanged header files to avoid useless # recompilations. Always update the parser itself: it is the # destination of the .y.c rule in the Makefile. Divert the # output of all other files to a temporary file so we can # compare them to existing versions. if test $from != $parser; then realtarget=$target target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'` fi # Munge "#line" or "#" directives. Don't let the resulting # debug information point at an absolute srcdir. Use the real # output file name, not yy.lex.c for instance. Adjust the # include guards too. sed -e "/^#/!b" \ -e "s|$input_rx|$input_sub_rx|" \ -e "$sed_fix_filenames" \ -e "$sed_fix_header_guards" \ "$from" >"$target" || ret=$? # Check whether files must be updated. if test "$from" != "$parser"; then if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then echo "$to is unchanged" rm -f "$target" else echo "updating $to" mv -f "$target" "$realtarget" fi fi else # A missing file is only an error for the parser. This is a # blatant hack to let us support using "yacc -d". If -d is not # specified, don't fail when the header file is "missing". if test "$from" = "$parser"; then ret=1 fi fi done fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: nip2-8.7.1/nip2.desktop.in0000644000175000017500000000043313351443023012166 00000000000000[Desktop Entry] Name=@PACKAGE@ Comment=Image manipulation program based on VIPS Comment[it]=Programma per la manipolazione di immagini basato su VIPS Exec=nip2 %F Icon=nip2 Terminal=false Type=Application Categories=Graphics;RasterGraphics; StartupNotify=true MimeType=image/x-vips; nip2-8.7.1/man/0000755000175000017500000000000013417043452010156 500000000000000nip2-8.7.1/man/man1/0000755000175000017500000000000013417043452011012 500000000000000nip2-8.7.1/man/man1/nip2.10000644000175000017500000000624513351443023011666 00000000000000.TH NIP2 1 "Oct 4 2004" .SH NAME nip2 \- image processing with the VIPS library .SH SYNOPSIS .B nip2 [filename1 ...] .br .B nip2 -s filename [arg1 ...] .br .B nip2 -e expression [arg1 ...] .SH DESCRIPTION .B nip2 (for New Image Processing) is a tool for manipulating images using the VIPS image processing library. There are three principal modes: .B nip2 [filename1 ...] .br start in GUI mode, loading the named files .B nip2 -e expression [arg1 ...] .br .B nip2 --expression=EXPRESSION [arg1 ...] .br start in no-GUI mode; set main = expression, set list argv to ["filename", "arg1", "arg2", ...], set argc to length of list; print the value of symbol "main" to stdout; exit .B nip2 -s filename [arg1 ...] .br .B nip2 --script=FILENAME [arg1 ...] .br start in no-GUI mode; read in filename as a set of definitions, set list argv to ["filename", "arg1", "arg2", ...], set argc to length of list; print the value of symbol "main" to stdout; exit; useful for running nip2 as an interpreter on unix You can use .B -o to direct output to a file rather than stdout. .B -o filename .br .B --output=FILENAME .br the value of main is written to the named file. If main is a list, the filename is incremented between objects. You can use the suffix to specify the format and options to write in Other options provide finer control over startup and shutdown. If you need to do something strange, don't use -e/-s, use these in combination. .B -b .br .B --batch .br batch (ie. non-GUI) mode .B -m .br .B --no-load-menus .br don't load menus, for faster startup .B -a .br .B --no-load-args .br don't load extra command-line arguments .B -w .br .B --stdin-ws .br load stdin as a workspace .B -d .br .B --stdin-def .br load stdin as a set of definitions .B -p .br .B --print-main .br print the value of main on exit. nip2 will check for a top-level symbol called main, and also check each workspace for a main Finally some other options are useful for debugging, timing and for generating strings for internationalisation. .B -V .br .B --verbose .br produce verbose error messages: handy for debugging in batch mode .B -i .br .B --i18n .br output strings from .def files for internationalisation .B -v .br .B --version .br print version information .B -c .br .B --benchmark .br benchmark: no GUI, just start up and shut down .B -t .br .B --time-save .br time saves: after every image save a popup tells you the time the save took in seconds .B -T .br .B --test .br test: start up (including any arg processing), test for any errors, and exit with an error code if any occured. Useful for running automated tests. .B -x PREFIX .br .B --prefix=PREFIX .br set install prefix: start up as if nip2 had been installed to PREFIX. Useful for running automated tests without installing the thing. .SH EXAMPLES nip2 fred.jpg Start nip2, loading fred.jpg. nip2 -e "2 + 2" Prints 4 to stdout. nip2 -e "99 + Image_file argv?1" -o result.png fred.jpg Load argv1 (fred.jpg), add 99, output to result.png. nip2 -e "Matrix [[1,2],[4,5]] ** -1" -o poop.mat Invert the 2x2 matrix and write the result to poop.mat. .SH COPYRIGHT 2008 (c) Imperial College, London nip2-8.7.1/man/man1/Makefile.am0000644000175000017500000000005413351443023012760 00000000000000man_MANS = nip2.1 EXTRA_DIST = ${man_MANS} nip2-8.7.1/man/man1/Makefile.in0000644000175000017500000004015113417043241012774 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = man/man1 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 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; }; \ } man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" NROFF = nroff MANS = $(man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ man_MANS = nip2.1 EXTRA_DIST = ${man_MANS} all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign man/man1/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign man/man1/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs 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) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man1dir)"; 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-dvi: install-dvi-am install-dvi-am: install-exec-am: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-man \ uninstall-man1 .PRECIOUS: Makefile # 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: nip2-8.7.1/man/Makefile.am0000644000175000017500000000001713351443023012123 00000000000000SUBDIRS = man1 nip2-8.7.1/man/Makefile.in0000644000175000017500000004641513417043241012151 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = man ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ SUBDIRS = man1 all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign man/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign man/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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: 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-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # 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: nip2-8.7.1/THANKS0000644000175000017500000000025213351443023010230 00000000000000nip THANKS file nip is a rewrite of ip, so see the THANKS file for that package. We've had very helpful funding from the European Commission and from Hewlett-Packard. nip2-8.7.1/m4/0000755000175000017500000000000013417042641007722 500000000000000nip2-8.7.1/m4/codeset.m40000644000175000017500000000151213417042632011531 00000000000000# codeset.m4 serial 5 (gettext-0.18.2) dnl Copyright (C) 2000-2002, 2006, 2008-2014, 2016 Free Software Foundation, dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_LANGINFO_CODESET], [ AC_CACHE_CHECK([for nl_langinfo and CODESET], [am_cv_langinfo_codeset], [AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [[char* cs = nl_langinfo(CODESET); return !cs;]])], [am_cv_langinfo_codeset=yes], [am_cv_langinfo_codeset=no]) ]) if test $am_cv_langinfo_codeset = yes; then AC_DEFINE([HAVE_LANGINFO_CODESET], [1], [Define if you have and nl_langinfo(CODESET).]) fi ]) nip2-8.7.1/m4/gettext.m40000644000175000017500000003676313417042632011607 00000000000000# gettext.m4 serial 68 (gettext-0.19.8) dnl Copyright (C) 1995-2014, 2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2006, 2008-2010. dnl Macro to add for using GNU gettext. dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The dnl default (if it is not specified or empty) is 'no-libtool'. dnl INTLSYMBOL should be 'external' for packages with no intl directory, dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. dnl If INTLSYMBOL is 'use-libtool', then a libtool library dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, dnl depending on --{enable,disable}-{shared,static} and on the presence of dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library dnl $(top_builddir)/intl/libintl.a will be created. dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext dnl implementations (in libc or libintl) without the ngettext() function dnl will be ignored. If NEEDSYMBOL is specified and is dnl 'need-formatstring-macros', then GNU gettext implementations that don't dnl support the ISO C 99 formatstring macros will be ignored. dnl INTLDIR is used to find the intl libraries. If empty, dnl the value '$(top_builddir)/intl/' is used. dnl dnl The result of the configuration is one of three cases: dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled dnl and used. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 2) GNU gettext has been found in the system's C library. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 3) No internationalization, always use English msgid. dnl Catalog format: none dnl Catalog extension: none dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. dnl The use of .gmo is historical (it was needed to avoid overwriting the dnl GNU format catalogs when building on a platform with an X/Open gettext), dnl but we keep it in order not to force irrelevant filename changes on the dnl maintainers. dnl AC_DEFUN([AM_GNU_GETTEXT], [ dnl Argument checking. ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT ])])])])]) ifelse(ifelse([$1], [], [old])[]ifelse([$1], [no-libtool], [old]), [old], [AC_DIAGNOSE([obsolete], [Use of AM_GNU_GETTEXT without [external] argument is deprecated.])]) ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT ])])])]) define([gt_included_intl], ifelse([$1], [external], ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), [yes])) define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) gt_NEEDS_INIT AM_GNU_GETTEXT_NEED([$2]) AC_REQUIRE([AM_PO_SUBDIRS])dnl ifelse(gt_included_intl, yes, [ AC_REQUIRE([AM_INTL_SUBDIR])dnl ]) dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Sometimes libintl requires libiconv, so first search for libiconv. dnl Ideally we would do this search only after the dnl if test "$USE_NLS" = "yes"; then dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT dnl the configure script would need to contain the same shell code dnl again, outside any 'if'. There are two solutions: dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not dnl documented, we avoid it. ifelse(gt_included_intl, yes, , [ AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) ]) dnl Sometimes, on Mac OS X, libintl requires linking with CoreFoundation. gt_INTL_MACOSX dnl Set USE_NLS. AC_REQUIRE([AM_NLS]) ifelse(gt_included_intl, yes, [ BUILD_INCLUDED_LIBINTL=no USE_INCLUDED_LIBINTL=no ]) LIBINTL= LTLIBINTL= POSUB= dnl Add a version number to the cache macros. case " $gt_needs " in *" need-formatstring-macros "*) gt_api_version=3 ;; *" need-ngettext "*) gt_api_version=2 ;; *) gt_api_version=1 ;; esac gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" dnl If we use NLS figure out what method if test "$USE_NLS" = "yes"; then gt_use_preinstalled_gnugettext=no ifelse(gt_included_intl, yes, [ AC_MSG_CHECKING([whether included gettext is requested]) AC_ARG_WITH([included-gettext], [ --with-included-gettext use the GNU gettext library included here], nls_cv_force_use_gnu_gettext=$withval, nls_cv_force_use_gnu_gettext=no) AC_MSG_RESULT([$nls_cv_force_use_gnu_gettext]) nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" if test "$nls_cv_force_use_gnu_gettext" != "yes"; then ]) dnl User does not insist on using GNU NLS library. Figure out what dnl to use. If GNU gettext is available we use this. Else we have dnl to fall back to GNU NLS library. if test $gt_api_version -ge 3; then gt_revision_test_code=' #ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ' else gt_revision_test_code= fi if test $gt_api_version -ge 2; then gt_expression_test_code=' + * ngettext ("", "", 0)' else gt_expression_test_code= fi AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], [AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings; #define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_domain_bindings) #else #define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 #endif $gt_revision_test_code ]], [[ bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ]])], [eval "$gt_func_gnugettext_libc=yes"], [eval "$gt_func_gnugettext_libc=no"])]) if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then dnl Sometimes libintl requires libiconv, so first search for libiconv. ifelse(gt_included_intl, yes, , [ AM_ICONV_LINK ]) dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) dnl because that would add "-liconv" to LIBINTL and LTLIBINTL dnl even if libiconv doesn't exist. AC_LIB_LINKFLAGS_BODY([intl]) AC_CACHE_CHECK([for GNU gettext in libintl], [$gt_func_gnugettext_libintl], [gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" dnl Now see whether libintl exists and does not depend on libiconv. AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); #define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) #else #define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 #endif $gt_revision_test_code ]], [[ bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ]])], [eval "$gt_func_gnugettext_libintl=yes"], [eval "$gt_func_gnugettext_libintl=no"]) dnl Now see whether libintl exists and depends on libiconv. if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then LIBS="$LIBS $LIBICONV" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); #define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) #else #define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 #endif $gt_revision_test_code ]], [[ bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ]])], [LIBINTL="$LIBINTL $LIBICONV" LTLIBINTL="$LTLIBINTL $LTLIBICONV" eval "$gt_func_gnugettext_libintl=yes" ]) fi CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS"]) fi dnl If an already present or preinstalled GNU gettext() is found, dnl use it. But if this macro is used in GNU gettext, and GNU dnl gettext is already preinstalled in libintl, we update this dnl libintl. (Cf. the install rule in intl/Makefile.in.) if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ && test "$PACKAGE" != gettext-runtime \ && test "$PACKAGE" != gettext-tools; }; then gt_use_preinstalled_gnugettext=yes else dnl Reset the values set by searching for libintl. LIBINTL= LTLIBINTL= INCINTL= fi ifelse(gt_included_intl, yes, [ if test "$gt_use_preinstalled_gnugettext" != "yes"; then dnl GNU gettext is not found in the C library. dnl Fall back on included GNU gettext library. nls_cv_use_gnu_gettext=yes fi fi if test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions used to generate GNU NLS library. BUILD_INCLUDED_LIBINTL=yes USE_INCLUDED_LIBINTL=yes LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` fi CATOBJEXT= if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions to use GNU gettext tools. CATOBJEXT=.gmo fi ]) if test -n "$INTL_MACOSX_LIBS"; then if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Some extra flags are needed during linking. LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" fi fi if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then AC_DEFINE([ENABLE_NLS], [1], [Define to 1 if translation of program messages to the user's native language is requested.]) else USE_NLS=no fi fi AC_MSG_CHECKING([whether to use NLS]) AC_MSG_RESULT([$USE_NLS]) if test "$USE_NLS" = "yes"; then AC_MSG_CHECKING([where the gettext function comes from]) if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then gt_source="external libintl" else gt_source="libc" fi else gt_source="included intl directory" fi AC_MSG_RESULT([$gt_source]) fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then AC_MSG_CHECKING([how to link with libintl]) AC_MSG_RESULT([$LIBINTL]) AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) fi dnl For backward compatibility. Some packages may be using this. AC_DEFINE([HAVE_GETTEXT], [1], [Define if the GNU gettext() function is already present or preinstalled.]) AC_DEFINE([HAVE_DCGETTEXT], [1], [Define if the GNU dcgettext() function is already present or preinstalled.]) fi dnl We need to process the po/ directory. POSUB=po fi ifelse(gt_included_intl, yes, [ dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL dnl to 'yes' because some of the testsuite requires it. if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then BUILD_INCLUDED_LIBINTL=yes fi dnl Make all variables we use known to autoconf. AC_SUBST([BUILD_INCLUDED_LIBINTL]) AC_SUBST([USE_INCLUDED_LIBINTL]) AC_SUBST([CATOBJEXT]) dnl For backward compatibility. Some configure.ins may be using this. nls_cv_header_intl= nls_cv_header_libgt= dnl For backward compatibility. Some Makefiles may be using this. DATADIRNAME=share AC_SUBST([DATADIRNAME]) dnl For backward compatibility. Some Makefiles may be using this. INSTOBJEXT=.mo AC_SUBST([INSTOBJEXT]) dnl For backward compatibility. Some Makefiles may be using this. GENCAT=gencat AC_SUBST([GENCAT]) dnl For backward compatibility. Some Makefiles may be using this. INTLOBJS= if test "$USE_INCLUDED_LIBINTL" = yes; then INTLOBJS="\$(GETTOBJS)" fi AC_SUBST([INTLOBJS]) dnl Enable libtool support if the surrounding package wishes it. INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX]) ]) dnl For backward compatibility. Some Makefiles may be using this. INTLLIBS="$LIBINTL" AC_SUBST([INTLLIBS]) dnl Make all documented variables known to autoconf. AC_SUBST([LIBINTL]) AC_SUBST([LTLIBINTL]) AC_SUBST([POSUB]) ]) dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. m4_define([gt_NEEDS_INIT], [ m4_divert_text([DEFAULTS], [gt_needs=]) m4_define([gt_NEEDS_INIT], []) ]) dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) AC_DEFUN([AM_GNU_GETTEXT_NEED], [ m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) ]) dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) dnl Usage: AM_GNU_GETTEXT_REQUIRE_VERSION([gettext-version]) AC_DEFUN([AM_GNU_GETTEXT_REQUIRE_VERSION], []) nip2-8.7.1/m4/lcmessage.m40000644000175000017500000000252513417042632012053 00000000000000# lcmessage.m4 serial 7 (gettext-0.18.2) dnl Copyright (C) 1995-2002, 2004-2005, 2008-2014, 2016 Free Software dnl Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995. # Check whether LC_MESSAGES is available in . AC_DEFUN([gt_LC_MESSAGES], [ AC_CACHE_CHECK([for LC_MESSAGES], [gt_cv_val_LC_MESSAGES], [AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [[return LC_MESSAGES]])], [gt_cv_val_LC_MESSAGES=yes], [gt_cv_val_LC_MESSAGES=no])]) if test $gt_cv_val_LC_MESSAGES = yes; then AC_DEFINE([HAVE_LC_MESSAGES], [1], [Define if your file defines LC_MESSAGES.]) fi ]) nip2-8.7.1/m4/glibc21.m40000644000175000017500000000161313417042632011330 00000000000000# glibc21.m4 serial 5 dnl Copyright (C) 2000-2002, 2004, 2008, 2010-2016 Free Software Foundation, dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # Test for the GNU C Library, version 2.1 or newer, or uClibc. # From Bruno Haible. AC_DEFUN([gl_GLIBC21], [ AC_CACHE_CHECK([whether we are using the GNU C Library >= 2.1 or uClibc], [ac_cv_gnu_library_2_1], [AC_EGREP_CPP([Lucky], [ #include #ifdef __GNU_LIBRARY__ #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) Lucky GNU user #endif #endif #ifdef __UCLIBC__ Lucky user #endif ], [ac_cv_gnu_library_2_1=yes], [ac_cv_gnu_library_2_1=no]) ] ) AC_SUBST([GLIBC21]) GLIBC21="$ac_cv_gnu_library_2_1" ] ) nip2-8.7.1/m4/ltsugar.m40000644000175000017500000001044013417042641011564 00000000000000# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # 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. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59, which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) nip2-8.7.1/m4/libtool.m40000644000175000017500000112617713417042641011567 00000000000000# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # 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. m4_define([_LT_COPYING], [dnl # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can 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 of of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . ]) # serial 58 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_PREPARE_CC_BASENAME # ----------------------- m4_defun([_LT_PREPARE_CC_BASENAME], [ # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in @S|@*""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } ])# _LT_PREPARE_CC_BASENAME # _LT_CC_BASENAME(CC) # ------------------- # It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, # but that macro is also expanded into generated libtool script, which # arranges for $SED and $ECHO to be set by different means. m4_defun([_LT_CC_BASENAME], [m4_require([_LT_PREPARE_CC_BASENAME])dnl AC_REQUIRE([_LT_DECL_SED])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl func_cc_basename $1 cc_basename=$func_cc_basename_result ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl m4_require([_LT_CMD_TRUNCATE])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from 'configure', and 'config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # 'config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain=$ac_aux_dir/ltmain.sh ])# _LT_PROG_LTMAIN ## ------------------------------------- ## ## Accumulate code for creating libtool. ## ## ------------------------------------- ## # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the 'libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) ## ------------------------ ## ## FIXME: Eliminate VARNAME ## ## ------------------------ ## # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to 'config.status' so that its # declaration there will have the same value as in 'configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags='_LT_TAGS'dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into 'config.status', and then the shell code to quote escape them in # for loops in 'config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # '#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test 0 = "$lt_write_fail" && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ '$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test 0 != $[#] do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try '$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try '$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test yes = "$silent" && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 _LT_COPYING _LT_LIBTOOL_TAGS # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE _LT_PREPARE_MUNGE_PATH_LIST _LT_PREPARE_CC_BASENAME # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS=$save_LDFLAGS ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[[012]][[,.]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test yes = "$lt_cv_ld_force_load"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], [ if test yes != "$lt_cv_apple_cc_single_mod"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script that will find a shell with a builtin # printf (that we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case $ECHO in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot if not specified).])], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([$with_sysroot]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and where our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test yes = "[$]$2"; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS ]) if test yes = "[$]$2"; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n "$lt_cv_sys_max_cmd_len"; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes = "$cross_compiling"; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen=shl_load], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen=dlopen], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) ]) ]) ]) ]) ]) ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links=nottested if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test no = "$hard_links"; then AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", [Define to the sub-directory where libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then # We can hardcode non-existent directories. if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_PREPARE_MUNGE_PATH_LIST # --------------------------- # Make sure func_munge_path_list() is defined correctly. m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], [[# func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x@S|@2 in x) ;; *:) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" ;; x:*) eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; *::*) eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" ;; *) eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" ;; esac } ]])# _LT_PREPARE_PATH_LIST # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown AC_ARG_VAR([LT_SYS_LIBRARY_PATH], [User-defined run-time library search path.]) case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a[(]lib.so.V[)]' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], [Detected run-time system search path for libraries]) _LT_DECL([], [configure_time_lt_sys_library_path], [2], [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program that can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$1"; then lt_cv_path_MAGIC_CMD=$ac_dir/"$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac]) MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program that can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], [if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi]) rm -f conftest.i conftest2.i conftest.out]) ])# _LT_PATH_DD # _LT_CMD_TRUNCATE # ---------------- # find command to truncate a binary pipe m4_defun([_LT_CMD_TRUNCATE], [m4_require([_LT_PATH_DD]) AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], [printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) _LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], [Command to truncate a binary pipe]) ])# _LT_CMD_TRUNCATE # _LT_CHECK_MAGIC_METHOD # ---------------------- # how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_MAGIC_METHOD], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) AC_CACHE_CHECK([how to recognize dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[[4-9]]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi]) if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # _LT_DLL_DEF_P([FILE]) # --------------------- # True iff FILE is a Windows DLL '.def' file. # Keep in sync with func_dll_def_p in the libtool script AC_DEFUN([_LT_DLL_DEF_P], [dnl test DEF = "`$SED -n dnl -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl -e q dnl Only consider the first "real" line $1`" dnl ])# _LT_DLL_DEF_P # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM=-lm) ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test yes = "$GCC"; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], [Transform the output of nm into a list of symbols to manually relocate]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([nm_interface], [lt_cv_nm_interface], [1], [The name lister interface]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' if test ia64 != "$host_cpu"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64, which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test yes = "$GCC"; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) case $host_os in os2*) _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS=$save_LDFLAGS]) if test yes = "$lt_cv_irix_exported_symbol"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi _LT_TAGVAR(link_all_deplibs, $1)=no else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; osf3*) if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test yes,yes = "$GCC,$enable_shared"; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC=$CC AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report what library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC=$lt_save_CC ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to 'libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test no != "$CXX" && ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || (test g++ != "$CXX"))); then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_caught_CXX_error"; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test yes = "$GXX"; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test yes = "$GXX"; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no ;; esac if test yes = "$GXX"; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag=$shared_flag' $wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. # The "-G" linker flag allows undefined symbols. _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ func_to_tool_file "$lt_outputfile"~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported shrext_cmds=.dll _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test no = "$with_gnu_ld"; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no _LT_TAGVAR(GCC, $1)=$GXX _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test yes != "$_lt_caught_CXX_error" AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case @S|@2 in .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case $prev$p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test x-L = "$p" || test x-R = "$p"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test no = "$pre_test_object_deps_done"; then case $prev in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test no = "$pre_test_object_deps_done"; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)=$p else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)=$p else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test no = "$F77"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_F77"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$G77 _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_F77" AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test no = "$FC"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test yes != "$_lt_disable_FC"; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu _LT_TAGVAR(LD, $1)=$LD ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test yes != "$_lt_disable_FC" AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)=$LD _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to 'libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code=$lt_simple_compile_test_code # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ ############################################################ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # ############################################################ m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f "$lt_ac_sed" && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test 10 -lt "$lt_ac_count" && break lt_ac_count=`expr $lt_ac_count + 1` if test "$lt_ac_count" -gt "$lt_ac_max"; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine what file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS nip2-8.7.1/m4/iconv.m40000644000175000017500000002207213417042632011225 00000000000000# iconv.m4 serial 19 (gettext-0.18.2) dnl Copyright (C) 2000-2002, 2007-2014, 2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);]])], [am_cv_func_iconv=yes]) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);]])], [am_cv_lib_iconv=yes] [am_cv_func_iconv=yes]) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11, dnl Solaris 10. am_save_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi am_cv_func_iconv_works=no for ac_iconv_const in '' 'const'; do AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[ #include #include #ifndef ICONV_CONST # define ICONV_CONST $ac_iconv_const #endif ]], [[int result = 0; /* Test against AIX 5.1 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 1; iconv_close (cd_utf8_to_88591); } } /* Test against Solaris 10 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); if (cd_ascii_to_88591 != (iconv_t)(-1)) { static ICONV_CONST char input[] = "\263"; char buf[10]; ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_ascii_to_88591, &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 2; iconv_close (cd_ascii_to_88591); } } /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ { iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static ICONV_CONST char input[] = "\304"; static char buf[2] = { (char)0xDE, (char)0xAD }; ICONV_CONST char *inptr = input; size_t inbytesleft = 1; char *outptr = buf; size_t outbytesleft = 1; size_t res = iconv (cd_88591_to_utf8, &inptr, &inbytesleft, &outptr, &outbytesleft); if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) result |= 4; iconv_close (cd_88591_to_utf8); } } #if 0 /* This bug could be worked around by the caller. */ /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ { iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, &inptr, &inbytesleft, &outptr, &outbytesleft); if ((int)res > 0) result |= 8; iconv_close (cd_88591_to_utf8); } } #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ if (/* Try standardized names. */ iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) /* Try IRIX, OSF/1 names. */ && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) /* Try AIX names. */ && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) /* Try HP-UX names. */ && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) result |= 16; return result; ]])], [am_cv_func_iconv_works=yes], , [case "$host_os" in aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; *) am_cv_func_iconv_works="guessing yes" ;; esac]) test "$am_cv_func_iconv_works" = no || break done LIBS="$am_save_LIBS" ]) case "$am_cv_func_iconv_works" in *no) am_func_iconv=no am_cv_lib_iconv=no ;; *) am_func_iconv=yes ;; esac else am_func_iconv=no am_cv_lib_iconv=no fi if test "$am_func_iconv" = yes; then AC_DEFINE([HAVE_ICONV], [1], [Define if you have the iconv() function and it works.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST([LIBICONV]) AC_SUBST([LTLIBICONV]) ]) dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to dnl avoid warnings like dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". dnl This is tricky because of the way 'aclocal' is implemented: dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. dnl Otherwise aclocal's initial scan pass would miss the macro definition. dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. dnl Otherwise aclocal would emit many "Use of uninitialized value $1" dnl warnings. m4_define([gl_iconv_AC_DEFUN], m4_version_prereq([2.64], [[AC_DEFUN_ONCE( [$1], [$2])]], [m4_ifdef([gl_00GNULIB], [[AC_DEFUN_ONCE( [$1], [$2])]], [[AC_DEFUN( [$1], [$2])]])])) gl_iconv_AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL([am_cv_proto_iconv], [ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ]], [[]])], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"]) am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([ $am_cv_proto_iconv]) AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], [Define as const if the declaration of iconv() needs const.]) dnl Also substitute ICONV_CONST in the gnulib generated . m4_ifdef([gl_ICONV_H_DEFAULTS], [AC_REQUIRE([gl_ICONV_H_DEFAULTS]) if test -n "$am_cv_proto_iconv_arg1"; then ICONV_CONST="const" fi ]) fi ]) nip2-8.7.1/m4/lt~obsolete.m40000644000175000017500000001377413417042641012472 00000000000000# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software # Foundation, Inc. # Written by Scott James Remnant, 2004. # # 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. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) nip2-8.7.1/m4/ltoptions.m40000644000175000017500000003426213417042641012146 00000000000000# Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software # Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # 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. # serial 8 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option '$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl 'shared' nor 'disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], [_LT_WITH_AIX_SONAME([aix])]) ]) ])# _LT_SET_OPTIONS ## --------------------------------- ## ## Macros to handle LT_INIT options. ## ## --------------------------------- ## # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the 'shared' and # 'disable-shared' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the 'static' and # 'disable-static' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the 'fast-install' # and 'disable-fast-install' LT_INIT options. # DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_AIX_SONAME([DEFAULT]) # ---------------------------------- # implement the --with-aix-soname flag, and support the `aix-soname=aix' # and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT # is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. m4_define([_LT_WITH_AIX_SONAME], [m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[[5-9]]*,yes) AC_MSG_CHECKING([which variant of shared library versioning to provide]) AC_ARG_WITH([aix-soname], [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], [case $withval in aix|svr4|both) ;; *) AC_MSG_ERROR([Unknown argument to --with-aix-soname]) ;; esac lt_cv_with_aix_soname=$with_aix_soname], [AC_CACHE_VAL([lt_cv_with_aix_soname], [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) with_aix_soname=$lt_cv_with_aix_soname]) AC_MSG_RESULT([$with_aix_soname]) if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac _LT_DECL([], [shared_archive_member_spec], [0], [Shared archive member basename, for filename based shared library versioning on AIX])dnl ])# _LT_WITH_AIX_SONAME LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the 'pic-only' and 'no-pic' # LT_INIT options. # MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac], [pic_mode=m4_default([$1], [default])]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the 'pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) ## ----------------- ## ## LTDL_INIT Options ## ## ----------------- ## m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) nip2-8.7.1/m4/progtest.m40000644000175000017500000000602413417042632011755 00000000000000# progtest.m4 serial 7 (gettext-0.18.2) dnl Copyright (C) 1996-2003, 2005, 2008-2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1996. AC_PREREQ([2.50]) # Search path for a program which passes the given test. dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) AC_DEFUN([AM_PATH_PROG_WITH_TEST], [ # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which # contains only /bin. Note that ksh looks also at the FPATH variable, # so we have to set that as well for the test. 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 # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "$2", so it can be a program name with args. set dummy $2; ac_word=[$]2 AC_MSG_CHECKING([for $ac_word]) AC_CACHE_VAL([ac_cv_path_$1], [case "[$]$1" in [[\\/]]* | ?:[[\\/]]*) ac_cv_path_$1="[$]$1" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in ifelse([$5], , $PATH, [$5]); do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD if [$3]; then ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" dnl If no 4th arg is given, leave the cache variable unset, dnl so AC_PATH_PROGS will keep looking. ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ])dnl ;; esac])dnl $1="$ac_cv_path_$1" if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then AC_MSG_RESULT([$][$1]) else AC_MSG_RESULT([no]) fi AC_SUBST([$1])dnl ]) nip2-8.7.1/m4/ltversion.m40000644000175000017500000000127313417042641012134 00000000000000# ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # 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. # @configure_input@ # serial 4179 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.6]) m4_define([LT_PACKAGE_REVISION], [2.4.6]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.6' macro_revision='2.4.6' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) nip2-8.7.1/ChangeLog0000644000175000017500000025116413414613217011105 00000000000000started 8.7.1 13/11/18 - fix uint status bar pixels >2**31 [Rob Erdmann] - fix crash on redhat [bgilbert] started 8.7.0 22/5/18 - added vips7compat.h include for libvips 8.7 - more output for -V to help debugging CLI mode - revised Text widget - added Canny - Sobel uses the new vips_sobel() operator - add mitchell kernel - add 8.6 compat started 8.6.1 1/5/18 - better enum display in header started 8.6.0 16/8/17 - add scRGB support - improve radiance support - add composite to alpha menu - add Image / Select / Fill - add combine mode to indexed histogram - better compat handling started 8.5.1 22/1/17 - fix a crash bug - make separate Image / Alpha menu, add Add, Extract, Drop started 8.5 24/1/17 - add max_slope to lhist - gaussnoise goes via vips8 now - add snake option to array join [Joe Padfield] - parse_float was broken for numbers starting "0." - add alpha section to Image / Band menu ... Flatten, Premultiply, Unpremultiply, Blend - add Entropy to hist menu started 8.4.1 25/9/16 - simplify nip2-icon.rc build, bgilbert started 8.4 - added Perlin and Worley menu items started 8.3.1 on 19/5/16 - disable debug by default, thanks Benjamin - configure changes to help win64 - improve middle-drag in ws and image view - be more careful about the name of the image file we remove on close - simpler system for positioning new columns - rename boostrap.sh as autogen to help snapcraft started 8.3.0 on 28/3/16 - move path search stuff into _convert from _magick - added autotrace menu item - resize now uses vips_resize() behind the scenes - added Kernel type for picking interpolators started 8.2.1 on 4/12/16 - tiny improvement to idle handling - added R2 to linreg and linregw - fixed vips_call for image array args - changed default unsharp settings to be less brutal and to ban -ve sharpness started 8.2 on 4/11/15 - version bump to match vips - fix icc_import with RGBA images - added mapim and Image / Transform / Map - added Filter / Coordinate Transform ... polar and rect in there started 8.0 on 3/5/15 - version bump for vips-8.0 release - fix a race in Makefile.am, thanks nieder - get rid of run-nip2.sh, mostly useless, thanks nieder started 7.42.1 started 30/12/14 - add fftw3 configure - fix gvc configure started 7.42.0 started 4/11/14 - removed the non-nip2 bits of the test suite, they are in vips now started 7.41.0 8/10/14 - remove greyc stuff started 7.40.5 17/9/14 - improve .desktop file - fix Lch -> Yxy conversion started 7.40.4 19/8/14 - swap the HP printer profile for a freer one - swap lena for a PD sample started 7.40.3 4/7/14 - fix compile with older libvipes, now goes back to at least 7.30 - fix more bash-isms to help freebsd - don't test IM by default, in case it's not installed - get graph display working again with latest libgvc started 7.40.2 30/6/14 - fix quoting in magick commands - auto-fallback to gm if no convert found - use libxml2 pretty-printer started 7.40.1 24/6/14 - update copyright date - larger max size for dialog text - fix popen()pclose() warnings on win started 7.40.0 23/6/14 - version bump started 7.39.0 28/1/14 - add optional libgsf dependency - added export-to-file to plotwindow - added graph_export_image - added .to_image to Plot - added .caption / .xcaption / .ycaption options to Plot - added caption / xcaption / ycaption options to Plot_object - added snibgo's much better ImageMagick menu items - added test_magick.ws to make check - added series_captions option to Plot_object - support imagevec as a vips_call argument - added system2 and system3 - added Magick.version detector - better image cache menu item - added hough_line and hough_circle - removed tear-off menus, gtk+ has deprecated them started 7.38.4 23/6/14 - fix memccpy() in tool.c, thanks khindenburg started 7.38.3 16/5/14 - fix tiny timeout error started 7.38.2 21/1/14 - fix a tiny mem leak started 7.38.1 20/1/14 - fix scRGB display started 7.38.0 18/1/14 - version bump started 7.36.6 9/1/14 - fix some clang warnings - add some brackets to find_colour-calib, seems to help clang builds with optimiser, strangely started 7.36.5 19/12/13 - add "merge into ws" item to rmb tab gutter menu - oops, progress feedback was accidentally disabled - error boxes were accidentally supressed started 7.36.4 18/10/13 - fix bootstrap warnings - use g_mkdir() - better load of workspaces with closed columns started 7.36.2 8/10/13 - add --profile option - fix + button on wsgv started 7.36.1 7/10/13 - better ^Q behaviour, thanks MvGulik started 7.36.0 3/10/13 started 7.35.0 9/8/13 - removed old thing to show API docs (thanks Benjamin) - measure now lets you pick the area to measure, and draws sample patches - new column now goes to right of current column, not alphabetically - detect doubleclick on ws tab label background - tabs can be locked - tabs have error indicators started 7.34.1 28/6/13 - fix build on older gtk, thanks Joe started 7.34.0 7/6/13 - version bump - drag col to far left to insert - fix compat warning text - fix prefs revert to default - reenable scroll-wheel slider change in paintbox and conversionview - insert new columns in alphabetical position started 7.33.0 14/3/13 - add tabs - get_* work on Groups - columns snap to a grid started 7.32.2 12/3/13 - add a test for seq mode started 7.32.1 7/3/13 - remove "fred" from dist - license updates, thanks Benjamin started 7.32.0 22/1/13 - added colour temperature to colour and colour to colour temperature - removed gtksheet, broken on windows, no future on anywhere - added histogram invert - much better Matrix / New items started 7.31 3/9/12 - don't show tooltips for toolkit menu items with submenus (thanks MvGulik) - better definition of foldr1 - better definition of to_group (thanks MvGulik) - better defintion of scan, renamed as scanl - don't clear def browser filter on text buffer ::changed in program window - update program window filter on cursor move started 7.30.2 24/12/12 - small fix for OS X ML started 7.30.1 7/8/12 - update rectangle select (thanks Joe) - group save was broken (thanks John VV) started 7.30.0 20/7/12 - update for new version started 7.29.0 20/6/12 - added skew and kurtosis - added Definition Browser to program window, shows stuff as you program - program window cleanups - Find calib is much faster and handles linear float input better - Find calib optionally leaves brightness untouched - Apply calib handles linear float input better - add a 7.28 compat area started 7.28.5, 8/5/12 - change keybinding for Delete to ctrl+bsp to work around a GTK bug - rewrite filenames on workspace load, file selection and file drag-drop started 7.28.4, 6/5/12 - added bigtiff save option started 7.28.3, 17/4/12 - up max size of user defs, lets you work with larger groups started 7.28.2, 10/4/12 - complex constant divided by real constant was wrong - more self-tests - disable the libvips operation cache, it doesn't know about invalidate and breaks various things started 7.28.1, 12/3/12 - oop, add Array to private Type decoder (thanks MvGulik) - new version of Draw / Scale (thanks Joe) started 7.28.0, 30/1/12 - bump for new stable version - better "make check" - disable asserts and cast checks in production builds - much faster draw_rect - remove background stipple from image display (helps win32) - Draw / Rect lets you adjust line thickness - added Draw / Scale (thanks Joe) - added VipsStats test (thanks Rebecca) started 7.27.0, 23/8/11 - bump for new cycle - add raw load/save test - test fits load/save - better image header display, now on right-click rowview menu - search image header - rmb popup menu on imageview windows - popup menu button widget - added "vips_call" builtin to call any vips8 operation - added Matrix / New / Series - added Matrix / Sort started 7.26.5, 31/12/11 - fix possible security thing in yyerror(), thanks Jay started 7.26.4, 14/9/11 - better error messages for print-main started 7.26.3, 15/8/11 - tidier cancel messages - disable dump.c debug started 7.26.2, 10/8/11 - update threading test for fixed benchmark - fix blocking in progress update (thanks M. v. Gulik) - search returns empty list for file not found rather than throwing an exception - magick_command tries to use $VIPSHOME/bin/convert.exe, if it exists - magick_command tries quotes filenames started 7.26.1, 28/7/11 - much better threading test, based on im_benchmarkn() started 7.26.0, 26/7/11 - version bump started 7.25.0, 7/1/11 - version bump - oop spelling - fix a crash with resizing dirty matrices - minor fix to vips_call error messages - more tests in "make check" - moved vips_cache and vips_call out of the vips_ namespace - added approx. option to blur/sharpen - added Matrix / New Circular / Square / Identity - removed the splash screen, all machines are fast enough now - added EXEEXT env var - better "bad superclass" error - changed order of args for Option_enum - added Option_list - added a simple Magick menu - better compat handling - added a 7.24 compat dir - removed the "already open for read" error on save, too annoying for the small amount of safety it gave you - test pfm load/save - also test cmyk jpeg/tif load/save - allow file modes in filenames, so "nip2 wtc_pyr.tif:2" works - show main window much sooner during workspace load and startup - better progress feedback - added Image / Select / Rectangle - added Image / Draw menu started 7.24.0, 30/11/10 - bump for 7.24 - fix build without graphviz - much faster colour atlas menu item - fix make check, again - fix debug everywhere - fix a va_args problem on Windows started 7.23.0, 2/8/10 - fix a crash in thumbnail preview with large images - doublelick while painting with a rect (eg. text) would crash (thanks M.v.Gulik) - drag multiple workspaces to the mainw could get stuck (thanks M.v.Gulik) - find-again before find would crash (thanks M.v.Gulik) - open multiple ws in file browser would crash - added filemodel_set_window_hint() and filemodel_get_window_hint() to help ^Q display popups on the right window - split vips_call.c to vips_call / vips_cache - added IM_TYPE_RW support to vips_call.c: you can call paintbox operations directly now - gtk_window_present() parents when we show children in iwindow.c - fix a crash with win32 and two PRESS on a window while in rect mode (thanks M.v.Gulik) - fix a crash with duplicate Colour (thanks M.v.Gulik) - fix an occasional crash with ^Q in imageview - added high-quality thumbnail option (thanks Martin) - set lib env var more carefully (thanks Jay) - configure tests for libgvc, the graphviz library - added "Workspace as graph" view option - better "segment" menu item - "value" menu item - rename stuff to avoid name clashes with cfitsio - "make check" runs twice, with and without vector stuff - better infobar behaviour - test_conv.ws tests convolution carefully - nib radius slider replaces the old 1-10 dropdown, nibs above radius 0 are anti-aliased - changes to help rhel5 - oop, could delete vips files accidentally - better file search started 7.22.2, 5/7/10 - show nthreads in space free tooltip - fix win32 button order, again - fix duplicate workspace - added ^Q, for quit nip2, to all windows - rename gtk_entry_*() to gtk_item_entry_*() in gtkitementry.c, thanks Adam started 7.22.1, 13/6/10 - relax tolerances in test_colour.ws, thanks Peter - improve region repaint during drag, thanks Ruven - test relational constants - test load / save in various file formats - test threading system - removed malkovich locale, oops started 7.22.0, 12/5/10 - version bump - gtksheet sizing changes, again - plot window destroy cleanup started 7.21.0, 8/12/09 - 7.16 ws load could fail (thanks Jim) - "make check" tests the example workspaces too - nip2-cli.c improvements (thanks Leo) - leak test improvements - set double-click time from the system - don't copy to file for paintbox, it makes dangling pointers if you use it in complex workspaces - thumbnail updates on paint actions, woo - rect and text tools have a working preview box - safer handling of missing exprs in formula - handle im_invalidate() in paintbox ourselves - much faster and smarter image window repaints, especially with the paintbox active - #CPUs in prefs defaults to zero, meaning autodetect - works without GtkInfoBar - better show/hide behaviour for paned - progress feedback for paintbox open started 7.20.5, 27/11/09 - fixed up GtkInfoBar support - oop, help was rather broken started 7.20.4, 26/11/09 - removed 'browse thumbnails' button from filesel - added 'preview' widget to file open - added some basic GtkInfoBar support started 7.20.3, 25/11/09 - argh, button order error in dialogs on win32 - updated help index - initial window size was too large started 7.20.2, 11/11/09 - make GRegex optional so we can work with older glibs - fix a crash with "-p" and Managedstring started 7.20.1, 11/11/09 - add "convf" operator - default number of CPUs bumped to 4 - plot.c can work with goffice-0.7.15 started 7.20.0, 9/11/09 - version bump - "make dist" fixes started 7.19.0 - remove deprecated use of GtkList in option edit ... needs replacing - dropped in new Joe defs (thanks Joe) - reverse dialog button order on win32 - fix memleak with IMAGEVEC args to VIPS - _check_all etc. no longer chain up, for a slight speed increase - fix crash with "" as LHS for various copy operations, eg. ("" ++ "a") - add test_snip.def to test language features - replace-from-file marks a workspace as modified - Arrow and Mark grab handles improved - "don't attach a profile" option for jpeg save - fixes for gtkdoc merge - set TMPDIR on startup to help im_system() - add RAD as a coding type (thanks Roland) - add Filter / Morphology / Segment menu item - much faster meanze for 8 & 16-bit unsigned images - added a "rotate" option to custom convolution - added Histogram / Find / Indexed - Cache defaults to 128x128 tiles - use libgoffice to display plots - use new gtksheet widget, fall back to treeview if we can't build it - better regexp searching in Program window (now full PCRE) - oop horrible tree_map() bug with uops caused a variety of strangeness - group image save now sets image save options (thanks Joe) - sum and product now work for any object - don't set non-existant properties in vips_object_new - faster constant image maker with im_embed() - added "join image array from list", thanks Joe - phew, label backgrounds are back - added raw import (thanks Jim) started 7.18.0 - bumped version numbers - added 7.16 compat mode - revised manual - added snohalo1 wrapper - dropper did not update inkwell picture - better button colour changes - fix examples started 7.17.2 - added progress.[hc] for a better progress/cancel system (again) - splash screen uses new progress system - added list delete, difference, "--" operator - fixed a bug with startup recomps not happening (it was trying to do them in the background, argh) - buildlut makes Plot, not Image - much faster gaussian mask build for large masks - "Size To" has a "break aspect ratio" option - better error message for "[1, 2] < [3, 4]" - support RAD coding - added Radiance menu started 7.17.0 - merged 7.16 branch back into trunk - bumped version number - manual version number was wrong - removed vips8 link, we've started moving that stuff into vips7 now - patches for ubuntu 8.10 - added yafr interp - rotate etc. now have an interp param - revised "resize" to use new modes - transform menu items have inter options - configure fails if bison is not found - fix the filesel filter after a filename change - nicer message on cancel - new VipsFormat stuff - LEXLIBS->LEXLIB (thanks Adam) - added Managedstring, removed old static string system - caption columns can be null, display "doubleclick to edit .." message if they are - added vipsobject builder from old call8 code - added vips_object_new builtin - moved BufInfo down into vips - added IM_INTERPOLATE to vips_call - added Interpolate class and Interpolate_picker - error window output no longer truncates on symbols with many errors - renamed 'Recover After Crash' as 'Search for Workspace Backups' - better Scale alignment in display - regions and scales default to live dragging - better image display defaults (no ruler, no display bar etc.) - thumbnails are transparent when you drag them - side panes have titlebars and close buttons - block attempts to OK on directories in file dialogs - we have a copyright symbol! nicer 'about' box too - better region label positioning - double images ignored rgb16/grey16 hints - configure dies if flex/lex not found - Managedgobject."property" works - added (dir gtype), (dir gobject) - oops, rank filters were off by one by default started 7.16.3 - fixed cancel system (again) started 7.16.2 - argh, "-o" was broken - oops, some left over code for function overloading in the parser - init builtins earlier, so we can spot accidental redefinition - added a NULL type, Group now uses it to indicate an empty slot - another stab at fixing the order of startup actions started 7.16.1 - better pointer set - fixed a couple of notify snafus - use g_assert() instead of assert() to avoid abort() death branch for 7.16 - bumped version - grey16/rgb16 not always set on colour space conversion - revamped test system - set GValue strings as refstrings - try to transform gvalues we get to strings, if we can - added Joe's shrink within macro - removed the last of the fade stuff for faster repaint - open multiple now makea a group, so we can process more files at once - revamped 'make check', much nicer and more useful - better file type guessing - better progress feedback - revised image write code gives better feedback - better group-save, again - fixed a problem with recalc backtracking started 7.15.0 - fixed segv with making tools for non-toplevels - expand the heap if more than 50% full after a GC (was 70%) - added nip2-cli.c (thanks Leo) - updated README - more HIGgy titlebar text in mainw/program - refactor: IWINDOW_TRUE/_FALSE renamed to _YES/_NO - adjustable panes in image header view - histdif was broken for unsigned image types - fix memleak in compile_lcomp() - better --help text - get rid of intltool - use g_idle_add() instead of GAsyncQueue for render notify - fix a segv in imageview destroy - == did not always find the best method - better time debugging in symbol recalc - added $var for string constants - added s => v syntax - fixed recursive invocation bug in vips_call.c - much better hashing of vips calls - configure shows a summary at the end - syntax change :-( lcomps now use [expr :: generators] to reduce ambiguity the old syntax failed for things like [a || b | a <- [true]; b <- [false]] - added --test, so we can check test_toolkits automatically - added --prefix, so we can run without installing - added "make check" support - got rid of the annoying progress popup, it's back in the status bar now - status bar tells you which sym it is computing - revised busy system does all busy feedback - configure switch to stop update of desktop database (thanks Adam) - vips_call hashing improvements - images are GCd after 60s of inactivity, rather than immediately, giving the call cache a chance to revive them ... speedup in some cases - added a 7.14 compat area - join_lr/_tb args swapped - check_args now does not recurse up a class, instead all _check members have to chain up ... a bit quicker - watch "invalidate" in vips_call.c cache ... so paint actions now decache indirect results as well - added Math / Cluster, though it needs a bit of work - insert now format-alikes - another go at removing refresh flicker ... region dragging flickers a bit instead - added Image / Header / Get / Custom - recurse for save groups of groups - added Image / Cache menu item - merged loadable-formats branch started 7.14.0 - updated docs - added 7.12 compat - check for update-mime-database and friends (thanks Tom) - more leak fixes - updated examples and prefs workspaces - break _Object.def out of _types.def - better "if image then constant else constant" behaviour - fixed segvs with IMAGE lifetime and progress dialogs - use xdg-open to show help pages, if available - fixed segvs with IMAGE lifetime and progress dialogs - fixed segvs with outdated iimage change callbacks - some tweaking of the toolkits menu - fixed another lcomp bug - intercept from greyscale option in find_calib - removed unnecessaary assert() from parser - recomp all on startup even in batch mode fixes some strange bugs - apply calib works for groups of images - renamed Error as iError to help windows - more small windows fixes - more small os x fixes started 7.13.3 - save image was broken, weakrefs were not being updated - wrongly setting vips-7.8 region compat mode on all old WS load - "Close" in ws defs pane menu was not working - removed image window / plot window transient-for behaviour, we lost maximise buttons :( - block ungroup of things larger than 100 elements - allow +/- for zoom in and out shortcuts - mainw rmb menu has open/merge items - merge ws doesn't add extra space - added LHS patterns, eg. "[a, b] = fred 12;" - better spacing in merge ws / load ws - added is_list_len and friends ... faster then len for long lists - compile on demand, saves 25% of startup time - now bison only, we won't work with yacc (will package deps need updating?) - added lcomp patterns, eg. "[x*y|[x,y]<-zip2[1..10][11..20]]" - use LHS patterns in defs - oop, dist typechecking could segv - split trace.c to make log.c, base class for logging windows - added error ... error logging window - added destory_if_destroyed() and done some cleanups - oop, im_and_image etc. refs remaining in compat - disallow const-only LHS patterns, eg. "12 = fred;" started 7.13.2 - remove Application from nip2.desktop.in - revised progress system ... works for "max" now! - fix reporting of parse errors in inner scopes - lcomps now nest correctly ... try "Matrix [[x*y|x<-[1..10]]|y<-[1..10]]" - workspaces loaded from stdin with -w save more sensibly started 7.13.1 - you can type "fred = 12" into a columnview, woo - gah, lcomps had "undefined" set on various members because of trimming off parser temps - more visible arrow dashes - added pane.[hc] - added a left pane to mainw to hold ws-local defs - ws-local defs sort-of work - added workspacedefs.[hc] - print all workspace mains on exit too - renamed lor/land as any/all, in line with Haskell - added INTVEC and DOUBLEVEC output - added greyc filter - added "--set" command-line option - better left/right pane widget - resize tk browser search box with pane - nicer widget colour change ... use "*xx*" in style file rather than setting names and contained names started 7.13.0 - woo, fork for new development version - started cleaning up parse.y - simpler DOT syntax ... A1."poop" works now - added lambdas ... \x x + 1 - added listcomp syntax ... [x | x <- [1..]; x > 12] - recomb was broken for >3 band images (thanks km) - lambdas were not being marked as locals correctly, oops - added listcomp code generator started 7.12.5 - tiny win32 cleanups - nicer formula widget, better view switching - better file filter lookup - oops, min and max only worked for rectangular lists started 7.12.4 - cleaner Makefile.ams - transform was only working for [[real]] :-( (thanks Mikkel) started 7.12.3 - added right click / save for plot widgets - remove .svn dirs from dist started 7.12.2 - added support for TIFF predictor - added Tasks / Capture / Plot Bands started 7.12.1 9/5/07 - custom convolution of Plot no longer loses Plot wrapper - better plot colours - better spacing in plot status bar - added histogram differentiate, zero crossings - better ifthenelse on groups - added "expr.(expr)" form, removed builtin get_member - larger sensitive area for arrow crosshairs - added region-on-image-from-region, again - minpos/maxpos work for lists - Math / List works for Groups - maxpos/minpos return -1 for [] - max/min error for [] - stricter about the empty matrix being [[]] - image/Image ==/!= list was broken - empty groups were broken - remove special case for assemble on groups ... you now need to group->list first - [] as a group member means no-value - better Group insides started 7.12.0 28/4/07 - fix up 7.10 compat mode - more fixes to the convert.sed script - small fixes to 7.12 toolkits for test_toolkits.ws started 7.11.18 10/3/07 - added plotwindow, floatwindow - duplicate plot was broken - floating plots have stuff - gtkplotcanvas.c only swallows motion/buttonpress events it handles - gtkplotcanvas.c no longer tries to do focus handling - plotwindow status bar - added plotmodel.[hc], plotpresent.[hc] - plotview has a caption, displays class name - better captions for real/group/vector in heapmodel - gtk_plot_canvas_destroy() was not unreffing the pixmap (thanks Simon) - added next error stock item - better clock value display - added keep-child-windows-in-front pref (thanks Rachel) - gtkplotcanvas.c has new cursor handling stuff to help nip do cursor changes for middle-drag scrolling - lots of toolkit tweaks - revised the manual - ooop, increment_filename fix, it was putting the number at the start of the filename if there was no number there - better batch mode error messages, added -V flag for verbose messages - oop, variable name from filename was a bit broken - started revising the examples - increment on save and browse thumbnails were broken by gtk-2.10, gah - removed debugging menus - bump for 7.12! w00t started 7.11.17 26/1/07 - snap hdrag of columns to make lining up easier - better CSV import - added zero-excluding mean and deviation to Math - better set-workspace-name on ws load - started a ws background popup menu - grey ramp orientation swaps w/h - better display control bar scale/offset for HDR XYZ/Lab/etc. images - possible fix for intermittent fail to recomp on edit bug - fix for image * group - paste in gtkplot sources (we will probably need to hack it about a little) - added plot/plotview - oop, memleak in icontainer - added a temporary Plot menu for testing - set plot tick step to avoid mad mallocs on large ranges started 7.11.16 21/12/06 - look for release on rulers as well as press - adapt for new Hist system - use im_concurrency_set() - add im_get_option_group() - oop, recursive invocation gah - slightly better error messages - better mainw title bar text - added 'splits' - better trace / profile / leak options - more robust find chart calib - only interpret RGB16 for display for int formats - change im_histgr args - oops, paintbox could set delete-on-close sometimes - custom blur has many more controls - better inter-workspace "depends on ..." messages - chop/assemble image arrays now work on groups of groups, not list of lists so you can process the chopped up image - added 7.11 toolkit_tester, plus a little sed sscript to update old workspaces started 7.11.15 6/12/06 - tiny fixes to startup code started 7.11.14 6/12/06 - Vector arithmetic fix - Vector display class - more Matrix fixes started 7.11.12 8/9/06 - Image Rank no longer rounds up - only obey IM_CONCURRENCY pref in GUI mode - added GVALUE input/output args - added set_header, Set Metadata - use LC_ALL rather then LC_MESSAGES (thanks Simon) - better range == 0 check in conversionview - re-added make-named-column action - better textview reset during background recomp behaviour - added LUT from scatter - added AC_CHECK_TOOL to configure to find tools for cross-compilation. - added map_nary, Crop now loops on all args - test for glibtoolize during configure - added tag image as hist, set type, image->matrix more flexible - added get header field - added Real displayer - reordered Image menu - optionview refresh was a bit broken - ruler resize was a bit broken - map_nary recurses - make image windows children of the mainw ... so they can't pop behind - "mean" can do lists of images etc. - move ->parent from idialog into iwindow - revised to_list behaviour, added to_Group - show save prefs automatically on save - removed broken scroll on focus code in columnview - map_*ary no longer loop over lists ... they often represent compound objects, eg. "mean [1, 2, 3]" - new preferences viewer - kill parent of nested dialog now kills dialog as well - more JPEG save prefs - CSV save prefs started 7.11.11 18/7/06 - small polishes from gtkdisp3 - tweak for im_init_world() changes - better behaviour for scale == 0 in conversionview - better original-filename handling - use im_msb() for GREY16/RGB16 images - csv2vips wrapper update - added parse_time - fontname defaults to "Sans" ... stops a warning on load - set window title less often - update i18n infrastructure started 7.11.10 23/6/06 - sync CVS again - oop, selected closed columns caused kb grab confusion - added call8.[hc].. vips8 interface - new builtins vips_image_new, vips_call - reworked doc build again, seems to work in dapper now - added missing .br to man page - allow '_' in environment variables in "expand" - mainw tooltip reports operation cache size - upped default memoisation cache max to 10000 - better caption for Group objects - oop, mac os x detect was broken - GSL error handler - more work on vips8 interface - add gcc attributes for varargs and noreturn - mac build fixes - keep prefs in ~/Library on mac - vips8 interface done - more tweaking for vips_call for robustness - quick stab at background recomp in workspaces ... some stability problems - tiny Toolitem fixes - "Calculating ..." appears in status bar during a background recomp - is_image builtin says yes to vips8 images too - added Analyze and Vips8 menus - added vips8_get_header builtin - better ifthenelse behaviour for image/constant mixes started 7.11.9 15/5/06 - reverse order of decls in image_name etc. to sensibleify Change Header options - better HIST preserving - bug in complex display control bar (thanks Jean) - use gtk_disable_setlocale() to preserve LC_NUMERIC setting (thanks Peter) - more g_ascii_strtod() and friends for double parse/print - disallow vips funcs with no input args - gtksheet was freeing pixmaps with g_free(), not g_object_unref() - better matrix type guesser - optional link to vips8 for testing - CSV load/save - strict reduction of vips_call arguments prevents GC during argument gather and dangling pointers - oop, problem in Transform in Image.def - added "dir" builtin - always grab focus for bottom entry widget on column select - even more test view reset tweaks - added "objects in workspace" count to main status tooltip - limit number of cursor shape updates started 7.11.8 22/4/06 - added gravity, Find Projections now shows centre - added project - added OpenEXR read support - fewer int/void* tricks to help x64 - call im_existsf() more sanely - better Group caption - don't save/load ->name automatically ... better 7.10 compat - better pointer printing - added support for RGB16 and GREY16 image types - workspace window size is saved in ws file and overrides the global default - some edit dialogs now done with member automation - fixed NO_SPLASH - fixed scroll to row on error, for closed columns started 7.11.7 11/3/06 - allow complex constants of the form "12j", cf. python (also allow i) - optionally display complex as "x + yj" - ifdef'd out some more debugging code .. saved 30kb! - new Managed class abstracts out code for GC/C managed objects - Imageinfo now sits on this - Managedfile object replaces the thing we had for read - split trims trailing fails too - scrapped ELEMENT_IMAGE .. we just have managed objects now - added managedgobject - added experimental Clock class - moved some views into modelview.c - delay showing the hglass for 0.2s - change clock to seconds, subclass off Real - modelview now has a right-button menu - disable tile fade animation for thumbnails - model _get()/_set()/_load()/_save() now automated - sort column jump widget - better scroll-to-column behaviour - column jump is tear-off-able - column jump is sorted by column name and name length - added geometric mean - added sum, product - added linear regression - fixed assert( 0 ) for VIPS operations with an implicit DISPLAY param - added optional dependency on GSL, added gammq builtin - print_base was broken for some argument combinations - shift + mwheel scrolls left-right in workspaces - update thumbnail on falsecolour / type changes in display bar - matrix now uses member automation - main uses GOption command-line parser - make sure we don't clear dirty on rows coontain errors - optionview only rebuilds the menu on change - 7.10 compat defs updated - itextview/clock fixes to make editing members easier - added -o cmdline switch - scrapped print-last mechanism ... printing main from an associated .def file is much better - always set argv, allow save of Image, split save to file and print value - save Matrix as well with -o - added -e option - revised man page - added Find Projections - raised default memoisation cache size and heap size started 7.11.6 18/2/06 - custom morph was broken, grid was broken (thanks Dave) - Matrix_file now uses "search" - reorganised morph menu slightly - added Format / CSV import - better handling of display of very long strings - added lazy (read "filename") builtin - \n was missing in expr_info error report - removed "save successful" info box for great HIG-ness - added is_prefix, is_suffix, is_substr - Pathname widgets add to session path - widgets like Group, Toggle, etc no longer add annoying stuff to tooltips - readded "auto-recalc" menu item - renamed Slider as Scale and added a caption field - oops, string constant "\\" failed - drag from konqueror might work now - added hist_thresh, added threshold items to Image / Levels menu - prettier Scale display, better display of multiline class member formula - added correlate, correlate_fast, Filter / Correlate - added "jump to column" menu item, handy for navigation in large workspaces started 7.11.5 15/2/06 - added "search" builtin - (c) line changed - itextview mouse enter/exit now does help/highlight - itextview insensitive in noedit mode - tweak formula to stop resize with clearlooks theme started 7.11.4 18/11/05 - added tile fade pref for Kirk ... it is a bit slow on win32 - fix compiler crash for [1..2] (thanks Jay) - automatically add an icon to the win32 .exe - added -main_load_args switch ... just a temp hack - better -main printing - added "path_separator" ... either '/' or '\\' depending on platform - better char constant parsing - better char constant display - added path_relative/_absolute/_parse - prefs now switch between / and \ automatically started 7.11.3 26/9/05 - display original filename only for iimage which really were loaded from a file - ppm read uses direct open, rather than converting to vips - fixed used-before-set problem in option ... could cause segvs when displaying rows built from .defs containing errors - added Filter / Blend / Alpha Blend (thanks rich) - added Edit / Info (Ctrl-I) to mainw, some stuff there now, space for more to go in - removed nip2-7.11.ebuild now that nip2 is in gentoo portage - desktop integration binds .v files to nip2 (thanks Ruven) - align cols marks the ws as modified - configure.in magic stolen from pango ... we now automatically disable gobject cast checks in production builds - display formula rather than value if there's a visible graphic - falsecolour and type applied to thumbnails - fix gcc4 warnings - use g_mem_profile() - plot slice can now plot along any arrow - oop, some filters inadvertantly overrode width/height - fix isclass is_class confusion - itextview only shows value for non-class rows ... we assume members / graphic will show the value, so we show the formula - don't apply scale/offset displaybar controls to histograms / fourier images if Interpret Types is on - better initial kb focus for file load/save dialogs - better tooltip for iimageview - tooltips on demand function added - colourdisplay, ... adapted to new dynamic tooltip API - use input-only eventboxes for spinbuttons - better rowview tooltip - oops, buf_appendc() was a bit broken, fixed in vips too started 7.11 (1/6/05) - view image header now shows meta fields too - does INTVEC args to vips - now in CVS - added Analyze format - added name2gtype, gtype2name builtins - added get_header, grid, matrix lr/tb join - slice into tiles was broken for case tile size == image size - removed led.[hc], now uses stock system - always define our own strcasestr - icc import offers to use embedded profile - added 7.10 compat mode - "reset" in display bar resets to workspace default, not to 1/0 - column titlebars reorganised - reenable gtksheet support now gtkextra-2.0 is out - original-filename tracks name loaded at - bumped version to 7.11.2 - oop, fixed a nasty refresh bug - configure now adds LEXLIB to link line - pasted gtksheet code in so we can hack it - added matrix area selects - added Matrix / Extract / Area - slightly better default widget handliing in dialogs started 7.10.11 - docs no longer contain absolute nav links - increment filename on save works again - hide closed columns in NOEDIT mode - install a .desktop file for GNOME (thanks Denis) - group, right click, ungroup, no longer pops a spurious error dialog - new pref lets you not use the crosshair in image display windows ... some desktop themes have very annoying crosshair cursors - call libMagick less to reduce segvs from the file open dialog with broken ImageMagick libs - show args in vips history - fixed a rounding bug in image resize which sometimes made it miss by a pixel started 7.10.10 - fixed crash in vips_call with repeated calls to fns with large image vectors - fixed crash replacing a region with an image - fixed exit if temp area was missing (thanks Denis) started 7.10.9 - allow filenames containing ':' chars - uses im_render_fade() for prettier image display - added CCITTFAX4 compression mode for TIFF save - oops, image save options were being ignored :-( - fix 64-bit compiler warnings - fixed problem with very long filenames - recover-after-crash no longer messes up recent menu - "Jump to" in program window was broken - fixed a crash with very large objects (thanks David) - swap shift/control scroll modifiers to match HIG - rotate matrix works for any size matrix - rotate quadrants works for matrix as well as image - added recalc after reload start stuff - use auto label wrap - firefox is now the default HTML viewer on *nix - limit matrix display size to 10x10 unless we have gtksheet - small startup speedups - destroy views when a column is folded away to save some memory - added Image Rank - band join is much faster at joining many bands - safer empty temp area - added cute column open/close animation - fixed a couple of problems with region dragging in compatibility mode - removed column name dialog (thanks Joe) - program window now lets you collapse the current kit - allow \r in .def files (so we work with DOS edited files) - added Image / Tile / Chop Into Tiles - added 'Open Examples' started 7.10.8 - explicit gthread dependency makes us work even if vips is built without threads - tiny .def fixes - "-time_save" switch turns on image save timer for benchmarking - mainw, trace, imageview, program now use gtkaction / gtkuimanager - mainw and imagewindow 'view' settings now update prefs for you - trace window uses new gtk_text_buffer/view widget - image header uses GtkTextView for history display - program window uses GtkTextView / GtkTreeView - windows remember their size and pane positions - fix a crash for edit defs of live widgets in prog window - removed default file type pref ... now remembers last image and matrix file type - added "Set As Workspace Default" to conversion bar - mnemonics for more popups - fixed a crash if you quit mainw with an image window open (thanks Jay) - new default cursor for imageview windows (thanks Jay) - regions only update when grabbed - now passes distcheck - use g_setenv(), g_mkstemp(), IM_FREE*(), g_set_application_name(), g_set_prgname() - better cursor change layering - better initial toolkitbrowser size - absoluteize & canonicalize VIPSHOME (so we work with a relative path for VIPSHOME) - better time-to-go text - more fixes to help compiles on 64-bit systems - invalidate operation cache on paintbox actions ... makes paint on FFT work again - save settings in APPDIR on win32 rather than a dotfile - added SAVEDIR environment variable started 7.10.7 - tiny build fixes - added "_" builtin function for i18n of toolkit menus - softer 'unpainted' checkerboard (thanks Kirk) - added "-i18n" command-line switch ... outputs constant _() strings and quits - compiled string constants are automatically shared between all defs - (_ "kjh") substituted at compile time - started marking up .defs for i18n - trace_args() was printing backwards started 7.10.6 - uses fftw3 if available started 7.10.5 19 oct 04 - removed "beta" from version - perspective distort works on groups (thanks Joe) - added get_left/get_top - chaneg and tag colourspace now have option boxes - new enum class and option builder cleans up some stuff - fixed crash for display control bar scale on black image (thanks Mikkel) - fixed image windows appearing off screen for workspaces made on large displays being used on small displays (thanks Mikkel) - un-offset regions during create in compatibility mode (thanks Rachel) - fixed a race in vips history memo-isation (thanks Joe) - speedups to vips function call history too started 7.10.4 4 oct 04 - always include formatted html in dist, and install on install - enable line crawl on win32 - prefs now autolayout, so look sensible even with font changes - added Image/Bands/Extract|Insert|Delete - linear match now works for groups - prefs were not always saving automatically - white_balance now takes two args: uses band ratios in small image to fix large image ... makes using one image to fix a group of images much easier - also, works in XYZ, has adjustable white point target - new icon (also used in About) - LabQ and LabS conversions were broken - check for strcasestr in libc - display symbolic names in iimage caption - oops, custom rank menu item was broken - use a dumber sort algorithm for row recomp order ... glib was skipping too many tests - thumbnail convert settings update is smarter - much faster display convert bar - Joe's .defs are in - image blend is smarter about reordering args - small win32 fixes - oops, did not remove all temp files if debugging was turned off started 7.10.3 13 sep 04 - to_real now works for toggle & bool - Rubber menu items were b0rked (thanks Joe) - Rubber scale removed (rubber transforms now automatically rescale) - fixed crash if you gave a number as a superclass (thanks Joe) - win32: block log output to prevent annoying console window appearing - shared model for toolkits menu and toolkitbrowser for big speed-up on main window build and better update behaviour - tk browser columns are reorderable (thanks Joe) - better image type guessing (thanks Joe) - thumbnails now use Type hint (thanks Joe) - added simple number base conversion - compound unary ops on Rect now work on width/height rather than left/top ... so abs(Arrow) now gives the expected result - repaint regionview immediately for better feedback - group save can save unboxed images and will iterate over nested lists - added trace VIPS operations, including cache hits/misses - small menu polishing - better 'revert to defaults' in prefs (thanks Jay) - documentation revised - fixed dependency tracking inside zero-arg hidden classes (thanks Joe) - help system updated started 7.10.2 23 aug 04 - convert bar settings now affect thumbnails too (thanks John VanVliet) - show hglass cursor more often - free rotate is now -180 to 180 (thanks Jay) - added 'toolkit browser' - work on docs - small toolkit fixes - better mainw decoration handling - minor main window menu rearranging started 7.10.1 28 july 04 + top-bottom 2 point mos was broken (thanks Joe) + added aliases for resample and estpar to help compat mode rubber sheet + colour ops on LABQ were broken by the alpha channel stuff + larger default max heap size (thanks Mikkel) + added ebuild (thanks Ruven) + oop, fftw includes missing from IP_CFLAGS + added Expression widget + suppress unneeded textview in NOEDIT mode + better textview layout + indent subcolumns in NOEDIT mode + better regionview text layout + Image/Format reamed to Image/Number Format (thanks Joe) + prelight for rows, expressions and spinbuttons + better row label layout + menus reworked (again) for Expression class + oops, resample renamed as transform_search + win32 build fixes + added "Align Columns To Grid" + better focus handling in imageview (thanks Mikkel) started 7.10.0 21 june 04 + toolkit menu is now built dynamically from heap ... you can write functions that generate menus + menu items can have tooltips, icons and labels + reorganised all menus + added "scope" keyword ... helps remove "root" from toolkits and makes them relocatable + added "solarise" filter for fun + added "diffuse glow" filter for fun + slight improvement to references to non-local members in deeply nested classes + ungroup will now also unpack lists + fixed segv if option menus were rebuilt while posted + added vips function call cache ... memoisation! + added prefs for #cpus and #memoise + gah, had forgotten to add several new widgets to model_base_init(), so they were not loading correctly if used in prefs + put tearoffs back and fixed accels + added empty-temps yesno on startup + -main can output many images correctly + display control bar false colour works on RGB images + regionviews are offset in compatibility mode started 7.9.7 1 jun 04 + enable broken for gtk all the time in program.h (thanks Ruven) + now uses im_text() to paint paintbox text (imageinfo.c:2185) + better zooming from menu items (imageview.c, imagepresent.c, imagepresent.h) + extra recalc on startup to build classes before we load args (main.c) + set_output() was missing an "!" before imageinfo_file (graph.c) + saner startup error logging (main.c) + expr_error_print_all() now goes to a buffer (expr.[hc]) + program.c has an error lister + main.c knows about new error lister + prefs.ws had max_undo broken by precedence change + String now interprets and expands C escape chars (eg. \n) + fixed close program window with selected text crash + fixed edit of row with error itext crash + added tile and Tile (replicate/mirror ... using im_replicate) + leak testing only in DEBUG builds + binary and unary operators now track the function they were called from, for slightly better error messages + Number spots trailing characters + shadow and text paint work on labq + added resize longest axis mode to Shrink_to + fixed up menu dumper + don't track load/save progress in command-line mode (thanks Joe) + arithmetic and relational ops now work on images with a mixed number of bands + UI polish suggestions from Joe are in or noted on the TODO + better update of visible hints in imagedisplay + new menu item system with "action" member lets you have icons, mnenonics and i18n for toolkits + compatibility system for 7.8 workspaces + better recent menu started 7.9.6 8 mar 04 + added Group class + .def files rewritten for Groups, also many enhancements + oops, imageview=>file=>view header was broken + prefs option for 1 bit TIFF write + scale in display control bar was broken (thanks Ruven) + removed on-demand compile, caused strange recomp problems :-( + value display no longer decompiles class args + tracks lineno for tools + better "not defined" error message + better "bad parent class" error message + better error messages from calling VIPS functions + better "link report" error message + relaxed the restriction on superclasses ... you can now have anything as a superclass, including a full constructed multi-arg class + detects redefinition of syms within a single parse action + precedence change: "?" and "." now the same precedence, like C + better "member not found" error message + spots nested comments + visualise image can handle labq hist + case ignored for class names in ws save files + SHIFT-mwheel now zooms in and out, like gimp-2.0; CTRL-mwheel scrolls left-right + autosave does not back up system workspaces (eg. prefs) (thanks Joe) + raised arrow/region create threshold + optionmenu swapped for gtk-2.4's combobox + now gtk 2.4 only, gah! too annoying to have lots of ifdefs + uses GtkFileChooser + oops, String/Number did not implement load/save + much polishing + row.c no longer tries to recomp all rows that ref "this", was causing confusion ... so, much faster, but will change row recomp order in some cases + hmm, trace was a bit broken + auug, instanceof_exact was broken for deeply nested classes, must have been like that forever + fixed a nasty and long-standing bug with shared classes ... we now always copy code rather than trying to cache it + ruler menus now have mm and offset setting + got rid of all xoffset/yoffset stuff, what a pain it was + Rect (and hence Arrow, Point, etc.) now behaves (roughly) like a complex for arithmetic + better select behavior on thumbnail drag + renamed Point as Mark, Point is now a subclass that lets old nip workspaces load + added Fontname widget + colour picker can be pinned up + better image thumbnail in workspace sizing + renamed Filename as Pathname and added a caption + all menus items rewritten for new batch system started 7.9.5 6 feb 04 + Rotate_fixed now has an option menu for the angle + imagearray_chop was broken + image thumbnail drags no longer embed the workspace name (unless they have to) + merge workspace now shows an error dialog on failure + statusview does not display more than 8 bands + workspace saves view mode in files, and mainw knows about it + now uses pkg-config to find vips + splash does not focus "remove" toggle by default + oop, hourglass was broken + better hourglass animation + select/extend select now works on image thumbnails again + PRINT_LAST now done in workspace _dispose() + drag image thumbnail to background to make a new column and put in a link + compile now delayed until value needed ... saves 10% on startup time + value pointers only registered for GC if necessary .. saves another 3% started 7.9.4 9 dec 03 + removed last gtk_timeout*()s + fixed some memleaks + views now _sink() their child views, so even if views don't ever get added to containers (eg. toolview, rowview), they still get freed properly + niprc now sets gtk-can-change-accels ... no one will discover this otherwise + added Custom_blur, dropshadow now uses a gaussian blur + some better error messages + Toolkits=>New items for filename, number, string + usage and About have version info + row delete now asks for confirmation + faster and more comprehensive common subexpression removal ... removed the 'optimise' option, might as well have it on always + better session path behaviour + much better open recent menu + better graphic save/replace scheme ... image filenames now change in a much more sensible way + better iimage/iregion/iarrow caption scheme + can now drag from image thumbnails, cool drag icons + progress feedback on non-vips saves, and you can cancel too (!) + added extract_row, extract_column, extract_band, join_lr join_tb + extract_area now works for matricies too + better ruler tracking at high magnifications + defines HAVE_FFTW so we actually save and load wisdom now + "pos_changed" signal stops all the suprious imageinfo changed signals + "file_changed" signal lets iimage know when files are swapped about + better vips_call error messages + image cache is on mtime as well as filename, so loading changed files gets the new version + auto-reload on file change preference + reorganised main window menus and scrapped "Insert" + done a simple splash screen with some startup feedback started 7.9.3 20 oct 03 + better welcome message + command-line mode with -main/-script/-workspace/-benchmark flags + better middle drag scroll + fixed the annoying race condition in repaint + fixed annoying rounding problems with colour drag + added TRUE/FALSE as synonyms for true/false + better image zoom shortcuts + more HIG-y layout in NOEDIT mode + added String/Number types + windows have icons, yea + fixed browse icons window + message internationalisation done + en_GB translation file + more higgy Stringset class + better help system for dialog boxes + paintbox now has buttons for tool select + cursor shape change in subwindows + load and save accelerators + configurable accelerators on the toolkit menu + more HIGgy dialogs for sliders, regions and matricies + basic "Open Recent" thing on workspace file menu + better keyboard nav for workspaceview + reworked image viewer for more model-view-ness + unified image view state + hmm, row_new_heap had a double paste, wonder how long that's been there ... should be a bit faster at recomps started 7.9.2 (30 sep 03) + toolbar accelerators done + image display, colour display, region display all reworked for gtk2-ness started 7.9.1 + HIG-ified (I hope) + broken into SDI interface + prefs dialog + toolbar in mainw + progress dialogs for image load/save + new error message system + live watch system started 7.9.0 (1 aug 03) + compiles with gtk2! + lots of cleaning up started 7.8.11 (30 jul 03) + better run-nip.sh start script + tiny fix to Calibrate_chart, thanks haida + big LED stolen from mozilla, just one of them now + add "%s" to existsf() calls for filenames with % in, thanks Clare started 7.8.10 (22 may 03) + icc profile JPEG save option + "." now on end of datapath in prefs + fixed a race condition in regionview ... could crash during paint on slow machines + better vector/image ops + D65 <-> D50 conversions improved + added d50 macbeth data file + added "measure" to _stdenv + added "insert", "extract_area" to _stdenv + "recomb" now works on matrix, vector etc. + more use of extract_area + mark_tree() is now iterative, so no stack overflow on large heaps + reduce_spine() is (slightly) less stack-hungry + recomp_row() will not rebuild models for rows with errors ... is this the best way to stop it though? + calib_chart now works on 16 bit images + bumped version to 7.8.10 to match vips ... less confusing + changed doc builds so that we can include formatted documentation in the make dist + fix to drag-n-drop code on winders (thanks Jim) + fix to incorrect error message in file info view + blocked dash crawl on winders, does nothing but flicker + "config" help option (thanks Kirk) + columns resize on close + middle-drag in workspace scrolls + new version of Joe's x-ray stuff + spec/ now has RPM .spec file + added a "run-nip.sh" startup script + moved reload to program window + drag column and workspace gets a + cursor + added "Match" to Image menu + added "Tone_for_print" to Print menu + new macos icon, thanks denis started 7.8.7 (10 feb 03) + added set of relative constructors for point/region/arrow/etc. + used in various places to fix problems with dialogs on images with displaced origins + _vislevel member sets default visibility level + updated widget menu items to set vislevel + added has_member, get_member builtins + add "%s" to everror() calls so we can have "%" in error messages safely + better if-then-else overloading + add "." to the end of the default search path + added "Area", a non-resizeable region + option.c was not initing value edit correctly + better initial size for option edit dialog + added orderlist_scan() + better title for region edit dialog + better row_save_test() means member ordering does not get lost on clone of edited rows + imagedisplay_link() no longer makes conversion for you ... change to iimageview.c _init() in step (removes redundant create/destroy pair) + imageview_new_area() could pick shrink == -1 in some circumstances (thanks Joe) + drag file to imageview or thumbnail does replace-image + Region can now never fail (thanks Clare) + better feedback during paint image creation + better imageview File=>New=>* for images with displaced origins + added Edit_header to Image menu + catch errors from libxml2 + Image == Vector was broken + Overlay has a "lock size" toggle + added Image=>Insert + renamed "Clear edits" as "Reset" + saves/restores fftw wisdom for first fft speedup + snap-to-* on region drag could resize region for zoom != 1 + statusbar gave bad numbers for FFT and histogram images + use im_invfftr() for speedup + better ruler display at high magnification + oops, program=>find was broken + pin-up now part of dialog started 7.8.6 (23 dec 02) + swapped list for hash table in heap set of managed pointers ... startup time fallen from 2.4s to 1s! + much better heap-full reporting + knows about png + patch from Hans Breuer: + paintbox sort-of hacked back in + fixes to file selector on win32 + misc. win32 #include fixes + OK buttons in dialogs now verbs + knows about magick + oops, Colour_chart_from_matrix and New_CRT_test_chart were broken in 7.8.5 + new heap_is*() function style handles eval errors better + paintbox rewritten ... now paint bar + snap to guide added + much smarter region repaint system now does true xor animation + dash lines crawl in the background + Rect/Region/Arrow etc. can now have float args and won't barf on images with strange offsets + default image file format preference + colour temperature conversions sorted out (thanks Haida) + fourier transforms now work with optical transform, rather than having optical built into visualisation (helps paintbox) + removed use of g_mem_chunk() + new colourdisplay class for displaying swatches of flat colour + drag-n-drop colours + tries to detect C stack overflow in reduce_spine() + new trace system reduces C stack usage during reduction + fixed a few memleaks + copy-on-write for member edit slightly reduces overcomputations and makes changes feed forward more gracefully + scale column coordinates with changes in font size + Tilt_brightness now works with n-band images + nativize paths + drag URIs to main window to load files (thanks Hans) + load any file type from command line arguments + small menu fixes + added RPM .spec files to distribution + help launcher for mac os x started 7.8.5 (12 nov 02) + added a bunch of "%s" to allow percent in tooltips + rearranged reduce_spine() to trim stack usage ... should reduce C stack overflow segv on deep recursion + added IR sample images to data dir + added rachel.con IR sharpen matrix + added Join.Array to build an image array + added Rubber stuff to Image + removed auto column switch on row select + added New to imageview window + finished-ish docs + >3 band images now display as RGB, 2 band images as mono ... helps display of imported RGBA/GA tiffs + better update of toolkit menus on tool change with zero-param classes + better positioning in toolkit menus with hidden items + default vid crop fixed + added Overlay to Image menu (thanks Joe) + added Calibrate_chart and Calibrate_image to Capture menu (thanks Joe) + help buttons linked to html manual display + can now load workspaces from win machines on *nix, and vice versa (tries both types of dir separator) + added Joe's Xray menu + present menus and rows in definition order rather than reference dependence order + added Browse_multiband (thanks Joe) + can now pop up help viewer on win32 as well + knows about new im_LabS2Lab() and im_Lab2LabS() funcs + junk Hist on load to lessen balance confusion + more helpful save/replace file dialog titles + longer doubleclick time + sub-menus tear-offable + settable default image window size in prefs + optional auto-popup of new image rows + gtkfilesel2 knows not to select something twice + larger default max heap size + ws save files are prettyprinted and uncompressed by default for greater portability started 7.8.4 (8 nov 02) + fixed recover workspaces (thanks Joe) started 7.8.3 (31 oct 02) + acinclude.m4 fixes for mac os x + set extension on get_filename if none set and not showing All + added Mosaic_force ... no tie-point refining, ever + only save edited sub-trees on workspace save ... shrinks ws files to about 1/3 their previous size + setlocale for numeric conversions to "C" to avoid "," as decimal point madness + escape C sequences in filenames (eg. "\n" etc) + vips functions and builtins now linked via main symbol table, rather than an extra lookup on "undefined" + pseudo-toolkits group VIPS packages and builtins + display help text on pseudo-tools in program window + "go to def" for program window + auto-expand for rows in program window started 7.8.2 (27 oct 02) + set $HOME on win32 + WinMain on win32 for non-cmdline start + -mwindows flag to stop command.com starting for non-command line start on w32 + lots of hacking on gtkfilesel2 for win32 compat + Matrix_file "" + New_mark.Region etc. menu item + more robust row recalc on .def edit + zero-arg local classes of classes sometimes recomped in the wrong order (thanks Joe) started 7.8.1 (18 oct 02) + d'oh, matrix constructors have to be classes for is_instanceof to work + much better change/refresh/scan behaviour for gtk_sheet + uses IM_DIR_SEP* for some win compat + many configure fixes for mingw + use gtk_fixed for workspace layout for gtkwin compat + rename Text -> iText to stop windows breakage + woohoo, fixed the grab problem in regionview + more robust workspace load + polishing started 7.7.23 (23 aug 02) + bug in history tracking + better filename select + OK buttons in multi-select fsbs turn on and off + supress "super" iimages for region/arrow displays + rulers and status bar know about Xoffset/Yoffset + regionview uses IMAGE cods, converts to model cods and back on refresh/update + defs adapted to origin stuff ... including Mosaic! + region create is ctrl-left + save-as-TIFF traps errors + done Plot and Resize, phew ... all menus finished (the ones I did anyway) + added namespaces to XML save file, prettyprint disabled, compression on + tooltips for toolkit menu items + "Name param1 param1: " string automatically prepended to help text + preferences for mainw start window size + menus reorganised to be more logical (I hope) + Separator class for submenus + column save adds enclosing workspace + drag in program window was broken + #dialog back in again, with an edit dialog + "menu item from column" thingy + refcount bug for long image load fixed + iDialog can autopopdown for represented obj destroy + toggle MB free/cells free + use gtk_sheet for text matrix display + configure detects gtk+extra for gtk_sheet + iimage caption displays name of most derived class + relaesed as 7.8.0 ! yea! started 7.7.22 (15 july 02) + started Print menu + added "expand" builtin ... expands environment variables in a string + filesel history fixed + reconstruction from overridden constructor in oo removed ... now just there for edits + done Colour menu, started Morphology + done Morphology menu, started Filter + if_then_else is now an overrideable binop + use (double) for image size calc to avoid int overflow + logical_and and logical_or can be overloaded ... still shortcut for plain types, so not quite like other overloads + done Filter menu, started Freqfilter (will become part of Fourier) + done freqfilter, started Histogram + sliders no longer each have a continuous member ... set with a watch directly from prefs + histogram visualisation + better trace will never evaluate graph unexpectedly + Real widget ... just draws a real number + better row name set system gets less confused + can now edit superclass constructors + better recovery after error in row recomp + better region caption + better scroll to new object for main window + "<", "<=" work on strings + started Image menu + small fixes for large files + image window title bar update fixes + auto select 1st matching file on load if no file specified + rename Patch -> Colour to fix class name / gtk type name confusion + classmodel_class_instance_new() now uses CLASS_new in preference, if defined ... lets you have separate behaviours for _type object creation and OK in edit dialog + Xoffset/Yoffset added to header view + default class == thing, class != thing operations in _Object + class params no longer have subcolumns ... stops O(n**2) increase in complexity with workspace size! + multiple select for for fileselect ... load many images/matricies/etc at once + on load, objects renamed to the filename they were stored in + better workspace scroll on new object started 7.7.21 (21 june 02) + override Pixel constructor in Colour and Generate_colour.widget + rename ... ivector -> iarrow + new op type for colour-through-image operations + better expr->err update on link clean + convolution matrix display now shows scale & offset + Matrix is now the base class, Matrix_vips etc. inherit from that + tags now decompile for better error messages + better graphic rebuilds for sub/super classes + better member-not-found error message + better new column positioning + rotate menu started + convert menu started + segv on CTRL-S on local objects fixed + flash help on row buttons + suppress display of superclasses with a leading '_' + better auto new workspace name + better column rename on ws merge + better scroll-to-visible for columns + row just uses "name" property now ... no "sym" + toolkit list now scrolls down RHS of main window ... no more resize probs + parent/child relationships shown with colour changes in rowview + removing column with an error resets error state properly + x2 speed up for recalc with fancy heap node serial number system, heh + better regionview create/destroy/link fixes occasional bad casts + better auto workspace scroll on load + scrapped .hd/.tl etc., too hard to overload ... builtins now + '' chars are now unsigned, signed chars are numbers in [-128, 127], chars default to unsigned (now unlike int, short) + regions/arrows/etc. now defined on Image, not image + better trace system does not confusingly interleave prints + small filesel fixes + Complex, List, Fourier menus + display control bar knows about fourier images + display control bar menu resets properly + bits of Arithmetic broken out into Log and Trig menus + Filename widget ... should help make an ICC profile chooser started 7.7.20 (17 may 02) + redone configure system ... data files now go in share/nip, not share/vips/nip + fixes to Pixel class and Generate menu + -image is now *-1, not im_invert() + separate '!' and '-' operators for better C-style semantics + better toggle/extend select for thumbnails + Yxy display + ops on Matrix class done + stats menu added + removed matrix size limit + errors -> ierrors to please mac os + keep local edits on reload + oops, classes as parameters were broken + member edit of local classes was broken + class arg checks inherited + view header dialog in imageview + colour menu + nasty bug killed for discovered dynamic references to dirty symbols + Colour widget shows a swatch and lets you gtkcolorsel for edit + rowview menu on subrows too, plus select/extend-select + ceil/floor added as builtins + lots of small polishes started 7.7.19 (10 apr 02) + it's now (c) 2002 :) + better LED spacing + "stop" sign toned down + split Expr to static stuff (Compile: parse/compile logic) and dynamic stuff (called Expr still ... reduce stuff) + Exprs can share Compiles if we know they will have the same code + copy-on-write for edits + 100s of times faster for large workspaces: load ws with 270 images = 7s + oops, temp files now unlinked properly + icon browser refreshes in idle handler, plus better cancel behaviour + destroy callback added to iDialog, popdown_cb memleaks plugged + memleak in model rewrite plugged + all class instances in hierarchy have the same "this" ... simplifies OO stuff a lot + removed heap_gc() from REDUCE_CATCH_START() for big speed up (d'oh) + smarter row dependency finder + leak plugged in get_image_info, plus more informative + reset menu item on graphic edit objects + ooop, added '\'' as a constant + C-style hex constants, better real constants + even fancier operator overloading scheme does builtins too, and is extensible for other user funcs + abs/max/min/etc. can be overloaded + lots of menus done! + newimage dialog removed + classes with supers don't display as pull-rights in toolkits + updated vips.m4 for IRIX + top level dirties now say what they're blocked on in tooltip + cast to int type now behaves as C (no more round to nearest) + reload toolkit works better + smarter image cache dependency tracking fixes occasional segv + _animate() in class build for greater interruptibility + "++" is lazier for list args + image ++ [] allowed + builtins can be overloaded + tidies to reduce/action + dmalloc support + better column/row select behaviour + better event handling in image windows + scroll wheel in image windows + class typecheck delayed until first reference for great speedup + lots of polishing + Mac OS X fixes: - change include order in ip.h for mac os x - test for mount.h, util.c, ip.h changes for space free display on mac os x - file size stuff changes - small include order changes - temp_name() fixes for duff mkstemp() - ignore GDK warnings (eg. locale not known) + changeable max print length, dynamic buffers + Pixel[] class + ontop no longer saved for workspaces + text values display left justified started 7.7.18 (1 mar 02) + load images from command line + new operator overloading system + new check system allows check to be inherited + nasty ii_destroy bug fixed + new trace option for builtin functions + nasty row destroy bug nailed + much better busy/not busy handling, feels smoother + more sensible workspace checkmarking, good speed improvement + more info displayed in image status bar + red error arrow not always unset ... eg failed file load + try to load a damaged (eg. truncated) image file ... wrong err msg + recover ws after crash fixed started 7.7.17 (23 jan 02) + changed appearance order for subcolumn + params and super start with vislevel 0 + '.' now binds more tightly than '\' + '\' renamed to '?' + '&&' and '||' split to separate logical and bitwise operators + removed local function display + better code generated for access to members across nested classes + better preservation of sharing in class browser + decompile makes loop labels + non-row locals link back to enclosing row correctly + inter-row dependencies via non-row locals spotted + user def of default constructor banned + nested classes with implicits refs now work + operator overloading added started 7.7.16 (14 dec 01) + delay GC to once per sec where possible + ruler preferences + rows only reset on enter, not on dirty + graph.c indents prettily for easier debugging + nasty GC bug nailed + trace prefs options + assert() on program forced close fixed, class redef bug fixed, program window tracks filemodel->modified more closely + region clone menu + destroy regionviews on hide + smarter and simpler layout resize + final (I hope) precedence changes ... now just like C + '<<', '>>', '~' and '@' (function compose) added + row recomp refinement ... simpler and faster + oops, menu items all done in imageview + row locals with external refs were not adding to top level dirties correctly + more rigorous backtracking for deducing recomp order + fancy pantsy heapmodel_reset() system for great justice + traced and optimised recomp ... seldom repeats itself now started 7.7.15 (16/11/01) + rename workspace on top level load + added workspace merge + added column merge + clone stuff done + layout sizing done (tho' not very well) + toggle select and range select for rows + junked all old menus (now in scraps) + fancy new view manager only creates views when required ... x2 speed up on workspace load + file browser lets you change the suffix by typing (eg. type "fred.jpg" into save box while files-of-type is VIPS and you save JPEG) + replace and save matrix and image graphics + new Matrix class hierarchy + .nip-x.x.x directory stuff added, "Preferences" workspace loaded on startup + Watch class for getting pref settings quickly in C + removed all .iprc code + region drag now synchronous, so it can't lag + max heap size scales with workspaces loaded + duplicates automatically removed from paths, system files renamed to user directory on auto load + workspaces reorder correctly + new row number layout scheme using on model pos layout + row drag 'n drop reordering + is_class predicate + Abut.Left_right and Add menu items done as trials + syntax changes to become more C-like: and/or/eor/not keywords removed ... now &&/& ||/| ^ ! & (join) becomes ++ and does list cat too ! (region extract) removed ^ (raise to power) becomes ** + precedences changed to be more C-like ... `\` now binds like array subscript started 7.7.14 + oop, about copyright line was wrong + model now has child_add(), child_remove() methods + child_add() child_remove() used for much init and cleanup ... nice! + fewer typed parent/child pointers in models ... getters to cast model parent/child instead + parent_add(), parent_remove() methods in model + XML prettifier does indenting in save files + load/save moved to model from filemodel + text now loaded too, new rhs child add system + forward references in workspace load now work + simplified _build_display() system with _link() method for view subclasses + new iregiongroupview class for managing sets of region displays + more intelligent naming of objects across workspaces + workspace modified set for more actions ... reflected in mainw titlebar + context pointers are back, but inited from _child/parent_add() system + split to nip package + reworks for new package structure + row_recomp() sorts regeneration by row depth + new scan/reset system + Text now derives from Heapmodel, scrapped the last of the model_link() funcs + _refresh_value() -> _update_model()/_update_heap() pair, with ->modified to control behaviour + _stdenv.def changes ... added is_space, split, splitl, split_lines, parse_pint, parse_int, parse_float + program window parses on popdown + gtkutil has set-2-adjustments-at-once convenience function + all tally models (subcolumn downwards) now derive from Heapmodel + Heapmodel -> Heapmodel/Classmodel + all widget models derive from Classmodel + Text now delays parse/compile until recomp + regenerate system now uniform between graphic and text representations + new model_freeze()/model_thaw() system to reduce model_changed() emissions + XML load/save done for all class widgets + only save edited formula ... deduce others + better target symbol naming for region/point/vector/guide create + dialog boxes now have GNOME2 button ordering ... F1 binds to help + old row_change() mechanism ditched ... much simpler and clearer now + all class.c getters renamed + _update_model() -> _update_model()/_new_heap() pair ... faster + ditched base/derived instance vars, new rebuild from base system from new unified model recomp system + ditched remake-from-base system :-( can no longer do islider ... but much cleaner and more intuitive behaviour + tslider is now a proper widget + better jumping region labels during scroll + switch current column on row select + region labels / image window titles change helpfully on workspace switch + fantastically more complicated row_recomp() now deduces recomp order from dependencies + graphic displays only save and restore their settings if they've been edited + text edit resets edits on sub rows + don't make a display or RHS for system rows (eg. this, check, name) + mainw_countdown_animate() now updates display again ... this may cause problems, have to see :-( + tslider has elaborate workaround for slider destroy during changed callback problems started 7.7.12 + added program window + reworked TODO list ... only 140 issues outstanding ... :-( + toolkitgroup now emits "changed" on any tool/toolkit change + find/find-next thing for program + new info mechanism + link report finds undefined symbols + tree view maintains sort order + model_child_add_before() to aid drag and drop reordering + toolview does menu reordering + popups pass down host widget + general "are you sure you want to remove" for models + destroying a tool now destroys associated symbol too + destroying a toolkit destroys all contained tools + destroying a top level row destroys the symbol + symbol/filemodel/model destroy split to finalize as well + stable owns a ref to syms it holds + if destroy a sym, mark all parents as having "not defined" errors + expr_error_set() now zaps compiled code to force recompile ... ensures user fixes problems properly + textview always recompiles lines which you hit return on + better typecheck error messages for widget classes + right button menu on rulers + xml save + load_text and save_text methods in filemodel.c for tool/toolkit load/save started 7.7.11 + added trace window started 7.7.10 + BI_CONS is lazier and faster started 7.7.9 + "print" builtin added + oops, parse_function() was not passing sym down + better checkargs function + x-ray print menu patched, duh started 7.7.8 + browse now uses new image display code + ooops, PPM/PGM/PBM read added + conversion is now refcounted + all old image/region code removed + old window/dialog code removed + paintbox/edit/magic/menu/calibrate/cursor/request/dragdrop also gone for now + last of X11/Motif gone ... # of lines down 20k! + iregion/iregionview added + finally GNUified it + fixed newimage dialog + region redone as subclass of image + ip class names now have initial caps + better iwindow popdown behavious + imagedisplay implements gtk focus model + imageview key navigation: left-right-up-down-in-out, zoom to fit + imagedisplay repaint probs fixed + new expr_value_new()/_destroy() system to track images + regionview added + cursor manager added to iWindow + jumping region labels! + nasty reduce bug nailed ... heap corrupted if super-class constructor failed + class construction errors handled gracefully + rubberbanding regions on imagepresent + point and vector display types added + ivector/ivectorview added + instance vars can be virtualised by heapmodel ... for code sharing between iregion/ivector/etc. ... sort of a lame MI fudge + regionview morphs between display types if unfrozen + Region/Vector/Point/HGuide/VGuide classes added + lists/image-bands index from zero + mark spine stack on GC ... oops, sometimes broke for nested recomp + reduce.c -> reduce.c/action.c + new action_strict() interface handles nested reduce_spine() calls correctly ... allows mutually recursive locals + some reworking of reduce.c ... still not very pretty :-( started 7.7.7 + [] can have whitespace between the [s + conversion.c added ... manages display conversion model and region/thread display stuff + _list.def and _stdenv.def reworked from Miranda 2 stdenv: foldl function args reversed swap renamed as converse foldl1, foldr1, map2, merge, replicate, scan, until added faster sort (merge sort) + option/optionview pasted back in + image/option parts of sym->recomp scrapped + tslider widget ... entry, plus slider + conversionview ... display control bar + tslider does non-linear sliders + now uses 100%, 25%, 400% etc. to show magnification + oops, mono to labq was broken + statusview.[hc] added ... status bar! + iimage now tracks derived image value as well + better file_info display for JPEG/TIFF/PPM in file load + iimage now just has vips_image as class param + matrix/matrixview added, old mask stuff removed + lots of memory leaks removed (thank you memprof) + workspacegroup is a symbol ... workspaces are named root.Workspaces.blah + matrix resize + matrix load + is_string now defined in _stdenv.def, rather than being built in + vips_call knows about new matrix representation + better scanning system for text widgets + better uop/bop error messages with text_decompile() started 7.7.6 + decompile for parameter edit, value displays parameters (tho not secrets) + save/save as/close added to model + new workspace save done + better notebook tabs + new iWindowSusp stuff now allows composition of window funcs + iDialog now allows multiple OK buttons + Save/Don't save/Cancel on filemodel close + nasty nested iDialog problem found and fixed + close all filemodels on quit + tookit.c -> tool/toolview/toolkit/toolkitview; toolkits are filemodels + all sprintf()s gone + empty/load/replace for filemodel done + workspacegroup/workspacegroupview added + toolkitgroup/toolkitgroupview added + model -> view links removed, signals for 'changed' ... bit simpler n nicer + views track parents and children + scan set for auto re-reads of widgets + reset/scrollto now signals too + now called ip2 + gtkdisp imagedisplay/present/asynch code pasted in + "image" builtin renamed as "vips_image" + image class added + iimage/iimageview added ... thumbnail display! + new (smarter) behaviour for spin expand/shrink; affects rhsview visibility as well as subcolumnview visibility + threaded display code patched in + imageview added + image display rulers, magnification, titlebar wired up to menus started 7.7.5 + better centering of dialogs over their parents + oops, silly bug in stable_resolve() + new expr_resolve() sorts out static/dynamic scoping problems + uses mkstemp() for temp image file names + new mark dirty scheme + small destroy bugfixes + better tallyrow_recomp_rethink() code finds the right expr more often + better binding to root for dynamic exprs + expr_resolve() before expr_check() + "super" member is a regular member, not a parameter + about dialog, with easter egg :-) + new code for recomputation of superclasses ... does "this.x" if any supers change, tracks use of params in super construct + warp focus to column bottom on column select + ':' char banned in file names + workspace load/save/save as/close done + workspace tab menu and tooltip + don't mark zombies dirty clean up of front end started + Symbol extends GtkObject, Workspace extends Symbol + Columnset renamed Workspaceview, members moved between it and Workspace + Column split into Column and Columnview + refresh_note() system added + Model class underpins symbol/workspace/column etc. + tallycolumn -> subcolumn/subcolumnview + tallyrow -> row/rowview + tallyitem -> view + tallyrhs -> rhs/rhsview + text -> text/textview + Heapmodel class added to underpin slider/toggle/option/matpanel + slider -> slider/sliderview + toggle -> toggle/toggleview + mono <-> sRGB gammas both ways now started 7.7.4 + reload $VIPSHOME/lib on menu and plugin reload + no longer includes gtkintl.h + better namecaption API + better iwindow/idialog/namecaption build inheritance + cleaned up naming in main.c + gtkfilesel2 now inherits from idialog + filesel now inherits from gtkfilesel2 + browse now inherits from idialog + now builds cleanly on Sun cc + found horrible gtkfilesel2 bug + fileselect removed + toggle/option/matpanel edit uses idialog + secret optimisation supressed for tally display + edit value (rather than source) for class params + edit reset on column after ENTER + asynch/menu bug fixes backported + Histogram.def renaming + -,/,* for realvec started 7.7.3 + secret now in terms of expr + compile now in terms of expr, not sym + bulletproof errors()/verrors() + resolve_names now knows about tally scopes as well as symbol scopes + linked global recompute and tallyrow recompute up + new link object joins up topsyms for recomputation ... saves a search on tallyrow dirty, makes multiple external refs work + better slider edit dialog + new code for '.' operator now records context in heap, so we can spot dynamic dependencies + improved link objects ... better handling of multiple links, more stuff deduced, support for static and dynamic links + dynamic dependency management + class parameter edit + new spin widget for class display open/close + class member visibility table, controlled by spin widget + new im_vipshome() startup code started 7.7.2 + ws error button colour fix + big sym/expr/row relationship reorganisation + better error handling + better tally tooltips + better toolkit flash help, plus flash for sub menus + fixed some input_push/pop() problems + reorganised main menus, better pull-right display rules + automatic.c -> mainw.c ... lots of renaming and tidying up + multiple workspaces linked to symbols, columnsets now make syms local to their workspaces + iwindow/idialog improvements, newcolumn/workspace dialog is now subclassed off idialog + countdown fixes + another nasty tallyrow destroy bug + error message display fixes started 7.7.1 ... 19/10/00 + another nasty destroy bug + class browser looped for some classes containing errors + default constructor now not displayed (unless overridden in an enclosing class) + recomp inside a class instance done + abs in _stdenv.def failed for complex + nasty gcc error in class_member() with -O2 + tallytext rhs handling broken out into tallyrhs ... tallytext is simpler ... now have graphic/klass/text display + new tallyitem_trigger system with better error propogation + fold/unfold button for class instances + button tooltip displays long messages + tally => row rename + recomp/refresh/refresh_value sequences optimised + expr_clone() now works for function members of classes + refresh_value no longer uses _trigger() propogation mechanism + now tracks prhstext ... everything but the function name ... needed for class edit of local functions + class/super now properties of expr, not sym ... classes are expressions, not symbols + displays args to function members of classes + sym_tab tracks insert order, used to order class members in tally + table_find_child handles hidden children started 7.7.0 + default constructors + escape cancel in idialog + 'root.' and 'workspace.' static scope references + recalc dynamic dependencies on link + super-class constructors are blocked from referring to locals (other than params) + class_member_base() stuff sorted out in slider.c ... usually need non-overridden value + display update block mechanism for tally stops widgets updating themselves + slider text value display redone + fixed a couple of nasty destroy bugs + 'Arithmetic.Add' now does sliders! + released as 7.7.0 nip2-8.7.1/nip2.appdata.xml0000644000175000017500000000224113355423250012324 00000000000000 nip2.desktop CC0-1.0 GPL-2.0+ and LGPL-2.1+ nip2

Image processing spreadsheet

nip2 is a GUI for the VIPS scientific image processing library. It's a little like a spreadsheet: you create a set of formula connecting your images together, and on a change nip2 recalculates.

It can load images in most commonly used formats, but also in scientific formats such as Matlab, FITS, OpenSlide, OpenEXR, and others. nip2 is especially useful with very large images. You can easily work with multi-gigabyte images even on a modest computer.

https://raw.githubusercontent.com/libvips/nip2/master/doc/src/figs/snap1.jpg https://libvips.github.io/libvips https://github.com/libvips/nip2 nip2-8.7.1/nip2.xml0000644000175000017500000000066413351443023010716 00000000000000 VIPS image VIPS image nip2-8.7.1/install-sh0000755000175000017500000003601013417042641011326 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2018-03-11.20; # 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 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 the last 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. -s $stripprog installed files. -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 " 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;; -s) stripcmd=$stripprog;; -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=$? 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 '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # 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 case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) # Note that $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' feature. 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;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or 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 && $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 # 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 -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$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: nip2-8.7.1/config.h.in0000644000175000017500000001671213417043353011355 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ #undef CRAY_STACKSEG_END /* Define to 1 if using `alloca.c'. */ #undef C_ALLOCA /* always defined to indicate that i18n is enabled */ #undef ENABLE_NLS /* The prefix for our gettext translation domains. */ #undef GETTEXT_PACKAGE /* Define to 1 if you have `alloca', as a function or macro. */ #undef HAVE_ALLOCA /* Define to 1 if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H /* Define to 1 if you have the `bind_textdomain_codeset' function. */ #undef HAVE_BIND_TEXTDOMAIN_CODESET /* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the CoreFoundation framework. */ #undef HAVE_CFLOCALECOPYCURRENT /* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in the CoreFoundation framework. */ #undef HAVE_CFPREFERENCESCOPYAPPVALUE /* Define to 1 if you have the `dcgettext' function. */ #undef HAVE_DCGETTEXT /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT /* define if you have fftw3 installed. */ #undef HAVE_FFTW3 /* using flex, rather than lex */ #undef HAVE_FLEX /* Define to 1 if your system has a working POSIX `fnmatch' function. */ #undef HAVE_FNMATCH /* Define to 1 if you have the header file. */ #undef HAVE_FNMATCH_H /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD /* Define to 1 if you have the `geteuid' function. */ #undef HAVE_GETEUID /* Define to 1 if you have the `getpwent' function. */ #undef HAVE_GETPWENT /* Define to 1 if you have the `getpwnam' function. */ #undef HAVE_GETPWNAM /* Define to 1 if you have the `getrlimit' function. */ #undef HAVE_GETRLIMIT /* Define if the GNU gettext() function is already present or preinstalled. */ #undef HAVE_GETTEXT /* Define to 1 if you have the `getwd' function. */ #undef HAVE_GETWD /* define if you have GRegex */ #undef HAVE_GREGEX /* define if you have gsl installed. */ #undef HAVE_GSL /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define if your file defines LC_MESSAGES. */ #undef HAVE_LC_MESSAGES /* define if you have libgoffice installed. */ #undef HAVE_LIBGOFFICE /* define if you have libgsf installed. */ #undef HAVE_LIBGSF /* define if you have libgvc installed. */ #undef HAVE_LIBGVC /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV /* Define to 1 if you have the header file. */ #undef HAVE_PWD_H /* Define to 1 if you have the `regcomp' function. */ #undef HAVE_REGCOMP /* define if you have gdk_window_set_opacity() */ #undef HAVE_SET_OPACITY /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* have strccpy() in -lgen */ #undef HAVE_STRCCPY /* Define to 1 if you have the `strcspn' function. */ #undef HAVE_STRCSPN /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strspn' function. */ #undef HAVE_STRSPN /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STATVFS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_VFS_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF /* define if you have xdg-open */ #undef HAVE_XDG_OPEN /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Major version number */ #undef MAJOR_VERSION /* Micro version number */ #undef MICRO_VERSION /* Minor version number */ #undef MINOR_VERSION /* native Mac OS X */ #undef OS_DARWIN /* native win32 */ #undef OS_WIN32 /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* define if you have GtkInfoBar */ #undef USE_INFOBAR /* define if you have gtk_notebook_set_action_widget() */ #undef USE_NOTEBOOK_ACTION /* define if you have gtk_notebook_set_group_name() */ #undef USE_NOTEBOOK_GROUP_NAME /* Version number of package */ #undef VERSION /* Define if using the dmalloc debugging malloc package */ #undef WITH_DMALLOC /* path of xdg-open binary */ #undef XDG_OPEN /* Define to 1 if lex declares yyleng to be yy_size_t. */ #undef YYLENG_IS_YY_SIZE_T /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `unsigned int' if does not define. */ #undef size_t nip2-8.7.1/proj/0000755000175000017500000000000013351443023010350 500000000000000nip2-8.7.1/proj/README0000644000175000017500000000013313351443023011145 00000000000000sample config and makefiles for building with the MSC toolchain experts only, no support! nip2-8.7.1/proj/src/0000755000175000017500000000000013351443023011137 500000000000000nip2-8.7.1/proj/src/nip.rc0000644000175000017500000000002413351443023012167 00000000000000nip ICON "nip.ico" nip2-8.7.1/proj/src/makefile.msc0000644000175000017500000000723513351443023013347 00000000000000# autogenerated from automake.am with automake.py TOP = ..\.. PRJ_TOP = .. PACKAGE = nip PKG_VER = 7.8.6 !INCLUDE $(TOP)\glib\build\win32\make.msc !IFDEF DEBUG LDFLAGS = $(LDFLAGS) /NODEFAULTLIB:msvcrt !ENDIF top_srcdir = $(PRJ_TOP) top_builddir = $(PRJ_TOP) includedir = $(PRJ_TOP) LT_RELEASE = $(PKG_VER) SUBDIRS = # BITMAPS sub-all: for %d in ($(SUBDIRS)) do nmake -nologo -f makefile.msc sub-one THIS=%d sub-one: cd $(THIS) nmake -nologo -f makefile.msc cd .. YACC = \ @YACC@ -d OBJECTS = \ action.obj \ asynch.obj \ boxes.obj \ browse.obj \ builtin.obj \ class.obj \ colourdisplay.obj \ column.obj \ columnview.obj \ command.obj \ compile.obj \ conversion.obj \ conversionview.obj \ doubleclick.obj \ dump.obj \ expr.obj \ filemodel.obj \ filename.obj \ filenameview.obj \ filesel.obj \ graph.obj \ gtkfilesel2.obj \ gtkmenubar2.obj \ gtkutil.obj \ heap.obj \ heapmodel.obj \ classmodel.obj \ idialog.obj \ iimage.obj \ iimageview.obj \ iregionview.obj \ iregiongroup.obj \ iregiongroupview.obj \ regionview.obj \ iregion.obj \ iarrow.obj \ iarrowview.obj \ imageinfo.obj \ imagedisplay.obj \ imagepresent.obj \ imageview.obj \ iwindow.obj \ led.obj \ link.obj \ main.obj \ mainw.obj \ matrix.obj \ matrixview.obj \ model.obj \ orderitem.obj \ orderlist.obj \ paintboxview.obj \ path.obj \ predicate.obj \ watch.obj \ reduce.obj \ rhs.obj \ rhsview.obj \ row.obj \ rowview.obj \ secret.obj \ slider.obj \ colour.obj \ real.obj \ realview.obj \ option.obj \ tslider.obj \ optionview.obj \ sliderview.obj \ colourview.obj \ spin.obj \ statusview.obj \ subcolumn.obj \ subcolumnview.obj \ symbol.obj \ table.obj \ itext.obj \ itextview.obj \ toggle.obj \ toggleview.obj \ tool.obj \ toolkit.obj \ toolkitgroup.obj \ toolkitgroupview.obj \ toolkitview.obj \ toolview.obj \ trace.obj \ program.obj \ tree.obj \ util.obj \ view.obj \ vips_call.obj \ wild.obj \ workspace.obj \ workspacegroup.obj \ workspacegroupview.obj \ workspaceview.obj \ \ lex.obj \ parse.obj \ ADDONS = \ \ regex.obj \ fnmatch.obj regex.obj : regex.c regex.h $(CC) $(CFLAGS) -GD -c -DREGEX_MALLOC -DHAVE_STRING_H $(PKG_CFLAGS) regex.c $(PACKAGE).res : $(PACKAGE).rc $(PACKAGE).ico rc -r -fo $(PACKAGE).res $(PACKAGE).rc RESOURCE = $(PACKAGE).res EXTRA_DIST = \ doc LDADD = \ @IP_CFLAGS@ @IP_LIBS@ CLEANFILES = \ parse.c \ parse.h \ lex.c \ tags INCLUDES = \ -FI msvc_recommended_pragmas.h \ -DIM_NO_VIPS7_COMPAT \ -I $(PRJ_TOP) -DHAVE_CONFIG_H -I. \ $(VIPS_CFLAGS) \ $(GTK_CFLAGS) -DGTK_ENABLE_BROKEN \ $(LIBXML2_CFLAGS) \ $(DIRENT_CFLAGS) PKG_LINK = \ $(VIPS_LIBS) \ $(GLIB_LIBS) $(GTK_LIBS) \ $(DIRENT_LIBS) \ $(LIBXML2_LIBS) all : \ $(PRJ_TOP)\config.h \ sub-all \ $(PACKAGE).exe # bison --defines --output=parse d:\devel\my-gtk\nip-7.8.6\src\parse.y lex.c : lex.l flex -olex.c lex.l $(PRJ_TOP)\config.h: $(PRJ_TOP)\config.h.win32 copy $(PRJ_TOP)\config.h.win32 $(PRJ_TOP)\config.h RESOURCE = $(PACKAGE).res $(PACKAGE).lib : $(OBJECTS) lib /out:$(PACKAGE).lib $(OBJECTS) $(PACKAGE)-$(PKG_VER).dll : $(OBJECTS) $(PACKAGE).def $(CC) $(CFLAGS) -LD -Fe$(PACKAGE)-$(PKG_VER).dll $(OBJECTS) $(PKG_LINK) user32.lib advapi32.lib wsock32.lib $(LDFLAGS) /def:$(PACKAGE).def $(PACKAGE).exe : $(OBJECTS) $(PACKAGE).res $(CC) $(CFLAGS) -Fe$(PACKAGE).exe $(PACKAGE).res $(OBJECTS) $(PKG_LINK) \ user32.lib advapi32.lib shell32.lib wsock32.lib winspool.lib \ $(LDFLAGS) .c.obj : $(CC) $(CFLAGS) -GD -c $(PKG_CFLAGS) $< nip2-8.7.1/proj/src/nip.ico0000644000175000017500000000137613351443023012350 00000000000000 ( @3333333387wwwwwww88ww88wp88ww88pw88pww80www8www8wwww8ppw8 w8 w8w8wwww88wwp88 888888888333333338wwwwwwwww?nip2-8.7.1/proj/config.h.win320000644000175000017500000000673513351443023012662 00000000000000/* config.h.win32. Handcrafted */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ #undef CRAY_STACKSEG_END /* Define if using `alloca.c'. */ #undef C_ALLOCA /* Define if you have `alloca', as a function or macro. */ #undef HAVE_ALLOCA /* Define if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H /* Define if you have the header file, and it defines `DIR'. */ #define HAVE_DIRENT_H /* Define if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT /* using flex, rather than lex */ #define HAVE_FLEX /* Define if your system has a working `fnmatch' function. */ #undef HAVE_FNMATCH /* Define if you have the `getcwd' function. */ #undef HAVE_GETCWD /* Define if you have the `getwd' function. */ #undef HAVE_GETWD /* Define if you have the header file. */ #undef HAVE_LIMITS_H /* Define if you have the header file. */ #undef HAVE_MALLOC_H /* Define if you have the `mkdir' function. */ #define HAVE_MKTEMP 1 /* what a mess, use glib please! */ #define mktemp(s) _mktemp(s) /* have sys/mount.h */ #undef HAVE_MOUNT_H /* Define if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define if you have the `putenv' function. */ #undef HAVE_PUTENV /* Define if you have the `regcomp' function. */ #undef HAVE_REGCOMP /* have sys/statvfs.h */ #undef HAVE_STATVFS_H /* have strccpy() in -lgen */ #undef HAVE_STRCCPY /* Define if you have the `strcspn' function. */ #undef HAVE_STRCSPN /* Define if you have the `strspn' function. */ #undef HAVE_STRSPN /* Define if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define if you have the header file. */ #undef HAVE_UNISTD_H /* have sys/vfs.h */ #undef HAVE_VFS_H /* Define if you have the `vprintf' function. */ #undef HAVE_VPRINTF /* Name of package */ #define PACKAGE "nip" /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if your declares `struct tm'. */ #undef TM_IN_SYS_TIME #define HAVE_WINDOWS_H /* Version number of package */ #define VERSION "7.8.6" /* Define if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES /* Define to empty if `const' does not conform to ANSI C. */ #undef const #define HAVE__MKDIR //hacky #define PATH_MAX 512 #define strcasecmp(a,b) g_strcasecmp(a,b) nip2-8.7.1/missing0000755000175000017500000001533613417042641010731 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2018 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 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 . # 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 ." 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: nip2-8.7.1/src/0000755000175000017500000000000013417043451010171 500000000000000nip2-8.7.1/src/colourdisplay.c0000644000175000017500000002074213351443023013147 00000000000000/* run the display for an image in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Tag our drag-n-drops with these. */ enum { TARGET_COLOUR, TARGET_TEXT }; static ImagedisplayClass *parent_class = NULL; /* Prefer x-color drags for 3 band non-complex imageinfos, and for LABQ */ static void colourdisplay_set_drag_type( Colourdisplay *colourdisplay ) { static const GtkTargetEntry text_targets[] = { { "text/plain", 0, TARGET_TEXT }, { "application/x-color", 0, TARGET_COLOUR } }; static const GtkTargetEntry colour_targets[] = { { "application/x-color", 0, TARGET_COLOUR }, { "text/plain", 0, TARGET_TEXT } }; Imageinfo *imageinfo = IMAGEDISPLAY( colourdisplay )->conv->ii; IMAGE *im = imageinfo_get( FALSE, imageinfo ); const GtkTargetEntry *targets; if( !GTK_WIDGET_REALIZED( GTK_WIDGET( colourdisplay ) ) || !im ) return; if( im->Bands == 3 && !vips_bandfmt_iscomplex( im->BandFmt ) ) targets = colour_targets; else if( im->Coding == IM_CODING_LABQ ) targets = colour_targets; else targets = text_targets; gtk_drag_dest_unset( GTK_WIDGET( colourdisplay ) ); gtk_drag_dest_set( GTK_WIDGET( colourdisplay ), GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, targets, IM_NUMBER( text_targets ), GDK_ACTION_COPY ); gtk_drag_source_unset( GTK_WIDGET( colourdisplay ) ); gtk_drag_source_set( GTK_WIDGET( colourdisplay ), GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, targets, IM_NUMBER( text_targets ), GDK_ACTION_COPY | GDK_ACTION_MOVE ); } static void colourdisplay_realize( GtkWidget *widget ) { Colourdisplay *colourdisplay = COLOURDISPLAY( widget ); GTK_WIDGET_CLASS( parent_class )->realize( widget ); colourdisplay_set_drag_type( colourdisplay ); } static void colourdisplay_drag_begin( GtkWidget *widget, GdkDragContext *context ) { Colourdisplay *colourdisplay = COLOURDISPLAY( widget ); GtkWidget *window; double colours[4]; GdkColor bg; window = iimageview_drag_window_new( 48, 32 ); gtk_object_set_data_full( GTK_OBJECT( widget ), "nip2-drag-window", window, (GtkDestroyNotify) gtk_widget_destroy ); #ifdef DEBUG printf( "colourdisplay_drag_begin: generating drag swatch colour\n" ); #endif /*DEBUG*/ imageinfo_to_rgb( IMAGEDISPLAY( colourdisplay )->conv->ii, colours ); bg.red = 0xffff * colours[0]; bg.green = 0xffff * colours[1]; bg.blue = 0xffff * colours[2]; gtk_widget_modify_bg( window, GTK_STATE_NORMAL, &bg ); gtk_drag_set_icon_widget( context, window, -2, -2 ); } static void colourdisplay_drag_end( GtkWidget *widget, GdkDragContext *context ) { gtk_object_set_data( GTK_OBJECT( widget ), "nip2-drag-window", NULL ); } static void colourdisplay_drag_data_get( GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time ) { Colourdisplay *colourdisplay = COLOURDISPLAY( widget ); Imageinfo *imageinfo = IMAGEDISPLAY( colourdisplay )->conv->ii; double colours[3]; guint16 vals[4]; char vips_buf_text[256]; VipsBuf buf = VIPS_BUF_STATIC( vips_buf_text ); switch( info ) { case TARGET_COLOUR: imageinfo_to_rgb( imageinfo, colours ); vals[0] = IM_RINT( colours[0] * 0xffff ); vals[1] = IM_RINT( colours[1] * 0xffff ); vals[2] = IM_RINT( colours[2] * 0xffff ); vals[3] = 0xffff; gtk_selection_data_set( selection_data, gdk_atom_intern( "application/x-color", FALSE ), 16, (guchar *) vals, 8 ); #ifdef DEBUG printf( "colourdisplay_drag_data_get: sending x-color\n" ); #endif /*DEBUG*/ break; case TARGET_TEXT: imageinfo_to_text( imageinfo, &buf ); gtk_selection_data_set( selection_data, gdk_atom_intern( "text/plain", FALSE ), 8, (guchar *) vips_buf_all( &buf ), strlen( vips_buf_all( &buf ) ) ); #ifdef DEBUG printf( "colourdisplay_drag_data_get: sending text/plain\n" ); #endif /*DEBUG*/ break; default: g_assert( FALSE ); break; } } static void colourdisplay_drag_data_received( GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time ) { Colourdisplay *colourdisplay = COLOURDISPLAY( widget ); Imageinfo *imageinfo = IMAGEDISPLAY( colourdisplay )->conv->ii; guint16 *vals; gdouble old_rgb[4]; gdouble rgb[4]; if( selection_data->length < 0 ) return; switch( info ) { case TARGET_COLOUR: if( selection_data->format != 16 || selection_data->length != 8 ) return; #ifdef DEBUG printf( "colourdisplay_drag_data_received: seen x-color\n" ); #endif /*DEBUG*/ vals = (guint16 *)selection_data->data; rgb[0] = (double) vals[0] / 0xffff; rgb[1] = (double) vals[1] / 0xffff; rgb[2] = (double) vals[2] / 0xffff; /* Dragging as RGB can't express small differences. So only * accept the new value if it's sufficiently different from * what we have now. */ imageinfo_to_rgb( imageinfo, old_rgb ); if( fabs( rgb[0] - old_rgb[0] ) > (0.5 / 255) || fabs( rgb[1] - old_rgb[1] ) > (0.5 / 255) || fabs( rgb[2] - old_rgb[2] ) > (0.5 / 255) ) imageinfo_from_rgb( imageinfo, rgb ); break; case TARGET_TEXT: if( selection_data->format != 8 ) return; #ifdef DEBUG printf( "colourdisplay_drag_data_received: seen text/plain\n" ); #endif /*DEBUG*/ if( !imageinfo_from_text( imageinfo, (char *) selection_data->data ) ) iwindow_alert( widget, GTK_MESSAGE_ERROR ); break; default: g_assert( FALSE ); break; } } static void colourdisplay_generate_tooltip( Colourdisplay *colourdisplay, VipsBuf *buf ) { Imagedisplay *id = IMAGEDISPLAY( colourdisplay ); if( id->conv && id->conv->ii ) { imageinfo_to_text( id->conv->ii, buf ); vips_buf_appends( buf, "\n" ); vips_buf_appends( buf, _( "Double-click to edit this color, or " "drag-and-drop between colors" ) ); } } static void colourdisplay_conversion_changed( Imagedisplay *id ) { Colourdisplay *colourdisplay = COLOURDISPLAY( id ); IMAGEDISPLAY_CLASS( parent_class )->conversion_changed( id ); if( id->conv ) conversion_set_mag( id->conv, 5000 ); colourdisplay_set_drag_type( colourdisplay ); } static void colourdisplay_class_init( ColourdisplayClass *class ) { GtkWidgetClass *widget_class = (GtkWidgetClass *) class; ImagedisplayClass *imagedisplay_class = (ImagedisplayClass *) class; parent_class = g_type_class_peek_parent( class ); widget_class->realize = colourdisplay_realize; widget_class->drag_begin = colourdisplay_drag_begin; widget_class->drag_end = colourdisplay_drag_end; widget_class->drag_data_get = colourdisplay_drag_data_get; widget_class->drag_data_received = colourdisplay_drag_data_received; imagedisplay_class->conversion_changed = colourdisplay_conversion_changed; } static void colourdisplay_init( Colourdisplay *colourdisplay ) { #ifdef DEBUG printf( "colourdisplay_init\n" ); #endif /*DEBUG*/ /* Who wants to focus one of these :/ */ GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( colourdisplay ), GTK_CAN_FOCUS ); set_tooltip_generate( GTK_WIDGET( colourdisplay ), (TooltipGenerateFn) colourdisplay_generate_tooltip, NULL, NULL ); } GtkType colourdisplay_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Colourdisplay", sizeof( Colourdisplay ), sizeof( ColourdisplayClass ), (GtkClassInitFunc) colourdisplay_class_init, (GtkObjectInitFunc) colourdisplay_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_IMAGEDISPLAY, &info ); } return( type ); } Colourdisplay * colourdisplay_new( Conversion *conv ) { Colourdisplay *colourdisplay = gtk_type_new( TYPE_COLOURDISPLAY ); if( !conv ) conv = conversion_new( NULL ); conversion_set_synchronous( conv, TRUE ); imagedisplay_set_conversion( IMAGEDISPLAY( colourdisplay ), conv ); return( colourdisplay ); } nip2-8.7.1/src/conversion.c0000644000175000017500000007577413351443023012462 00000000000000/* Manage display conversion parameters. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Our signals. */ enum { SIG_AREA_CHANGED, /* Area of repaint image has changed */ SIG_IMAGEINFO_CHANGED, /* The imageinfo we hold has been replaced */ SIG_LAST }; static guint conversion_signals[SIG_LAST] = { 0 }; static ModelClass *parent_class = NULL; /* All active conversions. */ static GSList *conversion_all = NULL; static void * conversion_imageinfo_changed( Conversion *conv ) { #ifdef DEBUG g_print( "conversion_imageinfo_changed: " ); iobject_print( IOBJECT( conv ) ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( conv ), conversion_signals[SIG_IMAGEINFO_CHANGED], 0 ); return( NULL ); } static void conversion_area_changed( Conversion *conv, Rect *dirty ) { g_signal_emit( G_OBJECT( conv ), conversion_signals[SIG_AREA_CHANGED], 0, dirty ); } static void conversion_dispose( GObject *gobject ) { Conversion *conv; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_CONVERSION( gobject ) ); conv = CONVERSION( gobject ); #ifdef DEBUG g_print( "conversion_dispose: " ); iobject_print( IOBJECT( conv ) ); #endif /*DEBUG*/ FREESID( conv->changed_sid, conv->ii ); FREESID( conv->area_changed_sid, conv->ii ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void conversion_finalize( GObject *gobject ) { Conversion *conv; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_CONVERSION( gobject ) ); conv = CONVERSION( gobject ); #ifdef DEBUG g_print( "conversion_finalize: " ); iobject_print( IOBJECT( conv ) ); #endif /*DEBUG*/ conversion_all = g_slist_remove( conversion_all, conv ); IM_FREEF( im_region_free, conv->ireg ); IM_FREEF( im_region_free, conv->mreg ); IM_FREEF( im_region_free, conv->reg ); MANAGED_UNREF( conv->repaint_ii ); MANAGED_UNREF( conv->display_ii ); MANAGED_UNREF( conv->visual_ii ); MANAGED_UNREF( conv->ii ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Make the visualisation image ... eg. we im_histplot histograms, and we * log scale fourier images. */ static IMAGE * conversion_make_visualise( Conversion *conv, IMAGE *in ) { IMAGE *out = im_open( "conversion_make_visualise", "p" ); int tconv = !(conv && conv->enabled && !conv->type); /* Histogram type ... plot the histogram. Keep this old hist display * method in case the goffice plotter is not available. */ if( tconv && in->Type == IM_TYPE_HISTOGRAM && (in->Xsize == 1 || in->Ysize == 1) ) { IMAGE *t[3]; if( in->Coding == IM_CODING_LABQ ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_LabQ2Lab( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Coding == IM_CODING_RAD ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_rad2float( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( im_open_local_array( out, t, 3, "conv-1", "p" ) || im_histnorm( in, t[0] ) || im_histplot( t[0], t[1] ) ) { im_close( out ); return( NULL ); } /* Scale to a sensible size ... aim for a height of 256 * elements. */ if( in->Xsize == 1 && t[1]->Xsize > 256 ) { if( im_subsample( t[1], t[2], t[1]->Xsize / 256, 1 ) ) { im_close( out ); return( NULL ); } } else if( in->Ysize == 1 && t[1]->Ysize > 256 ) { if( im_subsample( t[1], t[2], 1, t[1]->Ysize / 256 ) ) { im_close( out ); return( NULL ); } } else t[2] = t[1]; in = t[2]; } /* IM_TYPE_FOURIER type ... pow/log scale, good for fourier * transforms. */ if( tconv && in->Type == IM_TYPE_FOURIER ) { IMAGE *t[2]; if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_abs( in, t[0] ) || im_scaleps( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( im_copy( in, out ) ) { im_close( out ); return( NULL ); } return( out ); } /* What we send from the notify callback to the main GUI thread. */ typedef struct _ConversionUpdate { Conversion *conv; IMAGE *im; Rect area; } ConversionUpdate; static gboolean conversion_render_idle_cb( gpointer data ) { ConversionUpdate *update = (ConversionUpdate *) data; Conversion *conv = update->conv; /* Must be a valid conversion, must be for the image that that * conversion is still using for display. */ if( g_slist_find( conversion_all, conv ) && imageinfo_get( FALSE, conv->display_ii ) == update->im ) { #ifdef DEBUG g_print( "conversion_update_dispatch: left = %d, top = %d, " "width = %d, height = %d\n", update->area.left, update->area.top, update->area.width, update->area.height ); #endif /*DEBUG*/ /* We need to invalid the main image too, since those * regions will have black in from the failed first calc. * * im_render() can't do this invalidate for us, * it needs to be done from the main loop. * * commented out, vips_sink_screen() now does this for us. * im_invalidate( conv->mask ); im_invalidate( imageinfo_get( FALSE, conv->display_ii ) ); */ conversion_area_changed( conv, &update->area ); } #ifdef DEBUG else g_print( "conversion_render_idle_cb: skipping dead update\n" ); #endif /*DEBUG*/ g_free( update ); return( FALSE ); } /* Here from the im_render() background thread. */ static void conversion_render_notify_cb( IMAGE *im, Rect *area, void *client ) { ConversionUpdate *update = g_new( ConversionUpdate, 1 ); /* Can't use CONVERSION() in this thread ... the GUI thread will check * this pointer for us when it reads from the queue. */ update->conv = (Conversion *) client; update->im = im; update->area = *area; g_idle_add( conversion_render_idle_cb, update ); } /* How many tiles should we ask for? A bit more than the number needed to * paint the screen. */ static int conversion_get_default_tiles( Conversion *conv ) { GdkScreen *screen = gdk_screen_get_default(); int width = gdk_screen_get_width( screen ) / conv->tile_size; int height = gdk_screen_get_height( screen ) / conv->tile_size; return( 2 * width * height ); } /* Resize to screen coordinates and cache it. */ static IMAGE * conversion_make_display( Conversion *conv, IMAGE *in, IMAGE **mask_out ) { IMAGE *out = im_open( "conversion_display:1", "p" ); if( !out ) return( NULL ); if( conv->mag < 0 ) { /* Ordinary image ... use im_subsample(). FIXME ... look for pyramid TIFFs here */ IMAGE *t = im_open_local( out, "conv:s", "p" ); /* Don't shrink by more than the image size (ie. to less than * 1 pixel). */ int xshrink = IM_MIN( -conv->mag, in->Xsize ); int yshrink = IM_MIN( -conv->mag, in->Ysize ); if( DISPLAY_THUMBNAIL_HQ ) { if( !t || im_shrink( in, t, xshrink, yshrink ) ) { im_close( out ); return( NULL ); } } else { if( !t || im_subsample( in, t, xshrink, yshrink ) ) { im_close( out ); return( NULL ); } } in = t; } /* Zoom, if necessary. */ if( conv->mag > 1 ) { IMAGE *t = im_open_local( out, "conv:z", "p" ); if( !t || im_zoom( in, t, conv->mag, conv->mag ) ) { im_close( out ); return( NULL ); } in = t; } /* Cache it. */ if( conv->synchronous ) { if( im_copy( in, out ) ) { im_close( out ); return( NULL ); } } else { IMAGE *mask = im_open_local( out, "conv:r", "p" ); if( im_render_priority( in, out, mask, conv->tile_size, conv->tile_size, conversion_get_default_tiles( conv ), conv->priority, conversion_render_notify_cb, conv ) ) { im_close( out ); return( NULL ); } if( mask_out ) *mask_out = mask; } return( out ); } /* Track during lintrauc. */ typedef struct { double a, b; IMAGE *in, *out; } LintraInfo; /* Define what we do for each band element type. Non-complex input, uchar * output. */ #define LOOP(IN) { \ IN *p = (IN *) in; \ PEL *q = (PEL *) out; \ \ for( x = 0; x < sz; x++ ) { \ double t; \ \ t = a * p[x] + b; \ \ if( t > 255 ) \ t = 255; \ else if( t < 0 ) \ t = 0; \ \ q[x] = t; \ } \ } /* Complex input, uchar output. */ #define LOOPCMPLX(IN) { \ IN *p = (IN *) in; \ PEL *q = (PEL *) out; \ \ for( x = 0; x < sz; x++ ) { \ double t; \ \ t = a * p[x << 1] + b; \ \ if( t > 255 ) \ t = 255; \ else if( t < 0 ) \ t = 0; \ \ q[x] = t; \ } \ } /* Lintra a buffer, 1 set of scale/offset. */ static int lintrauc_gen( PEL *in, PEL *out, int width, IMAGE *im, LintraInfo *inf ) { double a = inf->a; double b = inf->b; int sz = width * im->Bands; int x; /* Lintra all input types. */ switch( im->BandFmt ) { case IM_BANDFMT_UCHAR: LOOP( unsigned char ); break; case IM_BANDFMT_CHAR: LOOP( signed char ); break; case IM_BANDFMT_USHORT: LOOP( unsigned short ); break; case IM_BANDFMT_SHORT: LOOP( signed short ); break; case IM_BANDFMT_UINT: LOOP( unsigned int ); break; case IM_BANDFMT_INT: LOOP( signed int ); break; case IM_BANDFMT_FLOAT: LOOP( float ); break; case IM_BANDFMT_DOUBLE: LOOP( double ); break; case IM_BANDFMT_COMPLEX: LOOPCMPLX( float ); break; case IM_BANDFMT_DPCOMPLEX: LOOPCMPLX( double ); break; default: g_assert( 0 ); } return( 0 ); } /* im_lintra() that writes uchar (the VIPS one writes float/double). */ static int im_lintrauc( double a, IMAGE *in, double b, IMAGE *out ) { LintraInfo *inf; if( in->Coding != IM_CODING_NONE ) { im_error( "im_lintrauc", _( "not uncoded" ) ); return( -1 ); } if( im_cp_desc( out, in ) ) return( -1 ); out->Bbits = IM_BBITS_BYTE; out->BandFmt = IM_BANDFMT_UCHAR; if( !(inf = IM_NEW( out, LintraInfo )) ) return( -1 ); inf->a = a; inf->b = b; inf->in = in; inf->out = out; if( im_wrapone( in, out, (im_wrapone_fn) lintrauc_gen, in, inf ) ) return( -1 ); return( 0 ); } /* Turn any IMAGE into a 1/3 band IM_BANDFMT_UCHAR ready for gdk_rgb_*(). */ static IMAGE * conversion_make_repaint( Conversion *conv, IMAGE *in ) { IMAGE *out = im_open( "conversion_apply:1", "p" ); /* 7 is sRGB. this is all deprecated and unused now with vips-7.31 and later tag as unused to stop gcc complaints */ struct im_col_display *display __attribute__ ((unused)) = im_col_displays( 7 ); /* Do we do colorimetric type conversions? Look for * interpret-type-toggle. */ int tconv = !(conv && conv->enabled && !conv->type); if( !out ) return( NULL ); /* Special case: if this is a IM_CODING_LABQ and the display control * bar is turned off, we can go straight to RGB for speed. */ if( in->Coding == IM_CODING_LABQ && !(conv && conv->enabled) ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); static void *table = NULL; /* Make sure fast LabQ2disp tables are built. */ if( !table ) table = im_LabQ2disp_build_table( NULL, display ); if( !t || im_LabQ2disp_table( in, t, table ) ) { im_close( out ); return( NULL ); } in = t; } /* Get the bands right. If we have >3, drop down to 3. If we have 2, * drop down to 1. */ if( in->Coding == IM_CODING_NONE ) { if( in->Bands == 2 ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_extract_band( in, t, 0 ) ) { im_close( out ); return( NULL ); } in = t; } else if( in->Bands > 3 ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_extract_bands( in, t, 0, 3 ) ) { im_close( out ); return( NULL ); } in = t; } } /* Interpret the Type field for colorimetric images. */ if( tconv && in->Bands == 3 && in->BandFmt == IM_BANDFMT_SHORT && in->Type == IM_TYPE_LABS ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_LabS2LabQ( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Coding == IM_CODING_LABQ ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_LabQ2Lab( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Coding == IM_CODING_RAD ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_rad2float( in, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Coding != IM_CODING_NONE ) { im_close( out ); return( NULL ); } /* One of the colorimetric types? */ if( tconv && in->Bands == 3 && (in->Type == IM_TYPE_LCH || in->Type == IM_TYPE_YXY || in->Type == IM_TYPE_UCS || #if VIPS_MAJOR_VERSION > 7 || VIPS_MINOR_VERSION > 32 /* scRGB colourspace added in 7.32. */ in->Type == VIPS_INTERPRETATION_scRGB || #endif in->Type == IM_TYPE_LAB || in->Type == IM_TYPE_XYZ) ) { IMAGE *t[2]; /* We need to scale/offset before we go to 8 bit to work well * with HDR. */ if( conv && conv->enabled && (conv->scale != 1.0 || conv->offset != 0.0) ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_lintra( conv->scale, in, conv->offset, t ) ) { im_close( out ); return( NULL ); } in = t; } if( in->Type == IM_TYPE_LCH ) { if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_LCh2Lab( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } #if VIPS_MAJOR_VERSION > 7 || VIPS_MINOR_VERSION > 32 if( in->Type == VIPS_INTERPRETATION_scRGB ) { VipsImage *x; if( vips_scRGB2sRGB( in, &x, NULL ) ) { im_close( out ); return( NULL ); } vips_object_local( out, x ); in = x; } #endif if( in->Type == IM_TYPE_YXY ) { if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_Yxy2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Type == IM_TYPE_UCS ) { if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_UCS2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Type == IM_TYPE_LAB ) { if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_Lab2XYZ( t[0], t[1] ) ) { im_close( out ); return( NULL ); } in = t[1]; } if( in->Type == IM_TYPE_XYZ ) { if( im_open_local_array( out, t, 2, "conv-1", "p" ) || im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || im_XYZ2disp( t[0], t[1], display ) ) { im_close( out ); return( NULL ); } in = t[1]; } } else { /* Not colorimetric. We can use a special ->uchar lintra for * scale/offset. Don't scale/offset fourier or histogram * images, they are presented above. */ if( conv && conv->enabled && (!tconv || in->Type != IM_TYPE_FOURIER) && (!tconv || in->Type != IM_TYPE_HISTOGRAM) && (conv->scale != 1.0 || conv->offset != 0.0) ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_lintrauc( conv->scale, in, conv->offset, t ) ) { im_close( out ); return( NULL ); } in = t; } } if( tconv && (in->Type == IM_TYPE_RGB16 || in->Type == IM_TYPE_GREY16) ) { IMAGE *t[1]; if( im_open_local_array( out, t, 1, "conv-1", "p" ) ) { im_close( out ); return( NULL ); } /* im_msb() only works for the int formats. */ if( vips_bandfmt_isint( in->BandFmt ) ) { if( im_msb( in, t[0] ) ) { im_close( out ); return( NULL ); } } else { if( im_lintrauc( 1 / 256.0, in, 0.0, t[0] ) ) { im_close( out ); return( NULL ); } } in = t[0]; } /* Clip to uchar if not there already. */ if( in->BandFmt != IM_BANDFMT_UCHAR ) { IMAGE *t = im_open_local( out, "conv:1", "p" ); if( !t || im_clip2fmt( in, t, IM_BANDFMT_UCHAR ) ) { im_close( out ); return( NULL ); } in = t; } /* Falsecolour. Just use the green channel if we're RGB. */ if( conv && conv->enabled && conv->falsecolour ) { IMAGE *t1 = im_open_local( out, "conv:1", "p" ); if( !t1 ) { im_close( out ); return( NULL ); } if( in->Bands == 3 ) { IMAGE *t2 = im_open_local( out, "conv:1", "p" ); if( im_extract_band( in, t2, 1 ) ) { im_close( out ); return( NULL ); } in = t2; } if( im_falsecolour( in, t1 ) ) { im_close( out ); return( NULL ); } in = t1; } if( im_copy( in, out ) ) { im_close( out ); return( NULL ); } return( out ); } /* Controls in the display conversion bar, or the display image have changed. * Remake the repaint image. */ static void conversion_rebuild_repaint( Conversion *conv ) { IMAGE *display_im; IMAGE *new_repaint_im; Imageinfo *new_repaint_ii; REGION *new_ireg; #ifdef DEBUG g_print( "conversion_remake_repaint: %p\n", conv ); #endif /*DEBUG*/ if( conv->display_ii ) display_im = imageinfo_get( FALSE, conv->display_ii ); else display_im = NULL; /* Keep gcc quiet about annoying possible-used-before-set warnings. */ new_repaint_ii = NULL; new_ireg = NULL; /* Make the new stuff first. */ if( display_im ) { if( !(new_repaint_im = conversion_make_repaint( conv, display_im )) ) return; if( !(new_repaint_ii = imageinfo_new( main_imageinfogroup, NULL, new_repaint_im, NULL )) ) { im_close( new_repaint_im ); return; } managed_sub_add( MANAGED( new_repaint_ii ), MANAGED( conv->display_ii ) ); if( !(new_ireg = im_region_create( new_repaint_im )) ) return; } IM_FREEF( im_region_free, conv->ireg ); MANAGED_UNREF( conv->repaint_ii ); if( display_im ) { conv->repaint_ii = new_repaint_ii; MANAGED_REF( conv->repaint_ii ); conv->ireg = new_ireg; } } /* The magnification or the visual image have changed ... remake the * display image. */ static void conversion_rebuild_display( Conversion *conv ) { IMAGE *visual_im; IMAGE *new_display_im; Imageinfo *new_display_ii; IMAGE *mask; REGION *new_mreg; #ifdef DEBUG g_print( "conversion_remake_display: %p\n", conv ); #endif /*DEBUG*/ if( conv->visual_ii ) visual_im = imageinfo_get( FALSE, conv->visual_ii ); else visual_im = NULL; /* Keep gcc quiet about annoying possible-used-before-set warnings. */ new_display_ii = NULL; new_display_im = NULL; new_mreg = NULL; mask = NULL; /* Make the new stuff first. */ if( visual_im ) { if( !(new_display_im = conversion_make_display( conv, visual_im, &mask )) ) return; if( !(new_display_ii = imageinfo_new( main_imageinfogroup, NULL, new_display_im, NULL )) ) { im_close( new_display_im ); return; } managed_sub_add( MANAGED( new_display_ii ), MANAGED( conv->visual_ii ) ); if( mask && !(new_mreg = im_region_create( mask )) ) return; } IM_FREEF( im_region_free, conv->mreg ); MANAGED_UNREF( conv->display_ii ); if( visual_im ) { conv->display_ii = new_display_ii; conv->mask = mask; conv->mreg = new_mreg; MANAGED_REF( conv->display_ii ); conv->canvas.width = new_display_im->Xsize; conv->canvas.height = new_display_im->Ysize; } /* Certainly need a new repaint image. */ conversion_rebuild_repaint( conv ); } /* The underlying ii has changed. Remake the visualisation image. */ static void conversion_rebuild_visual( Conversion *conv ) { IMAGE *im = imageinfo_get( FALSE, conv->ii ); IMAGE *new_visual_im; Imageinfo *new_visual_ii; REGION *new_reg; #ifdef DEBUG g_print( "conversion_rebuild_visual: %p\n", conv ); #endif /*DEBUG*/ /* Keep gcc quiet about annoying possible-used-before-set warnings. */ new_visual_im = NULL; new_visual_ii = NULL; new_reg = NULL; /* Make new visualization image. */ if( im ) { if( !(new_visual_im = conversion_make_visualise( conv, im )) ) return; if( !(new_visual_ii = imageinfo_new( main_imageinfogroup, NULL, new_visual_im, NULL )) ) { im_close( new_visual_im ); return; } managed_sub_add( MANAGED( new_visual_ii ), MANAGED( conv->ii ) ); if( !(new_reg = im_region_create( im )) ) return; } /* Junk old stuff. */ IM_FREEF( im_region_free, conv->reg ); MANAGED_UNREF( conv->visual_ii ); /* Install new stuff. */ if( im ) { conv->visual_ii = new_visual_ii; MANAGED_REF( conv->visual_ii ); conv->image.width = new_visual_im->Xsize; conv->image.height = new_visual_im->Ysize; conv->reg = new_reg; } /* Certainly need a new display. */ conversion_rebuild_display( conv ); } /* Something has changed ... check it out. */ static void conversion_changed( iObject *iobject ) { Conversion *conv = CONVERSION( iobject ); gboolean rebuild_display = FALSE; gboolean rebuild_repaint = FALSE; #ifdef DEBUG g_print( "conversion_changed: %p\n", conv ); #endif /*DEBUG*/ /* Need to remake the display image if mag has changed. */ if( conv->mag != conv->display_mag ) { rebuild_display = TRUE; conv->display_mag = conv->mag; } /* Need to rebuild repaint if display control bar has changed. */ if( conv->changed ) { conv->changed = FALSE; rebuild_repaint = TRUE; } if( rebuild_display ) conversion_rebuild_display( conv ); else if( rebuild_repaint ) conversion_rebuild_repaint( conv ); IOBJECT_CLASS( parent_class )->changed( iobject ); } static void conversion_class_init( ConversionClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = conversion_dispose; gobject_class->finalize = conversion_finalize; iobject_class->changed = conversion_changed; /* Create signals. */ conversion_signals[SIG_AREA_CHANGED] = g_signal_new( "area_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ConversionClass, area_changed ), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER ); conversion_signals[SIG_IMAGEINFO_CHANGED] = g_signal_new( "imageinfo_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ConversionClass, imageinfo_changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); } static void conversion_init( Conversion *conv ) { static const Rect emptyrect = { 0, 0, 0, 0 }; #ifdef DEBUG g_print( "conversion_init: " ); iobject_print( IOBJECT( conv ) ); #endif /*DEBUG*/ conv->ii = NULL; conv->changed_sid = 0; conv->area_changed_sid = 0; conv->reg = NULL; conv->synchronous = FALSE; conv->priority = 0; conv->visual_ii = NULL; conv->display_ii = NULL; conv->display_mag = 99999999; conv->repaint_ii = NULL; conv->ireg = NULL; conv->mreg = NULL; /* Default tile size ... OK for image display, too big for * thumbnails. */ conv->tile_size = 64; conv->underlay = emptyrect; conv->image = emptyrect; conv->canvas = emptyrect; conv->visible = emptyrect; conv->mag = 1; conv->changed = FALSE; conv->enabled = FALSE; conv->scale = 1.0; conv->offset = 0.0; conv->falsecolour = FALSE; conv->type = TRUE; conversion_all = g_slist_prepend( conversion_all, conv ); } GType conversion_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ConversionClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) conversion_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Conversion ), 32, /* n_preallocs */ (GInstanceInitFunc) conversion_init, }; type = g_type_register_static( TYPE_MODEL, "Conversion", &info, 0 ); } return( type ); } static void conversion_link( Conversion *conv, Imageinfo *ii ) { iobject_set( IOBJECT( conv ), "display_conversion", NULL ); conversion_set_image( conv, ii ); } Conversion * conversion_new( Imageinfo *ii ) { Conversion *conv; conv = CONVERSION( g_object_new( TYPE_CONVERSION, NULL ) ); conversion_link( conv, ii ); return( conv ); } /* Imageinfo has changed signal. The ii is the same, but the image it * represents may have changed from "p" to "r" or whatever. Assume size/etc. * stay the same. */ static void conversion_ii_changed_cb( Imageinfo *ii, Conversion *conv ) { conversion_rebuild_visual( conv ); iobject_changed( IOBJECT( conv ) ); } /* Something like a paint action on the ii. */ static void conversion_ii_area_changed_cb( Imageinfo *imageinfo, Rect *dirty, Conversion *conv ) { Rect repaint; conversion_im_to_disp_rect( conv, dirty, &repaint ); conversion_area_changed( conv, &repaint ); } /* Install a new image. */ void conversion_set_image( Conversion *conv, Imageinfo *ii ) { /* Pointer compare is safe, since we hold a ref to conv->ii and it * can't have been freed. So we can't have a new ii at the same * address as the old ii. */ if( conv->ii != ii ) { IMAGE *im; if( ii ) im = imageinfo_get( FALSE, ii ); else im = NULL; /* Junk old stuff. */ FREESID( conv->changed_sid, conv->ii ); FREESID( conv->area_changed_sid, conv->ii ); MANAGED_UNREF( conv->ii ); conv->image.width = -1; conv->image.height = -1; /* Install new stuff. */ if( ii ) { conv->ii = ii; MANAGED_REF( conv->ii ); conv->changed_sid = g_signal_connect( G_OBJECT( ii ), "changed", G_CALLBACK( conversion_ii_changed_cb ), conv ); conv->area_changed_sid = g_signal_connect( G_OBJECT( ii ), "area_changed", G_CALLBACK( conversion_ii_area_changed_cb ), conv ); } if( im ) { conv->underlay.width = im->Xsize; conv->underlay.height = im->Ysize; } /* Make new visualization image. */ conversion_rebuild_visual( conv ); /* Tell everyone about our new ii. */ conversion_imageinfo_changed( conv ); } iobject_changed( IOBJECT( conv ) ); } double conversion_dmag( int mag ) { g_assert( mag != 0 ); if( mag > 0 ) return( mag ); else return( 1.0 / (-mag) ); } /* Zoom in and zoom out scale factors ... a little tricky with our funny -ve * representation for subsample. */ int conversion_double( int mag ) { g_assert( mag != -1 ); if( mag == -3 ) return( -2 ); else if( mag == -2 ) return( 1 ); else if( mag > 0 ) return( mag * 2 ); else return( mag / 2 ); } int conversion_halve( int mag ) { g_assert( mag != -1 ); if( mag == 1 ) return( -2 ); else if( mag > 1 ) return( mag / 2 ); else return( mag * 2 ); } /* Convert display to image coordinates and back. */ void conversion_disp_to_im( Conversion *conv, int dx, int dy, int *ix, int *iy ) { double fmag = conversion_dmag( conv->mag ); *ix = (int) (dx / fmag); *iy = (int) (dy / fmag); } void conversion_im_to_disp( Conversion *conv, int ix, int iy, int *dx, int *dy ) { double fmag = conversion_dmag( conv->mag ); *dx = (int) (ix * fmag); *dy = (int) (iy * fmag); } /* Same for rects. */ void conversion_disp_to_im_rect( Conversion *conv, Rect *dr, Rect *ir ) { double fmag = conversion_dmag( conv->mag ); int brx, bry; Rect out; out.left = floor( dr->left / fmag ); out.top = floor( dr->top / fmag ); brx = ceil( IM_RECT_RIGHT( dr ) / fmag ); bry = ceil( IM_RECT_BOTTOM( dr ) / fmag ); out.width = brx - out.left; out.height = bry - out.top; *ir = out; } void conversion_im_to_disp_rect( Conversion *conv, Rect *ir, Rect *dr ) { double fmag = conversion_dmag( conv->mag ); int brx, bry; Rect out; out.left = floor( ir->left * fmag ); out.top = floor( ir->top * fmag ); brx = ceil( IM_RECT_RIGHT( ir ) * fmag ); bry = ceil( IM_RECT_BOTTOM( ir ) * fmag ); out.width = brx - out.left; out.height = bry - out.top; *dr = out; } void conversion_set_mag( Conversion *conv, int mag ) { int x, y; /* Mag 0 means scale image to fit window. Use visible hint in * conversion to pick the mag. */ if( mag == 0 ) { float xfac; float yfac; float fac; /* Need to have image and visible set. */ if( conv->visible.width <= 0 || conv->image.width <= 0 || !conv->ii || !conv->ii->im ) return; xfac = (float) conv->visible.width / conv->image.width; yfac = (float) conv->visible.height / conv->image.height; fac = IM_MIN( xfac, yfac ); if( fac >= 1 ) mag = (int) fac; else /* 0.999 means we don't round up on an exact fit. FIXME ... yuk */ mag = -((int) (0.99999999 + 1.0/fac)); #ifdef DEBUG g_print( "conversion_set_mag: shrink to fit:\n" ); g_print( " visible %dx%d, image %dx%d\n", conv->visible.width, conv->visible.height, conv->image.width, conv->image.height ); g_print( " picked mag of %d\n", mag ); #endif /*DEBUG*/ } /* Check for this-mag-will-cause-integer-overflow. Should flag an * error, but we just bail out instead. */ if( mag > 0 && ((double) conv->image.width * mag > (double) INT_MAX / 2 || (double) conv->image.height * mag > (double) INT_MAX / 2) ) return; /* Will this mag result in width/height of <1? If it will, pick a * mag that most nearly gives us width/height 1. */ conv->mag = mag; conversion_im_to_disp( conv, conv->image.width, conv->image.height, &x, &y ); if( x <= 0 || y <= 0 ) { conv->mag = IM_MAX( -conv->image.width, -conv->image.height ); if( conv->mag == -1 ) conv->mag = 1; } if( conv->mag != conv->display_mag ) iobject_changed( IOBJECT( conv ) ); } void conversion_set_synchronous( Conversion *conv, gboolean synchronous ) { if( conv->synchronous != synchronous ) { #ifdef DEBUG printf( "conversion_set_synchronous: %d", synchronous ); iobject_print( IOBJECT( conv ) ); #endif /*DEBUG*/ conv->synchronous = synchronous; if( conv->ii ) iobject_changed( IOBJECT( conv->ii ) ); } } void conversion_set_params( Conversion *conv, gboolean enabled, double scale, double offset, gboolean falsecolour, gboolean type ) { gboolean changed = FALSE; if( conv->enabled != enabled ) changed = TRUE; if( enabled ) if( conv->scale != scale || conv->offset != offset || conv->falsecolour != falsecolour || conv->type != type ) changed = TRUE; if( changed ) { conv->enabled = enabled; conv->scale = scale; conv->offset = offset; conv->falsecolour = falsecolour; conv->type = type; conv->changed = TRUE; iobject_changed( IOBJECT( conv ) ); } } nip2-8.7.1/src/filesel.h0000644000175000017500000001071713351443023011707 00000000000000/* Declarations for ifileselect.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* How we define a file type. Pass a NULL-terminated array of pointers * to these puppies to gtk_file_selection2_set_file_types(). * gtk_file_selection2_set_file_types() makes a copy of the data itself, * so you can free if you want. */ typedef struct _FileselFileType { /* Descriptive name for this file type. Eg: * "TIFF image file (*.tif; *.tiff)" */ const char *name; /* NULL-terminated array of suffixes identifying this * file type. Put the default first. Eg: * { ".tif", ".tiff", NULL }, or * { ".htm", ".html", NULL } */ const char **suffixes; } FileselFileType; /* Basic types. */ extern FileselFileType filesel_wfile_type, filesel_rfile_type, filesel_mfile_type, filesel_cfile_type, filesel_xfile_type, filesel_dfile_type, filesel_ifile_type; /* Suffix sets we support. */ extern FileselFileType *filesel_type_definition[]; extern FileselFileType *filesel_type_workspace[]; extern FileselFileType *filesel_type_matrix[]; extern FileselFileType **filesel_type_image; extern FileselFileType **filesel_type_mainw; extern FileselFileType **filesel_type_any; /* Subclass off gtkfilesel2.c to make one of our fileselectors. */ #define TYPE_FILESEL (filesel_get_type()) #define FILESEL( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_FILESEL, Filesel )) #define FILESEL_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_FILESEL, FileselClass )) #define IS_FILESEL( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FILESEL )) #define IS_FILESEL_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_FILESEL )) /* Must be enough. */ #define FILESEL_MAX_FILTERS (100) typedef struct _Filesel { iDialog parent; /* Widgets. */ GtkWidget *chooser; /* Filechooser widget */ GtkWidget *space; /* Space available */ GtkWidget *info; /* File info */ Preview *preview; /* Selected file preview */ GtkFileFilter *filter[FILESEL_MAX_FILTERS]; /* State. */ gboolean incr; /* True for increment filename */ gboolean imls; /* True if this is image load/save */ gboolean save; /* True if this is a save dialog */ gboolean multi; /* Multiple-select */ gboolean start_name; /* True if we have a suggested name */ FileselFileType **type; /* Allowable types for this filesel */ int ntypes; int default_type; const char *type_pref; /* Pref to set on type change */ /* Last dir we entered. Used to stop dir_changed being emitted too * often. */ char *current_dir; iWindowFn done_cb; /* On OK */ void *client; } Filesel; typedef struct _FileselClass { iDialogClass parent_class; /* My methods. */ } FileselClass; void filesel_startup( void ); gboolean is_file_type( const FileselFileType *type, const char *filename ); typedef void *(*FileselMapFn)( Filesel *, const char *, void *, void * ); void filesel_add_mode( char *filename ); GtkType filesel_get_type( void ); GtkWidget *filesel_new( void ); gboolean filesel_set_filename( Filesel *filesel, const char *name ); char *filesel_get_filename( Filesel *filesel ); void *filesel_map_filename_multi( Filesel *filesel, FileselMapFn fn, void *a, void *b ); void filesel_set_done( Filesel *filesel, iWindowFn done_cb, void *client ); void filesel_set_filetype( Filesel *filesel, FileselFileType **type, int default_type ); void filesel_set_filetype_pref( Filesel *filesel, const char *type_pref ); int filesel_get_filetype( Filesel *filesel ); void filesel_make_patt( FileselFileType *type, VipsBuf *patt ); void filesel_set_flags( Filesel *filesel, gboolean imls, gboolean save ); void filesel_set_multi( Filesel *filesel, gboolean multi ); nip2-8.7.1/src/regionview.c0000644000175000017500000014723313351443023012441 00000000000000/* run the displays for regions on images */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Verbose. #define DEBUG */ /* Just trace create/destroy. #define DEBUG_MAKE */ /* Trace grab/ungrab #define DEBUG_GRAB */ /* Define this to trace event propogation #define EVENT */ /* See paint events. #define DEBUG_PAINT */ /* Define this to make region drags default to no-update during drag/resize. #define NO_UPDATE */ #include "ip.h" typedef void *(*regionview_rect_fn)( Regionview *, Rect *, void * ); typedef void (*regionview_paint_fn)( Regionview * ); /* Cursor shape for each resize type. */ iWindowShape regionview_cursors[REGIONVIEW_RESIZE_LAST] = { IWINDOW_SHAPE_EDIT, /* REGIONVIEW_RESIZE_NONE */ IWINDOW_SHAPE_MOVE, /* REGIONVIEW_RESIZE_MOVE */ IWINDOW_SHAPE_MOVE, /* REGIONVIEW_RESIZE_EDIT */ IWINDOW_SHAPE_TOPLEFT, /* REGIONVIEW_RESIZE_TOPLEFT */ IWINDOW_SHAPE_TOP, /* REGIONVIEW_RESIZE_TOP */ IWINDOW_SHAPE_TOPRIGHT, /* REGIONVIEW_RESIZE_TOPRIGHT */ IWINDOW_SHAPE_RIGHT, /* REGIONVIEW_RESIZE_RIGHT */ IWINDOW_SHAPE_BOTTOMRIGHT, /* REGIONVIEW_RESIZE_BOTTOMRIGHT */ IWINDOW_SHAPE_BOTTOM, /* REGIONVIEW_RESIZE_BOTTOM */ IWINDOW_SHAPE_BOTTOMLEFT, /* REGIONVIEW_RESIZE_BOTTOMLEFT */ IWINDOW_SHAPE_LEFT /* REGIONVIEW_RESIZE_LEFT */ }; /* Region border width, without shadows. */ static const int regionview_border_width = 2; /* Space around text in label. */ static const int regionview_label_border = 5; /* Length of crosshair bars. */ static const int regionview_crosshair_length = 5; /* The center of the crosshair is also sensitive for arrows. */ static const int regionview_crosshair_centre = 8; /* How close you need to get to switch the type. */ static const int regionview_morph_threshold = 20; static ViewClass *parent_class = NULL; /* Just one popup for all regions. */ static GtkWidget *regionview_popup_menu = NULL; /* Paint a rectangle. */ void regionview_paint_rect( GdkDrawable *draw, GdkGC *gc, Rect *r ) { gdk_draw_rectangle( draw, gc, FALSE, r->left, r->top, IM_MAX( 0, r->width - 1 ), IM_MAX( 0, r->height - 1 ) ); } /* Paint a thick rectangle. */ void regionview_paint_rect_thick( GdkDrawable *draw, GdkGC *gc, Rect *r, int n ) { Rect our_r; int i; our_r = *r; for( i = 0; i < n; i++ ) { regionview_paint_rect( draw, gc, &our_r ); im_rect_marginadjust( &our_r, 1 ); } } /* Paint a rect in 3D --- pass a GC for the top-left and a gc for the * bottom-right shadows. */ static void regionview_paint_rect_3d( GdkDrawable *draw, GdkGC *tl, GdkGC *br, Rect *r ) { /* Bottom and right. */ gdk_draw_line( draw, br, IM_RECT_RIGHT( r ) - 1, r->top, IM_RECT_RIGHT( r ) - 1, IM_RECT_BOTTOM( r ) - 1 ); gdk_draw_line( draw, br, IM_RECT_RIGHT( r ) - 1, IM_RECT_BOTTOM( r ) - 1, r->left, IM_RECT_BOTTOM( r ) - 1 ); /* Top and left. */ gdk_draw_line( draw, tl, r->left, IM_RECT_BOTTOM( r ) - 1, r->left, r->top ); gdk_draw_line( draw, tl, r->left, r->top, IM_RECT_RIGHT( r ) - 1, r->top ); } /* Paint little ticks ... for marking the edges of the resize handles. */ static void regionview_paint_vtick( GdkDrawable *draw, GdkGC *tl, GdkGC *br, int x, int y, int n ) { gdk_draw_line( draw, br, x, y - 1, x, y - n ); gdk_draw_line( draw, tl, x + 1, y - 1, x + 1, y - n ); } static void regionview_paint_htick( GdkDrawable *draw, GdkGC *tl, GdkGC *br, int x, int y, int n ) { gdk_draw_line( draw, br, x - 1, y, x - n, y ); gdk_draw_line( draw, tl, x - 1, y + 1, x - n, y + 1 ); } /* Paint a region border, enclosing the pixels in r. */ static void regionview_paint_border( GdkDrawable *draw, GdkGC *tl, GdkGC *bg, GdkGC *br, Rect *r, gboolean locked ) { int n = regionview_border_width; Rect our_r = *r; im_rect_marginadjust( &our_r, 1 ); regionview_paint_rect_3d( draw, br, tl, &our_r ); im_rect_marginadjust( &our_r, 1 ); regionview_paint_rect_thick( draw, bg, &our_r, n ); im_rect_marginadjust( &our_r, n ); regionview_paint_rect_3d( draw, tl, br, &our_r ); /* Add little tick marks for corner resizing. Don't bother for very * small rects, or for locked rects. */ if( !locked && r->width > 20 ) { /* Top edge. */ regionview_paint_vtick( draw, tl, br, r->left + 10, r->top - 1, n ); regionview_paint_vtick( draw, tl, br, IM_RECT_RIGHT( r ) - 11, r->top - 1, n ); /* Bottom edge. */ regionview_paint_vtick( draw, tl, br, r->left + 10, IM_RECT_BOTTOM( r ) + n + 1, n ); regionview_paint_vtick( draw, tl, br, IM_RECT_RIGHT( r ) - 11, IM_RECT_BOTTOM( r ) + n + 1, n ); } if( !locked && r->height > 20 ) { /* Left edge. */ regionview_paint_htick( draw, tl, br, r->left - 1, r->top + 10, n ); regionview_paint_htick( draw, tl, br, r->left - 1, IM_RECT_BOTTOM( r ) - 12, n ); /* Right edge. */ regionview_paint_htick( draw, tl, br, IM_RECT_RIGHT( r ) + n + 1, r->top + 10, n ); regionview_paint_htick( draw, tl, br, IM_RECT_RIGHT( r ) + n + 1, IM_RECT_BOTTOM( r ) - 12, n ); } } /* Paint a square area, with a beveled edge. */ static void regionview_paint_area( GdkDrawable *draw, GdkGC *tl, GdkGC *bg, GdkGC *br, Rect *r ) { gdk_draw_rectangle( draw, bg, TRUE, r->left, r->top, r->width, r->height ); regionview_paint_rect_3d( draw, tl, br, r ); } /* Paint a region label. */ static void regionview_paint_label( Regionview *regionview, GdkDrawable *draw, Rect *r, int ascent, const char *txt ) { GtkWidget *widget = GTK_WIDGET( regionview->ip->id ); int n = regionview_label_border; PangoLayout *layout; GdkRectangle grect; /* Clip to this area ... don't want to paint outside label. */ grect.x = r->left; grect.y = r->top; grect.width = r->width; grect.height = r->height; gtk_paint_flat_box( widget->style, draw, regionview->paint_state, GTK_SHADOW_OUT, &grect, widget, "buttondefault", grect.x, grect.y, grect.width, grect.height ); /* Paint text over the top. */ layout = gtk_widget_create_pango_layout( widget, txt ); gtk_paint_layout( widget->style, draw, regionview->paint_state, FALSE, &grect, widget, NULL, r->left + n, r->top + n + ascent, layout ); g_object_unref( layout ); } /* Paint a crosshair, centered at x, y. */ static void regionview_paint_crosshair( GdkDrawable *draw, GdkGC *tl, GdkGC *bg, GdkGC *br, int x, int y ) { const int bw = regionview_border_width / 2 + 1; const int l = regionview_crosshair_length + 2; Rect area; area.left = x - bw - 1 - l; area.top = y - bw; area.width = l; area.height = bw * 2; regionview_paint_area( draw, tl, bg, br, &area ); area.left = x + bw + 1; regionview_paint_area( draw, tl, bg, br, &area ); area.left = x - bw; area.top = y - bw - 1 - l; area.width = bw * 2; area.height = l; regionview_paint_area( draw, tl, bg, br, &area ); area.top = y + bw + 1; regionview_paint_area( draw, tl, bg, br, &area ); } /* Paint the dotted line connecting an arrow or a guide. */ static void regionview_paint_arrow( GdkDrawable *draw, GdkGC *fg, int off, Rect *r ) { static gint8 dash_list[] = { 10, 10 }; gdk_gc_set_dashes( fg, off, dash_list, 2 ); gdk_gc_set_line_attributes( fg, 2, GDK_LINE_DOUBLE_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER ); gdk_draw_line( draw, fg, r->left, r->top, IM_RECT_RIGHT( r ), IM_RECT_BOTTOM( r ) ); gdk_gc_set_line_attributes( fg, 0, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER ); } /* Paint the dotted box for a text preview, or rectangle paint preview. */ static void regionview_paint_box( GdkDrawable *draw, GdkGC *fg, int off, Rect *r ) { static gint8 dash_list[] = { 10, 10 }; gdk_gc_set_dashes( fg, off, dash_list, 2 ); gdk_gc_set_line_attributes( fg, 2, GDK_LINE_DOUBLE_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER ); gdk_draw_line( draw, fg, r->left, r->top, IM_RECT_RIGHT( r ), r->top ); gdk_draw_line( draw, fg, IM_RECT_RIGHT( r ), r->top, IM_RECT_RIGHT( r ), IM_RECT_BOTTOM( r ) ); gdk_draw_line( draw, fg, IM_RECT_RIGHT( r ), IM_RECT_BOTTOM( r ), r->left, IM_RECT_BOTTOM( r ) ); gdk_draw_line( draw, fg, r->left, IM_RECT_BOTTOM( r ), r->left, r->top ); gdk_gc_set_line_attributes( fg, 0, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER ); } /* Apply a function to every rect in a crosshair positioned at (x, y). */ static void * regionview_crosshair_foreach( Regionview *regionview, int x, int y, regionview_rect_fn fn, void *data ) { const int n = regionview_border_width + 2; const int l = regionview_crosshair_length + 2; Rect area; void *res; area.left = x - n/2 - 1 - l; area.top = y - n/2; area.width = l; area.height = n; if( (res = fn( regionview, &area, data )) ) return( res ); area.left = x + n/2 + 1; if( (res = fn( regionview, &area, data )) ) return( res ); area.left = x - n/2; area.top = y - n/2 - 1 - l; area.width = n; area.height = l; if( (res = fn( regionview, &area, data )) ) return( res ); area.top = y + n/2 + 1; if( (res = fn( regionview, &area, data )) ) return( res ); return( NULL ); } /* Apply a function to every rect in a region border positioned at border. */ static void * regionview_border_foreach( Regionview *regionview, Rect *border, regionview_rect_fn fn, void *data ) { const int n = regionview_border_width + 2; Rect area; void *res; area.left = border->left - n; area.top = border->top - n; area.width = border->width + 2*n; area.height = n; if( (res = fn( regionview, &area, data )) ) return( res ); area.top = IM_RECT_BOTTOM( border ); if( (res = fn( regionview, &area, data )) ) return( res ); area.left = border->left - n; area.top = border->top; area.width = n; area.height = border->height; if( (res = fn( regionview, &area, data )) ) return( res ); area.left = IM_RECT_RIGHT( border ); if( (res = fn( regionview, &area, data )) ) return( res ); return( NULL ); } /* Repaint ... as a rect_foreach function. */ static void * regionview_queue_draw_area( Regionview *regionview, Rect *area, void *dummy ) { #ifdef DEBUG_PAINT printf( "regionview_queue_draw_area: at %dx%d size %dx%d\n", area->left, area->top, area->width, area->height ); #endif /*DEBUG_PAINT*/ imagedisplay_queue_draw_area( regionview->ip->id, area ); return( NULL ); } /* Queue draws for all the pixels a region might touch. */ static void regionview_queue_draw( Regionview *regionview ) { Imagedisplay *id = regionview->ip->id; Conversion *conv = id->conv; Rect *area = ®ionview->area; Rect dr; int x, y; switch( regionview->last_type ) { case REGIONVIEW_AREA: case REGIONVIEW_REGION: conversion_im_to_disp_rect( conv, area, &dr ); (void) regionview_border_foreach( regionview, &dr, regionview_queue_draw_area, NULL ); break; case REGIONVIEW_MARK: conversion_im_to_disp( conv, area->left, area->top, &x, &y ); (void) regionview_crosshair_foreach( regionview, x, y, regionview_queue_draw_area, NULL ); break; case REGIONVIEW_ARROW: conversion_im_to_disp_rect( conv, area, &dr ); (void) regionview_crosshair_foreach( regionview, dr.left, dr.top, regionview_queue_draw_area, NULL ); (void) regionview_crosshair_foreach( regionview, IM_RECT_RIGHT( &dr ), IM_RECT_BOTTOM( &dr ), regionview_queue_draw_area, NULL ); im_rect_normalise( &dr ); im_rect_marginadjust( &dr, 2 ); regionview_queue_draw_area( regionview, &dr, NULL ); break; case REGIONVIEW_HGUIDE: case REGIONVIEW_VGUIDE: case REGIONVIEW_LINE: conversion_im_to_disp_rect( conv, area, &dr ); im_rect_normalise( &dr ); im_rect_marginadjust( &dr, 2 ); regionview_queue_draw_area( regionview, &dr, NULL ); break; case REGIONVIEW_BOX: conversion_im_to_disp_rect( conv, area, &dr ); im_rect_normalise( &dr ); im_rect_marginadjust( &dr, -2 ); (void) regionview_border_foreach( regionview, &dr, regionview_queue_draw_area, NULL ); break; default: g_assert( FALSE ); } if( regionview->classmodel ) imagedisplay_queue_draw_area( id, ®ionview->label ); } /* Paint a region ... assume the screen has only the background visible (ie. * we've nothing of this region visible). Clip paints against clip rect (in * xev coordinates) ... either the expose area, or the imagedisplay area. */ static void regionview_paint( Regionview *regionview ) { Imagepresent *ip = regionview->ip; Imagedisplay *id = ip->id; Conversion *conv = id->conv; GtkStyle *style = gtk_widget_get_style( GTK_WIDGET( id ) ); GdkDrawable *draw = GTK_WIDGET( id )->window; int state = regionview->last_paint_state; GdkGC *tl, *br, *bg; Rect dr; tl = style->light_gc[state]; br = style->dark_gc[state]; bg = style->bg_gc[state]; conversion_im_to_disp_rect( conv, ®ionview->area, &dr ); switch( regionview->last_type ) { case REGIONVIEW_REGION: regionview_paint_border( draw, tl, bg, br, &dr, FALSE ); break; case REGIONVIEW_AREA: regionview_paint_border( draw, tl, bg, br, &dr, TRUE ); break; case REGIONVIEW_MARK: regionview_paint_crosshair( draw, tl, bg, br, dr.left, dr.top ); break; case REGIONVIEW_ARROW: regionview_paint_arrow( draw, tl, regionview->dash_offset, &dr ); regionview_paint_crosshair( draw, tl, bg, br, dr.left, dr.top ); regionview_paint_crosshair( draw, tl, bg, br, IM_RECT_RIGHT( &dr ), IM_RECT_BOTTOM( &dr ) ); break; case REGIONVIEW_HGUIDE: case REGIONVIEW_VGUIDE: case REGIONVIEW_LINE: regionview_paint_arrow( draw, tl, regionview->dash_offset, &dr ); break; case REGIONVIEW_BOX: im_rect_normalise( &dr ); regionview_paint_box( draw, tl, regionview->dash_offset, &dr ); break; default: g_assert( FALSE ); } if( regionview->classmodel ) regionview_paint_label( regionview, draw, ®ionview->label, regionview->ascent, vips_buf_all( ®ionview->caption ) ); } /* Stop tracking. */ static void regionview_detach( Regionview *regionview ) { if( regionview->grabbed ) { g_assert( regionview->ip->grabbed == regionview ); #ifdef DEBUG_GRAB printf( "regionview_detach: %p\n", regionview ); #endif /*DEBUG_GRAB*/ regionview->state = REGIONVIEW_WAIT; regionview->paint_state = GTK_STATE_PRELIGHT; regionview->grabbed = FALSE; regionview->ip->grabbed = NULL; imagepresent_scroll_stop( regionview->ip ); } } static void regionview_destroy( GtkObject *object ) { Regionview *regionview; Imagedisplay *id; #ifdef DEBUG_MAKE printf( "regionview_destroy: %p\n", object ); #endif /*DEBUG_MAKE*/ g_return_if_fail( object != NULL ); g_return_if_fail( IS_REGIONVIEW( object ) ); regionview = REGIONVIEW( object ); if( !regionview->first ) regionview_queue_draw( regionview ); regionview->first = FALSE; regionview_detach( regionview ); if( (id = regionview->ip->id) ) { FREESID( regionview->expose_sid, id ); FREESID( regionview->destroy_sid, id ); FREESID( regionview->event_sid, id ); FREESID( regionview->changed_sid, id->conv ); FREESID( regionview->conv_destroy_sid, id->conv ); } FREESID( regionview->model_changed_sid, regionview->classmodel ); IM_FREEF( g_source_remove, regionview->dash_crawl ); IM_FREEF( iwindow_cursor_context_destroy, regionview->cntxt ); vips_buf_destroy( ®ionview->caption ); if( regionview->ip ) { if( regionview->ip->regionview == regionview ) regionview->ip->regionview = NULL; regionview->ip->regionviews = g_slist_remove( regionview->ip->regionviews, regionview ); regionview->ip = NULL; } if( regionview->classmodel ) { regionview->classmodel->views = g_slist_remove( regionview->classmodel->views, regionview ); regionview->classmodel = NULL; } GTK_OBJECT_CLASS( parent_class )->destroy( object ); } /* Compute the label geometry. */ static void regionview_label_geo( Regionview *regionview ) { int n = regionview_label_border; const char *str = vips_buf_all( ®ionview->caption ); int width, height; PangoLayout *layout; layout = gtk_widget_create_pango_layout( GTK_WIDGET( regionview->ip->id ), str ); pango_layout_get_pixel_size( layout, &width, &height ); g_object_unref( layout ); regionview->label.width = width + 2 * n; regionview->label.height = height + 2 * n; regionview->ascent = 0; } static void regionview_refresh_label( Regionview *regionview ) { if( regionview->classmodel ) { Row *row = HEAPMODEL( regionview->classmodel )->row; vips_buf_rewind( ®ionview->caption ); row_qualified_name_relative( row->ws->sym, row, ®ionview->caption ); regionview_label_geo( regionview ); } } /* Move label to try to keep it within the window, and away from the * selected pixels. */ static void regionview_position_label( Regionview *regionview ) { Imagepresent *ip = regionview->ip; Conversion *conv = ip->id->conv; Rect *visible = &conv->visible; Rect *label = ®ionview->label; const int b = regionview_border_width + 2; Rect dr; if( regionview->label_geo ) { regionview_refresh_label( regionview ); regionview->label_geo = FALSE; } conversion_im_to_disp_rect( conv, ®ionview->area, &dr ); switch( regionview->type ) { case REGIONVIEW_REGION: case REGIONVIEW_AREA: case REGIONVIEW_BOX: if( dr.top > visible->top + label->height + b ) { /* Space above region for label. */ label->left = dr.left - b; label->top = dr.top - label->height - b; } else if( dr.left > visible->left + label->width + b ) { /* Space to left of region for label */ label->left = dr.left - label->width - b; label->top = dr.top - b; } else if( IM_RECT_RIGHT( &dr ) < IM_RECT_RIGHT( visible ) - label->width - b ) { /* Space at right. */ label->left = IM_RECT_RIGHT( &dr ) + b; label->top = dr.top - b; } else if( IM_RECT_BOTTOM( &dr ) < IM_RECT_BOTTOM( visible ) - label->height - b ) { /* Space at bottom. */ label->left = dr.left - b; label->top = IM_RECT_BOTTOM( &dr ) + b; } else { /* Inside top left. */ label->left = dr.left; label->top = dr.top; } break; case REGIONVIEW_HGUIDE: case REGIONVIEW_VGUIDE: case REGIONVIEW_MARK: case REGIONVIEW_ARROW: case REGIONVIEW_LINE: /* Space above? */ if( dr.top > visible->top + label->height + b/2 + 2 ) { if( dr.left > IM_RECT_RIGHT( visible ) - label->width - b/2 - 2 ) { /* Above left. */ label->left = dr.left - b/2 - 2 - label->width; label->top = dr.top - b/2 - 2 - label->height; } else { /* Above right. */ label->left = dr.left + b/2 + 2; label->top = dr.top - b/2 - 2 - label->height; } } else if( dr.left > IM_RECT_RIGHT( visible ) - label->width - b/2 - 2 ) { /* Below left. */ label->left = dr.left - b/2 - 2 - label->width; label->top = dr.top + b/2 + 2; } else { /* Below right. */ label->left = dr.left + b/2 + 2; label->top = dr.top + b/2 + 2; } break; default: g_assert( FALSE ); } } static Rect * regionview_get_model( Regionview *regionview ) { Classmodel *classmodel = regionview->classmodel; iRegionInstance *instance; Rect *model_area; /* If we have a class, update from the inside of that. */ if( classmodel && (instance = classmodel_get_instance( classmodel )) ) model_area = &instance->area; else model_area = regionview->model_area; return( model_area ); } /* Update our_area from the model. Translate to our cods too: we always have * x/y in 0 to xsize/ysize. */ static void regionview_update_from_model( Regionview *regionview ) { Rect *model_area = regionview_get_model( regionview ); #ifdef DEBUG printf( "regionview_update_from_model: model is %dx%d size %dx%d\n", model_area->left, model_area->top, model_area->width, model_area->height ); #endif /*DEBUG*/ regionview->our_area = *model_area; #ifdef DEBUG printf( "regionview_update_from_model: set regionview to %dx%d size %dx%d\n", regionview->our_area.left, regionview->our_area.top, regionview->our_area.width, regionview->our_area.height ); #endif /*DEBUG*/ } /* Update the model from our_area. */ static void regionview_model_update( Regionview *regionview ) { Classmodel *classmodel = regionview->classmodel; Rect *model_area = regionview_get_model( regionview ); #ifdef DEBUG printf( "regionview_model_update: regionview is %dx%d size %dx%d\n", regionview->our_area.left, regionview->our_area.top, regionview->our_area.width, regionview->our_area.height ); #endif /*DEBUG*/ *model_area = regionview->our_area; if( classmodel ) { classmodel_update( classmodel ); if( CALC_RECOMP_REGION ) symbol_recalculate_all(); } /* Refresh immediately .. gives faster feedback during drag. */ vobject_refresh( VOBJECT( regionview ) ); #ifdef DEBUG printf( "regionview_model_update: set model to %dx%d size %dx%d\n", model_area->left, model_area->top, model_area->width, model_area->height ); #endif /*DEBUG*/ } /* Our model has changed ... undraw in the old position, draw in the new * position. */ static void regionview_refresh( vObject *vobject ) { Regionview *regionview = REGIONVIEW( vobject ); #ifdef DEBUG printf( "regionview_refresh1: %dx%d size %dx%d\n", regionview->our_area.left, regionview->our_area.top, regionview->our_area.width, regionview->our_area.height ); #endif /*DEBUG*/ /* Update our_area from model. */ regionview_update_from_model( regionview ); #ifdef DEBUG printf( "regionview_refresh2: %dx%d size %dx%d\n", regionview->our_area.left, regionview->our_area.top, regionview->our_area.width, regionview->our_area.height ); #endif /*DEBUG*/ if( !regionview->first ) regionview_queue_draw( regionview ); regionview->first = FALSE; /* Set new position. */ regionview->area = regionview->our_area; regionview->last_paint_state = regionview->paint_state; regionview->last_type = regionview->type; /* Choose a new label position. */ regionview_position_label( regionview ); /* Draw in the new place, clip against imagedisplay draw area. */ regionview_queue_draw( regionview ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void regionview_edit_cb( GtkWidget *menu, Regionview *regionview, Imagepresent *ip ) { model_edit( GTK_WIDGET( ip ), MODEL( regionview->classmodel ) ); } static void regionview_clone_cb( GtkWidget *menu, Regionview *regionview, Imagepresent *ip ) { Row *row = HEAPMODEL( regionview->classmodel )->row; Workspace *ws = row->top_col->ws; if( row->top_row != row ) { error_top( _( "Can't duplicate." ) ); error_sub( "%s", _( "You can only duplicate top level regions." ) ); iwindow_alert( GTK_WIDGET( regionview->ip ), GTK_MESSAGE_INFO ); return; } workspace_deselect_all( ws ); row_select( row ); if( !workspace_selected_duplicate( ws ) ) iwindow_alert( GTK_WIDGET( regionview ), GTK_MESSAGE_ERROR ); workspace_deselect_all( ws ); symbol_recalculate_all(); } static void regionview_clear_edited_cb( GtkWidget *menu, Regionview *regionview, Imagepresent *ip ) { (void) icontainer_map_all( ICONTAINER( regionview->classmodel ), (icontainer_map_fn) model_clear_edited, NULL ); symbol_recalculate_all(); } static void regionview_remove_yes( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Regionview *regionview = REGIONVIEW( client ); Row *row = HEAPMODEL( regionview->classmodel )->row; IDESTROY( row->sym ); nfn( sys, IWINDOW_YES ); } static void regionview_remove_cb( GtkWidget *menu, Regionview *regionview, Imagepresent *ip ) { Row *row = HEAPMODEL( regionview->classmodel )->row; if( row->top_row != row ) { error_top( _( "Can't delete." ) ); error_sub( _( "You can only delete top level regions." ) ); iwindow_alert( GTK_WIDGET( regionview->ip ), GTK_MESSAGE_INFO ); return; } box_yesno( GTK_WIDGET( ip ), regionview_remove_yes, iwindow_true_cb, regionview, iwindow_notify_null, NULL, GTK_STOCK_DELETE, _( "Delete Region?" ), _( "Are you sure you want to delete Region \"%s\"?" ), vips_buf_all( ®ionview->caption ) ); } static void regionview_class_init( RegionviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; GtkWidget *pane; parent_class = g_type_class_peek_parent( class ); object_class->destroy = regionview_destroy; /* Create signals. */ /* Init methods. */ vobject_class->refresh = regionview_refresh; /* Other init. */ pane = regionview_popup_menu = popup_build( _( "Region menu" ) ); popup_add_but( pane, _( "_Edit" ), POPUP_FUNC( regionview_edit_cb ) ); popup_add_but( pane, STOCK_DUPLICATE, POPUP_FUNC( regionview_clone_cb ) ); popup_add_but( pane, _( "_Reset" ), POPUP_FUNC( regionview_clear_edited_cb ) ); menu_add_sep( pane ); popup_add_but( pane, GTK_STOCK_DELETE, POPUP_FUNC( regionview_remove_cb ) ); } static void regionview_init( Regionview *regionview ) { static Rect empty_rect = { -1, -1, -1, -1 }; #ifdef DEBUG_MAKE printf( "regionview_init\n" ); #endif /*DEBUG_MAKE*/ regionview->type = REGIONVIEW_MARK; regionview->frozen = TRUE; regionview->state = REGIONVIEW_WAIT; regionview->resize = REGIONVIEW_RESIZE_NONE; regionview->dx = -1; regionview->dy = -1; regionview->grabbed = FALSE; regionview->classmodel = NULL; regionview->ip = NULL; regionview->cntxt = NULL; regionview->expose_sid = 0; regionview->destroy_sid = 0; regionview->event_sid = 0; regionview->changed_sid = 0; regionview->conv_destroy_sid = 0; regionview->model_area = NULL; regionview->paint_state = GTK_STATE_NORMAL; regionview->area = empty_rect; regionview->label = empty_rect; regionview->ascent = 0; regionview->dash_offset = 0; regionview->dash_crawl = 0; regionview->last_paint_state = (GtkStateType) -1; regionview->last_type = (RegionviewType) -1; regionview->first = TRUE; regionview->label_geo = TRUE; vips_buf_init_dynamic( ®ionview->caption, REGIONVIEW_LABEL_MAX ); gtk_widget_set_name( GTK_WIDGET( regionview ), "regionview_widget" ); } GtkType regionview_get_type( void ) { static GtkType regionview_type = 0; if( !regionview_type ) { static const GtkTypeInfo info = { "Regionview", sizeof( Regionview ), sizeof( RegionviewClass ), (GtkClassInitFunc) regionview_class_init, (GtkObjectInitFunc) regionview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; regionview_type = gtk_type_unique( TYPE_VIEW, &info ); } return( regionview_type ); } /* Test for rect touches rect (non-empty intersection). */ static void * regionview_rect_touching( Regionview *regionview, Rect *a, Rect *b ) { Rect overlap; im_rect_intersectrect( a, b, &overlap ); if( !im_rect_isempty( &overlap ) ) return( regionview ); else return( NULL ); } /* Does expose rect touch the mark positioned at mark_x/mark_y. Include a big * grab handle in the centre of the crosshair. */ static gboolean regionview_rect_touches_mark( Regionview *regionview, int mark_x, int mark_y, Rect *expose ) { Conversion *conv = regionview->ip->id->conv; Rect tiny; int x, y; conversion_im_to_disp( conv, mark_x, mark_y, &x, &y ); if( regionview_crosshair_foreach( regionview, x, y, (regionview_rect_fn) regionview_rect_touching, expose ) ) return( TRUE ); /* ... and the centre of the crosshairs. */ tiny.left = x; tiny.top = y; tiny.width = 1; tiny.height = 1; im_rect_marginadjust( &tiny, regionview_crosshair_centre ); if( regionview_rect_touching( regionview, &tiny, expose ) ) return( TRUE ); return( FALSE ); } /* Test for rect intersects some part of region. */ static gboolean regionview_rect_touches_region( Regionview *regionview, Rect *expose ) { Conversion *conv = regionview->ip->id->conv; Rect canvas_area; if( regionview->classmodel && regionview_rect_touching( regionview, ®ionview->label, expose ) ) return( TRUE ); switch( regionview->type ) { case REGIONVIEW_REGION: case REGIONVIEW_AREA: case REGIONVIEW_BOX: case REGIONVIEW_LINE: conversion_im_to_disp_rect( conv, ®ionview->area, &canvas_area ); im_rect_normalise( &canvas_area ); if( regionview_border_foreach( regionview, &canvas_area, (regionview_rect_fn) regionview_rect_touching, expose ) ) return( TRUE ); break; case REGIONVIEW_MARK: if( regionview_rect_touches_mark( regionview, regionview->area.left, regionview->area.top, expose ) ) return( TRUE ); break; case REGIONVIEW_ARROW: /* Test two marks first. */ if( regionview_rect_touches_mark( regionview, regionview->area.left, regionview->area.top, expose ) ) return( TRUE ); if( regionview_rect_touches_mark( regionview, IM_RECT_RIGHT( ®ionview->area ), IM_RECT_BOTTOM( ®ionview->area ), expose ) ) return( TRUE ); /* Spot in main area too ... for the dotted line. Also avoid * zero-width/height areas for h and v lines. */ conversion_im_to_disp_rect( conv, ®ionview->area, &canvas_area ); im_rect_normalise( &canvas_area ); im_rect_marginadjust( &canvas_area, 1 ); if( regionview_rect_touching( regionview, &canvas_area, expose ) ) return( TRUE ); break; case REGIONVIEW_HGUIDE: case REGIONVIEW_VGUIDE: conversion_im_to_disp_rect( conv, ®ionview->area, &canvas_area ); im_rect_marginadjust( &canvas_area, 5 ); if( regionview_rect_touching( regionview, &canvas_area, expose ) ) return( TRUE ); break; default: g_assert( FALSE ); } return( FALSE ); } /* From the expose event. */ static void regionview_expose( Regionview *regionview, Rect *expose ) { #ifdef DEBUG_PAINT printf( "regionview_expose: at %dx%d size %dx%d\n", expose->left, expose->top, expose->width, expose->height ); #endif /*DEBUG_PAINT*/ g_assert( expose->width >= 0 && expose->height >= 0 ); /* If we've not finished init, don't paint. */ if( regionview->first ) return; /* If the expose doesn't touch the region, don't bother painting. */ if( !regionview_rect_touches_region( regionview, expose ) ) return; regionview_paint( regionview ); } static void regionview_model_changed_cb( Classmodel *classmodel, Regionview *regionview ) { vobject_refresh_queue( VOBJECT( regionview ) ); } static gboolean regionview_expose_cb( Imagedisplay *id, GdkEventExpose *event, Regionview *regionview ) { Rect expose; expose.left = event->area.x; expose.top = event->area.y; expose.width = event->area.width; expose.height = event->area.height; regionview_expose( regionview, &expose ); return( FALSE ); } /* Test for point is in the grab area of a region border or label. */ static gboolean regionview_point_in_region( Regionview *regionview, int x, int y ) { Rect r; r.left = x; r.top = y; r.width = 1; r.height = 1; return( regionview_rect_touches_region( regionview, &r ) ); } /* Given a position, find the sort of resize we should allow. */ static RegionviewResize regionview_find_resize( Regionview *regionview, int x, int y ) { Conversion *conv = regionview->ip->id->conv; Rect canvas_area, tiny; int dx, dy; if( im_rect_includespoint( ®ionview->label, x, y ) ) return( REGIONVIEW_RESIZE_EDIT ); conversion_im_to_disp_rect( conv, ®ionview->area, &canvas_area ); dx = x - canvas_area.left; dy = y - canvas_area.top; switch( regionview->type ) { case REGIONVIEW_REGION: if( dx > canvas_area.width - 10 ) { if( dy > canvas_area.height - 10 ) return( REGIONVIEW_RESIZE_BOTTOMRIGHT ); else if( dy < 10 ) return( REGIONVIEW_RESIZE_TOPRIGHT ); else return( REGIONVIEW_RESIZE_RIGHT ); } else if( dx < 10 ) { if( dy > canvas_area.height - 10 ) return( REGIONVIEW_RESIZE_BOTTOMLEFT ); else if( dy < 10 ) return( REGIONVIEW_RESIZE_TOPLEFT ); else return( REGIONVIEW_RESIZE_LEFT ); } else { if( dy < canvas_area.height / 2 ) return( REGIONVIEW_RESIZE_TOP ); else return( REGIONVIEW_RESIZE_BOTTOM ); } break; case REGIONVIEW_MARK: case REGIONVIEW_AREA: return( REGIONVIEW_RESIZE_MOVE ); case REGIONVIEW_ARROW: tiny.left = x; tiny.top = y; tiny.width = 1; tiny.height = 1; if( regionview_crosshair_foreach( regionview, canvas_area.left, canvas_area.top, (regionview_rect_fn) regionview_rect_touching, &tiny ) ) return( REGIONVIEW_RESIZE_TOPLEFT ); if( regionview_crosshair_foreach( regionview, IM_RECT_RIGHT( &canvas_area ), IM_RECT_BOTTOM( &canvas_area ), (regionview_rect_fn) regionview_rect_touching, &tiny ) ) return( REGIONVIEW_RESIZE_BOTTOMRIGHT ); /* Extra tests ... allow grabs in the centre of the crosshairs * too. */ tiny.left = IM_RECT_RIGHT( &canvas_area ); tiny.top = IM_RECT_BOTTOM( &canvas_area ); tiny.width = 1; tiny.height = 1; im_rect_marginadjust( &tiny, regionview_crosshair_centre ); if( im_rect_includespoint( &tiny, x, y ) ) return( REGIONVIEW_RESIZE_BOTTOMRIGHT ); tiny.left = canvas_area.left; tiny.top = canvas_area.top; tiny.width = 1; tiny.height = 1; im_rect_marginadjust( &tiny, regionview_crosshair_centre ); if( im_rect_includespoint( &tiny, x, y ) ) return( REGIONVIEW_RESIZE_TOPLEFT ); break; case REGIONVIEW_VGUIDE: case REGIONVIEW_HGUIDE: im_rect_marginadjust( &canvas_area, 5 ); if( im_rect_includespoint( &canvas_area, x, y ) ) return( REGIONVIEW_RESIZE_MOVE ); break; case REGIONVIEW_BOX: case REGIONVIEW_LINE: break; default: g_assert( FALSE ); } return( REGIONVIEW_RESIZE_NONE ); } /* Right button press event. */ static gint regionview_right_press( Regionview *regionview, GdkEvent *ev, int x, int y ) { if( im_rect_includespoint( ®ionview->label, x, y ) ) { popup_show( GTK_WIDGET( regionview ), ev ); return( TRUE ); } return( FALSE ); } /* Get ready to track this region. See imagepresent.c. */ void regionview_attach( Regionview *regionview, int x, int y ) { Imagepresent *ip = regionview->ip; Conversion *conv = ip->id->conv; int dx, dy; g_assert( !regionview->grabbed ); g_assert( !regionview->ip->grabbed ); #ifdef DEBUG_GRAB printf( "regionview_attach: %p\n", regionview ); #endif /*DEBUG_GRAB*/ switch( regionview->resize ) { case REGIONVIEW_RESIZE_NONE: regionview->resize = REGIONVIEW_RESIZE_BOTTOMRIGHT; regionview->state = REGIONVIEW_RESIZE; break; case REGIONVIEW_RESIZE_MOVE: case REGIONVIEW_RESIZE_EDIT: regionview->state = REGIONVIEW_MOVE; break; default: regionview->state = REGIONVIEW_RESIZE; break; } regionview->paint_state = GTK_STATE_ACTIVE; iwindow_cursor_context_set_cursor( regionview->cntxt, regionview_cursors[regionview->resize] ); regionview->grabbed = TRUE; regionview->ip->grabbed = regionview; conversion_im_to_disp( conv, regionview->our_area.left, regionview->our_area.top, &dx, &dy ); regionview->dx = dx - x; regionview->dy = dy - y; } /* Left button press event. */ static gint regionview_left_press( Regionview *regionview, GdkEvent *ev, int x, int y ) { gboolean handled = FALSE; if( !regionview_point_in_region( regionview, x, y ) ) return( FALSE ); switch( regionview->state ) { case REGIONVIEW_WAIT: regionview->resize = regionview_find_resize( regionview, x, y ); if( regionview->resize != REGIONVIEW_RESIZE_NONE ) { regionview_attach( regionview, x, y ); handled = TRUE; } break; case REGIONVIEW_MOVE: case REGIONVIEW_RESIZE: break; default: g_assert( FALSE ); } return( handled ); } /* Left button release event. */ static gint regionview_left_release( Regionview *regionview, GdkEvent *ev ) { switch( regionview->state ) { case REGIONVIEW_WAIT: break; case REGIONVIEW_MOVE: case REGIONVIEW_RESIZE: regionview_detach( regionview ); if( !CALC_RECOMP_REGION ) symbol_recalculate_all(); break; } return( FALSE ); } static void regionview_resize_area( Regionview *regionview, int ix, int iy ) { Imagepresent *ip = regionview->ip; Conversion *conv = ip->id->conv; IMAGE *im = imageinfo_get( FALSE, conv->ii ); Rect *our_area = ®ionview->our_area; int th = regionview_morph_threshold / conversion_dmag( conv->mag ); int bot = our_area->top + our_area->height; int ri = our_area->left + our_area->width; int rx = ix - our_area->left; int ry = iy - our_area->top; /* If we're not frozen, do an unconstrained resize. */ if( !regionview->frozen ) { switch( regionview->resize ) { case REGIONVIEW_RESIZE_RIGHT: our_area->width = IM_CLIP( -our_area->left, rx, im->Xsize - our_area->left ); break; case REGIONVIEW_RESIZE_BOTTOM: our_area->height = IM_CLIP( -our_area->top, ry, im->Ysize - our_area->top ); break; case REGIONVIEW_RESIZE_MOVE: /* Get this for POINT on create ... treat as * BOTTOMRIGHT. */ case REGIONVIEW_RESIZE_BOTTOMRIGHT: our_area->width = IM_CLIP( -our_area->left, rx, im->Xsize - our_area->left ); our_area->height = IM_CLIP( -our_area->top, ry, im->Ysize - our_area->top ); break; case REGIONVIEW_RESIZE_LEFT: our_area->left = IM_CLIP( 0, ix, im->Xsize - 1 ); our_area->width = ri - our_area->left; break; case REGIONVIEW_RESIZE_TOP: our_area->top = IM_CLIP( 0, iy, im->Ysize - 1 ); our_area->height = bot - our_area->top; break; case REGIONVIEW_RESIZE_TOPLEFT: our_area->top = IM_CLIP( 0, iy, im->Ysize - 1 ); our_area->left = IM_CLIP( 0, ix, im->Xsize - 1 ); our_area->width = ri - our_area->left; our_area->height = bot - our_area->top; break; case REGIONVIEW_RESIZE_TOPRIGHT: our_area->top = IM_CLIP( 0, iy, im->Ysize - 1 ); our_area->height = bot - our_area->top; our_area->width = IM_CLIP( -our_area->left, rx, im->Xsize - our_area->left ); break; case REGIONVIEW_RESIZE_BOTTOMLEFT: our_area->left = IM_CLIP( 0, ix, im->Xsize - 1 ); our_area->width = ri - our_area->left; our_area->height = IM_CLIP( -our_area->top, ry, im->Ysize - our_area->top ); break; default: g_assert( FALSE ); } if( abs( our_area->width ) < th && abs( our_area->height - im->Ysize ) < th ) regionview->type = REGIONVIEW_VGUIDE; else if( abs( our_area->height ) < th && abs( our_area->width - im->Xsize ) < th ) regionview->type = REGIONVIEW_HGUIDE; else if( abs( our_area->width ) < th && abs( our_area->height ) < th ) regionview->type = REGIONVIEW_MARK; else if( our_area->width > 0 && our_area->height > 0 ) regionview->type = REGIONVIEW_REGION; else regionview->type = REGIONVIEW_ARROW; } else { /* We're frozen ... resize should be tightly constrained. */ switch( regionview->type ) { case REGIONVIEW_REGION: switch( regionview->resize ) { case REGIONVIEW_RESIZE_RIGHT: our_area->width = IM_CLIP( 1, rx, im->Xsize - our_area->left ); break; case REGIONVIEW_RESIZE_BOTTOM: our_area->height = IM_CLIP( 1, ry, im->Ysize - our_area->top ); break; case REGIONVIEW_RESIZE_BOTTOMRIGHT: our_area->width = IM_CLIP( 1, rx, im->Xsize - our_area->left ); our_area->height = IM_CLIP( 1, ry, im->Ysize - our_area->top ); break; case REGIONVIEW_RESIZE_TOP: our_area->top = IM_CLIP( 0, iy, bot - 1 ); our_area->height = bot - our_area->top; break; case REGIONVIEW_RESIZE_LEFT: our_area->left = IM_CLIP( 0, ix, ri - 1 ); our_area->width = ri - our_area->left; break; case REGIONVIEW_RESIZE_TOPLEFT: our_area->left = IM_CLIP( 0, ix, ri - 1 ); our_area->width = ri - our_area->left; our_area->top = IM_CLIP( 0, iy, bot - 1 ); our_area->height = bot - our_area->top; break; case REGIONVIEW_RESIZE_TOPRIGHT: our_area->top = IM_CLIP( 0, iy, bot - 1 ); our_area->height = bot - our_area->top; our_area->width = IM_CLIP( 1, rx, im->Xsize - our_area->left ); break; case REGIONVIEW_RESIZE_BOTTOMLEFT: our_area->left = IM_CLIP( 0, ix, ri - 1 ); our_area->width = ri - our_area->left; our_area->height = IM_CLIP( 1, ry, im->Ysize - our_area->top ); break; default: g_assert( FALSE ); } break; case REGIONVIEW_ARROW: case REGIONVIEW_LINE: case REGIONVIEW_BOX: switch( regionview->resize ) { case REGIONVIEW_RESIZE_TOPLEFT: our_area->left = IM_CLIP( 0, ix, im->Xsize ); our_area->width = ri - our_area->left; our_area->top = IM_CLIP( 0, iy, im->Ysize ); our_area->height = bot - our_area->top; break; case REGIONVIEW_RESIZE_BOTTOMRIGHT: our_area->width = IM_CLIP( -our_area->left, rx, im->Xsize - our_area->left ); our_area->height = IM_CLIP( -our_area->top, ry, im->Ysize - our_area->top ); break; default: g_assert( FALSE ); } break; case REGIONVIEW_MARK: our_area->left = IM_CLIP( 0, ix, im->Xsize - 1 ); our_area->top = IM_CLIP( 0, iy, im->Ysize - 1 ); our_area->width = 0; our_area->height = 0; break; case REGIONVIEW_HGUIDE: our_area->top = IM_CLIP( 0, iy, im->Ysize - 1 ); break; case REGIONVIEW_VGUIDE: our_area->left = IM_CLIP( 0, ix, im->Xsize - 1 ); break; default: g_assert( FALSE ); } } } /* Change the state. */ static void regionview_set_paint_state( Regionview *regionview, GtkStateType paint_state ) { if( regionview->paint_state != paint_state ) { regionview->paint_state = paint_state; vobject_refresh_queue( VOBJECT( regionview ) ); } } /* A motion event while we're grabbed. */ static void regionview_motion_grab( Regionview *regionview, int x, int y ) { Imagepresent *ip = regionview->ip; Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; Rect *visible = &imagemodel->visible; Rect *our_area = ®ionview->our_area; Rect snap; IMAGE *im; int ix, iy; #ifdef DEBUG printf( "regionview_motion_grab:\n" ); printf( "cods: %dx%d size %dx%d\n", our_area->left, our_area->top, our_area->width, our_area->height ); #endif /*DEBUG*/ switch( regionview->state ) { case REGIONVIEW_MOVE: conversion_disp_to_im( conv, x + regionview->dx, y + regionview->dy, &ix, &iy ); im = imageinfo_get( FALSE, conv->ii ); switch( regionview->type ) { case REGIONVIEW_REGION: case REGIONVIEW_AREA: our_area->left = IM_CLIP( 0, ix, im->Xsize - our_area->width ); our_area->top = IM_CLIP( 0, iy, im->Ysize - our_area->height ); break; case REGIONVIEW_ARROW: our_area->left = IM_CLIP( IM_MAX( 0, -our_area->width ), ix, IM_MIN( im->Xsize - 1, im->Xsize - our_area->width ) ); our_area->top = IM_CLIP( IM_MAX( 0, -our_area->height ), iy, IM_MIN( im->Ysize - 1, im->Ysize - our_area->height ) ); break; case REGIONVIEW_MARK: case REGIONVIEW_HGUIDE: case REGIONVIEW_VGUIDE: our_area->left = IM_CLIP( 0, ix, im->Xsize - our_area->width - 1 ); our_area->top = IM_CLIP( 0, iy, im->Ysize - our_area->height - 1 ); break; case REGIONVIEW_LINE: case REGIONVIEW_BOX: our_area->left = ix; our_area->top = iy; break; default: g_assert( FALSE ); } snap = *our_area; conversion_im_to_disp_rect( conv, &snap, &snap ); if( imagepresent_snap_rect( ip, &snap, &snap ) ) { conversion_disp_to_im_rect( conv, &snap, &snap ); our_area->left = snap.left; our_area->top = snap.top; } regionview_model_update( regionview ); break; case REGIONVIEW_RESIZE: imagepresent_snap_point( ip, x, y, &x, &y ); conversion_disp_to_im( conv, x, y, &ix, &iy ); regionview_resize_area( regionview, ix, iy ); regionview_model_update( regionview ); break; default: break; } if( !im_rect_includespoint( visible, x, y ) ) { int u, v; if( x < visible->left ) u = -8; else if( x > IM_RECT_RIGHT( visible ) ) u = 8; else u = 0; if( y < visible->top ) v = -8; else if( y > IM_RECT_BOTTOM( visible ) ) v = 8; else v = 0; imagepresent_scroll_start( regionview->ip, u, v ); } else imagepresent_scroll_stop( regionview->ip ); } #ifdef EVENT static char * resize_to_str( RegionviewResize resize ) { switch( resize ) { case REGIONVIEW_RESIZE_NONE: return( "REGIONVIEW_RESIZE_NONE" ); case REGIONVIEW_RESIZE_MOVE: return( "REGIONVIEW_RESIZE_MOVE" ); case REGIONVIEW_RESIZE_EDIT: return( "REGIONVIEW_RESIZE_EDIT" ); case REGIONVIEW_RESIZE_TOPLEFT: return( "REGIONVIEW_RESIZE_TOPLEFT" ); case REGIONVIEW_RESIZE_TOP: return( "REGIONVIEW_RESIZE_TOP" ); case REGIONVIEW_RESIZE_TOPRIGHT: return( "REGIONVIEW_RESIZE_TOPRIGHT" ); case REGIONVIEW_RESIZE_RIGHT: return( "REGIONVIEW_RESIZE_RIGHT" ); case REGIONVIEW_RESIZE_BOTTOMRIGHT: return( "REGIONVIEW_RESIZE_BOTTOMRIGHT" ); case REGIONVIEW_RESIZE_BOTTOM: return( "REGIONVIEW_RESIZE_BOTTOM" ); case REGIONVIEW_RESIZE_BOTTOMLEFT: return( "REGIONVIEW_RESIZE_BOTTOMLEFT" ); case REGIONVIEW_RESIZE_LEFT: return( "REGIONVIEW_RESIZE_LEFT" ); case REGIONVIEW_RESIZE_LAST: return( "REGIONVIEW_RESIZE_LAST" ); default: g_assert( 0 ); } } #endif /*EVENT*/ /* Motion event. */ static gint regionview_motion( Regionview *regionview, GdkEvent *ev, int x, int y ) { GdkWindow *win = GTK_WIDGET( regionview->ip->id )->window; RegionviewResize resize; #ifdef EVENT printf( "regionview_motion: %p, %d x %d\n", regionview, x, y ); #endif /*EVENT*/ /* We've got hints turned on, so we have to read the pointer. */ gdk_window_get_pointer( win, &x, &y, NULL ); switch( regionview->state ) { case REGIONVIEW_WAIT: if( regionview_point_in_region( regionview, x, y ) ) { resize = regionview_find_resize( regionview, x, y ); iwindow_cursor_context_set_cursor( regionview->cntxt, regionview_cursors[resize] ); regionview_set_paint_state( regionview, GTK_STATE_PRELIGHT ); } else { iwindow_cursor_context_set_cursor( regionview->cntxt, IWINDOW_SHAPE_NONE ); regionview_set_paint_state( regionview, GTK_STATE_NORMAL ); } break; case REGIONVIEW_MOVE: case REGIONVIEW_RESIZE: if( regionview->grabbed ) regionview_motion_grab( regionview, x, y ); break; default: g_assert( FALSE ); } return( FALSE ); } /* Main event loop. */ static gint regionview_event_cb( GtkWidget *widget, GdkEvent *ev, Regionview *regionview ) { Imagepresent *ip = regionview->ip; Imagemodel *imagemodel = ip->imagemodel; gboolean handled = FALSE; #ifdef EVENT if( ev->type == GDK_BUTTON_PRESS ) printf( "regionview_event: GDK_BUTTON_PRESS\n" ); if( ev->type == GDK_MOTION_NOTIFY ) printf( "regionview_event: GDK_MOTION_NOTIFY\n" ); #endif /*EVENT*/ /* Only manipulate regions if we're in SELECT mode ... don't want to * drag regions while we're panning, for example. Exception ... we can * drag/resize floating regions any time. */ if( imagemodel->state != IMAGEMODEL_SELECT && regionview->classmodel ) return( FALSE ); /* If there's a regionview grabbed, only that regionview responds to * events. */ if( regionview->ip->grabbed && regionview->ip->grabbed != regionview ) return( FALSE ); switch( ev->type ) { case GDK_BUTTON_PRESS: switch( ev->button.button ) { case 1: handled = regionview_left_press( regionview, ev, ev->button.x, ev->button.y ); break; case 3: handled = regionview_right_press( regionview, ev, ev->button.x, ev->button.y ); break; default: break; } break; case GDK_2BUTTON_PRESS: switch( ev->button.button ) { case 1: if( regionview->state == REGIONVIEW_MOVE && regionview->resize == REGIONVIEW_RESIZE_EDIT && regionview->classmodel ) { model_edit( GTK_WIDGET( ip ), MODEL( regionview->classmodel ) ); handled = TRUE; } break; default: break; } break; case GDK_BUTTON_RELEASE: switch( ev->button.button ) { case 1: handled = regionview_left_release( regionview, ev ); break; default: break; } break; case GDK_MOTION_NOTIFY: handled = regionview_motion( regionview, ev, ev->button.x, ev->button.y ); break; default: break; } return( handled ); } /* The conversion on our image has changed ... eg. on zoom in/out we need to * rethink the label position. */ static void regionview_changed_cb( Model *model, Regionview *regionview ) { #ifdef DEBUG printf( "regionview_changed\n" ); #endif /*DEBUG*/ vobject_refresh_queue( VOBJECT( regionview ) ); } /* The conversion on our image has been destroyed ... make sure we won't try * to disconnect when we go too. */ static void regionview_conv_destroy_cb( Model *model, Regionview *regionview ) { regionview->changed_sid = 0; regionview->conv_destroy_sid = 0; } static gboolean regionview_dash_crawl_cb( Regionview *regionview ) { /* Don't for regions, areas and points ... no lines in 'em. */ if( regionview->type != REGIONVIEW_REGION && regionview->type != REGIONVIEW_MARK && regionview->type != REGIONVIEW_AREA ) { regionview->dash_offset += 3; /* Don't repaint before the first expose. last_type etc. * won't have been inited properly yet. */ if( !regionview->first ) regionview_queue_draw( regionview ); } return( TRUE ); } static void regionview_setup( Regionview *regionview, Classmodel *classmodel, Rect *model_area, Imagepresent *ip ) { iWindow *iwnd; regionview->classmodel = classmodel; regionview->ip = ip; regionview->model_area = model_area; regionview->our_area = *model_area; regionview->model_changed_sid = 0; ip->regionviews = g_slist_prepend( ip->regionviews, regionview ); if( classmodel ) { classmodel->views = g_slist_prepend( classmodel->views, regionview ); regionview->model_changed_sid = g_signal_connect( G_OBJECT( classmodel ), "changed", G_CALLBACK( regionview_model_changed_cb ), regionview ); } regionview->expose_sid = g_signal_connect_after( GTK_OBJECT( ip->id ), "expose_event", GTK_SIGNAL_FUNC( regionview_expose_cb ), regionview ); regionview->destroy_sid = gtk_signal_connect_object( GTK_OBJECT( ip->id ), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), GTK_OBJECT( regionview ) ); regionview->event_sid = gtk_signal_connect( GTK_OBJECT( ip->id ), "event", GTK_SIGNAL_FUNC( regionview_event_cb ), regionview ); regionview->changed_sid = g_signal_connect( G_OBJECT( ip->id->conv ), "changed", G_CALLBACK( regionview_changed_cb ), regionview ); regionview->conv_destroy_sid = g_signal_connect( G_OBJECT( ip->id->conv ), "destroy", G_CALLBACK( regionview_conv_destroy_cb ), regionview ); iwnd = IWINDOW( gtk_widget_get_toplevel( GTK_WIDGET( ip ) ) ); regionview->cntxt = iwindow_cursor_context_new( iwnd, 1, "regionview" ); popup_link( GTK_WIDGET( regionview ), regionview_popup_menu, ip ); regionview->dash_crawl = g_timeout_add( 200, (GSourceFunc) regionview_dash_crawl_cb, regionview ); } Regionview * regionview_new( Classmodel *classmodel, Rect *model_area, Imagepresent *ip ) { Regionview *regionview = gtk_type_new( TYPE_REGIONVIEW ); regionview_setup( regionview, classmodel, model_area, ip ); #ifdef DEBUG_MAKE printf( "regionview_new: %dx%d size %dx%d\n", model_area->left, model_area->top, model_area->width, model_area->height ); #endif /*DEBUG_MAKE*/ return( regionview ); } /* Type we display for each of the classes. Order is important! */ typedef struct { const char *name; RegionviewType type; } RegionviewDisplay; static RegionviewDisplay regionview_display_table[] = { { CLASS_HGUIDE, REGIONVIEW_HGUIDE }, { CLASS_VGUIDE, REGIONVIEW_VGUIDE }, { CLASS_MARK, REGIONVIEW_MARK }, { CLASS_AREA, REGIONVIEW_AREA }, { CLASS_REGION, REGIONVIEW_REGION }, { CLASS_ARROW, REGIONVIEW_ARROW } }; /* Look at the class we are drawing, set the display type. */ void regionview_set_type( Regionview *regionview, PElement *root ) { gboolean result; int i; if( heap_is_class( root, &result ) && result ) for( i = 0; i < IM_NUMBER( regionview_display_table ); i++ ) { const char *name = regionview_display_table[i].name; if( !heap_is_instanceof( name, root, &result ) ) continue; if( result ) { regionview->type = regionview_display_table[i].type; vobject_refresh_queue( VOBJECT( regionview ) ); break; } } } nip2-8.7.1/src/managedstring.h0000644000175000017500000000356713351443023013114 00000000000000/* a managed STRING* ... for lazy string read */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These strings are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_MANAGEDSTRING (managedstring_get_type()) #define MANAGEDSTRING( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGEDSTRING, Managedstring )) #define MANAGEDSTRING_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_MANAGEDSTRING, ManagedstringClass)) #define IS_MANAGEDSTRING( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGEDSTRING )) #define IS_MANAGEDSTRING_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGEDSTRING )) #define MANAGEDSTRING_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_MANAGEDSTRING, ManagedstringClass )) struct _Managedstring { Managed parent_object; const char *string; Element e; /* Points to compiled string */ }; typedef struct _ManagedstringClass { ManagedClass parent_class; } ManagedstringClass; GType managedstring_get_type( void ); Managedstring *managedstring_find( Heap *heap, const char *string ); gboolean managedstring_get( Managedstring *managedstring, PElement *out ); nip2-8.7.1/src/symbol.h0000644000175000017500000001270513351443023011570 00000000000000/* Types for the symbol table. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_SYMBOL (symbol_get_type()) #define SYMBOL( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_SYMBOL, Symbol )) #define SYMBOL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_SYMBOL, SymbolClass)) #define IS_SYMBOL( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_SYMBOL )) #define IS_SYMBOL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_SYMBOL )) #define SYMBOL_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_SYMBOL, SymbolClass )) /* The types of symbol we can have. */ typedef enum { SYM_VALUE, /* Symbol with a value attached */ SYM_PARAM, /* A parameter to a user function */ SYM_ZOMBIE, /* A referred to but not defined */ SYM_WORKSPACE, /* A loaded workspace */ SYM_WORKSPACEROOT, /* Base of all workspaces */ SYM_ROOT, /* The root symbol */ SYM_EXTERNAL, /* A reference to an external function */ SYM_BUILTIN /* A reference to a built-in function */ } SymbolType; /* A symbol. */ struct _Symbol { Filemodel parent_class; /* The type of this symbol. */ SymbolType type; /* Track during parse. A list of pointers to pointers to this * symbol which we need to patch if we resolve to an outer scope. */ GSList *patch; /* Main expression for this sym. All expressions are icontainer * children of us. */ Expr *expr; /* Base of graph for value of this symbol. Use sym->expr->root to get * value though .. we just hold pointer for GC here. Expressions on * ext_expr have their GC handled by their enclosing Subcolumn. */ Element base; /* Value for this expr */ /* Recomputation links. Use these to work out what to build next. */ gboolean dirty; /* True if this sym needs recalc */ GSList *parents; /* Compiles which refer to this sym */ GSList *topchildren; /* For top syms, all top-level children */ GSList *topparents; /* For top syms, all top-level parents */ int ndirtychildren; /* Number of dirty top syms we refer to */ gboolean leaf; /* True for in recomp set */ /* This is a generated symbol, like $$result, $$fn1, whatever. */ gboolean generated; /* A temporary intermediate symbol generated during parse to hold * stuff until we need it. Don't generate code for these. */ gboolean placeholder; /* X-tras for definitions. */ Tool *tool; /* Tool and toolkit defined in */ /* X-tras for SYM_EXTERNAL ... our im_function. */ im_function *function; /* Function we run */ int fn_nargs; /* Number of args fn needs from nip */ /* X-tras for SYM_BUILTIN ... our function. */ BuiltinInfo *builtin; /* For WORKSPACEROOT ... the wsr we represent. */ Workspaceroot *wsr; /* For WORKSPACE ... the ws we represent. */ Workspace *ws; }; typedef struct _SymbolClass { FilemodelClass parent_class; /* new_value sym->expr has a new value (this signal is fwd'd from sym->expr) */ void (*new_value)( Symbol *sym ); } SymbolClass; GType symbol_get_type( void ); /* All symbols come off this. */ extern Symbol *symbol_root; Symbol *symbol_map_all( Symbol *sym, symbol_map_fn fn, void *a, void *b ); Symbol *symbol_get_parent( Symbol *sym ); Workspace *symbol_get_workspace( Symbol *sym ); Tool *symbol_get_tool( Symbol *sym ); Symbol *symbol_get_scope( Symbol *sym ); void symbol_qualified_name( Symbol *sym, VipsBuf *buf ); void symbol_qualified_name_relative( Symbol *context, Symbol *sym, VipsBuf *buf ); void *symbol_name_error( Symbol *sym, VipsBuf *buf ); const char *symbol_name( Symbol *sym ); void *symbol_name_print( Symbol *sym ); const char *symbol_name_scope( Symbol *sym ); void symbol_name_scope_print( Symbol *sym ); void symbol_new_value( Symbol *sym ); void *symbol_patch_add( void **pnt, Symbol *sym ); Symbol *symbol_root_init( void ); Symbol *symbol_new( Compile *compile, const char *name ); gboolean symbol_rename( Symbol *sym, const char *new_name ); void symbol_error_redefine( Symbol *sym ); Symbol *symbol_new_defining( Compile *compile, const char *name ); Symbol *symbol_new_reference( Compile *compile, const char *name ); void symbol_made( Symbol *sym ); void symbol_not_defined( Symbol *sym ); void *symbol_link_break( Symbol *child, Compile *compile ); gboolean symbol_user_init( Symbol *sym ); gboolean symbol_parameter_init( Symbol *sym ); gboolean symbol_parameter_builtin_init( Symbol *sym ); gboolean symbol_busy( void ); void *symbol_sanity( Symbol *sym ); void symbol_leaf_set_sanity( void ); void *symbol_strip( Symbol *sym ); void symbol_state_change( Symbol *sym ); const char *symbol_get_last_calc( void ); gboolean symbol_recalculate_check( Symbol *sym ); void symbol_recalculate_all_force( gboolean now ); void symbol_recalculate_all( void ); nip2-8.7.1/src/string.c0000644000175000017500000000564413351443023011570 00000000000000/* an editable string */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void string_finalize( GObject *gobject ) { String *string; #ifdef DEBUG printf( "string_finalize\n" ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_STRING( gobject ) ); string = STRING( gobject ); IM_FREE( string->value ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static View * string_view_new( Model *model, View *parent ) { return( stringview_new() ); } /* Members of string we automate. */ static ClassmodelMember string_members[] = { { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_CAPTION, "caption", N_( "Caption" ), G_STRUCT_OFFSET( iObject, caption ) }, { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( String, value ) } }; static void string_class_init( StringClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Init methods. */ gobject_class->finalize = string_finalize; model_class->view_new = string_view_new; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = string_members; classmodel_class->n_members = IM_NUMBER( string_members ); } static void string_init( String *string ) { string->value = NULL; IM_SETSTR( string->value, "" ); iobject_set( IOBJECT( string ), CLASS_STRING, NULL ); } GType string_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( StringClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) string_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( String ), 32, /* n_pstringlocs */ (GInstanceInitFunc) string_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "String", &info, 0 ); } return( type ); } nip2-8.7.1/src/itextview.h0000644000175000017500000000303013351443023012302 00000000000000/* a textview button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_ITEXTVIEW (itextview_get_type()) #define ITEXTVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_ITEXTVIEW, iTextview )) #define ITEXTVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_ITEXTVIEW, iTextviewClass )) #define IS_ITEXTVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_ITEXTVIEW )) #define IS_ITEXTVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_ITEXTVIEW )) typedef struct _iTextview { View view; /* Widgets. */ Formula *formula; } iTextview; typedef struct _iTextviewClass { ViewClass parent_class; /* My methods. */ } iTextviewClass; GtkType itextview_get_type( void ); View *itextview_new( void ); nip2-8.7.1/src/rhsview.c0000644000175000017500000001256713351443023011753 00000000000000/* the rhs of a tallyrow ... group together everything to the right of the * button */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; /* Get this if ws->mode changes. */ static void rhsview_reset( View *view ) { Rhsview *rhsview = RHSVIEW( view ); Rhs *rhs = RHS( VOBJECT( rhsview )->iobject ); Row *row = HEAPMODEL( rhs )->row; model_display( rhs->itext, row->ws->mode == WORKSPACE_MODE_FORMULA || rhs->flags & RHS_ITEXT ); VIEW_CLASS( parent_class )->reset( view ); } static void rhsview_refresh( vObject *vobject ) { Rhsview *rhsview = RHSVIEW( vobject ); Rhs *rhs = RHS( VOBJECT( rhsview )->iobject ); Row *row = HEAPMODEL( rhs )->row; #ifdef DEBUG printf( "rhsview_refresh: " ); row_name_print( HEAPMODEL( rhs )->row ); printf( " " ); if( rhs->flags & RHS_GRAPHIC ) printf( "RHS_GRAPHIC " ); if( rhs->flags & RHS_SCOL ) printf( "RHS_SCOL " ); if( rhs->flags & RHS_ITEXT ) printf( "RHS_ITEXT " ); printf( "\n" ); #endif /*DEBUG*/ /* Add/remove children according to rhs->flags. */ model_display( rhs->graphic, rhs->flags & RHS_GRAPHIC ); model_display( rhs->scol, rhs->flags & RHS_SCOL ); switch( row->ws->mode ) { case WORKSPACE_MODE_REGULAR: model_display( rhs->itext, rhs->flags & RHS_ITEXT ); break; case WORKSPACE_MODE_FORMULA: model_display( rhs->itext, TRUE ); break; case WORKSPACE_MODE_NOEDIT: /* Only show the text if it's the only this we have for this * row. */ if( rhs->graphic && rhs->flags & RHS_GRAPHIC ) model_display( rhs->itext, FALSE ); else if( rhs->scol && rhs->flags & RHS_SCOL ) model_display( rhs->itext, FALSE ); else model_display( rhs->itext, rhs->flags & RHS_ITEXT ); break; default: g_assert( 0 ); } VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void rhsview_link( View *view, Model *model, View *parent ) { Rhsview *rhsview = RHSVIEW( view ); Rowview *rview = ROWVIEW( parent ); #ifdef DEBUG printf( "rhsview_link: " ); row_name_print( ROW( VOBJECT( rview )->iobject ) ); printf( "\n" ); #endif /*DEBUG*/ VIEW_CLASS( parent_class )->link( view, model, parent ); rhsview->rview = rview; } static void rhsview_child_add( View *parent, View *child ) { Rhsview *rhsview = RHSVIEW( parent ); if( IS_SUBCOLUMNVIEW( child ) ) { gtk_table_attach_defaults( GTK_TABLE( rhsview->table ), GTK_WIDGET( child ), 0, 1, 1, 2 ); rhsview->scol = child; } else if( IS_ITEXTVIEW( child ) ) { gtk_table_attach_defaults( GTK_TABLE( rhsview->table ), GTK_WIDGET( child ), 0, 1, 2, 3 ); rhsview->itext = child; } else { gtk_table_attach_defaults( GTK_TABLE( rhsview->table ), GTK_WIDGET( child ), 0, 1, 0, 1 ); rhsview->graphic = child; g_assert( IS_GRAPHICVIEW( child ) ); } VIEW_CLASS( parent_class )->child_add( parent, child ); } static void rhsview_child_remove( View *parent, View *child ) { Rhsview *rhsview = RHSVIEW( parent ); if( IS_SUBCOLUMNVIEW( child ) ) rhsview->scol = NULL; else if( IS_ITEXTVIEW( child ) ) rhsview->itext = NULL; else rhsview->graphic = NULL; VIEW_CLASS( parent_class )->child_remove( parent, child ); } static void rhsview_class_init( RhsviewClass *class ) { vObjectClass *vobject_class = (vObjectClass*) class; ViewClass *view_class = (ViewClass*) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = rhsview_refresh; view_class->link = rhsview_link; view_class->child_add = rhsview_child_add; view_class->child_remove = rhsview_child_remove; view_class->reset = rhsview_reset; } static void rhsview_init( Rhsview *rhsview ) { rhsview->rview = NULL; /* Attached on refresh. */ rhsview->graphic = NULL; rhsview->scol = NULL; rhsview->itext = NULL; rhsview->table = gtk_table_new( 3, 1, FALSE ); gtk_box_pack_start( GTK_BOX( rhsview ), rhsview->table, TRUE, FALSE, 0 ); gtk_widget_show( rhsview->table ); rhsview->flags = 0; gtk_widget_show( GTK_WIDGET( rhsview ) ); } GtkType rhsview_get_type( void ) { static GtkType rhsview_type = 0; if( !rhsview_type ) { static const GtkTypeInfo rhsview_info = { "Rhsview", sizeof( Rhsview ), sizeof( RhsviewClass ), (GtkClassInitFunc) rhsview_class_init, (GtkObjectInitFunc) rhsview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; rhsview_type = gtk_type_unique( TYPE_VIEW, &rhsview_info ); } return( rhsview_type ); } View * rhsview_new( void ) { Rhsview *rhsview = gtk_type_new( TYPE_RHSVIEW ); return( VIEW( rhsview ) ); } nip2-8.7.1/src/parse.y0000644000175000017500000010651513351443023011421 00000000000000%{ /* Parse ip's macro language. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ /* trace text read system #define DEBUG_CHARACTER */ /* The lexer from lex.l. */ int yylex( void ); void yyrestart( FILE *input_file ); /* Declare file-private stuff, shared with the lexer. Bison will put this * stuff into parse.h, so just declare, don't define. Sadly we can't have * these things static :( */ /* Global .. the symbol whose definition we are currently parsing, the symbol * which all defs in this parse action should be made local to. */ extern Symbol *current_symbol; extern Symbol *root_symbol; /* The current parse context. */ extern Compile *current_compile; extern ParseNode *current_parsenode; /* The kit we are adding new symbols to. */ extern Toolkit *current_kit; /* Where it should go in the kit. */ extern int tool_position; /* Lineno of start of last top-level def. */ extern int last_top_lineno; /* Text we've gathered in this lex. */ extern char lex_text_buffer[MAX_STRSIZE]; /* Stack of symbols for parser - each represents a new scope level. */ extern Symbol *scope_stack_symbol[MAX_SSTACK]; extern Compile *scope_stack_compile[MAX_SSTACK]; extern int scope_sp; /* Use to generate unique ids for anonymouse parse objects (eg. lambdas etc). */ extern int parse_object_id; /* Get text for parsed objects. */ char *input_text( char *out ); void input_reset( void ); void input_push( int n ); void input_backtoch( char ch ); void input_back1( void ); void input_pop( void ); /* Nest and unnest scopes. */ void scope_push( void ); void scope_pop( void ); void scope_pop_all( void ); void scope_reset( void ); /* Helper functions. */ void *parse_toplevel_end( Symbol *sym ); void *parse_access_end( Symbol *sym, Symbol *main ); %} %union { struct sym_table *yy_symtab; ParseNode *yy_node; char *yy_name; ParseConst yy_const; UnOp yy_uop; BinOp yy_binop; } %token TK_TAG TK_IDENT TK_CONST TK_DOTDOTDOT TK_LAMBDA TK_FROM TK_TO TK_SUCHTHAT %token TK_UMINUS TK_UPLUS TK_POW %token TK_LESS TK_LESSEQ TK_MORE TK_MOREEQ TK_NOTEQ %token TK_LAND TK_LOR TK_BAND TK_BOR TK_JOIN TK_DIFF %token TK_IF TK_THEN TK_ELSE %token TK_CHAR TK_SHORT TK_CLASS TK_SCOPE %token TK_INT TK_FLOAT TK_DOUBLE TK_SIGNED TK_UNSIGNED TK_COMPLEX %token TK_SEPARATOR TK_DIALOG TK_LSHIFT TK_RSHIFT %type expr binop uop rhs list_expression comma_list body %type simple_pattern complex_pattern list_pattern %type leaf_pattern %type crhs cexprlist prhs lambda %type TK_CONST %type TK_IDENT TK_TAG %left TK_SUCHTHAT %left TK_LAMBDA %nonassoc TK_IF %left ',' %left TK_TO %left TK_LOR %left TK_LAND '@' %left TK_BOR %left '^' %left TK_BAND %nonassoc TK_EQ TK_NOTEQ TK_PEQ TK_PNOTEQ %nonassoc TK_LESS TK_LESSEQ TK_MORE TK_MOREEQ %left TK_LSHIFT TK_RSHIFT %left '+' '-' %left '*' '/' '%' %left '!' '~' TK_JOIN TK_DIFF TK_UMINUS TK_UPLUS %right TK_POW ':' %right TK_CONST '(' %right TK_IDENT TK_TAG TK_SCOPE '[' %right TK_APPLICATION %left '?' '.' %start select /* Our syntax for list comprehensions is not LALR(1). We have: simple_pattern '<-' expr ';' | expr ';' simple_pattern can be something like a:x which is also an expr. We don't know which branch to take until we see a '<' or a ';'. Use bison's GLR system to parse this, and ignore the first 13 reduce/reduce conflicts caused by this ambiguity. FIXME ... we now depend on bison, but we still have some yacc compatibility stuff in here, and we don't use all of bison's nice features (eg. for tracking line numbers in the source file). Fix this up at some stage. */ %glr-parser %expect-rr 13 %error-verbose %% select: ',' main | '^' single_definition | '*' params_plus_rhs optsemi { compile_check( current_compile ); } | prhs { char buf[MAX_STRSIZE]; current_compile->tree = $1; /* Junk any old text. */ IM_FREE( current_compile->text ); IM_FREE( current_compile->prhstext ); IM_FREE( current_compile->rhstext ); /* Set new text. */ IM_SETSTR( current_compile->rhstext, input_text( buf ) ); compile_check( current_compile ); } ; prhs: TK_BAND expr { $$ = $2; } | '@' cexprlist { $$ = $2; } ; main: /* Empty */ | main single_definition ; single_definition: directive { tool_position += 1; } | toplevel_definition optsemi { tool_position += 1; } ; directive: TK_SEPARATOR { Tool *tool; if( !is_top( current_symbol ) ) yyerror( _( "not top level" ) ); tool = tool_new_sep( current_kit, tool_position ); tool->lineno = input_state.lineno; input_reset(); } | TK_DIALOG TK_CONST TK_CONST { Tool *tool; if( !is_top( current_symbol ) ) yyerror( _( "not top level" ) ); /* Should have two strings. */ if( $2.type != PARSE_CONST_STR || $3.type != PARSE_CONST_STR ) yyerror( _( "not strings" ) ); /* Add tool. */ tool = tool_new_dia( current_kit, tool_position, $2.val.str, $3.val.str ); if( !tool ) yyerror( error_get_sub() ); tool->lineno = input_state.lineno; /* Cast away const here. */ tree_const_destroy( (ParseConst *) &$2 ); tree_const_destroy( (ParseConst *) &$3 ); input_reset(); } ; toplevel_definition: { last_top_lineno = input_state.lineno; scope_reset(); current_compile = root_symbol->expr->compile; } definition { input_reset(); } ; /* Parse a new defining occurence. This can be a local or a top-level. */ definition: simple_pattern { Symbol *sym; /* Two forms: , or . * Enforce the no-args-to-pattern-assignment rule in the arg * pattern parser. */ if( $1->type == NODE_LEAF ) { const char *name = IOBJECT( $1->leaf )->name; /* Make a new defining occurence. */ sym = symbol_new_defining( current_compile, name ); (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); } else { char name[256]; /* We have . Make an anon symbol for this * value, then the variables in the pattern become * toplevels which access that. */ if( !compile_pattern_has_leaf( $1 ) ) yyerror( _( "left-hand-side pattern " "contains no identifiers" ) ); im_snprintf( name, 256, "$$pattern_lhs%d", parse_object_id++ ); sym = symbol_new_defining( current_compile, name ); sym->generated = TRUE; (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); } /* Note on the enclosing last_sym. Things like the program * window use this to work out what sym to display after a * parse. symbol_dispose() is careful to NULL this out. */ current_compile->last_sym = sym; /* Initialise symbol parsing variables. Save old current symbol, * add new one. */ scope_push(); current_symbol = sym; current_compile = sym->expr->compile; g_assert( !current_compile->param ); g_assert( current_compile->nparam == 0 ); /* Junk any old def text. */ IM_FREE( current_compile->text ); IM_FREE( current_compile->prhstext ); IM_FREE( current_compile->rhstext ); } params_plus_rhs { compile_check( current_compile ); /* Link unresolved names into the outer scope. */ compile_resolve_names( current_compile, compile_get_parent( current_compile ) ); /* Is this the end of a top-level? Needs extra work to add to * the enclosing toolkit etc. */ if( is_scope( symbol_get_parent( current_symbol ) ) ) parse_toplevel_end( current_symbol ); /* Is this a pattern definition? Expand the pattern to a * set of access defs. */ if( $1->type != NODE_LEAF ) { Compile *parent = compile_get_parent( current_compile ); GSList *built_syms; built_syms = compile_pattern_lhs( parent, current_symbol, $1 ); if( is_scope( symbol_get_parent( current_symbol ) ) ) slist_map( built_syms, (SListMapFn) parse_toplevel_end, NULL ); slist_map( built_syms, (SListMapFn) parse_access_end, current_symbol ); g_slist_free( built_syms ); } scope_pop(); } ; /* Parse params/body/locals into current_expr */ params_plus_rhs: { input_push( 1 ); /* We've already read the character past the end of the * identifier (that's why we know the identifier is over). */ input_back1(); } params { input_push( 2 ); input_backtoch( '=' ); } body { current_compile->tree = $4; g_assert( current_compile->tree ); input_push( 4 ); } locals { char buf[MAX_STRSIZE]; input_pop(); /* Save body text as rhstext. */ IM_SETSTR( current_compile->rhstext, input_text( buf ) ); input_pop(); /* Save params '=' body as prhstext. */ IM_SETSTR( current_compile->prhstext, input_text( buf ) ); input_pop(); /* Save full text of definition. */ IM_SETSTR( current_compile->text, input_text( buf ) ); #ifdef DEBUG printf( "%s->compile->text = \"%s\"\n", IOBJECT( current_compile->sym )->name, current_compile->text ); printf( "%s->compile->prhstext = \"%s\"\n", IOBJECT( current_compile->sym )->name, current_compile->prhstext ); printf( "%s->compile->rhstext = \"%s\"\n", IOBJECT( current_compile->sym )->name, current_compile->rhstext ); #endif /*DEBUG*/ } ; params: /* Empty */ | params simple_pattern { Symbol *sym; /* If the pattern is just an identifier, make it a direct * parameter. Otherwise make an anon param and put the pattern * in as a local with the same id. * * fred [a] = 12; * * parses to: * * fred $$arg42 = 12 { $$patt42 = [a]; } * * A later pass creates the "a = $$arg42?0" definition. */ if( $2->type == NODE_LEAF ) { const char *name = IOBJECT( $2->leaf )->name; /* Make defining occurence. */ sym = symbol_new_defining( current_compile, name ); (void) symbol_parameter_init( sym ); } else { char name[256]; im_snprintf( name, 256, "$$arg%d", parse_object_id ); sym = symbol_new_defining( current_compile, name ); sym->generated = TRUE; (void) symbol_parameter_init( sym ); im_snprintf( name, 256, "$$patt%d", parse_object_id++ ); sym = symbol_new_defining( current_compile, name ); sym->generated = TRUE; (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); sym->expr->compile->tree = $2; } } ; body : '=' TK_CLASS crhs { $$ = $3; } | rhs { $$ = $1; } ; crhs: { ParseNode *pn = tree_class_new( current_compile ); input_push( 3 ); scope_push(); current_symbol = current_compile->super; current_compile = current_symbol->expr->compile; current_parsenode = pn; } cexprlist { Compile *parent = compile_get_parent( current_compile ); char buf[MAX_STRSIZE]; int len; (void) input_text( buf ); /* Always read 1 char too many. */ if( (len = strlen( buf )) > 0 ) buf[len - 1] = '\0'; IM_SETSTR( current_compile->rhstext, buf ); input_pop(); current_compile->tree = $2; if( current_compile->tree->elist ) parent->has_super = TRUE; /* Do some checking. */ compile_check( current_compile ); /* Link unresolved names. */ compile_resolve_names( current_compile, parent ); scope_pop(); $$ = current_parsenode; current_parsenode = NULL; } ; rhs: '=' expr { $$ = $2; } | '=' expr ',' expr optsemi rhs { $$ = tree_ifelse_new( current_compile, $4, $2, $6 ); } ; locals: ';' | '{' deflist '}' | '{' '}' ; optsemi: /* Empty */ | ';' optsemi ; deflist: definition { input_pop(); input_push( 5 ); } optsemi | deflist definition { input_pop(); input_push( 6 ); } optsemi ; cexprlist: /* Empty */ { $$ = tree_super_new( current_compile ); } | cexprlist expr %prec TK_APPLICATION { $$ = tree_super_extend( current_compile, $1, $2 ); } ; expr: '(' expr ')' { $$ = $2; } | TK_CONST { $$ = tree_const_new( current_compile, $1 ); } | TK_IDENT { $$ = tree_leaf_new( current_compile, $1 ); im_free( $1 ); } | TK_TAG { $$ = tree_tag_new( current_compile, $1 ); im_free( $1 ); } | TK_SCOPE { $$ = tree_leaf_new( current_compile, IOBJECT( symbol_get_scope( current_symbol ) )->name ); } | TK_IF expr TK_THEN expr TK_ELSE expr %prec TK_IF { $$ = tree_ifelse_new( current_compile, $2, $4, $6 ); } | expr expr %prec TK_APPLICATION { $$ = tree_appl_new( current_compile, $1, $2 ); } | lambda | list_expression { $$ = $1; } | '(' expr ',' expr ')' { $$ = tree_binop_new( current_compile, BI_COMMA, $2, $4 ); } | binop | uop ; lambda: TK_LAMBDA TK_IDENT %prec TK_LAMBDA { char name[256]; Symbol *sym; /* Make an anonymous symbol local to the current sym, compile * the expr inside that. */ im_snprintf( name, 256, "$$lambda%d", parse_object_id++ ); sym = symbol_new_defining( current_compile, name ); sym->generated = TRUE; (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); /* Initialise symbol parsing variables. Save old current symbol, * add new one. */ scope_push(); current_symbol = sym; current_compile = sym->expr->compile; /* Make the parameter. */ sym = symbol_new_defining( current_compile, $2 ); symbol_parameter_init( sym ); im_free( $2 ); } expr { Symbol *sym; current_compile->tree = $4; if( !compile_check( current_compile ) ) yyerror( error_get_sub() ); /* Link unresolved names in to the outer scope. */ compile_resolve_names( current_compile, compile_get_parent( current_compile ) ); /* The value of the expr is the anon we defined. */ sym = current_symbol; scope_pop(); $$ = tree_leafsym_new( current_compile, sym ); } ; list_expression: '[' expr TK_DOTDOTDOT ']' { $$ = tree_generator_new( current_compile, $2, NULL, NULL ); } | '[' expr TK_DOTDOTDOT expr ']' { $$ = tree_generator_new( current_compile, $2, NULL, $4 ); } | '[' expr ',' expr TK_DOTDOTDOT ']' { $$ = tree_generator_new( current_compile, $2, $4, NULL ); } | '[' expr ',' expr TK_DOTDOTDOT expr ']' { $$ = tree_generator_new( current_compile, $2, $4, $6 ); } | '[' expr TK_SUCHTHAT { char name[256]; Symbol *sym; Compile *enclosing = current_compile; /* Make an anonymous symbol local to the current sym, copy * the map expr inside that. */ im_snprintf( name, 256, "$$lcomp%d", parse_object_id++ ); sym = symbol_new_defining( current_compile, name ); (void) symbol_user_init( sym ); sym->generated = TRUE; (void) compile_new_local( sym->expr ); /* Push a new scope. */ scope_push(); current_symbol = sym; current_compile = sym->expr->compile; /* Somewhere to save the result expr. We have to copy the * expr, as we want it to be bound in $$lcomp's context so * that it can see the generators. */ sym = symbol_new_defining( current_compile, "$$result" ); sym->generated = TRUE; sym->placeholder = TRUE; (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); sym->expr->compile->tree = compile_copy_tree( enclosing, $2, sym->expr->compile ); } generator frompred_list ']' { Symbol *sym; /* The map expr can refer to generator names. Resolve inwards * so it links to the generators. */ compile_resolve_names( compile_get_parent( current_compile ), current_compile ); /* Generate the code for the list comp. */ compile_lcomp( current_compile ); compile_check( current_compile ); /* Link unresolved names outwards. */ compile_resolve_names( current_compile, compile_get_parent( current_compile ) ); /* The value of the expr is the anon we defined. */ sym = current_symbol; scope_pop(); $$ = tree_leafsym_new( current_compile, sym ); } | '[' comma_list ']' { $$ = $2; } | '[' ']' { ParseConst elist; elist.type = PARSE_CONST_ELIST; $$ = tree_const_new( current_compile, elist ); } ; frompred_list: /* Empty */ { } | frompred_list ';' frompred { } ; generator: simple_pattern TK_FROM expr { char name[256]; Symbol *sym; im_snprintf( name, 256, "$$pattern%d", parse_object_id ); sym = symbol_new_defining( current_compile, name ); sym->generated = TRUE; sym->placeholder = TRUE; (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); sym->expr->compile->tree = $1; im_snprintf( name, 256, "$$generator%d", parse_object_id++ ); sym = symbol_new_defining( current_compile, name ); sym->generated = TRUE; sym->placeholder = TRUE; (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); sym->expr->compile->tree = $3; } ; frompred: generator | expr { char name[256]; Symbol *sym; im_snprintf( name, 256, "$$filter%d", parse_object_id++ ); sym = symbol_new_defining( current_compile, name ); sym->generated = TRUE; sym->placeholder = TRUE; (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); sym->expr->compile->tree = $1; } ; comma_list: expr ',' comma_list { $$ = tree_lconst_extend( current_compile, $3, $1 ); } | expr { $$ = tree_lconst_new( current_compile, $1 ); } ; /* How odd, break the "'+' { BI_ADD } | ..." into a separate production and we * get reduce/reduce conflits. Copypaste a lot instead. */ binop: expr '+' expr { $$ = tree_binop_new( current_compile, BI_ADD, $1, $3 ); } | expr ':' expr { $$ = tree_binop_new( current_compile, BI_CONS, $1, $3 ); } | expr '-' expr { $$ = tree_binop_new( current_compile, BI_SUB, $1, $3 ); } | expr '?' expr { $$ = tree_binop_new( current_compile, BI_SELECT, $1, $3 ); } | expr '/' expr { $$ = tree_binop_new( current_compile, BI_DIV, $1, $3 ); } | expr '*' expr { $$ = tree_binop_new( current_compile, BI_MUL, $1, $3 ); } | expr '%' expr { $$ = tree_binop_new( current_compile, BI_REM, $1, $3 ); } | expr TK_JOIN expr { $$ = tree_binop_new( current_compile, BI_JOIN, $1, $3 ); } | expr TK_POW expr { $$ = tree_binop_new( current_compile, BI_POW, $1, $3 ); } | expr TK_LSHIFT expr { $$ = tree_binop_new( current_compile, BI_LSHIFT, $1, $3 ); } | expr TK_RSHIFT expr { $$ = tree_binop_new( current_compile, BI_RSHIFT, $1, $3 ); } | expr '^' expr { $$ = tree_binop_new( current_compile, BI_EOR, $1, $3 ); } | expr TK_LAND expr { $$ = tree_binop_new( current_compile, BI_LAND, $1, $3 ); } | expr TK_BAND expr { $$ = tree_binop_new( current_compile, BI_BAND, $1, $3 ); } | expr '@' expr { $$ = tree_compose_new( current_compile, $1, $3 ); } | expr TK_LOR expr { $$ = tree_binop_new( current_compile, BI_LOR, $1, $3 ); } | expr TK_BOR expr { $$ = tree_binop_new( current_compile, BI_BOR, $1, $3 ); } | expr TK_LESS expr { $$ = tree_binop_new( current_compile, BI_LESS, $1, $3 ); } | expr TK_LESSEQ expr { $$ = tree_binop_new( current_compile, BI_LESSEQ, $1, $3 ); } | expr TK_MORE expr { $$ = tree_binop_new( current_compile, BI_MORE, $1, $3 ); } | expr TK_MOREEQ expr { $$ = tree_binop_new( current_compile, BI_MOREEQ, $1, $3 ); } | expr TK_EQ expr { $$ = tree_binop_new( current_compile, BI_EQ, $1, $3 ); } | expr TK_NOTEQ expr { $$ = tree_binop_new( current_compile, BI_NOTEQ, $1, $3 ); } | expr TK_PEQ expr { $$ = tree_binop_new( current_compile, BI_PEQ, $1, $3 ); } | expr TK_PNOTEQ expr { $$ = tree_binop_new( current_compile, BI_PNOTEQ, $1, $3 ); } | expr '.' expr { $$ = tree_binop_new( current_compile, BI_DOT, $1, $3 ); } | expr TK_DIFF expr { ParseNode *pn1, *pn2; pn1 = tree_leaf_new( current_compile, "difference" ); pn2 = tree_leaf_new( current_compile, "equal" ); pn1 = tree_appl_new( current_compile, pn1, pn2 ); pn1 = tree_appl_new( current_compile, pn1, $1 ); pn1 = tree_appl_new( current_compile, pn1, $3 ); $$ = pn1; } | expr TK_TO expr { ParseNode *pn; pn = tree_leaf_new( current_compile, "mknvpair" ); pn = tree_appl_new( current_compile, pn, $1 ); pn = tree_appl_new( current_compile, pn, $3 ); $$ = pn; } ; signed: /* Nothing */ | TK_SIGNED ; unsigned: /* Nothing */ | TK_UNSIGNED ; uop: '(' unsigned TK_CHAR ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CUCHAR, $5 ); } | '(' TK_SIGNED TK_CHAR ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CSCHAR, $5 ); } | '(' signed TK_SHORT ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CSSHORT, $5 ); } | '(' TK_UNSIGNED TK_SHORT ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CUSHORT, $5 ); } | '(' signed TK_INT ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CSINT, $5 ); } | '(' TK_UNSIGNED TK_INT ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CUINT, $5 ); } | '(' TK_FLOAT ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CFLOAT, $4 ); } | '(' TK_DOUBLE ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CDOUBLE, $4 ); } | '(' TK_COMPLEX ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CCOMPLEX, $4 ); } | '(' TK_DOUBLE TK_COMPLEX ')' expr %prec TK_UMINUS { $$ = tree_unop_new( current_compile, UN_CDCOMPLEX, $5 ); } | TK_UMINUS expr { $$ = tree_unop_new( current_compile, UN_MINUS, $2 ); } | '!' expr { $$ = tree_unop_new( current_compile, UN_NEG, $2 ); } | '~' expr { $$ = tree_unop_new( current_compile, UN_COMPLEMENT, $2 ); } | TK_UPLUS expr { $$ = tree_unop_new( current_compile, UN_PLUS, $2 ); } ; /* Stuff that can appear on the LHS of an equals, or as a parameter pattern. */ simple_pattern: leaf_pattern | '(' leaf_pattern ',' leaf_pattern ')' { $$ = tree_binop_new( current_compile, BI_COMMA, $2, $4 ); } | simple_pattern ':' simple_pattern { $$ = tree_binop_new( current_compile, BI_CONS, $1, $3 ); } | '(' complex_pattern ')' { $$ = $2; } | '[' list_pattern ']' { $$ = $2; } | '[' ']' { ParseConst elist; elist.type = PARSE_CONST_ELIST; $$ = tree_const_new( current_compile, elist ); } ; /* Stuff that can appear in a complex (a, b) pattern. */ leaf_pattern: TK_IDENT { $$ = tree_leaf_new( current_compile, $1 ); im_free( $1 ); } | TK_CONST { $$ = tree_const_new( current_compile, $1 ); } ; /* What can appear in round brackets or a comma list. */ complex_pattern: TK_IDENT TK_IDENT { $$ = tree_pattern_class_new( current_compile, $1, tree_leaf_new( current_compile, $2 ) ); im_free( $1 ); im_free( $2 ); } | simple_pattern ; list_pattern: complex_pattern ',' list_pattern { $$ = tree_lconst_extend( current_compile, $3, $1 ); } | complex_pattern { $$ = tree_lconst_new( current_compile, $1 ); } ; %% /* Return point on syntax error. */ jmp_buf parse_error_point; /* Text we've lexed. */ char lex_text_buffer[MAX_STRSIZE]; VipsBuf lex_text = VIPS_BUF_STATIC( lex_text_buffer ); /* State of input system. */ InputState input_state; /* Defintions for the static decls at the top. We have to put the defs down * here to mkake sure they don't creep in to the generated parser.h. */ /* Actually, we can't make these static :-( since they are declared extern at * the top of the file. */ Symbol *current_symbol; Symbol *root_symbol; Compile *current_compile = NULL; ParseNode *current_parsenode = NULL; Toolkit *current_kit; int tool_position; int last_top_lineno; Symbol *scope_stack_symbol[MAX_SSTACK]; Compile *scope_stack_compile[MAX_SSTACK]; int scope_sp = 0; int parse_object_id = 0; /* Here for errors in parse. * * Bison calls yyerror with only a char* arg. This printf() version is called * from nip2 in a few places during parse. */ void nip2yyerror( const char *sub, ... ) { va_list ap; char buf[4096]; va_start( ap, sub ); (void) im_vsnprintf( buf, 4096, sub, ap ); va_end( ap ); error_top( _( "Parse error." ) ); if( current_compile && current_compile->last_sym ) error_sub( _( "Error in %s: %s" ), IOBJECT( current_compile->last_sym )->name, buf ); else error_sub( _( "Error: %s" ), buf ); longjmp( parse_error_point, -1 ); } /* Bison calls this. */ void yyerror( const char *msg ) { nip2yyerror( "%s", msg ); } /* Attach yyinput to a file. */ void attach_input_file( iOpenFile *of ) { InputState *is = &input_state; #ifdef DEBUG printf( "attach_input_file: \"%s\"\n", of->fname ); #endif /*DEBUG*/ /* Need to clear flex/bison's buffers in case we abandoned the * previous parse. */ yyrestart( NULL ); is->of = of; is->str = NULL; is->strpos = NULL; is->bwp = 0; is->bspsp = 0; is->bsp[is->bspsp] = 0; is->lineno = 1; is->charno = 0; is->pcharno = 0; is->charpos = 0; is->oldchar = -1; /* Init text gatherer. */ vips_buf_rewind( &lex_text ); } /* Attach yyinput to a string. */ void attach_input_string( const char *str ) { InputState *is = &input_state; #ifdef DEBUG printf( "attach_input_string: \"%s\"\n", str ); #endif /*DEBUG*/ yyrestart( NULL ); is->of = NULL; is->str = (char *) str; is->strpos = (char *) str; is->bwp = 0; is->bspsp = 0; is->bsp[is->bspsp] = 0; is->lineno = 1; is->charno = 0; is->pcharno = 0; is->charpos = 0; is->oldchar = -1; /* Init text gatherer. */ vips_buf_rewind( &lex_text ); } /* Read a character from the input. */ int ip_input( void ) { InputState *is = &input_state; int ch; if( is->oldchar >= 0 ) { /* From unget buffer. */ ch = is->oldchar; is->oldchar = -1; } else if( is->of ) { /* Input from file. */ if( (ch = getc( is->of->fp )) == EOF ) return( 0 ); } else { /* Input from string. */ if( (ch = *is->strpos) ) is->strpos++; else /* No counts to update! */ return( 0 ); } /* Update counts. */ if( ch == '\n' ) { is->lineno++; is->pcharno = is->charno + 1; is->charno = 0; } is->charno++; is->charpos++; /* Add this character to the characters we have accumulated for this * definition. */ if( is->bwp >= MAX_STRSIZE ) yyerror( _( "definition is too long" ) ); if( is->bwp >= 0 ) is->buf[is->bwp] = ch; is->bwp++; /* Add to lex text buffer. */ if( is->charno > 0 ) vips_buf_appendc( &lex_text, ch ); #ifdef DEBUG_CHARACTER printf( "ip_input: returning '%c'\n", ch ); #endif /*DEBUG_CHARACTER*/ return( ch ); } /* Unget an input character. */ void ip_unput( int ch ) { InputState *is = &input_state; #ifdef DEBUG_CHARACTER printf( "ip_unput: ungetting '%c'\n", ch ); #endif /*DEBUG_CHARACTER*/ /* Is lex trying to unget the end-of-file marker? Do nothing if it is. */ if( !ch ) return; if( is->of ) { if( ungetc( ch, is->of->fp ) == EOF ) error( "unget buffer overflow" ); } else /* Save extra char here. */ is->oldchar = ch; /* Redo counts. */ if( ch == '\n' ) { is->lineno--; /* Restore previous charno. */ is->charno = is->pcharno; is->pcharno = 0; } is->charno--; is->charpos--; is->bwp--; /* Unget from lex text buffer. */ if( is->charno > 0 ) vips_buf_removec( &lex_text, ch ); } /* Test for end-of-input. */ gboolean is_EOF( void ) { InputState *is = &input_state; if( is->of ) return( feof( is->of->fp ) ); else return( *is->str == '\0' ); } /* Return the text we have accumulated for the current definition. Remove * leading and trailing whitespace and spare semicolons. out needs to be * MAX_STRSIZE. */ char * input_text( char *out ) { InputState *is = &input_state; const char *buf = is->buf; int start = is->bsp[is->bspsp]; int end = is->bwp; int len; int i; for( i = start; i < end && (isspace( buf[i] ) || buf[i] == ';'); i++ ) ; start = i; for( i = end - 1; i > start && (isspace( buf[i] ) || buf[i] == ';'); i-- ) ; end = i + 1; len = end - start; g_assert( len < MAX_STRSIZE - 1 ); im_strncpy( out, buf + start, len + 1 ); out[len] = '\0'; #ifdef DEBUG_CHARACTER printf( "input_text: level %d, returning \"%s\"\n", is->bspsp, out ); #endif /*DEBUG_CHARACTER*/ return( out ); } /* Reset/push/pop input stacks. */ void input_reset( void ) { InputState *is = &input_state; #ifdef DEBUG_CHARACTER printf( "input_reset:\n" ); #endif /*DEBUG_CHARACTER*/ is->bwp = 0; is->bspsp = 0; is->bsp[0] = 0; vips_buf_rewind( &lex_text ); } void input_push( int n ) { InputState *is = &input_state; #ifdef DEBUG_CHARACTER printf( "input_push(%d): going to level %d, %d bytes into buffer\n", n, is->bspsp + 1, is->bwp ); { const int len = IM_MIN( is->bwp, 20 ); int i; for( i = is->bwp - len; i < is->bwp; i++ ) if( is->buf[i] == '\n' ) printf( "@" ); else if( is->buf[i] == ' ' || is->buf[i] == '\t' ) printf( "_" ); else printf( "%c", is->buf[i] ); printf( "\n" ); for( i = 0; i < len; i++ ) printf( "-" ); printf( "^\n" ); } #endif /*DEBUG_CHARACTER*/ is->bspsp += 1; if( is->bspsp >= MAX_SSTACK ) error( "bstack overflow" ); is->bsp[is->bspsp] = is->bwp; } /* Yuk! We've just done an input_push() to try to grab the RHS of a * definition ... unfortunately, due to token readahead, we've probably * already read the start of the RHS. * * Back up the start point to just after the last ch character. */ void input_backtoch( char ch ) { InputState *is = &input_state; int i; for( i = is->bsp[is->bspsp] - 1; i > 0 && is->buf[i] != ch; i-- ) ; if( is->buf[i] == ch ) is->bsp[is->bspsp] = i + 1; } /* Move the last input_push() point back 1 character. */ void input_back1( void ) { InputState *is = &input_state; if( is->bsp[is->bspsp] > 0 ) is->bsp[is->bspsp] -= 1; } void input_pop( void ) { InputState *is = &input_state; #ifdef DEBUG_CHARACTER printf( "input_pop: %d bytes into buffer\n", input_state.bwp ); #endif /*DEBUG_CHARACTER*/ if( is->bspsp <= 0 ) error( "bstack underflow" ); is->bspsp--; } void scope_push( void ) { if( scope_sp == MAX_SSTACK ) error( "sstack overflow" ); scope_stack_symbol[scope_sp] = current_symbol; scope_stack_compile[scope_sp] = current_compile; scope_sp += 1; } void scope_pop( void ) { if( scope_sp <= 0 ) error( "sstack underflow" ); scope_sp -= 1; current_symbol = scope_stack_symbol[scope_sp]; current_compile = scope_stack_compile[scope_sp]; } /* Back to the outermost scope. */ void scope_pop_all( void ) { if( scope_sp > 0 ) { scope_sp = 0; current_symbol = scope_stack_symbol[scope_sp]; current_compile = scope_stack_compile[scope_sp]; } } /* Reset/push/pop parser stacks. */ void scope_reset( void ) { scope_sp = 0; } /* End of top level parse. Fix up the symbol. */ void * parse_toplevel_end( Symbol *sym ) { Tool *tool; tool = tool_new_sym( current_kit, tool_position, sym ); tool->lineno = last_top_lineno; symbol_made( sym ); return( NULL ); } /* Built a pattern access definition. Set the various text fragments from the * def we are drived from. */ void * parse_access_end( Symbol *sym, Symbol *main ) { IM_SETSTR( sym->expr->compile->rhstext, main->expr->compile->rhstext ); IM_SETSTR( sym->expr->compile->prhstext, main->expr->compile->prhstext ); IM_SETSTR( sym->expr->compile->text, main->expr->compile->text ); return( NULL ); } /* Interface to parser. */ static gboolean parse_input( int ch, Symbol *sym, Toolkit *kit, int pos ) { current_kit = kit; current_symbol = sym; root_symbol = sym; tool_position = pos; scope_reset(); input_reset(); /* Signal start nonterminal to parser. */ ip_unput( ch ); if( setjmp( parse_error_point ) ) { /* Restore current_compile. */ scope_pop_all(); if( current_compile ) compile_error_set( current_compile ); return( FALSE ); } yyparse(); /* All ok. */ return( TRUE ); } /* Parse the input into a set of symbols at a position in a kit. * kit may be NULL for no kit. */ gboolean parse_toplevel( Toolkit *kit, int pos ) { gboolean result; current_compile = NULL; result = parse_input( ',', kit->kitg->root, kit, pos ); iobject_changed( IOBJECT( kit ) ); return( result ); } /* Parse a single top-level definition. */ gboolean parse_onedef( Toolkit *kit, int pos ) { gboolean result; current_compile = NULL; result = parse_input( '^', kit->kitg->root, kit, pos ); iobject_changed( IOBJECT( kit ) ); return( result ); } /* Parse new text into "expr". If params is set, str should be "a b = a+b" * (ie. include params), if not, then just rhs (eg. "a+b"). */ gboolean parse_rhs( Expr *expr, ParseRhsSyntax syntax ) { static const char start_ch_table[] = { '&', /* PARSE_RHS */ '*', /* PARSE_PARAMS */ '@' /* PARSE_SUPER */ }; char start_ch = start_ch_table[(int) syntax]; Compile *compile = compile_new_local( expr ); current_compile = compile; if( !parse_input( start_ch, expr->sym, NULL, -1 ) ) { current_compile = NULL; return( FALSE ); } current_compile = NULL; #ifdef DEBUG printf( "parse_rhs:\n" ); dump_tree( compile->tree ); #endif /*DEBUG*/ /* Resolve any dynamic refs. */ expr_resolve( expr ); /* Compile. */ if( compile_object( compile ) ) return( FALSE ); return( TRUE ); } /* Free any stuff the lexer might have allocated. */ void free_lex( int yychar ) { switch( yychar ) { case TK_CONST: tree_const_destroy( &yylval.yy_const ); break; case TK_IDENT: case TK_TAG: IM_FREE( yylval.yy_name ); break; default: break; } } /* Do we have a string of the form "IDENT = .."? Use the lexer to look along * the string checking components, return the IDENT if we do, NULL otherwise. */ char * parse_test_define( void ) { extern int yylex( void ); int yychar; char *ident; ident = NULL; if( setjmp( parse_error_point ) ) { /* Here for yyerror in lex. */ IM_FREE( ident ); return( NULL ); } if( (yychar = yylex()) != TK_IDENT ) { free_lex( yychar ); return( NULL ); } ident = yylval.yy_name; if( (yychar = yylex()) != '=' ) { free_lex( yychar ); IM_FREE( ident ); return( NULL ); } return( ident ); } /* Do we have a string like "Workspaces.untitled.A1 = .."? Check for the * symbols as we see them, make the last one and return it. Used by --set. */ Symbol * parse_set_symbol( void ) { int yychar; extern int yylex( void ); Compile *compile = symbol_root->expr->compile; char *ident; Symbol *sym; ident = NULL; if( setjmp( parse_error_point ) ) { /* Here for yyerror in lex. */ IM_FREE( ident ); return( NULL ); } do { if( (yychar = yylex()) != TK_IDENT && yychar != TK_TAG ) { free_lex( yychar ); yyerror( _( "identifier expected" ) ); } ident = yylval.yy_name; switch( (yychar = yylex()) ) { case '.': /* There's a dot, so we expect another identifier to * come. Look up this one and move to that context. */ if( !(sym = compile_lookup( compile, ident )) ) nip2yyerror( _( "'%s' does not exist" ), ident ); if( !sym->expr || !sym->expr->compile ) nip2yyerror( _( "'%s' has no members" ), ident ); compile = sym->expr->compile; IM_FREE( ident ); break; case '=': /* This is the final identifier: create the symbol in * this context. */ sym = symbol_new_defining( compile, ident ); IM_FREE( ident ); break; default: free_lex( yychar ); yyerror( _( "'.' or '=' expected" ) ); } } while( yychar != '=' ); return( sym ); } nip2-8.7.1/src/idialog.h0000644000175000017500000001042413351443023011667 00000000000000/* make and manage dialogs ... subclass off this for dialog boxes */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef IDIALOG_H #define IDIALOG_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define TYPE_IDIALOG (idialog_get_type()) #define IDIALOG( obj ) (GTK_CHECK_CAST( (obj), TYPE_IDIALOG, iDialog )) #define IDIALOG_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_IDIALOG, iDialogClass )) #define IS_IDIALOG( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IDIALOG )) #define IS_IDIALOG_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_IDIALOG )) typedef struct _iDialog iDialog; typedef void (*iDialogFreeFn)( iDialog *, void * ); struct _iDialog { iWindow parent_object; /* My instance vars. */ iObject *iobject; /* Kill dialog if this obj goes */ guint destroy_sid; /* Signal id for obj destroy */ GtkWidget *work; /* Our work area */ GtkWidget *hb; GtkWidget *bb; GSList *ok_l; /* List of OKbutton as set by user */ GSList *ok_disp_l; /* List of OKbutton as displayed */ GSList *ok_but_l; /* List of OK GtkButton as displayed */ GtkWidget *but_cancel; GtkWidget *but_help; GtkWidget *tog_pin; /* Optional pinup widget */ GtkEntry *entry; /* Last entry we added as default */ /* Flags. */ gboolean modal; /* Modal/non-modal */ gboolean pinup; /* Stay up on OK */ gboolean nosep; /* Suppress hseparator */ gboolean button_focus; /* TRUE to focus buttons */ /* Name of help tag ... if set, make a help button and link to display * of this. */ char *help_tag; /* What we label the cancel button as (if any). Usually * GTK_STOCK_CANCEL, but instant-apply dialogs should change this to * GTK_STOCK_CLOSE. */ const char *cancel_text; /* Per-instance build function. */ iWindowBuildFn build; void *build_a, *build_b, *build_c; /* Our callbacks. */ iWindowFn cancel_cb; iWindowFn popdown_cb; iDialogFreeFn destroy_cb; /* Called from _destroy() */ void *client; /* Client data for callbacks */ void *arg; /* Misc thing provided to client */ /* Notify our parent when we finish. */ iWindowNotifyFn nfn; void *sys; }; typedef struct _iDialogClass { iWindowClass parent_class; /* Our methods. */ } iDialogClass; void idialog_free_client( iDialog *idlg, void *client ); void idialog_set_ok_button_state( iDialog *idlg, gboolean state ); GtkType idialog_get_type( void ); GtkWidget *idialog_new( void ); void idialog_set_iobject( iDialog *idlg, iObject *iobject ); void idialog_set_modal( iDialog *, gboolean ); void idialog_set_pinup( iDialog *idlg, gboolean pinup ); void idialog_set_nosep( iDialog *, gboolean ); void idialog_set_button_focus( iDialog *idlg, gboolean button_focus ); void idialog_set_help_tag( iDialog *, const char *help_tag ); void idialog_set_callbacks( iDialog *, iWindowFn cancel_cb, iWindowFn popdown_cb, iDialogFreeFn destroy_cb, void *client ); void idialog_add_ok( iDialog *, iWindowFn done_cb, const char *fmt, ... ) __attribute__((format(printf, 3, 4))); void idialog_set_notify( iDialog *, iWindowNotifyFn, void * ); void idialog_set_build( iDialog *, iWindowBuildFn, void *, void *, void * ); void idialog_set_cancel_text( iDialog *, const char *cancel_text ); void idialog_set_default_entry( iDialog *idlg, GtkEntry *entry ); void idialog_init_entry( iDialog *idlg, GtkWidget *entry, const char *tip, const char *fmt, ... ) __attribute__((format(printf, 4, 5))); void idialog_done_trigger( iDialog *idlg, int pos ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* IDIALOG_H */ nip2-8.7.1/src/iimage.c0000644000175000017500000003070113351443023011505 00000000000000/* an image class object in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void iimage_dispose( GObject *gobject ) { iImage *iimage; #ifdef DEBUG printf( "iimage_dispose %p\n", gobject ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_IIMAGE( gobject ) ); iimage = IIMAGE( gobject ); slist_map( iimage->classmodels, (SListMapFn) classmodel_iimage_unlink, iimage ); g_assert( !iimage->classmodels ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void iimage_finalize( GObject *gobject ) { iImage *iimage; #ifdef DEBUG printf( "iimage_finalize\n" ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_IIMAGE( gobject ) ); iimage = IIMAGE( gobject ); image_value_destroy( &iimage->value ); IM_FREEF( g_slist_free, iimage->views ); vips_buf_destroy( &iimage->caption_buffer ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Return the main caption. */ static const char * iimage_generate_caption( iObject *iobject ) { iImage *iimage = IIMAGE( iobject ); Imageinfo *ii = iimage->value.ii; VipsBuf *buf = &iimage->caption_buffer; vips_buf_rewind( buf ); image_value_caption( &iimage->value, buf ); if( ii ) { vips_buf_appends( buf, ", " ); iobject_info( IOBJECT( iimage->value.ii ), buf ); } return( vips_buf_all( buf ) ); } static void iimage_info( iObject *iobject, VipsBuf *buf ) { iImage *iimage = IIMAGE( iobject ); Imageinfo *ii = iimage->value.ii; IMAGE *im; if( ii && (im = imageinfo_get( FALSE, ii )) ) { char *filename; if( im_header_get_typeof( im, ORIGINAL_FILENAME ) != 0 ) { if( !im_header_string( im, ORIGINAL_FILENAME, &filename ) ) { vips_buf_appends( buf, _( "Original filename" ) ); vips_buf_appendf( buf, ": %s\n", filename ); } } } } static View * iimage_view_new( Model *model, View *parent ) { return( iimageview_new() ); } static void iimage_edit( GtkWidget *parent, Model *model ) { iImage *iimage = IIMAGE( model ); if( iimage->value.ii ) (void) imageview_new( iimage, parent ); } void iimage_header( GtkWidget *parent, Model *model ) { iImage *iimage = IIMAGE( model ); Row *row = HEAPMODEL( iimage )->row; Workspace *ws = row_get_workspace( row ); GtkWidget *imageheader; char txt[512]; VipsBuf buf = VIPS_BUF_STATIC( txt ); imageheader = imageheader_new( iimage ); row_qualified_name_relative( ws->sym, row, &buf ); iwindow_set_title( IWINDOW( imageheader ), _( "Header for \"%s\"" ), vips_buf_all( &buf ) ); idialog_set_callbacks( IDIALOG( imageheader ), NULL, NULL, NULL, NULL ); idialog_add_ok( IDIALOG( imageheader ), iwindow_true_cb, _( "OK" ) ); iwindow_set_parent( IWINDOW( imageheader ), parent ); idialog_set_iobject( IDIALOG( imageheader ), IOBJECT( iimage ) ); iwindow_build( IWINDOW( imageheader ) ); gtk_widget_show( imageheader ); } static xmlNode * iimage_save( Model *model, xmlNode *xnode ) { iImage *iimage = IIMAGE( model ); xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); /* We always rebuild the value from the expr ... don't save. */ if( !set_iprop( xthis, "image_left", iimage->image_left ) || !set_iprop( xthis, "image_top", iimage->image_top ) || !set_iprop( xthis, "image_mag", iimage->image_mag ) || !set_sprop( xthis, "show_status", bool_to_char( iimage->show_status ) ) || !set_sprop( xthis, "show_paintbox", bool_to_char( iimage->show_paintbox ) ) || !set_sprop( xthis, "show_convert", bool_to_char( iimage->show_convert ) ) || !set_sprop( xthis, "show_rulers", bool_to_char( iimage->show_rulers ) ) || !set_dprop( xthis, "scale", iimage->scale ) || !set_dprop( xthis, "offset", iimage->offset ) || !set_sprop( xthis, "falsecolour", bool_to_char( iimage->falsecolour ) ) || !set_sprop( xthis, "type", bool_to_char( iimage->type ) ) ) return( NULL ); return( xthis ); } static gboolean iimage_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { iImage *iimage = IIMAGE( model ); g_assert( IS_RHS( parent ) ); (void) get_iprop( xnode, "image_left", &iimage->image_left ); (void) get_iprop( xnode, "image_top", &iimage->image_top ); (void) get_iprop( xnode, "image_mag", &iimage->image_mag ); (void) get_bprop( xnode, "show_status", &iimage->show_status ); (void) get_bprop( xnode, "show_paintbox", &iimage->show_paintbox ); (void) get_bprop( xnode, "show_convert", &iimage->show_convert ); (void) get_bprop( xnode, "show_rulers", &iimage->show_rulers ); (void) get_dprop( xnode, "scale", &iimage->scale ); (void) get_dprop( xnode, "offset", &iimage->offset ); (void) get_bprop( xnode, "falsecolour", &iimage->falsecolour ); (void) get_bprop( xnode, "type", &iimage->type ); return( MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ); } /* Need to implement _update_heap(), as not all model fields are directly * editable ... some are set only from expr. See also iregion.c. */ static void * iimage_update_heap( Heapmodel *heapmodel ) { Expr *expr = heapmodel->row->expr; iImage *iimage = IIMAGE( heapmodel ); ImageValue *value = &iimage->value; PElement pe; Imageinfo *ii; #ifdef DEBUG printf( "iimage_update_heap: " ); row_name_print( HEAPMODEL( iimage )->row ); printf( "\n" ); #endif /*DEBUG*/ /* Read the heap into the model, over the top of the unapplied edits. */ if( !class_get_exact( &expr->root, IOBJECT( heapmodel )->name, &pe ) ) return( FALSE ); if( !class_get_member_image( &pe, MEMBER_VALUE, &ii ) ) return( FALSE ); image_value_set( value, ii ); IM_FREE( CLASSMODEL( iimage )->filename ); if( value->ii && imageinfo_is_from_file( value->ii ) ) IM_SETSTR( CLASSMODEL( iimage )->filename, IOBJECT( value->ii )->name ); /* Classmodel _update_heap() will do _instance_new() from the fixed up * model. */ return( HEAPMODEL_CLASS( parent_class )->update_heap( heapmodel ) ); } /* Update iImage from heap. */ static gboolean iimage_class_get( Classmodel *classmodel, PElement *root ) { iImage *iimage = IIMAGE( classmodel ); ImageValue *value = &iimage->value; Imageinfo *ii; #ifdef DEBUG printf( "iimage_class_get: " ); row_name_print( HEAPMODEL( iimage )->row ); printf( "\n" ); #endif /*DEBUG*/ if( !class_get_member_image( root, MEMBER_VALUE, &ii ) ) return( FALSE ); image_value_set( value, ii ); /* Try to update the filename for this row ... get from the meta if we * can. */ IM_FREE( classmodel->filename ); if( ii ) { IMAGE *im; char *filename; if( (im = imageinfo_get( FALSE, ii )) && im_header_get_typeof( im, ORIGINAL_FILENAME ) != 0 ) { if( im_header_string( im, ORIGINAL_FILENAME, &filename ) ) return( FALSE ); } else if( imageinfo_is_from_file( ii ) ) filename = IOBJECT( ii )->name; else filename = NULL; IM_SETSTR( classmodel->filename, filename ); } return( CLASSMODEL_CLASS( parent_class )->class_get( classmodel, root ) ); } /* Make a new "fn value" application. */ static gboolean iimage_class_new( Classmodel *classmodel, PElement *fn, PElement *out ) { Heap *heap = reduce_context->heap; iImage *iimage = IIMAGE( classmodel ); ImageValue *value = &iimage->value; PElement rhs; #ifdef DEBUG printf( "iimage_class_new: " ); row_name_print( HEAPMODEL( iimage )->row ); printf( "\n" ); #endif /*DEBUG*/ /* Make application nodes. */ heap_appl_init( out, fn ); if( !heap_appl_add( heap, out, &rhs ) ) return( FALSE ); PEPUTP( &rhs, ELEMENT_MANAGED, value->ii ); return( TRUE ); } static gboolean iimage_graphic_save( Classmodel *classmodel, GtkWidget *parent, const char *filename ) { iImage *iimage = IIMAGE( classmodel ); ImageValue *value = &iimage->value; char buf[FILENAME_MAX]; /* Can't happen nested-ly, so a static is OK. */ static GTimer *timer = NULL; /* We don't want $VAR etc. in the filename we pass down to the file * ops. */ im_strncpy( buf, filename, FILENAME_MAX ); path_expand( buf ); /* Append the mode string. This needs an expanded filename. */ filesel_add_mode( buf ); if( !timer ) timer = g_timer_new(); g_timer_reset( timer ); if( value->ii ) if( !imageinfo_write( value->ii, buf ) ) return( FALSE ); mainw_recent_add( &mainw_recent_image, filename ); if( main_option_time_save ) { double elapsed; elapsed = g_timer_elapsed( timer, NULL ); error_top( _( "Save timer." ) ); error_sub( _( "Image save took %g seconds." ), elapsed ); return( FALSE ); } return( TRUE ); } gboolean iimage_replace( iImage *iimage, const char *filename ) { Row *row = HEAPMODEL( iimage )->row; iText *itext = ITEXT( HEAPMODEL( iimage )->rhs->itext ); char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_appends( &buf, "Image_file \"" ); vips_buf_appendsc( &buf, TRUE, filename ); vips_buf_appends( &buf, "\"" ); if( itext_set_formula( itext, vips_buf_all( &buf ) ) ) { itext_set_edited( itext, TRUE ); workspace_set_modified( row->ws, TRUE ); (void) expr_dirty( row->expr, link_serial_new() ); mainw_recent_add( &mainw_recent_image, filename ); } return( TRUE ); } static gboolean iimage_graphic_replace( Classmodel *classmodel, GtkWidget *parent, const char *filename ) { return( iimage_replace( IIMAGE( classmodel ), filename ) ); } static void iimage_class_init( iImageClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->dispose = iimage_dispose; gobject_class->finalize = iimage_finalize; iobject_class->user_name = _( "Image" ); iobject_class->generate_caption = iimage_generate_caption; iobject_class->info = iimage_info; model_class->view_new = iimage_view_new; model_class->edit = iimage_edit; model_class->header = iimage_header; model_class->save = iimage_save; model_class->load = iimage_load; heapmodel_class->update_heap = iimage_update_heap; classmodel_class->class_get = iimage_class_get; classmodel_class->class_new = iimage_class_new; classmodel_class->graphic_save = iimage_graphic_save; classmodel_class->graphic_replace = iimage_graphic_replace; classmodel_class->filetype = filesel_type_image; classmodel_class->filetype_pref = "IMAGE_FILE_TYPE"; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void iimage_init( iImage *iimage ) { image_value_init( &iimage->value, CLASSMODEL( iimage ) ); iimage->classmodels = NULL; iimage->views = NULL; iimage->image_left = 0; iimage->image_top = 0; iimage->image_mag = 0; iimage->show_status = FALSE; iimage->show_paintbox = FALSE; iimage->show_convert = FALSE; iimage->show_rulers = FALSE; iimage->scale = 0.0; iimage->offset = 0.0; iimage->falsecolour = FALSE; iimage->type = TRUE; vips_buf_init_dynamic( &iimage->caption_buffer, MAX_LINELENGTH ); iobject_set( IOBJECT( iimage ), CLASS_IMAGE, NULL ); } GtkType iimage_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( iImageClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) iimage_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( iImage ), 32, /* n_preallocs */ (GInstanceInitFunc) iimage_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "iImage", &info, 0 ); } return( type ); } nip2-8.7.1/src/nip2-icon.rc0000644000175000017500000000002713351443023012230 000000000000001 ICON "nip2-icon.ico" nip2-8.7.1/src/model.c0000644000175000017500000005135713351443023011364 00000000000000/* abstract base class for things which form the model half of a model/view * pair */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Stuff from bison ... needed as we call the lexer directly to rewrite * expressions. */ #include "parse.h" /* Our signals. */ enum { SIG_SCROLLTO, /* Views should try to make themselves visible */ SIG_LAYOUT, /* Views should lay out their children */ SIG_RESET, /* Reset edit mode in views */ SIG_FRONT, /* Bring views to front */ SIG_DISPLAY, /* Display on/off */ SIG_LAST }; static iContainerClass *parent_class = NULL; static guint model_signals[SIG_LAST] = { 0 }; /* Base model ... built at startup. */ static Model *model_base = NULL; /* All the model classes which can be built from XML. */ static GSList *model_registered_loadable = NULL; /* The loadstate the lexer gets its rename stuff from. */ ModelLoadState *model_loadstate = NULL; /* Rename list functions. */ static void * model_rename_destroy( ModelRename *rename ) { IM_FREE( rename->old_name ); IM_FREE( rename->new_name ); IM_FREE( rename ); return( NULL ); } static ModelRename * model_rename_new( const char *old_name, const char *new_name ) { ModelRename *rename; if( !(rename = INEW( NULL, ModelRename )) ) return( NULL ); rename->old_name = im_strdup( NULL, old_name ); rename->new_name = im_strdup( NULL, new_name ); if( !rename->old_name || !rename->new_name ) { model_rename_destroy( rename ); return( NULL ); } return( rename ); } gboolean model_loadstate_rename_new( ModelLoadState *state, const char *old_name, const char *new_name ) { /* Make a rename, even if old_name == new_name, since we want to have * new_name on the taken list. */ ModelRename *rename; if( !(rename = model_rename_new( old_name, new_name )) ) return( FALSE ); state->renames = g_slist_prepend( state->renames, rename ); return( TRUE ); } static void * model_loadstate_taken_sub( ModelRename *rename, const char *name ) { if( strcmp( rename->new_name, name ) == 0 ) return( rename ); return( NULL ); } /* Is something already being renamed to @name. */ gboolean model_loadstate_taken( ModelLoadState *state, const char *name ) { return( slist_map( state->renames, (SListMapFn) model_loadstate_taken_sub, (char *) name ) != NULL ); } gboolean model_loadstate_column_rename_new( ModelLoadState *state, const char *old_name, const char *new_name ) { if( strcmp( old_name, new_name ) != 0 ) { ModelRename *rename; if( !(rename = model_rename_new( old_name, new_name )) ) return( FALSE ); state->column_renames = g_slist_prepend( state->column_renames, rename ); } return( TRUE ); } /* Is something already being renamed to @name. */ gboolean model_loadstate_column_taken( ModelLoadState *state, const char *name ) { return( !!slist_map( state->column_renames, (SListMapFn) model_loadstate_taken_sub, (char *) name ) ); } void model_loadstate_destroy( ModelLoadState *state ) { /* We are probably registered as the xml error handler ... unregister! */ xmlSetGenericErrorFunc( NULL, NULL ); IM_FREE( state->filename ); IM_FREE( state->filename_user ); IM_FREEF( xmlFreeDoc, state->xdoc ); slist_map( state->renames, (SListMapFn) model_rename_destroy, NULL ); slist_map( state->column_renames, (SListMapFn) model_rename_destroy, NULL ); g_slist_free( state->renames ); if( state->old_dir ) { path_rewrite_add( state->old_dir, NULL, FALSE ); IM_FREE( state->old_dir ); } IM_FREE( state ); } static void model_loadstate_error( ModelLoadState *state, const char *fmt, ... ) { va_list ap; va_start( ap, fmt ); (void) vips_buf_vappendf( &state->error_log, fmt, ap ); va_end( ap ); } static void model_loadstate_error_get( ModelLoadState *state ) { char *utf8; utf8 = f2utf8( vips_buf_all( &state->error_log ) ); error_top( _( "Load failed." ) ); error_sub( _( "Unable to load from file \"%s\". Error log is:\n%s" ), state->filename, utf8 ); g_free( utf8 ); } ModelLoadState * model_loadstate_new( const char *filename, const char *filename_user ) { ModelLoadState *state; if( !(state = INEW( NULL, ModelLoadState )) ) return( NULL ); state->xdoc = NULL; state->renames = NULL; state->column_renames = NULL; state->major = MAJOR_VERSION; state->minor = MINOR_VERSION; state->micro = MICRO_VERSION; state->rewrite_path = FALSE; state->old_dir = FALSE; state->filename = im_strdup( NULL, filename ); if( filename_user ) state->filename_user = im_strdup( NULL, filename_user ); else state->filename_user = im_strdup( NULL, filename ); if( !state->filename || !state->filename_user ) { model_loadstate_destroy( state ); return( NULL ); } vips_buf_init_static( &state->error_log, state->error_log_buffer, MAX_STRSIZE ); xmlSetGenericErrorFunc( state, (xmlGenericErrorFunc) model_loadstate_error ); if( !(state->xdoc = (xmlDoc *) callv_string_filename( (callv_string_fn) xmlParseFile, state->filename, NULL, NULL, NULL )) ) { model_loadstate_error_get( state ); model_loadstate_destroy( state ); return( NULL ); } return( state ); } ModelLoadState * model_loadstate_new_openfile( iOpenFile *of ) { ModelLoadState *state; char load_buffer[MAX_STRSIZE]; if( !(state = INEW( NULL, ModelLoadState )) ) return( NULL ); state->renames = NULL; state->xdoc = NULL; if( !(state->filename = im_strdup( NULL, of->fname )) ) { model_loadstate_destroy( state ); return( NULL ); } vips_buf_init_static( &state->error_log, state->error_log_buffer, MAX_STRSIZE ); xmlSetGenericErrorFunc( state, (xmlGenericErrorFunc) model_loadstate_error ); if( !ifile_read_buffer( of, load_buffer, MAX_STRSIZE ) ) { model_loadstate_destroy( state ); return( NULL ); } if( !(state->xdoc = xmlParseMemory( load_buffer, MAX_STRSIZE )) ) { model_loadstate_error_get( state ); model_loadstate_destroy( state ); return( NULL ); } return( state ); } /* If old_name is on the global rewrite list, rewrite it! Called from the * lexer. */ char * model_loadstate_rewrite_name( char *name ) { ModelLoadState *state = model_loadstate; GSList *i; if( !state || !state->renames ) return( NULL ); for( i = state->renames; i; i = i->next ) { ModelRename *rename = (ModelRename *) (i->data); if( strcmp( name, rename->old_name ) == 0 ) return( rename->new_name ); } return( NULL ); } /* Use the lexer to rewrite an expression, swapping all symbols on the rewrite * list. */ void model_loadstate_rewrite( ModelLoadState *state, char *old_rhs, char *new_rhs ) { int yychar; extern int yylex( void ); model_loadstate = state; attach_input_string( old_rhs ); if( setjmp( parse_error_point ) ) { /* Here for yyerror in lex. Just ignore errors --- the parser * will spot them later anyway. */ model_loadstate = NULL; return; } /* Lex and rewrite. */ state->rewrite_path = FALSE; while( (yychar = yylex()) > 0 ) { /* If we see an Image_file or Matrix_file token, rewrite the * following token if it's a string constant. */ state->rewrite_path = FALSE; if( yychar == TK_IDENT && strcmp( yylval.yy_name, "Image_file" ) == 0 ) state->rewrite_path = TRUE; if( yychar == TK_IDENT && strcmp( yylval.yy_name, "Matrix_file" ) == 0 ) state->rewrite_path = TRUE; free_lex( yychar ); } model_loadstate = NULL; /* Take copy of lexed and rewritten stuff. */ im_strncpy( new_rhs, vips_buf_all( &lex_text ), MAX_STRSIZE ); } View * model_view_new( Model *model, View *parent ) { ModelClass *model_class = MODEL_GET_CLASS( model ); View *view; if( !model_class->view_new ) return( NULL ); view = model_class->view_new( model, parent ); view_link( view, model, parent ); return( view ); } /* Register a model subclass as loadable ... what we allow when we load an * XML node's children. */ void model_register_loadable( ModelClass *model_class ) { model_registered_loadable = g_slist_prepend( model_registered_loadable, model_class ); } void model_scrollto( Model *model, ModelScrollPosition position ) { g_assert( IS_MODEL( model ) ); g_signal_emit( G_OBJECT( model ), model_signals[SIG_SCROLLTO], 0, position ); } void model_layout( Model *model ) { g_assert( IS_MODEL( model ) ); g_signal_emit( G_OBJECT( model ), model_signals[SIG_LAYOUT], 0 ); } void model_front( Model *model ) { g_assert( IS_MODEL( model ) ); g_signal_emit( G_OBJECT( model ), model_signals[SIG_FRONT], 0 ); } void model_display( Model *model, gboolean display ) { if( model ) { g_assert( IS_MODEL( model ) ); g_signal_emit( G_OBJECT( model ), model_signals[SIG_DISPLAY], 0, display ); } } void * model_reset( Model *model ) { g_assert( IS_MODEL( model ) ); g_signal_emit( G_OBJECT( model ), model_signals[SIG_RESET], 0 ); return( NULL ); } void * model_edit( GtkWidget *parent, Model *model ) { ModelClass *model_class = MODEL_GET_CLASS( model ); if( model_class->edit ) model_class->edit( parent, model ); else { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() not implemented for class \"%s\"." ), "edit", G_OBJECT_CLASS_NAME( model_class ) ); } return( NULL ); } void * model_header( GtkWidget *parent, Model *model ) { ModelClass *model_class = MODEL_GET_CLASS( model ); if( model_class->header ) model_class->header( parent, model ); else { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() not implemented for class \"%s\"." ), "header", G_OBJECT_CLASS_NAME( model_class ) ); } return( NULL ); } void * model_save( Model *model, xmlNode *xnode ) { ModelClass *model_class = MODEL_GET_CLASS( model ); if( model_save_test( model ) ) { if( model_class->save && !model_class->save( model, xnode ) ) return( model ); } return( NULL ); } gboolean model_save_test( Model *model ) { ModelClass *model_class = MODEL_GET_CLASS( model ); if( model_class->save_test ) return( model_class->save_test( model ) ); return( TRUE ); } void * model_save_text( Model *model, iOpenFile *of ) { ModelClass *model_class = MODEL_GET_CLASS( model ); if( model_class->save_text && !model_class->save_text( model, of ) ) return( model ); return( NULL ); } void * model_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { ModelClass *model_class = MODEL_GET_CLASS( model ); if( model_class->load ) { if( !model_class->load( model, state, parent, xnode ) ) return( model ); } else { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() not implemented for class \"%s\"." ), "load", G_OBJECT_CLASS_NAME( model_class ) ); } return( NULL ); } void * model_load_text( Model *model, Model *parent, iOpenFile *of ) { ModelClass *model_class = MODEL_GET_CLASS( model ); if( model_class->load_text ) { if( !model_class->load_text( model, parent, of ) ) return( model ); } else { error_top( "Not implemented." ); error_sub( _( "_%s() not implemented for class \"%s\"." ), "load_text", G_OBJECT_CLASS_NAME( model_class ) ); } return( NULL ); } void * model_empty( Model *model ) { ModelClass *model_class = MODEL_GET_CLASS( model ); if( model_class->empty ) model_class->empty( model ); return( NULL ); } static void model_real_scrollto( Model *model, ModelScrollPosition position ) { } static void model_real_front( Model *model ) { } static void model_real_display( Model *model, gboolean display ) { if( display != model->display ) { model->display = display; iobject_changed( IOBJECT( model ) ); } } static xmlNode * model_real_save( Model *model, xmlNode *xnode ) { const char *tname = G_OBJECT_TYPE_NAME( model ); xmlNode *xthis; if( !(xthis = xmlNewChild( xnode, NULL, (xmlChar *) tname, NULL )) ) { error_top( _( "XML library error." ) ); error_sub( _( "model_save: xmlNewChild() failed" ) ); return( NULL ); } if( icontainer_map( ICONTAINER( model ), (icontainer_map_fn) model_save, xthis, NULL ) ) return( NULL ); if( model->window_width != -1 ) { if( !set_iprop( xthis, "window_x", model->window_x ) || !set_iprop( xthis, "window_y", model->window_y ) || !set_iprop( xthis, "window_width", model->window_width ) || !set_iprop( xthis, "window_height", model->window_height ) ) return( NULL ); } return( xthis ); } static void * model_new_xml_sub( ModelClass *model_class, ModelLoadState *state, Model *parent, xmlNode *xnode ) { GtkType type = GTK_CLASS_TYPE( model_class ); const char *tname = gtk_type_name( type ); if( strcasecmp( (char *) xnode->name, tname ) == 0 ) { Model *model = MODEL( g_object_new( type, NULL ) ); if( model_load( model, state, parent, xnode ) ) { g_object_unref( model ); return( model_class ); } return( NULL ); } return( NULL ); } gboolean model_new_xml( ModelLoadState *state, Model *parent, xmlNode *xnode ) { /* FIXME ... slow! some sort of hash? time this at some point */ if( slist_map3( model_registered_loadable, (SListMap3Fn) model_new_xml_sub, state, parent, xnode ) ) return( FALSE ); return( TRUE ); } static gboolean model_real_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { const char *tname = G_OBJECT_TYPE_NAME( model ); xmlNode *i; /* Should just be a sanity check. */ if( strcasecmp( (char *) xnode->name, tname ) != 0 ) { error_top( _( "XML load error." ) ); error_sub( _( "Can't load node of type \"%s\" into " "object of type \"%s\"" ), xnode->name, tname ); return( FALSE ); } (void) get_iprop( xnode, "window_x", &model->window_x ); (void) get_iprop( xnode, "window_y", &model->window_y ); (void) get_iprop( xnode, "window_width", &model->window_width ); (void) get_iprop( xnode, "window_height", &model->window_height ); if( !ICONTAINER( model )->parent ) icontainer_child_add( ICONTAINER( parent ), ICONTAINER( model ), -1 ); for( i = xnode->children; i; i = i->next ) if( !model_new_xml( state, MODEL( model ), i ) ) return( FALSE ); #ifdef DEBUG printf( "model_real_load: finished loading %s (name = %s)\n", tname, NN( IOBJECT( model )->name ) ); #endif /*DEBUG*/ return( TRUE ); } static void model_real_empty( Model *model ) { icontainer_map( ICONTAINER( model ), (icontainer_map_fn) icontainer_child_remove, NULL, NULL ); } static void model_class_init( ModelClass *class ) { iObjectClass *object_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); class->view_new = NULL; class->edit = NULL; class->scrollto = model_real_scrollto; class->layout = NULL; class->front = model_real_front; class->display = model_real_display; class->reset = NULL; class->save = model_real_save; class->save_test = NULL; class->save_text = NULL; class->load = model_real_load; class->load_text = NULL; class->empty = model_real_empty; /* Create signals. */ model_signals[SIG_SCROLLTO] = g_signal_new( "scrollto", G_OBJECT_CLASS_TYPE( object_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ModelClass, scrollto ), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT ); model_signals[SIG_LAYOUT] = g_signal_new( "layout", G_OBJECT_CLASS_TYPE( object_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ModelClass, layout ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); model_signals[SIG_FRONT] = g_signal_new( "front", G_OBJECT_CLASS_TYPE( object_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ModelClass, front ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); model_signals[SIG_RESET] = g_signal_new( "reset", G_OBJECT_CLASS_TYPE( object_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ModelClass, reset ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); model_signals[SIG_DISPLAY] = g_signal_new( "display", G_OBJECT_CLASS_TYPE( object_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ModelClass, display ), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN ); } static void model_init( Model *model ) { model->display = TRUE; /* Magic: -1 means none of these saved settings are valid. It'd be * nice to do something better, but we'd break old workspaces. */ model->window_x = 0; model->window_y = 0; model->window_width = -1; model->window_height = 0; } GType model_get_type( void ) { static GType model_type = 0; if( !model_type ) { static const GTypeInfo info = { sizeof( ModelClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) model_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Model ), 32, /* n_preallocs */ (GInstanceInitFunc) model_init, }; model_type = g_type_register_static( TYPE_ICONTAINER, "Model", &info, 0 ); } return( model_type ); } void model_base_init( void ) { model_base = MODEL( g_object_new( TYPE_MODEL, NULL ) ); /* We have to init some of our other classes to get them registered * with the class loader. */ (void) g_type_class_ref( TYPE_CLOCK ); (void) g_type_class_ref( TYPE_COLOUR ); (void) g_type_class_ref( TYPE_EXPRESSION ); (void) g_type_class_ref( TYPE_FONTNAME ); (void) g_type_class_ref( TYPE_GROUP ); (void) g_type_class_ref( TYPE_IARROW ); (void) g_type_class_ref( TYPE_IIMAGE ); (void) g_type_class_ref( TYPE_IREGION ); (void) g_type_class_ref( TYPE_ITEXT ); (void) g_type_class_ref( TYPE_MATRIX ); (void) g_type_class_ref( TYPE_NUMBER ); (void) g_type_class_ref( TYPE_OPTION ); (void) g_type_class_ref( TYPE_PATHNAME ); (void) g_type_class_ref( TYPE_PLOT ); (void) g_type_class_ref( TYPE_REAL ); (void) g_type_class_ref( TYPE_SLIDER ); (void) g_type_class_ref( TYPE_STRING ); (void) g_type_class_ref( TYPE_TOGGLE ); (void) g_type_class_ref( TYPE_VECTOR ); (void) g_type_class_ref( TYPE_RHS ); (void) g_type_class_ref( TYPE_ROW ); (void) g_type_class_ref( TYPE_SUBCOLUMN ); (void) g_type_class_ref( TYPE_WORKSPACE ); (void) g_type_class_ref( TYPE_COLUMN ); } typedef struct { iDialog *idlg; /* The yesno we run */ Model *model; /* The model we watch */ guint destroy_sid; /* sid for the destroy */ iWindowFn done_cb; /* Call this at the end */ } ModelCheckDestroy; /* OK to destroy. */ static void model_check_destroy_sub( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { ModelCheckDestroy *mcd = (ModelCheckDestroy *) client; mcd->idlg = NULL; IDESTROY( mcd->model ); symbol_recalculate_all(); mcd->done_cb( iwnd, NULL, nfn, sys ); } /* The model we are watching has been killed, maybe by us. */ static void model_check_destroy_destroy_cb( Model *model, ModelCheckDestroy *mcd ) { g_assert( IS_MODEL( model ) ); g_assert( IS_MODEL( mcd->model ) ); g_assert( !mcd->idlg || IS_IDIALOG( mcd->idlg ) ); mcd->model = NULL; mcd->destroy_sid = 0; if( mcd->idlg ) { iWindow *iwnd = IWINDOW( mcd->idlg ); mcd->idlg = NULL; iwindow_kill( iwnd ); } } /* Our dialog is done. */ static void model_check_destroy_finished( void *client, iWindowResult result ) { ModelCheckDestroy *mcd = (ModelCheckDestroy *) client; FREESID( mcd->destroy_sid, mcd->model ); IM_FREE( mcd ); } void model_check_destroy( GtkWidget *parent, Model *model, iWindowFn done_cb ) { char txt[30]; VipsBuf buf = VIPS_BUF_STATIC( txt ); const char *name; ModelCheckDestroy *mcd = INEW( NULL, ModelCheckDestroy ); mcd->idlg = NULL; mcd->model = model; mcd->done_cb = done_cb ? done_cb : iwindow_true_cb; if( IS_SYMBOL( model ) ) { symbol_qualified_name( SYMBOL( model ), &buf ); name = vips_buf_all( &buf ); } else name = IOBJECT( model )->name; mcd->idlg = box_yesno( parent, model_check_destroy_sub, iwindow_true_cb, mcd, model_check_destroy_finished, mcd, GTK_STOCK_DELETE, _( "Delete?" ), _( "Are you sure you want to delete %s \"%s\"?" ), IOBJECT_GET_CLASS_NAME( model ), name ); /* In case someone else kills this model before we do. */ mcd->destroy_sid = g_signal_connect( model, "destroy", G_CALLBACK( model_check_destroy_destroy_cb ), mcd ); } /* Useful for icontainer_map_all() ... trigger all heapmodel_clear_edited() * methods. */ void * model_clear_edited( Model *model ) { void *result; if( IS_HEAPMODEL( model ) && (result = heapmodel_clear_edited( HEAPMODEL( model ) )) ) return( result ); return( NULL ); } nip2-8.7.1/src/call.h0000644000175000017500000001023013351443023011165 00000000000000/* Call vips functions from the graph reducer. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with CALL - http://www.vips.ecs.soton.ac.uk */ /* Maxiumum number of args to a CALL function. */ #define MAX_CALL_ARGS (100) /* Maximum length of a vector we pass to INTVEC etc. */ #define MAX_VEC (10000) typedef enum _CallArgumentType { CALL_NONE = -1, CALL_DOUBLE = 0, CALL_INT, CALL_COMPLEX, CALL_STRING, CALL_IMAGE, CALL_DOUBLEVEC, CALL_DMASK, CALL_IMASK, CALL_IMAGEVEC, CALL_INTVEC, CALL_GVALUE, CALL_INTERPOLATE } CallArgumentType; #define TYPE_CALL_INFO (call_info_get_type()) #define CALL_INFO( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_CALL_INFO, CallInfo )) #define CALL_INFO_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_CALL_INFO, CallInfoClass)) #define IS_CALL_INFO( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_CALL_INFO )) #define IS_CALL_INFO_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_CALL_INFO )) #define CALL_INFO_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_CALL_INFO, CallInfoClass )) /* Stuff we hold about a call to a CALL function. */ typedef struct _CallInfo { iObject parent_object; /* Environment. */ const char *name; im_function *fn; /* Function we call */ Reduce *rc; /* RC we run inside */ /* Args we build. Images in vargv are IMAGE* pointers. */ im_object *vargv; /* vargv we build for CALL */ int nargs; /* Number of args needed from ip */ int nres; /* Number of objects we write back */ int nires; /* Number of images we write back */ int inpos[MAX_CALL_ARGS]; /* Positions of inputs */ int outpos[MAX_CALL_ARGS]; /* Positions of outputs */ /* Input images. Need to track "destroy" on each one (and kill us * in turn). * * RW images are a bit different. These are really output images (we * create the image that gets passed to the operation, just like * output images), but it's a "t" image and we im_copy() an input to * it to init it. * * So RW images appear in both inii and outii, but we don't look for * destroy for it. */ int ninii; Imageinfo *inii[MAX_CALL_ARGS]; unsigned int inii_destroy_sid[MAX_CALL_ARGS]; unsigned int inii_invalidate_sid[MAX_CALL_ARGS]; /* Output images. */ int noutii; Imageinfo *outii[MAX_CALL_ARGS]; unsigned int outii_destroy_sid[MAX_CALL_ARGS]; gboolean use_lut; /* TRUE for using a lut */ /* Cache hash code here. */ unsigned int hash; gboolean found_hash; /* Set if we're in the history cache. */ gboolean in_cache; /* Set if we hold refs in inii/outii that must be dropped. */ gboolean must_drop; } CallInfo; typedef struct _CallInfoClass { iObjectClass parent_class; } CallInfoClass; extern GSList *call_info_all; CallArgumentType call_lookup_type( im_arg_type type ); void call_error( CallInfo *vi ); void call_error_toomany( CallInfo *vi ); GType call_info_get_type( void ); void call_check_all_destroyed( void ); gboolean call_type_needs_input( im_type_desc *ty ); gboolean call_type_makes_output( im_type_desc *ty ); gboolean call_is_callable( im_function *fn ); int call_n_args( im_function *fn ); void call_usage( VipsBuf *buf, im_function *fn ); void call_spine( Reduce *rc, const char *name, HeapNode **arg, PElement *out ); void call_run( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out, im_function *function ); void callva( Reduce *rc, PElement *out, const char *name, ... ); nip2-8.7.1/src/compile.c0000644000175000017500000017167513351443023011722 00000000000000/* Stuff to parse and compile text. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_RESOLVE */ /* regular (and very slow) sanity checks on symbols ... needs DEBUG in * symbol.c as well #define DEBUG_SANITY */ /* count how many nodes we find with common sub-expression removal. #define DEBUG_COMMON */ /* show what everything compiled to #define DEBUG_RESULT */ /* trace list comp compile #define DEBUG_LCOMP */ /* trace pattern LHS generation #define DEBUG_PATTERN */ /* #define DEBUG */ #include "ip.h" static iContainerClass *parent_class = NULL; Compile * compile_get_parent( Compile *compile ) { if( !ICONTAINER( compile->sym )->parent ) return( NULL ); return( COMPILE( ICONTAINER( compile->sym )->parent ) ); } void * compile_name_print( Compile *compile ) { printf( "compile(%p) ", compile ); symbol_name_print( compile->sym ); return( NULL ); } static void * compile_name_sub( Expr *expr, VipsBuf *buf ) { if( expr->row ) { if( !vips_buf_is_empty( buf ) ) vips_buf_appends( buf, ", " ); row_qualified_name( expr->row, buf ); } return( NULL ); } void compile_name( Compile *compile, VipsBuf *buf ) { char txt[256]; VipsBuf buf2 = VIPS_BUF_STATIC( txt ); vips_buf_appends( buf, "\"" ); symbol_qualified_name( compile->sym, buf ); vips_buf_appends( buf, "\"" ); slist_map( compile->exprs, (SListMapFn) compile_name_sub, &buf2 ); if( !vips_buf_is_empty( &buf2 ) ) vips_buf_appendf( buf, " (%s)", vips_buf_all( &buf2 ) ); } static Compile * compile_map_all_sub( Symbol *sym, map_compile_fn fn, void *a ) { if( !sym->expr || !sym->expr->compile ) return( NULL ); else return( compile_map_all( sym->expr->compile, fn, a ) ); } /* Apply a function to a compile ... and any local compiles. Do top-down. */ Compile * compile_map_all( Compile *compile, map_compile_fn fn, void *a ) { Compile *res; /* Us first. */ if( (res = fn( compile, a )) ) return( res ); /* Then any children. */ if( (res = (Compile *) icontainer_map( ICONTAINER( compile ), (icontainer_map_fn) compile_map_all_sub, (void *) fn, a )) ) return( res ); return( NULL ); } /* Look up by name. */ Symbol * compile_lookup( Compile *compile, const char *name ) { return( SYMBOL( icontainer_child_lookup( ICONTAINER( compile ), name ) ) ); } /* Make a dependency. Text in compile refers to sym. */ void compile_link_make( Compile *compile, Symbol *child ) { /* Already a dependency? Don't make a second link. */ if( !g_slist_find( compile->children, child ) ) { /* New link, each direction. */ compile->children = g_slist_prepend( compile->children, child ); child->parents = g_slist_prepend( child->parents, compile ); /* If the child is a forward reference, we may have to patch * this later. Save the pointer-to-child pointer on child. */ if( child->type == SYM_ZOMBIE ) (void) symbol_patch_add( &compile->children->data, child ); } #ifdef DEBUG_SANITY /* Sanity check. */ symbol_sanity( child ); symbol_leaf_set_sanity(); #endif /*DEBUG_SANITY*/ } /* Break a dependency. Text in compile referred to child. */ void * compile_link_break( Compile *compile, Symbol *child ) { /* Sanity check. */ #ifdef DEBUG_SANITY symbol_sanity( child ); symbol_leaf_set_sanity(); #endif /*DEBUG_SANITY*/ /* Must be there. */ g_assert( g_slist_find( compile->children, child ) && g_slist_find( child->parents, compile ) ); compile->children = g_slist_remove( compile->children, child ); child->parents = g_slist_remove( child->parents, compile ); /* Sanity check. */ #ifdef DEBUG_SANITY symbol_sanity( child ); symbol_leaf_set_sanity(); #endif /*DEBUG_SANITY*/ return( NULL ); } void * compile_expr_link_break( Compile *compile, Expr *expr ) { g_assert( expr->compile == compile ); g_assert( g_slist_find( compile->exprs, expr ) ); expr->compile = NULL; compile->exprs = g_slist_remove( compile->exprs, expr ); g_object_unref( G_OBJECT( compile ) ); return( NULL ); } void * compile_expr_link_break_rev( Expr *expr, Compile *compile ) { return( compile_expr_link_break( compile, expr ) ); } void compile_expr_link_make( Compile *compile, Expr *expr ) { g_assert( !expr->compile ); g_assert( !g_slist_find( compile->exprs, expr ) ); g_assert( compile->sym == expr->sym ); expr->compile = compile; compile->exprs = g_slist_prepend( compile->exprs, expr ); g_object_ref( G_OBJECT( compile ) ); iobject_sink( IOBJECT( compile ) ); } static void compile_finalize( GObject *gobject ) { Compile *compile; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_COMPILE( gobject ) ); compile = COMPILE( gobject ); #ifdef DEBUG printf( "compile_finalize: " ); compile_name_print( compile ); printf( "\n" ); #endif /*DEBUG*/ /* My instance destroy stuff. */ /* Junk parse tree. */ slist_map( compile->treefrag, (SListMapFn) tree_node_destroy, NULL ); IM_FREEF( g_slist_free, compile->treefrag ); compile->tree = NULL; /* Break links to all locals. */ IM_FREEF( g_slist_free, compile->param ); compile->nparam = 0; IM_FREEF( g_slist_free, compile->secret ); compile->nsecret = 0; compile->this = NULL; compile->super = NULL; (void) slist_map( compile->children, (SListMapFn) symbol_link_break, compile ); IM_FREEF( g_slist_free, compile->children ); /* Remove static strings we created. */ slist_map( compile->statics, (SListMapFn) managed_destroy_nonheap, NULL ); IM_FREEF( g_slist_free, compile->statics ); /* Junk heap. */ if( compile->heap ) { compile->base.type = ELEMENT_NOVAL; compile->base.ele = (void *) 1; heap_unregister_element( compile->heap, &compile->base ); UNREF( compile->heap ); } /* Junk text. */ IM_FREE( compile->text ); IM_FREE( compile->prhstext ); IM_FREE( compile->rhstext ); compile->sym = NULL; /* If we're being finalized, we must have a ref count of zero, so * there shouldn't be any exprs looking at us. */ g_assert( !compile->exprs ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void compile_class_init( CompileClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = compile_finalize; /* Create signals. */ /* Init default methods. */ } static void compile_init( Compile *compile ) { /* Init our instance fields. */ compile->sym = NULL; compile->exprs = NULL; compile->is_klass = FALSE; compile->has_super = FALSE; compile->text = NULL; compile->prhstext = NULL; compile->rhstext = NULL; compile->tree = NULL; compile->treefrag = NULL; compile->last_sym = NULL; compile->nparam = 0; compile->param = NULL; compile->nsecret = 0; compile->secret = NULL; compile->this = NULL; compile->super = NULL; compile->children = NULL; compile->base.type = ELEMENT_NOVAL; compile->heap = NULL; compile->statics = NULL; } GType compile_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( CompileClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) compile_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Compile ), 32, /* n_preallocs */ (GInstanceInitFunc) compile_init, }; type = g_type_register_static( TYPE_ICONTAINER, "Compile", &info, 0 ); } return( type ); } /* Make a compile linked to an expr. */ Compile * compile_new( Expr *expr ) { Compile *compile = COMPILE( g_object_new( TYPE_COMPILE, NULL ) ); compile->sym = expr->sym; /* Junk any old compile. */ if( expr->compile ) compile_expr_link_break( expr->compile, expr ); compile_expr_link_make( compile, expr ); /* We'll want to be able to do name lookups. */ icontainer_set_hash( ICONTAINER( compile ) ); #ifdef DEBUG printf( "compile_new: " ); compile_name_print( compile ); printf( "\n" ); #endif /*DEBUG*/ return( compile ); } /* Max cells function for symbols. Enough to compile something big. */ static int compile_heap_max_fn( Heap *heap ) { return( 10000 ); } /* Make a exprinfo suitable for a top-level symbol. */ Compile * compile_new_toplevel( Expr *expr ) { Compile *compile = compile_new( expr ); compile->heap = heap_new( compile, compile_heap_max_fn, 100, 1000 ); g_object_ref( G_OBJECT( compile->heap ) ); iobject_sink( IOBJECT( compile->heap ) ); heap_register_element( compile->heap, &compile->base ); return( compile ); } /* Make a exprinfo suitable for a local. */ Compile * compile_new_local( Expr *expr ) { Compile *compile = compile_new( expr ); compile->heap = heap_new( compile, compile_heap_max_fn, 100, 100 ); g_object_ref( G_OBJECT( compile->heap ) ); iobject_sink( IOBJECT( compile->heap ) ); heap_register_element( compile->heap, &compile->base ); return( compile ); } /* Code generation. */ /* Generate a binop. Point arg1 and arg2 at the elements to be filled in: * caller sets them later. First arg is the compile that this operator came * from. */ static gboolean compile_binop( Compile *compile, BinOp bop, PElement *arg1, PElement *arg2, PElement *out ) { Heap *heap = compile->heap; HeapNode *hn1, *hn2, *hn3; PElement e1, e2; if( NEWNODE( heap, hn1 ) ) return( FALSE ); hn1->type = TAG_APPL; PPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( out, ELEMENT_NODE, hn1 ); PEPOINTLEFT( hn1, &e1 ); PEPOINTRIGHT( hn1, arg2 ); if( NEWNODE( heap, hn2 ) ) return( FALSE ); hn2->type = TAG_APPL; PPUT( hn2, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( &e1, ELEMENT_NODE, hn2 ); PEPOINTRIGHT( hn2, arg1 ); PEPOINTLEFT( hn2, &e2 ); if( NEWNODE( heap, hn3 ) ) return( FALSE ); hn3->type = TAG_APPL; PPUT( hn3, ELEMENT_BINOP, bop, ELEMENT_COMPILEREF, compile ); PEPUTP( &e2, ELEMENT_NODE, hn3 ); return( TRUE ); } /* Generate "x.sym". Set x to be NULL and point rhs at it .. caller * fills in later. */ static gboolean compile_dotsym( Compile *compile, Symbol *sym, PElement *rhs, PElement *out ) { PElement e; if( !compile_binop( compile, BI_DOT, rhs, &e, out ) ) return( FALSE ); PEPUTP( &e, ELEMENT_SYMREF, sym ); return( TRUE ); } /* Compile a reference to sym from expr. */ static gboolean compile_reference( Compile *compile, Symbol *sym, PElement *out ) { Heap *heap = compile->heap; Compile *parent = compile_get_parent( compile ); #ifdef DEBUG printf( "generate_reference: ref to " ); symbol_name_print( sym ); printf( "inside " ); compile_name_print( compile ); printf( "\n" ); #endif /*DEBUG*/ if( g_slist_find( compile->param, sym ) || g_slist_find( compile->secret, sym ) ) { /* sym is a simple parameter, easy! */ PEPUTP( out, ELEMENT_SYMBOL, sym ); } else if( is_class( parent ) && (symbol_get_parent( sym ) == parent->sym || g_slist_find( parent->secret, sym )) ) { Symbol *ths = parent->this; /* sym is a member of the same class as expr, or sym is a * secret to our constructor (in which case it'll be in this * as well) ... generate (.sym this) * * Optimisation: don't generate (.this this) */ if( sym == ths ) { PEPUTP( out, ELEMENT_SYMBOL, ths ); } else { PElement rhs; if( !compile_dotsym( compile, sym, &rhs, out ) ) return( FALSE ); PEPUTP( &rhs, ELEMENT_SYMBOL, ths ); } } else if( is_member_enclosing( compile, sym ) ) { Symbol *sths = symbol_get_parent( sym )->expr->compile->this; PElement rhs; /* Sym is a member of an enclosing class ... * generate (.sym ref-to-this-for-that-class) */ if( !compile_dotsym( compile, sym, &rhs, out ) || !compile_reference( compile, sths, &rhs ) ) return( FALSE ); } else { /* some other reference ... generate (sym secret1 .. secretn) * recurse for secrets, since we may have to fetch them from * "this" */ PElement e = *out; PElement f; GSList *l; PEPUTP( &e, ELEMENT_SYMBOL, sym ); /* Build secret args to this sym. */ if( sym->expr && sym->expr->compile ) for( l = sym->expr->compile->secret; l; l = l->next ) { Symbol *arg = SYMBOL( l->data ); HeapNode *hn1; if( NEWNODE( heap, hn1 ) ) return( FALSE ); hn1->type = TAG_APPL; PEPUTLEFT( hn1, &e ); PPUTRIGHT( hn1, ELEMENT_ELIST, NULL ); PEPUTP( &e, ELEMENT_NODE, hn1 ); PEPOINTRIGHT( hn1, &f ); if( !compile_reference( compile, arg, &f ) ) return( FALSE ); } } return( TRUE ); } /* Build a graph with vars still in it. Write result to *out. */ static gboolean compile_graph( Compile *compile, ParseNode *pn, PElement *out ) { Heap *heap = compile->heap; HeapNode *hn1, *hn2, *hn3; PElement e1, e2, e3; GSList *l; switch( pn->type ) { case NODE_APPLY: /* Build apply node. */ if( NEWNODE( heap, hn1 ) ) return( FALSE ); hn1->type = TAG_APPL; PPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( out, ELEMENT_NODE, hn1 ); /* Make sides. */ PEPOINTLEFT( hn1, &e1 ); PEPOINTRIGHT( hn1, &e2 ); if( !compile_graph( compile, pn->arg1, &e1 ) || !compile_graph( compile, pn->arg2, &e2 ) ) return( FALSE ); break; case NODE_UOP: /* Build apply node. */ if( NEWNODE( heap, hn1 ) ) return( FALSE ); hn1->type = TAG_APPL; PPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( out, ELEMENT_NODE, hn1 ); PEPOINTLEFT( hn1, &e1 ); if( NEWNODE( heap, hn2 ) ) return( FALSE ); hn2->type = TAG_APPL; PPUT( hn2, ELEMENT_UNOP, pn->uop, ELEMENT_COMPILEREF, compile ); PEPUTP( &e1, ELEMENT_NODE, hn2 ); /* Build arg. */ PEPOINTRIGHT( hn1, &e2 ); if( !compile_graph( compile, pn->arg1, &e2 ) ) return( FALSE ); break; case NODE_BINOP: if( !compile_binop( compile, pn->biop, &e1, &e2, out ) || !compile_graph( compile, pn->arg1, &e1 ) || !compile_graph( compile, pn->arg2, &e2 ) ) return( FALSE ); break; case NODE_COMPOSE: if( NEWNODE( heap, hn1 ) ) return( FALSE ); hn1->type = TAG_APPL; PPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( out, ELEMENT_NODE, hn1 ); PEPOINTLEFT( hn1, &e1 ); if( NEWNODE( heap, hn2 ) ) return( FALSE ); hn2->type = TAG_APPL; PPUT( hn2, ELEMENT_COMB, COMB_SR, ELEMENT_ELIST, NULL ); PEPUTP( &e1, ELEMENT_NODE, hn2 ); /* Build args. */ PEPOINTRIGHT( hn1, &e2 ); PEPOINTRIGHT( hn2, &e3 ); if( !compile_graph( compile, pn->arg1, &e3 ) || !compile_graph( compile, pn->arg2, &e2 ) ) return( FALSE ); break; case NODE_LEAF: /* A reference to a symbol. */ if( !compile_reference( compile, pn->leaf, out ) ) return( FALSE ); break; case NODE_CLASS: /* Output constructor. */ PEPUTP( out, ELEMENT_CONSTRUCTOR, pn->klass ); break; case NODE_TAG: /* RHS of projection. */ PEPUTP( out, ELEMENT_TAG, pn->tag ); break; case NODE_GENERATOR: /* Build apply nodes. */ if( NEWNODE( heap, hn1 ) ) return( FALSE ); hn1->type = TAG_APPL; PPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( out, ELEMENT_NODE, hn1 ); PEPOINTLEFT( hn1, &e1 ); if( NEWNODE( heap, hn2 ) ) return( FALSE ); hn2->type = TAG_APPL; PPUT( hn2, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( &e1, ELEMENT_NODE, hn2 ); PEPOINTLEFT( hn2, &e2 ); if( NEWNODE( heap, hn3 ) ) return( FALSE ); hn3->type = TAG_APPL; PPUT( hn3, ELEMENT_COMB, COMB_GEN, ELEMENT_ELIST, NULL ); PEPUTP( &e2, ELEMENT_NODE, hn3 ); /* Build args. */ PEPOINTRIGHT( hn1, &e3 ); PEPOINTRIGHT( hn2, &e2 ); PEPOINTRIGHT( hn3, &e1 ); if( !compile_graph( compile, pn->arg1, &e1 ) ) return( FALSE ); if( pn->arg2 ) if( !compile_graph( compile, pn->arg2, &e2 ) ) return( FALSE ); if( pn->arg3 ) if( !compile_graph( compile, pn->arg3, &e3 ) ) return( FALSE ); break; case NODE_LISTCONST: case NODE_SUPER: /* List of expressions. */ /* Make first RHS ... the end of the list. */ e1 = *out; PEPUTP( &e1, ELEMENT_ELIST, NULL ); /* Build @':' for each element. */ for( l = pn->elist; l; l = l->next ) { ParseNode *arg = (ParseNode *) l->data; /* Build apply nodes. */ if( NEWNODE( heap, hn1 ) ) return( FALSE ); hn1->type = TAG_APPL; PPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( &e1, ELEMENT_NODE, hn1 ); PEPOINTLEFT( hn1, &e2 ); if( NEWNODE( heap, hn2 ) ) return( FALSE ); hn2->type = TAG_APPL; PPUT( hn2, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PEPUTP( &e2, ELEMENT_NODE, hn2 ); PEPOINTLEFT( hn2, &e2 ); if( NEWNODE( heap, hn3 ) ) return( FALSE ); hn3->type = TAG_APPL; PPUT( hn3, ELEMENT_BINOP, BI_CONS, ELEMENT_COMPILEREF, compile ); PEPUTP( &e2, ELEMENT_NODE, hn3 ); /* Build arg. */ PEPOINTRIGHT( hn2, &e3 ); if( !compile_graph( compile, arg, &e3 ) ) return( FALSE ); /* APPL is now our LHS. */ PEPOINTRIGHT( hn1, &e1 ); } break; case NODE_CONST: /* Constant. */ switch( pn->con.type ) { case PARSE_CONST_STR: { Managedstring *managedstring; if( !(managedstring = managedstring_find( reduce_context->heap, pn->con.val.str )) ) return( FALSE ); MANAGED_REF( managedstring ); compile->statics = g_slist_prepend( compile->statics, managedstring ); PEPUTP( out, ELEMENT_MANAGED, managedstring ); } break; case PARSE_CONST_CHAR: PEPUTP( out, ELEMENT_CHAR, pn->con.val.ch ); break; case PARSE_CONST_BOOL: PEPUTP( out, ELEMENT_BOOL, pn->con.val.bool ); break; case PARSE_CONST_ELIST: PEPUTP( out, ELEMENT_ELIST, NULL ); break; case PARSE_CONST_NUM: if( !heap_real_new( heap, pn->con.val.num, out ) ) return( FALSE ); break; case PARSE_CONST_COMPLEX: if( !heap_complex_new( heap, 0, pn->con.val.num, out ) ) return( FALSE ); break; default: g_assert( FALSE ); } break; case NODE_NONE: default: g_assert( FALSE ); } return( TRUE ); } /* Parameter abstraction. */ /* Abstract a symbol from the body of a piece of graph. Set *used if we found * the symbol in this piece of graph ... ie. if our caller should add an * Sx-combinator for us. Update *root with the new piece of graph. */ static int compile_abstract_body( Compile *compile, PElement *root, Symbol *sym, gboolean *used ) { Heap *heap = compile->heap; HeapNode *hn; HeapNode *hn1; PElement e1, e2; gboolean b1, b2; CombinatorType comb; switch( PEGETTYPE( root ) ) { case ELEMENT_NODE: hn = PEGETVAL( root ); switch( hn->type ) { case TAG_APPL: case TAG_CONS: b1 = FALSE; b2 = FALSE; PEPOINTLEFT( hn, &e1 ); PEPOINTRIGHT( hn, &e2 ); if( compile_abstract_body( compile, &e1, sym, &b1 ) || compile_abstract_body( compile, &e2, sym, &b2 ) ) return( -1 ); if( PEISCOMB( &e2 ) && PEGETCOMB( &e2 ) == COMB_I && !b1 && b2 && hn->type == TAG_APPL ) { PEPUTPE( root, &e1 ); *used = TRUE; } else if( b1 || b2 ) { if( b1 && !b2 ) comb = COMB_SL; else if( !b1 && b2 ) comb = COMB_SR; else comb = COMB_S; /* Generate Sx combinator. */ if( NEWNODE( heap, hn1 ) ) return( -1 ); hn1->type = TAG_APPL; PPUTLEFT( hn1, ELEMENT_COMB, comb ); PEPUTRIGHT( hn1, &e1 ); PEPUTP( &e1, ELEMENT_NODE, hn1 ); /* We've used the var too! */ *used = TRUE; } break; case TAG_DOUBLE: case TAG_COMPLEX: case TAG_CLASS: case TAG_GEN: break; case TAG_FILE: case TAG_FREE: default: g_assert( FALSE ); } break; case ELEMENT_SYMBOL: if( SYMBOL( PEGETVAL( root ) ) == sym ) { /* Found an instance! Make an I combinator. */ *used = TRUE; PEPUTP( root, ELEMENT_COMB, COMB_I ); } break; case ELEMENT_CONSTRUCTOR: /* set used .. to stop K being generated for this * class parameter. */ *used = TRUE; break; case ELEMENT_MANAGED: case ELEMENT_CHAR: case ELEMENT_BOOL: case ELEMENT_BINOP: case ELEMENT_UNOP: case ELEMENT_COMB: case ELEMENT_ELIST: case ELEMENT_SYMREF: case ELEMENT_COMPILEREF: case ELEMENT_NOVAL: case ELEMENT_TAG: /* Leave alone. */ break; default: g_assert( FALSE ); } return( 0 ); } /* Abstract a symbol from a graph. As above, but make a K if the symbol is * entirely unused. */ static void * compile_abstract_symbol( Symbol *sym, Compile *compile, PElement *root ) { Heap *heap = compile->heap; gboolean b; #ifdef DEBUG printf( "abstracting " ); symbol_name_print( sym ); printf( "\n" ); #endif /*DEBUG*/ b = FALSE; if( compile_abstract_body( compile, root, sym, &b ) ) return( sym ); if( !b ) { HeapNode *hn1; /* Parameter not used! Need a K. */ if( NEWNODE( heap, hn1 ) ) return( sym ); hn1->type = TAG_APPL; PPUTLEFT( hn1, ELEMENT_COMB, COMB_K ); PEPUTRIGHT( hn1, root ); /* Update root. */ PEPUTP( root, ELEMENT_NODE, hn1 ); } return( NULL ); } /* Common sub-expression elimination. */ #ifdef DEBUG_COMMON static void * compile_node_count_sub( HeapNode *hn, int *n ) { *n += 1; return( NULL ); } static int compile_node_count( HeapNode *hn ) { int n; n = 0; heap_map( hn, (heap_map_fn) compile_node_count_sub, &n, NULL ); return( n ); } /* Accumulate total saved here during walk of this tree. */ static int compile_node_sum; #endif /*DEBUG_COMMON*/ /* A hash code we calculate from a bit of heap. */ typedef gpointer CompileHash; /* Combine two hashes. */ #define COMPILEHASH_ADD( A, B ) \ GUINT_TO_POINTER( GPOINTER_TO_UINT( A ) + GPOINTER_TO_UINT( B ) ) /* An int to a hash. */ #define INT_TO_HASH GUINT_TO_POINTER /* Build one of these during sharing analysis. From node pointers to * hash codes, and from hash codes to a list of matching node pointers. */ typedef struct _CompileShare { Compile *compile; GHashTable *node2hash; GHashTable *hash2nodel; } CompileShare; static gboolean compile_share_destroy_sub( gpointer key, gpointer value, gpointer user_data ) { if( value ) g_slist_free( (GSList *) value ); return( TRUE ); } static void compile_share_destroy( CompileShare *share ) { share->compile = NULL; if( share->node2hash ) { g_hash_table_destroy( share->node2hash ); share->node2hash = NULL; } if( share->hash2nodel ) { g_hash_table_foreach_remove( share->hash2nodel, compile_share_destroy_sub, NULL ); g_hash_table_destroy( share->hash2nodel ); share->hash2nodel = NULL; } } static void compile_share_init( CompileShare *share, Compile *compile ) { share->compile = compile; share->node2hash = g_hash_table_new( NULL, g_direct_equal ); share->hash2nodel = g_hash_table_new( NULL, g_direct_equal ); } /* Remove a heapnode from the share. */ static void * compile_share_remove( HeapNode *hn, CompileShare *share ) { CompileHash hash; if( (hash = g_hash_table_lookup( share->node2hash, hn )) ) { GSList *nodel; if( (nodel = g_hash_table_lookup( share->hash2nodel, hash )) ) { nodel = slist_remove_all( nodel, hn ); g_hash_table_replace( share->hash2nodel, hash, nodel ); } g_hash_table_remove( share->node2hash, hn ); } return( NULL ); } /* Add a new heapnode. */ static void compile_share_add( CompileShare *share, HeapNode *hn, CompileHash hash ) { /* Make sure hash is non-zero (very unlikely). */ if( !hash ) hash = INT_TO_HASH( 1 ); if( !g_hash_table_lookup( share->node2hash, hn ) ) { GSList *nodel; g_hash_table_insert( share->node2hash, hn, hash ); if( (nodel = g_hash_table_lookup( share->hash2nodel, hash )) ) { nodel = g_slist_prepend( nodel, hn ); g_hash_table_replace( share->hash2nodel, hash, nodel ); } else { nodel = g_slist_prepend( NULL, hn ); g_hash_table_insert( share->hash2nodel, hash, nodel ); } } } /* From a HeapNode, find a list of the other heapnodes which hashed to the same * value. */ static GSList * compile_share_lookup( CompileShare *share, HeapNode *hn ) { CompileHash hash; if( (hash = (CompileHash) g_hash_table_lookup( share->node2hash, hn )) ) return( g_hash_table_lookup( share->hash2nodel, (gpointer) hash ) ); return( NULL ); } static CompileHash compile_share_scan_node( CompileShare *share, HeapNode *hn ); static CompileHash compile_share_scan_element( CompileShare *share, PElement *e ) { CompileHash hash; switch( PEGETTYPE( e ) ) { case ELEMENT_NODE: hash = compile_share_scan_node( share, PEGETVAL( e ) ); break; case ELEMENT_SYMBOL: case ELEMENT_SYMREF: case ELEMENT_COMPILEREF: case ELEMENT_CHAR: case ELEMENT_BOOL: case ELEMENT_BINOP: case ELEMENT_UNOP: case ELEMENT_COMB: case ELEMENT_CONSTRUCTOR: hash = INT_TO_HASH( PEGETTYPE( e ) + PEGETVAL( e ) ); break; case ELEMENT_ELIST: hash = INT_TO_HASH( ELEMENT_ELIST ); break; case ELEMENT_TAG: hash = INT_TO_HASH( g_str_hash( PEGETTAG( e ) ) ); break; case ELEMENT_MANAGED: hash = INT_TO_HASH( PEGETMANAGED( e )->hash ); break; case ELEMENT_NOVAL: default: hash = 0; g_assert( 0 ); } return( hash ); } /* Calculate a hash for every node in a tree. We can just recurse and * calculate bottom-up, since we'll never get very deep. If we were scanning * run-time code, we'd need a better scheme. */ static CompileHash compile_share_scan_node( CompileShare *share, HeapNode *hn ) { CompileHash hash; PElement a; hash = INT_TO_HASH( 0 ); switch( hn->type ) { case TAG_CONS: case TAG_GEN: case TAG_CLASS: case TAG_COMPLEX: case TAG_APPL: PEPOINTLEFT( hn, &a ); hash = COMPILEHASH_ADD( hash, compile_share_scan_element( share, &a ) ); PEPOINTRIGHT( hn, &a ); hash = COMPILEHASH_ADD( hash, compile_share_scan_element( share, &a ) ); hash = COMPILEHASH_ADD( hash, INT_TO_HASH( (int) hn->type ) ); break; case TAG_DOUBLE: hash = COMPILEHASH_ADD( hash, INT_TO_HASH( (int) hn->body.num ) ); hash = COMPILEHASH_ADD( hash, INT_TO_HASH( (int) hn->type ) ); break; case TAG_FILE: case TAG_REFERENCE: case TAG_SHARED: case TAG_FREE: default: g_assert( FALSE ); } /* Add to accumulated table. */ compile_share_add( share, hn, hash ); return( hash ); } /* Test two sub-trees for equality. */ static gboolean compile_equal_node( HeapNode *hn1, HeapNode *hn2 ) { /* Test for pointer equality. */ if( hn1 == hn2 ) return( TRUE ); /* Test type tags for equality. */ if( hn1->type != hn2->type ) return( FALSE ); /* If double, test immediately. */ if( hn1->type == TAG_DOUBLE ) { if( hn1->body.num == hn2->body.num ) return( TRUE ); else return( FALSE ); } /* If complex, test immediately. */ if( hn1->type == TAG_COMPLEX ) { if( GETLEFT( hn1 )->body.num == GETLEFT( hn2 )->body.num && GETRIGHT( hn1 )->body.num == GETRIGHT( hn2 )->body.num ) return( TRUE ); else return( FALSE ); } /* If compound type, something is wrong! Only built by reduce. */ g_assert( hn1->type != TAG_CLASS ); /* In two parts, test tags. */ if( GETLT( hn1 ) != GETLT( hn2 ) ) return( FALSE ); if( GETRT( hn1 ) != GETRT( hn2 ) ) return( FALSE ); /* Test non-subtree parts. */ if( GETLT( hn1 ) != ELEMENT_NODE ) if( GETLEFT( hn1 ) != GETLEFT( hn2 ) ) return( FALSE ); if( GETRT( hn1 ) != ELEMENT_NODE ) if( GETRIGHT( hn1 ) != GETRIGHT( hn2 ) ) return( FALSE ); /* If sub-trees, test them. */ if( GETLT( hn1 ) == ELEMENT_NODE ) if( !compile_equal_node( GETLEFT( hn1 ), GETLEFT( hn2 ) ) ) return( FALSE ); if( GETRT( hn1 ) == ELEMENT_NODE ) if( !compile_equal_node( GETRIGHT( hn1 ), GETRIGHT( hn2 ) ) ) return( FALSE ); return( TRUE ); } /* Found two equal sub-expressions. We can change hn1 to just be a reference * to hn2. */ static int compile_transform_reference( Compile *compile, HeapNode *hn1, HeapNode *hn2 ) { #ifdef DEBUG { Heap *heap = compile->heap; char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_node( heap, &buf, hn1, TRUE ); printf( "Found common subexpression: %s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG*/ #ifdef DEBUG_COMMON compile_node_sum += compile_node_count( hn1 ); #endif /*DEBUG_COMMON*/ /* Zap nodes to indicate sharing. */ hn1->type = TAG_REFERENCE; PPUTLEFT( hn1, ELEMENT_NODE, hn2 ); PPUTRIGHT( hn1, ELEMENT_NODE, NULL ); return( 0 ); } /* Node other hashes to the same value as our node. Test for equality, and if * they match, turn us into a share point and turn the other node into a ref. */ static void * compile_share_test( HeapNode *other, CompileShare *share, HeapNode *hn ) { if( hn != other && compile_equal_node( hn, other ) ) { heap_map( other, (heap_map_fn) compile_share_remove, share, NULL ); compile_transform_reference( share->compile, other, hn ); } return( NULL ); } /* Scan a chunk of tree top-down, looking for and eliminating common nodes. */ static void compile_share_trim( CompileShare *share, HeapNode *hn ) { PElement a; GSList *nodel; if( (nodel = compile_share_lookup( share, hn )) ) slist_map2( nodel, (SListMap2Fn) compile_share_test, share, hn ); switch( hn->type ) { case TAG_CONS: case TAG_GEN: case TAG_CLASS: case TAG_COMPLEX: case TAG_APPL: PEPOINTLEFT( hn, &a ); if( PEISNODE( &a ) ) compile_share_trim( share, PEGETVAL( &a ) ); PEPOINTRIGHT( hn, &a ); if( PEISNODE( &a ) ) compile_share_trim( share, PEGETVAL( &a ) ); break; case TAG_DOUBLE: case TAG_REFERENCE: break; case TAG_SHARED: case TAG_FREE: case TAG_FILE: default: g_assert( FALSE ); } } static void compile_share_scan( Compile *compile, PElement *a ) { if( PEISNODE( a ) ) { HeapNode *hn = PEGETVAL( a ); CompileShare share; compile_share_init( &share, compile ); compile_share_scan_node( &share, hn ); compile_share_trim( &share, hn ); compile_share_destroy( &share ); } } /* Use this to generate an id for each SHARE node. */ static int compile_share_number = 0; /* If this is a REF node, make sure dest is a SHARE node. */ static void * compile_transform_share( HeapNode *hn, Compile *compile ) { Heap *heap = compile->heap; if( hn->type == TAG_REFERENCE ) { HeapNode *hn1 = GETLEFT( hn ); if( hn1->type != TAG_SHARED ) { HeapNode *hn2; #ifdef DEBUG { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_node( heap, &buf, hn1, TRUE ); printf( "Found shared code: %s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG*/ if( NEWNODE( heap, hn2 ) ) return( hn ); *hn2 = *hn1; hn1->type = TAG_SHARED; PPUT( hn1, ELEMENT_NODE, hn2, ELEMENT_CHAR, GUINT_TO_POINTER( compile_share_number ) ); compile_share_number++; if( compile_share_number == MAX_RELOC ) { error_top( _( "Too many shared nodes in " "graph." ) ); error_sub( _( "Raise MAX_RELOC" ) ); return( hn ); } } } return( NULL ); } /* Do common-subexpression elimination. */ static gboolean compile_remove_subexpr( Compile *compile, PElement *root ) { HeapNode *rootn = PEGETVAL( root ); #ifdef DEBUG_COMMON static int compile_node_total = 0; #endif /*DEBUG_COMMON*/ if( PEGETTYPE( root ) != ELEMENT_NODE ) /* Nowt to do. */ return( TRUE ); #ifdef DEBUG_COMMON compile_node_sum = 0; #endif /*DEBUG_COMMON*/ /* Scan for common nodes, replace stuff we remove with REFERENCE * nodes. */ compile_share_scan( compile, root ); /* Now search for destinations of reference nodes and mark all shared * sections. Each shared section is given a number ... saves a lookup * during copy. */ compile_share_number = 0; if( heap_map( rootn, (heap_map_fn) compile_transform_share, compile, NULL ) ) { /* We can't leave the graph half-done, it'll confuse the copier * later. Zap the graph. */ PEPUTP( root, ELEMENT_NOVAL, NULL ); return( FALSE ); } #ifdef DEBUG_COMMON if( compile_node_sum ) { compile_node_total += compile_node_sum; printf( "compile_remove_subexpr: " ); symbol_name_print( compile->sym ); printf( "saved %d nodes (total %d)\n", compile_node_sum, compile_node_total ); } #endif /*DEBUG_COMMON*/ return( TRUE ); } /* Top-level compiler driver. */ /* Compile a symbol into a heap. */ static void * compile_heap( Compile *compile ) { PElement base; /* Don't generate code for parser temps. */ if( compile->sym->placeholder ) return( NULL ); PEPOINTE( &base, &compile->base ); /* Is there an existing function base? GC it away. */ if( PEGETTYPE( &base ) != ELEMENT_NOVAL ) { PEPUTP( &base, ELEMENT_NOVAL, (void *) 2 ); if( !heap_gc( compile->heap ) ) return( compile->sym ); return( NULL ); } #ifdef DEBUG printf( "*** compile_expr: about to compile " ); symbol_name_print( compile->sym ); printf( "\n" ); if( compile->tree ) dump_tree( compile->tree ); #endif /*DEBUG*/ /* Compile function body. Tree can be NULL for classes. */ if( compile->tree ) { if( !compile_graph( compile, compile->tree, &base ) ) return( compile->sym ); } else { PEPUTP( &base, ELEMENT_NOVAL, (void *) 3 ); } #ifdef DEBUG { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( compile->heap, &buf, &base, TRUE ); printf( "before var abstraction, compiled \"%s\" to: %s\n", IOBJECT( compile->sym )->name, vips_buf_all( &buf ) ); } #endif /*DEBUG*/ /* Abstract real parameters. */ #ifdef DEBUG printf( "abstracting real params ...\n" ); #endif /*DEBUG*/ if( slist_map2_rev( compile->param, (SListMap2Fn) compile_abstract_symbol, compile, &base ) ) return( compile->sym ); /* Abstract secret parameters. */ #ifdef DEBUG printf( "abstracting secret params ...\n" ); #endif /*DEBUG*/ if( slist_map2_rev( compile->secret, (SListMap2Fn) compile_abstract_symbol, compile, &base ) ) return( compile->sym ); /* Remove common sub-expressions. */ if( !compile_remove_subexpr( compile, &base ) ) return( compile->sym ); #ifdef DEBUG_RESULT { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); printf( "compiled " ); symbol_name_print( compile->sym ); printf( "to: " ); graph_pelement( compile->heap, &buf, &base, TRUE ); printf( "%s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_RESULT*/ return( NULL ); } static void *compile_object_sub( Compile *compile ); static void * compile_symbol_sub( Symbol *sym ) { Compile *compile; if( sym->expr && (compile = sym->expr->compile) ) if( compile_object_sub( compile ) ) return( sym ); return( NULL ); } static void * compile_object_sub( Compile *compile ) { if( icontainer_map( ICONTAINER( compile ), (icontainer_map_fn) compile_symbol_sub, NULL, NULL ) ) return( compile ); if( compile_heap( compile ) ) return( compile ); return( NULL ); } /* Top-level compile a thing entry point. */ void * compile_object( Compile *compile ) { /* Walk this tree of symbols computing the secret lists. */ secret_build( compile ); /* Compile all definitions from the inside out. */ if( compile_object_sub( compile ) ) return( compile ); return( NULL ); } static void * compile_toolkit_sub( Tool *tool ) { Compile *compile; if( tool->sym && tool->sym->expr && (compile = tool->sym->expr->compile )) /* Only if we have no code. */ if( compile->base.type == ELEMENT_NOVAL ) if( compile_object( compile ) ) return( tool ); return( NULL ); } /* Scan a toolkit and make sure all the symbols have been compiled. */ void * compile_toolkit( Toolkit *kit ) { return( toolkit_map( kit, (tool_map_fn) compile_toolkit_sub, NULL, NULL ) ); } /* Parse support. */ static ParseNode * compile_check_i18n( Compile *compile, ParseNode *pn ) { switch( pn->type ) { case NODE_APPLY: if( pn->arg1->type == NODE_LEAF && strcmp( IOBJECT( pn->arg1->leaf )->name, "_" ) == 0 && pn->arg2->type == NODE_CONST && pn->arg2->con.type == PARSE_CONST_STR ) { const char *text = pn->arg2->con.val.str; if( main_option_i18n ) { /* Remove msgid duplicates with this. */ static GHashTable *msgid = NULL; if( !msgid ) msgid = g_hash_table_new( g_str_hash, g_str_equal ); if( !g_hash_table_lookup( msgid, text ) ) { char buf[MAX_STRSIZE]; g_hash_table_insert( msgid, (void *) text, NULL ); my_strecpy( buf, text, TRUE ); printf( "msgid \"%s\"\n", buf ); printf( "msgstr \"\"\n\n" ); } } /* We can gettext these at compile time. Replace the * APPLY node with a fixed-up text string. */ pn->type = NODE_CONST; pn->con.type = PARSE_CONST_STR; pn->con.val.str = im_strdupn( _( text ) ); } break; default: break; } return( NULL ); } static ParseNode * compile_check_more( Compile *compile, ParseNode *pn ) { switch( pn->type ) { case NODE_BINOP: switch( pn->biop ) { case BI_MORE: pn->biop = BI_LESS; SWAPP( pn->arg1, pn->arg2 ); break; case BI_MOREEQ: pn->biop = BI_LESSEQ; SWAPP( pn->arg1, pn->arg2 ); break; default: break; } break; default: break; } return( NULL ); } /* Do end-of-parse checks. Called after every 'A = ...' style definition (not * just top-level syms). Used to do lots of checks, not much left now. */ gboolean compile_check( Compile *compile ) { Symbol *sym = compile->sym; Symbol *parent = symbol_get_parent( sym ); /* Check "check" member. */ if( is_member( sym ) && strcmp( IOBJECT( sym )->name, MEMBER_CHECK ) == 0 ) { if( compile->nparam != 0 ) { error_top( _( "Too many arguments." ) ); error_sub( _( "Member \"%s\" of class " "\"%s\" should have no arguments." ), MEMBER_CHECK, symbol_name( parent ) ); return( FALSE ); } } /* Look for (_ "string constant") and pump it through gettext. We can * do a lot of i18n at compile-time. */ #ifdef DEBUG printf( "compile_check_i18n: " ); compile_name_print( compile ); printf( "\n" ); #endif /*DEBUG*/ (void) tree_map( compile, (tree_map_fn) compile_check_i18n, compile->tree, NULL, NULL ); /* Swap MORE and MOREEQ for LESS and LESSEQ. Reduces the number of * cases for the compiler. */ (void) tree_map( compile, (tree_map_fn) compile_check_more, compile->tree, NULL, NULL ); return( TRUE ); } /* Mark error on all exprs using this compile. */ void compile_error_set( Compile *compile ) { (void) slist_map( compile->exprs, (SListMapFn) expr_error_set, NULL ); } /* Patch a pointer on a patch list. */ static void * compile_patch_pointers_sub( void **pnt, void *nsym, void *osym ) { g_assert( *pnt == osym ); *pnt = nsym; return( NULL ); } /* Patch pointers to old to point to new instead. */ static void compile_patch_pointers( Symbol *nsym, Symbol *osym ) { (void) slist_map2( osym->patch, (SListMap2Fn) compile_patch_pointers_sub, nsym, osym ); } /* Sub fn of below. */ static void * compile_resolve_sub( Compile *pnt, Symbol *sym ) { if( !g_slist_find( sym->parents, pnt ) ) sym->parents = g_slist_prepend( sym->parents, pnt ); return( NULL ); } /* Sub fn 2 of below. */ static void * compile_resolve_sub1( Compile *compile ) { return( symbol_fix_counts( compile->sym ) ); } /* We've found a symbol which is the true definition of an unresolved symbol. * We fiddle references to zombie to refer to sym instead. */ static void compile_resolve( Symbol *sym, Symbol *zombie ) { #ifdef DEBUG_RESOLVE printf( "compile_resolve: resolving zombie " ); symbol_name_print( zombie ); printf( "to symbol " ); symbol_name_print( sym ); printf( "\n" ); #endif /*DEBUG_RESOLVE*/ /* Symbol on outer table. Patch pointers to zombie to point to * sym instead. */ compile_patch_pointers( sym, zombie ); /* Also unresolved in outer scope? */ if( sym->type == SYM_ZOMBIE ) /* We may need to move it again - so add the patch * pointers we have just used to the patch list on * sym. */ (void) slist_map( zombie->patch, (SListMapFn) symbol_patch_add, sym ); /* Add other information the ZOMBIE has picked up. We only * need to make the link one way: the patching will make the * other half for us. */ (void) slist_map( zombie->parents, (SListMapFn) compile_resolve_sub, sym ); /* Make sure the dirty counts are set correctly. We have * changed dep (maybe), so need a fiddle. */ (void) slist_map( zombie->parents, (SListMapFn) compile_resolve_sub1, NULL ); /* No one refers to the zombie now. */ IM_FREEF( g_slist_free, zombie->parents ); IDESTROY( zombie ); } /* Sub-function of below. */ static void * compile_resolve_names_sub( Symbol *sym, Compile *outer ) { const char *name = IOBJECT( sym )->name; Symbol *old; /* Is it the sort of thing we are looking for? ZOMBIEs only, please. */ if( sym->type != SYM_ZOMBIE ) return( NULL ); if( (old = compile_lookup( outer, name )) ) compile_resolve( old, sym ); else { /* Nothing on the outer table of that name. Can just move the * symbol across. */ g_object_ref( G_OBJECT( sym ) ); icontainer_child_remove( ICONTAINER( sym ) ); icontainer_child_add( ICONTAINER( outer ), ICONTAINER( sym ), -1 ); g_object_unref( G_OBJECT( sym ) ); } return( NULL ); } /* End of definition parse: we search the symbol table we have built for this * definition, looking for unresolved names (ZOMBIEs). If we find any, we move * the zombie to the enclosing symbol table, since the name may be * resolved one level up. If we find a symbol on the enclosing table of the * same name, we have to patch pointers to our inner ZOMBIE to point to this * new symbol. Nasty! */ void compile_resolve_names( Compile *inner, Compile *outer ) { (void) icontainer_map( ICONTAINER( inner ), (icontainer_map_fn) compile_resolve_names_sub, outer, NULL ); } /* Hit a top-level zombie during reduction. Search outwards to root looking on * enclosing tables for a match. */ Symbol * compile_resolve_top( Symbol *sym ) { Compile *enclosing; for( enclosing = COMPILE( ICONTAINER( sym )->parent ); enclosing; enclosing = compile_get_parent( enclosing ) ) { Symbol *outer_sym; if( (outer_sym = compile_lookup( enclosing, IOBJECT( sym )->name )) && outer_sym->type != SYM_ZOMBIE ) return( outer_sym ); } return( NULL ); } /* Search outwards for this sym. */ static void * compile_resolve_dynamic_sub( Symbol *sym, Compile *context ) { Compile *tab; if( sym->type != SYM_ZOMBIE ) return( NULL ); for( tab = context; tab; tab = compile_get_parent( tab ) ) { Symbol *def = compile_lookup( tab, IOBJECT( sym )->name ); if( def && def->type != SYM_ZOMBIE ) { /* We've found a non-zombie! Bind and we're done. */ compile_resolve( def, sym ); break; } } return( NULL ); } /* Resolve ZOMBIEs in tab by searching outwards from context. We only move * and patch if we find a match ... otherwise we leave the zombie where is is. * * This is used for dynamic exprs in the tally display: we don't care about * fwd refs, but we want to be able to handle multiple scope contexts. */ void compile_resolve_dynamic( Compile *tab, Compile *context ) { (void) icontainer_map( ICONTAINER( tab ), (icontainer_map_fn) compile_resolve_dynamic_sub, context, NULL ); } Symbol * compile_get_member( Compile *compile, const char *name ) { iContainer *child; if( is_class( compile ) && (child = icontainer_child_lookup( ICONTAINER( compile ), name )) ) return( SYMBOL( child ) ); return( NULL ); } const char * compile_get_member_string( Compile *compile, const char *name ) { Symbol *member; Compile *member_compile; if( (member = compile_get_member( compile, name )) && is_value( member ) && (member_compile = member->expr->compile) && member_compile->tree && member_compile->tree->type == NODE_CONST && member_compile->tree->con.type == PARSE_CONST_STR ) return( member_compile->tree->con.val.str ); return( NULL ); } static void * compile_find_generated_node( Compile *compile, ParseNode *node, GSList **list ) { Symbol *sym = node->leaf; if( node->type == NODE_LEAF && sym->generated && symbol_get_parent( sym ) && symbol_get_parent( sym )->expr->compile == compile ) *list = g_slist_prepend( *list, sym ); return( NULL ); } /* Search a scrap of tree and build a list of all the lambdas/lcomps/etc. it * generated. */ static GSList * compile_find_generated( Compile *compile, ParseNode *tree ) { GSList *list; list = NULL; tree_map( compile, (tree_map_fn) compile_find_generated_node, tree, &list, NULL ); return( list ); } /* Make a copy of sym (and all it's children and trees) in the destination * scope. This only works for stuff from the parse stage. Symbols which have * values and stuff attached are too complicated to copy easily. */ static void * compile_copy_sym( Symbol *sym, Compile *dest ) { const char *name = IOBJECT( sym )->name; Symbol *copy_sym; #ifdef DEBUG printf( "compile_copy_sym: copying " ); symbol_name_print( sym ); printf( "to scope of " ); compile_name_print( dest ); printf( "\n" ); #endif /*DEBUG*/ /* Must be a different place. */ g_assert( symbol_get_parent( sym )->expr->compile != dest ); /* Must not be an existing sym of that name. Or if there is, it has to * be a zombie. */ g_assert( !compile_lookup( dest, name ) || compile_lookup( dest, name )->type == SYM_ZOMBIE ); switch( sym->type ) { case SYM_VALUE: copy_sym = symbol_new_defining( dest, name ); copy_sym->generated = sym->generated; (void) symbol_user_init( copy_sym ); (void) compile_new_local( copy_sym->expr ); /* Copy any locals over. We have to do this before we copy the * tree so that the new tree links to the new syms. */ icontainer_map( ICONTAINER( sym->expr->compile ), (icontainer_map_fn) compile_copy_sym, copy_sym->expr->compile, NULL ); copy_sym->expr->compile->tree = tree_copy( copy_sym->expr->compile, sym->expr->compile->tree ); /* Copying the tree may have made some zombies. Resolve * outwards. */ compile_resolve_names( copy_sym->expr->compile, dest ); break; case SYM_PARAM: copy_sym = symbol_new_defining( dest, name ); copy_sym->generated = sym->generated; symbol_parameter_init( copy_sym ); break; case SYM_ZOMBIE: break; case SYM_WORKSPACE: case SYM_WORKSPACEROOT: case SYM_ROOT: case SYM_EXTERNAL: case SYM_BUILTIN: default: g_assert( 0 ); } return( NULL ); } /* tree is a scrap of graph in fromscope's context. It may have caused the * generation of a number of lambdas, lcomps etc. in fromscope. Make a copy * of the tree in toscope and copy over any generated syms too. fromscope and * toscope can be the same, in which case we can just copy the tree. */ ParseNode * compile_copy_tree( Compile *fromscope, ParseNode *tree, Compile *toscope ) { ParseNode *copy_tree; #ifdef DEBUG printf( "compile_copy_tree: copying tree from " ); compile_name_print( fromscope ); printf( " to " ); compile_name_print( toscope ); printf( "\n" ); #endif /*DEBUG*/ /* A new context? Copy generated syms over. */ if( fromscope != toscope ) { GSList *generated; generated = compile_find_generated( fromscope, tree ); #ifdef DEBUG printf( "with generated children: " ); (void) slist_map( generated, (SListMapFn) dump_tiny, NULL ); printf( "\n" ); #endif /*DEBUG*/ slist_map( generated, (SListMapFn) compile_copy_sym, toscope ); g_slist_free( generated ); } copy_tree = tree_copy( toscope, tree ); /* Copying the tree may have made some zombies. Resolve * outwards. */ compile_resolve_names( toscope, compile_get_parent( toscope ) ); return( copy_tree ); } /* Generate the parse tree for this list comprehension. Example: after parse we have: [(x, y) :: x <- [1..3]; y <- [x..3]; x + y > 3]; ... $$lcomp1 ... { $$lcomp1 = NULL { $$result = (x, y); // elements in left-to-right order // in compile->children x = [1..3] y = [x..3] $$filter1 = x + y > 3 } } and we generate this code: z = $$lcomp1 { $$lcomp1 = foldr $f1 [] [1..3] { $f1 x $sofar = foldr $f2 $sofar [x..3] { $f2 y $sofar = if x + y > 3 then $f3 else $sofar { $f3 = (x, y) : $sofar; } } } } */ /* Find the placeholders generated by the parser. Filters, generators, * patterns and $$result. */ static void * compile_lcomp_find( Symbol *sym, GSList **children ) { if( sym->placeholder ) *children = g_slist_append( *children, sym ); return( NULL ); } static Symbol * compile_lcomp_find_pattern( GSList *children, const char *generator ) { int n; char pattern[256]; GSList *p; if( sscanf( generator, "$$generator%d", &n ) != 1 ) return( NULL ); im_snprintf( pattern, 256, "$$pattern%d", n ); for( p = children; p; p = p->next ) { Symbol *sym = (Symbol *) p->data; if( strcmp( IOBJECT( sym )->name, pattern ) == 0 ) return( sym ); } return( NULL ); } void compile_lcomp( Compile *compile ) { /* Number nested locals with this. Keep numbering global so debugging * nested lcomps is easier. */ static int count = 1; GSList *children; gboolean sofar; Compile *scope; Symbol *result; GSList *p; Symbol *child; char name[256]; ParseNode *n1, *n2, *n3; #ifdef DEBUG_LCOMP printf( "before compile_lcomp:\n" ); dump_compile( compile ); #endif /*DEBUG_LCOMP*/ /* Find all the elements of the lcomp: generators, filters, patterns * and $$result. */ children = NULL; (void) icontainer_map( ICONTAINER( compile ), (icontainer_map_fn) compile_lcomp_find, &children, NULL ); #ifdef DEBUG_LCOMP printf( "list comp " ); compile_name_print( compile ); printf( " has children: " ); (void) slist_map( children, (SListMapFn) dump_tiny, NULL ); printf( "\n" ); #endif /*DEBUG_LCOMP*/ /* As yet no list to build on. */ sofar = FALSE; /* Start by building a tree in this scope. */ scope = compile; /* Not seen the result element yet, but we should. */ result = NULL; /* Now generate code for each element, either a filter or a generator. * If we do a generator, we need to search for the associated pattern * and expand it. */ for( p = children; p; p = p->next ) { Symbol *element = (Symbol *) p->data; /* Just note the result element ... we use it right at the end. */ if( strcmp( "$$result", IOBJECT( element )->name ) == 0 ) { result = element; continue; } /* And only process filter/gen. */ if( !is_prefix( "$$filter", IOBJECT( element )->name ) && !is_prefix( "$$gen", IOBJECT( element )->name ) ) continue; /* Start the next nest in. child is the local we will make for * this scope. */ im_snprintf( name, 256, "$$fn%d", count++ ); child = symbol_new_defining( scope, name ); child->generated = TRUE; (void) symbol_user_init( child ); (void) compile_new_local( child->expr ); if( is_prefix( "$$filter", IOBJECT( element )->name ) ) { /* A filter. */ n1 = compile_copy_tree( compile, element->expr->compile->tree, scope ); n2 = tree_leafsym_new( scope, child ); n3 = tree_leaf_new( scope, "$$sofar" ); n1 = tree_ifelse_new( scope, n1, n2, n3 ); scope->tree = n1; } else if( is_prefix( "$$gen", IOBJECT( element )->name ) ) { Symbol *param1; Symbol *param2; Symbol *pattern; GSList *built_syms; /* A generator. */ param1 = symbol_new_defining( child->expr->compile, IOBJECT( element )->name ); param1->generated = TRUE; symbol_parameter_init( param1 ); param2 = symbol_new_defining( child->expr->compile, "$$sofar" ); param2->generated = TRUE; symbol_parameter_init( param2 ); /* Now expand the pattern: it will access parts of the * $$generator argument. */ pattern = compile_lcomp_find_pattern( children, IOBJECT( element )->name ); g_assert( pattern ); built_syms = compile_pattern_lhs( child->expr->compile, param1, pattern->expr->compile->tree ); g_slist_free( built_syms ); /* Make the "foldr $$fn $sofar expr" tree. */ n1 = tree_leaf_new( scope, "foldr" ); n2 = tree_leafsym_new( scope, child ); n3 = tree_appl_new( scope, n1, n2 ); if( sofar ) n2 = tree_leaf_new( scope, "$$sofar" ); else { ParseConst con; con.type = PARSE_CONST_ELIST; n2 = tree_const_new( scope, con ); } n3 = tree_appl_new( scope, n3, n2 ); n2 = compile_copy_tree( compile, element->expr->compile->tree, scope ); n3 = tree_appl_new( scope, n3, n2 ); scope->tree = n3; /* There's now an enclosing sofar we can use. */ sofar = TRUE; } /* Nest in again. */ scope = child->expr->compile; } /* Copy the code for the final result. */ g_assert( result ); n1 = compile_copy_tree( result->expr->compile, result->expr->compile->tree, scope ); n2 = tree_leaf_new( scope, "$$sofar" ); n3 = tree_binop_new( compile, BI_CONS, n1, n2 ); scope->tree = n3; /* Loop outwards again, closing the scopes we made. */ while( scope != compile ) { /* We know check can't fail on generated code. FIXME ... yuk, maybe compile_lcomp should be failable too */ (void) compile_check( scope ); compile_resolve_names( scope, compile_get_parent( scope ) ); scope = compile_get_parent( scope ); } #ifdef DEBUG_LCOMP printf( "after compile_lcomp:\n" ); dump_compile( compile ); #endif /*DEBUG_LCOMP*/ g_slist_free( children ); } /* Compile a pattern LHS. Generate a sym for each pattern variable, each of * which checks and accesses sym. For example: * * [a] = x; * * compiles to: * * sym = x; * a = if is_list sym && len sym == 1 then sym?0 else error ".."; */ /* Generate code to access element n of a pattern trail. Eg, pattern is * [[[a]]] * the trail will be * 0) LISTCONST 1) LISTCONST 2) LISTCONST 3) LEAF * then access(0) will be * leaf * and access(1) will be * leaf?0 * and access(3) (to get the value for a) will be * leaf?0?0?0 */ static ParseNode * compile_pattern_access( Compile *compile, Symbol *leaf, ParseNode **trail, int n ) { ParseNode *node; ParseNode *left; ParseNode *right; ParseConst c; int i; /* The initial leaf ref we access from. */ node = tree_leafsym_new( compile, leaf ); for( i = 0; i < n; i++ ) switch( trail[i]->type ) { case NODE_CONST: case NODE_PATTERN_CLASS: case NODE_LEAF: break; case NODE_BINOP: switch( trail[i]->biop ) { case BI_COMMA: /* Generate re or im? */ if( trail[i]->arg1 == trail[i + 1] ) left = tree_leaf_new( compile, "re" ); else left = tree_leaf_new( compile, "im" ); node = tree_appl_new( compile, left, node ); break; case BI_CONS: /* Generate hd or tl? */ if( trail[i]->arg1 == trail[i + 1] ) left = tree_leaf_new( compile, "hd" ); else left = tree_leaf_new( compile, "tl" ); node = tree_appl_new( compile, left, node ); break; default: g_assert( 0 ); } break; case NODE_LISTCONST: /* Which list element do we need? Look for the next * item in the trail in the list of elements. */ c.type = PARSE_CONST_NUM; c.val.num = g_slist_index( trail[i]->elist, trail[i + 1] ); right = tree_const_new( compile, c ); node = tree_binop_new( compile, BI_SELECT, node, right ); break; default: g_assert( 0 ); } return( node ); } /* Generate a parsetree for the condition test. The array of nodes represents * the set of conditions we have to test, left to right. */ static ParseNode * compile_pattern_condition( Compile *compile, Symbol *leaf, ParseNode **trail, int depth ) { ParseConst n; ParseNode *node; ParseNode *node2; ParseNode *left; ParseNode *right; int i; n.type = PARSE_CONST_BOOL; n.val.bool = TRUE; node = tree_const_new( compile, n ); for( i = depth - 1; i >= 0; i-- ) { switch( trail[i]->type ) { case NODE_LEAF: break; case NODE_BINOP: switch( trail[i]->biop ) { case BI_COMMA: /* Generate is_complex x. */ left = tree_leaf_new( compile, "is_complex" ); right = compile_pattern_access( compile, leaf, trail, i ); node2 = tree_appl_new( compile, left, right ); node = tree_binop_new( compile, BI_LAND, node2, node ); break; case BI_CONS: /* Generate is_list x && x != []. */ left = tree_leaf_new( compile, "is_list" ); right = compile_pattern_access( compile, leaf, trail, i ); node2 = tree_appl_new( compile, left, right ); node = tree_binop_new( compile, BI_LAND, node2, node ); left = compile_pattern_access( compile, leaf, trail, i ); n.type = PARSE_CONST_ELIST; right = tree_const_new( compile, n ); node2 = tree_binop_new( compile, BI_NOTEQ, left, right ); node = tree_binop_new( compile, BI_LAND, node, node2 ); break; default: g_assert( 0 ); } break; case NODE_LISTCONST: /* Generate is_list x && is_list_len n x. */ left = tree_leaf_new( compile, "is_list" ); right = compile_pattern_access( compile, leaf, trail, i ); node2 = tree_appl_new( compile, left, right ); node = tree_binop_new( compile, BI_LAND, node2, node ); left = tree_leaf_new( compile, "is_list_len" ); n.type = PARSE_CONST_NUM; n.val.num = g_slist_length( trail[i]->elist ); right = tree_const_new( compile, n ); left = tree_appl_new( compile, left, right ); right = compile_pattern_access( compile, leaf, trail, i ); node2 = tree_appl_new( compile, left, right ); node = tree_binop_new( compile, BI_LAND, node, node2 ); break; case NODE_CONST: /* Generate x == n. */ left = compile_pattern_access( compile, leaf, trail, i ); right = tree_const_new( compile, trail[i]->con ); node2 = tree_binop_new( compile, BI_EQ, left, right ); node = tree_binop_new( compile, BI_LAND, node2, node ); break; case NODE_PATTERN_CLASS: /* Generate is_instanceof "class-name" x. */ left = tree_leaf_new( compile, "is_instanceof" ); n.type = PARSE_CONST_STR; n.val.str = im_strdupn( trail[i]->tag ); right = tree_const_new( compile, n ); node2 = tree_appl_new( compile, left, right ); right = compile_pattern_access( compile, leaf, trail, i ); node2 = tree_appl_new( compile, node2, right ); node = tree_binop_new( compile, BI_LAND, node2, node ); break; default: g_assert( 0 ); } } return( node ); } /* Generate a parsetree for a "pattern match failed" error. */ static ParseNode * compile_pattern_error( Compile *compile, Symbol *leaf ) { ParseNode *left; ParseConst n; ParseNode *right; ParseNode *node; left = tree_leaf_new( compile, "error" ); n.type = PARSE_CONST_STR; n.val.str = im_strdupn( _( "pattern match failed" ) ); right = tree_const_new( compile, n ); node = tree_appl_new( compile, left, right ); return( node ); } /* Depth of trail we keep as we walk the pattern. */ #define MAX_TRAIL (10) typedef struct _PatternLhs { Compile *compile; /* Scope in which we generate new symbols */ Symbol *sym; /* Thing we access */ /* The trail of nodes representing this slice of the pattern. */ ParseNode *trail[MAX_TRAIL]; int depth; GSList *built_syms; } PatternLhs; /* Generate one reference. leaf is the new sym we generate. */ static void compile_pattern_lhs_leaf( PatternLhs *lhs, Symbol *leaf ) { Symbol *sym; Compile *compile; sym = symbol_new_defining( lhs->compile, IOBJECT( leaf )->name ); sym->generated = TRUE; (void) symbol_user_init( sym ); (void) compile_new_local( sym->expr ); lhs->built_syms = g_slist_prepend( lhs->built_syms, sym ); compile = sym->expr->compile; compile->tree = tree_ifelse_new( compile, compile_pattern_condition( compile, lhs->sym, lhs->trail, lhs->depth ), compile_pattern_access( compile, lhs->sym, lhs->trail, lhs->depth ), compile_pattern_error( compile, leaf ) ); #ifdef DEBUG_PATTERN printf( "compile_pattern_lhs_leaf: generated\n" ); dump_compile( compile ); #endif /*DEBUG_PATTERN*/ } /* Recurse over the pattern generating references. */ static void * compile_pattern_lhs_sub( ParseNode *node, PatternLhs *lhs ) { lhs->trail[lhs->depth++] = node; switch( node->type ) { case NODE_LEAF: compile_pattern_lhs_leaf( lhs, node->leaf ); break; case NODE_PATTERN_CLASS: compile_pattern_lhs_sub( node->arg1, lhs ); break; case NODE_BINOP: compile_pattern_lhs_sub( node->arg1, lhs ); compile_pattern_lhs_sub( node->arg2, lhs ); break; case NODE_LISTCONST: slist_map( node->elist, (SListMapFn) compile_pattern_lhs_sub, lhs ); break; case NODE_CONST: break; default: g_assert( 0 ); } lhs->depth--; return( NULL ); } /* Something like "[a] = [1];". sym is the $$pattern we are generating access * syms for, node is the pattern tree, compile is the scope in which we * generate the new defining symbols. Return a list of the syms we built: they * will need any final finishing up and then having symbol_made() called on * them. You need to free the list, too. */ GSList * compile_pattern_lhs( Compile *compile, Symbol *sym, ParseNode *node ) { PatternLhs lhs; #ifdef DEBUG_PATTERN printf( "compile_pattern_lhs: building access fns for %s\n", symbol_name( sym ) ); #endif /*DEBUG_PATTERN*/ lhs.compile = compile; lhs.sym = sym; lhs.depth = 0; lhs.built_syms = NULL; compile_pattern_lhs_sub( node, &lhs ); g_assert( lhs.depth == 0 ); return( lhs.built_syms ); } static ParseNode * compile_pattern_has_leaf_sub( Compile *compile, ParseNode *node, void *a, void *b ) { if( node->type == NODE_LEAF ) return( node ); return( NULL ); } /* Does a pattern contain a leaf? We don't allow const-only patterns in * definitions. */ gboolean compile_pattern_has_leaf( ParseNode *node ) { return( tree_map( NULL, (tree_map_fn) compile_pattern_has_leaf_sub, node, NULL, NULL ) != NULL ); } nip2-8.7.1/src/editview.h0000644000175000017500000000331313351443023012076 00000000000000/* abstract base class for text editable view widgets */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_EDITVIEW (editview_get_type()) #define EDITVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_EDITVIEW, Editview )) #define EDITVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_EDITVIEW, EditviewClass )) #define IS_EDITVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_EDITVIEW )) #define IS_EDITVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_EDITVIEW )) typedef struct _Editview { Graphicview parent_object; /* Widgets. */ GtkWidget *label; /* Display caption here */ GtkWidget *text; /* Edit value here */ } Editview; typedef struct _EditviewClass { GraphicviewClass parent_class; /* My methods. */ } EditviewClass; GtkType editview_get_type( void ); void editview_set_entry( Editview *editview, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); nip2-8.7.1/src/imageinfo.c0000644000175000017500000015671513351443023012226 00000000000000/* image management ... a layer over the VIPS IMAGE type */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* jobs: - reference counting layer ... in Managed base class, plus links to heap garbage collection - filesystem tracking: we stat open files and signal file_changed if we see a change - cache: several open( "fred.v" )s share a single Imageinfo, provided their mtimes are all the same - lookup table management ... if an operation can work with pixel lookup tables (found by examining a flag in the VIPS function descriptor), then instead of operating on the image, the operation runs on the LUT associated with that image ... Imageinfo tracks the LUTs representing delayed eval - dependency tracking ... an imageinfo can require several other imageinfos to be open for it to work properly; we follow these dependencies, and delay destroying an imageinfo until it's not required by any others - temp file management ... we can make temp images on disc; we unlink() these temps when they're no longer needed - imageinfo/expr association tracking ... we track when an expr receives an imageinfo as its value; the info is used to get region views to display in the right image ... see expr_real_new_value() - paint stuff: also undo/redo buffers, each with a "*_changed" signal */ /* more stuff: while we transition to vips8, also use imageinfo to wrap VipsImage most of the jobs above are pushed down into vips8 now ... except for - reference counting layer ... in Managed base class - filesystem tracking: we stat open files and signal file_changed if we see a change - cache: several open( "fred.v" )s share a single Imageinfo, provided their mtimes are all the same */ #include "ip.h" /* #define DEBUG #define DEBUG_MAKE #define DEBUG_RGB #define DEBUG_OPEN #define DEBUG_CHECK */ static iContainerClass *imageinfogroup_parent_class = NULL; static void imageinfogroup_finalize( GObject *gobject ) { Imageinfogroup *imageinfogroup = IMAGEINFOGROUP( gobject ); IM_FREEF( g_hash_table_destroy, imageinfogroup->filename_hash ); G_OBJECT_CLASS( imageinfogroup_parent_class )->finalize( gobject ); } static void imageinfogroup_child_add( iContainer *parent, iContainer *child, int pos ) { Imageinfogroup *imageinfogroup = IMAGEINFOGROUP( parent ); Imageinfo *imageinfo = IMAGEINFO( child ); const char *name = IOBJECT( imageinfo )->name; GSList *hits; hits = (GSList *) g_hash_table_lookup( imageinfogroup->filename_hash, name ); hits = g_slist_prepend( hits, imageinfo ); g_hash_table_insert( imageinfogroup->filename_hash, (gpointer) name, (gpointer) hits ); ICONTAINER_CLASS( imageinfogroup_parent_class )-> child_add( parent, child, pos ); } static void imageinfogroup_child_remove( iContainer *parent, iContainer *child ) { Imageinfogroup *imageinfogroup = IMAGEINFOGROUP( parent ); Imageinfo *imageinfo = IMAGEINFO( child ); const char *name = IOBJECT( imageinfo )->name; GSList *hits; hits = (GSList *) g_hash_table_lookup( imageinfogroup->filename_hash, name ); g_assert( hits ); hits = g_slist_remove( hits, imageinfo ); /* child is going away (probably), so we don't want to link hits back * on again with child->name as the key ... if possible, look down * hits for another name we can use instead. */ if( hits ) { const char *new_name = IOBJECT( hits->data )->name; g_hash_table_replace( imageinfogroup->filename_hash, (gpointer) new_name, (gpointer) hits ); } else g_hash_table_remove( imageinfogroup->filename_hash, (gpointer) name ); ICONTAINER_CLASS( imageinfogroup_parent_class )-> child_remove( parent, child ); } static void imageinfogroup_class_init( ImageinfogroupClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iContainerClass *icontainer_class = ICONTAINER_CLASS( class ); imageinfogroup_parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = imageinfogroup_finalize; icontainer_class->child_add = imageinfogroup_child_add; icontainer_class->child_remove = imageinfogroup_child_remove; } static void imageinfogroup_init( Imageinfogroup *imageinfogroup ) { #ifdef DEBUG printf( "imageinfogroup_init\n" ); #endif /*DEBUG*/ imageinfogroup->filename_hash = g_hash_table_new( g_str_hash, g_str_equal ); } GType imageinfogroup_get_type( void ) { static GType imageinfogroup_type = 0; if( !imageinfogroup_type ) { static const GTypeInfo info = { sizeof( ImageinfogroupClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) imageinfogroup_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Imageinfogroup ), 32, /* n_preallocs */ (GInstanceInitFunc) imageinfogroup_init, }; imageinfogroup_type = g_type_register_static( TYPE_ICONTAINER, "Imageinfogroup", &info, 0 ); } return( imageinfogroup_type ); } Imageinfogroup * imageinfogroup_new( void ) { Imageinfogroup *imageinfogroup = IMAGEINFOGROUP( g_object_new( TYPE_IMAGEINFOGROUP, NULL ) ); return( imageinfogroup ); } static void * imageinfogroup_lookup_test( Imageinfo *imageinfo, struct stat *buf ) { const char *name = IOBJECT( imageinfo )->name; if( name && buf->st_mtime == imageinfo->mtime ) return( imageinfo ); return( NULL ); } /* Look up by filename ... mtimes have to match too. */ static Imageinfo * imageinfogroup_lookup( Imageinfogroup *imageinfogroup, const char *filename ) { GSList *hits; Imageinfo *imageinfo; struct stat buf; if( stat( filename, &buf ) == 0 && (hits = (GSList *) g_hash_table_lookup( imageinfogroup->filename_hash, filename )) && (imageinfo = IMAGEINFO( slist_map( hits, (SListMapFn) imageinfogroup_lookup_test, &buf ) )) ) return( imageinfo ); return( NULL ); } /* Our signals. */ enum { SIG_AREA_CHANGED, /* Area of image has changed: update screen */ SIG_AREA_PAINTED, /* Area of image has been painted */ SIG_UNDO_CHANGED, /* Undo/redo state has changed */ SIG_FILE_CHANGED, /* Underlying file seems to have changed */ SIG_INVALIDATE, /* IMAGE* has been invalidated */ SIG_LAST }; static ManagedClass *parent_class = NULL; static guint imageinfo_signals[SIG_LAST] = { 0 }; #if defined(DEBUG) || defined(DEBUG_OPEN) || defined(DEBUG_RGB) || \ defined(DEBUG_CHECK) || defined(DEBUG_MAKE) static void imageinfo_print( Imageinfo *imageinfo ) { printf( " \"%s\" mtime = %d (%p)\n", IOBJECT( imageinfo )->name, (int) imageinfo->mtime, imageinfo ); } #endif void * imageinfo_area_changed( Imageinfo *imageinfo, Rect *dirty ) { g_assert( IS_IMAGEINFO( imageinfo ) ); #ifdef DEBUG printf( "imageinfo_area_changed: " "left = %d, top = %d, width = %d, height = %d\n", dirty->left, dirty->top, dirty->width, dirty->height ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( imageinfo ), imageinfo_signals[SIG_AREA_CHANGED], 0, dirty ); return( NULL ); } void * imageinfo_area_painted( Imageinfo *imageinfo, Rect *dirty ) { g_assert( IS_IMAGEINFO( imageinfo ) ); #ifdef DEBUG printf( "imageinfo_area_painted: left = %d, top = %d, " "width = %d, height = %d\n", dirty->left, dirty->top, dirty->width, dirty->height ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( imageinfo ), imageinfo_signals[SIG_AREA_PAINTED], 0, dirty ); return( NULL ); } static void * imageinfo_undo_changed( Imageinfo *imageinfo ) { g_assert( IS_IMAGEINFO( imageinfo ) ); g_signal_emit( G_OBJECT( imageinfo ), imageinfo_signals[SIG_UNDO_CHANGED], 0 ); return( NULL ); } static void * imageinfo_file_changed( Imageinfo *imageinfo ) { g_assert( IS_IMAGEINFO( imageinfo ) ); #ifdef DEBUG_CHECK printf( "imageinfo_file_changed:" ); imageinfo_print( imageinfo ); #endif /*DEBUG_CHECK*/ g_signal_emit( G_OBJECT( imageinfo ), imageinfo_signals[SIG_FILE_CHANGED], 0 ); return( NULL ); } static void * imageinfo_invalidate( Imageinfo *imageinfo ) { g_assert( IS_IMAGEINFO( imageinfo ) ); #ifdef DEBUG_CHECK printf( "imageinfo_invalidate:" ); imageinfo_print( imageinfo ); #endif /*DEBUG_CHECK*/ g_signal_emit( G_OBJECT( imageinfo ), imageinfo_signals[SIG_INVALIDATE], 0 ); return( NULL ); } void imageinfo_expr_add( Imageinfo *imageinfo, Expr *expr ) { #ifdef DEBUG printf( "imageinfo_expr_add: " ); expr_name_print( expr ); printf( "has imageinfo \"%s\" as value\n", imageinfo->im->filename ); #endif /*DEBUG*/ g_assert( !g_slist_find( imageinfo->exprs, expr ) ); g_assert( !expr->imageinfo ); expr->imageinfo = imageinfo; imageinfo->exprs = g_slist_prepend( imageinfo->exprs, expr ); } void * imageinfo_expr_remove( Expr *expr, Imageinfo *imageinfo ) { #ifdef DEBUG printf( "imageinfo_expr_remove: " ); expr_name_print( expr ); printf( "has lost imageinfo \"%s\" as value\n", imageinfo->im->filename ); #endif /*DEBUG*/ g_assert( expr->imageinfo ); g_assert( g_slist_find( imageinfo->exprs, expr ) ); g_assert( expr->imageinfo == imageinfo ); expr->imageinfo = NULL; imageinfo->exprs = g_slist_remove( imageinfo->exprs, expr ); return( NULL ); } GSList * imageinfo_expr_which( Imageinfo *imageinfo ) { return( imageinfo->exprs ); } /* Find the underlying image in an imageinfo. */ IMAGE * imageinfo_get_underlying( Imageinfo *imageinfo ) { if( imageinfo->underlying ) return( imageinfo_get_underlying( imageinfo->underlying ) ); else return( imageinfo->im ); } /* Free up an undo fragment. */ static void imageinfo_undofragment_free( Undofragment *frag ) { IM_FREEF( im_close, frag->im ); IM_FREE( frag ); } /* Free an undo buffer. */ static void imageinfo_undobuffer_free( Undobuffer *undo ) { slist_map( undo->frags, (SListMapFn) imageinfo_undofragment_free, NULL ); IM_FREEF( g_slist_free, undo->frags ); IM_FREE( undo ); } /* Free all undo information attached to an imageinfo. */ static void imageinfo_undo_free( Imageinfo *imageinfo ) { slist_map( imageinfo->redo, (SListMapFn) imageinfo_undobuffer_free, NULL ); IM_FREEF( g_slist_free, imageinfo->redo ); slist_map( imageinfo->undo, (SListMapFn) imageinfo_undobuffer_free, NULL ); IM_FREEF( g_slist_free, imageinfo->undo ); IM_FREEF( imageinfo_undobuffer_free, imageinfo->cundo ); } static void imageinfo_dispose_eval( Imageinfo *imageinfo ) { imageinfo->monitored = FALSE; /* Make sure any callbacks from the IMAGE stop working. */ if( imageinfo->proxy ) { imageinfo->proxy->imageinfo = NULL; imageinfo->proxy = NULL; } } static void imageinfo_dispose( GObject *gobject ) { Imageinfo *imageinfo = IMAGEINFO( gobject ); #ifdef DEBUG_OPEN printf( "imageinfo_dispose:" ); imageinfo_print( imageinfo ); #endif /*DEBUG_OPEN*/ slist_map( imageinfo->exprs, (SListMapFn) imageinfo_expr_remove, imageinfo ); g_assert( !imageinfo->exprs ); imageinfo_dispose_eval( imageinfo ); IM_FREEF( g_source_remove, imageinfo->check_tid ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } /* Final death! */ static void imageinfo_finalize( GObject *gobject ) { Imageinfo *imageinfo = IMAGEINFO( gobject ); gboolean isfile = imageinfo->im && im_isfile( imageinfo->im ); #ifdef DEBUG_MAKE printf( "imageinfo_finalize:" ); imageinfo_print( imageinfo ); #endif /*DEBUG_MAKE*/ IM_FREEF( im_close, imageinfo->im ); IM_FREEF( im_close, imageinfo->mapped_im ); IM_FREEF( im_close, imageinfo->identity_lut ); if( imageinfo->dfile && imageinfo->delete_filename && isfile ) { #ifdef DEBUG_OPEN printf( "imageinfo_destroy: unlinking \"%s\"\n", name ); #endif /*DEBUG_OPEN*/ unlinkf( "%s", imageinfo->delete_filename ); iobject_changed( IOBJECT( main_imageinfogroup ) ); } VIPS_FREE( imageinfo->delete_filename ); MANAGED_UNREF( imageinfo->underlying ); imageinfo_undo_free( imageinfo ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Make an info string about an imageinfo. */ static void imageinfo_info( iObject *iobject, VipsBuf *buf ) { Imageinfo *imageinfo = IMAGEINFO( iobject ); vips_buf_appendi( buf, imageinfo_get( FALSE, imageinfo ) ); /* Don't chain up to parent->info(), we don't want all the other * stuff, this is going to be used for a caption. */ } static void imageinfo_real_area_changed( Imageinfo *imageinfo, Rect *dirty ) { } static void imageinfo_real_area_painted( Imageinfo *imageinfo, Rect *dirty ) { /* Cache attaches to this signal and invalidates on paint. Trigger a * repaint in turn. */ imageinfo_area_changed( imageinfo, dirty ); } static void imageinfo_real_undo_changed( Imageinfo *imageinfo ) { } static void imageinfo_real_file_changed( Imageinfo *imageinfo ) { } static void imageinfo_real_invalidate( Imageinfo *imageinfo ) { } static void imageinfo_class_init( ImageinfoClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); ManagedClass *managed_class = MANAGED_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = imageinfo_dispose; gobject_class->finalize = imageinfo_finalize; iobject_class->info = imageinfo_info; /* Timeout on unreffed images. */ managed_class->keepalive = 60.0; class->area_changed = imageinfo_real_area_changed; class->area_painted = imageinfo_real_area_painted; class->undo_changed = imageinfo_real_undo_changed; class->file_changed = imageinfo_real_file_changed; class->invalidate = imageinfo_real_invalidate; /* Create signals. */ imageinfo_signals[SIG_AREA_CHANGED] = g_signal_new( "area_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ImageinfoClass, area_changed ), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER ); imageinfo_signals[SIG_AREA_PAINTED] = g_signal_new( "area_painted", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ImageinfoClass, area_painted ), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER ); imageinfo_signals[SIG_UNDO_CHANGED] = g_signal_new( "undo_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ImageinfoClass, undo_changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); imageinfo_signals[SIG_FILE_CHANGED] = g_signal_new( "file_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ImageinfoClass, file_changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); imageinfo_signals[SIG_INVALIDATE] = g_signal_new( "invalidate", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ImageinfoClass, invalidate ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); } static void imageinfo_init( Imageinfo *imageinfo ) { #ifdef DEBUG_MAKE printf( "imageinfo_init: %p\n", imageinfo ); #endif /*DEBUG_MAKE*/ imageinfo->im = NULL; imageinfo->mapped_im = NULL; imageinfo->identity_lut = NULL; imageinfo->underlying = NULL; imageinfo->proxy = NULL; imageinfo->dfile = FALSE; imageinfo->delete_filename = NULL; imageinfo->from_file = FALSE; imageinfo->mtime = 0; imageinfo->exprs = NULL; imageinfo->ok_to_paint = FALSE; imageinfo->undo = NULL; imageinfo->redo = NULL; imageinfo->cundo = NULL; imageinfo->monitored = FALSE; imageinfo->check_mtime = 0; imageinfo->check_tid = 0; } GType imageinfo_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ImageinfoClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) imageinfo_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Imageinfo ), 32, /* n_preallocs */ (GInstanceInitFunc) imageinfo_init, }; type = g_type_register_static( TYPE_MANAGED, "Imageinfo", &info, 0 ); } return( type ); } static int imageinfo_proxy_eval( Imageinfoproxy *proxy ) { Imageinfo *imageinfo = proxy->imageinfo; if( imageinfo && imageinfo->im->time ) if( progress_update_percent( imageinfo->im->time->percent, imageinfo->im->time->eta ) ) return( -1 ); return( 0 ); } static int imageinfo_proxy_invalidate( Imageinfoproxy *proxy ) { Imageinfo *imageinfo = proxy->imageinfo; if( imageinfo ) imageinfo_invalidate( imageinfo ); return( 0 ); } static int imageinfo_proxy_preclose( Imageinfoproxy *proxy ) { Imageinfo *imageinfo = proxy->imageinfo; /* Remove everything related to progress. */ if( imageinfo ) imageinfo_dispose_eval( imageinfo ); return( 0 ); } /* Add a proxy to track IMAGE events. */ static void imageinfo_proxy_add( Imageinfo *imageinfo ) { /* Only if we're running interactively. */ if( main_option_batch ) return; /* Already being monitored? */ if( imageinfo->monitored ) return; imageinfo->monitored = TRUE; /* Need a proxy on IMAGE. */ g_assert( !imageinfo->proxy ); if( !(imageinfo->proxy = IM_NEW( imageinfo->im, Imageinfoproxy )) ) if( !(imageinfo->proxy = IM_NEW( NULL, Imageinfoproxy )) ) return; imageinfo->proxy->im = imageinfo->im; imageinfo->proxy->imageinfo = imageinfo; (void) im_add_eval_callback( imageinfo->im, (im_callback_fn) imageinfo_proxy_eval, imageinfo->proxy, NULL ); (void) im_add_invalidate_callback( imageinfo->im, (im_callback_fn) imageinfo_proxy_invalidate, imageinfo->proxy, NULL ); /* Has to be preclose, because we want to be sure we disconnect before * the proxy is freed on a close callback. */ (void) im_add_preclose_callback( imageinfo->im, (im_callback_fn) imageinfo_proxy_preclose, imageinfo->proxy, NULL ); } /* Make a basic imageinfo. No refs, will be destroyed on next GC. If name is * NULL, make a temp name up; otherwise name needs to be unique. */ Imageinfo * imageinfo_new( Imageinfogroup *imageinfogroup, Heap *heap, IMAGE *im, const char *name ) { Imageinfo *imageinfo = IMAGEINFO( g_object_new( TYPE_IMAGEINFO, NULL ) ); char buf[FILENAME_MAX]; #ifdef DEBUG_OPEN printf( "imageinfo_new: %p \"%s\"\n", imageinfo, im->filename ); #endif /*DEBUG_OPEN*/ managed_link_heap( MANAGED( imageinfo ), heap ); if( !name ) { if( !temp_name( buf, "v" ) ) /* Will be freed on next GC. */ return( NULL ); name = buf; } iobject_set( IOBJECT( imageinfo ), name, NULL ); /* Only record the pointer when we know we will make the imageinfo * successfully. */ imageinfo->im = im; icontainer_child_add( ICONTAINER( imageinfogroup ), ICONTAINER( imageinfo ), -1 ); imageinfo_proxy_add( imageinfo ); return( imageinfo ); } /* An image is a result of a LUT operation on an earlier imageinfo. */ void imageinfo_set_underlying( Imageinfo *top_imageinfo, Imageinfo *imageinfo ) { g_assert( !top_imageinfo->underlying ); top_imageinfo->underlying = imageinfo; MANAGED_REF( top_imageinfo->underlying ); } /* Make a temp image. Deleted on close. No refs: closed on next GC. If you * want it to stick around, ref it! */ Imageinfo * imageinfo_new_temp( Imageinfogroup *imageinfogroup, Heap *heap, const char *name, const char *mode ) { IMAGE *im; char tname[FILENAME_MAX]; Imageinfo *imageinfo; if( !temp_name( tname, "v" ) || !(im = im_open( tname, mode )) ) return( NULL ); if( !(imageinfo = imageinfo_new( imageinfogroup, heap, im, name )) ) { im_close( im ); return( NULL ); } imageinfo->dfile = TRUE; VIPS_SETSTR( imageinfo->delete_filename, tname ); return( imageinfo ); } /* Need this context during imageinfo_open_image_input(). */ typedef struct _ImageinfoOpen { Imageinfogroup *imageinfogroup; Heap *heap; const char *filename; GtkWidget *parent; } ImageinfoOpen; /* Open for read ... returns a non-heap pointer, destroy if it goes in the * heap. */ static Imageinfo * imageinfo_open_image_input( const char *filename, ImageinfoOpen *open ) { Imageinfo *imageinfo; VipsFormatClass *format; if( !(format = vips_format_for_file( filename )) ) return( NULL ); if( strcmp( VIPS_OBJECT_CLASS( format )->nickname, "vips" ) == 0 ) { IMAGE *im; if( !(im = im_open( filename, "r" )) ) return( NULL ); if( !(imageinfo = imageinfo_new( open->imageinfogroup, open->heap, im, open->filename )) ) { im_close( im ); return( NULL ); } MANAGED_REF( imageinfo ); #ifdef DEBUG_OPEN printf( "imageinfo_open_image_input: opened VIPS \"%s\"\n", filename ); #endif /*DEBUG_OPEN*/ } else { VipsFormatFlags flags = vips_format_get_flags( format, filename ); const char *mode = flags & VIPS_FORMAT_PARTIAL ? "p" : "w"; if( !(imageinfo = imageinfo_new_temp( open->imageinfogroup, open->heap, open->filename, mode )) ) return( NULL ); MANAGED_REF( imageinfo ); if( format->load( filename, imageinfo->im ) || im_histlin( imageinfo->im, "im_copy %s %s", filename, imageinfo->im->filename ) ) { MANAGED_UNREF( imageinfo ); return( NULL ); } #ifdef DEBUG_OPEN printf( "imageinfo_open_image_input: opened %s \"%s\"\n", VIPS_OBJECT_CLASS( format )->nickname, filename ); #endif /*DEBUG_OPEN*/ } /* Get ready for input. */ if( im_pincheck( imageinfo->im ) ) return( NULL ); /* The rewind will have removed everything from the IMAGE. Reattach * progress. */ imageinfo_proxy_add( imageinfo ); /* Attach the original filename ... pick this up again later as a * save default. */ if( im_meta_set_string( imageinfo->im, ORIGINAL_FILENAME, filename ) ) return( NULL ); return( imageinfo ); } Imageinfo * imageinfo_new_from_pixbuf( Imageinfogroup *imageinfogroup, Heap *heap, GdkPixbuf *pixbuf ) { int width; int height; int bands; guchar *bytes; Imageinfo *ii; size_t vips_length; width = gdk_pixbuf_get_width( pixbuf ); height = gdk_pixbuf_get_height( pixbuf ); bands = gdk_pixbuf_get_n_channels( pixbuf ); /* 2.26 and later have gdk_pixbuf_get_pixels_with_length() * which would let us check the size, but we can't reslly use it yet. * Another time! guint length; bytes = gdk_pixbuf_get_pixels_with_length( pixbuf, &length ); if( vips_length != length ) { error_top( _( "Unable to create image." ) ); error_sub( _( "vips expected %zd bytes, gdkpixbuf made %d" ), vips_length, length ); return( NULL ); } */ bytes = gdk_pixbuf_get_pixels( pixbuf ); if( !(ii = imageinfo_new_temp( imageinfogroup, heap, NULL, "t" )) ) return( NULL ); im_initdesc( ii->im, width, height, bands, IM_BBITS_BYTE, IM_BANDFMT_UCHAR, IM_CODING_NONE, IM_TYPE_sRGB, 1.0, 1.0, 0, 0 ); if( im_setupout( ii->im ) ) return( NULL ); vips_length = VIPS_IMAGE_SIZEOF_LINE( ii->im ) * height; memcpy( ii->im->data, bytes, vips_length ); return( ii ); } /* Was this ii loaded from a file (ie. ->name contains a filename the user * might recognise). */ gboolean imageinfo_is_from_file( Imageinfo *imageinfo ) { return( IOBJECT( imageinfo )->name && imageinfo->from_file ); } static gint imageinfo_attach_check_cb( Imageinfo *imageinfo ) { if( imageinfo_is_from_file( imageinfo ) && imageinfo->check_tid ) { struct stat buf; if( !stat( IOBJECT( imageinfo )->name, &buf ) && buf.st_mtime != imageinfo->check_mtime ) { imageinfo->check_mtime = buf.st_mtime; imageinfo_file_changed( imageinfo ); } } return( TRUE ); } /* Start checking this file for updates, signal reload if there is one. */ static void imageinfo_attach_check( Imageinfo *imageinfo ) { if( imageinfo_is_from_file( imageinfo ) && !imageinfo->check_tid ) { struct stat buf; /* Need to be able to stat() to be able to track a file. */ if( stat( IOBJECT( imageinfo )->name, &buf ) ) return; imageinfo->mtime = buf.st_mtime; imageinfo->check_mtime = imageinfo->mtime; imageinfo->check_tid = g_timeout_add( 1000, (GSourceFunc) imageinfo_attach_check_cb, imageinfo ); #ifdef DEBUG_CHECK printf( "imageinfo_attach_check: starting to check" ); imageinfo_print( imageinfo ); #endif /*DEBUG_CHECK*/ } else IM_FREEF( g_source_remove, imageinfo->check_tid ); } /* Open a filename for input. The filenmae can have an embedded mode. */ Imageinfo * imageinfo_new_input( Imageinfogroup *imageinfogroup, GtkWidget *parent, Heap *heap, const char *name ) { Imageinfo *imageinfo; ImageinfoOpen open; if( (imageinfo = imageinfogroup_lookup( imageinfogroup, name )) ) { /* We always make a new non-heap pointer. */ MANAGED_REF( imageinfo ); return( imageinfo ); } open.imageinfogroup = imageinfogroup; open.heap = heap; open.filename = name; open.parent = parent; if( !(imageinfo = (Imageinfo *) callv_string_filename( (callv_string_fn) imageinfo_open_image_input, name, &open, NULL, NULL )) ) { error_top( _( "Unable to open image." ) ); error_sub( _( "Unable to open file \"%s\" as image." ), name ); error_vips(); return( NULL ); } imageinfo->from_file = TRUE; imageinfo_attach_check( imageinfo ); return( imageinfo ); } /* Add an identity lut, if this is a LUTtable image. */ static IMAGE * imageinfo_get_identity_lut( Imageinfo *imageinfo ) { if( imageinfo->im->Coding == IM_CODING_NONE && imageinfo->im->BandFmt == IM_BANDFMT_UCHAR ) { if( !imageinfo->identity_lut ) { char tname[FILENAME_MAX]; IMAGE *im; if( !temp_name( tname, "v" ) || !(im = im_open( tname, "p" )) ) return( NULL ); imageinfo->identity_lut = im; if( im_identity( imageinfo->identity_lut, imageinfo->im->Bands ) || im_histlin( imageinfo->identity_lut, "im_identity %s %d", imageinfo->identity_lut->filename, imageinfo->im->Bands ) ) return( NULL ); } return( imageinfo->identity_lut ); } else return( NULL ); } static IMAGE * imageinfo_get_mapped( Imageinfo *imageinfo ) { if( !imageinfo->mapped_im ) { IMAGE *im = imageinfo_get_underlying( imageinfo ); IMAGE *mapped_im; char name[FILENAME_MAX]; char *argv[4]; if( !temp_name( name, "v" ) || !(mapped_im = im_open( name, "p" )) ) return( NULL ); argv[0] = im->filename; argv[1] = mapped_im->filename; argv[2] = imageinfo->im->filename; argv[3] = NULL; if( im_maplut( im, mapped_im, imageinfo->im ) || im_updatehist( mapped_im, "im_maplut", 3, argv ) ) { im_close( mapped_im ); error_vips_all(); return( NULL ); } imageinfo->mapped_im = mapped_im; } return( imageinfo->mapped_im ); } /* Get a lut ... or not! */ IMAGE * imageinfo_get( gboolean use_lut, Imageinfo *imageinfo ) { if( !imageinfo ) return( NULL ); if( use_lut && imageinfo->underlying ) return( imageinfo->im ); if( use_lut && !imageinfo->underlying ) { IMAGE *lut; if( (lut = imageinfo_get_identity_lut( imageinfo )) ) return( lut ); else return( imageinfo->im ); } else if( !use_lut && imageinfo->underlying ) return( imageinfo_get_mapped( imageinfo ) ); else return( imageinfo->im ); } /* Do a set of II all refer to the same underlying image? Used to spot * LUTable optimisations. */ gboolean imageinfo_same_underlying( Imageinfo *imageinfo[], int n ) { int i; if( n < 2 ) return( TRUE ); else { IMAGE *first = imageinfo_get_underlying( imageinfo[0] ); for( i = 1; i < n; i++ ) if( imageinfo_get_underlying( imageinfo[i] ) != first ) return( FALSE ); return( TRUE ); } } /* Write to a filename. */ gboolean imageinfo_write( Imageinfo *imageinfo, const char *name ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); if( vips_format_write( im, name ) ) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split( name, filename, mode ); error_top( _( "Unable to write to file." ) ); error_sub( _( "Error writing image to file \"%s\"." ), filename ); error_vips(); return( FALSE ); } return( TRUE ); } static gboolean imageinfo_make_paintable( Imageinfo *imageinfo ) { progress_begin(); if( im_rwcheck( imageinfo->im ) ) { progress_end(); error_top( _( "Unable to paint on image." ) ); error_sub( _( "Unable to get write permission for " "file \"%s\".\nCheck permission settings." ), imageinfo->im->filename ); error_vips(); return( FALSE ); } progress_end(); imageinfo->ok_to_paint = TRUE; return( TRUE ); } static void imageinfo_check_paintable_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Imageinfo *imageinfo = IMAGEINFO( client ); if( !imageinfo_make_paintable( imageinfo ) ) { nfn( sys, IWINDOW_ERROR ); return; } nfn( sys, IWINDOW_YES ); } /* Check painting is OK. nfn() called on "ok!". Returns FALSE if it's * not immediately obvious that we can paint. */ gboolean imageinfo_check_paintable( Imageinfo *imageinfo, GtkWidget *parent, iWindowNotifyFn nfn, void *sys ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); if( im && im_isfile( im ) && !imageinfo->dfile && !imageinfo->ok_to_paint ) { iDialog *idlg; idlg = box_yesno( parent, imageinfo_check_paintable_cb, iwindow_true_cb, imageinfo, nfn, sys, _( "Modify" ), _( "Modify disc file?" ), _( "This image is being shown directly from the " "disc file:\n\n" " %s\n\n" "If you paint on this file, it will be permanently " "changed. If something goes wrong, you may lose work. " "Are you sure you want to modify this file?" ), IOBJECT( imageinfo )->name ); idialog_set_iobject( idlg, IOBJECT( imageinfo ) ); return( FALSE ); } else if( im && !im_isfile( im ) && !imageinfo->ok_to_paint ) { if( !imageinfo_make_paintable( imageinfo ) ) { nfn( sys, IWINDOW_ERROR ); return( FALSE ); } } nfn( sys, IWINDOW_YES ); return( TRUE ); } /* Try to get an Imageinfo from a symbol. */ Imageinfo * imageinfo_sym_image( Symbol *sym ) { PElement *root = &sym->expr->root; if( sym->type == SYM_VALUE && PEISIMAGE( root ) ) return( PEGETII( root ) ); else return( NULL ); } static Undofragment * imageinfo_undofragment_new( Undobuffer *undo ) { Undofragment *frag = INEW( NULL, Undofragment ); frag->undo = undo; frag->im = NULL; return( frag ); } static Undobuffer * imageinfo_undobuffer_new( Imageinfo *imageinfo ) { Undobuffer *undo = INEW( NULL, Undobuffer ); undo->imageinfo = imageinfo; undo->frags = NULL; /* No pixels in bounding box at the moment. */ undo->bbox.left = 0; undo->bbox.top = 0; undo->bbox.width = 0; undo->bbox.height = 0; return( undo ); } /* Grab from the image into an IMAGE buffer. Always grab to memory. */ static IMAGE * imageinfo_undo_grab_area( IMAGE *im, Rect *dirty ) { IMAGE *save; /* Make new image to extract to. */ if( !(save = im_open( "undo buffer", "t" )) ) return( NULL ); /* Try to extract from im. */ if( im_extract_area( im, save, dirty->left, dirty->top, dirty->width, dirty->height ) ) { im_close( save ); error_vips_all(); return( NULL ); } return( save ); } /* Grab into an undo fragment. Add frag to frag list on undo buffer, expand * bounding box. */ static Undofragment * imageinfo_undo_grab( Undobuffer *undo, Rect *dirty ) { Imageinfo *imageinfo = undo->imageinfo; Undofragment *frag = imageinfo_undofragment_new( undo ); IMAGE *im = imageinfo_get( FALSE, imageinfo ); Rect bbox; /* Try to extract from im. Memory allocation happens at this * point, so we must be careful! */ if( !(frag->im = imageinfo_undo_grab_area( im, dirty )) ) { imageinfo_undofragment_free( frag ); error_vips_all(); return( NULL ); } /* Note position of this frag. */ frag->pos = *dirty; /* Add frag to frag list on undo buffer. */ undo->frags = g_slist_prepend( undo->frags, frag ); /* Find bounding box for saved pixels. */ im_rect_unionrect( dirty, &undo->bbox, &bbox ); undo->bbox = bbox; /* Return new frag. */ return( frag ); } /* Trim the undo buffer if we have more than x items on it. */ static void imageinfo_undo_trim( Imageinfo *imageinfo ) { int max = PAINTBOX_MAX_UNDO; int len = g_slist_length( imageinfo->undo ); if( max >= 0 && len > max ) { GSList *l; int i; l = g_slist_reverse( imageinfo->undo ); for( i = 0; i < len - max; i++ ) { Undobuffer *undo = (Undobuffer *) l->data; imageinfo_undobuffer_free( undo ); l = g_slist_remove( l, undo ); } imageinfo->undo = g_slist_reverse( l ); } #ifdef DEBUG printf( "imageinfo_undo_trim: %d items in undo buffer\n", g_slist_length( imageinfo->undo ) ); #endif /*DEBUG*/ } /* Mark the start or end of an undo session. Copy current undo information * to the undo buffers and NULL out the current undo pointer. Junk all redo * information: this new undo action makes all that out of date. */ void imageinfo_undo_mark( Imageinfo *imageinfo ) { /* Is there an existing undo save area? */ if( imageinfo->cundo ) { /* Left over from the last undo save. Copy to undo save list * and get ready for new undo buffer. */ imageinfo->undo = g_slist_prepend( imageinfo->undo, imageinfo->cundo ); imageinfo->cundo = NULL; } /* Junk all redo information. */ slist_map( imageinfo->redo, (SListMapFn) imageinfo_undobuffer_free, NULL ); IM_FREEF( g_slist_free, imageinfo->redo ); /* Trim undo buffer. */ imageinfo_undo_trim( imageinfo ); /* Update menus. */ imageinfo_undo_changed( imageinfo ); } /* Add to the undo buffer. If there is no undo buffer currently under * construction, make a new one. If there is an existing undo buffer, try to * grow it left/right/up/down so as to just enclose the new bounding box. We * assume that our dirty areas are not going to be disconnected. Is this * always true? No - if you move smudge or smear quickly, you can get * non-overlapping areas. However: if you do lots of little operations in more * or less the same place (surely the usual case), then this technique will be * far better. */ static gboolean imageinfo_undo_add( Imageinfo *imageinfo, Rect *dirty ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); Undobuffer *undo = imageinfo->cundo; Rect over, image, clipped; /* Undo disabled? Do nothing. */ if( PAINTBOX_MAX_UNDO == 0 ) return( TRUE ); /* Clip dirty against image size. */ image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( &image, dirty, &clipped ); /* Is there anything left? If not, can return immediately. */ if( im_rect_isempty( &clipped ) ) return( TRUE ); if( !undo ) { /* No current undo buffer ... start a new one for this action. */ if( !(imageinfo->cundo = undo = imageinfo_undobuffer_new( imageinfo )) ) return( FALSE ); return( imageinfo_undo_grab( undo, &clipped ) != NULL ); } /* Existing stuff we are to add to. Try to expand our undo * area to just enclose the new bounding box. We assume that * there is an overlap between the new and old stuff. */ /* Do we need to expand our saved area to the right? */ if( IM_RECT_RIGHT( &clipped ) > IM_RECT_RIGHT( &undo->bbox ) ) { /* Expand to the right. Calculate the section we need * to add to our bounding box. */ over.left = IM_RECT_RIGHT( &undo->bbox ); over.top = undo->bbox.top; over.width = IM_RECT_RIGHT( &clipped ) - IM_RECT_RIGHT( &undo->bbox ); over.height = undo->bbox.height; /* Grab new fragment. */ if( !imageinfo_undo_grab( undo, &over ) ) return( FALSE ); } /* Do we need to expand our saved area to the left? */ if( undo->bbox.left > clipped.left ) { over.left = clipped.left; over.top = undo->bbox.top; over.width = undo->bbox.left - clipped.left; over.height = undo->bbox.height; if( !imageinfo_undo_grab( undo, &over ) ) return( FALSE ); } /* Do we need to expand our saved area upwards? */ if( undo->bbox.top > clipped.top ) { over.left = undo->bbox.left; over.top = clipped.top; over.width = undo->bbox.width; over.height = undo->bbox.top - clipped.top; if( !imageinfo_undo_grab( undo, &over ) ) return( FALSE ); } /* Do we need to expand our saved area downwards? */ if( IM_RECT_BOTTOM( &clipped ) > IM_RECT_BOTTOM( &undo->bbox ) ) { over.left = undo->bbox.left; over.top = IM_RECT_BOTTOM( &undo->bbox ); over.width = undo->bbox.width; over.height = IM_RECT_BOTTOM( &clipped ) - IM_RECT_BOTTOM( &undo->bbox ); if( !imageinfo_undo_grab( undo, &over ) ) return( FALSE ); } return( TRUE ); } /* Paste an undo fragment back into the image. */ static void * imageinfo_undofragment_paste( Undofragment *frag ) { Undobuffer *undo = frag->undo; Imageinfo *imageinfo = undo->imageinfo; IMAGE *im = imageinfo_get( FALSE, imageinfo ); im_insertplace( im, frag->im, frag->pos.left, frag->pos.top ); imageinfo_area_painted( imageinfo, &frag->pos ); return( NULL ); } /* Paste a whole undo buffer back into the image. */ static void imageinfo_undobuffer_paste( Undobuffer *undo ) { slist_map( undo->frags, (SListMapFn) imageinfo_undofragment_paste, NULL ); } /* Undo a paint action. */ gboolean imageinfo_undo( Imageinfo *imageinfo ) { Undobuffer *undo; /* Find the undo action we are to perform. */ if( !imageinfo->undo ) return( TRUE ); undo = (Undobuffer *) imageinfo->undo->data; /* We are going to undo the first action on the undo list. We must * save the area under the first undo action to the redo list. Do * the save, even if undo is disabled. */ if( !imageinfo_undo_add( imageinfo, &undo->bbox ) ) return( FALSE ); /* Add new undo area. */ imageinfo->redo = g_slist_prepend( imageinfo->redo, imageinfo->cundo ); imageinfo->cundo = NULL; /* Paint undo back. */ imageinfo_undobuffer_paste( undo ); /* Junk the undo action we have performed. */ imageinfo->undo = g_slist_remove( imageinfo->undo, undo ); imageinfo_undobuffer_free( undo ); /* Trim undo buffer. */ imageinfo_undo_trim( imageinfo ); /* Update menus. */ imageinfo_undo_changed( imageinfo ); return( TRUE ); } /* Redo a paint action, if possible. */ gboolean imageinfo_redo( Imageinfo *imageinfo ) { Undobuffer *undo; /* Find the redo action we are to perform. */ if( !imageinfo->redo ) return( TRUE ); undo = (Undobuffer *) imageinfo->redo->data; /* We are going to redo the first action on the redo list. We must * save the area under the first redo action to the undo list. Save * even if undo is disabled. */ if( !imageinfo_undo_add( imageinfo, &undo->bbox ) ) return( FALSE ); /* Add this new buffer to the undo list. */ imageinfo->undo = g_slist_prepend( imageinfo->undo, imageinfo->cundo ); imageinfo->cundo = NULL; /* Paint redo back. */ imageinfo_undobuffer_paste( undo ); /* We can junk the head of the undo list now. */ imageinfo->redo = g_slist_remove( imageinfo->redo, undo ); imageinfo_undobuffer_free( undo ); /* Trim undo buffer. */ imageinfo_undo_trim( imageinfo ); /* Update menus. */ imageinfo_undo_changed( imageinfo ); return( TRUE ); } void imageinfo_undo_clear( Imageinfo *imageinfo ) { imageinfo_undo_free( imageinfo ); imageinfo_undo_changed( imageinfo ); } static int imageinfo_draw_point_cb( IMAGE *im, int x, int y, void *a, void *b, void *c ) { IMAGE *mask = (IMAGE *) a; PEL *ink = (PEL *) b; return( im_draw_mask( im, mask, x - mask->Xsize / 2, y - mask->Ysize / 2, ink ) ); } /* Draw a line. */ gboolean imageinfo_paint_line( Imageinfo *imageinfo, Imageinfo *ink, Imageinfo *mask, int x1, int y1, int x2, int y2 ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); IMAGE *ink_im = imageinfo_get( FALSE, ink ); IMAGE *mask_im = imageinfo_get( FALSE, mask ); PEL *data = (PEL *) ink_im->data; Rect dirty, p1, p2, image, clipped; p1.width = mask_im->Xsize; p1.height = mask_im->Ysize; p1.left = x1 - mask_im->Xsize / 2; p1.top = y1 - mask_im->Ysize / 2; p2.width = mask_im->Xsize; p2.height = mask_im->Ysize; p2.left = x2 - mask_im->Xsize / 2; p2.top = y2 - mask_im->Ysize / 2; im_rect_unionrect( &p1, &p2, &dirty ); image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( &dirty, &image, &clipped ); if( im_rect_isempty( &clipped ) ) return( TRUE ); if( !imageinfo_undo_add( imageinfo, &clipped ) ) return( FALSE ); if( im_draw_line_user( im, x1, y1, x2, y2, (VipsPlotFn) imageinfo_draw_point_cb, mask_im, data, NULL ) ) { error_vips_all(); return( FALSE ); } imageinfo_area_painted( imageinfo, &dirty ); return( TRUE ); } /* Smudge a line. */ gboolean imageinfo_paint_smudge( Imageinfo *imageinfo, Rect *oper, int x1, int y1, int x2, int y2 ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); Rect p1, p2, dirty; /* Calculate bounding box for smudge. */ p1 = *oper; p1.left += x1; p1.top += y1; p2 = *oper; p2.left += x2; p2.top += y2; im_rect_unionrect( &p1, &p2, &dirty ); if( !imageinfo_undo_add( imageinfo, &dirty ) ) return( FALSE ); /* Smudge line connecting old and new points. */ if( im_draw_line_user( im, x1, y1, x2, y2, (VipsPlotFn) im_smudge, oper, NULL, NULL ) ) { error_vips_all(); return( FALSE ); } imageinfo_area_painted( imageinfo, &dirty ); return( TRUE ); } /* Flood an area. */ gboolean imageinfo_paint_flood( Imageinfo *imageinfo, Imageinfo *ink, int x, int y, gboolean blob ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); IMAGE *ink_im = imageinfo_get( FALSE, ink ); PEL *data = (PEL *) ink_im->data; Rect dirty; int result; /* Save undo area. We have to save the entire image since we don't know * how much the flood will change :( */ dirty.left = 0; dirty.top = 0; dirty.width = im->Xsize; dirty.height = im->Ysize; if( !imageinfo_undo_add( imageinfo, &dirty ) ) return( FALSE ); /* Flood! */ if( blob ) result = im_flood_blob( im, x, y, data, &dirty ); else result = im_flood( im, x, y, data, &dirty ); if( result ) { error_vips_all(); return( FALSE ); } imageinfo_area_painted( imageinfo, &dirty ); return( TRUE ); } gboolean imageinfo_paint_dropper( Imageinfo *imageinfo, Imageinfo *ink, int x, int y ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); IMAGE *ink_im = imageinfo_get( FALSE, ink ); PEL *data = (PEL *) ink_im->data; Rect dirty; if( im_readpoint( im, x, y, data ) ) { error_vips_all(); return( FALSE ); } im_invalidate( ink_im ); dirty.left = 0; dirty.top = 0; dirty.width = ink_im->Xsize; dirty.height = ink_im->Ysize; imageinfo_area_painted( ink, &dirty ); return( TRUE ); } /* Fill a rect. */ gboolean imageinfo_paint_rect( Imageinfo *imageinfo, Imageinfo *ink, Rect *area ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); IMAGE *ink_im = imageinfo_get( FALSE, ink ); PEL *data = (PEL *) ink_im->data; if( !imageinfo_undo_add( imageinfo, area ) ) return( FALSE ); if( im_draw_rect( im, area->left, area->top, area->width, area->height, 1, data ) ) { error_vips_all(); return( FALSE ); } imageinfo_area_painted( imageinfo, area ); return( TRUE ); } /* Paint text into imageinfo, return width/height in tarea. */ gboolean imageinfo_paint_text( Imageinfo *imageinfo, const char *font_name, const char *text, Rect *tarea ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); if( im_text( im, text, font_name, 0, 0, get_dpi() ) ) { error_top( _( "Unable to paint text." ) ); error_sub( _( "Unable to paint text \"%s\" in font \"%s\"." ), text, font_name ); error_vips(); return( FALSE ); } tarea->left = 0; tarea->top = 0; tarea->width = im->Xsize; tarea->height = im->Ysize; return( TRUE ); } /* Draw a nib mask. Radius 0 means a single-pixel mask. */ gboolean imageinfo_paint_nib( Imageinfo *imageinfo, int radius ) { static PEL ink[1] = { 255 }; IMAGE *im = imageinfo_get( FALSE, imageinfo ); if( radius ) { int r2 = radius * 2; IMAGE *t; if( !(t = im_open( "imageinfo_paint_nib", "p" )) ) { error_vips(); return( FALSE ); } if( im_black( t, 2 * (r2 + 1), 2 * (r2 + 1), 1 ) || im_draw_circle( t, r2, r2, r2, 1, ink ) || im_shrink( t, im, 2, 2 ) ) { im_close( t ); error_vips(); return( FALSE ); } im_close( t ); } else { if( im_black( im, 1, 1, 1 ) || im_draw_circle( im, 0, 0, 0, 1, ink ) ) return( FALSE ); } return( TRUE ); } /* Paint a mask. */ gboolean imageinfo_paint_mask( Imageinfo *imageinfo, Imageinfo *ink, Imageinfo *mask, int x, int y ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); IMAGE *ink_im = imageinfo_get( FALSE, ink ); IMAGE *mask_im = imageinfo_get( FALSE, mask ); Rect dirty, image, clipped; dirty.left = x; dirty.top = y; dirty.width = mask_im->Xsize; dirty.height = mask_im->Ysize; image.left = 0; image.top = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( &dirty, &image, &clipped ); if( im_rect_isempty( &clipped ) ) return( TRUE ); if( !imageinfo_undo_add( imageinfo, &clipped ) ) return( FALSE ); if( im_plotmask( im, 0, 0, (PEL *) ink_im->data, (PEL *) mask_im->data, &dirty ) ) { error_vips_all(); return( FALSE ); } imageinfo_area_painted( imageinfo, &dirty ); return( TRUE ); } /* Print a pixel. Output has to be parseable by imageinfo_from_text(). */ void imageinfo_to_text( Imageinfo *imageinfo, VipsBuf *buf ) { IMAGE *im = imageinfo_get( FALSE, imageinfo ); PEL *p = (PEL *) im->data; int i; #define PRINT_INT( T, I ) vips_buf_appendf( buf, "%d", ((T *)p)[I] ); #define PRINT_FLOAT( T, I ) vips_buf_appendg( buf, ((T *)p)[I] ); for( i = 0; i < im->Bands; i++ ) { if( i ) vips_buf_appends( buf, ", " ); switch( im->BandFmt ) { case IM_BANDFMT_UCHAR: PRINT_INT( unsigned char, i ); break; case IM_BANDFMT_CHAR: PRINT_INT( char, i ); break; case IM_BANDFMT_USHORT: PRINT_INT( unsigned short, i ); break; case IM_BANDFMT_SHORT: PRINT_INT( short, i ); break; case IM_BANDFMT_UINT: PRINT_INT( unsigned int, i ); break; case IM_BANDFMT_INT: PRINT_INT( int, i ); break; case IM_BANDFMT_FLOAT: PRINT_FLOAT( float, i ); break; case IM_BANDFMT_COMPLEX: vips_buf_appends( buf, "(" ); PRINT_FLOAT( float, (i << 1) ); vips_buf_appends( buf, ", " ); PRINT_FLOAT( float, (i << 1) + 1 ); vips_buf_appends( buf, ")" ); break; case IM_BANDFMT_DOUBLE: PRINT_FLOAT( double, i ); break; case IM_BANDFMT_DPCOMPLEX: vips_buf_appends( buf, "(" ); PRINT_FLOAT( double, i << 1 ); vips_buf_appends( buf, ", " ); PRINT_FLOAT( double, (i << 1) + 1 ); vips_buf_appends( buf, ")" ); break; default: vips_buf_appends( buf, "???" ); break; } } } /* Set band i to value. */ static void imageinfo_from_text_band( Imageinfo *imageinfo, int i, double re, double im ) { IMAGE *image = imageinfo_get( FALSE, imageinfo ); PEL *p = (PEL *) image->data; double mod = sqrt( re*re + im*im ); if( i < 0 || i >= image->Bands ) return; #define SET_INT( T, I, X ) (((T *)p)[I] = (T) IM_RINT(X)) #define SET_FLOAT( T, I, X ) (((T *)p)[I] = (T) (X)) switch( image->BandFmt ) { case IM_BANDFMT_UCHAR: SET_INT( unsigned char, i, mod ); break; case IM_BANDFMT_CHAR: SET_INT( char, i, mod ); break; case IM_BANDFMT_USHORT: SET_INT( unsigned short, i, mod ); break; case IM_BANDFMT_SHORT: SET_INT( short, i, mod ); break; case IM_BANDFMT_UINT: SET_INT( unsigned int, i, mod ); break; case IM_BANDFMT_INT: SET_INT( int, i, mod ); break; case IM_BANDFMT_FLOAT: SET_FLOAT( float, i, mod ); break; case IM_BANDFMT_COMPLEX: SET_FLOAT( float, (i << 1), re ); SET_FLOAT( float, (i << 1) + 1, im ); break; case IM_BANDFMT_DOUBLE: SET_FLOAT( double, i, mod ); break; case IM_BANDFMT_DPCOMPLEX: SET_FLOAT( double, i << 1, re ); SET_FLOAT( double, (i << 1) + 1, im ); break; default: break; } } /* Parse a string to an imageinfo. * Strings are from imageinfo_to_text(), ie. of the form: * * 50, 0, 0 * (12,13), (14,15) * */ gboolean imageinfo_from_text( Imageinfo *imageinfo, const char *text ) { char buf[MAX_LINELENGTH]; char *p; int i; Rect dirty; #ifdef DEBUG_RGB printf( "imageinfo_from_text: in: \"\%s\"\n", text ); #endif /*DEBUG_RGB*/ im_strncpy( buf, text, MAX_LINELENGTH ); for( i = 0, p = buf; p += strspn( p, WHITESPACE ), *p; i++ ) { double re, im; if( p[0] == '(' ) { /* Complex constant. */ re = g_ascii_strtod( p + 1, NULL ); p = break_token( p, "," ); im = g_ascii_strtod( p, NULL ); p = break_token( p, ")" ); } else { /* Real constant. */ re = g_ascii_strtod( p, NULL ); im = 0; } p = break_token( p, "," ); imageinfo_from_text_band( imageinfo, i, re, im ); } #ifdef DEBUG_RGB { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); printf( "imageinfo_from_text: out: " ); imageinfo_to_text( imageinfo, &buf ); printf( "%s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_RGB*/ dirty.left = 0; dirty.top = 0; dirty.width = 1; dirty.height = 1; imageinfo_area_painted( imageinfo, &dirty ); return( TRUE ); } /* Get the image as display RGB in rgb[0-2]. */ void imageinfo_to_rgb( Imageinfo *imageinfo, double *rgb ) { Conversion *conv; Rect area; PEL *p; int i; #ifdef DEBUG_RGB { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); printf( "imageinfo_to_rgb: in: " ); imageinfo_to_text( imageinfo, &buf ); printf( "%s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_RGB*/ /* Make a temporary conv ... we hold the ref. */ conv = conversion_new( NULL ); conversion_set_synchronous( conv, TRUE ); conversion_set_image( conv, imageinfo ); g_object_ref( G_OBJECT( conv ) ); iobject_sink( IOBJECT( conv ) ); area.left = 0; area.top = 0; area.width = 1; area.height = 1; if( im_prepare( conv->ireg, &area ) ) { UNREF( conv ); return; } p = (PEL *) IM_REGION_ADDR( conv->ireg, area.left, area.top ); if( imageinfo->im->Bands < 3 ) for( i = 0; i < 3; i++ ) rgb[i] = p[0] / 255.0; else for( i = 0; i < 3; i++ ) rgb[i] = p[i] / 255.0; #ifdef DEBUG_RGB printf( "imageinfo_to_rgb: out: r = %g, g = %g, b = %g\n", rgb[0], rgb[1], rgb[2] ); #endif /*DEBUG_RGB*/ UNREF( conv ); } /* Try to overwrite an imageinfo with a display RGB colour. */ void imageinfo_from_rgb( Imageinfo *imageinfo, double *rgb ) { Imageinfogroup *imageinfogroup = IMAGEINFOGROUP( ICONTAINER( imageinfo )->parent ); IMAGE *im = imageinfo_get( FALSE, imageinfo ); Imageinfo *in, *out; IMAGE *t1, *t2; int i; Rect dirty; /* Interchange format is sRGB. FIXME ... should let other displays be used here, see ../scraps/calibrate.[hc] */ struct im_col_display *display = im_col_displays( 7 ); #ifdef DEBUG_RGB printf( "imageinfo_from_rgb: in: r = %g, g = %g, b = %g\n", rgb[0], rgb[1], rgb[2] ); #endif /*DEBUG_RGB*/ /* Make 1 pixel images for conversion. */ in = imageinfo_new_temp( imageinfogroup, reduce_context->heap, NULL, "t" ); out = imageinfo_new_temp( imageinfogroup, reduce_context->heap, NULL, "t" ); if( !in || !out ) return; if( !(t1 = im_open_local( out->im, "imageinfo_from_rgb:1", "t" )) || !(t2 = im_open_local( out->im, "imageinfo_from_rgb:1", "t" )) ) return; /* Fill in with rgb. */ im_initdesc( in->im, 1, 1, 3, IM_BBITS_BYTE, IM_BANDFMT_UCHAR, IM_CODING_NONE, IM_TYPE_sRGB, 1.0, 1.0, 0, 0 ); if( im_setupout( in->im ) ) return; for( i = 0; i < 3; i++ ) ((PEL *) in->im->data)[i] = IM_RINT( rgb[i] * 255.0 ); /* To imageinfo->type. Make sure we get a float ... except for LABQ * and RAD. */ if( im->Coding == IM_CODING_LABQ ) { if( im_disp2Lab( in->im, t1, display ) || im_Lab2LabQ( t1, out->im ) ) return; } else if( im->Coding == IM_CODING_RAD ) { if( im_disp2XYZ( in->im, t1, display ) || im_float2rad( t1, out->im ) ) return; } else if( im->Coding == IM_CODING_NONE ) { switch( im->Type ) { case IM_TYPE_XYZ: if( im_disp2XYZ( in->im, out->im, display ) ) return; break; case IM_TYPE_YXY: if( im_disp2XYZ( in->im, t1, display ) || im_XYZ2Yxy( t1, out->im ) ) return; break; case IM_TYPE_LAB: if( im_disp2Lab( in->im, out->im, display ) ) return; break; case IM_TYPE_LCH: if( im_disp2Lab( in->im, t1, display ) || im_Lab2LCh( t1, out->im ) ) return; break; case IM_TYPE_UCS: if( im_disp2Lab( in->im, t1, display ) || im_Lab2LCh( t1, t2 ) || im_LCh2UCS( t2, out->im ) ) return; break; case IM_TYPE_RGB16: case IM_TYPE_GREY16: if( im_lintra( 1.0 / 256.0, in->im, 0.0, out->im ) ) return; break; case IM_TYPE_RGB: case IM_TYPE_sRGB: default: if( im_clip2fmt( in->im, out->im, IM_BANDFMT_FLOAT ) ) return; break; } } #define SET( TYPE, i ) ((TYPE *) im->data)[i] = ((float *) out->im->data)[i]; /* Now ... overwrite imageinfo. */ if( im->Coding == IM_CODING_LABQ || im->Coding == IM_CODING_RAD ) { for( i = 0; i < im->Bands; i++ ) ((PEL *) im->data)[i] = ((PEL *) out->im->data)[i]; } else { for( i = 0; i < im->Bands; i++ ) switch( im->BandFmt ) { case IM_BANDFMT_UCHAR: SET( unsigned char, i ); break; case IM_BANDFMT_CHAR: SET( signed char, i ); break; case IM_BANDFMT_USHORT: SET( unsigned short, i ); break; case IM_BANDFMT_SHORT: SET( signed short, i ); break; case IM_BANDFMT_UINT: SET( unsigned int, i ); break; case IM_BANDFMT_INT: SET( signed int, i ); break; case IM_BANDFMT_FLOAT: SET( float, i ); break; case IM_BANDFMT_DOUBLE: SET( double, i ); break; case IM_BANDFMT_COMPLEX: SET( float, i * 2 ); SET( float, i * 2 + 1 ); break; case IM_BANDFMT_DPCOMPLEX: SET( double, i * 2 ); SET( double, i * 2 + 1 ); break; default: g_assert( FALSE ); } } im_invalidate( im ); #ifdef DEBUG_RGB { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); printf( "imageinfo_from_rgb: out: " ); imageinfo_to_text( imageinfo, &buf ); printf( "%s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_RGB*/ dirty.left = 0; dirty.top = 0; dirty.width = 1; dirty.height = 1; imageinfo_area_painted( imageinfo, &dirty ); } /* Widgets for colour edit. */ typedef struct _ColourEdit { iDialog *idlg; Imageinfo *imageinfo; GtkWidget *colour_widget; } ColourEdit; /* Done button hit. */ static void imageinfo_colour_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { ColourEdit *eds = (ColourEdit *) client; Imageinfo *imageinfo = eds->imageinfo; double rgb[4]; gtk_color_selection_get_color( GTK_COLOR_SELECTION( eds->colour_widget ), rgb ); /* This will emit "area_painted" on our imageinfo. */ imageinfo_from_rgb( imageinfo, rgb ); nfn( sys, IWINDOW_YES ); } /* Build the insides of colour edit. */ static void imageinfo_colour_buildedit( iDialog *idlg, GtkWidget *work, ColourEdit *eds ) { Imageinfo *imageinfo = eds->imageinfo; double rgb[4]; eds->colour_widget = gtk_color_selection_new(); gtk_color_selection_set_has_opacity_control( GTK_COLOR_SELECTION( eds->colour_widget ), FALSE ); imageinfo_to_rgb( imageinfo, rgb ); gtk_color_selection_set_color( GTK_COLOR_SELECTION( eds->colour_widget ), rgb ); gtk_box_pack_start( GTK_BOX( work ), eds->colour_widget, TRUE, TRUE, 2 ); gtk_widget_show_all( work ); } void imageinfo_colour_edit( GtkWidget *parent, Imageinfo *imageinfo ) { ColourEdit *eds = INEW( NULL, ColourEdit ); GtkWidget *idlg; eds->imageinfo = imageinfo; idlg = idialog_new(); iwindow_set_title( IWINDOW( idlg ), "Edit Colour" ); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) imageinfo_colour_buildedit, eds, NULL, NULL ); idialog_set_callbacks( IDIALOG( idlg ), iwindow_true_cb, NULL, idialog_free_client, eds ); idialog_add_ok( IDIALOG( idlg ), imageinfo_colour_done_cb, "Set Colour" ); iwindow_set_parent( IWINDOW( idlg ), parent ); idialog_set_iobject( IDIALOG( idlg ), IOBJECT( imageinfo ) ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); } nip2-8.7.1/src/expr.c0000644000175000017500000003415313351443023011235 00000000000000/* Expressions! */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Trace error_set()/_clear(). #define DEBUG_ERROR */ /* Trace expr_clone() #define DEBUG_CLONE */ /* #define DEBUG */ #include "ip.h" /* Our signals. */ enum { SIG_NEW_VALUE, /* new value for root */ SIG_LAST }; static iContainerClass *parent_class = NULL; static guint expr_signals[SIG_LAST] = { 0 }; /* Set of expressions containing errors. */ GSList *expr_error_all = NULL; void * expr_error_print( Expr *expr, VipsBuf *buf ) { g_assert( expr->err ); vips_buf_appendf( buf, _( "error in \"%s\"" ), IOBJECT( expr->sym )->name ); if( expr->sym->tool ) tool_error( expr->sym->tool, buf ); else if( expr->row ) { Workspace *ws = expr->row->ws; Workspacegroup *wsg = workspace_get_workspacegroup( ws ); vips_buf_appendf( buf, " (" ); row_qualified_name( expr->row, buf ); if( FILEMODEL( wsg )->filename ) vips_buf_appendf( buf, " - %s", FILEMODEL( wsg )->filename ); vips_buf_appendf( buf, ")" ); } /* Don't show error_top, it's just a summary of error_sub. */ vips_buf_appendf( buf, ": %s\n", expr->error_sub ); return( NULL ); } static Expr * expr_map_all_sub( Symbol *sym, map_expr_fn fn, void *a ) { if( !sym->expr ) return( NULL ); else return( expr_map_all( sym->expr, fn, a ) ); } /* Apply a function to a expr ... and any local exprs. */ Expr * expr_map_all( Expr *expr, map_expr_fn fn, void *a ) { Expr *res; /* Apply to this expr. */ if( (res = fn( expr, a, NULL )) ) return( res ); /* And over any locals. */ if( expr->compile && (res = (Expr *) icontainer_map( ICONTAINER( expr->compile ), (icontainer_map_fn) expr_map_all_sub, (void *) fn, a )) ) return( res ); return( NULL ); } void * expr_name_print( Expr *expr ) { printf( "expr(%p) ", expr ); symbol_name_print( expr->sym ); if( expr->row ) { printf( "(row " ); row_name_print( expr->row ); printf( ") " ); } return( NULL ); } void expr_name( Expr *expr, VipsBuf *buf ) { if( expr->row ) row_qualified_name( expr->row, buf ); else symbol_qualified_name( expr->sym, buf ); } Expr * expr_get_parent( Expr *expr ) { Symbol *sym_parent = symbol_get_parent( expr->sym ); if( !sym_parent ) return( NULL ); return( sym_parent->expr ); } /* Find the enclosing expr in the dynamic scope hierarchy. */ static Expr * expr_get_parent_dynamic( Expr *expr ) { Row *row; if( !expr->row ) return( expr_get_parent( expr ) ); else if( (row = HEAPMODEL( expr->row )->row) ) /* Enclosing row expr. */ return( row->expr ); else { /* Enclosing workspace expr. */ Workspace *ws = expr->row->top_col->ws; return( ws->sym->expr ); } } /* Look back up to find the root expr. */ Expr * expr_get_root( Expr *expr ) { if( is_top( expr->sym ) ) return( expr ); else return( expr_get_root( expr_get_parent( expr ) ) ); } /* Look back up to find the root expr using the dynamic hierarchy (if it's * there). */ Expr * expr_get_root_dynamic( Expr *expr ) { Expr *parent; if( is_top( expr->sym ) ) return( expr ); else if( expr->row && expr->row->top_row && expr->row->top_row->expr ) return( expr->row->top_row->expr ); else if( (parent = expr_get_parent_dynamic( expr )) ) return( expr_get_root_dynamic( parent ) ); else return( NULL ); } /* Is an expr part of a row, including enclosing exprs. * * For example, row A1 could be "[x::x<-A2]", that would be expanded to * something like * "$lcomp0 {$lcomp0 = foldr $f0 [] A2 {$f0 x $sofar = x : $sofar}}" * Now, row A1 depends on A2, but expr A1 will not ... it's $lcomp0, the local * expr of A1, that will get called for expr_dirty. * * Return NULL for expr is not a row and has no enclosing rows. */ static Row * expr_get_row( Expr *expr ) { if( expr->row ) return( expr->row ); else if( is_top( expr->sym ) ) return( NULL ); else return( expr_get_row( expr_get_parent( expr ) ) ); } void expr_new_value( Expr *expr ) { #ifdef DEBUG { PElement *root = &expr->root; printf( "expr_new_value: " ); symbol_name_print( expr->sym ); printf( ": " ); graph_pointer( root ); } #endif /*DEBUG*/ g_signal_emit( G_OBJECT( expr ), expr_signals[SIG_NEW_VALUE], 0 ); } /* An expr has lost a value. */ void expr_value_destroy( Expr *expr ) { /* Break ImageInfo link (if any). */ if( expr->imageinfo ) imageinfo_expr_remove( expr, expr->imageinfo ); } /* Clean up an expr, ready to have a new def parsed into it. */ void * expr_strip( Expr *expr ) { expr_error_clear( expr ); /* Break top links we're part of. */ if( slist_map( expr->static_links, (SListMapFn) link_expr_destroy, NULL ) ) return( expr ); if( slist_map( expr->dynamic_links, (SListMapFn) link_expr_destroy, NULL ) ) return( expr ); g_assert( !expr->static_links ); g_assert( !expr->dynamic_links ); /* Junk error stuff. */ IM_FREE( expr->error_top ); IM_FREE( expr->error_sub ); /* Unref the compile. */ if( expr->compile ) (void) compile_expr_link_break( expr->compile, expr ); return( NULL ); } static void expr_dispose( GObject *gobject ) { Expr *expr = EXPR( gobject ); Symbol *sym = expr->sym; #ifdef DEBUG printf( "expr_dispose: " ); expr_name_print( expr ); printf( "\n" ); #endif /*DEBUG*/ expr_strip( expr ); /* Break the value link. */ expr_value_destroy( expr ); /* Unlink from symbol. */ if( sym->expr == expr ) sym->expr = NULL; if( expr->row ) { Row *row = expr->row; /* If this is the sym for a top row, kill the row too. * Otherwise just break the link and wait for the next row * refresh to do the kill for us. */ if( row == row->top_row ) { IDESTROY( row ); } else { row->expr = NULL; row->sym = NULL; expr->row = NULL; /* Make sure we will re-parse and compile any text * with this sym that might have been modified from * the default. */ if( row->child_rhs && row->child_rhs->itext ) { iText *itext = ITEXT( row->child_rhs->itext ); if( itext->edited ) heapmodel_set_modified( HEAPMODEL( itext ), TRUE ); } } } G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void expr_info( iObject *iobject, VipsBuf *buf ) { Expr *expr = EXPR( iobject ); if( expr->err ) { vips_buf_appends( buf, _( "Error" ) ); vips_buf_appendf( buf, ": %s\n%s\n", expr->error_top, expr->error_sub ); } } static void expr_real_new_value( Expr *expr ) { PElement *root = &expr->root; expr_value_destroy( expr ); if( PEISIMAGE( root ) && PEGETII( root ) ) imageinfo_expr_add( PEGETII( root ), expr ); /* If this is the main expr for this symbol, signal new value there * too. */ if( expr->sym->expr == expr ) symbol_new_value( expr->sym ); } static void expr_class_init( ExprClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ expr_signals[SIG_NEW_VALUE] = g_signal_new( "new_value", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ExprClass, new_value ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); /* Init methods. */ gobject_class->dispose = expr_dispose; iobject_class->info = expr_info; class->new_value = expr_real_new_value; /* Static init. */ } static void expr_init( Expr *expr ) { expr->sym = NULL; expr->row = NULL; expr->compile = NULL; expr->static_links = NULL; expr->dynamic_links = NULL; expr->imageinfo = NULL; expr->err = FALSE; expr->error_top = NULL; expr->error_sub = NULL; } GType expr_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ExprClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) expr_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Expr ), 32, /* n_preallocs */ (GInstanceInitFunc) expr_init, }; type = g_type_register_static( TYPE_ICONTAINER, "Expr", &info, 0 ); } return( type ); } Expr * expr_new( Symbol *sym ) { Expr *expr; expr = EXPR( g_object_new( TYPE_EXPR, NULL ) ); expr->sym = sym; PEPOINTE( &expr->root, &sym->base ); icontainer_child_add( ICONTAINER( sym ), ICONTAINER( expr ), -1 ); #ifdef DEBUG printf( "expr_new: " ); expr_name_print( expr ); printf( "\n" ); #endif /*DEBUG*/ return( expr ); } /* Clone an existing expr. */ Expr * expr_clone( Symbol *sym ) { Expr *expr; if( sym->expr && sym->expr->compile ) { /* Make a new expr, share the compile. */ expr = expr_new( sym ); compile_expr_link_make( sym->expr->compile, expr ); } else { /* No existing expr to copy, make a bare one for the * row, at the same scope level as sym. */ expr = expr_new( sym ); } return( expr ); } /* Mark an expression as containing an error, save the error buffers. */ void * expr_error_set( Expr *expr ) { /* Was not in error? Add to error set. */ if( !expr->err ) { #ifdef DEBUG_ERROR printf( "expr_error_set: error in " ); symbol_name_print( expr->sym ); printf( ": %s %s\n", error_get_top(), error_get_sub() ); #endif /*DEBUG_ERROR*/ IM_SETSTR( expr->error_top, error_get_top() ); IM_SETSTR( expr->error_sub, error_get_sub() ); /* Zap the value of the expr ... it may contain pointers to * dead stuff. */ PEPUTP( &expr->root, ELEMENT_NOVAL, (void *) 99 ); expr_error_all = g_slist_prepend( expr_error_all, expr ); expr->err = TRUE; if( expr->row ) row_error_set( expr->row ); /* If this is the value of a top-level sym, note state * change on symbol. */ if( is_top( expr->sym ) && expr->sym->expr == expr ) symbol_state_change( expr->sym ); } return( NULL ); } /* Extract the error from an expression. */ void expr_error_get( Expr *expr ) { if( !expr->err ) error_clear(); else { g_assert( expr->error_top ); g_assert( expr->error_sub ); error_top( "%s", expr->error_top ); error_sub( "%s", expr->error_sub ); } } /* Clear error state. */ void expr_error_clear( Expr *expr ) { if( expr->err ) { #ifdef DEBUG_ERROR printf( "expr_error_clear: " ); symbol_name_print( expr->sym ); printf( "\n" ); #endif /*DEBUG_ERROR*/ expr->err = FALSE; expr_error_all = g_slist_remove( expr_error_all, expr ); if( expr->row ) row_error_clear( expr->row ); if( is_top( expr->sym ) && expr->sym->expr == expr ) symbol_state_change( expr->sym ); } } /* Mark an expr dirty. * * Two cases: if expr has a row, this is part of a display. Use the row * stuff to mark this expr dirty. Then use symbol_dirty() to mark on from the * root of this row. * * Case two: this must be an expr inside a top-level ... just * symbol_dirty() on from that top level. * * FIXME ... we should be able to scrap this expr_get_root() ... we want the * 'parent' field in the Link we are probably being called from. */ void * expr_dirty( Expr *expr, int serial ) { Row *row; #ifdef DEBUG printf( "expr_dirty: " ); symbol_name_print( expr->sym ); printf( "\n" ); #endif /*DEBUG*/ if( (row = expr_get_row( expr )) && row->top_row->sym ) { Symbol *top_sym = row->top_row->sym; row_dirty( row, TRUE ); symbol_dirty( top_sym, serial ); } else symbol_dirty( expr_get_root( expr )->sym, serial ); return( NULL ); } void * expr_dirty_intrans( Expr *expr, int serial ) { if( expr->row && expr->row->top_row->sym ) { row_dirty_intrans( expr->row, TRUE ); symbol_dirty( expr->row->top_row->sym, serial ); } else symbol_dirty_intrans( expr->sym, serial ); return( NULL ); } void expr_tip_sub( Expr *expr, VipsBuf *buf ) { Compile *compile = expr->compile; if( is_top( expr->sym ) ) { vips_buf_appends( buf, _( "top level" ) ); vips_buf_appends( buf, " " ); } if( compile && is_class( compile ) ) { vips_buf_appends( buf, _( "class" ) ); vips_buf_appends( buf, " " ); if( compile->nparam == 0 ) { vips_buf_appends( buf, _( "instance" ) ); vips_buf_appends( buf, " " ); } else { vips_buf_appends( buf, _( "definition" ) ); vips_buf_appends( buf, " " ); } vips_buf_appendf( buf, "\"%s\"", IOBJECT( expr->sym )->name ); } else if( expr->sym->type == SYM_PARAM ) vips_buf_appendf( buf, _( "parameter \"%s\"" ), IOBJECT( expr->sym )->name ); else if( compile ) { if( is_member( expr->sym ) ) { vips_buf_appends( buf, _( "member" ) ); vips_buf_appends( buf, " " ); } if( compile->nparam == 0 ) { vips_buf_appends( buf, _( "value" ) ); vips_buf_appends( buf, " " ); } else { vips_buf_appends( buf, _( "function" ) ); vips_buf_appends( buf, " " ); } vips_buf_appendf( buf, "\"%s\"", IOBJECT( expr->sym )->name ); } if( !is_top( expr->sym ) ) { vips_buf_appends( buf, " " ); vips_buf_appends( buf, _( "of" ) ); vips_buf_appends( buf, " " ); expr_tip_sub( expr_get_parent( expr ), buf ); } } /* Look at an expr, make a tooltip. */ void expr_tip( Expr *expr, VipsBuf *buf ) { expr_name( expr, buf ); vips_buf_appends( buf, ": " ); expr_tip_sub( expr, buf ); } /* Bind unresolved refs in an expr. Bind for every enclosing dynamic scope. */ void expr_resolve( Expr *expr ) { Expr *top = symbol_root->expr; Expr *i; #ifdef DEBUG printf( "expr_resolve: " ); expr_name_print( expr ); printf( "\n" ); #endif /*DEBUG*/ for( i = expr; i != top; i = expr_get_parent_dynamic( i ) ) /* May try to resolve out through a parameter. */ if( i->compile ) compile_resolve_dynamic( expr->compile, i->compile ); } nip2-8.7.1/src/plotwindow.c0000644000175000017500000002361313351443023012464 00000000000000/* a plotpresent / plotmodel in a floating window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static FloatwindowClass *parent_class = NULL; static void plotwindow_destroy( GtkObject *object ) { Plotwindow *plotwindow; g_return_if_fail( object != NULL ); g_return_if_fail( IS_PLOTWINDOW( object ) ); plotwindow = PLOTWINDOW( object ); #ifdef DEBUG printf( "plotwindow_destroy: %p\n", plotwindow ); #endif /*DEBUG*/ /* My instance destroy stuff. */ UNREF( plotwindow->plotmodel ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void plotwindow_class_init( PlotwindowClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = plotwindow_destroy; /* Create signals. */ /* Init methods. */ } static void plotwindow_init( Plotwindow *plotwindow ) { #ifdef DEBUG printf( "plotwindow_init: %p\n", plotwindow ); #endif /*DEBUG*/ plotwindow->plotmodel = NULL; } GtkType plotwindow_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Plotwindow", sizeof( Plotwindow ), sizeof( PlotwindowClass ), (GtkClassInitFunc) plotwindow_class_init, (GtkObjectInitFunc) plotwindow_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_FLOATWINDOW, &info ); } return( type ); } static void plotwindow_refresh_title( Plotwindow *plotwindow ) { Plotmodel *plotmodel = plotwindow->plotmodel; Plot *plot = plotmodel->plot; Row *row = HEAPMODEL( plot )->row; Workspace *ws = row_get_workspace( row ); #ifdef DEBUG printf( "plotwindow_refresh_title\n" ); #endif /*DEBUG*/ /* Can come here during ws destroy. */ if( ws ) { VipsBuf buf; char txt[512]; vips_buf_init_static( &buf, txt, 512 ); row_qualified_name_relative( ws->sym, row, &buf ); iwindow_set_title( IWINDOW( plotwindow ), "%s", vips_buf_all( &buf ) ); } } /* The model has changed ... update our menus and titlebar. */ static void plotwindow_changed_cb( Plotmodel *plotmodel, Plotwindow *plotwindow ) { iWindow *iwnd = IWINDOW( plotwindow ); GtkAction *action; plotwindow_refresh_title( plotwindow ); action = gtk_action_group_get_action( iwnd->action_group, "Status" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), plotmodel->show_status ); } static void plotwindow_mouse_move_cb( Plotpresent *plotpresent, double x, double y, Plotwindow *plotwindow ) { plotstatus_mouse( plotwindow->plotstatus, x, y ); } static void plotwindow_show_status_action_cb( GtkToggleAction *action, Plotwindow *plotwindow ) { plotmodel_set_status( plotwindow->plotmodel, gtk_toggle_action_get_active( action ) ); } static void plotwindow_export_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { #ifdef HAVE_LIBGOFFICE #ifdef HAVE_LIBGSF Filesel *filesel = FILESEL( iwnd ); Plotwindow *plotwindow = (Plotwindow *) client; Plotpresent *plotpresent = plotwindow->plotpresent; GogGraph *ggraph = plotpresent->ggraph; char *filename; char buf[FILENAME_MAX]; char *extension; GOImageFormat format; GsfOutput *output; GError *err = NULL; gboolean result; if( !(filename = filesel_get_filename( filesel )) ) { nfn( sys, IWINDOW_ERROR ); return; } expand_variables( filename, buf ); if( !(output = gsf_output_stdio_new( buf, &err )) ) { error_top( _( "Unable to write." ) ); if( err ) error_sub( "%s", err->message ); IM_FREEF( g_error_free, err ); g_free( filename ); nfn( sys, IWINDOW_ERROR ); return; } if( (extension = strrchr( buf, '.' )) ) extension += 1; else extension = buf; format = go_image_get_format_from_name( extension ); g_free( filename ); result = gog_graph_export_image( ggraph, format, output, 72, 72 ); UNREF( output ); nfn( sys, result ? IWINDOW_YES : IWINDOW_ERROR ); #endif /*HAVE_LIBGSF*/ #endif /*HAVE_LIBGOFFICE*/ } static void plotwindow_export_action_cb( GtkAction *action, Plotwindow *plotwindow ) { Filesel *filesel = FILESEL( filesel_new() ); iwindow_set_title( IWINDOW( filesel ), "%s", _( "Export Plot As" ) ); filesel_set_flags( filesel, TRUE, TRUE ); filesel_set_filetype( filesel, filesel_type_image, IMAGE_FILE_TYPE ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( plotwindow ) ); filesel_set_done( filesel, plotwindow_export_done_cb, plotwindow ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } static GtkToggleActionEntry plotwindow_toggle_actions[] = { { "Status", NULL, N_( "_Status" ), NULL, N_( "Show status bar" ), G_CALLBACK( plotwindow_show_status_action_cb ), TRUE } }; static GtkActionEntry plotwindow_actions[] = { { "Export", GTK_STOCK_SAVE_AS, N_( "Export Plot" ), NULL, N_( "Export plot to file" ), G_CALLBACK( plotwindow_export_action_cb ) } }; static const char *plotwindow_menubar_ui_description = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static void plotwindow_build( Plotwindow *plotwindow, GtkWidget *vbox, Plot *plot ) { iWindow *iwnd = IWINDOW( plotwindow ); GError *error; GtkWidget *mbar; GtkWidget *frame; GList *focus_chain; int w, h; /* Make our model. */ plotwindow->plotmodel = plotmodel_new( plot ); g_object_ref( G_OBJECT( plotwindow->plotmodel ) ); iobject_sink( IOBJECT( plotwindow->plotmodel ) ); g_signal_connect( G_OBJECT( plotwindow->plotmodel ), "changed", G_CALLBACK( plotwindow_changed_cb ), plotwindow ); /* Make main menu bar */ gtk_action_group_add_actions( iwnd->action_group, plotwindow_actions, G_N_ELEMENTS( plotwindow_actions ), GTK_WINDOW( plotwindow ) ); gtk_action_group_add_toggle_actions( iwnd->action_group, plotwindow_toggle_actions, G_N_ELEMENTS( plotwindow_toggle_actions ), GTK_WINDOW( plotwindow ) ); error = NULL; if( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager, plotwindow_menubar_ui_description, -1, &error ) ) { g_message( "building menus failed: %s", error->message ); g_error_free( error ); exit( EXIT_FAILURE ); } mbar = gtk_ui_manager_get_widget( iwnd->ui_manager, "/PlotwindowMenubar" ); gtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 ); gtk_widget_show( mbar ); /* Status bar. Show/hide set on first refresh. */ plotwindow->plotstatus = plotstatus_new( plotwindow->plotmodel ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( plotwindow->plotstatus ), FALSE, FALSE, 0 ); /* Plot area. */ frame = gtk_frame_new( NULL ); gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_OUT ); gtk_widget_show( frame ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 ); #ifdef HAVE_LIBGOFFICE plotwindow->plotpresent = plotpresent_new( plotwindow->plotmodel ); #endif /*HAVE_LIBGOFFICE*/ gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( plotwindow->plotpresent ) ); gtk_widget_show( GTK_WIDGET( plotwindow->plotpresent ) ); g_signal_connect( G_OBJECT( plotwindow->plotpresent ), "mouse_move", G_CALLBACK( plotwindow_mouse_move_cb ), plotwindow ); /* Initial window size. */ if( MODEL( plot )->window_width == -1 ) { w = IM_MIN( IMAGE_WINDOW_WIDTH, 500 ); h = IM_MIN( IMAGE_WINDOW_HEIGHT, 500 ); gtk_window_set_default_size( GTK_WINDOW( plotwindow ), w, h ); } /* Override the focus_chain ... we want the imagedisplay first. */ focus_chain = NULL; focus_chain = g_list_append( focus_chain, plotwindow->plotpresent ); gtk_container_set_focus_chain( GTK_CONTAINER( vbox ), focus_chain ); gtk_widget_grab_focus( GTK_WIDGET( plotwindow->plotpresent ) ); } static void plotwindow_popdown( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Plotwindow *plotwindow = PLOTWINDOW( iwnd ); Plotmodel *plotmodel = plotwindow->plotmodel; Plot *plot = plotmodel->plot; /* We have to note position/size in popdown rather than destroy, since * the widgets have to all still be extant. */ plot->show_status = plotmodel->show_status; nfn( sys, IWINDOW_YES ); } static void plotwindow_link( Plotwindow *plotwindow, Plot *plot, GtkWidget *parent ) { iwindow_set_build( IWINDOW( plotwindow ), (iWindowBuildFn) plotwindow_build, plot, NULL, NULL ); iwindow_set_parent( IWINDOW( plotwindow ), parent ); iwindow_set_popdown( IWINDOW( plotwindow ), plotwindow_popdown, NULL ); floatwindow_link( FLOATWINDOW( plotwindow ), MODEL( plot ) ); iwindow_build( IWINDOW( plotwindow ) ); /* Initial "changed" on the model to get all views to init. */ iobject_changed( IOBJECT( plotwindow->plotmodel ) ); } Plotwindow * plotwindow_new( Plot *plot, GtkWidget *parent ) { Plotwindow *plotwindow = gtk_type_new( TYPE_PLOTWINDOW ); plotwindow_link( plotwindow, plot, parent ); return( plotwindow ); } nip2-8.7.1/src/predicate.h0000644000175000017500000000261413351443023012221 00000000000000/* Declarations for predicate.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ gboolean is_system( Symbol *sym ); gboolean is_separator( Symbol *sym ); gboolean is_member( Symbol *sym ); gboolean is_class( Compile *compile ); gboolean is_super( Symbol *sym ); gboolean is_this( Symbol *sym ); gboolean is_member_enclosing( Compile *compile, Symbol *sym ); gboolean is_top( Symbol *sym ); gboolean is_scope( Symbol *sym ); gboolean is_memberfunc( Compile *compile ); gboolean is_value( Symbol *sym ); gboolean is_ancestor( Symbol *context, Symbol *sym ); gboolean is_menuable( Symbol *sym ); nip2-8.7.1/src/tree.c0000644000175000017500000002337113351443023011216 00000000000000/* Build parse trees. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* Free any stuff attached to a ParseConst. */ void tree_const_destroy( ParseConst *pc ) { if( pc->type == PARSE_CONST_STR ) IM_FREE( pc->val.str ); pc->type = PARSE_CONST_NONE; } void tree_const_copy( ParseConst *from, ParseConst *to ) { *to = *from; if( to->type == PARSE_CONST_STR && to->val.str ) to->val.str = im_strdupn( to->val.str ); } /* Free a parse node. */ void * tree_node_destroy( ParseNode *n ) { switch( n->type ) { case NODE_PATTERN_CLASS: case NODE_TAG: IM_FREE( n->tag ); break; case NODE_CONST: tree_const_destroy( &n->con ); break; case NODE_LISTCONST: case NODE_SUPER: IM_FREEF( g_slist_free, n->elist ); break; case NODE_APPLY: case NODE_CLASS: case NODE_BINOP: case NODE_UOP: case NODE_LEAF: case NODE_GENERATOR: case NODE_NONE: case NODE_COMPOSE: break; default: g_assert( FALSE ); } IM_FREE( n ); return( NULL ); } /* Make an empty parse node. */ static ParseNode * tree_new( Compile *compile ) { ParseNode *no = INEW( NULL, ParseNode ); no->compile = compile; no->type = NODE_NONE; no->biop = BI_NONE; no->uop = UN_NONE; no->arg1 = NULL; no->arg2 = NULL; no->arg3 = NULL; no->leaf = NULL; no->klass = NULL; no->elist = NULL; no->tag = NULL; no->con.type = PARSE_CONST_NONE; no->con.val.str = NULL; compile->treefrag = g_slist_prepend( compile->treefrag, no ); return( no ); } /* Make a binary operator node. */ ParseNode * tree_binop_new( Compile *compile, BinOp op, ParseNode *l, ParseNode *r ) { ParseNode *no = tree_new( compile ); no->type = NODE_BINOP; no->biop = op; no->arg1 = l; no->arg2 = r; return( no ); } /* Make a function compose node. */ ParseNode * tree_compose_new( Compile *compile, ParseNode *f, ParseNode *g ) { ParseNode *no = tree_new( compile ); no->type = NODE_COMPOSE; no->arg1 = f; no->arg2 = g; return( no ); } /* Make a generator node. */ ParseNode * tree_generator_new( Compile *compile, ParseNode *s, ParseNode *n, ParseNode *f ) { ParseNode *no = tree_new( compile ); no->type = NODE_GENERATOR; no->arg1 = s; no->arg2 = n; no->arg3 = f; return( no ); } /* Make an IF node. */ ParseNode * tree_ifelse_new( Compile *compile, ParseNode *c, ParseNode *t, ParseNode *e ) { ParseNode *else_node = tree_lconst_new( compile, e ); ParseNode *then_node = tree_lconst_extend( compile, else_node, t ); ParseNode *if_node = tree_binop_new( compile, BI_IF, c, then_node ); return( if_node ); } /* Make a class node. */ ParseNode * tree_class_new( Compile *compile ) { ParseNode *no = tree_new( compile ); Symbol *this, *super, *name, *cons; g_assert( !compile->is_klass ); g_assert( !compile->this ); g_assert( !compile->super ); no->type = NODE_CLASS; no->klass = compile; /* Make enclosing into a class. */ compile->is_klass = TRUE; /* Add builtin syms. */ this = symbol_new_defining( compile, MEMBER_THIS ); (void) symbol_parameter_builtin_init( this ); compile->this = this; super = symbol_new_defining( compile, MEMBER_SUPER ); (void) symbol_user_init( super ); (void) compile_new_local( super->expr ); symbol_made( super ); compile->super = super; name = symbol_new_defining( compile, MEMBER_NAME ); (void) symbol_parameter_builtin_init( name ); cons = symbol_new_defining( compile, IOBJECT( compile->sym )->name ); (void) symbol_user_init( cons ); (void) compile_new_local( cons->expr ); cons->expr->compile->tree = tree_leafsym_new( compile, compile->sym ); symbol_made( cons ); return( no ); } /* Make a tag node. */ ParseNode * tree_tag_new( Compile *compile, const char *r ) { ParseNode *no = tree_new( compile ); no->type = NODE_TAG; no->tag = im_strdupn( r ); return( no ); } /* Make a unary operator node. */ ParseNode * tree_unop_new( Compile *compile, UnOp op, ParseNode *a ) { ParseNode *no = tree_new( compile ); no->type = NODE_UOP; no->uop = op; no->arg1 = a; return( no ); } ParseNode * tree_leaf_new( Compile *compile, const char *name ) { ParseNode *no = tree_new( compile ); no->type = NODE_LEAF; no->leaf = symbol_new_reference( compile, name ); /* Have we a reference to a ZOMBIE? If yes, we may need to patch this * leaf to point to a new symbol. Add the leaf's pointer to the * refedat list on the ZOMBIE. */ if( no->leaf->type == SYM_ZOMBIE ) (void) symbol_patch_add( (void **) &no->leaf, no->leaf ); return( no ); } /* Make a new leaf node ... except we know the final symbol now. */ ParseNode * tree_leafsym_new( Compile *compile, Symbol *sym ) { ParseNode *no = tree_new( compile ); /* Fill fields. */ no->type = NODE_LEAF; no->leaf = sym; /* Note that this compile refs this sym. */ compile_link_make( compile, sym ); /* Have we a reference to a ZOMBIE? If yes, we may need to patch this * leaf to point to a new symbol. Add the leaf's pointer to the * refedat list on the ZOMBIE. */ if( sym->type == SYM_ZOMBIE ) (void) symbol_patch_add( (void **) &no->leaf, sym ); return( no ); } /* Init a clist. */ ParseNode * tree_lconst_new( Compile *compile, ParseNode *a ) { ParseNode *no = tree_new( compile ); /* Fill fields. */ no->type = NODE_LISTCONST; no->elist = NULL; no->elist = g_slist_prepend( no->elist, a ); return( no ); } /* Extend a clist. */ ParseNode * tree_lconst_extend( Compile *compile, ParseNode *base, ParseNode *new ) { g_assert( base->type == NODE_LISTCONST ); base->elist = g_slist_prepend( base->elist, new ); return( base ); } /* Init a super. */ ParseNode * tree_super_new( Compile *compile ) { ParseNode *no = tree_new( compile ); no->type = NODE_SUPER; return( no ); } /* Extend a super. */ ParseNode * tree_super_extend( Compile *compile, ParseNode *base, ParseNode *new ) { g_assert( base->type == NODE_SUPER ); base->elist = g_slist_append( base->elist, new ); return( base ); } /* Make a new constant node. */ ParseNode * tree_const_new( Compile *compile, ParseConst n ) { ParseNode *no = tree_new( compile ); no->type = NODE_CONST; no->con = n; return( no ); } /* Make a new apply node. */ ParseNode * tree_appl_new( Compile *compile, ParseNode *l, ParseNode *r ) { ParseNode *no = tree_new( compile ); no->type = NODE_APPLY; no->arg1 = l; no->arg2 = r; return( no ); } ParseNode * tree_pattern_class_new( Compile *compile, const char *class_name, ParseNode *l ) { ParseNode *no = tree_new( compile ); no->type = NODE_PATTERN_CLASS; no->arg1 = l; no->tag = im_strdupn( class_name ); return( no ); } ParseNode * tree_map( Compile *compile, tree_map_fn fn, ParseNode *node, void *a, void *b ) { ParseNode *result; GSList *l; g_assert( node ); if( (result = fn( compile, node, a, b )) ) return( result ); switch( node->type ) { case NODE_GENERATOR: if( (result = tree_map( compile, fn, node->arg1, a, b )) ) return( result ); if( node->arg2 && (result = tree_map( compile, fn, node->arg2, a, b )) ) return( result ); if( node->arg3 && (result = tree_map( compile, fn, node->arg3, a, b )) ) return( result ); break; case NODE_APPLY: case NODE_BINOP: case NODE_COMPOSE: if( (result = tree_map( compile, fn, node->arg1, a, b )) || (result = tree_map( compile, fn, node->arg2, a, b )) ) return( result ); break; case NODE_UOP: if( (result = tree_map( compile, fn, node->arg1, a, b )) ) return( result ); break; case NODE_SUPER: case NODE_LISTCONST: for( l = node->elist; l; l = l->next ) { ParseNode *arg = (ParseNode *) l->data; if( (result = tree_map( compile, fn, arg, a, b )) ) return( result ); } break; case NODE_LEAF: case NODE_CLASS: case NODE_TAG: case NODE_CONST: break; case NODE_NONE: default: g_assert( FALSE ); } return( NULL ); } /* Copy a tree to a new context. Make all symbols afresh ... you need to link * after calling this. */ ParseNode * tree_copy( Compile *compile, ParseNode *node ) { ParseNode *copy; GSList *l; g_assert( node ); switch( node->type ) { case NODE_GENERATOR: case NODE_APPLY: case NODE_BINOP: case NODE_COMPOSE: case NODE_UOP: case NODE_TAG: case NODE_CONST: case NODE_PATTERN_CLASS: copy = tree_new( compile ); copy->type = node->type; copy->uop = node->uop; copy->biop = node->biop; if( node->tag ) copy->tag = im_strdupn( node->tag ); tree_const_copy( &node->con, ©->con ); if( node->arg1 ) copy->arg1 = tree_copy( compile, node->arg1 ); if( node->arg2 ) copy->arg2 = tree_copy( compile, node->arg2 ); if( node->arg3 ) copy->arg3 = tree_copy( compile, node->arg3 ); break; case NODE_SUPER: case NODE_LISTCONST: copy = tree_new( compile ); for( l = node->elist; l; l = l->next ) { ParseNode *arg = (ParseNode *) l->data; copy->elist = g_slist_append( copy->elist, tree_copy( compile, arg ) ); } copy->type = node->type; break; case NODE_CLASS: copy = tree_class_new( compile ); break; case NODE_LEAF: copy = tree_leaf_new( compile, IOBJECT( node->leaf )->name ); break; case NODE_NONE: default: copy = NULL; g_assert( FALSE ); } return( copy ); } nip2-8.7.1/src/plotview.c0000644000175000017500000001326713351443023012133 00000000000000/* run the display for a plotview in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_GEO #define DEBUG */ #include "ip.h" #ifdef HAVE_LIBGOFFICE static GraphicviewClass *parent_class = NULL; static void plotview_destroy( GtkObject *object ) { Plotview *plotview; g_return_if_fail( object != NULL ); g_return_if_fail( IS_PLOTVIEW( object ) ); #ifdef DEBUG printf( "plotview_destroy\n" ); #endif /*DEBUG*/ plotview = PLOTVIEW( object ); GOG_UNREF( plotview->gplot ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void plotview_refresh( vObject *vobject ) { Plotview *plotview = PLOTVIEW( vobject ); Plot *plot = PLOT( VOBJECT( plotview )->iobject ); #ifdef DEBUG printf( "plotview_refresh\n" ); #endif /*DEBUG*/ /* Can't refresh before model build. */ if( plot->rows == 0 || plot->columns == 0 ) return; set_gcaption( plotview->label, "%s", NN( IOBJECT( plot )->caption ) ); GOG_UNREF( plotview->gplot ); plotview->gplot = plot_new_gplot( plot ); gog_object_add_by_name( GOG_OBJECT( plotview->gchart ), "Plot", GOG_OBJECT( plotview->gplot ) ); plot_style_thumbnail( plot, plotview->gchart ); gtk_widget_show_all( plotview->canvas ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void plotview_link( View *view, Model *model, View *parent ) { Plotview *plotview = PLOTVIEW( view ); Rowview *rview = ROWVIEW( parent->parent ); VIEW_CLASS( parent_class )->link( view, model, parent ); rowview_menu_attach( rview, GTK_WIDGET( plotview->box ) ); } static void plotview_class_init( PlotviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = plotview_destroy; vobject_class->refresh = plotview_refresh; view_class->link = plotview_link; } static void plotview_tooltip_generate( GtkWidget *widget, VipsBuf *buf, Plotview *plotview ) { Plot *plot = PLOT( VOBJECT( plotview )->iobject ); IMAGE *im; vips_buf_rewind( buf ); vips_buf_appends( buf, vips_buf_all( &plot->caption_buffer ) ); vips_buf_appendf( buf, ", %s, %s", plot_f2c( plot->format ), plot_s2c( plot->style ) ); if( (im = imageinfo_get( FALSE, plot->value.ii )) ) { vips_buf_appends( buf, ", " ); vips_buf_appendi( buf, im ); } } static void plotview_doubleclick_one_cb( GtkWidget *widget, GdkEvent *event, Plotview *plotview ) { Heapmodel *heapmodel = HEAPMODEL( VOBJECT( plotview )->iobject ); Row *row = heapmodel->row; row_select_modifier( row, event->button.state ); } static void plotview_doubleclick_two_cb( GtkWidget *widget, GdkEvent *event, Plotview *plotview ) { Plot *plot = PLOT( VOBJECT( plotview )->iobject ); model_edit( widget, MODEL( plot ) ); } static void plotview_init( Plotview *plotview ) { GtkWidget *eb; #ifdef DEBUG printf( "plotview_init\n" ); #endif /*DEBUG*/ eb = gtk_event_box_new(); gtk_box_pack_start( GTK_BOX( plotview ), eb, FALSE, FALSE, 0 ); gtk_widget_show( eb ); gtk_widget_set_name( eb, "caption_widget" ); set_tooltip_generate( eb, (TooltipGenerateFn) plotview_tooltip_generate, plotview, NULL ); doubleclick_add( eb, FALSE, DOUBLECLICK_FUNC( plotview_doubleclick_one_cb ), plotview, DOUBLECLICK_FUNC( plotview_doubleclick_two_cb ), plotview ); plotview->box = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( eb ), plotview->box ); gtk_widget_show( plotview->box ); plotview->canvas = go_graph_widget_new( NULL ); gtk_box_pack_start( GTK_BOX( plotview->box ), plotview->canvas, FALSE, FALSE, 0 ); plotview->gchart = go_graph_widget_get_chart( GO_GRAPH_WIDGET( plotview->canvas ) ); gtk_widget_set_size_request( GTK_WIDGET( plotview->canvas ), DISPLAY_THUMBNAIL, DISPLAY_THUMBNAIL ); plotview->gplot = NULL; plotview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( plotview->label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( plotview->label ), 2, 0 ); gtk_box_pack_end( GTK_BOX( plotview->box ), GTK_WIDGET( plotview->label ), FALSE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( plotview->label ) ); } GtkType plotview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Plotview", sizeof( Plotview ), sizeof( PlotviewClass ), (GtkClassInitFunc) plotview_class_init, (GtkObjectInitFunc) plotview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( type ); } View * plotview_new( void ) { Plotview *plotview = gtk_type_new( TYPE_PLOTVIEW ); return( VIEW( plotview ) ); } #endif /*HAVE_LIBGOFFICE*/ nip2-8.7.1/src/heap.c0000644000175000017500000015520313351443023011174 00000000000000/* Heap management. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* GC on every alloc too! Extraordinarily slow. Turn on DEBUG_HEAP in ip.h * first. Good for spotting heap pointer errors. #define DEBUG_HEAP_GC */ /* Count GCs and %full, handy for tuning. #define DEBUG_GETMEM */ /* Time each GC, handy for benchmarking. #define DEBUG_GC_TIME */ #include "ip.h" static iObjectClass *parent_class = NULL; static GSList *heap_all = NULL; /* Call a function, passing in a "safe" PElement ... ie. the PElement points * at a fresh element which will be safe from the GC. */ void * heap_safe_pointer( Heap *heap, heap_safe_pointer_fn fn, void *a, void *b, void *c, void *d ) { Element e; PElement pe; void *result; e.type = ELEMENT_NOVAL; e.ele = (void *) 5; PEPOINTE( &pe, &e ); heap_register_element( heap, &e ); result = fn( heap, &pe, a, b, c, d ); heap_unregister_element( heap, &e ); return( result ); } /* Map a function over a piece of graph. */ void * heap_map( HeapNode *hn, heap_map_fn fn, void *a, void *b ) { void *c; if( !hn ) return( NULL ); switch( hn->type ) { case TAG_APPL: case TAG_CONS: if( (c = fn( hn, a, b )) ) return( c ); if( GETLT( hn ) == ELEMENT_NODE && (c = heap_map( GETLEFT( hn ), fn, a, b )) ) return( c ); if( GETRT( hn ) == ELEMENT_NODE && (c = heap_map( GETRIGHT( hn ), fn, a, b )) ) return( c ); return( NULL ); case TAG_REFERENCE: case TAG_COMPLEX: case TAG_GEN: case TAG_FILE: case TAG_CLASS: case TAG_DOUBLE: return( fn( hn, a, b ) ); case TAG_SHARED: if( (c = fn( hn, a, b )) ) return( c ); return( heap_map( GETLEFT( hn ), fn, a, b ) ); case TAG_FREE: default: g_assert( FALSE ); /* Keep gcc happy. */ return( NULL ); } } #ifdef DEBUG_HEAP_GC /* Debugging ... check that all nodes on the free list are TAG_FREE, and that * all other nodes are not TAG_FREE. */ static void heap_check_free( Heap *heap ) { HeapNode *hn; HeapBlock *hb; /* Clear all the DEBUG flags. */ for( hb = heap->hb; hb; hb = hb->next ) { int i; for( i = 0; i < hb->sz; i++ ) { HeapNode *hn = &hb->node[i]; hn->flgs &= FLAG_DEBUG ^ FLAG_ALL; } } /* Check free list. */ for( hn = heap->free; hn; hn = GETLEFT( hn ) ) { g_assert( hn->type == TAG_FREE ); hn->flgs |= FLAG_DEBUG; } /* Check for all non-free. */ for( hb = heap->hb; hb; hb = hb->next ) { int i; for( i = 0; i < hb->sz; i++ ) { HeapNode *hn = &hb->node[i]; g_assert( hn->type != TAG_FREE || (hn->flgs & FLAG_DEBUG) ); } } } #endif /*DEBUG_HEAP_GC*/ #ifdef DEBUG_HEAP_GC static void heap_check_managed( void *key, void *value, Heap *heap ) { /* Validate pointer. */ (void) MANAGED( value ); } #endif /*DEBUG_HEAP_GC*/ /* Test for sanity. */ int heap_sanity( Heap *heap ) { #ifdef DEBUG_HEAP_GC heap_check_free( heap ); heap_gc( heap ); heap_check_free( heap ); g_hash_table_foreach( heap->mtable, (GHFunc) heap_check_managed, heap ); #endif /*DEBUG_HEAP_GC*/ return( 0 ); } /* Debugging ... check that all heaps have been closed, dump any which * haven't. */ void heap_check_all_destroyed( void ) { slist_map( heap_all, (SListMapFn) iobject_dump, NULL ); } /* Free a HeapBlock. */ static void heapblock_free( HeapBlock *hb ) { #ifdef DEBUG printf( "heapblock_free\n" ); #endif /*DEBUG*/ if( hb->next ) heapblock_free( hb->next ); if( hb->node ) IM_FREE( hb->node ); IM_FREE( hb ); } static void heap_set_flush( Heap *heap, gboolean flush ) { heap->flush = flush; } static void heap_dispose_print( void *key, void *value ) { Managed *managed = MANAGED( value ); iobject_print( IOBJECT( managed ) ); } static void heap_dispose( GObject *gobject ) { Heap *heap = HEAP( gobject ); /* Repeatedly close managed objects. Each close can trigger other * closes, so we need to loop until done. */ managed_clear( heap ); heap_set_flush( heap, TRUE ); while( managed_free_unused( heap ) ) ; /* Check all managed objects are dead. */ g_hash_table_foreach( heap->mtable, (GHFunc) heap_dispose_print, NULL ); IM_FREEF( g_source_remove, heap->gc_tid ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void heap_finalize( GObject *gobject ) { Heap *heap = HEAP( gobject ); if( heap->hb ) heapblock_free( heap->hb ); IM_FREEF( g_hash_table_destroy, heap->emark ); IM_FREEF( g_hash_table_destroy, heap->rmark ); IM_FREEF( g_hash_table_destroy, heap->mtable ); heap_all = g_slist_remove( heap_all, heap ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void heap_info( iObject *iobject, VipsBuf *buf ) { Heap *heap = HEAP( iobject ); vips_buf_appendf( buf, "compile = " ); if( heap->compile ) if( heap->compile->sym ) { symbol_qualified_name( heap->compile->sym, buf ); vips_buf_appendf( buf, "(%p) (sym)\n", heap->compile->sym ); } else vips_buf_appendf( buf, "(compile, but no sym)\n" ); else vips_buf_appendf( buf, "(no compile)\n" ); vips_buf_appendf( buf, "mxb (max blocks) = %d\n", heap->mxb ); vips_buf_appendf( buf, "rsz (nodes per block) = %d\n", heap->rsz ); vips_buf_appendf( buf, "nb (number of blocks) = %d\n", heap->nb ); vips_buf_appendf( buf, "emark = %d pointers\n", g_hash_table_size( heap->emark ) ); vips_buf_appendf( buf, "rmark = %d pointers\n", g_hash_table_size( heap->rmark ) ); vips_buf_appendf( buf, "ncells (cells allocated) = %d\n", heap->ncells ); vips_buf_appendf( buf, "nfree (cells free at last GC) = %d\n", heap->nfree ); vips_buf_appendf( buf, "mtable (Managed blocks) = %d pointers\n", g_hash_table_size( heap->mtable ) ); IOBJECT_CLASS( parent_class )->info( iobject, buf ); } /* Empty a heap block. */ static void heapblock_empty( HeapBlock *hb ) { int i; /* Set as empty free-list. */ for( i = 0; i < hb->sz; i++ ) { HeapNode *hn = &hb->node[i]; hn->type = TAG_FREE; hn->flgs = 0; PPUTLEFT( hn, ELEMENT_NODE, hn + 1 ); } PPUTLEFT( &hb->node[hb->sz - 1], ELEMENT_NODE, NULL ); } /* Add another HeapBlock, if we can. */ static gboolean heapblock_create( Heap *heap, int sz ) { HeapBlock *hb; if( heap->nb > heap->mxb ) { heap->mxb = 1 + (heap->max_fn( heap ) / heap->rsz); if( heap->nb > heap->mxb ) /* Hit limit ... caller detects full by ->free becomng * NULL. */ return( TRUE ); } #ifdef DEBUG printf( "heapblock_create: new block, size %d\n", sz ); #endif /*DEBUG*/ if( !(hb = INEW( NULL, HeapBlock )) ) return( FALSE ); hb->heap = heap; hb->next = NULL; hb->node = NULL; hb->sz = sz; if( !(hb->node = IARRAY( NULL, sz, HeapNode )) ) { heapblock_free( hb ); return( FALSE ); } heapblock_empty( hb ); /* Link to existing blocks. */ hb->next = heap->hb; heap->hb = hb; PPUTLEFT( &hb->node[hb->sz - 1], ELEMENT_NODE, heap->free ); heap->free = &hb->node[0]; heap->nb++; return( TRUE ); } static void heap_class_init( HeapClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = heap_dispose; gobject_class->finalize = heap_finalize; iobject_class->info = heap_info; } static void heap_init( Heap *heap ) { heap->compile = NULL; heap->max_fn = NULL; heap->mxb = -1; heap->rsz = 0; heap->nb = 0; heap->hb = NULL; heap->free = NULL; heap->ncells = 0; heap->nfree = 0; heap->serial = 0; heap->filled = FALSE; heap->emark = g_hash_table_new( NULL, g_direct_equal ); heap->rmark = g_hash_table_new( NULL, g_direct_equal ); heap->mtable = g_hash_table_new( NULL, g_direct_equal ); heap->gc_tid = 0; heap->flush = FALSE; heap_all = g_slist_prepend( heap_all, heap ); } GType heap_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( HeapClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) heap_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Heap ), 32, /* n_preallocs */ (GInstanceInitFunc) heap_init, }; type = g_type_register_static( TYPE_IOBJECT, "Heap", &info, 0 ); } return( type ); } static void heap_link( Heap *heap, Compile *compile, heap_max_fn max_fn, int stsz, int rsz ) { heap->compile = compile; heap->max_fn = max_fn; heap->rsz = rsz; (void) heapblock_create( heap, stsz ); if( compile ) iobject_set( IOBJECT( heap ), IOBJECT( compile->sym )->name, NULL ); /* Can now set max blocks. */ heap->mxb = 1 + (heap->max_fn( heap ) / rsz); } /* Create an empty heap. mxsz is maximum size of heap in units of nodes, * stsz is start size, rsz is heap growth unit. */ Heap * heap_new( Compile *compile, heap_max_fn max_fn, int stsz, int rsz ) { Heap *heap; heap = HEAP( g_object_new( TYPE_HEAP, NULL ) ); heap_link( heap, compile, max_fn, stsz, rsz ); return( heap ); } /* Set flags on a heap. */ void heap_set( Heap *heap, NodeFlags setmask ) { HeapBlock *hb; int i; for( hb = heap->hb; hb; hb = hb->next ) for( i = 0; i < hb->sz; i++ ) hb->node[i].flgs |= setmask; } /* Clear flags on a heap. */ void heap_clear( Heap *heap, NodeFlags clearmask ) { HeapBlock *hb; int i; int cmask = clearmask ^ FLAG_ALL; for( hb = heap->hb; hb; hb = hb->next ) for( i = 0; i < hb->sz; i++ ) hb->node[i].flgs &= cmask; } /* Allocate a new serial number for a heap. On return, we guarantee that * heap->serial is a value not used by any nodes in the heap. */ int heap_serial_new( Heap *heap ) { heap->serial += 1; if( heap->serial > FLAG_SERIAL ) { heap->serial = 1; heap_clear( heap, FLAG_SERIAL ); } return( heap->serial ); } /* Mark a tree. Avoid recursion because of the danger of C stack overflow on * large heaps. */ static void heap_mark_tree( Heap *heap, HeapNode *hn ) { GSList *pending = NULL; pending = g_slist_prepend( pending, hn ); while( pending ) { hn = (HeapNode *) pending->data; pending = g_slist_remove( pending, hn ); /* Chase down the LHS of the nodes, add the RHS nodes we pass * to the pending list. */ for(;;) { if( hn->flgs & FLAG_MARK ) break; hn->flgs |= FLAG_MARK; /* Don't modify hn for the do-nothing case: we'll * break on the next loop. */ switch( hn->type ) { case TAG_GEN: case TAG_COMPLEX: case TAG_CLASS: case TAG_APPL: case TAG_CONS: if( GETRT( hn ) == ELEMENT_MANAGED ) managed_mark( (Managed *) GETRIGHT( hn ) ); if( GETLT( hn ) == ELEMENT_MANAGED ) managed_mark( (Managed *) GETLEFT( hn ) ); if( GETRT( hn ) == ELEMENT_NODE ) { if( GETLT( hn ) == ELEMENT_NODE ) { pending = g_slist_prepend( pending, GETRIGHT( hn ) ); hn = GETLEFT( hn ); } else hn = GETRIGHT( hn ); } else if( GETLT( hn ) == ELEMENT_NODE ) hn = GETLEFT( hn ); break; case TAG_FILE: g_assert( GETLT( hn ) == ELEMENT_MANAGED ); managed_mark( (Managed *) GETLEFT( hn ) ); break; case TAG_DOUBLE: break; case TAG_SHARED: case TAG_REFERENCE: if( GETLT( hn ) == ELEMENT_NODE ) hn = GETLEFT( hn ); break; case TAG_FREE: default: g_assert( FALSE ); } } } } /* Mark an element. */ static void * mark_pelement( PElement *base, Heap *heap ) { if( PEISMANAGED( base ) ) managed_mark( MANAGED( PEGETVAL( base ) ) ); else if( PEISNODE( base ) ) heap_mark_tree( heap, PEGETVAL( base ) ); return( NULL ); } /* Mark an element. */ static void mark_element( void *key, void *value, Heap *heap ) { Element *root = (Element *) value; PElement base; PEPOINTE( &base, root ); (void) mark_pelement( &base, heap ); } /* Mark a reduce context ... the heapnodes on the spine stack etc. */ static void * mark_reduce( void *key, void *value, Heap *heap ) { Reduce *rc = (Reduce *) value; int i; #ifdef DEBUG printf( "mark_reduce: marking %d stack elements\n", rc->sp ); #endif /*DEBUG*/ for( i = 0; i < rc->sp; i++ ) heap_mark_tree( heap, rc->nstack[i] ); return( NULL ); } /* Do a garbage collect. */ gboolean heap_gc( Heap *heap ) { HeapBlock *hb; int nfree; int ncells; int nblocks; #ifdef DEBUG_GC_TIME static GTimer *GC_timer = NULL; if( !GC_timer ) GC_timer = g_timer_new(); g_timer_reset( GC_timer ); printf( "heap_gc: starting GC for heap %s\n", IOBJECT( heap )->name ); #endif /*DEBUG_GC_TIME*/ /* Clear marks on managed objects. Nodes should all be clear already. */ managed_clear( heap ); /* All flags should be clear, so just mark. */ g_hash_table_foreach( heap->emark, (GHFunc) mark_element, heap ); g_hash_table_foreach( heap->rmark, (GHFunc) mark_reduce, heap ); /* And sweep up unmarked into new free list. */ heap->free = NULL; ncells = nfree = nblocks = 0; for( hb = heap->hb; hb; hb = hb->next ) { const int sz = hb->sz; int i; for( i = 0; i < sz; i++ ) { HeapNode * const hn = &hb->node[i]; if( !(hn->flgs & FLAG_MARK) ) { hn->type = TAG_FREE; PPUTLEFT( hn, ELEMENT_NODE, heap->free ); #ifdef DEBUG_HEAP_GC /* Not necessary, but may be helpful to zap * any pointer in there. */ PPUTRIGHT( hn, ELEMENT_NODE, NULL ); #endif /*DEBUG_HEAP_GC*/ heap->free = hn; nfree += 1; } hn->flgs &= FLAG_MARK ^ FLAG_ALL; } ncells += hb->sz; nblocks += 1; } heap->ncells = ncells; heap->nfree = nfree; /* Close unused managed objects. It can (potentially) take a couple of * passes through mtable to free everything ... but we'll do more on * the next GC. */ managed_free_unused( heap ); #ifdef DEBUG_GC_TIME printf( "heap_gc: %d cells in %d blocks, %d in use\n", ncells, nblocks, ncells - nfree ); printf( "(GC took %gs)\n", g_timer_elapsed( GC_timer, NULL ) ); #endif /*DEBUG_GC_TIME*/ return( TRUE ); } static gint heap_gc_request_cb( Heap *heap ) { heap->gc_tid = 0; if( !heap_gc( heap ) ) printf( "help! delayed GC failed!\n" ); iobject_changed( IOBJECT( heap ) ); return( FALSE ); } /* Request a delayed garbage collect. */ void heap_gc_request( Heap *heap ) { IM_FREEF( g_source_remove, heap->gc_tid ); heap->gc_tid = g_timeout_add( 1000, (GSourceFunc) heap_gc_request_cb, heap ); } /* Register a pointer into a heap. */ void heap_register_element( Heap *heap, Element *root ) { g_hash_table_insert( heap->emark, root, root ); } /* Unregister a pointer into a heap. */ void heap_unregister_element( Heap *heap, Element *root ) { if( g_hash_table_remove( heap->emark, root ) ) { #ifdef DEBUG printf( "heap_unregister_element: %d pointers\n", g_hash_table_size( heap->emark ) ); #endif } } /* Register a Reduce working on this heap. */ void heap_register_reduce( Heap *heap, Reduce *rc ) { g_hash_table_insert( heap->rmark, rc, rc ); } /* Unregister a reduce context. */ void heap_unregister_reduce( Heap *heap, Reduce *rc ) { g_hash_table_remove( heap->rmark, rc ); } /* Allocate a new HeapNode ... long version. See NEWNODE() macro. */ HeapNode * heap_getmem( Heap *heap ) { HeapNode *hn; int pcused; #ifdef DEBUG_GETMEM static int n_heap_getmem = 0; #endif /*DEBUG_GETMEM*/ /* Easy case ... this should be handled by the NEWNODE macro, but do * it here as well just in case. */ if( heap->free ) { (void) EXTRACTNODE( heap, hn ); return( hn ); } #ifdef DEBUG printf( "heap_getmem: GC on full heap for heap %s\n", IOBJECT( heap )->name ); #endif /*DEBUG*/ /* Try a GC. */ if( !heap_gc( heap ) ) return( NULL ); /* Is heap over x% full? Add another heap block if we can. */ pcused = 100 * (heap->ncells - heap->nfree) / heap->ncells; #ifdef DEBUG_GETMEM n_heap_getmem += 1; printf( "heap_getmem: %d%% (%d)\n", pcused, n_heap_getmem ); #endif /*DEBUG_GETMEM*/ if( pcused > 50 ) { int nblocks = 1 + (heap->ncells - heap->nfree) / heap->rsz; int i; #ifdef DEBUG_GETMEM printf( "heap_getmem: %d more blocks added\n", nblocks ); #endif /*DEBUG_GETMEM*/ for( i = 0; i < nblocks; i++ ) if( !heapblock_create( heap, heap->rsz ) ) return( NULL ); } if( !heap->free ) { error_top( _( "Heap full." ) ); if( heap->compile ) { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); compile_name( heap->compile, &buf ); error_sub( _( "The compile heap for %s has filled. " "Make it smaller and less complicated." ), vips_buf_all( &buf ) ); } else error_sub( _( "The main calculation heap has filled. " "Raise the heap size limit in Preferences." ) ); heap->filled = TRUE; return( NULL ); } (void) EXTRACTNODE( heap, hn ); return( hn ); } gboolean heap_bool_new( Heap *heap, gboolean val, PElement *out ) { PEPUTP( out, ELEMENT_BOOL, val ); return( TRUE ); } /* Write a real to an element. */ gboolean heap_real_new( Heap *heap, double in, PElement *out ) { HeapNode *hn; if( NEWNODE( heap, hn ) ) return( FALSE ); hn->type = TAG_DOUBLE; hn->body.num = in; PEPUTP( out, ELEMENT_NODE, hn ); return( TRUE ); } /* Write an element to an element. */ gboolean heap_element_new( Heap *heap, Element *e, PElement *out ) { PEPUTE( out, e ); return( TRUE ); } /* Make a complex node from two elements. */ gboolean heap_complex_element_new( Heap *heap, PElement *rp, PElement *ip, PElement *out ) { HeapNode *hn; if( NEWNODE( heap, hn ) ) return( FALSE ); hn->type = TAG_COMPLEX; PPUT( hn, PEGETTYPE( rp ), PEGETVAL( rp ), PEGETTYPE( ip ), PEGETVAL( ip ) ); PEPUTP( out, ELEMENT_NODE, hn ); return( TRUE ); } /* Make a complex node. */ gboolean heap_complex_new( Heap *heap, double rp, double ip, PElement *out ) { Element dummy; PElement t; /* Form complex node. */ dummy.type = ELEMENT_NOVAL; dummy.ele = (void *) 6; PEPOINTE( &t, &dummy ); if( !heap_complex_element_new( heap, &t, &t, out ) ) return( FALSE ); /* Install real and imag parts. */ PEPOINTLEFT( PEGETVAL( out ), &t ); if( !heap_real_new( heap, rp, &t ) ) return( FALSE ); PEPOINTRIGHT( PEGETVAL( out ), &t ); if( !heap_real_new( heap, ip, &t ) ) return( FALSE ); return( TRUE ); } /* 'get' a list: move the PE to point at the list. */ gboolean heap_get_list( PElement *list ) { g_assert( PEISLIST( list ) ); if( PEISMANAGEDSTRING( list ) ) { if( !managedstring_get( PEGETMANAGEDSTRING( list ), list ) ) return( FALSE ); } return( TRUE ); } /* Set list to []. */ void heap_list_init( PElement *list ) { PEPUTP( list, ELEMENT_ELIST, NULL ); } /* Add new node to list, point data at new CONS LHS. */ gboolean heap_list_add( Heap *heap, PElement *list, PElement *data ) { HeapNode *hn; /* Build CONS node. */ if( NEWNODE( heap, hn ) ) return( FALSE ); hn->type = TAG_CONS; PPUTLEFT( hn, ELEMENT_NOVAL, (void *) 7 ); PEPUTRIGHT( hn, list ); PEPUTP( list, ELEMENT_NODE, hn ); /* Point data to new LHS. */ PEPOINTLEFT( hn, data ); return( TRUE ); } /* Move list on to the next RHS. list points at [], or pointer to next node. * Used with heap_list_init()/heap_list_add() to build lists. */ gboolean heap_list_next( PElement *list ) { HeapNode *hn = PEGETVAL( list ); if( hn ) { PEPOINTRIGHT( hn, list ); return( TRUE ); } else return( FALSE ); } gboolean heap_list_cat( Reduce *rc, PElement *a, PElement *b, PElement *out ) { PElement list = *out; REDUCE_CATCH_START( FALSE ); reduce_clone_list( rc, a, &list ); PEPUTPE( &list, b ); REDUCE_CATCH_STOP; return( TRUE ); } /* Start off a function application. */ void heap_appl_init( PElement *base, PElement *func ) { PEPUTPE( base, func ); } /* Add a new parameter to a function application. base points at the * function built so far ... update base to point to new node (old base * becomes LHS), return parm pointing to new RHS */ gboolean heap_appl_add( Heap *heap, PElement *base, PElement *parm ) { HeapNode *hn; /* Build appl node. */ if( NEWNODE( heap, hn ) ) return( FALSE ); hn->type = TAG_APPL; PEPUTLEFT( hn, base ); PPUTRIGHT( hn, ELEMENT_ELIST, NULL ); PEPUTP( base, ELEMENT_NODE, hn ); /* Point parm to new RHS. */ PEPOINTRIGHT( hn, parm ); return( TRUE ); } /* Make a lazy file read node. */ gboolean heap_file_new( Heap *heap, const char *filename, PElement *out ) { Managedfile *managedfile; HeapNode *hn; if( !(managedfile = managedfile_new( heap, filename )) ) return( FALSE ); /* Make sure the managedfile survives a GC. */ MANAGED_REF( managedfile ); if( NEWNODE( heap, hn ) ) { MANAGED_UNREF( managedfile ); return( FALSE ); } hn->type = TAG_FILE; PPUT( hn, ELEMENT_MANAGED, managedfile, ELEMENT_ELIST, NULL ); PEPUTP( out, ELEMENT_NODE, hn ); MANAGED_UNREF( managedfile ); return( TRUE ); } /* Make a heap string. */ gboolean heap_string_new( Heap *heap, const char *str, PElement *out ) { PElement list = *out; const int n = strlen( str ); int i; heap_list_init( &list ); for( i = 0; i < n; i++ ) { PElement t; if( !heap_list_add( heap, &list, &t ) ) return( FALSE ); PEPUTP( &t, ELEMENT_CHAR, (int) str[i] ); (void) heap_list_next( &list ); } return( TRUE ); } /* Make a managed string. */ gboolean heap_managedstring_new( Heap *heap, const char *str, PElement *out ) { Managedstring *managedstring; if( strcmp( str, "" ) == 0 ) { PEPUTP( out, ELEMENT_ELIST, NULL ); } else { if( !(managedstring = managedstring_find( heap, str )) ) return( FALSE ); PEPUTP( out, ELEMENT_MANAGED, managedstring ); } return( TRUE ); } /* Make a [[char]]. */ gboolean heap_lstring_new( Heap *heap, GSList *labels, PElement *out ) { PElement list = *out; const int n = g_slist_length( labels ); int i; /* Make first RHS ... the end of the list. */ heap_list_init( &list ); /* Build a CONS node for each element. */ for( i = 0; i < n; i++ ) { PElement t; if( !heap_list_add( heap, &list, &t ) || !heap_managedstring_new( heap, g_slist_nth_data( labels, i ), &t ) ) return( FALSE ); (void) heap_list_next( &list ); } return( TRUE ); } /* Make a realvec. */ gboolean heap_realvec_new( Heap *heap, int n, double *vec, PElement *out ) { PElement list = *out; int i; /* Make first RHS ... the end of the list. */ heap_list_init( &list ); /* Build a CONS node for each element. */ for( i = 0; i < n; i++ ) { PElement t; if( !heap_list_add( heap, &list, &t ) ) return( FALSE ); if( !heap_real_new( heap, vec[i], &t ) ) return( FALSE ); (void) heap_list_next( &list ); } return( TRUE ); } /* Make a realvec, but from an int*. */ gboolean heap_intvec_new( Heap *heap, int n, int *vec, PElement *out ) { PElement list = *out; int i; /* Make first RHS ... the end of the list. */ heap_list_init( &list ); /* Build a CONS node for each element. */ for( i = 0; i < n; i++ ) { PElement t; if( !heap_list_add( heap, &list, &t ) ) return( FALSE ); if( !heap_real_new( heap, (double) vec[i], &t ) ) return( FALSE ); (void) heap_list_next( &list ); } return( TRUE ); } /* Make a matrix. */ gboolean heap_matrix_new( Heap *heap, int xsize, int ysize, double *vec, PElement *out ) { PElement list = *out; int y, i; /* Make first RHS ... the end of the list. */ heap_list_init( &list ); /* Build a CONS node for each element. */ for( i = 0, y = 0; y < ysize; y++ ) { PElement t; if( !heap_list_add( heap, &list, &t ) ) return( FALSE ); if( !heap_realvec_new( heap, xsize, vec + i, &t ) ) return( FALSE ); i += xsize; (void) heap_list_next( &list ); } return( TRUE ); } /* Make a typecheck error. Always return FALSE ... the gboolean is just there * for REDUCE_CATCH. */ gboolean heap_error_typecheck( PElement *e, const char *name, const char *type ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); (void) reduce_error_typecheck( reduce_context, e, name, type ); REDUCE_CATCH_STOP; return( FALSE ); } /* Map over a heap list. Reduce the list spine as we go, don't reduce the * heads. Return base on error, or whatever the user function returns (unlike * reduce_map_list(), which we can't just wrap). */ void * heap_map_list( PElement *base, heap_map_list_fn fn, void *a, void *b ) { Reduce *rc = reduce_context; PElement e = *base; if( !reduce_pelement( rc, reduce_spine, &e ) ) return( base ); if( !PEISLIST( &e ) ) { heap_error_typecheck( &e, "heap_map_list", "[*]" ); return( base ); } while( PEISFLIST( &e ) ) { PElement head; void *res; if( !heap_get_list( &e ) ) return( base ); /* Apply user function to the head. */ PEGETHD( &head, &e ); if( (res = fn( &head, a, b )) ) return( res ); /* Reduce the tail. */ PEGETTL( &e, &e ); if( !reduce_pelement( rc, reduce_spine, &e ) ) return( base ); } return( NULL ); } /* Iterate over a list. Move list on to the next tl, point data at the * head of the current node, FALSE for []. */ gboolean heap_get_list_next( PElement *list, PElement *data ) { Reduce *rc = reduce_context; if( !reduce_pelement( rc, reduce_spine, list ) ) return( FALSE ); if( PEISFLIST( list ) ) { HeapNode *hn; if( !heap_get_list( list ) ) return( FALSE ); hn = PEGETVAL( list ); PEPOINTRIGHT( hn, list ); PEPOINTLEFT( hn, data ); return( TRUE ); } else return( FALSE ); } typedef struct _HeapMapDict { heap_map_dict_fn fn; void *a; void *b; } HeapMapDict; static void * heap_map_dict_entry( PElement *head, HeapMapDict *map_dict ) { Reduce *rc = reduce_context; char key[256]; PElement p1, p2; void *result; if( !reduce_pelement( rc, reduce_spine, head ) ) return( head ); if( !PEISFLIST( head ) ) { heap_error_typecheck( head, "heap_map_dict", "[*]" ); return( head ); } if( !heap_get_list( head ) ) return( head ); PEGETHD( &p1, head ); if( !heap_get_string( &p1, key, 256 ) ) return( head ); PEGETTL( &p2, head ); if( !reduce_pelement( rc, reduce_spine, &p2 ) ) return( head ); if( !PEISFLIST( &p2 ) ) { heap_error_typecheck( &p2, "heap_map_dict", "[*]" ); return( head ); } if( !heap_get_list( &p2 ) ) return( head ); PEGETHD( &p1, &p2 ); if( (result = map_dict->fn( key, &p1, map_dict->a, map_dict->b )) ) return( result ); PEGETTL( &p1, &p2 ); if( !reduce_pelement( rc, reduce_spine, &p1 ) ) return( head ); if( !PEISELIST( &p1 ) ) { heap_error_typecheck( &p1, "heap_map_dict", "[]" ); return( head ); } return( NULL ); } /* Map over a list of ["key", value] pairs. */ void * heap_map_dict( PElement *base, heap_map_dict_fn fn, void *a, void *b ) { HeapMapDict map_dict; map_dict.fn = fn; map_dict.a = a; map_dict.b = b; return( heap_map_list( base, (heap_map_list_fn) heap_map_dict_entry, &map_dict, NULL ) ); } /* Evaluate a PElement into a string buffer. */ gboolean heap_get_string( PElement *base, char *buf, int n ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); (void) reduce_get_string( reduce_context, base, buf, n ); REDUCE_CATCH_STOP; return( TRUE ); } /* Evaluate a PElement to a [[char]]. */ gboolean heap_get_lstring( PElement *base, GSList **labels ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); (void) reduce_get_lstring( reduce_context, base, labels ); REDUCE_CATCH_STOP; return( TRUE ); } /* Get an element as a bool. */ gboolean heap_get_bool( PElement *base, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_get_bool( reduce_context, base ); REDUCE_CATCH_STOP; return( TRUE ); } /* Get an element as a real. */ gboolean heap_get_real( PElement *base, double *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_get_real( reduce_context, base ); REDUCE_CATCH_STOP; return( TRUE ); } /* Get an element as a class ... just reduce and typecheck. */ gboolean heap_get_class( PElement *base, PElement *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); reduce_get_class( reduce_context, base ); REDUCE_CATCH_STOP; /* Point out at base ... for consistency with other getters. */ *out = *base; return( TRUE ); } /* Get an element as an image. */ gboolean heap_get_image( PElement *base, Imageinfo **out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_get_image( reduce_context, base ); REDUCE_CATCH_STOP; return( TRUE ); } /* Get an element as a realvec. Return -1 on error, or length of vector. */ int heap_get_realvec( PElement *base, double *buf, int n ) { Reduce *rc = reduce_context; int l; REDUCE_CATCH_START( -1 ); l = reduce_get_realvec( reduce_context, base, buf, n ); REDUCE_CATCH_STOP; return( l ); } /* Get an element as a imagevec. Return -1 on error, or length of vector. */ int heap_get_imagevec( PElement *base, Imageinfo **buf, int n ) { Reduce *rc = reduce_context; int l; REDUCE_CATCH_START( -1 ); l = reduce_get_imagevec( reduce_context, base, buf, n ); REDUCE_CATCH_STOP; return( l ); } /* Get an element as a matrix. Return -1 on error, or length of buffer used. * Write xsize/ysize to args. */ gboolean heap_get_matrix_size( PElement *base, int *xsize, int *ysize ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); (void) reduce_get_matrix_size( reduce_context, base, xsize, ysize ); REDUCE_CATCH_STOP; return( TRUE ); } /* Get an element as a matrix. Return -1 on error, or length of buffer used. * Write xsize/ysize to args. */ gboolean heap_get_matrix( PElement *base, double *buf, int n, int *xsize, int *ysize ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); (void) reduce_get_matrix( reduce_context, base, buf, n, xsize, ysize ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_is_elist( PElement *base, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_elist( rc, base ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_is_list( PElement *base, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_list( rc, base ); REDUCE_CATCH_STOP; return( TRUE ); } /* Do a get, check it's OK. We don't get very much, in case it's a long * string and will take a while to eval. */ gboolean heap_is_string( PElement *base, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_string( rc, base ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_is_realvec( PElement *base, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_realvec( rc, base ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_is_imagevec( PElement *base, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_imagevec( rc, base ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_is_matrix( PElement *base, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_matrix( rc, base ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_is_class( PElement *base, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_class( rc, base ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_is_instanceof_exact( const char *name, PElement *klass, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_instanceof_exact( rc, name, klass ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_is_instanceof( const char *name, PElement *klass, gboolean *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); *out = reduce_is_instanceof( rc, name, klass ); REDUCE_CATCH_STOP; return( TRUE ); } int heap_list_length( PElement *base ) { Reduce *rc = reduce_context; int result; REDUCE_CATCH_START( -1 ); result = reduce_list_length( rc, base ); REDUCE_CATCH_STOP; return( result ); } int heap_list_length_max( PElement *base, int max_length ) { Reduce *rc = reduce_context; int result; REDUCE_CATCH_START( -1 ); result = reduce_list_length_max( rc, base, max_length ); REDUCE_CATCH_STOP; return( result ); } gboolean heap_list_index( PElement *base, int n, PElement *out ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); reduce_list_index( rc, base, n, out ); REDUCE_CATCH_STOP; return( TRUE ); } gboolean heap_reduce_strict( PElement *base ) { Reduce *rc = reduce_context; REDUCE_CATCH_START( FALSE ); reduce_spine_strict( rc, base ); REDUCE_CATCH_STOP; return( TRUE ); } /* hn is a node in a compiled function, out is part of a node in reduce * space to which it should be copied. * * Have to be careful to copy sym pointers in nodes from compile heap. */ static gboolean copy_node( Heap *heap, HeapNode *ri[], HeapNode *hn, PElement *out ) { HeapNode *hn1; PElement pleft, pright; int i; /* Look for relocation nodes. */ if( hn->type == TAG_SHARED ) { /* RHS of SHARE is the index of this share node. */ i = GPOINTER_TO_INT( GETRIGHT( hn ) ); /* Skip to shared section. */ hn = GETLEFT( hn ); /* Copy and link on this node. */ if( NEWNODE( heap, hn1 ) ) return( FALSE ); *hn1 = *hn; PEPUTP( out, ELEMENT_NODE, hn1 ); /* Note pointer in relocation table. */ ri[i] = hn1; } else if( hn->type == TAG_REFERENCE ) { /* Must have already copied this SHARE, just link back. */ hn1 = GETLEFT( hn ); i = GPOINTER_TO_INT( GETRIGHT( hn1 ) ); PEPUTP( out, ELEMENT_NODE, ri[i] ); /* Done! */ return( TRUE ); } else { /* Copy and link on this node. */ if( NEWNODE( heap, hn1 ) ) return( FALSE ); *hn1 = *hn; PEPUTP( out, ELEMENT_NODE, hn1 ); } /* If it's a DOUBLE, no more to do. */ if( hn->type == TAG_DOUBLE ) return( TRUE ); if( hn->ltype != ELEMENT_NODE && hn->rtype == ELEMENT_NODE ) { /* Right pointer only. Zap pointer so we can GC * safely. */ hn1->rtype = ELEMENT_CHAR; /* Recurse for RHS of node. */ PEPOINTRIGHT( hn1, &pright ); if( !copy_node( heap, ri, GETRIGHT( hn ), &pright ) ) return( FALSE ); } else if( hn->ltype == ELEMENT_NODE && hn->rtype != ELEMENT_NODE ) { /* Left pointer only. Zap pointer so we can GC * safely. */ hn1->ltype = ELEMENT_CHAR; /* Recurse for LHS of node. */ PEPOINTLEFT( hn1, &pleft ); if( !copy_node( heap, ri, GETLEFT( hn ), &pleft ) ) return( FALSE ); } else if( hn->ltype == ELEMENT_NODE && hn->rtype == ELEMENT_NODE ) { /* Both pointers. Zap pointers so we can GC safely. */ hn1->ltype = ELEMENT_CHAR; hn1->rtype = ELEMENT_CHAR; /* Recurse for boths sides of node. */ PEPOINTLEFT( hn1, &pleft ); PEPOINTRIGHT( hn1, &pright ); if( !copy_node( heap, ri, GETLEFT( hn ), &pleft ) || !copy_node( heap, ri, GETRIGHT( hn ), &pright ) ) return( FALSE ); } return( TRUE ); } /* Copy a compiled graph into the main reduce space. Overwrite the node at * out. */ gboolean heap_copy( Heap *heap, Compile *compile, PElement *out ) { Element *root = &compile->base; HeapNode *ri[MAX_RELOC]; /* Check for possible C stack overflow ... can't go over 2M on most * systems if we're using (or any of our libs are using) threads. */ if( (char *) main_c_stack_base - (char *) &heap > 2000000 ) { error_top( _( "Overflow error." ) ); error_sub( _( "C stack overflow. Circular definition." ) ); return( FALSE ); } #ifdef DEBUG printf( "heap_copy: " ); symbol_name_print( compile->sym ); printf( "\n" ); #endif /*DEBUG*/ /* Check for possible C stack overflow ... can't go over 2M on most * systems if we're using (or any of our libs are using) threads. */ if( (char *) main_c_stack_base - (char *) &heap > 2000000 ) { error_top( _( "Overflow error." ) ); error_sub( _( "C stack overflow. Expression too complex." ) ); return( FALSE ); } switch( root->type ) { case ELEMENT_NODE: /* Need a tree copy. */ if( !copy_node( heap, &ri[0], (HeapNode *) root->ele, out ) ) return( FALSE ); break; case ELEMENT_SYMBOL: case ELEMENT_CHAR: case ELEMENT_BOOL: case ELEMENT_BINOP: case ELEMENT_SYMREF: case ELEMENT_COMPILEREF: case ELEMENT_CONSTRUCTOR: case ELEMENT_UNOP: case ELEMENT_COMB: case ELEMENT_TAG: case ELEMENT_ELIST: case ELEMENT_MANAGED: /* Copy value. */ PEPUTP( out, root->type, root->ele ); break; case ELEMENT_NOVAL: /* Not compiled yet: compile now, then copy. */ if( compile_object( compile ) ) return( FALSE ); if( !heap_copy( heap, compile, out ) ) return( FALSE ); break; default: g_assert( FALSE ); } return( TRUE ); } /* Try to make a gvalue from a heap object. */ gboolean heap_ip_to_gvalue( PElement *in, GValue *out ) { Reduce *rc = reduce_context; if( !reduce_pelement( rc, reduce_spine_strict, in ) ) return( FALSE ); if( PEISREAL( in ) ) { g_value_init( out, G_TYPE_DOUBLE ); g_value_set_double( out, PEGETREAL( in ) ); } else if( PEISBOOL( in ) ) { g_value_init( out, G_TYPE_BOOLEAN ); g_value_set_boolean( out, PEGETBOOL( in ) ); } else if( PEISCOMPLEX( in ) ) { printf( "ip_to_gvalue: no complex gtype!\n" ); return( FALSE ); } else if( PEISIMAGE( in ) ) { Imageinfo *ii = PEGETII( in ); VipsImage *im = imageinfo_get( FALSE, ii ); g_value_init( out, VIPS_TYPE_IMAGE ); g_value_set_object( out, im ); } else if( PEISLIST( in ) ) { gboolean result; if( heap_is_string( in, &result ) && result ) { char name[256]; if( !heap_get_string( in, name, 256 ) ) return( FALSE ); /* We want a refstring, not a G_TYPE_STRING, since * this GValue will (probably) be used by vips with * im_header_string() etc. */ g_value_init( out, IM_TYPE_REF_STRING ); im_ref_string_set( out, name ); } #if VIPS_MAJOR_VERSION > 7 || VIPS_MINOR_VERSION > 39 /* vips_value_set_array_*() is a 7.40 feature. */ else if( heap_is_imagevec( in, &result ) && result ) { Imageinfo *iivec[100]; VipsImage **ivec; int n; int i; if( (n = heap_get_imagevec( in, iivec, 100 )) < 0 ) return( FALSE ); g_value_init( out, VIPS_TYPE_ARRAY_IMAGE ); vips_value_set_array_image( out, n ); ivec = vips_value_get_array_image( out, NULL ); for( i = 0; i < n; i++ ) { ivec[i] = imageinfo_get( FALSE, iivec[i] ); /* g_value_unset() on out will unref every * array element, so we need to ref. */ g_object_ref( ivec[i] ); } } else if( heap_is_realvec( in, &result ) && result ) { double realvec[100]; int n; if( (n = heap_get_realvec( in, realvec, 100 )) < 0 ) return( FALSE ); g_value_init( out, VIPS_TYPE_ARRAY_DOUBLE ); vips_value_set_array_double( out, realvec, n ); } #endif else { error_top( _( "Unimplemented list type." ) ); return( FALSE ); } } else if( PEISMANAGED( in ) && IS_MANAGEDGOBJECT( PEGETVAL( in ) ) ) { g_value_init( out, G_TYPE_OBJECT ); g_value_set_object( out, MANAGEDGOBJECT( PEGETMANAGED( in ) )->object ); } else { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); error_top( _( "Unimplemented argument type." ) ); (void) itext_value( rc, &buf, in ); error_sub( _( "Cannot convert %s to GValue." ), vips_buf_all( &buf ) ); return( FALSE ); } return( TRUE ); } /* Try to make a heap object from a gvalue. */ gboolean heap_gvalue_to_ip( GValue *in, PElement *out ) { Reduce *rc = reduce_context; Heap *heap = rc->heap; if( G_VALUE_HOLDS_BOOLEAN( in ) ) { PEPUTP( out, ELEMENT_BOOL, (int) g_value_get_boolean( in ) ); } else if( G_VALUE_HOLDS_CHAR( in ) ) { /* g_value_get_schar() is not in older glibs. */ PEPUTP( out, ELEMENT_CHAR, (int) g_value_get_uchar( in ) ); } else if( G_VALUE_HOLDS_UCHAR( in ) ) { PEPUTP( out, ELEMENT_CHAR, (int) g_value_get_uchar( in ) ); } else if( G_VALUE_HOLDS_INT( in ) ) { if( !heap_real_new( heap, g_value_get_int( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_UINT( in ) ) { if( !heap_real_new( heap, g_value_get_uint( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_LONG( in ) ) { if( !heap_real_new( heap, g_value_get_long( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_ULONG( in ) ) { if( !heap_real_new( heap, g_value_get_ulong( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_INT64( in ) ) { if( !heap_real_new( heap, g_value_get_int64( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_UINT64( in ) ) { if( !heap_real_new( heap, g_value_get_uint64( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_FLOAT( in ) ) { if( !heap_real_new( heap, g_value_get_float( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_DOUBLE( in ) ) { if( !heap_real_new( heap, g_value_get_double( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_ENUM( in ) ) { if( !heap_real_new( heap, g_value_get_enum( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_STRING( in ) ) { if( !heap_managedstring_new( heap, g_value_get_string( in ), out ) ) return( FALSE ); } else if( G_VALUE_HOLDS_OBJECT( in ) ) { GObject *object; Managed *managed; object = g_value_get_object( in ); if( VIPS_IS_IMAGE( object ) ) { VipsImage *image = VIPS_IMAGE( object ); g_object_ref( image ); managed = MANAGED( imageinfo_new( main_imageinfogroup, heap, image, image->filename ) ); } else managed = MANAGED( managedgobject_new( heap, object ) ); PEPUTP( out, ELEMENT_MANAGED, managed ); } else if( g_value_type_transformable( G_VALUE_TYPE( in ), G_TYPE_STRING ) ) { GValue temp = { 0 }; g_value_init( &temp, G_TYPE_STRING ); g_value_transform( in, &temp ); if( !heap_managedstring_new( heap, g_value_get_string( &temp ), out ) ) { return( FALSE ); g_value_unset( &temp ); } g_value_unset( &temp ); } else { error_top( _( "Unimplemented type." ) ); error_sub( _( "Unable to convert %s to a nip type." ), G_VALUE_TYPE_NAME( in ) ); return( FALSE ); } return( TRUE ); } /* Indent step. */ #define TAB (2) /* Fwd ref. */ static void lisp_pelement( VipsBuf *buf, PElement *base, GSList **back, gboolean fn, int indent ); /* Print a sym-value list. */ static void lisp_symval( VipsBuf *buf, PElement *base, GSList **back, gboolean fn, int indent, PElement *stop ) { gboolean error = FALSE; /* Reached the "stop" element? */ if( stop && *base->type == *stop->type && *base->ele == *stop->ele ) return; if( PEISNODE( base ) ) { HeapNode *hn = PEGETVAL( base ); PElement pe; if( hn->type != TAG_CONS ) error = TRUE; PEPOINTLEFT( hn, &pe ); if( !error && PEISNODE( &pe ) ) { HeapNode *hn2 = PEGETVAL( &pe ); if( hn2->type != TAG_CONS ) error = TRUE; PEPOINTLEFT( hn2, &pe ); if( !error && PEISSYMREF( &pe ) ) { vips_buf_appendf( buf, "\n%s", spc( indent ) ); symbol_qualified_name( PEGETSYMREF( &pe ), buf ); vips_buf_appendf( buf, " = " ); PEPOINTRIGHT( hn2, &pe ); lisp_pelement( buf, &pe, back, fn, indent + TAB ); PEPOINTRIGHT( hn, &pe ); lisp_symval( buf, &pe, back, fn, indent, stop ); } else error = TRUE; } else error = TRUE; } else if( !PEISELIST( base ) ) error = TRUE; if( error ) vips_buf_appendf( buf, "\n%s<*** malformed symval list>", spc( indent ) ); } /* Print a [*] ... our caller has printed the enclosing [ ] and the first * element, so we print a ", " followed by us. */ static void lisp_list( VipsBuf *buf, PElement *base, GSList **back, gboolean fn, int indent ) { if( PEISNODE( base ) ) { HeapNode *hn = PEGETVAL( base ); PElement pe; vips_buf_appends( buf, ", " ); if( hn->type == TAG_CONS ) { PEPOINTLEFT( hn, &pe ); lisp_pelement( buf, &pe, back, fn, indent ); PEPOINTRIGHT( hn, &pe ); lisp_list( buf, &pe, back, fn, indent ); } else lisp_pelement( buf, base, back, fn, indent ); } else if( PEISMANAGEDSTRING( base ) ) { vips_buf_appends( buf, ", Managedstring <" ); vips_buf_appends( buf, PEGETMANAGEDSTRING( base )->string ); vips_buf_appends( buf, ">" ); } else if( !PEISELIST( base ) ) lisp_pelement( buf, base, back, fn, indent ); } /* Print a [char] ... fall back to lisp_list() if we hit a non-char * element. base is the RHS of a cons, so it can be a managedstring too. */ static gboolean lisp_string( VipsBuf *buf, PElement *base, GSList **back, gboolean fn, int indent ) { gboolean error = FALSE; if( PEISNODE( base ) ) { HeapNode *hn = PEGETVAL( base ); PElement pe; if( hn->type != TAG_CONS ) error = TRUE; PEPOINTLEFT( hn, &pe ); if( !error ) { if( PEISCHAR( &pe ) ) { vips_buf_appendf( buf, "%c", PEGETCHAR( &pe ) ); PEPOINTRIGHT( hn, &pe ); (void) lisp_string( buf, &pe, back, fn, indent ); } else { vips_buf_appends( buf, "\":[" ); lisp_pelement( buf, &pe, back, fn, indent ); PEPOINTRIGHT( hn, &pe ); lisp_list( buf, &pe, back, fn, indent ); vips_buf_appends( buf, "]" ); error = TRUE; } } else error = TRUE; } else if( PEISMANAGEDSTRING( base ) ) vips_buf_appends( buf, PEGETMANAGEDSTRING( base )->string ); else if( !PEISELIST( base ) ) error = TRUE; return( error ); } /* Print a graph LISP-style. */ static void lisp_node( VipsBuf *buf, HeapNode *hn, GSList **back, gboolean fn, int indent ) { int i; PElement p1, p2; /* Have we printed this node before? */ if( hn->flgs & FLAG_PRINT ) { if( (i = g_slist_index( *back, hn )) == -1 ) { *back = g_slist_prepend( *back, hn ); vips_buf_appendf( buf, "<" ); vips_buf_appendf( buf, _( "circular" ) ); vips_buf_appendf( buf, " (%p)>", hn ); } else { vips_buf_appendf( buf, "<" ); vips_buf_appendf( buf, _( "circular to label %d" ), i ); vips_buf_appendf( buf, ">" ); } return; } hn->flgs |= FLAG_PRINT; if( (i = g_slist_index( *back, hn )) != -1 ) { vips_buf_appendf( buf, "*" ); vips_buf_appendf( buf, _( "label %d" ), i ); vips_buf_appendf( buf, ": " ); } switch( hn->type ) { case TAG_APPL: if( fn ) { PEPOINTLEFT( hn, &p1 ); PEPOINTRIGHT( hn, &p2 ); vips_buf_appends( buf, "(" ); lisp_pelement( buf, &p1, back, fn, indent ); vips_buf_appends( buf, " " ); lisp_pelement( buf, &p2, back, fn, indent ); vips_buf_appends( buf, ")" ); } else { vips_buf_appends( buf, "<" ); vips_buf_appends( buf, _( "unevaluated" ) ); vips_buf_appends( buf, ">" ); } break; case TAG_CONS: PEPOINTLEFT( hn, &p1 ); if( PEISCHAR( &p1 ) ) { vips_buf_appendf( buf, "\"%c", PEGETCHAR( &p1 ) ); PEPOINTRIGHT( hn, &p2 ); (void) lisp_string( buf, &p2, back, fn, indent ); vips_buf_appends( buf, "\"" ); } else { vips_buf_appends( buf, "[" ); lisp_pelement( buf, &p1, back, fn, indent ); PEPOINTRIGHT( hn, &p2 ); lisp_list( buf, &p2, back, fn, indent ); vips_buf_appends( buf, "]" ); } break; case TAG_DOUBLE: vips_buf_appendf( buf, "%g", hn->body.num ); break; case TAG_COMPLEX: vips_buf_appendf( buf, "(%g,%g)", GETLEFT( hn )->body.num, GETRIGHT( hn )->body.num ); break; case TAG_CLASS: if( fn ) { vips_buf_appendf( buf, "\n%s", spc( indent ) ); vips_buf_appendf( buf, _( "class (%p)" ), hn ); vips_buf_appendf( buf, " " ); } PEPOINTLEFT( hn, &p1 ); lisp_pelement( buf, &p1, back, fn, indent ); if( fn ) { hn = GETRIGHT( hn ); vips_buf_appendf( buf, "\n%s", spc( indent + TAB ) ); vips_buf_appendf( buf, _( "members" ) ); vips_buf_appendf( buf, " = { " ); PEPOINTRIGHT( hn, &p1 ); lisp_symval( buf, &p1, back, fn, indent + TAB * 2, NULL ); vips_buf_appendf( buf, "\n%s}", spc( indent + TAB ) ); PEPOINTLEFT( hn, &p2 ); if( *p1.type != *p2.type || *p1.ele != *p2.ele ) { vips_buf_appendf( buf, "\n%s", spc( indent + TAB ) ); vips_buf_appendf( buf, _( "secret" ) ); vips_buf_appendf( buf, " = { " ); lisp_symval( buf, &p2, back, fn, indent + TAB * 2, &p1 ); vips_buf_appendf( buf, "\n%s} ", spc( indent + TAB ) ); } } break; case TAG_GEN: vips_buf_appendf( buf, "[%g,%g...", GETLEFT( hn )->body.num, GETLEFT( GETRIGHT( hn ) )->body.num ); if( GETRT( GETRIGHT( hn ) ) == ELEMENT_ELIST ) vips_buf_appends( buf, "[ ]]" ); else vips_buf_appendf( buf, "%g]", GETRIGHT( GETRIGHT( hn ) )->body.num ); break; case TAG_SHARED: PEPOINTLEFT( hn, &p1 ); i = GPOINTER_TO_INT( GETRIGHT( hn ) ); vips_buf_appendf( buf, "SHARE%d[", i ); lisp_pelement( buf, &p1, back, fn, indent ); vips_buf_appends( buf, "]" ); break; case TAG_REFERENCE: i = GPOINTER_TO_INT( GETRIGHT( GETLEFT( hn ) ) ); vips_buf_appendf( buf, "REF%d", i ); break; case TAG_FREE: default: g_assert( FALSE ); } } /* Print a pelement LISP-style. */ static void lisp_pelement( VipsBuf *buf, PElement *base, GSList **back, gboolean fn, int indent ) { HeapNode *hn; EType type = PEGETTYPE( base ); switch( type ) { case ELEMENT_NOVAL: vips_buf_appends( buf, "<" ); vips_buf_appendf( buf, _( "no value (type %d)" ), GPOINTER_TO_INT( PEGETVAL( base ) ) ); vips_buf_appends( buf, ">" ); break; case ELEMENT_NODE: if( !(hn = PEGETVAL( base )) ) { vips_buf_appends( buf, "<" ); vips_buf_appends( buf, _( "NULL pointer" ) ); vips_buf_appends( buf, ">" ); } else lisp_node( buf, hn, back, fn, indent ); break; case ELEMENT_SYMBOL: vips_buf_appends( buf, "<" ); vips_buf_appends( buf, _( "symbol" ) ); vips_buf_appends( buf, " \"" ); symbol_qualified_name( PEGETSYMBOL( base ), buf ); vips_buf_appends( buf, "\">" ); break; case ELEMENT_CONSTRUCTOR: vips_buf_appends( buf, "<" ); vips_buf_appends( buf, _( "constructor" ) ); vips_buf_appends( buf, " \"" ); symbol_qualified_name( PEGETCOMPILE( base )->sym, buf ); vips_buf_appends( buf, "\">" ); break; case ELEMENT_SYMREF: vips_buf_appends( buf, "<" ); vips_buf_appends( buf, _( "symref" ) ); vips_buf_appends( buf, " \"" ); symbol_qualified_name( PEGETSYMBOL( base ), buf ); vips_buf_appends( buf, "\">" ); break; case ELEMENT_COMPILEREF: vips_buf_appends( buf, "<" ); vips_buf_appends( buf, _( "compileref" ) ); vips_buf_appends( buf, " \"" ); symbol_qualified_name( PEGETCOMPILE( base )->sym, buf ); vips_buf_appends( buf, "\">" ); break; case ELEMENT_CHAR: vips_buf_appendf( buf, "'%c'", (int) PEGETCHAR( base ) ); break; case ELEMENT_BOOL: vips_buf_appends( buf, bool_to_char( PEGETBOOL( base ) ) ); break; case ELEMENT_BINOP: vips_buf_appends( buf, decode_BinOp( PEGETBINOP( base ) ) ); break; case ELEMENT_UNOP: vips_buf_appends( buf, decode_UnOp( PEGETUNOP( base ) ) ); break; case ELEMENT_ELIST: vips_buf_appends( buf, "[ ]" ); break; case ELEMENT_TAG: vips_buf_appendf( buf, "<" ); vips_buf_appendf( buf, _( "tag \"%s\"" ), PEGETTAG( base ) ); vips_buf_appendf( buf, ">" ); break; case ELEMENT_MANAGED: vips_buf_appendf( buf, "", PEGETVAL( base ) ); break; case ELEMENT_COMB: vips_buf_appends( buf, decode_CombinatorType( PEGETCOMB( base ) ) ); break; default: vips_buf_appendf( buf, "<" ); vips_buf_appendf( buf, _( "unknown element tag %d" ), type ); vips_buf_appendf( buf, ">" ); break; } } /* Print a node to a buffer. If fn is true, trace into functions. */ void graph_node( Heap *heap, VipsBuf *buf, HeapNode *root, gboolean fn ) { GSList *back; char txt[4]; VipsBuf buf2 = VIPS_BUF_STATIC( txt ); /* May be called before heap is built. */ if( !heap ) return; back = NULL; heap_clear( heap, FLAG_PRINT ); lisp_node( &buf2, root, &back, fn, 0 ); heap_clear( heap, FLAG_PRINT ); lisp_node( buf, root, &back, fn, 0 ); IM_FREEF( g_slist_free, back ); } /* As above, but start from a pelement. */ void graph_pelement( Heap *heap, VipsBuf *buf, PElement *root, gboolean fn ) { GSList *back; char txt[4]; VipsBuf buf2 = VIPS_BUF_STATIC( txt ); /* May be called before heap is built. */ if( !heap ) return; /* We print twice ... the first time through we build the list of back * pointers so we can label the graph correctly. */ back = NULL; heap_clear( heap, FLAG_PRINT ); lisp_pelement( &buf2, root, &back, fn, 0 ); heap_clear( heap, FLAG_PRINT ); lisp_pelement( buf, root, &back, fn, 0 ); IM_FREEF( g_slist_free, back ); } /* As above, but start from an element. */ void graph_element( Heap *heap, VipsBuf *buf, Element *root, gboolean fn ) { PElement base; PEPOINTE( &base, root ); graph_pelement( heap, buf, &base, fn ); } void graph_pointer( PElement *root ) { char txt[1000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( reduce_context->heap, &buf, root, TRUE ); printf( "%s\n", vips_buf_all( &buf ) ); } /* Fwd ref. */ static void shell_pelement( PElement *base ); /* Print a graph shell-style. */ static void shell_node( HeapNode *hn ) { PElement p1, p2; /* Have we printed this node before? */ if( hn->flgs & FLAG_PRINT ) { printf( "<*circular*>" ); return; } hn->flgs |= FLAG_PRINT; switch( hn->type ) { case TAG_CLASS: case TAG_APPL: case TAG_REFERENCE: case TAG_SHARED: case TAG_GEN: break; case TAG_CONS: { gboolean string_mode; PEPOINTLEFT( hn, &p1 ); string_mode = PEISCHAR( &p1 ); for(;;) { if( string_mode ) printf( "%c", PEGETCHAR( &p1 ) ); else shell_pelement( &p1 ); PEPOINTRIGHT( hn, &p2 ); if( PEISMANAGEDSTRING( &p2 ) ) { printf( "%s\n", PEGETMANAGEDSTRING( &p2 )->string ); break; } else if( PEISELIST( &p2 ) ) break; if( !string_mode ) printf( "\n" ); hn = PEGETVAL( &p2 ); PEPOINTLEFT( hn, &p1 ); if( string_mode && !PEISCHAR( &p1 ) ) string_mode = FALSE; } } break; case TAG_DOUBLE: printf( "%g", hn->body.num ); break; case TAG_COMPLEX: printf( "%g %g", GETLEFT( hn )->body.num, GETRIGHT( hn )->body.num ); break; case TAG_FREE: default: g_assert( FALSE ); } } /* Print a pelement shell-style. */ static void shell_pelement( PElement *base ) { switch( PEGETTYPE( base ) ) { /* Only allow concrete base types. */ case ELEMENT_SYMREF: case ELEMENT_COMPILEREF: case ELEMENT_CONSTRUCTOR: case ELEMENT_BINOP: case ELEMENT_UNOP: case ELEMENT_COMB: case ELEMENT_TAG: case ELEMENT_SYMBOL: case ELEMENT_NOVAL: printf( "no-value" ); break; case ELEMENT_NODE: shell_node( PEGETVAL( base ) ); break; case ELEMENT_CHAR: printf( "%c", (int)PEGETCHAR( base ) ); break; case ELEMENT_BOOL: printf( "%s", bool_to_char( PEGETBOOL( base ) ) ); break; case ELEMENT_ELIST: printf( "[ ]" ); break; case ELEMENT_MANAGED: if( PEISIMAGE( base ) ) printf( "%s", PEGETIMAGE( base )->filename ); else if( PEISMANAGEDSTRING( base ) ) printf( "%s", PEGETMANAGEDSTRING( base )->string ); break; default: g_assert( FALSE ); } } /* Print a pelement shell-style. */ void graph_value( PElement *root ) { Reduce *rc = reduce_context; if( !reduce_pelement( rc, reduce_spine_strict, root ) ) { iwindow_alert( NULL, GTK_MESSAGE_ERROR ); return; } heap_clear( reduce_context->heap, FLAG_PRINT ); shell_pelement( root ); printf( "\n" ); } nip2-8.7.1/src/spin.h0000644000175000017500000000300513351443023011225 00000000000000/* a pair of spin buttons */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_SPIN (spin_get_type()) #define SPIN( obj ) (GTK_CHECK_CAST( (obj), TYPE_SPIN, Spin )) #define SPIN_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_SPIN, SpinClass )) #define IS_SPIN( obj ) (GTK_CHECK_TYPE( (obj), TYPE_SPIN )) #define IS_SPIN_CLASS( klass ) (GTK_CHECK_CLASS_TYPE( (klass), TYPE_SPIN )) typedef struct _Spin { View view; /* My instance vars. */ GtkWidget *up; /* Arrow buttons */ GtkWidget *down; } Spin; typedef struct _SpinClass { ViewClass parent_class; void (*up_click)( Spin * ); void (*down_click)( Spin * ); } SpinClass; GtkType spin_get_type( void ); GtkWidget *spin_new( void ); nip2-8.7.1/src/nipmarshal.list0000644000175000017500000000241613351443023013143 00000000000000# see glib-genmarshal(1) for a detailed description of the file format, # possible parameter types are: # VOID indicates no return type, or no extra # parameters. if VOID is used as the parameter # list, no additional parameters may be present. # BOOLEAN for boolean types (gboolean) # CHAR for signed char types (gchar) # UCHAR for unsigned char types (guchar) # INT for signed integer types (gint) # UINT for unsigned integer types (guint) # LONG for signed long integer types (glong) # ULONG for unsigned long integer types (gulong) # ENUM for enumeration types (gint) # FLAGS for flag enumeration types (guint) # FLOAT for single-precision float types (gfloat) # DOUBLE for double-precision float types (gdouble) # STRING for string types (gchar*) # BOXED for boxed (anonymous but reference counted) types (GBoxed*) # POINTER for anonymous pointer types (gpointer) # PARAM for GParamSpec or derived types (GParamSpec*) # OBJECT for GObject or derived types (GObject*) # NONE deprecated alias for VOID # BOOL deprecated alias for BOOLEAN VOID: OBJECT, INT VOID: DOUBLE, DOUBLE BOOLEAN: INT, INT nip2-8.7.1/src/statusview.c0000644000175000017500000002627113414612631012502 00000000000000/* widgets for the status bar */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GtkFrameClass *parent_class = NULL; /* The popup menu. */ static GtkWidget *statusview_menu = NULL; /* Sub. fn. of below. Junk the widgets inside a band display. */ static void * statusviewband_destroy_sub( StatusviewBand *svb ) { DESTROY_GTK( svb->val ); IM_FREE( svb ); return( NULL ); } /* Junk the widgets inside a band display. */ static void statusviewband_destroy( Statusview *sv ) { slist_map( sv->bands, (SListMapFn) statusviewband_destroy_sub, NULL ); IM_FREEF( g_slist_free, sv->bands ); } static void statusview_destroy( GtkObject *object ) { Statusview *sv; g_return_if_fail( object != NULL ); g_return_if_fail( IS_STATUSVIEW( object ) ); sv = STATUSVIEW( object ); #ifdef DEBUG printf( "statusview_destroy\n" ); #endif /*DEBUG*/ statusviewband_destroy( sv ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } /* Hide this statusview. */ static void statusview_hide_cb( GtkWidget *menu, GtkWidget *host, Statusview *sv ) { sv->imagemodel->show_status = FALSE; iobject_changed( IOBJECT( sv->imagemodel ) ); } static void statusview_class_init( StatusviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidget *pane; parent_class = g_type_class_peek_parent( class ); object_class->destroy = statusview_destroy; /* Create signals. */ /* Init methods. */ pane = statusview_menu = popup_build( _( "Status bar menu" ) ); popup_add_but( pane, GTK_STOCK_CLOSE, POPUP_FUNC( statusview_hide_cb ) ); } static void statusview_init( Statusview *sv ) { GtkWidget *vb, *hb; GtkWidget *eb; sv->imagemodel = NULL; sv->bands = NULL; sv->fmt = -1; sv->nb = -1; gtk_frame_set_shadow_type( GTK_FRAME( sv ), GTK_SHADOW_OUT ); eb = gtk_event_box_new(); gtk_container_add( GTK_CONTAINER( sv ), eb ); popup_attach( eb, statusview_menu, sv ); vb = gtk_vbox_new( FALSE, 0 ); gtk_container_set_border_width( GTK_CONTAINER( vb ), 1 ); gtk_container_add( GTK_CONTAINER( eb ), vb ); sv->top = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( sv->top ), 0.0, 0.5 ); gtk_box_pack_start( GTK_BOX( vb ), sv->top, TRUE, TRUE, 0 ); hb = gtk_hbox_new( FALSE, 5 ); gtk_box_pack_start( GTK_BOX( vb ), hb, TRUE, TRUE, 0 ); sv->pos = gtk_label_new( "" ); set_fixed( sv->pos, strlen( "(888888,888888)" ) ); gtk_misc_set_alignment( GTK_MISC( sv->pos ), 0.0, 0.5 ); gtk_box_pack_start( GTK_BOX( hb ), sv->pos, FALSE, FALSE, 0 ); sv->hb = gtk_hbox_new( FALSE, 5 ); gtk_box_pack_start( GTK_BOX( hb ), sv->hb, TRUE, TRUE, 0 ); sv->mag = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( sv->mag ), 0.0, 0.5 ); gtk_box_pack_end( GTK_BOX( hb ), sv->mag, FALSE, FALSE, 0 ); gtk_widget_show_all( eb ); } GtkType statusview_get_type( void ) { static GtkType statusview_type = 0; if( !statusview_type ) { static const GtkTypeInfo sinfo = { "Statusview", sizeof( Statusview ), sizeof( StatusviewClass ), (GtkClassInitFunc) statusview_class_init, (GtkObjectInitFunc) statusview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; statusview_type = gtk_type_unique( GTK_TYPE_FRAME, &sinfo ); } return( statusview_type ); } /* Our model has changed ... update. */ static void statusview_changed_cb( Imagemodel *imagemodel, Statusview *sv ) { static char *sample[] = { /* Sample text for each BandFmt. Used to try to get * the spacing right. */ "888", /* uchar */ "-888", /* char */ "88888", /* ushort */ "-88888", /* short */ "888888888", /* int */ "-888888888", /* uint */ "888888888", /* float */ "(88888888,888888888)", /* complex */ "88888888888", /* double */ "(8888888888,888888888)" /* dpcomplex */ }; Conversion *conv = imagemodel->conv; iImage *iimage = imagemodel->iimage; IMAGE *im = imageinfo_get( FALSE, iimage->value.ii ); double size = (double) im->Ysize * IM_IMAGE_SIZEOF_LINE( im ); unsigned int nb; int fmt; char txt[MAX_LINELENGTH]; VipsBuf buf = VIPS_BUF_STATIC( txt ); #ifdef DEBUG printf( "statusview_changed_cb: %p\n", imagemodel ); #endif /*DEBUG*/ widget_visible( GTK_WIDGET( sv ), imagemodel->show_status ); /* If we're hidden, no need to do any more. */ if( !imagemodel->show_status ) return; if( conv->mag > 0 ) set_glabel( sv->mag, "%s %d:1", _( "Magnification" ), conv->mag ); else set_glabel( sv->mag, "%s 1:%d", _( "Magnification" ), -conv->mag ); vips_buf_appendf( &buf, "%s, ", NN( IOBJECT( iimage )->caption ) ); vips_buf_append_size( &buf, size ); vips_buf_appendf( &buf, ", %.3gx%.3g p/mm", im->Xres, im->Yres ); set_gcaption( sv->top, "%s", vips_buf_all( &buf ) ); if( im->Coding == IM_CODING_LABQ || im->Coding == IM_CODING_RAD ) { nb = 3; fmt = 6; } else { nb = im->Bands; fmt = im->BandFmt; } if( sv->nb != nb || sv->fmt != fmt ) { /* Bands/fmt has changed ... rebuild band display widgets. */ unsigned int i; int width; statusviewband_destroy( sv ); sv->fmt = fmt; sv->nb = nb; if( sv->fmt >= 0 && sv->fmt < IM_NUMBER( sample ) ) width = strlen( sample[sv->fmt] ); else width = 10; /* Don't display more than 8 bands ... it'll make the window * too large. FIXME ... now very kewl */ for( i = 0; i < IM_MIN( 8, nb ); i++ ) { StatusviewBand *band = INEW( NULL, StatusviewBand ); band->sv = sv; band->bandno = i; band->val = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( band->val ), 0.0, 0.5 ); set_fixed( band->val, width ); gtk_box_pack_start( GTK_BOX( sv->hb ), band->val, FALSE, FALSE, 0 ); gtk_widget_show( band->val ); sv->bands = g_slist_append( sv->bands, band ); } } } static void statusview_link( Statusview *sv, Imagemodel *imagemodel ) { sv->imagemodel = imagemodel; g_signal_connect( G_OBJECT( sv->imagemodel ), "changed", G_CALLBACK( statusview_changed_cb ), sv ); } Statusview * statusview_new( Imagemodel *imagemodel ) { Statusview *sv = gtk_type_new( TYPE_STATUSVIEW ); statusview_link( sv, imagemodel ); return( sv ); } /* Turn a IM_CODING_LABQ 4-band image into three floats. */ static void statusview_mouse_LABPACK( Statusview *sv, int x, int y ) { Imagemodel *imagemodel = sv->imagemodel; Conversion *conv = imagemodel->conv; GSList *bands = sv->bands; /* Three widgets we update. */ StatusviewBand *b1; StatusviewBand *b2; StatusviewBand *b3; unsigned char *e = (unsigned char *) get_element( conv->reg, x, y, 0 ); unsigned int iL = (e[0] << 2) | (e[3] >> 6); float L = 100.0 * iL / 1023.0; signed int ia = ((signed char) e[1] << 3) | ((e[3] >> 3) & 0x7); float a = 0.125 * ia; signed int ib = ((signed char) e[2] << 3) | (e[3] & 0x7); float b = 0.125 * ib; if( g_slist_length( sv->bands ) == 3 ) { b1 = (StatusviewBand *) bands->data; b2 = (StatusviewBand *) bands->next->data; b3 = (StatusviewBand *) bands->next->next->data; set_glabel( b1->val, "%g", L ); set_glabel( b2->val, "%g", a ); set_glabel( b3->val, "%g", b ); } } /* Turn a IM_CODING_RAD 4-band image into three floats. */ static void statusview_mouse_RAD( Statusview *sv, int x, int y ) { Imagemodel *imagemodel = sv->imagemodel; Conversion *conv = imagemodel->conv; GSList *bands = sv->bands; /* Three widgets we update. */ StatusviewBand *b1; StatusviewBand *b2; StatusviewBand *b3; unsigned char *e = (unsigned char *) get_element( conv->reg, x, y, 0 ); double f = ldexp( 1.0, e[3] - (128 + 8) ); float r = (e[0] + 0.5) * f; float g = (e[1] + 0.5) * f; float b = (e[2] + 0.5) * f; if( g_slist_length( sv->bands ) == 3 ) { b1 = (StatusviewBand *) bands->data; b2 = (StatusviewBand *) bands->next->data; b3 = (StatusviewBand *) bands->next->next->data; set_glabel( b1->val, "%g", r ); set_glabel( b2->val, "%g", g ); set_glabel( b3->val, "%g", b ); } } /* Sub-fn of below. Remake a band in the bar. */ static void * statusview_mouse_band( StatusviewBand *svb, void *e ) { Imagemodel *imagemodel = svb->sv->imagemodel; Conversion *conv = imagemodel->conv; REGION *reg = conv->reg; IMAGE *im = reg->im; /* Generate string for contents of band element. */ if( im->Coding == IM_CODING_NONE ) switch( im->BandFmt ) { case IM_BANDFMT_UCHAR: set_glabel( svb->val, "%d", ((unsigned char *)e)[svb->bandno] ); break; case IM_BANDFMT_CHAR: set_glabel( svb->val, "%d", ((char *)e)[svb->bandno] ); break; case IM_BANDFMT_USHORT: set_glabel( svb->val, "%d", ((unsigned short *)e)[svb->bandno] ); break; case IM_BANDFMT_SHORT: set_glabel( svb->val, "%d", ((short *)e)[svb->bandno] ); break; case IM_BANDFMT_UINT: set_glabel( svb->val, "%u", ((unsigned int *)e)[svb->bandno] ); break; case IM_BANDFMT_INT: set_glabel( svb->val, "%d", ((int *)e)[svb->bandno] ); break; case IM_BANDFMT_FLOAT: set_glabel( svb->val, "%g", ((float *)e)[svb->bandno] ); break; case IM_BANDFMT_COMPLEX: set_glabel( svb->val, "(%g,%g)", ((float *)e)[svb->bandno << 1], ((float *)e)[(svb->bandno << 1) + 1] ); break; case IM_BANDFMT_DOUBLE: set_glabel( svb->val, "%g", ((double *)e)[svb->bandno] ); break; case IM_BANDFMT_DPCOMPLEX: set_glabel( svb->val, "(%g,%g)", ((double *)e)[svb->bandno << 1], ((double *)e)[(svb->bandno << 1) + 1] ); break; default: set_glabel( svb->val, "???" ); break; } else set_glabel( svb->val, "???" ); return( NULL ); } void statusview_mouse( Statusview *sv, int x, int y ) { Imagemodel *imagemodel = sv->imagemodel; Conversion *conv = imagemodel->conv; IMAGE *im = imageinfo_get( FALSE, conv->ii ); REGION *reg = conv->reg; double dx, dy; x = IM_CLIP( 0, x, conv->underlay.width - 1 ); y = IM_CLIP( 0, y, conv->underlay.height - 1 ); /* Calculate x/y pos we display. */ dx = x; dy = y; if( imagemodel->rulers_offset ) { dx -= im->Xoffset; dy -= im->Yoffset; } if( imagemodel->rulers_mm ) { dx /= im->Xres; dy /= im->Yres; } set_glabel( sv->pos, "(%5g, %5g)", dx, dy ); /* Update value list. */ if( reg ) { if( reg->im->Coding == IM_CODING_LABQ ) statusview_mouse_LABPACK( sv, x, y ); else if( reg->im->Coding == IM_CODING_RAD ) statusview_mouse_RAD( sv, x, y ); else slist_map( sv->bands, (SListMapFn) statusview_mouse_band, get_element( reg, x, y, 0 ) ); } } nip2-8.7.1/src/reduce.h0000644000175000017500000001563413351443023011536 00000000000000/* Header for reduction machine. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Huge :-( this pushes sizeof(Reduce) up to 14MB. But we need to be able to * loop down very long lists, eg. for a 65k x 3 LUT held as a Matrix. Drop * this down when we represent matricies more sensibly. */ #define SPINE_SIZE (80000) /* Reduction machine state. Not very opaque ... see mark_reduce() */ struct _Reduce { /* Stack of heap nodes for spine. */ HeapNode *nstack[SPINE_SIZE]; /* Index of free element above node stack top. */ int sp; /* Frame stack ... top of fstack is sp we block GET above. */ int fstack[SPINE_SIZE]; /* Writeback stack ... where the result of each frame goes. */ PElement wbstack[SPINE_SIZE]; /* Frame stack pointer. */ int fsp; /* Heap we evaluate. */ Heap *heap; /* Nested reductions ... need to be able to longjmp() out of stuff, * and restore the machine state. */ int running; jmp_buf error[SPINE_SIZE]; int sps[SPINE_SIZE]; int fsps[SPINE_SIZE]; int tsp[SPINE_SIZE]; }; #define RSPUSH(RC,N) { \ if( (RC)->sp == SPINE_SIZE ) { \ error_top( _( "Stack overflow." ) ); \ error_sub( _( "Spine stack overflow, runaway recursion?" ) ); \ reduce_throw( (RC) ); \ } \ else \ (RC)->nstack[(RC)->sp++]=(N); \ } /* Number of items in current frame. */ #define RSFRAMESIZE(RC) ((RC)->sp - (RC)->fstack[(RC)->fsp - 1]) /* Check for at least N args present. */ #define RSCHECKARGS(RC,N) (RSFRAMESIZE(RC) >= (N)) /* Frame is empty? */ #define RSFRAMEEMPTY(RC) (RSFRAMESIZE(RC) == 0) /* Get offset from stack top, offset 0 is top item. */ #define RSGET(RC,N) ((RC)->nstack[(RC)->sp - ((N) + 1)]) /* Get the writeback for this frame. */ #define RSGETWB(RC) ((RC)->wbstack[(RC)->fsp - 1]) #define RSPUSHFRAME(RC,OUT) { \ if( (RC)->fsp == SPINE_SIZE ) { \ error_top( _( "Stack overflow." ) ); \ error_sub( _( "Frame stack overflow, " \ "expression too complex." ) ); \ reduce_throw( (RC) ); \ } \ else { \ (RC)->wbstack[(RC)->fsp] = *out; \ (RC)->fstack[(RC)->fsp] = (RC)->sp; \ (RC)->fsp++; \ } \ } #define RSPOPFRAME(RC) { \ if( (RC)->fsp == 0 ) { \ error_top( _( "Stack underflow." ) ); \ error_sub( _( "Frame stack underflow, you've found a bug!" ) ); \ reduce_throw( (RC) ); \ } \ else { \ (RC)->fsp--; \ (RC)->sp = (RC)->fstack[(RC)->fsp]; \ } \ } #define RSPOP(RC,N) { \ if( !RSCHECKARGS(RC,N) ) { \ error_top( _( "Stack underflow." ) ); \ error_sub( _( "Spine stack underflow, you've found a bug!" ) ); \ reduce_throw( (RC) ); \ } \ else \ (RC)->sp -= (N); \ } /* Pop this code before any calls to reduce_*() to init stuff and catch * errors. Arg is function return value. The missing running decrement is done * by throw(). */ #define REDUCE_CATCH_START( R ) \ { \ rc->sps[rc->running] = rc->sp; \ rc->fsps[rc->running] = rc->fsp; \ rc->tsp[rc->running] = trace_get_mark(); \ if( setjmp( rc->error[rc->running++] ) ) { \ g_assert( rc->running >= 0 ); \ rc->sp = rc->sps[rc->running]; \ rc->fsp = rc->fsps[rc->running]; \ trace_pop_to( rc->tsp[rc->running] ); \ return( (R) ); \ } \ } /* After any calls to reduce_*(). */ #define REDUCE_CATCH_STOP \ { \ rc->running -= 1; \ g_assert( rc->running >= 0 ); \ } /* Util. */ void reduce_throw( Reduce *rc ) __attribute__((noreturn)); typedef void *(*reduce_safe_pointer_fn)( Reduce *rc, PElement *, void *, void *, void *, void * ); void *reduce_safe_pointer( Reduce *rc, reduce_safe_pointer_fn fn, void *a, void *b, void *c, void *d ); void reduce_get_list( Reduce *rc, PElement *list ); void reduce_error_typecheck( Reduce *rc, PElement *e, const char *name, const char *type ); typedef void *(*reduce_map_list_fn)( Reduce *rc, PElement *, void *, void * ); void *reduce_map_list( Reduce *rc, PElement *base, reduce_map_list_fn fn, void *a, void *b ); typedef void *(*reduce_map_dict_fn)( Reduce *, const char *, PElement *, void *a, void *b ); void *reduce_map_dict( Reduce *rc, PElement *base, reduce_map_dict_fn fn, void *a, void *b ); void reduce_clone_list( Reduce *rc, PElement *base, PElement *out ); int reduce_get_string( Reduce *rc, PElement *base, char *buf, int n ); int reduce_get_lstring( Reduce *rc, PElement *base, GSList **labels ); gboolean reduce_get_bool( Reduce *rc, PElement *base ); double reduce_get_real( Reduce *rc, PElement *base ); void reduce_get_class( Reduce *rc, PElement *base ); Imageinfo *reduce_get_image( Reduce *rc, PElement *base ); int reduce_get_realvec( Reduce *rc, PElement *base, double *buf, int n ); int reduce_get_imagevec( Reduce *rc, PElement *base, Imageinfo **buf, int n ); int reduce_get_matrix( Reduce *rc, PElement *base, double *buf, int n, int *xsize, int *ysize ); void reduce_get_matrix_size( Reduce *rc, PElement *base, int *xsize, int *ysize ); gboolean reduce_is_elist( Reduce *rc, PElement *base ); gboolean reduce_is_list( Reduce *rc, PElement *base ); gboolean reduce_is_string( Reduce *rc, PElement *base ); gboolean reduce_is_finitestring( Reduce *rc, PElement *base ); gboolean reduce_is_realvec( Reduce *rc, PElement *base ); gboolean reduce_is_imagevec( Reduce *rc, PElement *base ); gboolean reduce_is_matrix( Reduce *rc, PElement *base ); gboolean reduce_is_class( Reduce *rc, PElement *klass ); int reduce_list_length( Reduce *rc, PElement *base ); int reduce_list_length_max( Reduce *rc, PElement *base, int max_length ); void reduce_list_index( Reduce *rc, PElement *base, int n, PElement *out ); gboolean reduce_is_instanceof_exact( Reduce *rc, const char *name, PElement *instance ); gboolean reduce_is_instanceof( Reduce *rc, const char *name, PElement *instance ); /* Main. */ extern Reduce *reduce_context; extern int reduce_total_recomputations; void reduce_destroy( Reduce *rc ); Reduce *reduce_new( void ); gboolean reduce_regenerate( Expr *expr, PElement *out ); gboolean reduce_regenerate_member( Expr *expr, PElement *ths, PElement *out ); void reduce_spine( Reduce *rc, PElement *out ); void reduce_spine_strict( Reduce *rc, PElement *out ); gboolean reduce_pelement( Reduce *, ReduceFunction fn, PElement *out ); /* Register and unregister values. */ void reduce_register( Symbol *sym ); void reduce_unregister( Symbol *sym ); nip2-8.7.1/src/prefs.c0000644000175000017500000001273713351443023011402 00000000000000/* preferences dialog */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static iDialogClass *parent_class = NULL; static void prefs_destroy( GtkObject *object ) { Prefs *prefs = PREFS( object ); #ifdef DEBUG printf( "prefs_destroy\n" ); #endif /*DEBUG*/ if( prefs->ws ) { Workspacegroup *wsg = workspace_get_workspacegroup( prefs->ws ); Filemodel *filemodel = FILEMODEL( wsg ); /* Force a recalc, in case we've changed the autorecalc * settings. Also does a scan on any widgets. */ symbol_recalculate_all_force( TRUE ); if( filemodel->modified && filemodel_top_save( filemodel, filemodel->filename ) ) filemodel_set_modified( filemodel, FALSE ); } /* My instance destroy stuff. */ FREESID( prefs->destroy_sid, prefs->ws ); IM_FREE( prefs->caption_filter ); prefs->ws = NULL; GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void prefs_build( GtkWidget *widget ) { Prefs *prefs = PREFS( widget ); GtkWidget *work; #ifdef DEBUG printf( "prefs_build: %p\n", prefs ); #endif /*DEBUG*/ /* Call all builds in superclasses. */ IWINDOW_CLASS( parent_class )->build( widget ); work = IDIALOG( prefs )->work; prefs->pwview = PREFWORKSPACEVIEW( prefworkspaceview_new() ); prefworkspaceview_set_caption_filter( prefs->pwview, prefs->caption_filter ); view_link( VIEW( prefs->pwview ), MODEL( prefs->ws ), NULL ); if( prefs->caption_filter ) { gtk_box_pack_start( GTK_BOX( work ), GTK_WIDGET( prefs->pwview ), TRUE, TRUE, 0 ); gtk_widget_show( GTK_WIDGET( prefs->pwview ) ); } else { /* No caption_filter set, so this is probably a big prefs * window. Build a scrolledwindow for the content. */ GtkWidget *window; window = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( window ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( window ), GTK_WIDGET( prefs->pwview ) ); gtk_viewport_set_shadow_type( GTK_VIEWPORT( GTK_BIN( window )->child ), GTK_SHADOW_NONE ); gtk_box_pack_start( GTK_BOX( work ), GTK_WIDGET( window ), TRUE, TRUE, 0 ); gtk_widget_show( GTK_WIDGET( prefs->pwview ) ); gtk_widget_show( window ); } } static void prefs_class_init( PrefsClass *class ) { GtkObjectClass *gobject_class = (GtkObjectClass *) class; iWindowClass *iwindow_class = (iWindowClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->destroy = prefs_destroy; iwindow_class->build = prefs_build; /* Create signals. */ /* Init methods. */ } static void prefs_init( Prefs *prefs ) { prefs->ws = NULL; prefs->destroy_sid = 0; } GType prefs_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( PrefsClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) prefs_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Prefs ), 32, /* n_preallocs */ (GInstanceInitFunc) prefs_init, }; type = g_type_register_static( TYPE_IDIALOG, "Prefs", &info, 0 ); } return( type ); } static void prefs_workspace_destroy_cb( Workspace *ws, Prefs *prefs ) { prefs->destroy_sid = 0; prefs->ws = NULL; iwindow_kill( IWINDOW( prefs ) ); } static void prefs_link( Prefs *prefs, Workspace *ws ) { g_assert( !prefs->ws ); prefs->ws = ws; prefs->ws->mode = WORKSPACE_MODE_NOEDIT; prefs->destroy_sid = g_signal_connect( ws, "destroy", G_CALLBACK( prefs_workspace_destroy_cb ), prefs ); } static gint prefs_column_compare( Column *a, Column *b ) { return( b->y - a->y ); } Prefs * prefs_new( const char *caption_filter ) { Symbol *wsr_sym = main_workspaceroot->sym; Symbol *ws_sym = SYMBOL( icontainer_child_lookup( ICONTAINER( wsr_sym->expr->compile ), "Preferences" ) ); Prefs *prefs; if( !ws_sym ) { /* Probably failed to load prefs on startup for some reason. */ error_top( _( "Unable to display preferences." ) ); error_sub( _( "No preferences workspace was found. " "Preferences probably failed to load when " "%s started." ), PACKAGE ); return( NULL ); } icontainer_custom_sort( ICONTAINER( ws_sym->ws ), (GCompareFunc) prefs_column_compare ); prefs = PREFS( g_object_new( TYPE_PREFS, NULL ) ); IM_SETSTR( prefs->caption_filter, caption_filter ); prefs_link( prefs, ws_sym->ws ); return( prefs ); } gboolean prefs_set( const char *name, const char *fmt, ... ) { Watch *watch; if( main_watchgroup && (watch = watch_find( main_watchgroup, name )) ) { va_list args; va_start( args, fmt ); watch_vset( watch, fmt, args ); va_end( args ); } return( TRUE ); } nip2-8.7.1/src/makehelpindex.pl0000755000175000017500000000176613351443023013275 00000000000000#!/usr/bin/perl # html docs in $VIPSHOME/share/nip2/doc/html include extra anchor tags # generated from \mylabel{} stuff in doc src (nip2-xx/doc/src/nipguide) # # latex source # # \section{Image view window} # \mylabel{sec:view} # # generates html which includes # #
# # scan all html files in $VIPSHOME/share/nip2/doc/html for patterns like this, # and generate C along the lines of: # # { "sec:view", "node4.html#nip_label_sec:view" }, # # this is includes in boxes.c ... then on # # box_help( par, "sec:view" ) # # we can pop up a web browser pointing at the right place in the docs $prefix = @ARGV[0]; $docbase = "$prefix/share/doc/nip2/html"; opendir( SDIR, "$docbase" ); while( $filename = readdir SDIR ) { if( $filename =~ /.html$/ ) { open( HTMLFILE, "$docbase/$filename" ); while( ) { if( /"nip_label_([^"]*)"/ ) { print "{ \"$1\", \"$filename#nip_label_" . "$1\" },\n"; } } close( HTMLFILE ); } } closedir( SDIR ); nip2-8.7.1/src/managedgvalue.h0000644000175000017500000000344513351443023013064 00000000000000/* a managed gvalue */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_MANAGEDGVALUE (managedgvalue_get_type()) #define MANAGEDGVALUE( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGEDGVALUE, Managedgvalue )) #define MANAGEDGVALUE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_MANAGEDGVALUE, ManagedgvalueClass)) #define IS_MANAGEDGVALUE( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGEDGVALUE )) #define IS_MANAGEDGVALUE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGEDGVALUE )) #define MANAGEDGVALUE_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_MANAGEDGVALUE, ManagedgvalueClass )) struct _Managedgvalue { Managed parent_object; GValue value; }; typedef struct _ManagedgvalueClass { ManagedClass parent_class; } ManagedgvalueClass; GType managedgvalue_get_type( void ); void managedgvalue_set_value( Managedgvalue *managedgvalue, GValue *value ); Managedgvalue *managedgvalue_new( Heap *heap, GValue *value ); nip2-8.7.1/src/view.h0000644000175000017500000001112413351443023011227 00000000000000/* abstract base class for our UI widgets */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_VIEW (view_get_type()) #define VIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_VIEW, View )) #define VIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_VIEW, ViewClass )) #define IS_VIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_VIEW )) #define IS_VIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_VIEW )) #define VIEW_GET_CLASS( obj ) \ (GTK_CHECK_GET_CLASS( (obj), TYPE_VIEW, ViewClass )) /* We track all of the children of our model, listening to "changed", so we * can lazily add or remove child views of us as the model requests. */ typedef struct { View *parent_view; /* Us */ Model *child_model; /* The child we are watching */ guint child_model_changed_sid; /* Listen to "changed" on child here */ View *child_view; /* The child view for this model */ } ViewChild; struct _View { vObject parent_object; /* My instance vars. */ guint pos_changed_sid; /* Signals we use to watch iObject */ guint scrollto_sid; guint layout_sid; guint front_sid; guint reset_sid; guint child_add_sid; guint child_remove_sid; guint child_detach_sid; guint child_attach_sid; View *parent; /* Enclosing view (if any) */ GSList *managed; /* List of ViewChild for us */ gboolean scannable; /* On scannable list */ gboolean resettable; /* On resettable list */ }; typedef struct _ViewClass { vObjectClass parent_class; /* Create/destroy link this view is about to be linked to this model with this parent view child_add this view has just gained a child child_remove this view is about to lose a child child_position this child needs repositioning child_front pop this child to the front display should this child be displayed */ void (*link)( View *, Model *, View * ); void (*child_add)( View *parent, View *child ); void (*child_remove)( View *parent, View *child ); void (*child_position)( View *parent, View *child ); void (*child_front)( View *parent, View *child ); gboolean (*display)( View *parent, Model *child ); /* State change reset reset edit mode ... eg. text pops back to value display scan scan widgets, reading any new text off the display scrollto try to make this view visible layout try to lay children out */ void (*reset)( View * ); void *(*scan)( View * ); void (*scrollto)( View *, ModelScrollPosition ); void (*layout)( View * ); } ViewClass; void view_scannable_register( View *view ); void view_scannable_unregister( View *view ); gboolean view_scan_all( void ); void view_resettable_register( View *view ); void view_resettable_unregister( View *view ); void view_reset_all( void ); gboolean view_hasmodel( View *view ); void *view_model_test( View *child, Model *model ); GtkType view_get_type( void ); void view_link( View *view, Model *model, View *parent ); void view_unlink( View *view ); void view_child_add( View *parent, View *child ); void view_child_remove( View *child ); void view_child_position( View *child ); void view_child_front( View *child ); void *view_reset( View *view ); void *view_scan( View *view ); void *view_scrollto( View *view, ModelScrollPosition ); void *view_layout( View *view ); void *view_map( View *view, view_map_fn fn, void *a, void *b ); void *view_map_all( View *view, view_map_fn fn, void *a ); void view_save_as_cb( GtkWidget *menu, GtkWidget *host, View *view ); void view_save_cb( GtkWidget *menu, GtkWidget *host, View *view ); void view_close_cb( GtkWidget *menu, GtkWidget *host, View *view ); void view_activate_cb( View *view ); void view_changed_cb( View *view ); void view_not_implemented_cb( GtkWidget *menu, GtkWidget *host, View *view ); GtkWidget *view_get_toplevel( View *view ); Columnview *view_get_columnview( View *child ); void *view_resize( View *view ); nip2-8.7.1/src/workspacegroup.c0000644000175000017500000006012113351443023013324 00000000000000/* A set of workspaces loaded and saved from a ws file. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static FilemodelClass *parent_class = NULL; void workspacegroup_set_load_type( Workspacegroup *wsg, WorkspacegroupLoadType load_type ) { wsg->load_type = load_type; } void workspacegroup_set_save_type( Workspacegroup *wsg, WorkspacegroupSaveType save_type ) { wsg->save_type = save_type; } Workspace * workspacegroup_get_workspace( Workspacegroup *wsg ) { if( ICONTAINER( wsg )->current ) return( WORKSPACE( ICONTAINER( wsg )->current ) ); if( ICONTAINER( wsg )->children ) return( WORKSPACE( ICONTAINER( wsg )->children->data ) ); return( NULL ); } static Workspace * workspacegroup_workspace_pick( Workspacegroup *wsg ) { Workspace *ws; if( (ws = workspacegroup_get_workspace( wsg )) ) return( ws ); if( ICONTAINER( wsg )->children ) { ws = WORKSPACE( ICONTAINER( wsg )->children->data ); icontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) ); return( ws ); } ws = workspace_new_blank( wsg ); (void) workspace_column_pick( ws ); return( ws ); } Workspace * workspacegroup_map( Workspacegroup *wsg, workspace_map_fn fn, void *a, void *b ) { return( (Workspace *) icontainer_map( ICONTAINER( wsg ), (icontainer_map_fn) fn, a, b ) ); } static void * workspacegroup_is_empty_sub( Workspace *ws, gboolean *empty ) { if( !workspace_is_empty( ws ) ) { *empty = FALSE; return( ws ); } return( NULL ); } gboolean workspacegroup_is_empty( Workspacegroup *wsg ) { gboolean empty; empty = TRUE; (void) workspacegroup_map( wsg, (workspace_map_fn) workspacegroup_is_empty_sub, &empty, NULL ); return( empty ); } static void * workspacegroup_get_n_objects_sub( Workspace *ws, int *n_objects ) { Compile *compile = ws->sym->expr->compile; *n_objects += g_slist_length( ICONTAINER( compile )->children ); return( NULL ); } int workspacegroup_get_n_objects( Workspacegroup *wsg ) { int n_objects; n_objects = 0; workspacegroup_map( wsg, (workspace_map_fn) workspacegroup_get_n_objects_sub, &n_objects, NULL ); return( n_objects ); } static void workspacegroup_dispose( GObject *gobject ) { Workspacegroup *wsg; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_WORKSPACEGROUP( gobject ) ); wsg = WORKSPACEGROUP( gobject ); #ifdef DEBUG printf( "workspacegroup_dispose %s\n", IOBJECT( wsg )->name ); #endif /*DEBUG*/ IM_FREEF( g_source_remove, wsg->autosave_timeout ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static View * workspacegroup_view_new( Model *model, View *parent ) { return( workspacegroupview_new() ); } static void * workspacegroup_save_sub( iContainer *icontainer, void *a, void *b ) { Workspace *ws = WORKSPACE( icontainer ); xmlNode *xnode = (xmlNode *) a; Workspacegroup *wsg = WORKSPACEGROUP( b ); /* Only save all workspaces in save-all mode. */ if( wsg->save_type != WORKSPACEGROUP_SAVE_ALL && WORKSPACE( ICONTAINER( wsg )->current ) != ws ) return( NULL ); return( model_save( MODEL( ws ), xnode ) ); } static xmlNode * workspacegroup_save( Model *model, xmlNode *xnode ) { /* We normally chain up like this: * * xthis = MODEL_CLASS( parent_class )->save( model, xnode ) * * but that will make a workspacegroup holding our workspaces. Instead * we want to save all our workspaces directly to xnode with nothing * about us in there. * * See model_real_save(). */ if( icontainer_map( ICONTAINER( model ), workspacegroup_save_sub, xnode, model ) ) return( NULL ); return( xnode ); } /* Loops over xml trees follow this pattern. */ #define FOR_ALL_XML( ROOT, CHILD, CHILD_NAME ) { \ xmlNode *CHILD; \ \ for( CHILD = ROOT->children; CHILD; CHILD = CHILD->next ) { \ if( strcmp( (char *) CHILD->name, CHILD_NAME ) != 0 ) \ continue; #define FOR_ALL_XML_END } } static void workspacegroup_rename_workspace_node( Workspacegroup *wsg, ModelLoadState *state, xmlNode *xws ) { Workspaceroot *wsr = wsg->wsr; char name[MAX_STRSIZE]; char new_name[MAX_STRSIZE]; if( !get_sprop( xws, "name", name, MAX_STRSIZE ) ) return; strcpy( new_name, name ); while( compile_lookup( wsr->sym->expr->compile, new_name ) || model_loadstate_taken( state, new_name ) ) increment_name( new_name ); (void) set_sprop( xws, "name", new_name ); (void) model_loadstate_rename_new( state, name, new_name ); } /* Does a scrap of XML need compat defs? */ static gboolean workspacegroup_xml_needs_compat( ModelLoadState *state, xmlNode *xws, int *best_major, int *best_minor ) { int major; int minor; /* What version is the XML expecting? A combination of the version of * nip that saved the file, and any compat notes on the workspace XML */ if( !get_iprop( xws, "major", &major ) || !get_iprop( xws, "minor", &minor ) ) { /* Fall back to the version number in the xml header. */ major = state->major; minor = state->minor; } /* Find the best set of compat we have. */ return( workspace_have_compat( major, minor, best_major, best_minor ) ); } /* Load all workspaces into this wsg. */ static gboolean workspacegroup_load_new( Workspacegroup *wsg, ModelLoadState *state, xmlNode *xroot ) { Workspace *first_ws; /* Rename ... new names for any workspaces which clash. */ FOR_ALL_XML( xroot, xws, "Workspace" ) { workspacegroup_rename_workspace_node( wsg, state, xws ); } FOR_ALL_XML_END /* _front() the first ws we load. Needed for things like duplicate ws * and merge wses. */ first_ws = NULL; FOR_ALL_XML( xroot, xws, "Workspace" ) { char name[MAX_STRSIZE]; Workspace *ws; int major; int minor; column_set_offset( WORKSPACEVIEW_MARGIN_LEFT, WORKSPACEVIEW_MARGIN_TOP ); if( !get_sprop( xws, "name", name, FILENAME_MAX ) || !(ws = workspace_new( wsg, name )) ) return( FALSE ); if( workspacegroup_xml_needs_compat( state, xws, &major, &minor ) && !workspace_load_compat( ws, major, minor ) ) return( FALSE ); if( model_load( MODEL( ws ), state, MODEL( wsg ), xws ) ) return( FALSE ); if( !first_ws ) first_ws = ws; } FOR_ALL_XML_END if( first_ws ) icontainer_current( ICONTAINER( wsg ), ICONTAINER( first_ws ) ); return( TRUE ); } static void workspacegroup_rename_row_node( Workspace *ws, ModelLoadState *state, const char *col_name, xmlNode *xrow ) { char old_name[MAX_STRSIZE]; char new_name[MAX_STRSIZE]; if( !get_sprop( xrow, "name", old_name, MAX_STRSIZE ) ) return; im_snprintf( new_name, MAX_STRSIZE, "%s1", col_name ); while( compile_lookup( ws->sym->expr->compile, new_name ) || model_loadstate_taken( state, new_name ) ) increment_name( new_name ); (void) set_sprop( xrow, "name", new_name ); (void) model_loadstate_rename_new( state, old_name, new_name ); #ifdef DEBUG printf( "workspacegroup_rename_row_node: renaming " "'%s' to '%s'\n", old_name, new_name ); #endif } /* Rename column if there's one of that name in workspace. */ static void workspacegroup_rename_column_node( Workspacegroup *wsg, Workspace *ws, ModelLoadState *state, xmlNode *xcol ) { char name[MAX_STRSIZE]; char new_name[256]; if( !get_sprop( xcol, "name", name, MAX_STRSIZE ) ) return; im_strncpy( new_name, name, 256 ); while( workspace_column_find( ws, new_name ) || model_loadstate_column_taken( state, new_name ) ) workspace_column_name_new( ws, new_name ); if( strcmp( name, new_name ) != 0 ) { #ifdef DEBUG printf( "workspace_rename_column_node: renaming column " "%s to %s\n", name, new_name ); #endif /*DEBUG*/ (void) set_sprop( xcol, "name", new_name ); (void) model_loadstate_column_rename_new( state, name, new_name ); /* And allocate new names for all rows in the subcolumn. */ FOR_ALL_XML( xcol, xsub, "Subcolumn" ) { FOR_ALL_XML( xsub, xrow, "Row" ) { workspacegroup_rename_row_node( ws, state, new_name, xrow ); } FOR_ALL_XML_END } FOR_ALL_XML_END } } /* Load at column level ... rename columns which clash with * columns in the current workspace. Also look out for clashes * with columns we will load. */ static gboolean workspacegroup_load_columns( Workspacegroup *wsg, ModelLoadState *state, xmlNode *xroot ) { Workspace *ws = workspacegroup_workspace_pick( wsg ); int xml_major; int xml_minor; gboolean found; int ws_major; int ws_minor; /* Look for any compat problems. */ found = FALSE; FOR_ALL_XML( xroot, xws, "Workspace" ) { if( workspacegroup_xml_needs_compat( state, xws, &xml_major, &xml_minor ) ) { found = TRUE; break; } } FOR_ALL_XML_END workspace_get_version( ws, &ws_major, &ws_minor ); if( found && (xml_major != ws_major || xml_minor != ws_minor) ) { error_top( _( "Version mismatch." ) ); error_sub( _( "File \"%s\" needs version %d.%d. Merging " "into this tab may cause compatibility problems." ), state->filename, xml_major, xml_minor ); iwindow_alert( GTK_WIDGET( wsg->iwnd ), GTK_MESSAGE_INFO ); } /* Search all the columns we will load for their names and add rename * rules. */ FOR_ALL_XML( xroot, xws, "Workspace" ) { FOR_ALL_XML( xws, xcol, "Column" ) { workspacegroup_rename_column_node( wsg, ws, state, xcol ); } FOR_ALL_XML_END } FOR_ALL_XML_END /* Load those columns. */ FOR_ALL_XML( xroot, xws, "Workspace" ) { FOR_ALL_XML( xws, xcol, "Column" ) { if( !model_new_xml( state, MODEL( ws ), xcol ) ) return( FALSE ); } FOR_ALL_XML_END } FOR_ALL_XML_END return( TRUE ); } /* Load at row level ... merge into the current column. */ static gboolean workspacegroup_load_rows( Workspacegroup *wsg, ModelLoadState *state, xmlNode *xroot ) { Workspace *ws = workspacegroup_workspace_pick( wsg ); Column *col = workspace_column_pick( ws ); int xml_major; int xml_minor; gboolean found; int ws_major; int ws_minor; /* Look for any compat problems. */ found = FALSE; FOR_ALL_XML( xroot, xws, "Workspace" ) { if( workspacegroup_xml_needs_compat( state, xws, &xml_major, &xml_minor ) ) { found = TRUE; break; } } FOR_ALL_XML_END workspace_get_version( ws, &ws_major, &ws_minor ); if( found && (xml_major != ws_major || xml_minor != ws_minor) ) { error_top( _( "Version mismatch." ) ); error_sub( _( "File \"%s\" needs version %d.%d. Merging " "into this tab may cause compatibility problems." ), state->filename, xml_major, xml_minor ); iwindow_alert( GTK_WIDGET( wsg->iwnd ), GTK_MESSAGE_INFO ); } FOR_ALL_XML( xroot, xws, "Workspace" ) { FOR_ALL_XML( xws, xcol, "Column" ) { FOR_ALL_XML( xcol, xsub, "Subcolumn" ) { FOR_ALL_XML( xsub, xrow, "Row" ) { workspacegroup_rename_row_node( ws, state, IOBJECT( col )->name, xrow ); } FOR_ALL_XML_END } FOR_ALL_XML_END } FOR_ALL_XML_END } FOR_ALL_XML_END FOR_ALL_XML( xroot, xws, "Workspace" ) { FOR_ALL_XML( xws, xcol, "Column" ) { FOR_ALL_XML( xcol, xsub, "Subcolumn" ) { FOR_ALL_XML( xsub, xrow, "Row" ) { if( !model_new_xml( state, MODEL( col->scol ), xrow ) ) return( FALSE ); } FOR_ALL_XML_END } FOR_ALL_XML_END } FOR_ALL_XML_END } FOR_ALL_XML_END return( TRUE ); } static gboolean workspacegroup_top_load( Filemodel *filemodel, ModelLoadState *state, Model *parent, xmlNode *xroot ) { Workspacegroup *wsg = WORKSPACEGROUP( filemodel ); xmlNode *xnode; char name[FILENAME_MAX]; #ifdef DEBUG printf( "workspacegroup_top_load: from %s\n", state->filename ); #endif /*DEBUG*/ /* The top node should be the first workspace. Get the filename this * workspace was saved as so we can work out how to rewrite embedded * filenames. * * The filename field can be missing. */ if( (xnode = get_node( xroot, "Workspace" )) && get_sprop( xnode, "filename", name, FILENAME_MAX ) ) { char *new_dir; /* The old filename could be non-native, so we must rewrite * to native form first so g_path_get_dirname() can work. */ path_compact( name ); state->old_dir = g_path_get_dirname( name ); new_dir = g_path_get_dirname( state->filename_user ); path_rewrite_add( state->old_dir, new_dir, FALSE ); g_free( new_dir ); } switch( wsg->load_type ) { case WORKSPACEGROUP_LOAD_NEW: if( !workspacegroup_load_new( wsg, state, xroot ) ) return( FALSE ); break; case WORKSPACEGROUP_LOAD_COLUMNS: if( !workspacegroup_load_columns( wsg, state, xroot ) ) return( FALSE ); break; case WORKSPACEGROUP_LOAD_ROWS: if( !workspacegroup_load_rows( wsg, state, xroot ) ) return( FALSE ); break; default: g_assert( FALSE ); } return( FILEMODEL_CLASS( parent_class )->top_load( filemodel, state, parent, xnode ) ); } static gboolean workspacegroup_top_save( Filemodel *filemodel, const char *filename ) { gboolean result; #ifdef DEBUG printf( "workspacegroup_top_save: %s to %s\n", NN( IOBJECT( filemodel )->name ), filename ); #endif /*DEBUG*/ if( (result = FILEMODEL_CLASS( parent_class )-> top_save( filemodel, filename )) ) /* This will add save-as files to recent too. Don't note * auto_load on recent, since it won't have been loaded by the * user. */ if( !filemodel->auto_load ) mainw_recent_add( &mainw_recent_workspace, filename ); return( result ); } /* Backup the last WS_RETAIN workspaces. */ #define WS_RETAIN (10) /* Array of names of workspace files we are keeping. */ static char *retain_files[WS_RETAIN] = { NULL }; /* On safe exit, remove all ws checkmarks. */ void workspacegroup_autosave_clean( void ) { int i; for( i = 0; i < WS_RETAIN; i++ ) { if( retain_files[i] ) { unlinkf( "%s", retain_files[i] ); IM_FREE( retain_files[i] ); } } } /* Save the workspace to one of our temp files. */ static gboolean workspacegroup_checkmark_timeout( Workspacegroup *wsg ) { /* The next one we allocate. */ static int retain_next = 0; wsg->autosave_timeout = 0; if( !AUTO_WS_SAVE ) return( FALSE ); /* Don't backup auto loaded workspace (eg. preferences). These are * system things and don't need it. */ if( FILEMODEL( wsg )->auto_load ) return( FALSE ); /* Do we have a name for this retain file? */ if( !retain_files[retain_next] ) { char filename[FILENAME_MAX]; /* No name yet - make one up. */ if( !temp_name( filename, "ws" ) ) return( FALSE ); retain_files[retain_next] = im_strdup( NULL, filename ); } if( !filemodel_top_save( FILEMODEL( wsg ), retain_files[retain_next] ) ) return( FALSE ); retain_next = (retain_next + 1) % WS_RETAIN; return( FALSE ); } /* Save the workspace to one of our temp files. Don't save directly (pretty * slow), instead set a timeout and save when we're quiet for >1s. */ static void workspacegroup_checkmark( Workspacegroup *wsg ) { if( !AUTO_WS_SAVE ) return; if( FILEMODEL( wsg )->auto_load ) return; IM_FREEF( g_source_remove, wsg->autosave_timeout ); wsg->autosave_timeout = g_timeout_add( 1000, (GSourceFunc) workspacegroup_checkmark_timeout, wsg ); } typedef struct { /* Best so far filename. */ char filename[FILENAME_MAX]; /* Best-so-far file date. */ time_t time; } AutoRecover; /* This file any better than the previous best candidate? Subfn of below. */ static void * workspacegroup_test_file( const char *name, void *a, void *b, void *c ) { AutoRecover *recover = (AutoRecover *) a; char buf[FILENAME_MAX]; time_t time; int i; im_strncpy( buf, name, FILENAME_MAX ); path_expand( buf ); for( i = 0; i < WS_RETAIN; i++ ) if( retain_files[i] && strcmp( buf, retain_files[i] ) == 0 ) return( NULL ); if( !(time = mtime( "%s", buf )) ) return( NULL ); if( recover->time > 0 && time < recover->time ) return( NULL ); strcpy( recover->filename, buf ); recover->time = time; return( NULL ); } /* Search for the most recent "*.ws" file * in the tmp area owned by us, with a size > 0, that's not in our * retain_files[] set. */ char * workspacegroup_autosave_recover( void ) { AutoRecover recover; strcpy( recover.filename, "" ); recover.time = 0; (void) path_map_dir( PATH_TMP, "*.ws", (path_map_fn) workspacegroup_test_file, &recover ); if( !recover.time ) return( NULL ); return( g_strdup( recover.filename ) ); } static void workspacegroup_set_modified( Filemodel *filemodel, gboolean modified ) { Workspacegroup *wsg = WORKSPACEGROUP( filemodel ); workspacegroup_checkmark( wsg ); FILEMODEL_CLASS( parent_class )->set_modified( filemodel, modified ); } static void workspacegroup_class_init( WorkspacegroupClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; FilemodelClass *filemodel_class = (FilemodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->dispose = workspacegroup_dispose; iobject_class->user_name = _( "Workspace" ); /* ->load() is done by workspace_top_load(). */ model_class->view_new = workspacegroup_view_new; model_class->save = workspacegroup_save; filemodel_class->filetype = filesel_type_workspace; filemodel_class->top_load = workspacegroup_top_load; filemodel_class->top_save = workspacegroup_top_save; filemodel_class->set_modified = workspacegroup_set_modified; } static void workspacegroup_init( Workspacegroup *wsg ) { } GType workspacegroup_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( WorkspacegroupClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) workspacegroup_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Workspacegroup ), 32, /* n_preallocs */ (GInstanceInitFunc) workspacegroup_init, }; type = g_type_register_static( TYPE_FILEMODEL, "Workspacegroup", &info, 0 ); } return( type ); } static void workspacegroup_link( Workspacegroup *wsg, Workspaceroot *wsr ) { icontainer_child_add( ICONTAINER( wsr ), ICONTAINER( wsg ), -1 ); wsg->wsr = wsr; filemodel_register( FILEMODEL( wsg ) ); } Workspacegroup * workspacegroup_new( Workspaceroot *wsr ) { Workspacegroup *wsg; #ifdef DEBUG printf( "workspacegroup_new:\n" ); #endif /*DEBUG*/ wsg = WORKSPACEGROUP( g_object_new( TYPE_WORKSPACEGROUP, NULL ) ); /* Changed later. */ iobject_set( IOBJECT( wsg ), "untitled", _( "Empty workspace" ) ); workspacegroup_link( wsg, wsr ); filemodel_set_modified( FILEMODEL( wsg ), FALSE ); return( wsg ); } /* Make the blank workspacegroup we present the user with (in the absence of * anything else). */ Workspacegroup * workspacegroup_new_blank( Workspaceroot *wsr, const char *name ) { Workspacegroup *wsg; if( !(wsg = workspacegroup_new( wsr )) ) return( NULL ); iobject_set( IOBJECT( wsg ), name, NULL ); (void) workspacegroup_workspace_pick( wsg ); filemodel_set_modified( FILEMODEL( wsg ), FALSE ); return( wsg ); } Workspacegroup * workspacegroup_new_filename( Workspaceroot *wsr, const char *filename ) { Workspacegroup *wsg; char name[FILENAME_MAX]; if( !(wsg = workspacegroup_new( wsr )) ) return( NULL ); name_from_filename( filename, name ); iobject_set( IOBJECT( wsg ), name, _( "Default empty workspace" ) ); filemodel_set_filename( FILEMODEL( wsg ), filename ); filemodel_set_modified( FILEMODEL( wsg ), FALSE ); return( wsg ); } /* Load a file as a workspacegroup. */ Workspacegroup * workspacegroup_new_from_file( Workspaceroot *wsr, const char *filename, const char *filename_user ) { Workspacegroup *wsg; if( !(wsg = workspacegroup_new( wsr )) ) return( NULL ); workspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_NEW ); if( !filemodel_load_all( FILEMODEL( wsg ), MODEL( wsr ), filename, filename_user ) ) return( NULL ); filemodel_set_filename( FILEMODEL( wsg ), filename_user ); filemodel_set_modified( FILEMODEL( wsg ), FALSE ); if( filename_user ) { char name[FILENAME_MAX]; name_from_filename( filename_user, name ); iobject_set( IOBJECT( wsg ), name, NULL ); } else iobject_set( IOBJECT( wsg ), "untitled", NULL ); return( wsg ); } /* New workspacegroup from a file. */ Workspacegroup * workspacegroup_new_from_openfile( Workspaceroot *wsr, iOpenFile *of ) { Workspacegroup *wsg; char name[FILENAME_MAX]; #ifdef DEBUG printf( "workspacegroup_new_from_openfile: %s\n", of->fname ); #endif /*DEBUG*/ if( !(wsg = workspacegroup_new( wsr )) ) return( NULL ); workspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_NEW ); if( !filemodel_load_all_openfile( FILEMODEL( wsg ), MODEL( wsr ), of ) ) { g_object_unref( G_OBJECT( wsg ) ); return( NULL ); } filemodel_set_filename( FILEMODEL( wsg ), of->fname ); filemodel_set_modified( FILEMODEL( wsg ), FALSE ); name_from_filename( of->fname, name ); iobject_set( IOBJECT( wsg ), name, NULL ); return( wsg ); } /* Merge into workspacegroup as a set of new workspaces. */ gboolean workspacegroup_merge_workspaces( Workspacegroup *wsg, const char *filename ) { workspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_NEW ); if( !filemodel_load_all( FILEMODEL( wsg ), MODEL( wsg->wsr ), filename, NULL ) ) return( FALSE ); filemodel_set_modified( FILEMODEL( wsg ), TRUE ); return( TRUE ); } /* Merge into the current workspace as a set of columns. */ gboolean workspacegroup_merge_columns( Workspacegroup *wsg, const char *filename ) { Workspace *ws; if( (ws = workspacegroup_get_workspace( wsg )) ) /* We'll do a layout after load, so just load to a huge x and * we'll be OK. */ column_set_offset( 2 * IM_RECT_RIGHT( &ws->area ) + WORKSPACEVIEW_MARGIN_LEFT, WORKSPACEVIEW_MARGIN_TOP ); workspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_COLUMNS ); if( !filemodel_load_all( FILEMODEL( wsg ), MODEL( wsg->wsr ), filename, NULL ) ) return( FALSE ); filemodel_set_modified( FILEMODEL( wsg ), TRUE ); return( TRUE ); } /* Merge into the current workspace as a set of rows. */ gboolean workspacegroup_merge_rows( Workspacegroup *wsg, const char *filename ) { workspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_ROWS ); if( !filemodel_load_all( FILEMODEL( wsg ), MODEL( wsg->wsr ), filename, NULL ) ) return( FALSE ); filemodel_set_modified( FILEMODEL( wsg ), TRUE ); return( TRUE ); } /* Save just the selected objects in the current workspace. */ gboolean workspacegroup_save_selected( Workspacegroup *wsg, const char *filename ) { workspacegroup_set_save_type( wsg, WORKSPACEGROUP_SAVE_SELECTED ); if( !filemodel_top_save( FILEMODEL( wsg ), filename ) ) { unlinkf( "%s", filename ); return( FALSE ); } return( TRUE ); } /* Save just the current workspace. */ gboolean workspacegroup_save_current( Workspacegroup *wsg, const char *filename ) { workspacegroup_set_save_type( wsg, WORKSPACEGROUP_SAVE_WORKSPACE ); if( !filemodel_top_save( FILEMODEL( wsg ), filename ) ) { unlinkf( "%s", filename ); return( FALSE ); } return( TRUE ); } /* Save an entire workspacegroup. */ gboolean workspacegroup_save_all( Workspacegroup *wsg, const char *filename ) { workspacegroup_set_save_type( wsg, WORKSPACEGROUP_SAVE_ALL ); if( !filemodel_top_save( FILEMODEL( wsg ), filename ) ) { unlinkf( "%s", filename ); return( FALSE ); } return( TRUE ); } Workspacegroup * workspacegroup_duplicate( Workspacegroup *wsg ) { Workspaceroot *wsr = wsg->wsr; Workspacegroup *new_wsg; char filename[FILENAME_MAX]; if( !temp_name( filename, "ws" ) || !workspacegroup_save_all( wsg, filename ) ) return( NULL ); if( !(new_wsg = workspacegroup_new_from_file( wsr, filename, FILEMODEL( wsg )->filename )) ) { unlinkf( "%s", filename ); return( NULL ); } unlinkf( "%s", filename ); return( new_wsg ); } nip2-8.7.1/src/floatwindow.h0000644000175000017500000000320013351443023012606 00000000000000/* abstract base class for imageview / plotwindow etc. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_FLOATWINDOW (floatwindow_get_type()) #define FLOATWINDOW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_FLOATWINDOW, Floatwindow )) #define FLOATWINDOW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_FLOATWINDOW, FloatwindowClass )) #define IS_FLOATWINDOW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FLOATWINDOW )) #define IS_FLOATWINDOW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_FLOATWINDOW )) typedef struct _Floatwindow { iWindow parent_class; /* Model stuff here. */ Model *model; } Floatwindow; typedef struct _FloatwindowClass { iWindowClass parent_class; /* My methods. */ } FloatwindowClass; GtkType floatwindow_get_type( void ); void floatwindow_link( Floatwindow *floatwindow, Model *model ); nip2-8.7.1/src/iarrow.h0000644000175000017500000000324213351443023011562 00000000000000/* a ip region class in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IARROW (iarrow_get_type()) #define IARROW( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IARROW, iArrow )) #define IARROW_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IARROW, iArrowClass)) #define IS_IARROW( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IARROW )) #define IS_IARROW_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IARROW )) #define IARROW_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IARROW, iArrowClass )) struct _iArrow { Classmodel parent_class; /* Class fields. */ iRegionInstance instance; /* Private ... build iobject caption here. */ VipsBuf caption_buffer; }; typedef struct _iArrowClass { ClassmodelClass parent_class; /* My methods. */ } iArrowClass; GType iarrow_get_type( void ); nip2-8.7.1/src/gtkutil.h0000644000175000017500000001265013351443023011745 00000000000000/* Declarations supporting gtkutil.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Look up an object's parent class dynamically. */ #define PARENT_CLASS_DYNAMIC( OBJECT ) \ (g_type_class_peek( \ g_type_parent( \ G_TYPE_FROM_INSTANCE( OBJECT ) ) )) /* Like G_CHECK_TYPE, but insist on an exact match. */ #define TYPE_EXACT( OBJECT, TYPE ) \ (G_TYPE_FROM_INSTANCE( OBJECT ) == (TYPE)) #define DESTROY_GTK( X ) { \ if( X ) { \ gtk_object_destroy( GTK_OBJECT( X ) ); \ (X) = NULL; \ } \ } void adjustments_set_value( GtkAdjustment *hadj, GtkAdjustment *vadj, float hval, float vval ); void *object_destroy( void *obj ); void *null_g_free( void *obj ); const char *object_type_name( GtkObject *obj ); void widget_visible( GtkWidget *widget, gboolean visible ); /* Make widgets. */ GtkWidget *build_button( const char *name, GtkSignalFunc cb, gpointer user ); void get_geo( GtkWidget *widget, const char *text, Rect *geo ); void set_fixed( GtkWidget *widget, int nchars ); GtkWidget *build_entry( int nchars ); GtkWidget *menu_build( const char *name ); GtkWidget *menu_add_but( GtkWidget *menu, const char *name, GtkSignalFunc cb, void *user ); GtkWidget *menu_add_tog( GtkWidget *menu, const char *name, GtkSignalFunc cb, void *user ); GtkWidget *menu_add_sep( GtkWidget *menu ); GtkWidget *menu_add_pullright( GtkWidget *popup, const char *name ); /* Popup menu handling. */ typedef void (*PopupFunc)( GtkWidget *, GtkWidget *, void * ); #define POPUP_FUNC( fn ) ((PopupFunc) (fn)) GtkWidget *popup_build( const char *name ); GtkWidget *popup_add_but( GtkWidget *, const char *, PopupFunc ); GtkWidget *popup_add_tog( GtkWidget *, const char *, PopupFunc ); GtkWidget *popup_add_pullright( GtkWidget *popup, const char *name ); void popup_show( GtkWidget *host, GdkEvent *ev ); void popup_link( GtkWidget *host, GtkWidget *popup, void *data ); guint popup_attach( GtkWidget *host, GtkWidget *popup, void *data ); void popup_detach( GtkWidget *host, guint sid ); void set_tooltip( GtkWidget *wid, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); void junk_tooltips( void ); typedef void (*TooltipGenerateFn)( GtkWidget *, VipsBuf *, void *a, void *b ); void set_tooltip_generate( GtkWidget *widget, TooltipGenerateFn fn, void *a, void *b ); /* Set/get a label/entry, printf style. */ void set_gentryv( GtkWidget *edit, const char *fmt, va_list ap ); void set_gentry( GtkWidget *entry, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); void set_glabel( GtkWidget *label, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); void set_glabel1( GtkWidget *label, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); void set_gcaption( GtkWidget *label, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); gboolean get_geditable_string( GtkWidget *text, char *out, int sz ); gboolean get_geditable_name( GtkWidget *text, char *out, int sz ); gboolean get_geditable_filename( GtkWidget *text, char *out, int sz ); gboolean get_geditable_double( GtkWidget *text, double *out ); gboolean get_geditable_int( GtkWidget *text, int *n ); gboolean get_geditable_uint( GtkWidget *text, int *n ); gboolean get_geditable_pint( GtkWidget *text, int *n ); /* Make widget groups. */ GtkWidget *build_glabelframe2( GtkWidget *box, const char *label ); GtkWidget *build_glabeltext3( GtkWidget *box, const char *label ); GtkWidget *build_glabeltext4( GtkWidget *box, GtkSizeGroup *group, const char *label ); GtkWidget *build_gtoggle( GtkWidget *box, const char *caption ); GtkWidget *build_goption( GtkWidget *box, GtkSizeGroup *group, const char *name, const char *item_names[], int nitem, GtkSignalFunc fn, void *value ); typedef gboolean (*FiledropFunc)( void *client, const char *file ); void filedrop_register( GtkWidget *widget, FiledropFunc fn, void *client ); /* Tag our thumbnail drag-n-drops with these. Start up a bit to leave room for * filedrop. */ enum { TARGET_SYMBOL = 99 }; void set_symbol_drag_type( GtkWidget *widget ); void listen_add( GObject *gobject, GObject **zap, const char *name, GCallback gcallback ); void widget_update_pointer( GtkWidget *widget, GdkEvent *ev ); void *gobject_print( GObject *gobject ); int get_dpi( void ); GtkWidget *image_new_from_file( const char *name ); void vfatal( GError **error ); char *text_view_get_text( GtkTextView *text_view ); void text_view_set_text( GtkTextView *text_view, const char *text, gboolean editable ); void text_view_select_text( GtkTextView *text_view, int start, int end ); typedef void (*DestroyFn)( GObject * ); void destroy_if_destroyed( GObject *child, GObject *parent, DestroyFn destroy_fn ); void process_events( void ); nip2-8.7.1/src/watch.c0000644000175000017500000005513713415063137011377 00000000000000/* Watch stuff in the prefs workspace. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your watch) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static iContainerClass *watchgroup_parent_class = NULL; /* Our signals. */ enum { SIG_WATCH_CHANGED, /* "changed" on one of our watches */ SIG_LAST }; static guint watchgroup_signals[SIG_LAST] = { 0 }; static void watchgroup_changed( Watchgroup *watchgroup, Watch *watch ) { g_signal_emit( G_OBJECT( watchgroup ), watchgroup_signals[SIG_WATCH_CHANGED], 0, watch ); } static void watchgroup_class_init( WatchgroupClass *class ) { watchgroup_parent_class = g_type_class_peek_parent( class ); watchgroup_signals[SIG_WATCH_CHANGED] = g_signal_new( "watch_changed", G_OBJECT_CLASS_TYPE( class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( WatchgroupClass, watch_changed ), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, TYPE_WATCH ); } static void watchgroup_init( Watchgroup *watchgroup ) { #ifdef DEBUG printf( "watchgroup_init\n" ); #endif /*DEBUG*/ watchgroup->auto_save_timeout = 0; } GType watchgroup_get_type( void ) { static GType watchgroup_type = 0; if( !watchgroup_type ) { static const GTypeInfo info = { sizeof( WatchgroupClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) watchgroup_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Watchgroup ), 32, /* n_preallocs */ (GInstanceInitFunc) watchgroup_init, }; watchgroup_type = g_type_register_static( TYPE_ICONTAINER, "Watchgroup", &info, 0 ); } return( watchgroup_type ); } Watchgroup * watchgroup_new( Workspaceroot *workspaceroot, const char *name ) { Watchgroup *watchgroup = WATCHGROUP( g_object_new( TYPE_WATCHGROUP, NULL ) ); /* Assume it's a static string. */ watchgroup->name = name; watchgroup->workspaceroot = workspaceroot; icontainer_set_hash( ICONTAINER( watchgroup ) ); return( watchgroup ); } /* Get the ws we are storing prefs in, and check it looks OK. */ static Workspace * watchgroup_get_workspace( Watchgroup *watchgroup ) { Compile *compile; Symbol *sym; if( !watchgroup->workspaceroot->sym ) return( NULL ); compile = watchgroup->workspaceroot->sym->expr->compile; if( !(sym = compile_lookup( compile, watchgroup->name )) || !sym->expr->compile || sym->type != SYM_WORKSPACE || !sym->ws ) return( NULL ); return( sym->ws ); } static void watchgroup_save( Watchgroup *watchgroup ) { Workspace *ws; if( (ws = watchgroup_get_workspace( watchgroup )) ) { Workspacegroup *wsg = workspace_get_workspacegroup( ws ); Filemodel *filemodel = FILEMODEL( wsg ); if( filemodel->modified ) { symbol_recalculate_all(); /* Ignore error returns ... hmm! Tricky: we can come * here during shutdown. */ (void) filemodel_top_save( filemodel, filemodel->filename ); filemodel_set_modified( filemodel, FALSE ); } } } static gboolean watchgroup_dirty_timeout_cb( Watchgroup *watchgroup ) { watchgroup->auto_save_timeout = 0; watchgroup_save( watchgroup ); return( FALSE ); } void watchgroup_dirty( Watchgroup *watchgroup ) { Workspace *ws; /* Find the preferences workspace. */ if( (ws = watchgroup_get_workspace( watchgroup )) ) { Workspacegroup *wsg = workspace_get_workspacegroup( ws ); /* Mark ws dirty, start save timer. */ filemodel_set_modified( FILEMODEL( wsg ), TRUE ); IM_FREEF( g_source_remove, watchgroup->auto_save_timeout ); watchgroup->auto_save_timeout = g_timeout_add( 1000, (GSourceFunc) watchgroup_dirty_timeout_cb, watchgroup ); } } void watchgroup_flush( Watchgroup *watchgroup ) { /* Do we have a pending save? */ if( watchgroup->auto_save_timeout ) { watchgroup_save( watchgroup ); IM_FREEF( g_source_remove, watchgroup->auto_save_timeout ); } } static iContainerClass *watch_parent_class = NULL; static GSList *watch_all = NULL; static void watch_finalize( GObject *gobject ) { Watch *watch; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_WATCH( gobject ) ); watch = WATCH( gobject ); #ifdef DEBUG printf( "watch_finalize: %s\n", NN( IOBJECT( watch )->name ) ); #endif /*DEBUG*/ watch_all = g_slist_remove( watch_all, watch ); G_OBJECT_CLASS( watch_parent_class )->finalize( gobject ); } static void watch_dispose( GObject *gobject ) { Watch *watch; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_WATCH( gobject ) ); watch = WATCH( gobject ); #ifdef DEBUG printf( "watch_dispose: %s\n", NN( IOBJECT( watch )->name ) ); #endif /*DEBUG*/ /* My instance destroy stuff. */ FREESID( watch->destroy_sid, watch->row ); FREESID( watch->changed_sid, watch->row ); watch->row = NULL; G_OBJECT_CLASS( watch_parent_class )->dispose( gobject ); } static void watch_changed( iObject *iobject ) { Watch *watch = WATCH( iobject ); Watchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent ); /* Emit on our group too. Can get here before our parent is linked on, * careful. */ if( watchgroup ) watchgroup_changed( WATCHGROUP( ICONTAINER( watch )->parent ), watch ); IOBJECT_CLASS( watch_parent_class )->changed( iobject ); } static void watch_class_init( WatchClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; WatchClass *watch_class = (WatchClass *) class; watch_parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = watch_finalize; gobject_class->dispose = watch_dispose; iobject_class->changed = watch_changed; watch_class->update = NULL; watch_class->get_value = NULL; } static void watch_init( Watch *watch ) { watch->row = NULL; watch->ok = FALSE; watch->destroy_sid = 0; watch->changed_sid = 0; watch_all = g_slist_prepend( watch_all, watch ); } GType watch_get_type( void ) { static GType watch_type = 0; if( !watch_type ) { static const GTypeInfo info = { sizeof( WatchClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) watch_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Watch ), 32, /* n_preallocs */ (GInstanceInitFunc) watch_init, }; watch_type = g_type_register_static( TYPE_ICONTAINER, "Watch", &info, 0 ); } return( watch_type ); } static void watch_link( Watch *watch, Watchgroup *watchgroup, const char *name ) { iobject_set( IOBJECT( watch ), name, NULL ); icontainer_child_add( ICONTAINER( watchgroup ), ICONTAINER( watch ), -1 ); } static void watch_destroy_cb( Row *row, Watch *watch ) { #ifdef DEBUG printf( "watch_destroy_cb\n" ); #endif /*DEBUG*/ watch->row = NULL; watch->ok = FALSE; watch->destroy_sid = 0; watch->changed_sid = 0; } /* The row we are watching has changed. */ static void watch_changed_cb( Row *row, Watch *watch ) { #ifdef DEBUG printf( "watch_changed_cb: %s\n", NN( IOBJECT( watch )->name ) ); #endif /*DEBUG*/ if( row->expr ) watch->ok = WATCH_GET_CLASS( watch )->update( watch ); iobject_changed( IOBJECT( watch ) ); } /* Make sure we're linked to the thing we watch. */ static void watch_attach( Watch *watch ) { Watchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent ); const char *name = IOBJECT( watch )->name; Workspace *ws; Symbol *sym; if( watch->row ) return; if( (ws = watchgroup_get_workspace( watchgroup )) && ws->sym->expr && ws->sym->expr->compile && (sym = compile_lookup( ws->sym->expr->compile, name )) && sym->expr->row ) { watch->row = sym->expr->row; watch->destroy_sid = g_signal_connect( G_OBJECT( watch->row ), "destroy", G_CALLBACK( watch_destroy_cb ), watch ); watch->changed_sid = g_signal_connect( G_OBJECT( watch->row ), "changed", G_CALLBACK( watch_changed_cb ), watch ); } } Watch * watch_find( Watchgroup *watchgroup, const char *name ) { return( (Watch *) (icontainer_child_lookup( ICONTAINER( watchgroup ), name )) ); } static gboolean watch_get( Watch *watch, void **out ) { #ifdef DEBUG printf( "watch_get: %s\n", NN( IOBJECT( watch )->name ) ); #endif /*DEBUG*/ watch_attach( watch ); if( !watch->row ) return( FALSE ); if( !watch->ok ) watch->ok = WATCH_GET_CLASS( watch )->update( watch ); if( !watch->ok ) return( FALSE ); *out = WATCH_GET_CLASS( watch )->get_value( watch ); return( TRUE ); } static void * watch_relink( Watch *watch ) { if( !watch->row ) { watch_attach( watch ); if( watch->row ) iobject_changed( IOBJECT( watch ) ); } return( NULL ); } void watch_relink_all( void ) { slist_map( watch_all, (SListMapFn) watch_relink, NULL ); } void watch_vset( Watch *watch, const char *fmt, va_list args ) { Watchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent ); Workspace *ws; /* In case we try to set after prefs has gone. */ if( !(ws = watchgroup_get_workspace( watchgroup )) || ws->in_dispose ) return; if( watch->row && watch->row->child_rhs && watch->row->child_rhs->itext ) { iText *itext = ITEXT( watch->row->child_rhs->itext ); char buf[256]; (void) im_vsnprintf( buf, 256, fmt, args ); if( itext_set_formula( itext, buf ) ) { #ifdef DEBUG printf( "watch_vset: %s = %s\n", IOBJECT( watch )->name, buf ); #endif /*DEBUG*/ itext_set_edited( itext, TRUE ); if( watch->row->sym ) expr_dirty( watch->row->sym->expr, link_serial_new() ); watchgroup_dirty( WATCHGROUP( ICONTAINER( watch )->parent ) ); } } } void watch_set( Watch *watch, const char *fmt, ... ) { va_list args; va_start( args, fmt ); watch_vset( watch, fmt, args ); va_end( args ); } static WatchClass *watch_double_parent_class = NULL; static gboolean watch_double_update( Watch *watch ) { WatchDouble *watch_double = WATCH_DOUBLE( watch ); PElement *root = &watch->row->expr->root; #ifdef DEBUG printf( "watch_double_update\n" ); #endif /*DEBUG*/ if( PEISNOVAL( root ) ) return( FALSE ); if( !PEISREAL( root ) ) { heap_error_typecheck( root, IOBJECT( watch )->name, "real" ); return( FALSE ); } watch_double->value = PEGETREAL( root ); return( TRUE ); } static void * watch_double_get_value( Watch *watch ) { WatchDouble *watch_double = WATCH_DOUBLE( watch ); return( (void *) &watch_double->value ); } static void watch_double_class_init( WatchDoubleClass *class ) { WatchClass *watch_class = (WatchClass *) class; watch_double_parent_class = g_type_class_peek_parent( class ); watch_class->update = watch_double_update; watch_class->get_value = watch_double_get_value; } static void watch_double_init( WatchDouble *watch_double ) { #ifdef DEBUG printf( "watch_double_init\n" ); #endif /*DEBUG*/ watch_double->value = -1.0; } GType watch_double_get_type( void ) { static GType watch_double_type = 0; if( !watch_double_type ) { static const GTypeInfo info = { sizeof( WatchDoubleClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) watch_double_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( WatchDouble ), 32, /* n_preallocs */ (GInstanceInitFunc) watch_double_init, }; watch_double_type = g_type_register_static( TYPE_WATCH, "WatchDouble", &info, 0 ); } return( watch_double_type ); } static Watch * watch_double_new( Watchgroup *watchgroup, const char *name ) { WatchDouble *watch_double = WATCH_DOUBLE( g_object_new( TYPE_WATCH_DOUBLE, NULL ) ); watch_link( WATCH( watch_double ), watchgroup, name ); return( WATCH( watch_double ) ); } double watch_double_get( Watchgroup *watchgroup, const char *name, double fallback ) { Watch *watch; void *value; if( !watchgroup ) return( fallback ); if( !(watch = watch_find( watchgroup, name )) ) watch = watch_double_new( watchgroup, name ); g_assert( IS_WATCH_DOUBLE( watch ) ); if( !watch_get( watch, &value ) ) return( fallback ); return( *((double *) value) ); } static WatchClass *watch_int_parent_class = NULL; static gboolean watch_int_update( Watch *watch ) { WatchInt *watch_int = WATCH_INT( watch ); Expr *expr = watch->row->expr; PElement *root; #ifdef DEBUG printf( "watch_int_update: %s\n", NN( IOBJECT( watch )->name ) ); #endif /*DEBUG*/ /* Can get called during shutdown :-( main_watchgroup_changed_cb() can * call us before destroying the row, but after killing the expr. */ if( !expr ) return( FALSE ); root = &expr->root; if( PEISNOVAL( root ) ) return( FALSE ); if( !PEISREAL( root ) ) { heap_error_typecheck( root, IOBJECT( watch )->name, "real" ); return( FALSE ); } watch_int->value = IM_RINT( PEGETREAL( root ) ); return( TRUE ); } static void * watch_int_get_value( Watch *watch ) { WatchInt *watch_int = WATCH_INT( watch ); return( (void *) &watch_int->value ); } static void watch_int_class_init( WatchIntClass *class ) { WatchClass *watch_class = (WatchClass *) class; watch_int_parent_class = g_type_class_peek_parent( class ); watch_class->update = watch_int_update; watch_class->get_value = watch_int_get_value; } static void watch_int_init( WatchInt *watch_int ) { #ifdef DEBUG printf( "watch_int_init\n" ); #endif /*DEBUG*/ watch_int->value = -1; } GType watch_int_get_type( void ) { static GType watch_int_type = 0; if( !watch_int_type ) { static const GTypeInfo info = { sizeof( WatchIntClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) watch_int_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( WatchInt ), 32, /* n_preallocs */ (GInstanceInitFunc) watch_int_init, }; watch_int_type = g_type_register_static( TYPE_WATCH, "WatchInt", &info, 0 ); } return( watch_int_type ); } static Watch * watch_int_new( Watchgroup *watchgroup, const char *name ) { WatchInt *watch_int = WATCH_INT( g_object_new( TYPE_WATCH_INT, NULL ) ); watch_link( WATCH( watch_int ), watchgroup, name ); return( WATCH( watch_int ) ); } int watch_int_get( Watchgroup *watchgroup, const char *name, int fallback ) { Watch *watch; void *value; if( !watchgroup || !name ) return( fallback ); if( !(watch = watch_find( watchgroup, name )) ) watch = watch_int_new( watchgroup, name ); g_assert( IS_WATCH_INT( watch ) ); if( !watch_get( watch, &value ) ) return( fallback ); return( *((int *) value) ); } static WatchClass *watch_path_parent_class = NULL; static void watch_path_finalize( GObject *gobject ) { WatchPath *watch_path; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_WATCH_PATH( gobject ) ); #ifdef DEBUG printf( "watch_path_finalize\n" ); #endif /*DEBUG*/ watch_path = WATCH_PATH( gobject ); /* My instance destroy stuff. */ IM_FREEF( slist_free_all, watch_path->value ); G_OBJECT_CLASS( watch_path_parent_class )->finalize( gobject ); } static gboolean watch_path_update( Watch *watch ) { WatchPath *watch_path = WATCH_PATH( watch ); PElement *root = &watch->row->expr->root; GSList *value; #ifdef DEBUG printf( "watch_path_update\n" ); #endif /*DEBUG*/ if( !heap_get_lstring( root, &value ) ) return( FALSE ); IM_FREEF( slist_free_all, watch_path->value ); watch_path->value = value; return( TRUE ); } static void * watch_path_get_value( Watch *watch ) { WatchPath *watch_path = WATCH_PATH( watch ); return( (void *) &watch_path->value ); } static void watch_path_class_init( WatchPathClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; WatchClass *watch_class = (WatchClass *) class; watch_path_parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = watch_path_finalize; watch_class->update = watch_path_update; watch_class->get_value = watch_path_get_value; } static void watch_path_init( WatchPath *watch_path ) { #ifdef DEBUG printf( "watch_path_init\n" ); #endif /*DEBUG*/ watch_path->value = NULL; } GType watch_path_get_type( void ) { static GType watch_path_type = 0; if( !watch_path_type ) { static const GTypeInfo info = { sizeof( WatchPathClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) watch_path_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( WatchPath ), 32, /* n_preallocs */ (GInstanceInitFunc) watch_path_init, }; watch_path_type = g_type_register_static( TYPE_WATCH, "WatchPath", &info, 0 ); } return( watch_path_type ); } static Watch * watch_path_new( Watchgroup *watchgroup, const char *name ) { WatchPath *watch_path = WATCH_PATH( g_object_new( TYPE_WATCH_PATH, NULL ) ); watch_link( WATCH( watch_path ), watchgroup, name ); return( WATCH( watch_path ) ); } GSList * watch_path_get( Watchgroup *watchgroup, const char *name, GSList *fallback ) { Watch *watch; void *value; if( !watchgroup ) return( fallback ); if( !(watch = watch_find( watchgroup, name )) ) watch = watch_path_new( watchgroup, name ); g_assert( IS_WATCH_PATH( watch ) ); if( !watch_get( watch, &value ) ) return( fallback ); return( *((GSList **) value) ); } static WatchClass *watch_bool_parent_class = NULL; static gboolean watch_bool_update( Watch *watch ) { WatchBool *watch_bool = WATCH_BOOL( watch ); PElement *root = &watch->row->expr->root; #ifdef DEBUG printf( "watch_bool_update: %s\n", NN( IOBJECT( watch )->name ) ); #endif /*DEBUG*/ if( PEISNOVAL( root ) ) return( FALSE ); if( !PEISBOOL( root ) ) { heap_error_typecheck( root, IOBJECT( watch )->name, "bool" ); return( FALSE ); } watch_bool->value = PEGETBOOL( root ); return( TRUE ); } static void * watch_bool_get_value( Watch *watch ) { WatchBool *watch_bool = WATCH_BOOL( watch ); return( (void *) &watch_bool->value ); } static void watch_bool_class_init( WatchBoolClass *class ) { WatchClass *watch_class = (WatchClass *) class; watch_bool_parent_class = g_type_class_peek_parent( class ); watch_class->update = watch_bool_update; watch_class->get_value = watch_bool_get_value; } static void watch_bool_init( WatchBool *watch_bool ) { #ifdef DEBUG printf( "watch_bool_init\n" ); #endif /*DEBUG*/ watch_bool->value = FALSE; } GType watch_bool_get_type( void ) { static GType watch_bool_type = 0; if( !watch_bool_type ) { static const GTypeInfo info = { sizeof( WatchBoolClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) watch_bool_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( WatchBool ), 32, /* n_preallocs */ (GInstanceInitFunc) watch_bool_init, }; watch_bool_type = g_type_register_static( TYPE_WATCH, "WatchBool", &info, 0 ); } return( watch_bool_type ); } static Watch * watch_bool_new( Watchgroup *watchgroup, const char *name ) { WatchBool *watch_bool = WATCH_BOOL( g_object_new( TYPE_WATCH_BOOL, NULL ) ); watch_link( WATCH( watch_bool ), watchgroup, name ); return( WATCH( watch_bool ) ); } gboolean watch_bool_get( Watchgroup *watchgroup, const char *name, gboolean fallback ) { Watch *watch; void *value; if( !watchgroup ) return( fallback ); if( !(watch = watch_find( watchgroup, name )) ) watch = watch_bool_new( watchgroup, name ); g_assert( IS_WATCH_BOOL( watch ) ); if( !watch_get( watch, &value ) ) return( fallback ); return( *((gboolean *) value) ); } static WatchClass *watch_string_parent_class = NULL; static void watch_string_finalize( GObject *gobject ) { WatchString *watch_string; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_WATCH_STRING( gobject ) ); #ifdef DEBUG printf( "watch_string_finalize\n" ); #endif /*DEBUG*/ watch_string = WATCH_STRING( gobject ); /* My instance destroy stuff. */ IM_FREE( watch_string->value ); G_OBJECT_CLASS( watch_string_parent_class )->finalize( gobject ); } static gboolean watch_string_update( Watch *watch ) { WatchString *watch_string = WATCH_STRING( watch ); PElement *root = &watch->row->expr->root; char value[1024]; #ifdef DEBUG printf( "watch_string_update\n" ); #endif /*DEBUG*/ if( !heap_get_string( root, value, 1024 ) ) return( FALSE ); IM_SETSTR( watch_string->value, value ); return( TRUE ); } static void * watch_string_get_value( Watch *watch ) { WatchString *watch_string = WATCH_STRING( watch ); return( (void *) &watch_string->value ); } static void watch_string_class_init( WatchStringClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; WatchClass *watch_class = (WatchClass *) class; watch_string_parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = watch_string_finalize; watch_class->update = watch_string_update; watch_class->get_value = watch_string_get_value; } static void watch_string_init( WatchString *watch_string ) { #ifdef DEBUG printf( "watch_string_init\n" ); #endif /*DEBUG*/ watch_string->value = NULL; } GType watch_string_get_type( void ) { static GType watch_string_type = 0; if( !watch_string_type ) { static const GTypeInfo info = { sizeof( WatchStringClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) watch_string_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( WatchString ), 32, /* n_preallocs */ (GInstanceInitFunc) watch_string_init, }; watch_string_type = g_type_register_static( TYPE_WATCH, "WatchString", &info, 0 ); } return( watch_string_type ); } static Watch * watch_string_new( Watchgroup *watchgroup, const char *name ) { WatchString *watch_string = WATCH_STRING( g_object_new( TYPE_WATCH_STRING, NULL ) ); watch_link( WATCH( watch_string ), watchgroup, name ); return( WATCH( watch_string ) ); } const char * watch_string_get( Watchgroup *watchgroup, const char *name, const char *fallback ) { Watch *watch; void *value; if( !watchgroup ) return( fallback ); if( !(watch = watch_find( watchgroup, name )) ) watch = watch_string_new( watchgroup, name ); g_assert( IS_WATCH_STRING( watch ) ); if( !watch_get( watch, &value ) ) return( fallback ); return( *((const char **) value) ); } nip2-8.7.1/src/link.c0000644000175000017500000003415713351443023011220 00000000000000/* Links between top-level syms and the exprs which reference them */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define DEBUG_DIRTY */ #include "ip.h" void * link_expr_destroy( LinkExpr *le ) { GSList **llinks = le->dynamic ? &le->link->dynamic_links : &le->link->static_links; GSList **elinks = le->dynamic ? &le->expr->dynamic_links : &le->expr->static_links; #ifdef DEBUG printf( "link_expr_destroy: removing expr " ); symbol_name_print( le->expr->sym ); printf( "referencing link->child = " ); symbol_name_print( le->link->child ); printf( "\n" ); #endif /*DEBUG*/ *llinks = slist_remove_all( *llinks, le ); *elinks = slist_remove_all( *elinks, le ); im_free( le ); return( NULL ); } static LinkExpr * link_expr_new( Link *link, Expr *expr, gboolean dynamic ) { GSList **llinks = dynamic ? &link->dynamic_links : &link->static_links; GSList **elinks = dynamic ? &expr->dynamic_links : &expr->static_links; LinkExpr *le; g_assert( expr_get_root_dynamic( expr )->sym == link->parent ); #ifdef DEBUG printf( "link_expr_new: expr " ); symbol_name_print( expr->sym ); printf( "references link->child = " ); symbol_name_print( link->child ); printf( "\n" ); #endif /*DEBUG*/ if( !(le = INEW( NULL, LinkExpr )) ) return( NULL ); le->link = link; le->expr = expr; le->count = 1; le->dynamic = dynamic; *llinks = g_slist_prepend( *llinks, le ); *elinks = g_slist_prepend( *elinks, le ); return( le ); } /* Make a new serial number. */ int link_serial_new( void ) { static int serial = 0; return( serial++ ); } /* Fwd ref. */ static void *symbol_dirty_set( Symbol *sym ); /* child has become dirty ... update parent's dirty count. */ static void * link_dirty_child( Link *link ) { g_assert( link->parent->ndirtychildren >= 0 ); link->parent->ndirtychildren += 1; if( link->parent->ndirtychildren == 1 ) /* Parent had no dirty children ... it does now. */ symbol_dirty_set( link->parent ); symbol_state_change( link->parent ); return( NULL ); } /* link->parent no longer has link->child as a dirty child (cleaned or * removed) ... update counts. */ static void * link_clean_child( Link *link ) { Symbol *parent = link->parent; /* One fewer dirty children! */ parent->ndirtychildren--; g_assert( parent->ndirtychildren >= 0 ); /* Have we just cleaned the last dirty child of link->parent? If we * have and if link->parent has an error, clear the error so that * link->parent gets a chance to recalc. The new value of * link->child might fix the problem. */ if( parent->ndirtychildren == 0 ) expr_error_clear( parent->expr ); symbol_state_change( parent ); return( NULL ); } /* Junk a link. */ void * link_destroy( Link *link ) { #ifdef DEBUG printf( "link_destroy: destroying link from " ); symbol_name_print( link->parent ); printf( "to " ); symbol_name_print( link->child ); printf( "\n" ); #endif /*DEBUG*/ if( link->child->dirty ) (void) link_clean_child( link ); link->parent->topchildren = slist_remove_all( link->parent->topchildren, link ); link->child->topparents = slist_remove_all( link->child->topparents, link ); slist_map( link->static_links, (SListMapFn) link_expr_destroy, NULL ); slist_map( link->dynamic_links, (SListMapFn) link_expr_destroy, NULL ); im_free( link ); return( NULL ); } /* Make a new link. */ static Link * link_new( Symbol *child, Symbol *parent ) { Link *link; g_assert( is_top( parent ) && is_top( child ) ); g_assert( parent != child ); #ifdef DEBUG printf( "link_new: making link from " ); symbol_name_print( parent ); printf( "to " ); symbol_name_print( child ); printf( "\n" ); #endif /*DEBUG*/ if( !(link = INEW( NULL, Link )) ) return( NULL ); link->parent = parent; link->child = child; link->serial = 0; link->static_links = NULL; link->dynamic_links = NULL; parent->topchildren = g_slist_prepend( parent->topchildren, link ); child->topparents = g_slist_prepend( child->topparents, link ); /* If the new child is dirty, note it. */ if( child->dirty ) link_dirty_child( link ); return( link ); } static Link * link_find_child_sub( Link *link, Symbol *child ) { if( link->child == child ) return( link ); return( NULL ); } /* Look up connection between child and parent. */ static Link * link_find_child( Symbol *child, Symbol *parent ) { return( (Link *) slist_map( parent->topchildren, (SListMapFn) link_find_child_sub, child ) ); } static void * link_expr_find_expr_sub( LinkExpr *le, Expr *expr ) { if( le->expr == expr ) return( le ); return( NULL ); } /* Look up a linkexpr by expr. */ static LinkExpr * link_expr_find_expr( Link *link, Expr *expr, gboolean dynamic ) { GSList *links = dynamic ? link->dynamic_links : link->static_links; return( (LinkExpr *) slist_map( links, (SListMapFn) link_expr_find_expr_sub, expr ) ); } /* Add a reference from expr to child to the link graph. */ void * link_add( Symbol *child, Expr *expr, gboolean dynamic ) { Expr *parent = expr_get_root_dynamic( expr ); Link *link; LinkExpr *le; #ifdef DEBUG printf( "link_add: child = " ); symbol_name_print( child ); printf( "; expr = " ); expr_name_print( expr ); printf( "; dynamic = %s\n", bool_to_char( dynamic ) ); #endif /*DEBUG*/ g_assert( parent ); g_assert( parent->sym ); g_assert( is_top( child ) && is_top( parent->sym ) ); g_assert( child != parent->sym ); if( !(link = link_find_child( child, parent->sym )) ) { if( !(link = link_new( child, parent->sym )) ) return( child ); } if( !(le = link_expr_find_expr( link, expr, dynamic )) ) { if( !(le = link_expr_new( link, expr, dynamic )) ) return( child ); } else le->count++; return( NULL ); } /* Remove a ref from expr to child. */ void * link_remove( Symbol *child, Expr *expr, gboolean dynamic ) { Symbol *parent = expr_get_root_dynamic( expr )->sym; Link *link = link_find_child( child, parent ); LinkExpr *le = link_expr_find_expr( link, expr, dynamic ); g_assert( is_top( parent ) && is_top( child ) ); g_assert( parent != child ); g_assert( link ); le->count--; if( le->count == 0 ) { if( link_expr_destroy( le ) ) return( child ); } if( !link->static_links && !link->dynamic_links ) { if( link_destroy( link ) ) return( child ); } return( NULL ); } /* Is this a ref to a top-level? Add to link graph if it is. */ static void * link_children_expr_sub( Symbol *child, Expr *expr ) { if( is_top( child ) ) { Expr *root = expr_get_root_dynamic( expr ); /* Don't need to record recursive refs. */ if( root && root->sym && root->sym != child ) { if( link_add( child, expr, FALSE ) ) return( child ); } } return( NULL ); } /* Fwd. */ static void *link_children( Symbol *child, Symbol *parent ); /* Add any refs to top-level syms within this local to the * top-level sym we are within. */ static void * link_children_expr( Expr *expr, Symbol *parent ) { if( expr->compile ) { Compile *compile = expr->compile; /* Add refs which local makes directly. */ if( slist_map( compile->children, (SListMapFn) link_children_expr_sub, expr ) ) return( expr ); /* ... and recurse for sub-children. */ (void) icontainer_map( ICONTAINER( compile ), (icontainer_map_fn) link_children, parent, NULL ); } return( NULL ); } /* Add any refs to top-level syms within this local to the * top-level sym we are within. */ static void * link_children( Symbol *child, Symbol *parent ) { if( child->expr ) { if( link_children_expr( child->expr, parent ) ) return( child ); } return( NULL ); } /* row is editing sym's value ... add any dependancies the user has included * there. */ static void * link_row( Model *model, Symbol *parent ) { if( !IS_ROW( model ) || !ROW( model )->expr ) return( NULL ); /* Add any stuff in this row. */ return( link_children_expr( ROW( model )->expr, parent ) ); } static void * symbol_ndirty_sub( Link *link, int *nd ) { if( link->child->dirty ) *nd += 1; return( NULL ); } /* Count the number of dirty children. Used to generate initial leaf counts * and for assert() checking. */ int symbol_ndirty( Symbol *sym ) { int nd = 0; (void) slist_map( sym->topchildren, (SListMapFn) symbol_ndirty_sub, &nd ); return( nd ); } /* Fix a leaf count. */ void * symbol_fix_counts( Symbol *sym ) { #ifdef DEBUG int old_count = sym->ndirtychildren; #endif /*DEBUG*/ sym->ndirtychildren = symbol_ndirty( sym ); #ifdef DEBUG g_assert( sym->ndirtychildren == old_count ); #endif /*DEBUG*/ symbol_state_change( sym ); return( NULL ); } /* Junk all old links, static + dynamic. */ void symbol_link_destroy( Symbol *sym ) { (void) slist_map( sym->topchildren, (SListMapFn) link_destroy, NULL ); } /* Scan a symbol, remaking all the links. */ void symbol_link_build( Symbol *sym ) { g_assert( is_top( sym ) ); /* Make static links for our expr and all subexprs. If this symbol * is being edited, get stuff from the edited value. */ if( sym->expr ) { if( sym->expr->row ) (void) icontainer_map_all( ICONTAINER( sym->expr->row ), (icontainer_map_fn) link_row, sym ); else (void) link_children_expr( sym->expr, sym ); } #ifdef DEBUG printf( "symbol_link_build: " ); symbol_name_print( sym ); printf( "\n" ); dump_links( sym ); #endif /*DEBUG*/ } static void * link_dirty_set_sub( LinkExpr *le, int serial ) { return( expr_dirty( le->expr, serial ) ); } /* Mark exprs in parent dirty. These may be sub exprs, so parent is not * necessarily going to be symbol_dirty_set() ... eg. A2 may be displaying an * instance of class "fred", and we might have edited one of A2's members to * refer to A1 ... but A2 depends on A1, fred does not. */ static void * link_dirty_set( Link *link, int serial ) { /* Mark exprs in parent dirty. */ if( slist_map( link->static_links, (SListMapFn) link_dirty_set_sub, GINT_TO_POINTER( serial ) ) || slist_map( link->dynamic_links, (SListMapFn) link_dirty_set_sub, GINT_TO_POINTER( serial ) ) ) return( link ); return( NULL ); } /* Walk the link graph, marking stuff for recomputation ... link->child has * changed, mark link->parent dirty. */ static void * link_dirty_walk( Link *link, int serial ) { /* Have we walked down this link before? */ if( link->serial == serial ) return( NULL ); link->serial = serial; /* Mark all exprs in parent dirty. */ return( link_dirty_set( link, serial ) ); } /* A symbol has changed ... walk the link graph, marking stuff dirty as * required. We don't mark this sym dirty. */ void * symbol_dirty_intrans( Symbol *sym, int serial ) { g_assert( is_top( sym ) ); return( slist_map( sym->topparents, (SListMapFn) link_dirty_walk, GINT_TO_POINTER( serial ) ) ); } static void * symbol_dirty_set( Symbol *sym ) { g_assert( is_top( sym ) ); /* Clear error, to make sure we will recomp it. */ if( sym->expr ) expr_error_clear( sym->expr ); if( !sym->dirty ) { #ifdef DEBUG_DIRTY printf( "symbol_dirty_set: " ); symbol_name_print( sym ); printf( "(%p)\n", sym ); #endif /*DEBUG_DIRTY*/ /* Change of state. */ sym->dirty = TRUE; /* Update dirty counts on our parents. */ (void) slist_map( sym->topparents, (SListMapFn) link_dirty_child, NULL ); /* Note change in leaf set and display. */ symbol_state_change( sym ); } return( NULL ); } /* ... mark this one as well. */ void * symbol_dirty( Symbol *sym, int serial ) { g_assert( is_top( sym ) ); symbol_dirty_set( sym ); return( symbol_dirty_intrans( sym, serial ) ); } void * link_dirty_total( Link *link, int serial ) { static int recursion_depth = 0; /* Entering: note new recursion. */ if( recursion_depth++ > 1000 ) { error_top( _( "Circular dependency." ) ); error_sub( _( "Circular dependency detected near " "symbol \"%s\"." ), IOBJECT( link->parent )->name ); recursion_depth = 0; return( link ); } /* Mark this sub-tree as dirty. */ symbol_dirty( link->child, serial ); /* ... and repeat for any parents. */ if( link->child->type != SYM_ZOMBIE ) if( slist_map( link->child->topchildren, (SListMapFn) link_dirty_total, GINT_TO_POINTER( serial ) ) ) return( link ); /* Pop recursion measure. */ recursion_depth--; return( NULL ); } /* As above, but mark children as dirty as well. Used by force recalc to make * sure that everything is completely rebuilt. Be careful of cycles! */ void * symbol_dirty_total( Symbol *sym, int serial ) { if( sym->type == SYM_ZOMBIE ) return( NULL ); /* No children: just mark this sub-tree as dirty. */ if( !sym->topchildren && symbol_dirty( sym, serial ) ) return( sym ); if( slist_map( sym->topchildren, (SListMapFn) link_dirty_total, GINT_TO_POINTER( serial ) ) ) return( sym ); return( NULL ); } /* Mark a symbol as clean. Knock down the leaf count of the things which refer * to us ... one of them may turn into a leaf as a result. */ void * symbol_dirty_clear( Symbol *sym ) { g_assert( is_top( sym ) ); if( sym->dirty ) { #ifdef DEBUG_DIRTY printf( "symbol_dirty_clear: " ); symbol_name_print( sym ); printf( "(%p)\n", sym ); #endif /*DEBUG_DIRTY*/ /* Change of state. */ sym->dirty = FALSE; symbol_state_change( sym ); /* Update dirty counts on our parents. */ (void) slist_map( sym->topparents, (SListMapFn) link_clean_child, NULL ); } return( NULL ); } nip2-8.7.1/src/plotmodel.h0000644000175000017500000000362213351443023012260 00000000000000/* the model parts of a plot window .. all the window components watch this */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PLOTMODEL (plotmodel_get_type()) #define PLOTMODEL( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_PLOTMODEL, Plotmodel )) #define PLOTMODEL_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTMODEL, PlotmodelClass )) #define IS_PLOTMODEL( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTMODEL )) #define IS_PLOTMODEL_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTMODEL )) struct _Plotmodel { iObject parent_class; /* The class model we watch. */ Plot *plot; guint changed_sid; guint destroy_sid; /* The last canvas size we set ... stop resize loops with these. */ int width; int height; /* Viewer state. */ int mag; gboolean show_status; }; typedef struct _PlotmodelClass { iObjectClass parent_class; /* My methods. */ } PlotmodelClass; GtkType plotmodel_get_type( void ); Plotmodel *plotmodel_new( Plot *plot ); void plotmodel_set_mag( Plotmodel *plotmodel, int mag ); void plotmodel_set_status( Plotmodel *plotmodel, gboolean show_status ); nip2-8.7.1/src/tslider.h0000644000175000017500000000566613351443023011741 00000000000000/* A slider with an entry widget. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TSLIDER (tslider_get_type()) #define TSLIDER( obj ) (GTK_CHECK_CAST( (obj), TYPE_TSLIDER, Tslider )) #define TSLIDER_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_TSLIDER, TsliderClass )) #define IS_TSLIDER( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TSLIDER )) #define IS_TSLIDER_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_TSLIDER )) typedef double (*tslider_fn)( double from, double to, double value ); typedef struct _Tslider { GtkHBox parent_class; /* Our state. */ double from; double to; double value; /* Real value, as displayed in text */ double svalue; /* Slider value ... secret linear scale */ int digits; /* How many sf to display */ /* Keep last from/to/value settings here. Can't * use from/to since double and float don't compare reliably. */ double last_from, last_to, last_svalue; GtkWidget *entry; GtkWidget *slider; GtkAdjustment *adj; /* Optional functions ... how to make a value from a slider * position, how to make a slider position from a value. * If these are defined, text and slider are linked for you. */ gboolean auto_link; tslider_fn value_to_slider; tslider_fn slider_to_value; /* Ignore scroll events. In workspaces, we want the scroll-wheel to * just scroll the workspace and not adjust sliders. */ gboolean ignore_scroll; } Tslider; typedef struct _TsliderClass { GtkHBoxClass parent_class; void (*changed)( Tslider * ); /* from/to/value change */ void (*activate)( Tslider * ); /* enter in text */ void (*slider_changed)( Tslider * ); /* slider drag */ void (*text_changed)( Tslider * ); /* text has been touched */ } TsliderClass; void tslider_changed( Tslider * ); GtkType tslider_get_type( void ); Tslider *tslider_new( void ); void tslider_set_conversions( Tslider *tslider, tslider_fn value_to_slider, tslider_fn slider_to_value ); double tslider_log_value_to_slider( double from, double to, double value ); double tslider_log_slider_to_value( double from, double to, double value ); void tslider_set_ignore_scroll( Tslider *tslider, gboolean ignore_scroll ); nip2-8.7.1/src/class.h0000644000175000017500000001172313351443023011367 00000000000000/* Decls for class.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* The builtin member names we know about. */ #define MEMBER_BANDS "bands" #define MEMBER_CAPTION "caption" #define MEMBER_XCAPTION "xcaption" #define MEMBER_YCAPTION "ycaption" #define MEMBER_SERIES_CAPTIONS "series_captions" #define MEMBER_DISPLAY "display" #define MEMBER_CHECK "check" #define MEMBER_FILENAME "filename" #define MEMBER_FORMAT "format" #define MEMBER_FROM "from" #define MEMBER_HEIGHT "height" #define MEMBER_LABELS "labels" #define MEMBER_NAME "name" #define MEMBER_OFFSET "offset" #define MEMBER_SCALE "scale" #define MEMBER_SUPER "super" #define MEMBER_THIS "this" #define MEMBER_TO "to" #define MEMBER_VALUE "value" #define MEMBER_WIDTH "width" #define MEMBER_LEFT "left" #define MEMBER_TOP "top" #define MEMBER_IMAGE "image" #define MEMBER_OO_BINARY "oo_binary" #define MEMBER_OO_BINARY2 "oo_binary'" #define MEMBER_OO_UNARY "oo_unary" #define MEMBER_COLOUR_SPACE "colour_space" #define MEMBER_EXPR "expr" #define MEMBER_INTERVAL "interval" #define MEMBER_OPTIONS "options" #define MEMBER_VISLEVEL "_vislevel" #define MEMBER_ACTION "action" #define MEMBER_LABEL "label" #define MEMBER_ICON "icon" #define MEMBER_TOOLTIP "tooltip" /* The class names we know about. */ #define CLASS_SLIDER "Scale" #define CLASS_TOGGLE "Toggle" #define CLASS_IMAGE "Image" #define CLASS_COLOUR "Colour" #define CLASS_NUMBER "Number" #define CLASS_STRING "String" #define CLASS_OPTION "Option" #define CLASS_MATRIX "Matrix_vips" #define CLASS_ARROW "Arrow" #define CLASS_REGION "Region" #define CLASS_AREA "Area" #define CLASS_HGUIDE "HGuide" #define CLASS_VGUIDE "VGuide" #define CLASS_MARK "Mark" #define CLASS_POINT "Point" #define CLASS_PATHNAME "Pathname" #define CLASS_FONTNAME "Fontname" #define CLASS_SEPARATOR "Separator" #define CLASS_GROUP "Group" #define CLASS_LIST "List" #define CLASS_MENU "Menu" #define CLASS_MENUITEM "Menuitem" #define CLASS_MENUACTION "Menuaction" #define CLASS_MENUPULLRIGHT "Menupullright" #define CLASS_MENUSEPARATOR "Menuseparator" #define CLASS_EXPRESSION "Expression" #define CLASS_CLOCK "Clock" #define CLASS_REAL "Real" #define CLASS_VECTOR "Vector" #define CLASS_PLOT "Plot" /* What we loop over a class instance with. */ typedef void *(*class_map_fn)( Symbol *, PElement *, void *, void * ); Compile *class_get_compile( PElement *instance ); gboolean class_get_super( PElement *instance, PElement *out ); void *class_map( PElement *instance, class_map_fn fn, void *a, void *b ); gboolean class_get_member( PElement *instance, const char *name, Symbol **sym_out, PElement *value ); gboolean class_get_symbol( PElement *class, Symbol *sym, PElement *out ); gboolean class_get_exact( PElement *instance, const char *name, PElement *out ); gboolean class_new_super( Heap *heap, Compile *compile, PElement *this, PElement *instance ); gboolean class_new( Heap *heap, Compile *compile, HeapNode **args, PElement *out ); gboolean class_clone( Heap *heap, PElement *class, PElement *out ); gboolean class_clone_args( Heap *heap, PElement *klass, PElement *out ); gboolean class_newv( Heap *heap, const char *name, PElement *out, ... ); gboolean class_get_member_real( PElement *klass, const char *name, double *out ); gboolean class_get_member_int( PElement *instance, const char *name, int *out ); gboolean class_get_member_bool( PElement *klass, const char *name, gboolean *out ); gboolean class_get_member_image( PElement *instance, const char *name, Imageinfo **out ); gboolean class_get_member_class( PElement *instance, const char *name, const char *type, PElement *out ); gboolean class_get_member_lstring( PElement *instance, const char *name, GSList **labels ); gboolean class_get_member_string( PElement *klass, const char *name, char *buf, int sz ); gboolean class_get_member_instance( PElement *instance, const char *name, const char *klass, PElement *out ); gboolean class_get_member_matrix_size( PElement *instance, const char *name, int *xsize, int *ysize ); gboolean class_get_member_matrix( PElement *instance, const char *name, double *buf, int n, int *xsize, int *ysize ); gboolean class_get_member_realvec( PElement *instance, const char *name, double *buf, int n, int *length ); nip2-8.7.1/src/formula.h0000644000175000017500000000552013351443023011725 00000000000000/* display a caption/value label pair, on a click display the formula */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_FORMULA (formula_get_type()) #define FORMULA( obj ) (GTK_CHECK_CAST( (obj), \ TYPE_FORMULA, Formula )) #define FORMULA_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_FORMULA, FormulaClass )) #define IS_FORMULA( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FORMULA )) #define IS_FORMULA_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_FORMULA )) typedef struct _Formula { GtkEventBox parent_object; /* State. */ char *caption; char *value; char *expr; gboolean edit; /* In edit mode */ gboolean sensitive; /* Flick to edit on click */ gboolean changed; /* ->entry changed since we set it */ gboolean refresh_queued; /* Awaiting refresh */ gboolean needs_focus; /* Grab focus on refresh */ /* Widgets. */ GtkWidget *hbox; /* Container for our stuff */ GtkWidget *left_label; /* Caption label */ GtkWidget *right_label; /* Display value here */ GtkWidget *entry_frame; /* Frame edit text with this */ GtkWidget *entry; /* Edit formula here */ } Formula; typedef struct _FormulaClass { GtkEventBoxClass parent_class; /* My methods. */ void (*edit)( Formula * ); /* Formula has flicked to edit mode */ void (*changed)( Formula * ); /* Formula change */ void (*activate)( Formula * ); /* Pressed "Enter" key in formula */ void (*enter)( Formula * ); /* Highlight change */ void (*leave)( Formula * ); /* on eg. mouse enter/exit */ } FormulaClass; void formula_set_edit( Formula *formula, gboolean edit ); void formula_set_sensitive( Formula *formula, gboolean sensitive ); void formula_set_needs_focus( Formula *formula, gboolean needs_focus ); gboolean formula_scan( Formula *formula ); GType formula_get_type( void ); Formula *formula_new( void ); void formula_set_caption( Formula *formula, const char *caption ); void formula_set_value_expr( Formula *formula, const char *value, const char *expr ); nip2-8.7.1/src/toolkitbrowser.h0000644000175000017500000000404213351443023013347 00000000000000/* Toolkit browser */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TOOLKITBROWSER (toolkitbrowser_get_type()) #define TOOLKITBROWSER( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_TOOLKITBROWSER, Toolkitbrowser )) #define TOOLKITBROWSER_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_TOOLKITBROWSER, ToolkitbrowserClass )) #define IS_TOOLKITBROWSER( obj ) \ (GTK_CHECK_TYPE( (obj), TYPE_TOOLKITBROWSER )) #define IS_TOOLKITBROWSER_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKITBROWSER )) struct _Toolkitbrowser { vObject parent_object; Toolkitgroup *kitg; Workspace *ws; GtkListStore *store; /* Model for list view */ GtkTreeModel *filter; /* After filtering with search box */ GtkWidget *tree; /* Displayed tree */ GtkWidget *entry; /* Search widget */ GtkWidget *top; /* hbox for top bar */ }; typedef struct _ToolkitbrowserClass { vObjectClass parent_class; } ToolkitbrowserClass; GtkType toolkitbrowser_get_type( void ); void toolkitbrowser_set_mainw( Toolkitbrowser *toolkitbrowser, Mainw *mainw ); Toolkitbrowser *toolkitbrowser_new( void ); int toolkitbrowser_get_width( Toolkitbrowser *toolkitbrowser ); void toolkitbrowser_set_workspace( Toolkitbrowser *toolkitbrowser, Workspace *ws ); nip2-8.7.1/src/clock.h0000644000175000017500000000327513351443023011360 00000000000000/* a clock in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_CLOCK (clock_get_type()) #define CLOCK( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_CLOCK, Clock )) #define CLOCK_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_CLOCK, ClockClass)) #define IS_CLOCK( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_CLOCK )) #define IS_CLOCK_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_CLOCK )) #define CLOCK_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_CLOCK, ClockClass )) typedef struct _Clock { Value parent_object; double interval; double value; GTimer *elapsed_timer; double time_offset; /* Offset timer by this to get new value */ guint recalc_timeout; /* Timeout for next recalc */ } Clock; typedef struct _ClockClass { ValueClass parent_class; /* My methods. */ } ClockClass; GType clock_get_type( void ); nip2-8.7.1/src/valueview.c0000644000175000017500000000774213351443023012272 00000000000000/* display a minimal graphic for an object (just the caption) */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; static void valueview_refresh( vObject *vobject ) { Valueview *valueview = VALUEVIEW( vobject ); Model *model = MODEL( vobject->iobject ); #ifdef DEBUG printf( "valueview_refresh: " ); row_name_print( HEAPMODEL( model )->row ); printf( "\n" ); #endif /*DEBUG*/ set_gcaption( valueview->label, "%s", NN( IOBJECT( model )->caption ) ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void valueview_link( View *view, Model *model, View *parent ) { Valueview *valueview = VALUEVIEW( view ); Rowview *rview = ROWVIEW( parent->parent ); VIEW_CLASS( parent_class )->link( view, model, parent ); (void) rowview_menu_attach( rview, valueview->eb ); } static void valueview_class_init( ValueviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = valueview_refresh; view_class->link = valueview_link; } static gboolean valueview_event_cb( GtkWidget *widget, GdkEvent *ev, Valueview *valueview ) { Model *model = MODEL( VOBJECT( valueview )->iobject ); Row *row = HEAPMODEL( model )->row; gboolean handled = FALSE; switch( ev->type ) { case GDK_BUTTON_PRESS: if( ev->button.button == 1 ) { row_select_modifier( row, ev->button.state ); handled = TRUE; } break; case GDK_2BUTTON_PRESS: if( ev->button.button == 1 ) { model_edit( widget, MODEL( model ) ); handled = TRUE; } break; default: break; } return( handled ); } static void valueview_init( Valueview *valueview ) { #ifdef DEBUG printf( "valueview_init\n" ); #endif /*DEBUG*/ valueview->eb = gtk_event_box_new(); gtk_widget_add_events( GTK_WIDGET( valueview->eb ), GDK_POINTER_MOTION_HINT_MASK ); gtk_box_pack_start( GTK_BOX( valueview ), valueview->eb, FALSE, FALSE, 0 ); valueview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( valueview->label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( valueview->label ), 2, 0 ); gtk_container_add( GTK_CONTAINER( valueview->eb ), valueview->label ); gtk_widget_set_name( valueview->eb, "caption_widget" ); gtk_signal_connect( GTK_OBJECT( valueview->eb ), "event", GTK_SIGNAL_FUNC( valueview_event_cb ), valueview ); gtk_widget_show_all( GTK_WIDGET( valueview->eb ) ); } GtkType valueview_get_type( void ) { static GtkType valueview_type = 0; if( !valueview_type ) { static const GtkTypeInfo info = { "Valueview", sizeof( Valueview ), sizeof( ValueviewClass ), (GtkClassInitFunc) valueview_class_init, (GtkObjectInitFunc) valueview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; valueview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( valueview_type ); } View * valueview_new( void ) { Valueview *valueview = gtk_type_new( TYPE_VALUEVIEW ); return( VIEW( valueview ) ); } nip2-8.7.1/src/filemodel.h0000644000175000017500000001050713351443023012221 00000000000000/* abstract base class for things which are loaded or saved from files */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define FILEMODEL_LOAD_STATE( obj ) ((FilemodelLoadState *) obj) #define TYPE_FILEMODEL (filemodel_get_type()) #define FILEMODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_FILEMODEL, Filemodel )) #define FILEMODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_FILEMODEL, FilemodelClass)) #define IS_FILEMODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_FILEMODEL )) #define IS_FILEMODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_FILEMODEL )) #define FILEMODEL_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_FILEMODEL, FilemodelClass )) struct _Filemodel { Model model; char *filename; /* File we read this thing from */ gboolean modified; /* Set if modified (and should be saved) */ gboolean registered; /* Set if on list of things to save on quit */ gboolean auto_load; /* TRUE if loaded from path_start */ int x_off, y_off; /* Save offset for things below this */ /* When we loaded this filemodel, the version numbers we saw in the * XML file. */ gboolean versioned; /* Set means from a versioned file */ int major; int minor; int micro; iWindow *window_hint; /* Our views set this as a hint */ }; typedef struct _FilemodelClass { ModelClass parent_class; /* top_load top level load function ... controls how the rest of the load happens ... eg. merge, rename, etc. set_modified set/clear the modified state top_save top level save ... intercept this to override */ gboolean (*top_load)( Filemodel *filemodel, ModelLoadState *state, Model *parent, xmlNode *xnode ); void (*set_modified)( Filemodel *filemodel, gboolean modified ); gboolean (*top_save)( Filemodel *filemodel, const char *filename ); FileselFileType **filetype; const char *filetype_pref; } FilemodelClass; void filemodel_register( Filemodel *filemodel ); void filemodel_unregister( Filemodel *filemodel ); void *filemodel_top_load( Filemodel *filemodel, ModelLoadState *state, Model *parent, xmlNode *xnode ); void filemodel_set_filename( Filemodel *filemodel, const char *filename ); void filemodel_set_modified( Filemodel *filemodel, gboolean state ); void filemodel_set_window_hint( Filemodel *filemodel, iWindow *iwnd ); iWindow *filemodel_get_window_hint( Filemodel *filemodel ); GType filemodel_get_type( void ); void filemodel_set_offset( Filemodel *filemodel, int x_off, int y_off ); gboolean filemodel_top_save( Filemodel *filemodel, const char *filename ); gboolean filemodel_load_all( Filemodel *filemodel, Model *parent, const char *filename, const char *filename_user ); gboolean filemodel_load_all_openfile( Filemodel *filemodel, Model *parent, iOpenFile *of ); void filemodel_inter_saveas( iWindow *parent, Filemodel *filemodel ); void filemodel_inter_save( iWindow *parent, Filemodel *filemodel ); void filemodel_inter_savenempty_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ); void filemodel_inter_savenempty( iWindow *parent, Filemodel *filemodel ); void filemodel_inter_savenclose_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ); void filemodel_inter_savenclose( iWindow *parent, Filemodel *filemodel ); void filemodel_inter_loadas( iWindow *parent, Filemodel *filemodel ); void filemodel_inter_replace( iWindow *parent, Filemodel *filemodel ); void filemodel_inter_close_registered_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ); void filemodel_set_auto_load( Filemodel *filemodel ); nip2-8.7.1/src/toolkit.h0000644000175000017500000000454513351443023011753 00000000000000/* Groups of tools! */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TOOLKIT (toolkit_get_type()) #define TOOLKIT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_TOOLKIT, Toolkit )) #define TOOLKIT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_TOOLKIT, ToolkitClass)) #define IS_TOOLKIT( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_TOOLKIT )) #define IS_TOOLKIT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKIT )) #define TOOLKIT_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_TOOLKIT, ToolkitClass )) /* Toolkits: group definitions with these guys. One toolkit per definition file * loaded. */ struct _Toolkit { Filemodel parent_class; Toolkitgroup *kitg; /* Set this for auto-generated toolkits (eg. packages of function from * VIPS) ... blocks edit etc. in program window. */ gboolean pseudo; }; typedef struct _ToolkitClass { FilemodelClass parent_class; /* My methods. */ } ToolkitClass; Tool *toolkit_map( Toolkit *kit, tool_map_fn fn, void *a, void *b ); GType toolkit_get_type( void ); Toolkit *toolkit_find( Toolkitgroup *kitg, const char *name ); Toolkit *toolkit_by_name( Toolkitgroup *kitg, const char *name ); Toolkit *toolkit_new( Toolkitgroup *kitg, const char *filename ); Toolkit *toolkit_new_filename( Toolkitgroup *kitg, const char *filename ); Toolkit *toolkit_new_from_file( Toolkitgroup *kitg, const char *filename ); Toolkit *toolkit_new_from_openfile( Toolkitgroup *kitg, iOpenFile *of ); void *toolkit_linkreport( Toolkit *kit, VipsBuf *buf, gboolean *bad_links ); nip2-8.7.1/src/sliderview.c0000644000175000017500000001315413351443023012432 00000000000000/* run the display for a slider in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; static void sliderview_refresh( vObject *vobject ) { Sliderview *sliderview = SLIDERVIEW( vobject ); Slider *slider = SLIDER( VOBJECT( sliderview )->iobject ); Tslider *tslider = sliderview->tslider; const double range = slider->to - slider->from; const double lrange = log10( range ); const char *caption = IOBJECT( slider )->caption; #ifdef DEBUG printf( "sliderview_refresh\n" ); #endif /*DEBUG*/ /* Compatibility ... we used to not have a caption. Don't display * anything if there's o caption. */ if( caption ) { if( strcmp( caption, "" ) != 0 ) set_glabel( sliderview->label, _( "%s:" ), caption ); else set_glabel( sliderview->label, "%s", "" ); } tslider->from = slider->from; tslider->to = slider->to; tslider->svalue = slider->value; tslider->value = slider->value; tslider->digits = IM_MAX( 0, ceil( 2 - lrange ) ); if( CALC_RECOMP_SLIDER ) gtk_range_set_update_policy( GTK_RANGE( tslider->slider ), GTK_UPDATE_CONTINUOUS ); else gtk_range_set_update_policy( GTK_RANGE( tslider->slider ), GTK_UPDATE_DISCONTINUOUS ); #ifdef DEBUG gtk_range_set_update_policy( GTK_RANGE( tslider->slider ), GTK_UPDATE_DISCONTINUOUS ); #endif /*DEBUG*/ tslider_changed( tslider ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void * sliderview_scan( View *view ) { Sliderview *sliderview = SLIDERVIEW( view ); Slider *slider = SLIDER( VOBJECT( sliderview )->iobject ); Classmodel *classmodel = CLASSMODEL( slider ); Expr *expr = HEAPMODEL( classmodel )->row->expr; double value; if( !get_geditable_double( sliderview->tslider->entry, &value ) ) { expr_error_set( expr ); return( view ); } if( slider->value != value ) { slider->value = value; classmodel_update( classmodel ); } return( VIEW_CLASS( parent_class )->scan( view ) ); } static void sliderview_link( View *view, Model *model, View *parent ) { Sliderview *sliderview = SLIDERVIEW( view ); VIEW_CLASS( parent_class )->link( view, model, parent ); if( GRAPHICVIEW( view )->sview ) gtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group, sliderview->label ); } static void sliderview_class_init( SliderviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = sliderview_refresh; view_class->scan = sliderview_scan; view_class->link = sliderview_link; } /* Drag on slider. */ static void sliderview_change_cb( Tslider *tslider, Sliderview *sliderview ) { Slider *slider = SLIDER( VOBJECT( sliderview )->iobject ); #ifdef DEBUG printf( "sliderview_change_cb\n" ); #endif /*DEBUG*/ if( slider->value != tslider->svalue ) { slider->value = tslider->svalue; classmodel_update( CLASSMODEL( slider ) ); symbol_recalculate_all(); } } static void sliderview_init( Sliderview *sliderview ) { GtkWidget *hbox; hbox = gtk_hbox_new( FALSE, 12 ); gtk_box_pack_start( GTK_BOX( sliderview ), hbox, TRUE, FALSE, 0 ); sliderview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( sliderview->label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( sliderview->label ), 2, 1 ); gtk_box_pack_start( GTK_BOX( hbox ), sliderview->label, FALSE, FALSE, 0 ); sliderview->tslider = tslider_new(); tslider_set_conversions( sliderview->tslider, NULL, NULL ); gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( sliderview->tslider ), TRUE, TRUE, 6 ); gtk_signal_connect_object( GTK_OBJECT( sliderview->tslider ), "text_changed", GTK_SIGNAL_FUNC( view_changed_cb ), GTK_OBJECT( sliderview ) ); gtk_signal_connect_object( GTK_OBJECT( sliderview->tslider ), "activate", GTK_SIGNAL_FUNC( view_activate_cb ), GTK_OBJECT( sliderview ) ); gtk_signal_connect( GTK_OBJECT( sliderview->tslider ), "slider_changed", GTK_SIGNAL_FUNC( sliderview_change_cb ), sliderview ); gtk_widget_show_all( GTK_WIDGET( sliderview ) ); } GtkType sliderview_get_type( void ) { static GtkType sliderview_type = 0; if( !sliderview_type ) { static const GtkTypeInfo sinfo = { "Sliderview", sizeof( Sliderview ), sizeof( SliderviewClass ), (GtkClassInitFunc) sliderview_class_init, (GtkObjectInitFunc) sliderview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; sliderview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &sinfo ); } return( sliderview_type ); } View * sliderview_new( void ) { Sliderview *sliderview = gtk_type_new( TYPE_SLIDERVIEW ); return( VIEW( sliderview ) ); } nip2-8.7.1/src/row.c0000644000175000017500000013375513351443023011076 00000000000000/* A row in a workspace ... not a widget, part of subcolumn */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Mad detail. #define DEBUG */ /* Show each row being calculated. #define DEBUG_ROW */ /* Making and removing links between rows. #define DEBUG_LINK */ /* Time row recomp. #define DEBUG_TIME_SORT */ /* Trace create/destroy. #define DEBUG_NEW */ /* Dirty/clean stuff. #define DEBUG_DIRTY */ /* Error set/clear. #define DEBUG_ERROR */ /* Show row recomp order decisions. #define DEBUG_SORT_VERBOSE #define DEBUG_SORT */ #include "ip.h" static HeapmodelClass *parent_class = NULL; static void * row_map_all_sub( Model *model, row_map_fn fn, void *a, void *b, void *c ) { if( IS_ROW( model ) ) return( fn( ROW( model ), a, b, c ) ); return( NULL ); } static void * row_map_all( Row *row, row_map_fn fn, void *a, void *b, void *c ) { return( icontainer_map4_all( ICONTAINER( row ), (icontainer_map4_fn) row_map_all_sub, (void *) fn, a, b, c ) ); } const char * row_name( Row *row ) { if( row->sym ) return( IOBJECT( row->sym )->name ); else return( IOBJECT( row )->name ); } static Row * row_get_parent( Row *row ) { return( HEAPMODEL( row )->row ); } /* Make a fully-qualified name for a row's symbol ... walk back up the tally * hierarchy. eg. "A1.fred.x" ... produce a name which will find this row from * a local of context. */ void row_qualified_name_relative( Symbol *context, Row *row, VipsBuf *buf ) { if( !row_get_parent( row ) ) { if( !row->sym ) vips_buf_appends( buf, "(null)" ); else symbol_qualified_name_relative( context, row->sym, buf ); } else { /* Qualify our parents, then do us. */ row_qualified_name_relative( context, row_get_parent( row ), buf ); vips_buf_appends( buf, "." ); vips_buf_appends( buf, row_name( row ) ); } } /* Make a fully-qualified name for a row's symbol ... walk back up the tally * hierarchy. eg. "A1.fred.x". */ void row_qualified_name( Row *row, VipsBuf *buf ) { if( row->ws ) row_qualified_name_relative( row->ws->sym, row, buf ); } /* Convenience ... print a row name out, identifying by tally heirarchy. */ void * row_name_print( Row *row ) { if( row ) { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); row_qualified_name( row, &buf ); printf( "%s ", vips_buf_all( &buf ) ); } else printf( "(null)" ); return( NULL ); } static void * row_dirty_clear( Row *row ) { #ifdef DEBUG_DIRTY { Row *top_row = row->top_row; if( row->dirty ) g_assert( g_slist_find( top_row->recomp, row ) ); } #endif /*DEBUG_DIRTY*/ if( row->dirty ) { Row *top_row = row->top_row; row->dirty = FALSE; top_row->recomp = g_slist_remove( top_row->recomp, row ); #ifdef DEBUG_DIRTY printf( "row_dirty_clear: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG_DIRTY*/ iobject_changed( IOBJECT( row ) ); } return( NULL ); } /* Set a single row dirty. */ static void * row_dirty_set_single( Row *row, gboolean clear_error ) { #ifdef DEBUG_DIRTY { Row *top_row = row->top_row; if( row->dirty ) g_assert( g_slist_find( top_row->recomp, row ) ); if( !row->dirty ) g_assert( !g_slist_find( top_row->recomp, row ) ); } #endif /*DEBUG_DIRTY*/ if( !row->dirty ) { Row *top_row = row->top_row; row->dirty = TRUE; top_row->recomp = g_slist_prepend( top_row->recomp, row ); iobject_changed( IOBJECT( row ) ); #ifdef DEBUG_DIRTY printf( "row_dirty_set_single: " ); row_name_print( row ); printf( " clear_error = %s\n", bool_to_char( clear_error ) ); #endif /*DEBUG_DIRTY*/ /* Make sure error is clear ... we want to recomp. */ if( row->expr && clear_error ) expr_error_clear( row->expr ); } return( NULL ); } static void * row_dirty_set_sub( Model *model, gboolean clear_error ) { if( IS_ROW( model ) ) { Row *row = ROW( model ); Rhs *rhs = row->child_rhs; g_assert( !rhs || IS_RHS( rhs ) ); if( rhs && rhs->itext && ITEXT( rhs->itext )->edited ) row_dirty_set_single( row, clear_error ); else if( rhs && rhs->graphic && CLASSMODEL( rhs->graphic )->edited ) row_dirty_set_single( row, clear_error ); } return( NULL ); } /* When we mark a row dirty, we need to mark any subrows with non-default * values dirty too so that they will get a chance to reapply their edits over * the top of the new value we will make for this row. */ static void * row_dirty_set( Row *row, gboolean clear_error ) { row_dirty_set_single( row, clear_error ); return( icontainer_map_all( ICONTAINER( row ), (icontainer_map_fn) row_dirty_set_sub, GINT_TO_POINTER( clear_error ) ) ); } /* Mark a row as containing an error ... called from expr_error_set() * ... don't call this directly. */ void row_error_set( Row *row ) { if( !row->err ) { Workspace *ws = row->ws; gboolean was_clear = ws->errors == NULL; ws->errors = g_slist_prepend( ws->errors, row ); row->err = TRUE; #ifdef DEBUG_ERROR printf( "row_error_set: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG_ERROR*/ iobject_changed( IOBJECT( row ) ); /* First error? State change on workspace. */ if( was_clear ) iobject_changed( IOBJECT( ws ) ); /* If this is a local row, mark the top row in error too to end * recomp on this tree. */ if( row != row->top_row ) { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); row_qualified_name( row, &buf ); error_top( _( "Error in row." ) ); /* Elements are name of row, principal error, * secondary error. */ error_sub( _( "Error in row %s: %s\n%s" ), vips_buf_all( &buf ), row->expr->error_top, row->expr->error_sub ); expr_error_set( row->top_row->expr ); } } } /* Clear error state ... called from expr_error_clear() ... don't call this * directly. */ void row_error_clear( Row *row ) { if( row->err ) { Workspace *ws = row->ws; ws->errors = g_slist_remove( ws->errors, row ); row->err = FALSE; iobject_changed( IOBJECT( row ) ); #ifdef DEBUG_ERROR printf( "row_error_clear: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG_ERROR*/ /* Mark our text modified to make sure we reparse and compile. * The code may contain pointers to dead symbols if we were in * error because they were undefined. */ if( row->child_rhs && row->child_rhs->itext ) heapmodel_set_modified( HEAPMODEL( row->child_rhs->itext ), TRUE ); /* All errors gone? Ws changed too. */ if( !ws->errors ) iobject_changed( IOBJECT( ws ) ); /* Is this a local row? Clear the top row error as well, in * case it's in error because of us. */ if( row != row->top_row && row->top_row->expr ) { expr_error_clear( row->top_row->expr ); row_dirty_set( row->top_row, TRUE ); } } } /* Break a dependency. */ static void * row_link_break( Row *parent, Row *child ) { /* Must be there. */ g_assert( g_slist_find( parent->children, child ) && g_slist_find( child->parents, parent ) ); parent->children = g_slist_remove( parent->children, child ); child->parents = g_slist_remove( child->parents, parent ); #ifdef DEBUG_LINK printf( "row_link_break: breaking link from " ); row_name_print( parent ); printf( "to " ); row_name_print( child ); printf( "\n" ); #endif /*DEBUG_LINK*/ return( NULL ); } static void * row_link_break_rev( Row *child, Row *parent ) { return( row_link_break( parent, child ) ); } static void row_dispose( GObject *gobject ) { Row *row = ROW( gobject ); #ifdef DEBUG_NEW /* Can't use row_name_print(), we may not have a parent. */ printf( "row_dispose: %s", NN( IOBJECT( row )->name ) ); if( row->sym ) printf( " (%s)", symbol_name( row->sym ) ); printf( "\n" ); #endif /*DEBUG_NEW*/ /* Reset state. Also see row_parent_remove(). */ row_hide_dependents( row ); if( row->expr ) expr_error_clear( row->expr ); if( row->top_col && row->top_col->last_select == row ) row->top_col->last_select = NULL; row_deselect( row ); /* Break all recomp links. */ slist_map( row->parents, (SListMapFn) row_link_break, row ); slist_map( row->children, (SListMapFn) row_link_break_rev, row ); g_assert( !row->parents && !row->children ); (void) slist_map( row->recomp, (SListMapFn) row_dirty_clear, NULL ); if( row->top_row ) row->top_row->recomp_save = g_slist_remove( row->top_row->recomp_save, row ); IM_FREEF( g_slist_free, row->recomp_save ); g_assert( !row->recomp ); if( row->expr ) { g_assert( row->expr->row == row ); /* If we're a local row, we will have a private expr * allocated for us. Junk it. */ if( row != row->top_row ) icontainer_child_remove( ICONTAINER( row->expr ) ); else { /* Top-level row, we were zapping the sym's expr. * Break the link to it. */ row->expr->row = NULL; row->expr = NULL; } } /* Is this a top-level row? Kill the symbol too. Need to do this after * sorting out row->expr, since otherwise killing the symbol will kill * us again in turn. */ if( row == row->top_row ) IDESTROY( row->sym ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void * row_add_parent_name( Link *link, VipsBuf *buf ) { Row *row; if( link->parent->expr && (row = link->parent->expr->row) ) { row_qualified_name_relative( link->child, row, buf ); vips_buf_appends( buf, " " ); } return( NULL ); } static void * row_add_child_name( Link *link, VipsBuf *buf ) { Row *row; if( link->child->expr && (row = link->child->expr->row) ) { row_qualified_name_relative( link->parent, row, buf ); vips_buf_appends( buf, " " ); } return( NULL ); } static void * row_add_dirty_child_name( Link *link, VipsBuf *buf ) { if( link->child->dirty ) { symbol_qualified_name_relative( link->parent, link->child, buf ); vips_buf_appends( buf, " " ); } return( NULL ); } static void row_info( iObject *iobject, VipsBuf *buf ) { Row *row = ROW( iobject ); vips_buf_appends( buf, _( "Name" ) ); vips_buf_appends( buf, ": " ); row_qualified_name( row, buf ); vips_buf_appends( buf, "\n" ); if( row->expr ) iobject_info( IOBJECT( row->expr ), buf ); if( row->child_rhs && row->child_rhs->itext ) iobject_info( IOBJECT( row->child_rhs->itext ), buf ); if( row->child_rhs && row->child_rhs->graphic ) iobject_info( IOBJECT( row->child_rhs->graphic ), buf ); if( row->top_row->sym ) { if( row->top_row->sym->topchildren ) { row_qualified_name( row, buf ); vips_buf_appends( buf, " " ); /* Expands to eg. "B1 refers to: B2, B3". */ vips_buf_appends( buf, _( "refers to" ) ); vips_buf_appends( buf, ": " ); slist_map_rev( row->top_row->sym->topchildren, (SListMapFn) row_add_child_name, buf ); vips_buf_appends( buf, "\n" ); } if( row->top_row->sym->topparents ) { row_qualified_name( row, buf ); vips_buf_appends( buf, " " ); /* Expands to eg. "B1 is referred to by: B2, B3". */ vips_buf_appends( buf, _( "is referred to by" ) ); vips_buf_appends( buf, ": " ); slist_map_rev( row->top_row->sym->topparents, (SListMapFn) row_add_parent_name, buf ); vips_buf_appends( buf, "\n" ); } } if( row == row->top_row && row->sym && row->sym->dirty ) { Symbol *sym = row->sym; if( sym->ndirtychildren ) { row_qualified_name( row, buf ); vips_buf_appends( buf, " " ); vips_buf_appends( buf, _( "is blocked on" ) ); vips_buf_appends( buf, ": " ); slist_map_rev( sym->topchildren, (SListMapFn) row_add_dirty_child_name, buf ); vips_buf_appends( buf, "\n" ); } } } static Rhs * row_get_rhs( Row *row ) { g_assert( g_slist_length( ICONTAINER( row )->children ) == 1 ); return( RHS( ICONTAINER( row )->children->data ) ); } static void row_child_add( iContainer *parent, iContainer *child, int pos ) { Row *row = ROW( parent ); ICONTAINER_CLASS( parent_class )->child_add( parent, child, pos ); /* Update our context. */ row->child_rhs = row_get_rhs( row ); } static Subcolumn * row_get_subcolumn( Row *row ) { return( SUBCOLUMN( ICONTAINER( row )->parent ) ); } static Column * row_get_column( Row *row ) { Subcolumn *scol = row_get_subcolumn( row ); if( scol ) return( scol->top_col ); else return( NULL ); } /* Search back up the widget hierarchy for the base row for this * row ... eg "A7"->expr->row. */ static Row * row_get_root( Row *row ) { Row *enclosing = row_get_parent( row ); if( !enclosing ) return( row ); else return( row_get_root( enclosing ) ); } Workspace * row_get_workspace( Row *row ) { Column *col = row_get_column( row ); if( col ) return( col->ws ); else return( NULL ); } static void row_parent_add( iContainer *child ) { Row *row = ROW( child ); g_assert( IS_SUBCOLUMN( child->parent ) ); ICONTAINER_CLASS( parent_class )->parent_add( child ); /* Update our context. */ row->scol = row_get_subcolumn( row ); row->top_col = row_get_column( row ); row->ws = row_get_workspace( row ); row->top_row = row_get_root( row ); } static void row_parent_remove( iContainer *child ) { Row *row = ROW( child ); /* Reset the parts of state which touch our parent. */ row_dirty_clear( row ); row_deselect( row ); /* Don't clear error ... we may no longer have the link to expr. See * row_dispose() for that. */ ICONTAINER_CLASS( parent_class )->parent_remove( child ); } static View * row_view_new( Model *model, View *parent ) { return( rowview_new() ); } static void row_scrollto( Model *model, ModelScrollPosition position ) { Row *row = ROW( model ); Column *col = row->top_col; /* If our column is closed, there won't be a view to scrollto, ouch! * Need to open the column first, then scroll to that column. We can't * scroll to the exact row, since there's no view for it, and won't be * for a while after we hit the idle loop again. */ if( !col->open ) { column_set_open( col, TRUE ); column_scrollto( col, position ); } MODEL_CLASS( parent_class )->scrollto( model, position ); } static gboolean row_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { Row *row = ROW( model ); Subcolumn *scol = SUBCOLUMN( parent ); char name[256]; g_assert( IS_SUBCOLUMN( parent ) ); if( !get_sprop( xnode, "name", name, 256 ) ) return( FALSE ); IM_SETSTR( IOBJECT( row )->name, name ); #ifdef DEBUG printf( "row_load: loading row %s (xmlNode %p)\n", name, xnode ); #endif /*DEBUG*/ /* Popup is optional (top level only) */ (void) get_bprop( xnode, "popup", &row->popup ); if( scol->is_top ) { Column *col = scol->top_col; Workspace *ws = col->ws; Symbol *sym; sym = symbol_new( ws->sym->expr->compile, name ); symbol_user_init( sym ); (void) compile_new_local( sym->expr ); row_link_symbol( row, sym, NULL ); /* We can't symbol_made() here, we've not parsed our value * yet. See below ... we just make sure we're on the recomp * lists. */ } if( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ) return( FALSE ); /* If we've loaded a complete row system, mark this row plus any * edited subrows dirty, and make sure this sym is dirty too. */ if( scol->is_top ) { row_dirty_set( row, TRUE ); expr_dirty( row->sym->expr, link_serial_new() ); } return( TRUE ); } /* Should we display this row. Non-displayed rows don't have rhs, don't * appear on the screen, and aren't saved. They do have rows though, so their * dependencies are tracked. * * We work off sym rather than row so that we can work before the row is fully * built. */ static gboolean row_is_displayable( Symbol *sym ) { if( is_system( sym ) ) return( FALSE ); if( sym->expr && sym->expr->compile && sym->expr->compile->nparam > 0 ) return( FALSE ); if( is_super( sym ) && sym->expr ) { Expr *expr = sym->expr; PElement *root = &expr->root; /* Empty superclass. */ if( PEISELIST( root ) ) return( FALSE ); } return( TRUE ); } static xmlNode * row_save( Model *model, xmlNode *xnode ) { Row *row = ROW( model ); xmlNode *xthis; /* Don't save system rows, or empty superclasses. */ if( row->sym ) { if( !row_is_displayable( row->sym ) ) /* Need to return non-NULL for abort with no error. */ return( (xmlNode *) -1 ); } if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); /* Top-level only. */ if( row->top_row == row ) if( !set_sprop( xthis, "popup", bool_to_char( row->popup ) ) ) return( NULL ); if( !set_sprop( xthis, "name", IOBJECT( row )->name ) ) return( NULL ); return( xthis ); } static void * row_clear_to_save( Model *model ) { if( IS_ROW( model ) ) ROW( model )->to_save = FALSE; return( NULL ); } static void * row_set_to_save( Row *row ) { Row *enclosing; if( !row->to_save ) { row->to_save = TRUE; /* All peers must be saved. When we reload, we want to keep * row ordering. If we just save modded row, they'll move to * the front of the row list on reload, since they'll be made * first. */ icontainer_map( ICONTAINER( row->scol ), (icontainer_map_fn) row_set_to_save, NULL, NULL ); /* All rows back up to the top level must also be saved. */ for( enclosing = row; enclosing != row->top_row; enclosing = row_get_parent( enclosing ) ) row_set_to_save( enclosing ); } return( NULL ); } static void * row_calculate_to_save( Model *model ) { if( IS_ROW( model ) ) { Row *row = ROW( model ); Rhs *rhs = row->child_rhs; if( row != row->top_row && rhs && !row->to_save ) { if( rhs->itext && ITEXT( rhs->itext )->edited ) row_set_to_save( row ); else if( rhs->graphic && CLASSMODEL( rhs->graphic )->edited ) row_set_to_save( row ); } } return( NULL ); } static gboolean row_save_test( Model *model ) { Row *row = ROW( model ); Workspace *ws = row->ws; Workspacegroup *wsg = workspace_get_workspacegroup( ws ); gboolean save; if( row == row->top_row ) { /* This is a top-level row ... save unless we're in * only-save-selected mode. */ if( wsg->save_type == WORKSPACEGROUP_SAVE_SELECTED ) save = row->selected; else save = TRUE; /* If we're going to save this row, clear all the to_save * flags, then walk the tree working out which bits we will need * to write. */ if( save ) { icontainer_map_all( ICONTAINER( row ), (icontainer_map_fn) row_clear_to_save, NULL ); icontainer_map_all( ICONTAINER( row ), (icontainer_map_fn) row_calculate_to_save, NULL ); } } else save = row->to_save; return( save ); } static void * row_new_heap( Heapmodel *heapmodel, PElement *root ) { Row *row = ROW( heapmodel ); Expr *expr = row->expr; #ifdef DEBUG printf( "row_new_heap: " ); row_name_print( row ); printf( "\n" ); printf( "row_new_heap: new value is " ); pgraph( root ); printf( "row_new_heap: top value is " ); pgraph( &row->top_row->expr->root ); #endif /*DEBUG*/ if( row_is_displayable( row->sym ) ) { /* Hide superclasses whose constructor starts with "_". */ if( is_super( row->sym ) && PEISCLASS( root ) && *IOBJECT( PEGETCLASSCOMPILE( root )->sym )->name == '_' ) model_display( MODEL( row ), FALSE ); } /* New value ... reset error state. */ expr_error_clear( expr ); expr->root = *root; expr_new_value( expr ); if( row->child_rhs && heapmodel_new_heap( HEAPMODEL( row->child_rhs ), root ) ) return( row ); /* Class display only for non-param classes. */ row->is_class = PEISCLASS( root ) && row->sym->type != SYM_PARAM; /* Set the default vis level. */ if( row->child_rhs && row->child_rhs->vislevel == -1 ) { PElement member; double value; gboolean is_class; if( !heap_is_class( root, &is_class ) ) return( row ); /* If it's a class with a vis hint, use that. */ if( is_class && class_get_member( root, MEMBER_VISLEVEL, NULL, &member ) && heap_get_real( &member, &value ) ) rhs_set_vislevel( row->child_rhs, value ); /* Non-parameter rows get higher vislevel, except for super. */ else if( row->sym->type != SYM_PARAM && !is_super( row->sym ) ) rhs_set_vislevel( row->child_rhs, 1 ); else rhs_set_vislevel( row->child_rhs, 0 ); } return( HEAPMODEL_CLASS( parent_class )->new_heap( heapmodel, root ) ); } static void * row_update_model( Heapmodel *heapmodel ) { Row *row = ROW( heapmodel ); if( row->expr ) expr_new_value( row->expr ); return( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ); } static void row_class_init( RowClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->dispose = row_dispose; iobject_class->info = row_info; icontainer_class->child_add = row_child_add; icontainer_class->parent_add = row_parent_add; icontainer_class->parent_remove = row_parent_remove; model_class->view_new = row_view_new; model_class->scrollto = row_scrollto; model_class->load = row_load; model_class->save = row_save; model_class->save_test = row_save_test; heapmodel_class->new_heap = row_new_heap; heapmodel_class->update_model = row_update_model; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void row_init( Row *row ) { #ifdef DEBUG printf( "row_init\n" ); #endif /*DEBUG*/ row->scol = NULL; row->child_rhs = NULL; row->top_col = NULL; row->ws = NULL; row->top_row = NULL; row->sym = NULL; row->expr = NULL; row->err = FALSE; row->selected = FALSE; row->is_class = FALSE; row->popup = POPUP_NEW_ROWS; row->to_save = FALSE; /* Init recomp stuff. */ row->parents = NULL; row->children = NULL; row->dirty = FALSE; row->recomp = NULL; row->recomp_save = NULL; row->depend = FALSE; row->show = ROW_SHOW_NONE; } GType row_get_type( void ) { static GType row_type = 0; if( !row_type ) { static const GTypeInfo info = { sizeof( RowClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) row_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Row ), 32, /* n_preallocs */ (GInstanceInitFunc) row_init, }; row_type = g_type_register_static( TYPE_HEAPMODEL, "Row", &info, 0 ); } return( row_type ); } /* After making a row and adding it to model tree ... attach the symbol and * value this row displays. */ void row_link_symbol( Row *row, Symbol *sym, PElement *root ) { g_assert( !row->sym ); g_assert( !row->expr ); g_assert( !sym->expr || !sym->expr->row ); row->sym = sym; /* Code we display/update ... if this is a top-level row, we * directly change the symbol's expr. If it's a sub-row, we need a * cloned expr for us to fiddle with. */ if( is_top( sym ) ) { row->expr = sym->expr; g_assert( !row->expr->row ); row->expr->row = row; } else { row->expr = expr_clone( sym ); row->expr->row = row; if( root ) { row->expr->root = *root; expr_new_value( row->expr ); } } } Row * row_new( Subcolumn *scol, Symbol *sym, PElement *root ) { Row *row = g_object_new( TYPE_ROW, NULL ); #ifdef DEBUG_NEW printf( "row_new: " ); dump_tiny( sym ); printf( "\n" ); #endif /*DEBUG_NEW*/ /* Don't make a display or a RHS for invisible rows. */ if( !row_is_displayable( sym ) ) MODEL( row )->display = FALSE; else (void) rhs_new( row ); iobject_set( IOBJECT( row ), IOBJECT( sym )->name, NULL ); icontainer_child_add( ICONTAINER( scol ), ICONTAINER( row ), -1 ); row_link_symbol( row, sym, root ); return( row ); } /* Make a dependency. parent is displaying an expression which * refers to the symbol being displayed by child. */ static void * row_link_make( Row *parent, Row *child ) { /* Already a dependency? Don't make a second link. */ if( g_slist_find( parent->children, child ) ) return( NULL ); /* Don't link to self (harmless, but pointless too). */ if( parent == child ) return( NULL ); /* New link, each direction. */ parent->children = g_slist_prepend( parent->children, child ); child->parents = g_slist_prepend( child->parents, parent ); #ifdef DEBUG_LINK printf( "row_link_make: " ); row_name_print( parent ); printf( "refers to " ); row_name_print( child ); printf( "\n" ); #endif /*DEBUG_LINK*/ return( NULL ); } static void * row_link_build4( Expr *child_expr, Row *row ) { if( child_expr->row && child_expr->row->top_row == row ) return( child_expr->row ); return( NULL ); } /* Does child have a display in the same tally heirarchy as row? Make a link! */ static void * row_link_build3( Symbol *child, Row *row ) { Row *child_row; child_row = (Row *) icontainer_map( ICONTAINER( child ), (icontainer_map_fn) row_link_build4, row->top_row, NULL ); if( child_row ) (void) row_link_make( row, child_row ); return( NULL ); } static void *row_link_build2( Expr *expr, Row *row ); static void * row_link_build2_sym( Symbol *sym, Row *row ) { if( sym->expr && row_link_build2( sym->expr, row ) ) return( row ); return( NULL ); } static void * row_link_build2( Expr *expr, Row *row ) { /* Make links to anything expr refers to in this tree. */ if( expr->compile && slist_map( expr->compile->children, (SListMapFn) row_link_build3, row ) ) return( expr ); /* Recurse for any locals of expr. * Exception: * * f = class { * g = class { * a = 12; * } * } * * zero-arg local classes will have rows anyway, so we don't need to * check inside them for locals, since we'll do them anyway at the top * level. * * zero-arg hidden classes do need to be checked inside though :-( * since we will only have a row for the top element. */ if( expr->compile && !(is_class( expr->compile ) && expr->compile->nparam == 0 && expr->row && MODEL( expr->row )->display) && icontainer_map( ICONTAINER( expr->compile ), (icontainer_map_fn) row_link_build2_sym, row, NULL ) ) return( expr ); return( NULL ); } /* Scan a row, adding links for any dependencies we find. */ static void * row_link_build( Row *row ) { #ifdef DEBUG_LINK printf( "row_link_build: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG_LINK*/ /* Build new recomp list. Only for class displays. */ if( !row->scol->is_top && row->expr && row_link_build2( row->expr, row ) ) return( row ); return( NULL ); } /* Remove any links on a row. */ static void * row_link_destroy( Row *row ) { slist_map( row->children, (SListMapFn) row_link_break_rev, row ); return( NULL ); } static void *row_dependent_map_sub( Row *row, row_map_fn fn, void *a ); /* Do this row, and any that depend on it. */ static void * row_dependent_mark( Row *row, row_map_fn fn, void *a ) { void *res; /* Done this one already? */ if( row->depend ) return( NULL ); row->depend = TRUE; if( (res = fn( row, a, NULL, NULL )) ) return( res ); return( row_dependent_map_sub( row, fn, a ) ); } /* Apply to all dependents of row. */ static void * row_dependent_map_sub( Row *row, row_map_fn fn, void *a ) { Row *i; void *res; /* Things that refer to us. */ if( (res = slist_map2( row->parents, (SListMap2Fn) row_dependent_mark, (void *) fn, a )) ) return( res ); /* Things that refer to our enclosing syms ... eg. if A1.fred.x * changes, we don't want to recalc A1.fred, we do want to recalc * anything that refers to A1.fred. */ for( i = row; (i = HEAPMODEL( i )->row); ) if( (res = row_dependent_map_sub( i, fn, a )) ) return( res ); /* We are not going to spot things that refer to this.us :-( we could * say anything that depends on "this" depends on us, but that's much * too broad (and much too slow). FIXME ... could use dynamic dependency stuff to find things that refer to this.us? */ return( NULL ); } static void * row_dependent_clear( Row *row ) { row->depend = FALSE; return( NULL ); } /* Apply a function to all rows in this tree which depend on this row. */ void * row_dependent_map( Row *row, row_map_fn fn, void *a ) { /* Clear the flags we use to spot loops. */ row_map_all( row->top_row, (row_map_fn) row_dependent_clear, NULL, NULL, NULL ); return( row_dependent_map_sub( row, fn, a ) ); } /* This row has changed ... mark all dependents (direct and indirect) * dirty. */ void * row_dirty( Row *row, gboolean clear_error ) { (void) row_dirty_set( row, clear_error ); (void) row_dependent_map( row, (row_map_fn) row_dirty_set, GINT_TO_POINTER( clear_error ) ); return( NULL ); } /* This tally has changed ... mark all dependents (but not this one!) * dirty. */ void * row_dirty_intrans( Row *row, gboolean clear_error ) { (void) row_dependent_map( row, (row_map_fn) row_dirty_set, GINT_TO_POINTER( clear_error ) ); return( NULL ); } /* Find the 'depth' of a row ... 0 is top level. */ static int row_recomp_depth( Row *row ) { if( row == row->top_row ) return( 0 ); return( 1 + row_recomp_depth( row_get_parent( row ) ) ); } /* Compare func for row recomp sort. */ static int row_recomp_sort_func( Row *a, Row *b ) { int order; #ifdef DEBUG_TIME_SORT static GTimer *sort_func_timer = NULL; if( !sort_func_timer ) sort_func_timer = g_timer_new(); g_timer_reset( sort_func_timer ); #endif /*DEBUG_TIME_SORT*/ #ifdef DEBUG_SORT_VERBOSE printf( "row_recomp_sort_func: " ); #endif /*DEBUG_SORT_VERBOSE*/ /* If b depends on a, want a first. */ if( row_dependent_map( a, (row_map_fn) map_equal, b ) ) { #ifdef DEBUG_SORT_VERBOSE row_name_print( a ); printf( "before " ); row_name_print( b ); printf( "(2nd depends on 1st)\n" ); #endif /*DEBUG_SORT_VERBOSE*/ order = -1; } else if( row_dependent_map( b, (row_map_fn) map_equal, a ) ) { #ifdef DEBUG_SORT_VERBOSE row_name_print( b ); printf( "before " ); row_name_print( a ); printf( "(2nd depends on 1st #2)\n" ); #endif /*DEBUG_SORT_VERBOSE*/ order = 1; } else { int adepth = row_recomp_depth( a ); int bdepth = row_recomp_depth( b ); #ifdef DEBUG_SORT_VERBOSE if( adepth < bdepth ) { row_name_print( a ); printf( "before " ); row_name_print( b ); printf( "(1st shallower)\n" ); } else if( bdepth < adepth ) { row_name_print( b ); printf( "before " ); row_name_print( a ); printf( "(1st shallower)\n" ); } else { row_name_print( a ); printf( "and " ); row_name_print( b ); printf( "independent\n" ); } #endif /*DEBUG_SORT_VERBOSE*/ /* No dependency ... want shallower first. */ order = adepth - bdepth; } #ifdef DEBUG_TIME_SORT printf( "row_recomp_sort_func: took %gs\n", g_timer_elapsed( sort_func_timer, NULL ) ); #endif /*DEBUG_TIME_SORT*/ return( order ); } /* Insert-sort an slist. */ static GSList * row_recomp_sort_slist( GSList *old ) { GSList *new; GSList *p; new = NULL; for( p = old; p; p = p->next ) { Row *a = (Row *) p->data; Row *b; GSList *q; for( q = new; q; q = q->next ) { b = (Row *) q->data; if( row_recomp_sort_func( a, b ) < 0 ) break; } if( q ) { q->data = a; q->next = g_slist_prepend( q->next, b ); } else new = g_slist_append( new, a ); } g_slist_free( old ); return( new ); } /* Sort dirties into recomp order. */ static void row_recomp_sort( Row *row ) { #ifdef DEBUG_TIME_SORT static GTimer *sort_timer = NULL; if( !sort_timer ) sort_timer = g_timer_new(); g_timer_reset( sort_timer ); #endif /*DEBUG_TIME_SORT*/ g_assert( row == row->top_row ); /* Nope, can't use g_slist_sort(). We have a partial order and * g_slist_sort() uses an algorithm that assumes a full order. Do a * simple insert-sort, it'll do enough comparisons that we won't miss * things. row->recomp = g_slist_sort( row->recomp, (GCompareFunc) row_recomp_sort_func ); */ row->recomp = row_recomp_sort_slist( row->recomp ); #ifdef DEBUG_TIME_SORT printf( "row_recomp_sort: took %gs\n", g_timer_elapsed( sort_timer, NULL ) ); #endif /*DEBUG_TIME_SORT*/ #ifdef DEBUG_SORT printf( "row_recomp: sorted dirties are: " ); slist_map( row->recomp, (SListMapFn) row_name_print, NULL ); printf( "\n" ); #endif /*DEBUG_SORT*/ } static gboolean row_regenerate( Row *row ) { Expr *expr = row->expr; PElement base; /* Regenerate any compiled code. */ if( expr->compile ) { PEPOINTE( &base, &expr->compile->base ); if( !PEISNOVAL( &base ) ) { PElement *root = &expr->root; if( row == row->top_row ) { /* Recalcing base of tally display ... not a * class member, must be a sym with a value. */ gboolean res; res = reduce_regenerate( expr, root ); expr_new_value( expr ); if( !res ) return( FALSE ); } else { /* Recalcing a member somewhere inside ... * regen (member this) pair. Get the "this" * for the enclosing class instance ... the * top one won't always be right (eg. for * local classes); the enclosing one should * be the same as the most enclosing this. */ Row *this = row->scol->this; gboolean res; res = reduce_regenerate_member( expr, &this->expr->root, root ); expr_new_value( expr ); if( !res ) return( FALSE ); } /* We may have made a new class instance ... all our * children need to update their heap pointers. */ if( heapmodel_new_heap( HEAPMODEL( row ), root ) ) return( FALSE ); } } return( TRUE ); } static gboolean row_recomp_row( Row *row ) { Rhs *rhs = row->child_rhs; #ifdef DEBUG printf( "row_recomp_row: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ /* Not much we can do. */ if( !row->expr ) return( TRUE ); /* Clear old error state. */ expr_error_clear( row->expr ); /* Parse and compile any changes to our text since we last came through. */ if( rhs && rhs->itext && heapmodel_update_heap( HEAPMODEL( rhs->itext ) ) ) return( FALSE ); /* We're about to zap the graph: make sure this tree of rows has a * private copy. */ if( !subcolumn_make_private( row->scol ) ) return( FALSE ); /* Regenerate from the expr. */ if( !row_regenerate( row ) ) return( FALSE ); /* Reapply any graphic mods. */ if( rhs && rhs->graphic ) { Classmodel *classmodel = CLASSMODEL( rhs->graphic ); /* If the graphic is non-default, need to set modified to make * sure we reapply the changes. */ if( classmodel->edited ) heapmodel_set_modified( HEAPMODEL( classmodel ), TRUE ); if( heapmodel_update_heap( HEAPMODEL( classmodel ) ) ) return( FALSE ); } progress_update_tick(); return( TRUE ); } static void row_recomp_all( Row *top_row ) { /* Rebuild all dirty rows. */ while( !top_row->err && top_row->recomp ) { Row *dirty_row = ROW( top_row->recomp->data ); #ifdef DEBUG_ROW static GTimer *timer = NULL; if( !timer ) timer = g_timer_new(); g_timer_reset( timer ); #endif /*DEBUG_ROW*/ #ifdef DEBUG_ROW printf( "row_recomp_all: starting " ); row_name_print( dirty_row ); printf( "\n" ); #endif /*DEBUG_ROW*/ if( !row_recomp_row( dirty_row ) ) { /* This will set top_row->err and end the loop. */ if( dirty_row->expr ) expr_error_set( dirty_row->expr ); } else row_dirty_clear( dirty_row ); #ifdef DEBUG_ROW printf( "\t%gs\n", g_timer_elapsed( timer, NULL ) ); #endif /*DEBUG_ROW*/ #ifdef DEBUG printf( "row_recomp_all: after row recomp, top value now " ); pgraph( &top_row->expr->root ); #endif /*DEBUG*/ } } void row_recomp( Row *row ) { Row *top_row = row->top_row; static GTimer *recomp_timer = NULL; if( !recomp_timer ) recomp_timer = g_timer_new(); g_timer_reset( recomp_timer ); /* Sort dirties into recomp order. */ row_recomp_sort( top_row ); /* Take a copy of the recomp list for later testing. */ IM_FREEF( g_slist_free, top_row->recomp_save ); top_row->recomp_save = g_slist_copy( top_row->recomp ); /* Remove all top-level dependencies. */ symbol_link_destroy( top_row->sym ); /* Remove any row recomp links we have. */ (void) row_map_all( top_row, (row_map_fn) row_link_destroy, NULL, NULL, NULL ); /* Rebuild all dirty rows. This may add some dynamic top links. */ row_recomp_all( top_row ); /* Our workspace may have been closed in a callback: bail out. */ if( !top_row->sym ) return; /* Add all static row links. Have to do this after any * parsing in row_recomp_all(). */ (void) row_map_all( top_row, (row_map_fn) row_link_build, NULL, NULL, NULL ); /* Remake all static top-level links. */ (void) symbol_link_build( top_row->sym ); /* Now we know dependencies ... mark everything dirty again. This may * pick up stuff we missed last time and may change the order we * recomp rows in. * * Be careful not to wipe out any errors we found on this first pass. */ slist_map( top_row->recomp_save, (SListMapFn) row_dirty, FALSE ); /* Is this topsym still a leaf? We may have discovered an external * reference to another dirty top-level sym. We can come back here * later. */ if( top_row->sym->ndirtychildren != 0 ) { IM_FREEF( g_slist_free, top_row->recomp_save ); return; } /* Sort dirties into recomp order. */ row_recomp_sort( top_row ); /* Now: if the recomp list is the same as last time, we don't need to * recalc again. */ if( slist_equal( top_row->recomp_save, top_row->recomp ) ) { /* Provided we didn't abandon recomp on an error, we can * just mark all rows clean. */ if( !top_row->err ) slist_map( top_row->recomp, (SListMapFn) row_dirty_clear, NULL ); } else { #ifdef DEBUG_DIRTY printf( "row_recomp: recomp list has changed ... pass 2\n" ); #endif /*DEBUG_DIRTY*/ /* Rebuild all dirty rows in a second pass. */ row_recomp_all( top_row ); /* Our workspace may have been closed in a callback: bail out. */ if( !top_row->sym ) return; } IM_FREEF( g_slist_free, top_row->recomp_save ); /* The symbol can be cleared as well. */ if( !top_row->err ) symbol_dirty_clear( top_row->sym ); /* Now we're clean, all models can update from the heap. Rows * containing errors can have bad pointers in, so careful. */ if( !top_row->err && icontainer_map_all( ICONTAINER( top_row ), (icontainer_map_fn) heapmodel_update_model, NULL ) ) expr_error_set( top_row->expr ); if( main_option_profile ) { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); Symbol *context = symbol_get_parent( top_row->ws->sym ); row_qualified_name_relative( context, top_row, &buf ); printf( "%s\t%g\n", vips_buf_all( &buf ), g_timer_elapsed( recomp_timer, NULL ) ); } #ifdef DEBUG printf( "row_recomp: value of " ); row_name_print( top_row ); printf( "is " ); pgraph( &top_row->expr->root ); #endif /*DEBUG*/ } /* Test, suitable for mapping. */ void * row_is_selected( Row *row ) { if( row->selected ) return( row ); return( NULL ); } /* Deselect a row. */ void * row_deselect( Row *row ) { Workspace *ws = row->ws; if( !row->selected ) return( NULL ); g_assert( ws && IS_WORKSPACE( ws ) ); g_assert( g_slist_find( ws->selected, row ) ); ws->selected = g_slist_remove( ws->selected, row ); row->selected = FALSE; /* Hack: if this is a matrix with selected cells, deselect the matrix * sellection too. We should really have a row method for this I * guess :-( See also workspace_selected_names_sub(). */ if( row->child_rhs && row->child_rhs->graphic && IS_MATRIX( row->child_rhs->graphic ) && MATRIX( row->child_rhs->graphic )->selected ) matrix_deselect( MATRIX( row->child_rhs->graphic ) ); iobject_changed( IOBJECT( row ) ); iobject_changed( IOBJECT( ws ) ); return( NULL ); } /* Select a row. */ static void row_select2( Row *row ) { if( !row->selected ) { Workspace *ws = row->ws; row->selected = TRUE; ws->selected = g_slist_append( ws->selected, row ); iobject_changed( IOBJECT( row ) ); iobject_changed( IOBJECT( ws ) ); } } /* Make sure a row is selected ... used for (eg.) select changed on gktsheet. * No deselection. */ void * row_select_ensure( Row *row ) { row_select2( row ); /* Note for extend select. */ row->top_col->last_select = row; return( NULL ); } /* Select a row, deselecting others first. */ void * row_select( Row *row ) { Workspace *ws = row->ws; workspace_deselect_all( ws ); row_select2( row ); /* Note for extend select. */ row->top_col->last_select = row; return( NULL ); } /* Extend the previous selection. */ void * row_select_extend( Row *row ) { Column *col = row->top_col; Row *last_select = col->last_select; /* Range select if there was a previous selection, and it was in the * same subcolumn. */ if( last_select && row->scol == last_select->scol ) { Subcolumn *scol = row->scol; GSList *rows = ICONTAINER( scol )->children; int pos = g_slist_index( rows, row ); int pos_last = g_slist_index( rows, last_select ); int step = pos > pos_last ? 1 : -1; int i; g_assert( pos != -1 && pos_last != -1 ); for( i = pos_last; i != pos + step; i += step ) row_select2( ROW( g_slist_nth_data( rows, i ) ) ); } else row_select2( row ); /* Note for extend select. */ col->last_select = row; return( NULL ); } /* Toggle a selection. */ void * row_select_toggle( Row *row ) { if( row->selected ) { row_deselect( row ); row->top_col->last_select = NULL; } else { row_select2( row ); row->top_col->last_select = row; } return( NULL ); } /* Do a select action using a modifier. */ void row_select_modifier( Row *row, guint state ) { if( state & GDK_CONTROL_MASK ) row_select_toggle( row ); else if( state & GDK_SHIFT_MASK ) row_select_extend( row ); else row_select( row ); } static void row_set_show( Row *row, RowShowState show ) { if( row->show != show ) { row->show = show; iobject_changed( IOBJECT( row ) ); } } static void * row_show_parent( Link *link, RowShowState show ) { if( link->parent->expr && link->parent->expr->row ) row_set_show( link->parent->expr->row, show ); return( NULL ); } static void * row_show_child( Link *link, RowShowState show ) { if( link->child->expr && link->child->expr->row ) row_set_show( link->child->expr->row, show ); return( NULL ); } void row_show_dependents( Row *row ) { Symbol *topsym = row->top_row->sym; #ifdef DEBUG printf( "row_show_dependents: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ if( topsym ) { slist_map( topsym->topparents, (SListMapFn) row_show_parent, GUINT_TO_POINTER( ROW_SHOW_PARENT ) ); slist_map( topsym->topchildren, (SListMapFn) row_show_child, GUINT_TO_POINTER( ROW_SHOW_CHILD ) ); } } void row_hide_dependents( Row *row ) { Symbol *topsym; #ifdef DEBUG printf( "row_hide_dependents: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ if( row->top_row && (topsym = row->top_row->sym) ) { slist_map( topsym->topparents, (SListMapFn) row_show_parent, GUINT_TO_POINTER( ROW_SHOW_NONE ) ); slist_map( topsym->topchildren, (SListMapFn) row_show_child, GUINT_TO_POINTER( ROW_SHOW_NONE ) ); } } /* Set help for a row. Used by rowview and itextview etc. on mouseover. */ void row_set_status( Row *row ) { Expr *expr = row->expr; char txt[MAX_LINELENGTH]; VipsBuf buf = VIPS_BUF_STATIC( txt ); /* No symbol? eg. on load error. */ if( !expr ) return; row_qualified_name( row, &buf ); if( expr->err ) { vips_buf_appends( &buf, ": " ); vips_buf_appends( &buf, expr->error_top ); } else if( row->child_rhs->itext ) { iText *itext = ITEXT( row->child_rhs->itext ); vips_buf_appends( &buf, " = " ); if( row->ws && row->ws->mode != WORKSPACE_MODE_FORMULA ) vips_buf_appends( &buf, NN( itext->formula ) ); else vips_buf_appends( &buf, vips_buf_all( &itext->value ) ); } workspace_set_status( row->ws, "%s", vips_buf_firstline( &buf ) ); } /* Sub fn of below ... search inside a row hierarcy. Context is (eg.) row * "A1", path is (eg.) "super.name". */ static Row * row_parse_name_row( Row *context, const char *path ) { char name[256]; char *tail; Row *row; Subcolumn *scol; #ifdef DEBUG printf( "row_parse_name_row: \"%s\"\n", path ); #endif /*DEBUG*/ /* Break the name into "thing.tail", where tail could contain other * "." qualifiers. */ im_strncpy( name, path, 256 ); if( !(tail = break_token( name, "." )) ) /* Passed empty string. */ return( context ); /* Needs to be a subcolumn to look inside. We could search the value, * but it's safer to look inside the model we've built from the value. */ if( !context->child_rhs || !context->child_rhs->scol || !(scol = SUBCOLUMN( context->child_rhs->scol )) ) return( NULL ); if( !(row = subcolumn_map( scol, (row_map_fn) iobject_test_name, name, NULL )) ) return( NULL ); return( row_parse_name_row( row, tail ) ); } /* Parse a qualified name .. eg. "untitled.A1.name" and find the row. Find * relative to context. Context is a sym, so we can have workspaceroot etc. */ Row * row_parse_name( Symbol *context, const char *path ) { char name[256]; char *tail; Symbol *sym; Row *row; #ifdef DEBUG printf( "row_parse_name: \"%s\"\n", path ); #endif /*DEBUG*/ /* Break the name into "thing.tail", where tail could contain other * "." qualifiers. */ im_strncpy( name, path, 256 ); if( !(tail = break_token( name, "." )) ) { /* Run out of names ... return this row, if we've found one. */ if( context->expr ) return( context->expr->row ); else return( NULL ); } /* Try to look up name in context. For scopes, we can do it * statically. For other syms, look up in the value of the symbol. */ switch( context->type ) { case SYM_WORKSPACE: case SYM_WORKSPACEROOT: case SYM_ROOT: if( !(sym = compile_lookup( context->expr->compile, name )) ) return( NULL ); break; case SYM_VALUE: if( !(row = context->expr->row) ) return( NULL ); /* Hand off to the row searcher. */ return( row_parse_name_row( row, path ) ); case SYM_ZOMBIE: case SYM_PARAM: case SYM_EXTERNAL: case SYM_BUILTIN: default: /* How odd. */ return( NULL ); } return( row_parse_name( sym, tail ) ); } nip2-8.7.1/src/valueview.h0000644000175000017500000000307313351443023012270 00000000000000/* a basic view of a model ... just show the caption */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_VALUEVIEW (valueview_get_type()) #define VALUEVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_VALUEVIEW, Valueview )) #define VALUEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_VALUEVIEW, ValueviewClass )) #define IS_VALUEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_VALUEVIEW )) #define IS_VALUEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_VALUEVIEW )) typedef struct _Valueview { Graphicview parent_object; GtkWidget *eb; GtkWidget *label; } Valueview; typedef struct _ValueviewClass { GraphicviewClass parent_class; /* My methods. */ } ValueviewClass; GtkType valueview_get_type( void ); View *valueview_new( void ); nip2-8.7.1/src/watch.h0000644000175000017500000003327313351443023011374 00000000000000/* Watch stuff in the prefs workspace. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your watch) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Group watches with this. */ #define TYPE_WATCHGROUP (watchgroup_get_type()) #define WATCHGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCHGROUP, Watchgroup )) #define WATCHGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCHGROUP, WatchgroupClass)) #define IS_WATCHGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCHGROUP )) #define IS_WATCHGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCHGROUP )) #define WATCHGROUP_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCHGROUP, WatchgroupClass )) typedef struct _Watchgroup { iContainer parent_object; /* Workspaces we work within. Assume we are destroyed before this. */ Workspaceroot *workspaceroot; /* Name of workspace our watchers check for their syms. */ const char *name; /* Autosave timeout ... save our workspace automatically when this * ticks away. */ guint auto_save_timeout; } Watchgroup; typedef struct _WatchgroupClass { iContainerClass parent_class; /* One of the watches in this group has changed. * People interested in several watches can connect to * this, rather than having to try listening for many "changed" signals * on the watches. */ void (*watch_changed)( Watchgroup *, Watch * ); } WatchgroupClass; GType watchgroup_get_type( void ); Watchgroup *watchgroup_new( Workspaceroot *workspaceroot, const char *name ); void watchgroup_flush( Watchgroup *watchgroup ); /* Abstract base class for something that watches a row. */ #define TYPE_WATCH (watch_get_type()) #define WATCH( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH, Watch )) #define WATCH_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH, WatchClass)) #define IS_WATCH( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH )) #define IS_WATCH_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH )) #define WATCH_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH, WatchClass )) typedef void (*WatchCallbackFn)( void * ); struct _Watch { iContainer parent_class; Row *row; /* Row we watch */ gboolean ok; /* Value read OK on last change */ guint destroy_sid; /* Listen for events */ guint changed_sid; }; typedef struct _WatchClass { iContainerClass parent_class; /* Update value from row. */ gboolean (*update)( Watch * ); /* Get a pointer to value. */ void *(*get_value)( Watch * ); } WatchClass; Watch *watch_find( Watchgroup *watchgroup, const char *name ); GtkType watch_get_type( void ); void watch_relink_all( void ); void watch_vset( Watch *watch, const char *fmt, va_list args ); void watch_set( Watch *watch, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); /* A watch that watches something with an int value. */ typedef struct _WatchInt WatchInt; #define TYPE_WATCH_INT (watch_int_get_type()) #define WATCH_INT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_INT, WatchInt )) #define WATCH_INT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_INT, WatchIntClass)) #define IS_WATCH_INT( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_INT )) #define IS_WATCH_INT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_INT )) #define WATCH_INT_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_INT, WatchIntClass )) struct _WatchInt { Watch parent_class; int value; }; typedef struct _WatchIntClass { WatchClass parent_class; } WatchIntClass; GtkType watch_int_get_type( void ); int watch_int_get( Watchgroup *, const char *name, int fallback ); /* A watch that watches something with a double value. */ typedef struct _WatchDouble WatchDouble; #define TYPE_WATCH_DOUBLE (watch_double_get_type()) #define WATCH_DOUBLE( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_DOUBLE, WatchDouble )) #define WATCH_DOUBLE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_DOUBLE, WatchDoubleClass)) #define IS_WATCH_DOUBLE( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_DOUBLE )) #define IS_WATCH_DOUBLE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_DOUBLE )) #define WATCH_DOUBLE_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_DOUBLE, \ WatchDoubleClass )) struct _WatchDouble { Watch parent_class; double value; }; typedef struct _WatchDoubleClass { WatchClass parent_class; } WatchDoubleClass; GtkType watch_double_get_type( void ); double watch_double_get( Watchgroup *, const char *name, double fallback ); /* A watch that watches a path. */ typedef struct _WatchPath WatchPath; #define TYPE_WATCH_PATH (watch_path_get_type()) #define WATCH_PATH( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_PATH, WatchPath )) #define WATCH_PATH_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_PATH, WatchPathClass)) #define IS_WATCH_PATH( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_PATH )) #define IS_WATCH_PATH_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_PATH )) #define WATCH_PATH_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_PATH, WatchPathClass )) struct _WatchPath { Watch parent_class; GSList *value; }; typedef struct _WatchPathClass { WatchClass parent_class; } WatchPathClass; GtkType watch_path_get_type( void ); GSList *watch_path_get( Watchgroup *, const char *name, GSList *fallback ); typedef struct _WatchBool WatchBool; #define TYPE_WATCH_BOOL (watch_bool_get_type()) #define WATCH_BOOL( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_BOOL, WatchBool )) #define WATCH_BOOL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_BOOL, WatchBoolClass)) #define IS_WATCH_BOOL( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_BOOL )) #define IS_WATCH_BOOL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_BOOL )) #define WATCH_BOOL_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_BOOL, WatchBoolClass )) struct _WatchBool { Watch parent_class; gboolean value; }; typedef struct _WatchBoolClass { WatchClass parent_class; } WatchBoolClass; GtkType watch_bool_get_type( void ); gboolean watch_bool_get( Watchgroup *, const char *name, gboolean fallback ); typedef struct _WatchString WatchString; #define TYPE_WATCH_STRING (watch_string_get_type()) #define WATCH_STRING( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_STRING, WatchString )) #define WATCH_STRING_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_STRING, WatchStringClass)) #define IS_WATCH_STRING( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_STRING )) #define IS_WATCH_STRING_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_STRING )) #define WATCH_STRING_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_STRING, \ WatchStringClass )) struct _WatchString { Watch parent_class; char *value; }; typedef struct _WatchStringClass { WatchClass parent_class; } WatchStringClass; GtkType watch_string_get_type( void ); const char *watch_string_get( Watchgroup *, const char *name, const char *fallback ); /* Prefs we follow from C. */ /* Default show states. */ #define DISPLAY_RULERS \ (watch_bool_get( main_watchgroup, "DISPLAY_RULERS", FALSE )) #define DISPLAY_STATUS \ (watch_bool_get( main_watchgroup, "DISPLAY_STATUS", FALSE )) #define DISPLAY_CONVERSION \ (watch_bool_get( main_watchgroup, "DISPLAY_CONVERSION", FALSE )) /* Display a crosshair on image windows ... turn-off-able, since some desktop * themes have almost invisible crosshairs. */ #define DISPLAY_CROSSHAIR \ (watch_bool_get( main_watchgroup, "DISPLAY_CROSSHAIR", TRUE )) /* Update children during paint. */ #define PAINTBOX_RECOMP \ (watch_bool_get( main_watchgroup, "PAINTBOX_RECOMP", TRUE )) /* Help browser. */ #define BOX_BROWSER (watch_string_get( main_watchgroup, "BROWSER", "mozilla" )) #define BOX_BROWSER_REMOTE (watch_string_get( main_watchgroup, \ "BROWSER_REMOTE", "-remote 'openURL(%s)'" )) /* Thumbnail size. */ #define DISPLAY_THUMBNAIL \ (watch_int_get( main_watchgroup, "DISPLAY_THUMBNAIL", 64 )) /* High-quality thumbnails. */ #define DISPLAY_THUMBNAIL_HQ \ (watch_bool_get( main_watchgroup, "DISPLAY_THUMBNAIL_HQ", FALSE )) /* File stuff. */ #define PIN_FILESEL \ (watch_bool_get( main_watchgroup, "CALC_PIN_FILESEL", FALSE )) #define IP_JPEG_Q \ (watch_int_get( main_watchgroup, "JPEG_Q", 75 )) #define IP_JPEG_ICC_PROFILE \ (watch_int_get( main_watchgroup, "JPEG_ICC_PROFILE", 0 )) #define IP_JPEG_ICC_PROFILE_FILE \ (watch_string_get( main_watchgroup, "JPEG_ICC_PROFILE_FILE", \ "$VIPSHOME/share/nip2/data/sRGB.icm" )) #define IP_PPM_MODE \ (watch_int_get( main_watchgroup, "PPM_MODE", 0 )) #define IP_CSV_SEPARATOR \ (watch_string_get( main_watchgroup, "CSV_SEPARATOR", "\t" )) #define IP_PNG_COMPRESSION \ (watch_int_get( main_watchgroup, "PNG_COMPRESSION", 6 )) #define IP_PNG_INTERLACE \ (watch_int_get( main_watchgroup, "PNG_INTERLACE", 0 )) #define IP_TIFF_COMPRESSION \ (watch_int_get( main_watchgroup, "TIFF_COMPRESSION", 0 )) #define IP_TIFF_JPEG_Q \ (watch_int_get( main_watchgroup, "TIFF_JPEG_Q", 75 )) #define IP_TIFF_LAYOUT \ (watch_int_get( main_watchgroup, "TIFF_LAYOUT", 0 )) #define IP_TIFF_TILE_WIDTH \ (watch_int_get( main_watchgroup, "TIFF_TILE_WIDTH", 128 )) #define IP_TIFF_TILE_HEIGHT \ (watch_int_get( main_watchgroup, "TIFF_TILE_HEIGHT", 128 )) #define IP_TIFF_MULTI_RES \ (watch_int_get( main_watchgroup, "TIFF_MULTI_RES", 0 )) #define IP_TIFF_FORMAT \ (watch_int_get( main_watchgroup, "TIFF_FORMAT", 0 )) #define IP_TIFF_PREDICTOR \ (watch_int_get( main_watchgroup, "TIFF_PREDICTOR", 0 )) #define IP_TIFF_BIGTIFF \ (watch_bool_get( main_watchgroup, "TIFF_BIGTIFF", FALSE )) /* Autoreload. */ #define CALC_RELOAD (watch_bool_get( main_watchgroup, "CALC_RELOAD", FALSE )) /* Max chars we print. */ #define LINELENGTH \ IM_CLIP( 10, \ watch_int_get( main_watchgroup, "CALC_LINELENGTH", 80 ), \ MAX_LINELENGTH ) /* CPUs we work over. */ #define VIPS_CPUS \ (watch_int_get( main_watchgroup, "VIPS_CPUS", 1 )) /* Bar prefs. */ #define MAINW_TOOLBAR \ (watch_bool_get( main_watchgroup, "MAINW_TOOLBAR", TRUE )) #define MAINW_TOOLBAR_STYLE \ (watch_int_get( main_watchgroup, "MAINW_TOOLBAR_STYLE", 0 )) #define MAINW_STATUSBAR \ (watch_bool_get( main_watchgroup, "MAINW_STATUSBAR", TRUE )) #define WORKSPACE_LPANE_OPEN \ (watch_bool_get( main_watchgroup, "WORKSPACE_LPANE_OPEN", FALSE )) #define WORKSPACE_LPANE_POSITION \ (watch_int_get( main_watchgroup, "WORKSPACE_LPANE_POSITION", 200 )) #define WORKSPACE_RPANE_OPEN \ (watch_bool_get( main_watchgroup, "WORKSPACE_RPANE_OPEN", FALSE )) #define WORKSPACE_RPANE_POSITION \ (watch_int_get( main_watchgroup, "WORKSPACE_RPANE_POSITION", 400 )) /* Heap size. Big enough to always load prefs, small enough that it doesn't * trash the computer. */ #define MAX_HEAPSIZE \ IM_CLIP( 100000, \ watch_int_get( main_watchgroup, "CALC_MAX_HEAP", 200000 ), \ 10000000 ) /* Region dragging. */ #ifdef NO_UPDATE #define CALC_RECOMP_REGION \ (watch_bool_get( main_watchgroup, "CALC_RECOMP_REGION", FALSE )) #else #define CALC_RECOMP_REGION \ (watch_bool_get( main_watchgroup, "CALC_RECOMP_REGION", TRUE )) #endif /* Slider dragging. */ #define CALC_RECOMP_SLIDER \ (watch_bool_get( main_watchgroup, "CALC_RECOMP_SLIDER", FALSE )) /* Popup new objects. */ #define POPUP_NEW_ROWS \ (watch_bool_get( main_watchgroup, "POPUP_NEW_ROWS", FALSE )) /* Draw LEDs rather than recolouring tally buttons. */ #define CALC_DISPLAY_LED \ (watch_bool_get( main_watchgroup, "CALC_DISPLAY_LED", FALSE )) /* Number of vips calls to memoise. */ #define CALL_HISTORY_MAX \ (watch_int_get( main_watchgroup, "VIPS_HISTORY_MAX", 200 )) /* Auto save wses. */ #define AUTO_WS_SAVE \ (watch_bool_get( main_watchgroup, "CALC_AUTO_WS_SAVE", TRUE )) /* Image window geometry. */ #define IMAGE_WINDOW_WIDTH \ (watch_int_get( main_watchgroup, "IMAGE_WINDOW_WIDTH", 600 )) #define IMAGE_WINDOW_HEIGHT \ (watch_int_get( main_watchgroup, "IMAGE_WINDOW_HEIGHT", 650 )) /* Default font. */ #define PAINTBOX_FONT \ (watch_string_get( main_watchgroup, "PAINTBOX_FONT", "Sans 12" )) /* Max undo steps ... -1 == unlimited. */ #define PAINTBOX_MAX_UNDO \ (watch_int_get( main_watchgroup, "PAINTBOX_MAX_UNDO", -1 )) /* Default image file type. */ #define IMAGE_FILE_TYPE \ (watch_int_get( main_watchgroup, "IMAGE_FILE_TYPE", 0 )) /* Prefs we watch. */ #define PATH_SEARCH (watch_path_get( main_watchgroup, "CALC_PATH_SEARCH", \ path_search_default )) #define PATH_START (watch_path_get( main_watchgroup, "CALC_PATH_START", \ path_start_default )) #define PATH_TMP (watch_string_get( main_watchgroup, "CALC_PATH_TMP", \ path_tmp_default )) /* How we print stuff. */ #define TRACE_FUNCTIONS \ (watch_bool_get( main_watchgroup, "CALC_TRACE_FUNCTIONS", FALSE )) #define PRINT_CARTESIAN \ (watch_bool_get( main_watchgroup, "CALC_PRINT_CARTIESIAN", FALSE )) /* Program window. */ #define PROGRAM_PANE_POSITION \ (watch_double_get( main_watchgroup, "PROGRAM_PANE_POSITION", 200 )) nip2-8.7.1/src/builtin.h0000644000175000017500000000310713351443023011725 00000000000000/* Execute builtin functions. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* A type spotter ... a type name (used in error messages), plus a predicate. */ typedef struct { const char *name; gboolean (*pred)( Reduce *, PElement * ); } BuiltinTypeSpot; /* A builtin function. */ typedef void (*builtin_fn)( Reduce *, const char *, HeapNode **, PElement * ); /* A function name and a pointer to an implementation. */ struct _BuiltinInfo { const char *name; const char *desc; gboolean override; int nargs; BuiltinTypeSpot **args; builtin_fn fn; }; void builtin_init( void ); void builtin_usage( VipsBuf *buf, BuiltinInfo *builtin ); void builtin_run( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out, BuiltinInfo *builtin ); nip2-8.7.1/src/ip.h0000644000175000017500000003212513351443023010671 00000000000000/* All ip headers. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* We can get multiple includes sometimes, gah, thank you bison. */ #ifndef IP_H #define IP_H /* DEBUG everywhere. #define DEBUG */ /* Turn off VIPS's old and broken defines, we don't need them. */ #define IM_NO_VIPS7_COMPAT /* Enable heap sanity checks on every alloc ... very slow ... also see heap.c #define DEBUG_HEAP */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #ifdef ENABLE_NLS #include #define _(String) gettext(String) #ifdef gettext_noop #define N_(String) gettext_noop(String) #else #define N_(String) (String) #endif #else /* NLS is disabled */ #define _(String) (String) #define N_(String) (String) #define textdomain(String) (String) #define gettext(String) (String) #define dgettext(Domain,String) (String) #define dcgettext(Domain,String,Type) (String) #define bindtextdomain(Domain,Directory) (Domain) #define bind_textdomain_codeset(Domain,Codeset) (Codeset) #define ngettext(S, P, N) ((N) == 1 ? (S) : (P)) #endif /* ENABLE_NLS */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_PWD_H #include #endif /*HAVE_PWD_H*/ #ifdef HAVE_FNMATCH_H #include #endif /*HAVE_FNMATCH_H*/ #ifdef HAVE_SYS_PARAM_H #include #endif /*HAVE_SYS_PARAM_H*/ #include #ifdef HAVE_SYS_TIME_H #include #endif /*HAVE_SYS_TIME_H*/ #include #ifdef HAVE_SYS_RESOURCE_H #include #endif /*HAVE_SYS_RESOURCE_H*/ #ifdef HAVE_SYS_WAIT_H #include #endif /*HAVE_SYS_WAIT_H*/ #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #ifdef HAVE_SYS_STATVFS_H #include #endif /*HAVE_SYS_STATVFS_H*/ #ifdef HAVE_SYS_VFS_H #include extern int statfs(); #endif /*HAVE_SYS_VFS_H*/ #ifdef HAVE_SYS_MOUNT_H #include #endif /*HAVE_SYS_MOUNT_H*/ #ifdef OS_WIN32 #include #endif /*OS_WIN32*/ #ifdef HAVE_FFTW #include #endif /*HAVE_FFTW*/ #ifdef HAVE_FFTW3 #include #endif /*HAVE_FFTW3*/ #include /* Have to include glib before dmalloc ... dmalloc may be included by vips.h */ #include #include #ifdef HAVE_LIBGOFFICE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /*HAVE_LIBGOFFICE*/ #ifdef HAVE_LIBGVC #include #endif /*HAVE_LIBGVC*/ #include #include #include #include #include /* If we're not using GNU C, elide __attribute__ */ #ifndef __GNUC__ # ifndef __attribute__ # define __attribute__(x) /*NOTHING*/ # endif #endif /* Our general widgets. */ #include "formula.h" #include "doubleclick.h" /* Generated marshallers. */ #include "nipmarshal.h" /* XML namespace ... note, not nip2! We can't change this. */ #define NAMESPACE "http://www.vips.ecs.soton.ac.uk/nip" #define MAXFILES (4000) /* Max. no of files in path */ #define STACK_SIZE (1000) /* Depth of eval stack */ #define LEN_LABEL (512) /* Label on windows */ #define MAX_SYSTEM (50) /* Max number of args we allow */ #define MAX_BANDS (64) /* Max number of bands in image */ #define MAX_CSTACK (10) /* Max number of cursors we stack */ #define MAX_STRSIZE (100000) /* Size of text for user defs */ #define MAX_TRACE (1024) /* Biggest thing we print in trace */ #define MAX_SSTACK (40) /* Scope stack for parser */ #define VIPS_HOMEPAGE "https://github.com/jcupitt/nip2" #define IP_NAME PACKAGE "-" VERSION #define NIP_DOCPATH "$VIPSHOME" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S \ "doc" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "html" #define VIPS_DOCPATH "$VIPSHOME" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S \ "doc" G_DIR_SEPARATOR_S "vips" G_DIR_SEPARATOR_S "html" #define IP_NAME PACKAGE "-" VERSION #define MAX_LINELENGTH (120) /* Max chars we display of value */ #define MAX_RECENT (10) /* Number of recent items in file menu */ #define NIP_COPYRIGHT "%s: ©2018 Imperial College, London" /* Our stock_ids. */ #define STOCK_NEXT_ERROR "nip-next-error" #define STOCK_DROPPER "nip-dropper" #define STOCK_DUPLICATE "nip-duplicate" #define STOCK_PAINTBRUSH "nip-paintbrush" #define STOCK_LINE "nip-linedraw" #define STOCK_TEXT "nip-text" #define STOCK_SMUDGE "nip-smudge" #define STOCK_FLOOD "nip-flood" #define STOCK_FLOOD_BLOB "nip-floodblob" #define STOCK_RECT "nip-rect" #define STOCK_MOVE "nip-move" #define STOCK_LOCK "nip-lock" #define STOCK_ALERT "nip-alert" #define STOCK_SELECT "nip-select" #define STOCK_LED_RED "nip-led-red" #define STOCK_LED_GREEN "nip-led-green" #define STOCK_LED_BLUE "nip-led-blue" #define STOCK_LED_YELLOW "nip-led-yellow" #define STOCK_LED_CYAN "nip-led-cyan" #define STOCK_LED_OFF "nip-led-off" /* How much we decompile for error messages. */ #define MAX_ERROR_FRAG (100) /* win32 adds '_', sometimes. */ #ifdef OS_WIN32 #ifndef popen #define popen(b,m) _popen(b,m) #endif /*popen*/ #ifndef pclose #define pclose(f) _pclose(f) #endif /*pclose*/ #define mktemp(f) _mktemp(f) #endif /*OS_WIN32*/ /* Fwd ref these. */ typedef struct _Watch Watch; typedef struct _Toolitem Toolitem; typedef struct _BuiltinInfo BuiltinInfo; typedef struct _Classmodel Classmodel; typedef struct _Colour Colour; typedef struct _Column Column; typedef struct _Columnview Columnview; typedef struct _Compile Compile; typedef struct _Conversion Conversion; typedef struct _Conversionview Conversionview; typedef struct _Expr Expr; typedef struct _Filemodel Filemodel; typedef struct _Heap Heap; typedef struct _HeapBlock HeapBlock; typedef struct _Heapmodel Heapmodel; typedef struct _iArrow iArrow; typedef struct _iImage iImage; typedef struct _Imagedisplay Imagedisplay; typedef struct _Managed Managed; typedef struct _Managedfile Managedfile; typedef struct _Managedgvalue Managedgvalue; typedef struct _Managedgobject Managedgobject; typedef struct _Managedstring Managedstring; typedef struct _Imageinfo Imageinfo; typedef struct _Imagepresent Imagepresent; typedef struct _Imagemodel Imagemodel; typedef struct _iRegion iRegion; typedef struct _iRegiongroup iRegiongroup; typedef struct _Link Link; typedef struct _LinkExpr LinkExpr; typedef struct _Model Model; typedef struct _iObject iObject; typedef struct _iContainer iContainer; typedef struct _Paintboxview Paintboxview; typedef struct _ParseConst ParseConst; typedef struct _ParseNode ParseNode; typedef struct _Program Program; typedef struct _String String; typedef struct _Number Number; typedef struct _Reduce Reduce; typedef struct _Regionview Regionview; typedef struct _Rhs Rhs; typedef struct _Rhsview Rhsview; typedef struct _Row Row; typedef struct _Rowview Rowview; typedef struct _Statusview Statusview; typedef struct _Plotstatus Plotstatus; typedef struct _Plot Plot; typedef struct _Plotwindow Plotwindow; typedef struct _Plotpresent Plotpresent; typedef struct _Plotmodel Plotmodel; typedef struct _Graphwindow Graphwindow; typedef struct _Subcolumn Subcolumn; typedef struct _Subcolumnview Subcolumnview; typedef struct _Symbol Symbol; typedef struct _Tool Tool; typedef struct _Toolkit Toolkit; typedef struct _Toolkitgroup Toolkitgroup; typedef struct _Toolkitgroupview Toolkitgroupview; typedef struct _Toolkitview Toolkitview; typedef struct _Toolview Toolview; typedef struct _Trace Trace; typedef struct _Preview Preview; typedef struct _Infobar Infobar; typedef struct _iError iError; typedef struct _Log Log; typedef struct _vObject vObject; typedef struct _View View; typedef struct _Workspace Workspace; typedef struct _Workspaceview Workspaceview; typedef struct _Workspaceroot Workspaceroot; typedef struct _Workspacegroup Workspacegroup; typedef struct _Workspacegroupview Workspacegroupview; typedef struct _Prefworkspaceview Prefworkspaceview; typedef struct _Prefcolumnview Prefcolumnview; typedef struct _iText iText; typedef struct _Expression Expression; typedef struct _Mainw Mainw; typedef struct _Toolviewitemgroup Toolviewitemgroup; typedef struct _Panechild Panechild; typedef struct _Toolkitbrowser Toolkitbrowser; typedef struct _Workspacedefs Workspacedefs; /* container map function typedefs. */ typedef void *(*row_map_fn)( Row *, void *, void *, void * ); typedef void *(*symbol_map_fn)( Symbol *, void *, void *, void * ); typedef void *(*column_map_fn)( Column *, void * ); typedef void *(*view_map_fn)( View *, void *, void * ); typedef void *(*rowview_map_fn)( Rowview *, void * ); typedef void *(*workspace_map_fn)( Workspace *, void * ); typedef void *(*toolkit_map_fn)( Toolkit *, void *, void * ); typedef void *(*tool_map_fn)( Tool *, void *, void * ); /* Util stuff. */ #include "util.h" #include "gtkutil.h" #include "path.h" #include "iobject.h" #include "icontainer.h" #include "iwindow.h" #include "idialog.h" #include "boxes.h" #include "popupbutton.h" #include "imageheader.h" #include "filesel.h" #include "managed.h" #include "managedfile.h" #include "managedgvalue.h" #include "managedgobject.h" #include "imageinfo.h" #include "imagedisplay.h" #include "colourdisplay.h" #include "imagemodel.h" #include "imagepresent.h" #include "floatwindow.h" #include "imageview.h" #include "tslider.h" #include "pane.h" #include "progress.h" /* Basic ip includes (order important). */ #include "tree.h" #include "heap.h" #include "managedstring.h" #include "class.h" #include "link.h" #include "expr.h" #include "model.h" #include "paintboxview.h" #include "conversion.h" #include "heapmodel.h" #include "classmodel.h" #include "filemodel.h" #include "symbol.h" #include "workspace.h" #include "workspaceroot.h" #include "workspacegroup.h" #include "toolkitgroup.h" #include "secret.h" #include "action.h" #include "reduce.h" #include "vobject.h" #include "vipsobject.h" #include "view.h" #include "graphicview.h" #include "spin.h" #include "row.h" #include "rowview.h" #include "subcolumn.h" #include "subcolumnview.h" #include "rhs.h" #include "rhsview.h" #include "workspaceview.h" #include "workspacegroupview.h" #include "toolkitgroupview.h" #include "column.h" #include "columnview.h" #include "toolkit.h" #include "tool.h" #include "toolkitview.h" #include "toolview.h" #include "watch.h" #include "value.h" #include "panechild.h" /* Per module includes, any order */ #include "workspacedefs.h" #include "toolkitbrowser.h" #include "defbrowser.h" #include "log.h" #include "error.h" #include "trace.h" #include "program.h" #include "conversionview.h" #include "statusview.h" #include "plotstatus.h" #include "mainw.h" #include "preview.h" #include "builtin.h" #include "compile.h" #include "dump.h" #include "main.h" #include "predicate.h" #include "slider.h" #include "clock.h" #include "pathname.h" #include "fontname.h" #include "group.h" #include "real.h" #include "vector.h" #include "colour.h" #include "number.h" #include "istring.h" #include "editview.h" #include "expression.h" #include "expressionview.h" #include "stringview.h" #include "numberview.h" #include "matrix.h" #include "matrixview.h" #include "plot.h" #ifdef HAVE_LIBGOFFICE #include "plotview.h" #endif /*HAVE_LIBGOFFICE*/ #include "plotmodel.h" #include "plotpresent.h" #include "plotwindow.h" #include "graphwindow.h" #include "option.h" #include "optionview.h" #include "iimage.h" #include "iregion.h" #include "iregiongroup.h" #include "iarrow.h" #include "valueview.h" #include "sliderview.h" #include "pathnameview.h" #include "fontnameview.h" #include "colourview.h" #include "iimageview.h" #include "iregionview.h" #include "iregiongroupview.h" #include "prefs.h" #include "prefworkspaceview.h" #include "prefcolumnview.h" #include "regionview.h" #include "itext.h" #include "itextview.h" #include "toggle.h" #include "toggleview.h" #include "call.h" #include "cache.h" #include "parser.h" #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ #endif /*IP_H*/ nip2-8.7.1/src/symbol.c0000644000175000017500000006521513351443023011567 00000000000000/* Basic ops on symbols. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* All debug #define DEBUG */ /* Just trace create/destroy. #define DEBUG_MAKE */ /* Time recomputes. #define DEBUG_TIME */ /* Show symbols as we recalc #define DEBUG_RECALC */ /* If DEBUG is on, make sure other debugs are on too. */ #ifdef DEBUG # ifndef DEBUG_MAKE # define DEBUG_MAKE # endif # ifndef DEBUG_TIME # define DEBUG_TIME # endif # ifndef DEBUG_RECALC # define DEBUG_RECALC # endif #endif /* Our signals. */ enum { SIG_NEW_VALUE, /* new value for sym->expr */ SIG_LAST }; static guint symbol_signals[SIG_LAST] = { 0 }; /* Global symbol - top-level definitions are locals to this symbol. */ Symbol *symbol_root = NULL; /* Set of dirty top-level symbols with no dirty children which do not contain * errors. Used to generate next-to-recalc. */ static GSList *symbol_leaf_set = NULL; static FilemodelClass *parent_class = NULL; /* Apply a function to a symbol ... and any locals. */ Symbol * symbol_map_all( Symbol *sym, symbol_map_fn fn, void *a, void *b ) { Symbol *res; /* Apply to this sym. */ if( (res = fn( sym, a, b, NULL )) ) return( res ); /* And over any locals of those locals. */ if( sym->expr && sym->expr->compile && (res = icontainer_map3( ICONTAINER( sym->expr->compile ), (icontainer_map3_fn) symbol_map_all, (void *) fn, a, b )) ) return( res ); return( NULL ); } /* Find a symbol's enclosing sym. */ Symbol * symbol_get_parent( Symbol *sym ) { if( !ICONTAINER( sym )->parent ) return( NULL ); return( COMPILE( ICONTAINER( sym )->parent )->sym ); } /* Find the enclosing workspace, if any. */ Workspace * symbol_get_workspace( Symbol *sym ) { if( !sym->expr || !sym->expr->row ) return( NULL ); return( row_get_workspace( sym->expr->row ) ); } /* Find the enclosing tool, if any. */ Tool * symbol_get_tool( Symbol *sym ) { Symbol *i; for( i = sym; i && !i->tool; i = symbol_get_parent( i ) ) ; if( i ) return( i->tool ); return( NULL ); } /* Get the enclosing scope for a sym. */ Symbol * symbol_get_scope( Symbol *sym ) { Symbol *i; for( i = sym; i && !is_scope( i ); i = symbol_get_parent( i ) ) ; return( i ); } /* Make a fully-qualified symbol name .. eg fred.jim, given jim. Don't print * static scopes. */ void symbol_qualified_name( Symbol *sym, VipsBuf *buf ) { Symbol *parent = symbol_get_parent( sym ); if( parent && !is_scope( parent ) ) { symbol_qualified_name( parent, buf ); vips_buf_appends( buf, "." ); } vips_buf_appends( buf, NN( IOBJECT( sym )->name ) ); } /* Make a symbol name relative to a scope context ... ie. from the point of * view of a local of context, what name will find sym. */ void symbol_qualified_name_relative( Symbol *context, Symbol *sym, VipsBuf *buf ) { Symbol *parent = symbol_get_parent( sym ); if( parent && !is_ancestor( context, parent ) ) { symbol_qualified_name_relative( context, parent, buf ); vips_buf_appends( buf, "." ); } vips_buf_appends( buf, NN( IOBJECT( sym )->name ) ); } /* As above, but include stuff about where the symbol is defined, handy for * building error messages. */ void * symbol_name_error( Symbol *sym, VipsBuf *buf ) { Tool *tool; symbol_qualified_name( sym, buf ); if( (tool = symbol_get_tool( sym )) ) tool_error( tool, buf ); vips_buf_appends( buf, " " ); return( NULL ); } /* Handy for error messages ... but nowt else. Return string overwritten on * next call. */ const char * symbol_name( Symbol *sym ) { static char txt[200]; static VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_rewind( &buf ); symbol_qualified_name( sym, &buf ); return( vips_buf_all( &buf ) ); } /* Convenience ... print a qual name to stdout. */ void * symbol_name_print( Symbol *sym ) { printf( "%s ", symbol_name( sym ) ); return( NULL ); } /* Print a symbol's name, including the enclosing static scope. Return value * is a pointer to a static buffer :( */ const char * symbol_name_scope( Symbol *sym ) { Symbol *scope = symbol_get_scope( sym ); static char txt[200]; static VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_rewind( &buf ); vips_buf_appends( &buf, NN( IOBJECT( scope )->name ) ); vips_buf_appends( &buf, "." ); symbol_qualified_name_relative( scope, sym, &buf ); return( vips_buf_all( &buf ) ); } /* Convenience ... print a qual name to stdout. */ void symbol_name_scope_print( Symbol *sym ) { printf( "%s", symbol_name_scope( sym ) ); } void symbol_new_value( Symbol *sym ) { g_signal_emit( G_OBJECT( sym ), symbol_signals[SIG_NEW_VALUE], 0 ); } /* Add a pointer to a patch list. */ void * symbol_patch_add( void **pnt, Symbol *sym ) { g_assert( sym->type == SYM_ZOMBIE ); sym->patch = g_slist_prepend( sym->patch, pnt ); return( NULL ); } static void symbol_clear( Symbol *sym ) { sym->type = SYM_ZOMBIE; sym->patch = NULL; sym->expr = NULL; sym->base.type = ELEMENT_NOVAL; sym->base.ele = (void *) 15; /* handy for debugging */ sym->dirty = FALSE; sym->parents = NULL; sym->topchildren = NULL; sym->topparents = NULL; sym->ndirtychildren = 0; sym->leaf = FALSE; sym->generated = FALSE; sym->placeholder = FALSE; sym->tool = NULL; sym->function = NULL; sym->builtin = NULL; sym->wsr = NULL; sym->ws = NULL; } /* Initialise root symbol. */ Symbol * symbol_root_init( void ) { Symbol *root = SYMBOL( g_object_new( TYPE_SYMBOL, NULL ) ); symbol_clear( root ); iobject_set( IOBJECT( root ), "$$ROOT", NULL ); root->type = SYM_ROOT; root->expr = expr_new( root ); (void) compile_new_local( root->expr ); symbol_root = symbol_new( root->expr->compile, "root" ); symbol_root->type = SYM_ROOT; symbol_root->expr = expr_new( symbol_root ); (void) compile_new( symbol_root->expr ); return( root ); } /* Should a symbol be in the leaf set? */ static gboolean symbol_is_leafable( Symbol *sym ) { if( is_top( sym ) && sym->dirty && sym->expr && !sym->expr->err && sym->ndirtychildren == 0 ) return( TRUE ); return( FALSE ); } #ifdef DEBUG /* Do a sanity check on a symbol. */ void * symbol_sanity( Symbol *sym ) { if( is_top( sym ) ) { if( symbol_ndirty( sym ) != sym->ndirtychildren ) error( "sanity failure #1 for sym \"%s\"", symbol_name( sym ) ); } if( symbol_is_leafable( sym ) && !sym->leaf ) error( "sanity failure #2 for sym \"%s\"", symbol_name( sym ) ); if( !symbol_is_leafable( sym ) && sym->leaf ) error( "sanity failure #3 for sym \"%s\"", symbol_name( sym ) ); if( sym->leaf && !g_slist_find( symbol_leaf_set, sym ) ) error( "sanity failure #6 for sym \"%s\"", symbol_name( sym ) ); if( !sym->leaf && g_slist_find( symbol_leaf_set, sym ) ) error( "sanity failure #7 for sym \"%s\"", symbol_name( sym ) ); return( NULL ); } #endif/*DEBUG*/ #ifdef DEBUG /* Test the leaf set for sanity. */ void symbol_leaf_set_sanity( void ) { slist_map( symbol_leaf_set, (SListMapFn) symbol_sanity, NULL ); icontainer_map( ICONTAINER( symbol_root->expr->compile ), (icontainer_map_fn) symbol_sanity, NULL, NULL ); /* Commented out to reduce spam * printf( "Leaf set: " ); slist_map( symbol_leaf_set, (SListMapFn) dump_tiny, NULL ); printf( "\n" ); */ } #endif /*DEBUG*/ /* Strip a symbol down, ready for redefinition. */ void * symbol_strip( Symbol *sym ) { #ifdef DEBUG_MAKE printf( "symbol_strip: " ); symbol_name_print( sym ); printf( "\n" ); #endif /*DEBUG_MAKE*/ /* Anything that refers to us will need a recomp. */ if( is_top( sym ) ) symbol_dirty_intrans( sym, link_serial_new() ); /* Clean out old exprinfo. */ icontainer_map( ICONTAINER( sym ), (icontainer_map_fn) expr_strip, NULL, NULL ); /* Free any top-links we made. */ (void) slist_map( sym->topchildren, (SListMapFn) link_destroy, NULL ); /* Can free the patch list. We should not have to resolve off this * name again. */ IM_FREEF( g_slist_free, sym->patch ); /* Workspaceroot? Unlink from wsr. */ if( sym->wsr ) { sym->wsr->sym = NULL; sym->wsr = NULL; } /* Workspace? Unlink from ws. */ if( sym->ws ) { sym->ws->sym = NULL; sym->ws = NULL; } /* It's a ZOMBIE now. */ sym->type = SYM_ZOMBIE; #ifdef DEBUG symbol_sanity( sym ); #endif /*DEBUG*/ return( NULL ); } static void * symbol_made_error_clear( Link *link ) { expr_error_clear( link->parent->expr ); return( NULL ); } /* Finish creating a symbol. Sequence is: symbol_new(), specialise ZOMBIE * into a particular symbol type, symbol_made(). Do any final tidying up. */ void symbol_made( Symbol *sym ) { #ifdef DEBUG_MAKE printf( "symbol_made: " ); symbol_name_print( sym ); printf( "\n" ); #endif /*DEBUG_MAKE*/ if( is_top( sym ) ) { /* Remake all top-level dependencies. */ (void) symbol_link_build( sym ); /* Clear error on every symbol that refs us, then mark dirty. * This lets us replace refed-to syms cleanly. */ slist_map( sym->topparents, (SListMapFn) symbol_made_error_clear, NULL ); /* Real dirrrrty. */ if( sym->expr ) expr_dirty( sym->expr, link_serial_new() ); } #ifdef DEBUG dump_symbol( sym ); #endif /*DEBUG*/ } static void * symbol_not_defined_sub( Link *link, VipsBuf *buf ) { symbol_name_error( link->parent, buf ); return( NULL ); } /* Make a "not defined" error message. Can be called before symbol is removed, * so don't assume it's a ZOMBIE. */ void symbol_not_defined( Symbol *sym ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); error_top( _( "Not found." ) ); vips_buf_appendf( &buf, _( "Symbol %s is not defined." ), symbol_name( sym ) ); if( sym->topparents ) { vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%s is referred to by" ), symbol_name( sym ) ); vips_buf_appends( &buf, ": " ); slist_map2( sym->topparents, (SListMap2Fn) symbol_not_defined_sub, &buf, NULL ); vips_buf_appends( &buf, "\n" ); } error_sub( "%s", vips_buf_all( &buf ) ); } /* Compile refers to sym, which is going ... mark compile as containing an * error. */ static void * symbol_destroy_error( Compile *compile, Symbol *sym ) { symbol_not_defined( sym ); compile_error_set( compile ); return( NULL ); } static void symbol_dispose( GObject *gobject ) { Symbol *sym; Compile *compile; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_SYMBOL( gobject ) ); sym = SYMBOL( gobject ); compile = COMPILE( ICONTAINER( sym )->parent ); #ifdef DEBUG_MAKE printf( "symbol_dispose: " ); symbol_name_print( sym ); printf( "(%p)\n", sym ); #endif /*DEBUG_MAKE*/ /* Make sure we're not leaving last_sym dangling. */ if( compile && compile->last_sym == sym ) compile->last_sym = NULL; /* Clear state. */ if( is_top( sym ) ) { /* All stuff that depends on this sym is now dirty. */ symbol_dirty_intrans( sym, link_serial_new() ); /* This will knock this sym off the leaf set as well. */ symbol_dirty_clear( sym ); } /* Strip it down. */ (void) symbol_strip( sym ); IDESTROY( sym->tool ); /* Any exprs which refer to us must have errors. */ (void) slist_map( sym->parents, (SListMapFn) symbol_destroy_error, sym ); /* Remove links from any expr which refer to us. */ (void) slist_map( sym->parents, (SListMapFn) compile_link_break, sym ); /* No other syms should have toplinks to us. */ (void) slist_map( sym->topparents, (SListMapFn) link_destroy, NULL ); /* Unregister value with GC. */ reduce_unregister( sym ); /* Free other stuff. */ sym->type = SYM_ZOMBIE; g_assert( !sym->tool ); g_assert( !sym->parents ); g_assert( !sym->topparents ); g_assert( !sym->topchildren ); IM_FREEF( g_slist_free, sym->patch ); IM_FREEF( g_slist_free, sym->parents ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void symbol_changed( iObject *iobject ) { Symbol *sym = SYMBOL( iobject ); /* If we have a tool, signal changed on that as well. */ if( sym->tool ) iobject_changed( IOBJECT( sym->tool ) ); IOBJECT_CLASS( parent_class )->changed( iobject ); } static void symbol_real_new_value( Symbol *symbol ) { } static void symbol_class_init( SymbolClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = (iObjectClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = symbol_dispose; iobject_class->changed = symbol_changed; symbol_signals[SIG_NEW_VALUE] = g_signal_new( "new_value", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( SymbolClass, new_value ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); class->new_value = symbol_real_new_value; } static void symbol_init( Symbol *sym ) { symbol_clear( sym ); #ifdef DEBUG_MAKE printf( "symbol_init: (%p)\n", sym ); #endif /*DEBUG_MAKE*/ } GtkType symbol_get_type( void ) { static GtkType symbol_type = 0; if( !symbol_type ) { static const GTypeInfo info = { sizeof( SymbolClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) symbol_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Symbol ), 32, /* n_preallocs */ (GInstanceInitFunc) symbol_init, }; symbol_type = g_type_register_static( TYPE_FILEMODEL, "Symbol", &info, 0 ); } return( symbol_type ); } /* Make a new symbol on an expr. If it's already there and a ZOMBIE, just * return it. If it's not a ZOMBIE, turn it into one. Otherwise make and * link on a new symbol. */ Symbol * symbol_new( Compile *compile, const char *name ) { Symbol *sym; if( (sym = compile_lookup( compile, name )) ) { if( sym->type != SYM_ZOMBIE ) /* Already exists: strip it down. */ (void) symbol_strip( sym ); #ifdef DEBUG_MAKE printf( "symbol_new: redefining " ); symbol_name_print( sym ); printf( "(%p)\n", sym ); #endif /*DEBUG_MAKE*/ } else { sym = SYMBOL( g_object_new( TYPE_SYMBOL, NULL ) ); iobject_set( IOBJECT( sym ), name, NULL ); icontainer_child_add( ICONTAINER( compile ), ICONTAINER( sym ), -1 ); #ifdef DEBUG_MAKE printf( "symbol_new: creating " ); symbol_name_print( sym ); printf( "(%p)\n", sym ); #endif /*DEBUG_MAKE*/ } return( sym ); } gboolean symbol_rename( Symbol *sym, const char *new_name ) { Compile *compile = COMPILE( ICONTAINER( sym )->parent ); Symbol *old_sym; if( strcmp( IOBJECT( sym )->name, new_name ) == 0 ) return( TRUE ); if( (old_sym = compile_lookup( compile, new_name )) ) { error_top( "%s", _( "Name in use." ) ); error_sub( _( "Can't rename %s \"%s\" as \"%s\". " "The name is already in use." ), decode_SymbolType_user( sym->type ), IOBJECT( sym )->name, new_name ); return( FALSE ); } /* Everything that depends on us will break. */ symbol_dirty_intrans( sym, link_serial_new() ); g_object_ref( sym ); icontainer_child_remove( ICONTAINER( sym ) ); iobject_set( IOBJECT( sym ), new_name, NULL ); icontainer_child_add( ICONTAINER( compile ), ICONTAINER( sym ), ICONTAINER( sym )->pos ); g_object_unref( sym ); return( TRUE ); } void symbol_error_redefine( Symbol *sym ) { static char txt[200]; static VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_rewind( &buf ); vips_buf_appendf( &buf, _( "Redefinition of \"%s\"." ), IOBJECT( sym )->name ); if( sym->tool && sym->tool->lineno != -1 ) { vips_buf_appendf( &buf, "\n" ); vips_buf_appendf( &buf, _( "Previously defined at line %d." ), sym->tool->lineno ); } yyerror( vips_buf_all( &buf ) ); } /* Name in defining occurence. If this is a top-level definition, clean the * old symbol and get ready to attach a user function to it. If its not a top- * level definition, we flag an error. Consider repeated parameter names, * repeated occurence of names in locals, local name clashes with parameter * name etc. * We make a ZOMBIE: our caller should turn it into a blank user definition, a * parameter etc. */ Symbol * symbol_new_defining( Compile *compile, const char *name ) { Symbol *sym; /* Block definition of "root" anywhere ... too confusing. */ if( strcmp( name, IOBJECT( symbol_root )->name ) == 0 ) nip2yyerror( _( "Attempt to redefine root symbol \"%s\"." ), name ); /* Is this a redefinition of an existing symbol? */ if( (sym = compile_lookup( compile, name )) ) { /* Yes. Check that this redefinition is legal. */ switch( sym->type ) { case SYM_VALUE: /* Redef of existing symbol? Only allowed at top * level. */ if( !is_scope( compile->sym ) ) symbol_error_redefine( sym ); break; case SYM_ZOMBIE: /* This is the definition for a previously referenced * symbol. Just return the ZOMBIE we made. */ break; default: /* Parameter, workspace, etc. */ nip2yyerror( _( "Can't redefine %s \"%s\"." ), decode_SymbolType_user( sym->type ), name ); /*NOTREACHED*/ } /* This is the defining occurence ... move to the end of the * traverse order. */ icontainer_child_move( ICONTAINER( sym ), -1 ); } /* Get it ready. */ sym = symbol_new( compile, name ); return( sym ); } /* Make a reference to a symbol. Look on the local table for the name - if * it's not there, make a ZOMBIE. Note that ZOMBIEs etc. need patch lists * attached to them for all pointers to them we make. Responsibility of * caller! */ Symbol * symbol_new_reference( Compile *compile, const char *name ) { Symbol *sym = compile_lookup( compile, name ); if( !sym ) sym = symbol_new( compile, name ); /* Note the new dependency. */ compile_link_make( compile, sym ); return( sym ); } /* Compile refers to child ... break link. */ void * symbol_link_break( Symbol *child, Compile *compile ) { compile_link_break( compile, child ); return( NULL ); } /* Specialise into a user definition. */ gboolean symbol_user_init( Symbol *sym ) { g_assert( sym->type == SYM_ZOMBIE ); sym->type = SYM_VALUE; reduce_register( sym ); if( !sym->expr ) sym->expr = expr_new( sym ); /* We don't symbol_made() yet, wait until we have finished building * sym->expr. */ return( TRUE ); } /* Specialise into a parameter on an expression. */ gboolean symbol_parameter_init( Symbol *sym ) { Compile *parent = COMPILE( ICONTAINER( sym )->parent ); g_assert( sym->type == SYM_ZOMBIE ); sym->type = SYM_PARAM; parent->param = g_slist_append( parent->param, sym ); parent->nparam = g_slist_length( parent->param ); symbol_made( sym ); return( TRUE ); } /* Specialise into a builtin parameter (eg. "this"). */ gboolean symbol_parameter_builtin_init( Symbol *sym ) { g_assert( sym->type == SYM_ZOMBIE ); sym->type = SYM_PARAM; symbol_made( sym ); return( TRUE ); } /* Get the next dirty leaf symbol. */ static Symbol * symbol_leaf_next( void ) { if( symbol_leaf_set ) return( (Symbol *) symbol_leaf_set->data ); else return( NULL ); } /* Are there symbols we can recalculate? Used to display "Calculating ..." * status. */ gboolean symbol_busy( void ) { return( symbol_leaf_set != NULL ); } /* Set leaf state. */ static void symbol_set_leaf( Symbol *sym, gboolean leaf ) { if( sym->leaf != leaf ) { gboolean changed; sym->leaf = leaf; changed = FALSE; if( leaf ) { if( !symbol_leaf_set ) changed = TRUE; symbol_leaf_set = g_slist_prepend( symbol_leaf_set, sym ); } else { g_assert( symbol_leaf_set ); symbol_leaf_set = g_slist_remove( symbol_leaf_set, sym ); if( !symbol_leaf_set ) changed = TRUE; } if( changed ) iobject_changed( IOBJECT( reduce_context->heap ) ); if( sym->expr && sym->expr->row ) iobject_changed( IOBJECT( sym->expr->row ) ); } } /* State of a symbol has changed ... update! */ void symbol_state_change( Symbol *sym ) { g_assert( sym->ndirtychildren >= 0 ); /* Used to do more ... now we just set leaf. */ symbol_set_leaf( sym, symbol_is_leafable( sym ) ); } /* Recalculate a symbol. We know we are dirty and have no dirty ancestors. */ static gboolean symbol_recalculate_sub( Symbol *sym ) { gboolean result = TRUE; #ifdef DEBUG_TIME static GTimer *timer = NULL; if( !timer ) timer = g_timer_new(); g_timer_reset( timer ); #endif /*DEBUG_TIME*/ g_assert( is_value( sym ) ); if( sym->expr->row ) { /* This is the root of a display ... use that recomp * mechanism. */ row_recomp( sym->expr->row ); /* Stuff may have been removed. */ if( sym->expr && sym->expr->row && sym->expr->row->err ) result = FALSE; } else if( sym->expr->compile->nparam == 0 ) { /* No params: this ought to have a value. */ if( !reduce_regenerate( sym->expr, &sym->expr->root ) ) result = FALSE; } #ifdef DEBUG_TIME printf( "symbol_recalculate_sub: " ); symbol_name_scope_print( sym ); printf( " %g\n", g_timer_elapsed( timer, NULL ) ); #endif /*DEBUG_TIME*/ return( result ); } /* Note the name of the last thing we calced here, for progress to display. */ static char symbol_last_calc_txt[256]; static VipsBuf symbol_last_calc_buf = VIPS_BUF_STATIC( symbol_last_calc_txt ); static void symbol_note_calc_name( Symbol *sym ) { Symbol *scope = symbol_get_scope( sym ); VipsBuf *buf = &symbol_last_calc_buf; vips_buf_rewind( buf ); vips_buf_appends( buf, NN( IOBJECT( scope )->name ) ); vips_buf_appends( buf, "." ); symbol_qualified_name_relative( scope, sym, buf ); } const char * symbol_get_last_calc( void ) { return( vips_buf_all( &symbol_last_calc_buf ) ); } /* We can get called recursively .. eg. we do an im_tiff2vips(), that * pops a progress box, that triggers idle, that tries to recalc a * leaf again. */ static gboolean symbol_running = FALSE; /* Recalc a symbol ... with error checks. */ static void * symbol_recalculate_leaf_sub( Symbol *sym ) { #ifdef DEBUG_RECALC printf( "symbol_recalculate_leaf_sub: %s\n", symbol_name_scope( sym ) ); /* We can symbol_recalculate_leaf_sub() syms which are not dirty. */ g_assert( !sym->dirty || symbol_is_leafable( sym ) ); g_assert( symbol_ndirty( sym ) == 0 ); #endif /*DEBUG_RECALC*/ error_clear(); if( sym->expr->err ) { expr_error_get( sym->expr ); #ifdef DEBUG_RECALC printf( "\t(error: previous error)\n" ); #endif /*DEBUG_RECALC*/ return( sym ); } if( !sym->dirty ) return( NULL ); if( !is_value( sym ) ) { symbol_dirty_clear( sym ); return( NULL ); } if( symbol_running ) return( NULL ); reduce_context->heap->filled = FALSE; symbol_running = TRUE; progress_begin(); symbol_note_calc_name( sym ); if( !symbol_recalculate_sub( sym ) || reduce_context->heap->filled ) { expr_error_set( sym->expr ); symbol_running = FALSE; progress_end(); #ifdef DEBUG_RECALC printf( "\t(error: %s %s)\n", sym->expr->error_top, sym->expr->error_sub ); #endif /*DEBUG_RECALC*/ return( sym ); } symbol_running = FALSE; progress_end(); /* Have we discovered any dirty children? If not, we've cleaned this * sym. */ if( !sym->ndirtychildren ) { symbol_dirty_clear( sym ); if( sym->expr ) { expr_new_value( sym->expr ); #ifdef DEBUG_RECALC printf( "\tsuccess: " ); graph_pointer( &sym->expr->root ); #endif /*DEBUG_RECALC*/ } } #ifdef DEBUG_RECALC else { printf( "\t(found dirty children)\n" ); } #endif /*DEBUG_RECALC*/ return( NULL ); } /* Recalculate a symbol. FALSE if no symbols can be recalced. */ static gboolean symbol_recalculate_leaf( void ) { gboolean recalculated; Symbol *sym; recalculated = FALSE; #ifdef DEBUG printf( "symbol_recalculate_leaves: Leaf set: " ); slist_map( symbol_leaf_set, (SListMapFn) dump_tiny, NULL ); printf( "\n" ); #endif /*DEBUG*/ /* Grab stuff off the leaf set. */ if( (sym = symbol_leaf_next()) ) { /* Should be dirty with no dirty children. Unless it's a * function, in which case dirty kids are OK. */ g_assert( sym->dirty ); g_assert( !sym->expr->err ); g_assert( is_top( sym ) ); g_assert( symbol_ndirty( sym ) == 0 || is_value( sym ) ); /* Found a symbol! */ (void) symbol_recalculate_leaf_sub( sym ); /* Note a pending GC. */ (void) heap_gc_request( reduce_context->heap ); /* We have recalculated a symbol. */ recalculated = TRUE; } return( recalculated ); } /* Our idle recomp callback. */ static gint symbol_idle_id = 0; static gboolean symbol_recalculate_idle_cb( void ) { static GTimer *timer = NULL; gboolean run_again; #ifdef DEBUG_RECALC printf( "symbol_recalculate_idle_cb:\n" ); #endif /*DEBUG_RECALC*/ if( symbol_running ) /* We've been run from a nested main loop, perhaps from the * progress bar. Just run again and perhaps next time we'll be * back in the top-level main loop. */ return( TRUE ); if( !timer ) timer = g_timer_new(); g_timer_reset( timer ); run_again = TRUE; if( !mainw_auto_recalc ) /* Auto-calc has been turned off during a recomp. */ run_again = FALSE; else while( g_timer_elapsed( timer, NULL ) < 0.1 ) if( !symbol_recalculate_leaf() ) { run_again = FALSE; break; } if( !run_again ) { #ifdef DEBUG_RECALC printf( "symbol_recalculate_idle_cb: bg recalc done\n" ); #endif /*DEBUG_RECALC*/ symbol_idle_id = 0; progress_end(); } return( run_again ); } /* Recalculate ... either nudge the idle recomp, or in batch mode, do a recomp * right now. */ void symbol_recalculate_all_force( gboolean now ) { #ifdef DEBUG icontainer_map( ICONTAINER( symbol_root->expr->compile ), (icontainer_map_fn) symbol_sanity, NULL, NULL ); #endif /*DEBUG*/ /* In case we're called directly. */ (void) view_scan_all(); if( symbol_running ) /* Do nothing. */ ; else if( main_option_batch || now ) { progress_begin(); while( symbol_recalculate_leaf() ) ; progress_end(); } else if( !symbol_idle_id ) { #ifdef DEBUG_RECALC printf( "symbol_recalculate_all_force: " "starting bg recalc ...\n" ); #endif /*DEBUG_RECALC*/ progress_begin(); symbol_idle_id = g_idle_add( (GSourceFunc) symbol_recalculate_idle_cb, NULL ); } } /* Recalculate the symbol table. */ void symbol_recalculate_all( void ) { /* Do a scan, even if we don't recomp. We need to pick up edits before * views get refreshed. */ (void) view_scan_all(); if( mainw_auto_recalc ) symbol_recalculate_all_force( FALSE ); } /* Recalc a symbol ... with error checks. */ gboolean symbol_recalculate_check( Symbol *sym ) { gboolean result; result = symbol_recalculate_leaf_sub( sym ) == NULL; return( result ); } nip2-8.7.1/src/toolkit.c0000644000175000017500000001457013351443023011745 00000000000000/* Manage toolkits and their display. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static FilemodelClass *parent_class = NULL; Tool * toolkit_map( Toolkit *kit, tool_map_fn fn, void *a, void *b ) { return( (Tool *) icontainer_map( ICONTAINER( kit ), (icontainer_map_fn) fn, a, b ) ); } static void toolkit_changed( iObject *iobject ) { /* If we change, signal change on our parent too (toolkitgroup) ... * things like Program and Toolkitbrowser which need to spot any * change to any kit can connect to that, rather than having to * connect to all kits independently. */ if( IS_ICONTAINER( iobject ) && ICONTAINER( iobject )->parent ) iobject_changed( IOBJECT( ICONTAINER( iobject )->parent ) ); } static void toolkit_info( iObject *iobject, VipsBuf *buf ) { Toolkit *kit = TOOLKIT( iobject ); IOBJECT_CLASS( parent_class )->info( iobject, buf ); vips_buf_appendf( buf, "group = \"%s\"\n", IOBJECT( kit->kitg )->name ); } static View * toolkit_view_new( Model *model, View *parent ) { return( toolkitview_new() ); } static gboolean toolkit_save_text( Model *model, iOpenFile *of ) { if( icontainer_map( ICONTAINER( model ), (icontainer_map_fn) model_save_text, of, NULL ) ) return( FALSE ); return( TRUE ); } /* Load from an iOpenFile. */ static gboolean toolkit_load_text( Model *model, Model *parent, iOpenFile *of ) { Toolkit *kit = TOOLKIT( model ); int pos = icontainer_pos_last( ICONTAINER( model ) ) + 1; gboolean res; /* Load up definitions. */ filemodel_set_filename( FILEMODEL( model ), of->fname_real ); attach_input_file( of ); if( !(res = parse_toplevel( kit, pos )) ) /* The sub won't have filename or line number: zap them in. */ error_sub( "%s:%d\n%s\n", FILEMODEL( kit )->filename, input_state.lineno, error_get_sub() ); #ifdef DEBUG (void) dump_kit( kit ); #endif /*DEBUG*/ return( res ); } static void toolkit_class_init( ToolkitClass *class ) { iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; FilemodelClass *filemodel_class = (FilemodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ iobject_class->info = toolkit_info; iobject_class->changed = toolkit_changed; model_class->view_new = toolkit_view_new; model_class->save_text = toolkit_save_text; model_class->load_text = toolkit_load_text; filemodel_class->filetype = filesel_type_definition; } static void toolkit_init( Toolkit *kit ) { kit->kitg = NULL; kit->pseudo = FALSE; } GType toolkit_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ToolkitClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) toolkit_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Toolkit ), 32, /* n_preallocs */ (GInstanceInitFunc) toolkit_init, }; type = g_type_register_static( TYPE_FILEMODEL, "Toolkit", &info, 0 ); } return( type ); } static void toolkit_link( Toolkit *kit, Toolkitgroup *kitg, const char *name ) { iobject_set( IOBJECT( kit ), name, NULL ); icontainer_child_add( ICONTAINER( kitg ), ICONTAINER( kit ), -1 ); kit->kitg = kitg; filemodel_register( FILEMODEL( kit ) ); if( name[0] == '_' ) MODEL( kit )->display = FALSE; toolkitgroup_sort( kitg ); } /* Find a kit by kit name. */ Toolkit * toolkit_find( Toolkitgroup *kitg, const char *name ) { return( (Toolkit *) icontainer_map( ICONTAINER( kitg ), (icontainer_map_fn) iobject_test_name, (char *) name, NULL ) ); } Toolkit * toolkit_new( Toolkitgroup *kitg, const char *name ) { Toolkit *kit; #ifdef DEBUG printf( "toolkit_new: %s\n", name ); #endif /*DEBUG*/ /* Exists already? */ if( (kit = toolkit_find( kitg, name )) ) IDESTROY( kit ); /* Make a new kit. */ kit = TOOLKIT( g_object_new( TYPE_TOOLKIT, NULL ) ); toolkit_link( kit, kitg, name ); return( kit ); } Toolkit * toolkit_new_filename( Toolkitgroup *kitg, const char *filename ) { char name[FILENAME_MAX]; Toolkit *kit; name_from_filename( filename, name ); kit = toolkit_new( kitg, name ); filemodel_set_filename( FILEMODEL( kit ), filename ); return( kit ); } /* Load a file as a toolkit. */ Toolkit * toolkit_new_from_file( Toolkitgroup *kitg, const char *filename ) { Toolkit *kit = toolkit_new_filename( kitg, filename ); gboolean res; res = filemodel_load_all( FILEMODEL( kit ), MODEL( kitg ), filename, NULL ); filemodel_set_modified( FILEMODEL( kit ), FALSE ); /* Don't remove the kit if load failed, we want to leave it so the * user can try to fix the problem. */ if( res ) return( kit ); else return( NULL ); } /* Load from an iOpenFile. */ Toolkit * toolkit_new_from_openfile( Toolkitgroup *kitg, iOpenFile *of ) { Toolkit *kit = toolkit_new_filename( kitg, of->fname ); gboolean res; res = filemodel_load_all_openfile( FILEMODEL( kit ), MODEL( kitg ), of ); filemodel_set_modified( FILEMODEL( kit ), FALSE ); /* Don't remove the kit if load failed, we want to leave it so the * user can try to fix the problem. */ if( res ) return( kit ); else return( NULL ); } /* Look up a toolkit, make an empty one if not there. */ Toolkit * toolkit_by_name( Toolkitgroup *kitg, const char *name ) { Toolkit *kit; if( !(kit = toolkit_find( kitg, name )) ) { char file[FILENAME_MAX]; im_snprintf( file, FILENAME_MAX, "$SAVEDIR" G_DIR_SEPARATOR_S "start" G_DIR_SEPARATOR_S "%s.def", name ); kit = toolkit_new_filename( kitg, file ); } return( kit ); } nip2-8.7.1/src/main.c0000644000175000017500000012152313351443023011201 00000000000000/* main() ... start everything up. See mainw.c for main window stuff. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ /* Show all paint actions with flashing stuff. #define DEBUG_UPDATES */ /* Stop startup creation of externs for all VIPS functions etc. #define DEBUG_NOAUTO */ /* Stop on any gtk error/warning/whatever. Usually set by configure for dev * builds. #define DEBUG_FATAL */ /* But some themes can trigger warnings, argh, so sometimes we need to * undef it. VipsObject sets can trigger warnings. libgoffice will warn about * precision issues if run under valgrind. */ #undef DEBUG_FATAL /* Time startup. #define DEBUG_TIME */ /* On quit, make sure we free stuff we can free. #define DEBUG_LEAK */ /* Sometimes we need to be able to disable these at build time. #undef DEBUG_LEAK #undef DEBUG_FATAL */ /* General stuff. */ Workspaceroot *main_workspaceroot = NULL; /* All the workspaces */ Toolkitgroup *main_toolkitgroup = NULL; /* All the toolkits */ Symbol *main_symbol_root = NULL; /* Root of symtable */ Watchgroup *main_watchgroup = NULL; /* All of the watches */ Imageinfogroup *main_imageinfogroup = NULL; /* All of the images */ void *main_c_stack_base = NULL; /* Base of C stack */ gboolean main_starting = TRUE; /* In startup */ static const char *main_argv0 = NULL; /* argv[0] */ static iOpenFile *main_stdin = NULL; /* stdin as an iOpenFile */ static GtkIconFactory *main_icon_factory = NULL;/* Add stocks to this */ static char *main_option_script = NULL; static char *main_option_expression = NULL; gboolean main_option_batch = FALSE; static gboolean main_option_no_load_menus = FALSE; static gboolean main_option_no_load_args = FALSE; static gboolean main_option_stdin_ws = FALSE; static gboolean main_option_stdin_def = FALSE; static char *main_option_output = NULL; static char **main_option_set = NULL; static gboolean main_option_benchmark = FALSE; gboolean main_option_time_save = FALSE; gboolean main_option_profile = FALSE; gboolean main_option_i18n = FALSE; gboolean main_option_verbose = FALSE; static gboolean main_option_print_main = FALSE; static gboolean main_option_version = FALSE; static gboolean main_option_test = FALSE; static char *main_option_prefix = NULL; static GOptionEntry main_option[] = { { "expression", 'e', 0, G_OPTION_ARG_STRING, &main_option_expression, N_( "evaluate and print EXPRESSION" ), "EXPRESSION" }, { "script", 's', 0, G_OPTION_ARG_FILENAME, &main_option_script, N_( "load FILE as a set of definitions" ), "FILE" }, { "output", 'o', 0, G_OPTION_ARG_FILENAME, &main_option_output, N_( "write value of 'main' to FILE" ), "FILE" }, { "batch", 'b', 0, G_OPTION_ARG_NONE, &main_option_batch, N_( "run in batch mode" ), NULL }, { "set", '=', 0, G_OPTION_ARG_STRING_ARRAY, &main_option_set, N_( "set values" ), NULL }, { "verbose", 'V', 0, G_OPTION_ARG_NONE, &main_option_verbose, N_( "verbose error output" ), NULL }, { "no-load-menus", 'm', 0, G_OPTION_ARG_NONE, &main_option_no_load_menus, N_( "don't load menu definitions" ), NULL }, { "no-load-args", 'a', 0, G_OPTION_ARG_NONE, &main_option_no_load_args, N_( "don't try to load command-line arguments" ), NULL }, { "stdin-ws", 'w', 0, G_OPTION_ARG_NONE, &main_option_stdin_ws, N_( "load stdin as a workspace" ), NULL }, { "stdin-def", 'd', 0, G_OPTION_ARG_NONE, &main_option_stdin_def, N_( "load stdin as a set of definitions" ), NULL }, { "print-main", 'p', 0, G_OPTION_ARG_NONE, &main_option_print_main, N_( "print value of 'main' to stdout" ), NULL }, { "benchmark", 'c', 0, G_OPTION_ARG_NONE, &main_option_benchmark, N_( "start up and shut down" ), NULL }, { "time-save", 't', 0, G_OPTION_ARG_NONE, &main_option_time_save, N_( "time image save operations" ), NULL }, { "profile", 'r', 0, G_OPTION_ARG_NONE, &main_option_profile, N_( "profile workspace calculation" ), NULL }, { "prefix", 'x', 0, G_OPTION_ARG_FILENAME, &main_option_prefix, N_( "start as if installed to PREFIX" ), "PREFIX" }, { "i18n", 'i', 0, G_OPTION_ARG_NONE, &main_option_i18n, N_( "output strings for internationalisation" ), NULL }, { "version", 'v', 0, G_OPTION_ARG_NONE, &main_option_version, N_( "print version number" ), NULL }, { "test", 'T', 0, G_OPTION_ARG_NONE, &main_option_test, N_( "test for errors and quit" ), NULL }, { NULL } }; /* Accumulate startup errors here. */ static char main_start_error_txt[MAX_STRSIZE]; static VipsBuf main_start_error = VIPS_BUF_STATIC( main_start_error_txt ); static void main_log_add( const char *fmt, ... ) { va_list ap; va_start( ap, fmt ); vips_buf_vappendf( &main_start_error, fmt, ap ); va_end( ap ); } static const char * main_log_get( void ) { return( vips_buf_all( &main_start_error ) ); } static gboolean main_log_is_empty( void ) { return( vips_buf_is_empty( &main_start_error ) ); } /* NULL log handler. Used to suppress output on win32 without DEBUG_FATAL. */ #ifndef DEBUG_FATAL #ifdef OS_WIN32 static void main_log_null( const char *log_domain, GLogLevelFlags log_level, const char *message, void *user_data ) { } #endif /*OS_WIN32*/ #endif /*!DEBUG_FATAL*/ /* Print all errors and quit. Batch mode only. */ static void main_error_exit( const char *fmt, ... ) { va_list args; va_start( args, fmt ); (void) vfprintf( stderr, fmt, args ); va_end( args ); fprintf( stderr, "\n" ); if( strcmp( error_get_top(), "" ) != 0 ) { fprintf( stderr, "%s\n", error_get_top() ); if( strcmp( error_get_sub(), "" ) != 0 ) fprintf( stderr, "%s\n", error_get_sub() ); } if( main_option_verbose ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); slist_map( expr_error_all, (SListMapFn) expr_error_print, &buf ); fprintf( stderr, "%s", vips_buf_all( &buf ) ); } exit( 1 ); } /* Output a single main. */ static void main_print_main( Symbol *sym ) { PElement *root; root = &sym->expr->root; if( !symbol_recalculate_check( sym ) || !reduce_pelement( reduce_context, reduce_spine_strict, root ) ) main_error_exit( _( "error calculating \"%s\"" ), symbol_name_scope( sym ) ); if( main_option_output ) { char filename[FILENAME_MAX]; im_strncpy( filename, main_option_output, FILENAME_MAX ); if( !group_save_item( root, filename ) ) main_error_exit( _( "error saving \"%s\"" ), symbol_name_scope( sym ) ); } if( main_option_print_main ) graph_value( root ); } static void * main_print_ws( Workspace *ws, gboolean *found ) { Symbol *sym; if( (sym = compile_lookup( ws->sym->expr->compile, "main" )) ) { main_print_main( sym ); *found = TRUE; } return( NULL ); } /* Clean up our application and quit. Not interactive! Do any "has been * modified, OK to quit?" stuff before this, see main_quit_test(). */ static void main_quit( void ) { #if HAVE_FFTW || HAVE_FFTW3 iOpenFile *of; #endif /*HAVE_FFTW || HAVE_FFTW3*/ #ifdef DEBUG printf( "main_quit: cleaning up ...\n" ); #endif/*DEBUG*/ if( main_option_print_main || main_option_output ) { Symbol *sym; gboolean found; symbol_recalculate_all(); /* Process all the mains we can find: one at the top level, * one in each workspace. */ found = FALSE; if( (sym = compile_lookup( symbol_root->expr->compile, "main" )) ) { main_print_main( sym ); found = TRUE; } workspace_map( (workspace_map_fn) main_print_ws, &found, NULL ); if( !found ) main_error_exit( "%s", _( "no \"main\" found" ) ); } /* Force all our windows down. */ iwindow_map_all( (iWindowMapFn) iwindow_kill, NULL ); /* Saves recent and stuff like that. */ mainw_shutdown(); /* Dump wisdom back again. */ #if HAVE_FFTW || HAVE_FFTW3 if( (of = ifile_open_write( "%s" G_DIR_SEPARATOR_S "wisdom", get_savedir() )) ) { fftw_export_wisdom_to_file( of->fp ); ifile_close( of ); } #endif /*HAVE_FFTW*/ /* Remove any ws retain files. */ workspacegroup_autosave_clean(); /* Junk all symbols. This may remove a bunch of intermediate images * too. */ UNREF( main_watchgroup ); UNREF( main_symbol_root ); UNREF( main_toolkitgroup ); UNREF( main_workspaceroot ); /* Junk reduction machine ... this should remove all image temps. */ reduce_destroy( reduce_context ); #ifdef DEBUG_LEAK /* Free other GTK stuff. */ if( main_icon_factory ) gtk_icon_factory_remove_default( main_icon_factory ); junk_tooltips(); #ifdef HAVE_LIBGOFFICE /* Not quite sure what this does, but don't do it in batch mode. */ if( !main_option_batch ) libgoffice_shutdown (); #endif /*HAVE_LIBGOFFICE*/ path_rewrite_free_all(); /* Should have freed everything now. */ /* Make sure! FIXME ... #ifdef this lot out at some point */ UNREF( main_imageinfogroup ); heap_check_all_destroyed(); vips_shutdown(); managed_check_all_destroyed(); util_check_all_destroyed(); call_check_all_destroyed(); #endif /*DEBUG_LEAK*/ #ifdef DEBUG printf( "main_quit: exit( 0 )\n" ); #endif/*DEBUG*/ /* And exit. */ exit( 0 ); } /* We mustn't quit recursively! */ static gboolean main_quit_running = FALSE; static void main_quit_test_cb( void *sys, iWindowResult result ) { #ifdef DEBUG printf( "main_quit_test_cb:\n" ); #endif/*DEBUG*/ if( result == IWINDOW_YES ) /* No return from this. */ main_quit(); else /* Quit has been cancelled. */ main_quit_running = FALSE; } /* Check before quitting. */ void main_quit_test( void ) { if( main_quit_running ) { #ifdef DEBUG printf( "main_quit_test: recursive quit blocked\n" ); #endif/*DEBUG*/ return; } main_quit_running = TRUE; #ifdef DEBUG printf( "main_quit_test:\n" ); #endif/*DEBUG*/ /* Flush any pending preference saves before we look for dirty * objects. */ watchgroup_flush( main_watchgroup ); /* Close registered models. */ filemodel_inter_close_registered_cb( iwindow_pick_one(), NULL, main_quit_test_cb, NULL ); } static void main_watchgroup_changed_cb( void ) { /* Only set this in GUI mode. Otherwise, let the user control CPUs * with the env variable and --vips-concurrency args. */ if( !main_option_batch ) im_concurrency_set( VIPS_CPUS ); } /* Try to load a thing, anything at all. Actually, we don't load plugins * experimentally, win32 pops up an annoying error dialog if you try that. */ static gboolean main_load( Workspace *ws, const char *filename ) { Workspacegroup *new_wsg; if( (new_wsg = workspacegroup_new_from_file( main_workspaceroot, filename, filename )) ) { Mainw *mainw; if( !main_option_batch ) { mainw = mainw_new( new_wsg ); gtk_widget_show( GTK_WIDGET( mainw ) ); } mainw_recent_add( &mainw_recent_workspace, filename ); return( TRUE ); } error_clear(); /* workspace_load_file() needs to recalc to work, try to avoid that by * doing .defs first. */ if( is_file_type( &filesel_dfile_type, filename ) ) { if( toolkit_new_from_file( main_toolkitgroup, filename ) ) return( TRUE ); } /* Try as matrix or image. Have to do these via definitions. */ if( workspace_load_file( ws, filename ) ) return( TRUE ); error_clear(); error_top( _( "Unknown file type." ) ); error_sub( _( "Unable to load \"%s\"." ), filename ); return( FALSE ); } #ifndef DEBUG_NOAUTO static void * main_load_plug( char *name ) { if( !calli_string_filename( (calli_string_fn) im_load_plugin, name, NULL, NULL, NULL ) ) { error_top( _( "Unable to load." ) ); error_sub( _( "Error loading plug-in \"%s\"." ), name ); error_vips(); iwindow_alert( NULL, GTK_MESSAGE_ERROR ); } return( NULL ); } #endif /*!DEBUG_NOAUTO*/ static void * main_load_def( const char *filename ) { Toolkit *kit; if( !main_option_no_load_menus || im_skip_dir( filename )[0] == '_' ) { progress_update_loading( 0, im_skip_dir( filename ) ); if( !(kit = toolkit_new_from_file( main_toolkitgroup, filename )) ) iwindow_alert( NULL, GTK_MESSAGE_ERROR ); else filemodel_set_auto_load( FILEMODEL( kit ) ); } return( NULL ); } static void * main_load_wsg( const char *filename ) { Workspacegroup *wsg; #ifdef DEBUG printf( "main_load_wsg: %s\n", filename ); #endif/*DEBUG*/ progress_update_loading( 0, im_skip_dir( filename ) ); if( !(wsg = workspacegroup_new_from_file( main_workspaceroot, filename, filename )) ) iwindow_alert( NULL, GTK_MESSAGE_ERROR ); else { filemodel_set_auto_load( FILEMODEL( wsg ) ); } return( NULL ); } #ifndef DEBUG_NOAUTO /* Link all the packages in a function. */ static void * main_link_package( im_package *pack) { char name[MAX_STRSIZE]; Toolkit *kit; int i; im_snprintf( name, MAX_STRSIZE, "_%s", pack->name ); kit = toolkit_new( main_toolkitgroup, name ); for( i = 0; i < pack->nfuncs; i++ ) if( call_is_callable( pack->table[i] ) ) { Symbol *sym; sym = symbol_new( symbol_root->expr->compile, pack->table[i]->name ); g_assert( sym->type == SYM_ZOMBIE ); sym->type = SYM_EXTERNAL; sym->function = pack->table[i]; sym->fn_nargs = call_n_args( pack->table[i] ); (void) tool_new_sym( kit, -1, sym ); symbol_made( sym ); } filemodel_set_auto_load( FILEMODEL( kit ) ); filemodel_set_modified( FILEMODEL( kit ), FALSE ); kit->pseudo = TRUE; return( NULL ); } #endif /*!DEBUG_NOAUTO*/ /* Load all plugins and defs. */ static void main_load_startup( void ) { mainw_recent_freeze(); /* Stop load of builtins, plugs and vips ... handy for debugging if you're * tracing symbol.c */ #ifdef DEBUG_NOAUTO printf( "*** DEBUG_NOAUTO set, not loading builtin, plugs and vips\n" ); #else /*!DEBUG_NOAUTO*/ #ifdef DEBUG printf( "built-ins init\n" ); #endif/*DEBUG*/ /* Add builtin toolkit. */ builtin_init(); #ifdef DEBUG printf( "plug-ins init\n" ); #endif/*DEBUG*/ /* Load any plug-ins on PATH_START. */ (void) path_map( PATH_START, "*.plg", (path_map_fn) main_load_plug, NULL ); /* Link all VIPS functions as SYM_EXTERNAL. */ (void) im_map_packages( (VSListMap2Fn) main_link_package, NULL ); #endif /*!DEBUG_NOAUTO*/ /* Load up all defs and wses. */ #ifdef DEBUG printf( "definitions init\n" ); #endif/*DEBUG*/ (void) path_map( PATH_START, "*.def", (path_map_fn) main_load_def, NULL ); #ifdef DEBUG printf( "ws init\n" ); #endif/*DEBUG*/ (void) path_map( PATH_START, "*.ws", (path_map_fn) main_load_wsg, NULL ); mainw_recent_thaw(); } static void * main_junk_auto_load( Filemodel *filemodel ) { g_assert( IS_FILEMODEL( filemodel ) ); if( filemodel->auto_load ) IDESTROY( filemodel ); return( NULL ); } /* Remove and reload all menus/plugins/workspaces. */ void main_reload( void ) { progress_begin(); /* Remove. */ toolkitgroup_map( main_toolkitgroup, (toolkit_map_fn) main_junk_auto_load, NULL, NULL ); workspace_map( (workspace_map_fn) main_junk_auto_load, NULL, NULL ); im_close_plugins(); /* Reload. */ main_load_startup(); /* We may have changed our prefs ... link the watches to the * new prefs workspace. */ watch_relink_all(); progress_end(); } /* Use a file to paint a named stock item. */ static void main_file_for_stock( GtkIconFactory *icon_factory, const char *stock, const char *file ) { GtkIconSource *icon_source; GtkIconSet *icon_set; char buf[FILENAME_MAX]; im_snprintf( buf, FILENAME_MAX, "$VIPSHOME/share/$PACKAGE/data/%s", file ); path_expand( buf ); icon_source = gtk_icon_source_new(); gtk_icon_source_set_filename( icon_source, buf ); icon_set = gtk_icon_set_new(); gtk_icon_set_add_source( icon_set, icon_source ); gtk_icon_source_free( icon_source ); gtk_icon_factory_add( icon_factory, stock, icon_set ); gtk_icon_set_unref( icon_set ); } /* Make our custom icon sets. */ static void main_register_icons( void ) { static const GtkStockItem stock_item[] = { /* Can be (eg.) * * { GTK_STOCK_COPY, N_("_Copy"), GDK_CONTROL_MASK, 'c', GETTEXT_PACKAGE }, * */ { STOCK_NEXT_ERROR, N_( "Next _Error" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_DROPPER, N_( "Ink dropper" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_DUPLICATE, N_( "D_uplicate" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_PAINTBRUSH, N_( "Pen" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_LINE, N_( "Line" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_TEXT, N_( "Text" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_SMUDGE, N_( "Smudge" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_FLOOD, N_( "Flood" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_FLOOD_BLOB, N_( "Flood Blob" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_RECT, N_( "Fill Rectangle" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_MOVE, N_( "Pan" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_SELECT, N_( "Select" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_LOCK, N_( "Locked" ), 0, 0, GETTEXT_PACKAGE }, /* And the LEDs we use. */ { STOCK_LED_RED, N_( "Red LED" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_LED_GREEN, N_( "Green LED" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_LED_BLUE, N_( "Blue LED" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_LED_YELLOW, N_( "Yellow LED" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_LED_CYAN, N_( "Cyan LED" ), 0, 0, GETTEXT_PACKAGE }, { STOCK_LED_OFF, N_( "Off LED" ), 0, 0, GETTEXT_PACKAGE } }; GtkIconSet *icon_set; gtk_stock_add_static( stock_item, IM_NUMBER( stock_item ) ); main_icon_factory = gtk_icon_factory_new(); /* Make a colour picker stock ... take the stock icon and add our own * text (gtk defines no text for the standard version of this stock * icon). */ icon_set = gtk_icon_factory_lookup_default( GTK_STOCK_COLOR_PICKER ); gtk_icon_factory_add( main_icon_factory, STOCK_DROPPER, icon_set ); /* For Next Error, use JUMP_TO. */ icon_set = gtk_icon_factory_lookup_default( GTK_STOCK_JUMP_TO ); gtk_icon_factory_add( main_icon_factory, STOCK_NEXT_ERROR, icon_set ); /* For clone, use the DND_MULTIPLE icon (close enough). */ icon_set = gtk_icon_factory_lookup_default( GTK_STOCK_DND_MULTIPLE ); gtk_icon_factory_add( main_icon_factory, STOCK_DUPLICATE, icon_set ); /* Link to our stock .pngs. */ main_file_for_stock( main_icon_factory, STOCK_PAINTBRUSH, "stock-tool-ink-22.png" ); main_file_for_stock( main_icon_factory, STOCK_LINE, "stock-tool-path-22.png" ); main_file_for_stock( main_icon_factory, STOCK_TEXT, "stock-tool-text-22.png" ); main_file_for_stock( main_icon_factory, STOCK_SMUDGE, "stock-tool-smudge-22.png" ); main_file_for_stock( main_icon_factory, STOCK_FLOOD, "stock-tool-bucket-fill-22.png" ); main_file_for_stock( main_icon_factory, STOCK_FLOOD_BLOB, "stock-tool-bucket-fill-22.png" ); main_file_for_stock( main_icon_factory, STOCK_RECT, "stock-tool-rect-select-22.png" ); main_file_for_stock( main_icon_factory, STOCK_MOVE, "stock-tool-move-22.png" ); main_file_for_stock( main_icon_factory, STOCK_SELECT, "stock-tool-select-22.png" ); main_file_for_stock( main_icon_factory, STOCK_LOCK, "stock-padlock-closed-22.png" ); main_file_for_stock( main_icon_factory, STOCK_ALERT, "stock-alert-22.png" ); main_file_for_stock( main_icon_factory, STOCK_LED_RED, "stock-led-red-18.png" ); main_file_for_stock( main_icon_factory, STOCK_LED_GREEN, "stock-led-green-18.png" ); main_file_for_stock( main_icon_factory, STOCK_LED_BLUE, "stock-led-blue-18.png" ); main_file_for_stock( main_icon_factory, STOCK_LED_YELLOW, "stock-led-yellow-18.png" ); main_file_for_stock( main_icon_factory, STOCK_LED_CYAN, "stock-led-cyan-18.png" ); main_file_for_stock( main_icon_factory, STOCK_LED_OFF, "stock-led-off-18.png" ); gtk_icon_factory_add_default( main_icon_factory ); g_object_unref( main_icon_factory ); } /* Init the display connection stuff. */ static void main_x_init( int *argc, char ***argv ) { char buf[FILENAME_MAX]; #ifdef DEBUG printf( "X11 init\n" ); #endif/*DEBUG*/ (void) calli_string_filename( (calli_string_fn) gtk_rc_add_default_file, "$VIPSHOME" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "rc" G_DIR_SEPARATOR_S "ipgtkrc", NULL, NULL, NULL ); gtk_init( argc, argv ); /* Set the default icon. */ im_strncpy( buf, "$VIPSHOME/share/$PACKAGE/data/vips-128.png", FILENAME_MAX ); path_expand( buf ); gtk_window_set_default_icon_from_file( buf, NULL ); /* Turn off startup notification. Startup is done when we pop our * first window, not when we make this secret window. */ gtk_window_set_auto_startup_notification( FALSE ); #ifdef DEBUG_UPDATES printf( "*** debug updates is on\n" ); gdk_window_set_debug_updates( TRUE ); #endif /*DEBUG_UPDATES*/ main_register_icons(); /* Next window we make is end of startup. */ gtk_window_set_auto_startup_notification( TRUE ); /* Load up any saved accelerators. */ calli_string_filenamef( (calli_string_fn) gtk_accel_map_load, "%s" G_DIR_SEPARATOR_S "accel_map", get_savedir() ); } static void * main_toobig_done_sub( const char *filename ) { unlinkf( "%s", filename ); return( NULL ); } /* OK in "flush temps" yesno. */ static void main_toobig_done( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { /* Don't "rm *", too dangerous. */ path_map_dir( PATH_TMP, "*.v", (path_map_fn) main_toobig_done_sub, NULL ); path_map_dir( PATH_TMP, "*.ws", (path_map_fn) main_toobig_done_sub, NULL ); /* _stdenv.def:magick can generate .tif files. */ path_map_dir( PATH_TMP, "*.tif", (path_map_fn) main_toobig_done_sub, NULL ); /* autotrace can make some others. */ path_map_dir( PATH_TMP, "*.ppm", (path_map_fn) main_toobig_done_sub, NULL ); path_map_dir( PATH_TMP, "*.svg", (path_map_fn) main_toobig_done_sub, NULL ); /* Tell space-free indicators to update. */ if( main_imageinfogroup ) iobject_changed( IOBJECT( main_imageinfogroup ) ); nfn( sys, IWINDOW_YES ); } /* Test for a bunch of stuff in the TMP area. Need to do this before * we load args in case there are large JPEGs there. Only bother in * interactive mode: we won't be able to question the user without an * X connection. */ static void main_check_temp( double total ) { if( total > 10 * 1024 * 1024 ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); char tmp[FILENAME_MAX]; im_strncpy( tmp, PATH_TMP, FILENAME_MAX ); path_expand( tmp ); vips_buf_append_size( &buf, total ); box_yesno( NULL, main_toobig_done, iwindow_true_cb, NULL, NULL, NULL, _( "Empty temp area" ), _( "Many files in temp area." ), _( "The temp area \"%s\" contains %s of files. " "Would you like to empty the temp area? " "This will delete any workspace backups and " "cannot be undone." ), tmp, vips_buf_all( &buf ) ); } } /* Make sure a savedir exists. Used to build the "~/.nip2-xx/tmp" etc. * directory tree. */ static void main_mkdir( const char *dir ) { if( !existsf( "%s" G_DIR_SEPARATOR_S "%s", get_savedir(), dir ) ) if( !mkdirf( "%s" G_DIR_SEPARATOR_S "%s", get_savedir(), dir ) ) error_exit( _( "unable to make %s %s: %s" ), get_savedir(), dir, g_strerror( errno ) ); } static gboolean main_set( const char *str ) { Symbol *sym; attach_input_string( str ); if( !(sym = parse_set_symbol()) ) return( FALSE ); /* Put the input just after the '=', ready to parse a RHS into the * symbol. */ attach_input_string( str + IM_CLIP( 0, input_state.charpos - 1, strlen( str ) ) ); if( !symbol_user_init( sym ) || !parse_rhs( sym->expr, PARSE_RHS ) ) { /* Another parse error. */ expr_error_get( sym->expr ); /* Block changes to error_string ... symbol_destroy() * can set this for compound objects. */ error_block(); IDESTROY( sym ); error_unblock(); return( FALSE ); } symbol_made( sym ); /* Is there a row? Make sure any modified text there can't zap our new * text. */ if( sym->expr->row ) { Row *row = sym->expr->row; heapmodel_set_modified( HEAPMODEL( row->child_rhs->itext ), FALSE ); } return( TRUE ); } static char prefix_buffer[FILENAME_MAX]; static gboolean prefix_valid = FALSE; /* Override the install guess from vips. Handy for testing. */ static void set_prefix( const char *prefix ) { im_strncpy( prefix_buffer, prefix, FILENAME_MAX ); nativeize_path( prefix_buffer ); absoluteize_path( prefix_buffer ); setenvf( "VIPSHOME", "%s", prefix_buffer ); prefix_valid = TRUE; } /* Guess VIPSHOME, if we can. */ const char * get_prefix( void ) { if( !prefix_valid ) { const char *prefix; if( !(prefix = im_guess_prefix( main_argv0, "VIPSHOME" )) ) { error_top( _( "Unable to find install area." ) ); error_vips(); return( NULL ); } set_prefix( prefix ); } return( prefix_buffer ); } /* Start here! */ int main( int argc, char *argv[] ) { gboolean welcome_message = FALSE; Workspacegroup *wsg; Workspace *ws; GError *error = NULL; GOptionContext *context; const char *prefix; int i; double total = 0.0; #ifdef HAVE_GETRLIMIT struct rlimit rlp; #endif /*HAVE_GETRLIMIT*/ char name[256]; #if HAVE_FFTW || HAVE_FFTW3 iOpenFile *of; #endif /*HAVE_FFTW*/ Toolkit *kit; char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); #ifdef DEBUG_TIME GTimer *startup_timer = g_timer_new(); printf( "DEBUG_TIME: startup timer zeroed ...\n" ); #endif /*DEBUG_TIME*/ /* In startup phase. */ main_starting = TRUE; /* Want numeric locale to be "C", so we have C rules for doing * double <-> string (ie. no "," for decimal point). */ setlocale( LC_ALL, "" ); setlocale( LC_NUMERIC, "C" ); /* Make sure our LC_NUMERIC setting is not trashed. */ gtk_disable_setlocale(); #ifdef DEBUG printf( "main: sizeof( HeapNode ) == %zd\n", sizeof( HeapNode ) ); /* Should be 3 pointers, hopefully. */ if( sizeof( HeapNode ) != 3 * sizeof( void * ) ) printf( "*** struct packing problem!\n" ); #endif/*DEBUG*/ /* Yuk .. shouldn't really write to argv0. This can't change the * string length. * * On win32 we will sometimes get paths with mixed '/' and '\' which * confuses vips's prefix guessing. Make sure we have one or the other. */ nativeize_path( argv[0] ); main_argv0 = argv[0]; main_c_stack_base = &argc; /* Pass config.h stuff down to .ws files. */ setenvf( "PACKAGE", "%s", PACKAGE ); setenvf( "VERSION", "%s", VERSION ); #ifdef OS_WIN32 { /* No HOME on windows ... make one from HOMEDRIVE and HOMEDIR (via * glib). */ const char *home; char buf[FILENAME_MAX]; if( !(home = g_getenv( "HOME" )) ) home = g_get_home_dir(); /* We need native paths. */ strncpy( buf, home, FILENAME_MAX ); nativeize_path( buf ); setenvf( "HOME", "%s", buf ); } #endif /*OS_WIN32*/ /* Name of the dir we store our config stuff in. This can get used by * Preferences.ws. */ setenvf( "SAVEDIR", "%s", get_savedir() ); /* Path separator on this platform. */ setenvf( "SEP", "%s", G_DIR_SEPARATOR_S ); /* Executable file extension (eg. ".exe" on Windows). */ setenvf( "EXEEXT", "%s", VIPS_EXEEXT ); /* Start up vips. */ if( im_init_world( main_argv0 ) ) error_exit( "unable to start VIPS" ); /* The vips8 cache is no use to us. We have our own cache which is * integrated with our invalidate system. */ vips_cache_set_max( 0 ); /* Init i18n ... get catalogues from $VIPSHOME/share/locale so we're * relocatable. */ prefix = get_prefix(); im_snprintf( name, 256, "%s" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S "locale", prefix ); #ifdef DEBUG printf( "bindtextdomain: %s\n", name ); #endif /*DEBUG*/ textdomain( GETTEXT_PACKAGE ); bindtextdomain( GETTEXT_PACKAGE, name ); bind_textdomain_codeset( GETTEXT_PACKAGE, "UTF-8" ); /* Set localised application name. */ g_set_application_name( _( PACKAGE ) ); context = g_option_context_new( _( "- image processing spreadsheet" ) ); g_option_context_add_main_entries( context, main_option, GETTEXT_PACKAGE ); /* Don't start X here! We may be in batch mode. */ g_option_context_add_group( context, gtk_get_option_group( FALSE ) ); g_option_context_add_group( context, im_get_option_group() ); if( !g_option_context_parse( context, &argc, &argv, &error ) ) vfatal( &error ); g_option_context_free( context ); /* Override the install guess from vips. This won't pick up msg * cats sadly :( since we have to init i18n before arg parsing. Handy * for testing without installing. */ if( main_option_prefix ) set_prefix( main_option_prefix ); if( main_option_version ) { printf( "%s-%s", PACKAGE, VERSION ); printf( "\n" ); printf( _( "linked to vips-%s" ), im_version_string() ); printf( "\n" ); exit( 0 ); } #ifdef DEBUG_FATAL /* Set masks for debugging ... stop on any problem. */ g_log_set_always_fatal( G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL | G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING ); #else /*!DEBUG_FATAL*/ #ifdef OS_WIN32 /* No logging output ... on win32, log output pops up a very annoying * console text box. */ g_log_set_handler( "GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, main_log_null, NULL ); g_log_set_handler( "Gtk", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, main_log_null, NULL ); g_log_set_handler( NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, main_log_null, NULL ); #endif /*OS_WIN32*/ #endif /*DEBUG_FATAL*/ main_stdin = ifile_open_read_stdin(); #ifdef HAVE_GETRLIMIT /* Make sure we have lots of file descriptors. Some platforms have cur * as 256 and max at 1024 to keep stdio happy. */ if( getrlimit( RLIMIT_NOFILE, &rlp ) == 0 ) { rlim_t old_limit = rlp.rlim_cur; rlp.rlim_cur = rlp.rlim_max; if( setrlimit( RLIMIT_NOFILE, &rlp ) == 0 ) { #ifdef DEBUG printf( "set max file descriptors to %d\n", (int) rlp.rlim_max ); #endif /*DEBUG*/ } else if( (int) rlp.rlim_max != -1 ) { /* -1 means can't-be-set, at least on os x, so don't * warn. */ g_warning( _( "unable to change max file descriptors\n" "max file descriptors still set to %d" ), (int) old_limit ); } } else { g_warning( _( "unable to read max file descriptors" ) ); } #endif /*HAVE_GETRLIMIT*/ /* Make our file types. */ filesel_startup(); /* Set default values for paths. */ path_init(); /* First time we've been run? Welcome message. */ if( !existsf( "%s", get_savedir() ) ) welcome_message = TRUE; /* Always make these in case some got deleted. */ main_mkdir( "" ); main_mkdir( "tmp" ); main_mkdir( "start" ); main_mkdir( "data" ); /* Init other stuff. */ #ifdef HAVE_FFTW3 fftw_import_system_wisdom(); #endif /*HAVE_FFTW3*/ #if HAVE_FFTW || HAVE_FFTW3 if( (of = ifile_open_read( "%s" G_DIR_SEPARATOR_S "wisdom", get_savedir() )) ) { fftw_import_wisdom_from_file( of->fp ); ifile_close( of ); } #endif /*HAVE_FFTW*/ mainw_startup(); reduce_context = reduce_new(); main_symbol_root = symbol_root_init(); g_object_ref( G_OBJECT( main_symbol_root ) ); iobject_sink( IOBJECT( main_symbol_root ) ); model_base_init(); main_workspaceroot = workspaceroot_new( "Workspaces" ); g_object_ref( G_OBJECT( main_workspaceroot ) ); iobject_sink( IOBJECT( main_workspaceroot ) ); main_watchgroup = watchgroup_new( main_workspaceroot, "Preferences" ); g_object_ref( G_OBJECT( main_watchgroup ) ); iobject_sink( IOBJECT( main_watchgroup ) ); main_toolkitgroup = toolkitgroup_new( symbol_root ); g_object_ref( G_OBJECT( main_toolkitgroup ) ); iobject_sink( IOBJECT( main_toolkitgroup ) ); main_imageinfogroup = imageinfogroup_new(); g_object_ref( G_OBJECT( main_imageinfogroup ) ); iobject_sink( IOBJECT( main_imageinfogroup ) ); /* First pass at command-line options. Just look at the flags that * imply other flags, don't do any processing yet. */ if( main_option_script ) { main_option_batch = TRUE; main_option_no_load_menus = TRUE; main_option_no_load_args = TRUE; main_option_print_main = TRUE; } if( main_option_test ) { main_option_batch = TRUE; main_option_verbose = TRUE; } if( main_option_expression ) { main_option_batch = TRUE; main_option_no_load_menus = TRUE; main_option_no_load_args = TRUE; main_option_print_main = TRUE; } if( main_option_benchmark ) { main_option_batch = TRUE; main_option_no_load_menus = FALSE; } if( main_option_i18n ) { /* Just start up and shutdown, no X. Output constant * i18n strings. */ main_option_batch = TRUE; main_option_no_load_menus = FALSE; } #ifdef DEBUG if( main_option_batch ) printf( "non-interactive mode\n" ); #endif /*DEBUG*/ /* Start the X connection. We need this before _load_all(), so that * we can pop up error dialogs. */ if( !main_option_batch ) main_x_init( &argc, &argv ); #ifdef HAVE_LIBGOFFICE libgoffice_init(); go_plugins_init( NULL, NULL, NULL, NULL, TRUE, GO_TYPE_PLUGIN_LOADER_MODULE ); #endif /*HAVE_LIBGOFFICE*/ /* Load start-up stuff. Builtins, plugins, externals etc. We need to * do this before we load any user code so we can prevent redefinition * of builtins. */ main_load_startup(); /* Recalc to build all classes and gets prefs working. * * We have to do this in batch * mode since we can find dirties through dynamic lookups. Even though * you might think we could just follow recomps. */ symbol_recalculate_all_force( TRUE ); #ifdef DEBUG printf( "arg processing\n" ); #endif/*DEBUG*/ /* Might make this from stdin/whatever if we have a special * command-line flag. */ wsg = NULL; ws = NULL; /* Second command-line pass. This time we do any actions. */ if( main_option_script ) { if( !toolkit_new_from_file( main_toolkitgroup, main_option_script ) ) main_log_add( "%s\n", error_get_sub() ); } if( main_option_expression ) { kit = toolkit_new( main_toolkitgroup, "_expression" ); vips_buf_appendf( &buf, "main = %s;", main_option_expression ); attach_input_string( vips_buf_all( &buf ) ); (void) parse_onedef( kit, -1 ); filemodel_set_modified( FILEMODEL( kit ), FALSE ); } if( main_option_stdin_def ) { if( !(kit = toolkit_new_from_openfile( main_toolkitgroup, main_stdin )) ) main_log_add( "%s\n", error_get_sub() ); } if( main_option_stdin_ws ) { if( !(wsg = workspacegroup_new_from_openfile( main_workspaceroot, main_stdin )) ) main_log_add( "%s\n", error_get_sub() ); else /* Don't want to have "stdin" as the filename. */ filemodel_set_filename( FILEMODEL( wsg ), NULL ); } /* Make a start workspace and workspacegroup to load * stuff into. */ if( !wsg ) { wsg = workspacegroup_new_blank( main_workspaceroot, NULL ); ws = WORKSPACE( icontainer_get_nth_child( ICONTAINER( wsg ), 0 ) ); } /* Reset IM_CONCURRENCY if a watch changes. Need to do this after * parsing options so we skip in batch mode. */ g_signal_connect( main_watchgroup, "watch_changed", G_CALLBACK( main_watchgroup_changed_cb ), NULL ); /* Pass PATH_TMP down to vips via TMPDIR. See im_system(), for * example. We need to do this after the first recomp so that prefs * are loaded. */ { char buf[FILENAME_MAX]; im_strncpy( buf, PATH_TMP, FILENAME_MAX ); path_expand( buf ); setenvf( "TMPDIR", "%s", buf ); path_rewrite_add( PATH_TMP, "$TMPDIR", TRUE ); } /* Measure amount of stuff in temp area ... need this for checking * temps later. We pop a dialog if there are too many, so only useful * in interactive mode. */ if( !main_option_batch ) total = directory_size( PATH_TMP ); /* Make nip's argc/argv[]. */ kit = toolkit_new( main_toolkitgroup, "_args" ); vips_buf_rewind( &buf ); vips_buf_appendf( &buf, "argc = %d;", argc ); attach_input_string( vips_buf_all( &buf ) ); (void) parse_onedef( kit, -1 ); vips_buf_rewind( &buf ); vips_buf_appendf( &buf, "argv = [" ); for( i = 0; i < argc; i++ ) { /* Ignore "--" args. Consider eg. * * ./try201.nip2 -o x.v -- -12 ~/pics/shark.jpg * * if we didn't remove --, all scripts would need to. */ if( strcmp( argv[i], "--" ) == 0 ) continue; if( i > 0 ) vips_buf_appendf( &buf, ", " ); vips_buf_appendf( &buf, "\"%s\"", argv[i] ); } vips_buf_appendf( &buf, "];" ); attach_input_string( vips_buf_all( &buf ) ); if( !parse_onedef( kit, -1 ) ) main_log_add( "%s\n", error_get_sub() ); filemodel_set_modified( FILEMODEL( kit ), FALSE ); /* Double-check: we often forget to move the prefs ws to the latest * version. */ #ifdef DEBUG_LEAK { Symbol *wsr_sym = main_workspaceroot->sym; Symbol *ws_sym = SYMBOL( icontainer_child_lookup( ICONTAINER( wsr_sym->expr->compile ), "Preferences" ) ); if( !ws_sym ) printf( "No prefs workspace!\n" ); else { Workspace *ws = ws_sym->ws; if( ws->compat_major || ws->compat_minor ) printf( "Preferences loaded in compat mode!\n" ); } } #endif /*DEBUG_LEAK*/ if( !main_option_no_load_args ) { /* Load args as files, if we can. */ for( i = 1; i < argc; i++ ) { char buf[FILENAME_MAX]; /* We want to use the absolute, compact form of the * filename object so we don't get a dependency on CWD. */ im_strncpy( buf, argv[i], FILENAME_MAX ); path_compact( buf ); if( !main_load( ws, buf ) ) main_log_add( "%s\n", error_get_sub() ); } } /* In batch mode give up if there are startup errors. */ if( main_option_batch ) { if( !main_log_is_empty() ) { fprintf( stderr, _( "Startup error log:\n%s" ), main_log_get() ); exit( 1 ); } } if( main_option_set ) { int i; for( i = 0; main_option_set[i]; i++ ) { if( main_option_verbose ) printf( "main_set: %s\n", main_option_set[i] ); if( !main_set( main_option_set[i] ) ) main_log_add( "%s\n%s", error_get_top(), error_get_sub() ); } } /* Make sure our start ws doesn't have modified set. We may have * loaded some images or whatever into it. */ workspace_set_modified( ws, FALSE ); /* If the start ws is empty (we didn't load anything into it) and we * loaded some other workspaces, we can junk the empty ws. */ if( icontainer_get_n_children( ICONTAINER( main_workspaceroot ) ) > 2 && workspace_is_empty( ws ) ) { IDESTROY( wsg ); wsg = NULL; ws = NULL; } #ifdef DEBUG_TIME printf( "DEBUG_TIME: main init in %gs\n", g_timer_elapsed( startup_timer, NULL ) ); #endif /*DEBUG_TIME*/ /* Are we running interactively? Start the main window and loop. */ if( !main_option_batch ) { if( wsg ) { Mainw *mainw; mainw = mainw_new( wsg ); gtk_widget_show( GTK_WIDGET( mainw ) ); } /* Process a few events ... we want the window to be mapped so * that log/welcome/clean? messages we pop appear in the right * place on the screen. */ while( g_main_context_iteration( NULL, FALSE ) ) ; if( !main_log_is_empty() ) { error_top( _( "Startup error." ) ); error_sub( _( "Startup error log:\n%s" ), main_log_get() ); iwindow_alert( NULL, GTK_MESSAGE_ERROR ); } if( welcome_message ) { char save_dir[FILENAME_MAX]; char buf[256]; im_snprintf( buf, 256, _( "Welcome to %s-%s!" ), PACKAGE, VERSION ); im_strncpy( save_dir, get_savedir(), FILENAME_MAX ); path_expand( save_dir ); error_top( "%s", buf ); error_sub( _( "A new directory has been created to hold startup, " "data and temporary files:\n\n" " %s\n\n" "If you've used previous versions of %s, you might want " "to copy files over from your old work area." ), save_dir, PACKAGE ); iwindow_alert( NULL, GTK_MESSAGE_INFO ); } main_check_temp( total ); #ifdef DEBUG printf( "starting event dispatch loop\n" ); #endif/*DEBUG*/ main_starting = FALSE; symbol_recalculate_all_force( FALSE ); gtk_main(); } if( main_option_test ) { /* Make sure we've had at least one recomp. */ symbol_recalculate_all_force( TRUE ); if( expr_error_all ) main_error_exit( "--test: errors found" ); } /* No return from this. */ main_quit(); return( 0 ); } #ifdef OS_WIN32 /* Get non-cmd line args on win32. */ static int breakargs( char *program, char *line, char **argv ) { int argc = 1; argv[0] = program; while( *line && argc < MAX_SYSTEM - 1 ) { while( *line && isspace( *line ) ) line++; if( *line == '"' ) { /* Windows-95 quoted arguments */ char *start = line + 1; char *end = start; while( *end && *end != '"' ) end++; if( *end == '"' ) { *end = '\0'; argv[argc++] = start; line = end + 1; continue; } } if( *line ) { argv[argc++] = line; while( *line && !isspace( *line ) ) line++; if( *line ) *line++ = '\0'; } } /* add trailing NULL pointer to argv */ argv[argc] = NULL; return( argc ); } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nShowCmd ) { char *argv[MAX_SYSTEM]; int argc; TCHAR program[MAXPATHLEN]; GetModuleFileName( hInstance, program, sizeof(program) ); argc = breakargs( (char *) program, lpszCmdLine, argv ); return( main( argc, argv ) ); } #endif /*OS_WIN32*/ nip2-8.7.1/src/classmodel.c0000644000175000017500000010617113351443023012405 00000000000000/* like a heapmodel, but we represent a class in the heap */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static HeapmodelClass *parent_class = NULL; void image_value_init( ImageValue *image, Classmodel *classmodel ) { image->ii = NULL; image->file_changed_sid = 0; image->classmodel = classmodel; } void image_value_destroy( ImageValue *image ) { FREESID( image->file_changed_sid, image->ii ); MANAGED_UNREF( image->ii ); } static void image_value_file_changed_cb( Imageinfo *ii, ImageValue *image ) { #ifdef DEBUG printf( "image_value_file_changed_cb: " ); iobject_print( IOBJECT( image->classmodel ) ); #endif /*DEBUG*/ if( CALC_RELOAD ) { Row *row = HEAPMODEL( image->classmodel )->row; (void) expr_dirty( row->expr, link_serial_new() ); symbol_recalculate_all(); } } void image_value_set( ImageValue *image, Imageinfo *ii ) { image_value_destroy( image ); image->ii = ii; if( ii ) { MANAGED_REF( image->ii ); image->file_changed_sid = g_signal_connect( G_OBJECT( image->ii ), "file_changed", G_CALLBACK( image_value_file_changed_cb ), image ); } #ifdef DEBUG printf( "iimage_instance_update: ii = %p\n", ii ); #endif /*DEBUG*/ } /* Generate a descriptive name for an imagevalue. Used by plot.c etc. as well. */ void image_value_caption( ImageValue *value, VipsBuf *buf ) { Imageinfo *ii = value->ii; Classmodel *classmodel = value->classmodel; /* Show the filename if this ii came from a file, otherwise show * the class. */ if( ii && imageinfo_is_from_file( ii ) && classmodel->filename ) vips_buf_appends( buf, im_skip_dir( classmodel->filename ) ); else if( !heapmodel_name( HEAPMODEL( classmodel ), buf ) ) /* Only if there's no value, I think. */ vips_buf_appends( buf, CLASS_IMAGE ); } void * classmodel_get_instance( Classmodel *classmodel ) { ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); if( class && class->get_instance ) return( class->get_instance( classmodel ) ); return( NULL ); } static void classmodel_graphic_save_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Classmodel *classmodel = CLASSMODEL( client ); ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); char *filename; if( (filename = filesel_get_filename( filesel )) ) { if( class->graphic_save( classmodel, GTK_WIDGET( iwnd ), filename ) ) { IM_SETSTR( classmodel->filename, filename ); iobject_changed( IOBJECT( classmodel ) ); nfn( sys, IWINDOW_YES ); } else nfn( sys, IWINDOW_ERROR ); g_free( filename ); } else nfn( sys, IWINDOW_ERROR ); } void classmodel_graphic_save( Classmodel *classmodel, GtkWidget *parent ) { ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); GtkWidget *filesel; char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( !class->graphic_save ) { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() method not implemented for %s." ), "graphic_save", IOBJECT_GET_CLASS_NAME( classmodel ) ); iwindow_alert( parent, GTK_MESSAGE_ERROR ); return; } filesel = filesel_new(); row_qualified_name( HEAPMODEL( classmodel )->row, &buf ); iwindow_set_title( IWINDOW( filesel ), _( "Save %s \"%s\"" ), IOBJECT_GET_CLASS_NAME( classmodel ), vips_buf_all( &buf ) ); filesel_set_flags( FILESEL( filesel ), TRUE, TRUE ); filesel_set_filetype( FILESEL( filesel ), class->filetype, watch_int_get( main_watchgroup, class->filetype_pref, 0 ) ); filesel_set_filetype_pref( FILESEL( filesel ), class->filetype_pref ); iwindow_set_parent( IWINDOW( filesel ), parent ); idialog_set_iobject( IDIALOG( filesel ), IOBJECT( classmodel ) ); filesel_set_done( FILESEL( filesel ), classmodel_graphic_save_cb, classmodel ); iwindow_build( IWINDOW( filesel ) ); if( classmodel->filename ) filesel_set_filename( FILESEL( filesel ), classmodel->filename ); gtk_widget_show( GTK_WIDGET( filesel ) ); } static void classmodel_graphic_replace_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Classmodel *classmodel = CLASSMODEL( client ); ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); char *filename; if( (filename = filesel_get_filename( filesel )) ) { if( class->graphic_replace( classmodel, GTK_WIDGET( iwnd ), filename ) ) { /* Make sure client stays alive through the * recalculate. */ g_object_ref( G_OBJECT( classmodel ) ); symbol_recalculate_all(); IM_SETSTR( classmodel->filename, filename ); iobject_changed( IOBJECT( classmodel ) ); g_object_unref( G_OBJECT( classmodel ) ); nfn( sys, IWINDOW_YES ); } else nfn( sys, IWINDOW_ERROR ); g_free( filename ); } else nfn( sys, IWINDOW_ERROR ); } void classmodel_graphic_replace( Classmodel *classmodel, GtkWidget *parent ) { ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); GtkWidget *filesel; char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( !class->graphic_replace ) { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() method not implemented for %s." ), "graphic_replace", IOBJECT_GET_CLASS_NAME( classmodel ) ); iwindow_alert( parent, GTK_MESSAGE_ERROR ); return; } row_qualified_name( HEAPMODEL( classmodel )->row, &buf ); filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Replace %s \"%s\"" ), IOBJECT_GET_CLASS_NAME( classmodel ), vips_buf_all( &buf ) ); filesel_set_flags( FILESEL( filesel ), TRUE, FALSE ); filesel_set_filetype( FILESEL( filesel ), class->filetype, watch_int_get( main_watchgroup, class->filetype_pref, 0 ) ); filesel_set_filetype_pref( FILESEL( filesel ), class->filetype_pref ); iwindow_set_parent( IWINDOW( filesel ), parent ); idialog_set_iobject( IDIALOG( filesel ), IOBJECT( classmodel ) ); filesel_set_done( FILESEL( filesel ), classmodel_graphic_replace_cb, classmodel ); iwindow_build( IWINDOW( filesel ) ); if( classmodel->filename ) filesel_set_filename( FILESEL( filesel ), classmodel->filename ); gtk_widget_show( GTK_WIDGET( filesel ) ); } /* Make and break links between classmodels and the iimages displaying them. */ static void classmodel_iimage_link( Classmodel *classmodel, iImage *iimage ) { if( !g_slist_find( classmodel->iimages, iimage ) ) { #ifdef DEBUG printf( "classmodel_iimage_link: linking " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( " to " ); row_name_print( HEAPMODEL( iimage )->row ); printf( "\n" ); #endif /*DEBUG*/ iimage->classmodels = g_slist_prepend( iimage->classmodels, classmodel ); classmodel->iimages = g_slist_prepend( classmodel->iimages, iimage ); } } void * classmodel_iimage_unlink( Classmodel *classmodel, iImage *iimage ) { if( g_slist_find( classmodel->iimages, iimage ) ) { #ifdef DEBUG printf( "classmodel_iimage_unlink: unlinking " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( " from " ); row_name_print( HEAPMODEL( iimage )->row ); printf( "\n" ); #endif /*DEBUG*/ iimage->classmodels = g_slist_remove( iimage->classmodels, classmodel ); classmodel->iimages = g_slist_remove( classmodel->iimages, iimage ); } return( NULL ); } static void * classmodel_iimage_unlink_rev( iImage *iimage, Classmodel *classmodel ) { return( classmodel_iimage_unlink( classmodel, iimage ) ); } typedef struct { Classmodel *classmodel; Imageinfo *ii; } ClassmodelSearch; static void * classmodel_iimage_expr_model( Model *model, ClassmodelSearch *parms ) { /* Look for iimages which aren't super ... ie. if this is a class * derived from Image, display on the derived class, not on the * superclass. */ if( IS_IIMAGE( model ) && HEAPMODEL( model )->row->sym && !is_super( HEAPMODEL( model )->row->sym ) && !is_this( HEAPMODEL( model )->row->sym ) ) { iImage *iimage = IIMAGE( model ); if( iimage->value.ii == parms->ii ) classmodel_iimage_link( parms->classmodel, iimage ); } return( NULL ); } /* This classmodel is defined on an Imageinfo recorded as having been the value * of expr ... find an associated iImage, and link to that. */ static void * classmodel_iimage_expr( Expr *expr, ClassmodelSearch *parms ) { if( expr->row ) { #ifdef DEBUG printf( "classmodel_iimage_expr: starting for " ); row_name_print( expr->row ); printf( "\n" ); #endif /*DEBUG*/ /* Search this part of the tally for an iImage with ii as its * derived value, and link to us. */ (void) icontainer_map_all( ICONTAINER( expr->row->top_row ), (icontainer_map_fn) classmodel_iimage_expr_model, parms ); } return( NULL ); } /* classmodel is defined on ii ... update all the classmodel->iimage links. */ void classmodel_iimage_update( Classmodel *classmodel, Imageinfo *ii ) { ClassmodelSearch parms; parms.classmodel = classmodel; parms.ii = ii; slist_map( classmodel->iimages, (SListMapFn) classmodel_iimage_unlink_rev, classmodel ); /* Don't make links for supers/this. */ if( HEAPMODEL( classmodel )->row->sym && !is_super( HEAPMODEL( classmodel )->row->sym ) && !is_this( HEAPMODEL( classmodel )->row->sym ) ) { #ifdef DEBUG printf( "classmodel_iimage_update: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( " is defined on ii \"%s\" ... searching for client " "displays\n", ii->im->filename ); #endif /*DEBUG*/ slist_map( imageinfo_expr_which( ii ), (SListMapFn) classmodel_iimage_expr, &parms ); } } static gboolean classmodel_class_member_new( Classmodel *classmodel, ClassmodelMember *m, Heap *heap, PElement *out ); static gboolean classmodel_dict_new( Classmodel *classmodel, ClassmodelMember *options, int noptions, Heap *heap, PElement *out ) { PElement list = *out; int i; /* Make first RHS ... the end of the list. */ heap_list_init( &list ); for( i = 0; i < noptions; i++ ) { PElement pair, key, value; if( !heap_list_add( heap, &list, &pair ) || !heap_list_add( heap, &pair, &key ) || !heap_list_add( heap, &pair, &value ) || !heap_managedstring_new( heap, options[i].member_name, &key ) || !classmodel_class_member_new( classmodel, &options[i], heap, &value ) ) return( FALSE ); (void) heap_list_next( &list ); } return( TRUE ); } static gboolean classmodel_class_member_new( Classmodel *classmodel, ClassmodelMember *m, Heap *heap, PElement *out ) { switch( m->type ) { case CLASSMODEL_MEMBER_INT: case CLASSMODEL_MEMBER_ENUM: if( !heap_real_new( heap, G_STRUCT_MEMBER( int, classmodel, m->offset ), out ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_BOOLEAN: if( !heap_bool_new( heap, G_STRUCT_MEMBER( gboolean, classmodel, m->offset ), out ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_DOUBLE: if( !heap_real_new( heap, G_STRUCT_MEMBER( double, classmodel, m->offset ), out ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_STRING: if( !heap_managedstring_new( heap, G_STRUCT_MEMBER( char *, classmodel, m->offset ), out ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_STRING_LIST: if( !heap_lstring_new( heap, G_STRUCT_MEMBER( GSList *, classmodel, m->offset ), out ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_REALVEC_FIXED: if( !heap_realvec_new( heap, m->extent, &G_STRUCT_MEMBER( double, classmodel, m->offset ), out ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_MATRIX: { MatrixValue *value = &G_STRUCT_MEMBER( MatrixValue, classmodel, m->offset ); if( !heap_matrix_new( heap, value->width, value->height, value->coeff, out ) ) return( FALSE ); break; } case CLASSMODEL_MEMBER_OPTIONS: if( !classmodel_dict_new( classmodel, (ClassmodelMember *) m->details, m->extent, heap, out ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_IMAGE: { ImageValue *value = &G_STRUCT_MEMBER( ImageValue, classmodel, m->offset ); PEPUTP( out, ELEMENT_MANAGED, value->ii ); break; } default: g_assert( 0 ); } return( TRUE ); } /* Trigger the class_new method for a classmodel ... look for a constructor: * try CLASS_edit, then if that's not defined, try CLASS. Eg. * A1.Scale_edit from to value * if Scale_edit is not defined, try * A1.Scale from to value */ static gboolean classmodel_class_instance_new( Classmodel *classmodel ) { ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); Row *row = HEAPMODEL( classmodel )->row; PElement *root = &row->expr->root; const char *cname = IOBJECT( classmodel )->name; Reduce *rc = reduce_context; Heap *heap = rc->heap; char cname_new[256]; PElement fn; #ifdef DEBUG printf( "classmodel_class_instance_new: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( "\n" ); #endif /*DEBUG*/ /* Find and build. */ im_snprintf( cname_new, 256, "%s_edit", cname ); if( !class_get_member( root, cname_new, NULL, &fn ) ) { if( !class_get_member( root, cname, NULL, &fn ) ) return( FALSE ); } if( class->class_new ) { if( !class->class_new( classmodel, &fn, root ) ) return( FALSE ); } else { int i; PElement rhs; heap_appl_init( root, &fn ); for( i = 0; i < class->n_members; i++ ) { if( !heap_appl_add( heap, root, &rhs ) ) return( FALSE ); if( !classmodel_class_member_new( classmodel, &class->members[i], heap, &rhs ) ) return( FALSE ); } } /* Reduce to base type. */ if( !reduce_pelement( rc, reduce_spine, root ) ) return( FALSE ); /* We have a new heap struct ... tell everyone to get new pointers. */ if( heapmodel_new_heap( HEAPMODEL( row ), root ) ) return( FALSE ); return( TRUE ); } static void classmodel_dispose( GObject *gobject ) { Classmodel *classmodel; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_CLASSMODEL( gobject ) ); classmodel = CLASSMODEL( gobject ); /* My instance destroy stuff. */ slist_map( classmodel->iimages, (SListMapFn) classmodel_iimage_unlink_rev, classmodel ); IM_FREE( classmodel->filename ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } /* We don't want subclases like Group to have an _info() method, since it * will appear in tooltips and the Container _info() is rather annoying. * * Things like iImage define an _info() with useful stuff in. */ static void classmodel_info( iObject *iobject, VipsBuf *buf ) { } static void classmodel_parent_add( iContainer *child ) { g_assert( IS_CLASSMODEL( child ) ); ICONTAINER_CLASS( parent_class )->parent_add( child ); } /* How many widgets we allow for member automation edit. */ #define MAX_WIDGETS (10) /* Widgets for classmodel edit. */ typedef struct _ClassmodelEdit { iDialog *idlg; Classmodel *classmodel; GtkWidget *widgets[MAX_WIDGETS]; } ClassmodelEdit; static gboolean classmodel_done_member( Classmodel *classmodel, ClassmodelMember *m, GtkWidget *widget ) { char txt[256]; switch( m->type ) { case CLASSMODEL_MEMBER_INT: case CLASSMODEL_MEMBER_ENUM: break; case CLASSMODEL_MEMBER_BOOLEAN: G_STRUCT_MEMBER( gboolean, classmodel, m->offset ) = GTK_TOGGLE_BUTTON( widget )->active; break; case CLASSMODEL_MEMBER_DOUBLE: if( !get_geditable_double( widget, &G_STRUCT_MEMBER( double, classmodel, m->offset ) ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_STRING: get_geditable_string( widget, txt, 256 ); IM_SETSTR( G_STRUCT_MEMBER( char *, classmodel, m->offset ), txt ); break; case CLASSMODEL_MEMBER_STRING_LIST: case CLASSMODEL_MEMBER_REALVEC_FIXED: case CLASSMODEL_MEMBER_MATRIX: case CLASSMODEL_MEMBER_OPTIONS: case CLASSMODEL_MEMBER_IMAGE: break; default: g_assert( 0 ); } return( TRUE ); } /* Done button hit. */ static void classmodel_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { ClassmodelEdit *eds = (ClassmodelEdit *) client; Classmodel *classmodel = eds->classmodel; ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); int i; for( i = 0; i < class->n_members; i++ ) if( !classmodel_done_member( classmodel, &class->members[i], eds->widgets[i] ) ) { nfn( sys, IWINDOW_ERROR ); return; } /* Rebuild object. */ classmodel_update( classmodel ); symbol_recalculate_all(); nfn( sys, IWINDOW_YES ); } static GtkWidget * classmodel_buildedit_member( Classmodel *classmodel, ClassmodelMember *m, iDialog *idlg, GtkWidget *vb, GtkSizeGroup *group ) { GtkWidget *widget; widget = NULL; switch( m->type ) { case CLASSMODEL_MEMBER_INT: case CLASSMODEL_MEMBER_ENUM: break; case CLASSMODEL_MEMBER_BOOLEAN: widget = build_gtoggle( vb, _( m->user_name ) ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( widget ), G_STRUCT_MEMBER( gboolean, classmodel, m->offset ) ); set_tooltip( widget, _( "Set boolean value here" ) ); break; case CLASSMODEL_MEMBER_DOUBLE: widget = build_glabeltext4( vb, group, _( m->user_name ) ); idialog_init_entry( idlg, widget, _( "Enter a floating point number here" ), "%g", G_STRUCT_MEMBER( double, classmodel, m->offset ) ); break; case CLASSMODEL_MEMBER_STRING: widget = build_glabeltext4( vb, group, _( m->user_name ) ); idialog_init_entry( idlg, widget, _( "Enter a string here" ), "%s", G_STRUCT_MEMBER( char *, classmodel, m->offset ) ); break; case CLASSMODEL_MEMBER_STRING_LIST: case CLASSMODEL_MEMBER_REALVEC_FIXED: case CLASSMODEL_MEMBER_MATRIX: case CLASSMODEL_MEMBER_OPTIONS: case CLASSMODEL_MEMBER_IMAGE: break; default: g_assert( 0 ); } return( widget ); } /* Build the insides of edit. */ static void classmodel_buildedit( iDialog *idlg, GtkWidget *vb, ClassmodelEdit *eds ) { Classmodel *classmodel = eds->classmodel; ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); GtkSizeGroup *group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL ); int i; for( i = 0; i < class->n_members; i++ ) eds->widgets[i] = classmodel_buildedit_member( classmodel, &class->members[i], idlg, vb, group ); gtk_widget_show_all( vb ); g_object_unref( group ); } static void classmodel_edit( GtkWidget *parent, Model *model ) { Classmodel *classmodel = CLASSMODEL( model ); ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); if( class->n_members ) { GtkWidget *idlg; ClassmodelEdit *eds = INEW( NULL, ClassmodelEdit ); eds->classmodel = classmodel; idlg = idialog_new(); /* Expands to eg. "Edit Toggle A1". */ iwindow_set_title( IWINDOW( idlg ), _( "Edit %s %s" ), IOBJECT_GET_CLASS_NAME( model ), IOBJECT( HEAPMODEL( model )->row )->name ); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) classmodel_buildedit, eds, NULL, NULL ); idialog_set_callbacks( IDIALOG( idlg ), iwindow_true_cb, NULL, idialog_free_client, eds ); /* Expands to eg. "Set Toggle". */ idialog_add_ok( IDIALOG( idlg ), classmodel_done_cb, _( "Set %s" ), IOBJECT_GET_CLASS_NAME( classmodel ) ); iwindow_set_parent( IWINDOW( idlg ), parent ); idialog_set_iobject( IDIALOG( idlg ), IOBJECT( classmodel ) ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); } } static gboolean classmodel_save_member( Classmodel *classmodel, ClassmodelMember *m, xmlNode *xthis ) { int i; switch( m->type ) { case CLASSMODEL_MEMBER_INT: case CLASSMODEL_MEMBER_ENUM: if( !set_iprop( xthis, m->save_name, G_STRUCT_MEMBER( int, classmodel, m->offset ) ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_BOOLEAN: if( !set_sprop( xthis, m->save_name, bool_to_char( G_STRUCT_MEMBER( gboolean, classmodel, m->offset ) ) ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_DOUBLE: if( !set_dprop( xthis, m->save_name, G_STRUCT_MEMBER( double, classmodel, m->offset ) ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_STRING: if( !set_sprop( xthis, m->save_name, G_STRUCT_MEMBER( char *, classmodel, m->offset ) ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_STRING_LIST: if( !set_slprop( xthis, m->save_name, G_STRUCT_MEMBER( GSList *, classmodel, m->offset ) ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_REALVEC_FIXED: for( i = 0; i < m->extent; i++ ) { char buf[256]; im_snprintf( buf, 256, "%s%d", m->save_name, i ); if( !set_dprop( xthis, buf, (&G_STRUCT_MEMBER( double, classmodel, m->offset ))[i] ) ) return( FALSE ); } break; case CLASSMODEL_MEMBER_MATRIX: { MatrixValue *value = &G_STRUCT_MEMBER( MatrixValue, classmodel, m->offset ); const int n = value->width * value->height; if( !set_dlprop( xthis, "value", value->coeff, n ) || !set_iprop( xthis, "width", value->width ) || !set_iprop( xthis, "height", value->height ) ) return( FALSE ); break; } case CLASSMODEL_MEMBER_OPTIONS: for( i = 0; i < m->extent; i++ ) { ClassmodelMember *options = (ClassmodelMember *) m->details; if( !classmodel_save_member( classmodel, &options[i], xthis ) ) return( FALSE ); } break; case CLASSMODEL_MEMBER_IMAGE: break; default: g_assert( 0 ); } return( TRUE ); } static xmlNode * classmodel_save( Model *model, xmlNode *xnode ) { Classmodel *classmodel = CLASSMODEL( model ); ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); xmlNode *xthis; int i; #ifdef DEBUG printf( "classmodel_save: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( "\n" ); #endif /*DEBUG*/ if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( classmodel->edited ) for( i = 0; i < class->n_members; i++ ) if( !classmodel_save_member( classmodel, &class->members[i], xthis ) ) return( NULL ); return( xthis ); } static gboolean classmodel_load_member( Classmodel *classmodel, ClassmodelMember *m, xmlNode *xthis ) { char buf[MAX_STRSIZE]; gboolean found; int i; found = FALSE; switch( m->type ) { case CLASSMODEL_MEMBER_INT: if( get_iprop( xthis, m->save_name, &G_STRUCT_MEMBER( int, classmodel, m->offset ) ) ) found = TRUE; break; case CLASSMODEL_MEMBER_ENUM: { int v; if( get_iprop( xthis, m->save_name, &v ) ) { v = IM_CLIP( 0, v, m->extent ); G_STRUCT_MEMBER( int, classmodel, m->offset ) = v; found = TRUE; } break; } case CLASSMODEL_MEMBER_BOOLEAN: if( get_bprop( xthis, m->save_name, &G_STRUCT_MEMBER( gboolean, classmodel, m->offset ) ) ) found = TRUE; break; case CLASSMODEL_MEMBER_DOUBLE: if( get_dprop( xthis, m->save_name, &G_STRUCT_MEMBER( double, classmodel, m->offset ) ) ) found = TRUE; break; case CLASSMODEL_MEMBER_STRING: if( get_sprop( xthis, m->save_name, buf, MAX_STRSIZE ) ) { IM_SETSTR( G_STRUCT_MEMBER( char *, classmodel, m->offset ), buf ); found = TRUE; } /* Nasty: before member automation, we used to always * save/load caption, as a member of model. Now caption is * only present if the class has it as a automated member. * Plus some classes used to not support captions (eg. Scale). * So: caption can be missing, even if it should be there. Set * a fall-back value. */ if( !found && strcmp( m->save_name, "caption" ) == 0 ) { IM_SETSTR( G_STRUCT_MEMBER( char *, classmodel, m->offset ), "" ); found = TRUE; } break; case CLASSMODEL_MEMBER_STRING_LIST: { GSList *slist; GSList **member = &G_STRUCT_MEMBER( GSList *, classmodel, m->offset ); if( get_slprop( xthis, m->member_name, &slist ) ) { IM_FREEF( slist_free_all, *member ); *member = slist; found = TRUE; } break; } case CLASSMODEL_MEMBER_REALVEC_FIXED: for( i = 0; i < m->extent; i++ ) { im_snprintf( buf, MAX_STRSIZE, "%s%d", m->save_name, i ); if( get_dprop( xthis, buf, &((&G_STRUCT_MEMBER( double, classmodel, m->offset ))[i]) ) ) found = TRUE; } break; case CLASSMODEL_MEMBER_MATRIX: { MatrixValue *value = &G_STRUCT_MEMBER( MatrixValue, classmodel, m->offset ); if( get_dlprop( xthis, "value", &value->coeff ) && get_iprop( xthis, "width", &value->width ) && get_iprop( xthis, "height", &value->height ) ) found = TRUE; break; } case CLASSMODEL_MEMBER_OPTIONS: for( i = 0; i < m->extent; i++ ) { ClassmodelMember *options = (ClassmodelMember *) m->details; if( !classmodel_load_member( classmodel, &options[i], xthis ) ) return( FALSE ); } break; case CLASSMODEL_MEMBER_IMAGE: break; default: g_assert( 0 ); } return( found ); } static gboolean classmodel_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xthis ) { Classmodel *classmodel = CLASSMODEL( model ); ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); #ifdef DEBUG printf( "classmodel_load: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( "\n" ); #endif /*DEBUG*/ /* Only for classes with member automation. */ if( class->n_members ) { gboolean all_found; int i; /* Before we mark the graphic as edited, insist all * members have values set. This can be important in * compatibility mode, where the old nip might not have * supported all the members we have. */ all_found = TRUE; for( i = 0; i < class->n_members; i++ ) all_found &= classmodel_load_member( classmodel, &class->members[i], xthis ); if( all_found ) classmodel_set_edited( CLASSMODEL( model ), TRUE ); } return( MODEL_CLASS( parent_class )->load( model, state, parent, xthis ) ); } static gboolean classmodel_get_item( Classmodel *classmodel, ClassmodelMember *m, PElement *value ); static void * classmodel_parse_option( const char *key, PElement *value, Classmodel *classmodel, ClassmodelMember *m ) { ClassmodelMember *options = (ClassmodelMember *) m->details; int noptions = m->extent; int i; for( i = 0; i < noptions; i++ ) if( strcmp( key, options[i].member_name ) == 0 ) break; if( i == noptions ) { error_top( _( "Unknown option." ) ); error_sub( _( "Option \"%s\" not known." ), key ); return( value ); } if( !classmodel_get_item( classmodel, &options[i], value ) ) return( value ); return( NULL ); } static gboolean classmodel_get_item( Classmodel *classmodel, ClassmodelMember *m, PElement *value ) { char buf[MAX_STRSIZE]; double vec[3]; int l; int i; double d; switch( m->type ) { case CLASSMODEL_MEMBER_INT: if( !heap_get_real( value, &d ) ) return( FALSE ); G_STRUCT_MEMBER( int, classmodel, m->offset ) = d; break; case CLASSMODEL_MEMBER_ENUM: if( !heap_get_real( value, &d ) ) return( FALSE ); d = IM_CLIP( 0, d, m->extent ); G_STRUCT_MEMBER( int, classmodel, m->offset ) = d; break; case CLASSMODEL_MEMBER_BOOLEAN: if( !heap_get_bool( value, &G_STRUCT_MEMBER( gboolean, classmodel, m->offset ) ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_DOUBLE: if( !heap_get_real( value, &G_STRUCT_MEMBER( double, classmodel, m->offset ) ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_STRING: if( !heap_get_string( value, buf, MAX_STRSIZE ) ) return( FALSE ); IM_SETSTR( G_STRUCT_MEMBER( char *, classmodel, m->offset ), buf ); break; case CLASSMODEL_MEMBER_STRING_LIST: { GSList *slist; GSList **member = &G_STRUCT_MEMBER( GSList *, classmodel, m->offset ); if( !heap_get_lstring( value, &slist ) ) return( FALSE ); IM_FREEF( slist_free_all, *member ); *member = slist; break; } case CLASSMODEL_MEMBER_REALVEC_FIXED: g_assert( m->extent < 4 ); if( (l = heap_get_realvec( value, vec, m->extent )) < 0 ) return( FALSE ); if( l != m->extent ) { error_top( _( "Bad value." ) ); error_sub( _( "%d band value only" ), m->extent ); return( FALSE ); } for( i = 0; i < m->extent; i++ ) (&G_STRUCT_MEMBER( double, classmodel, m->offset ))[i] = vec[i]; break; case CLASSMODEL_MEMBER_MATRIX: { MatrixValue *matrix = &G_STRUCT_MEMBER( MatrixValue, classmodel, m->offset ); int w, h; if( !heap_get_matrix_size( value, &w, &h ) || !matrix_value_resize( matrix, w, h ) || !heap_get_matrix( value, matrix->coeff, matrix->width * matrix->height, &w, &h ) ) return( FALSE ); break; } case CLASSMODEL_MEMBER_OPTIONS: /* If there are optional fields, we have to have a reset * method for clearing the ones we don't use. */ g_assert( CLASSMODEL_GET_CLASS( classmodel )->reset ); if( heap_map_dict( value, (heap_map_dict_fn) classmodel_parse_option, classmodel, m ) ) return( FALSE ); break; case CLASSMODEL_MEMBER_IMAGE: { ImageValue *image = &G_STRUCT_MEMBER( ImageValue, classmodel, m->offset ); Imageinfo *ii; g_assert( image->classmodel == classmodel ); if( !heap_get_image( value, &ii ) ) return( FALSE ); image_value_set( image, ii ); break; } default: g_assert( 0 ); } return( TRUE ); } static gboolean classmodel_update_model_member( Classmodel *classmodel, ClassmodelMember *m, PElement *root ) { PElement value; if( !class_get_member( root, m->member_name, NULL, &value ) ) return( FALSE ); #ifdef DEBUG printf( "classmodel_update_model_member: setting %s = ", m->member_name ); pgraph( &value ); #endif /*DEBUG*/ if( !classmodel_get_item( classmodel, m, &value ) ) return( FALSE ); return( TRUE ); } /* Update all members from the heap. Also used from graph_export_image. */ gboolean classmodel_update_members( Classmodel *classmodel, PElement *root ) { ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); int i; for( i = 0; i < class->n_members; i++ ) if( !classmodel_update_model_member( classmodel, &class->members[i], root ) ) return( FALSE ); if( class->class_get && !class->class_get( classmodel, root ) ) return( FALSE ); return( TRUE ); } static void * classmodel_update_model( Heapmodel *heapmodel ) { Classmodel *classmodel = CLASSMODEL( heapmodel ); ClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel ); #ifdef DEBUG printf( "classmodel_update_model: " ); row_name_print( heapmodel->row ); printf( "\n" ); #endif /*DEBUG*/ /* If necessary, reset model to default. */ if( class->reset ) class->reset( classmodel ); if( heapmodel->row && heapmodel->row->expr ) { Expr *expr = heapmodel->row->expr; if( !heapmodel->modified ) if( !classmodel_update_members( classmodel, &expr->root ) ) return( classmodel ); } return( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ); } static void * classmodel_update_heap( Heapmodel *heapmodel ) { Classmodel *classmodel = CLASSMODEL( heapmodel ); #ifdef DEBUG printf( "classmodel_update_heap: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( "\n" ); #endif /*DEBUG*/ /* Nasty: classmodel_class_instance_new() can (indirectly) destroy us. * Wrap a _ref()/_unref() pair around it to make sure we stay alive. */ g_object_ref( G_OBJECT( heapmodel ) ); /* Build a new instance from the model. */ if( !classmodel_class_instance_new( classmodel ) ) { g_object_unref( G_OBJECT( heapmodel ) ); return( heapmodel ); } if( HEAPMODEL_CLASS( parent_class )->update_heap( heapmodel ) ) { g_object_unref( G_OBJECT( heapmodel ) ); return( heapmodel ); } g_object_unref( G_OBJECT( heapmodel ) ); return( NULL ); } static void * classmodel_clear_edited( Heapmodel *heapmodel ) { Classmodel *classmodel = CLASSMODEL( heapmodel ); classmodel_set_edited( classmodel, FALSE ); return( HEAPMODEL_CLASS( parent_class )->clear_edited( heapmodel ) ); } static gboolean classmodel_real_class_get( Classmodel *classmodel, PElement *root ) { return( TRUE ); } static void classmodel_class_init( ClassmodelClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Init methods. */ gobject_class->dispose = classmodel_dispose; iobject_class->info = classmodel_info; icontainer_class->parent_add = classmodel_parent_add; model_class->edit = classmodel_edit; model_class->save = classmodel_save; model_class->load = classmodel_load; heapmodel_class->update_model = classmodel_update_model; heapmodel_class->update_heap = classmodel_update_heap; heapmodel_class->clear_edited = classmodel_clear_edited; classmodel_class->get_instance = NULL; classmodel_class->class_get = classmodel_real_class_get; classmodel_class->class_new = NULL; classmodel_class->graphic_save = NULL; classmodel_class->graphic_replace = NULL; classmodel_class->filetype = filesel_type_any; classmodel_class->filetype_pref = NULL; classmodel_class->members = NULL; classmodel_class->n_members = 0; } static void classmodel_init( Classmodel *classmodel ) { Model *model = MODEL( classmodel ); model->display = FALSE; classmodel->edited = FALSE; classmodel->iimages = NULL; classmodel->views = NULL; classmodel->filename = NULL; } GType classmodel_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ClassmodelClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) classmodel_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Classmodel ), 32, /* n_preallocs */ (GInstanceInitFunc) classmodel_init, }; type = g_type_register_static( TYPE_HEAPMODEL, "Classmodel", &info, 0 ); } return( type ); } void classmodel_set_edited( Classmodel *classmodel, gboolean edited ) { if( classmodel->edited != edited ) { #ifdef DEBUG printf( "classmodel_set_edited: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( " %s\n", bool_to_char( edited ) ); #endif /*DEBUG*/ classmodel->edited = edited; iobject_changed( IOBJECT( classmodel ) ); if( HEAPMODEL( classmodel )->row && HEAPMODEL( classmodel )->row->expr ) expr_dirty( HEAPMODEL( classmodel )->row->expr, link_serial_new() ); } /* Mark eds for application. */ if( edited ) heapmodel_set_modified( HEAPMODEL( classmodel ), TRUE ); } /* The model has changed: mark for recomp. */ void classmodel_update( Classmodel *classmodel ) { Row *row = HEAPMODEL( classmodel )->row; /* Eg. for no symol on load. */ if( !row->expr ) return; #ifdef DEBUG printf( "classmodel_update: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( "\n" ); #endif /*DEBUG*/ /* classmodel_update_heap() will rebuild us on recomp. */ classmodel_set_edited( classmodel, TRUE ); expr_dirty( row->expr, link_serial_new() ); workspace_set_modified( row->ws, TRUE ); } /* Make a new classmodel subtype (eg. TYPE_PATHNAME) and link it on. */ Classmodel * classmodel_new_classmodel( GType type, Rhs *rhs ) { Classmodel *classmodel; classmodel = g_object_new( type, NULL ); icontainer_child_add( ICONTAINER( rhs ), ICONTAINER( classmodel ), -1 ); return( classmodel ); } nip2-8.7.1/src/path.h0000644000175000017500000000326313351443023011216 00000000000000/* Declarations supporting search.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ extern GSList *path_search_default; extern GSList *path_start_default; extern const char *path_tmp_default; /* Type of path_map functions. */ typedef void *(*path_map_fn)( const char *, void *, void *, void * ); void path_rewrite_free_all( void ); void path_rewrite_add( const char *old, const char *new, gboolean lock ); void path_rewrite( char *buf ); void path_compact( char *path ); void path_expand( char *path ); char *path_rewrite_file( const char *patt ); GSList *path_parse( const char *path ); char *path_unparse( GSList *path ); void path_free2( GSList *path ); void *path_map( GSList *path, const char *patt, path_map_fn fn, void *a ); void *path_map_dir( const char *dir, const char *patt, path_map_fn fn, void *a ); char *path_find_file( const char *patt ); void path_init( void ); nip2-8.7.1/src/heapmodel.c0000644000175000017500000001462513351443023012217 00000000000000/* base class for models of heap classes */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ModelClass *parent_class = NULL; void * heapmodel_new_heap( Heapmodel *heapmodel, PElement *root ) { HeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel ); if( heapmodel_class->new_heap ) { void *res; res = heapmodel_class->new_heap( heapmodel, root ); return( res ); } return( NULL ); } void * heapmodel_update_model( Heapmodel *heapmodel ) { HeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel ); #ifdef DEBUG printf( "heapmodel_update_model: %s ", G_OBJECT_TYPE_NAME( heapmodel ) ); row_name_print( heapmodel->row ); printf( " modified = %d\n", heapmodel->modified ); #endif /*DEBUG*/ if( heapmodel_class->update_model && !heapmodel->modified ) { void *res; res = heapmodel_class->update_model( heapmodel ); return( res ); } return( NULL ); } void * heapmodel_update_heap( Heapmodel *heapmodel ) { HeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel ); if( heapmodel_class->update_heap && heapmodel->modified ) { void *res; res = heapmodel_class->update_heap( heapmodel ); return( res ); } return( NULL ); } void * heapmodel_clear_edited( Heapmodel *heapmodel ) { HeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel ); if( heapmodel_class->clear_edited ) return( heapmodel_class->clear_edited( heapmodel ) ); return( NULL ); } static Rhs * heapmodel_get_rhs( Heapmodel *heapmodel ) { iContainer *p; /* Search for the enclosing RHS ... may not be one if (eg.) this is a * top-level row. */ for( p = ICONTAINER( heapmodel )->parent; p; p = p->parent ) if( IS_RHS( p ) ) return( RHS( p ) ); return( NULL ); } static Row * heapmodel_get_row( Heapmodel *heapmodel ) { Rhs *rhs; if( IS_RHS( heapmodel ) ) return( ROW( ICONTAINER( heapmodel )->parent ) ); else if( (rhs = heapmodel_get_rhs( heapmodel )) ) return( HEAPMODEL( rhs )->row ); else return( NULL ); } static void heapmodel_parent_add( iContainer *child ) { Heapmodel *heapmodel = HEAPMODEL( child ); g_assert( IS_HEAPMODEL( child->parent ) || IS_FILEMODEL( child->parent ) ); ICONTAINER_CLASS( parent_class )->parent_add( child ); /* Update our context. */ heapmodel->rhs = heapmodel_get_rhs( heapmodel ); heapmodel->row = heapmodel_get_row( heapmodel ); } static void * heapmodel_real_new_heap( Heapmodel *heapmodel, PElement *root ) { iobject_changed( IOBJECT( heapmodel ) ); return( NULL ); } static void * heapmodel_real_update_model( Heapmodel *heapmodel ) { iobject_changed( IOBJECT( heapmodel ) ); return( NULL ); } static void * heapmodel_real_update_heap( Heapmodel *heapmodel ) { g_assert( heapmodel->modified ); heapmodel_set_modified( heapmodel, FALSE ); return( NULL ); } static void * heapmodel_real_clear_edited( Heapmodel *heapmodel ) { return( NULL ); } static void heapmodel_class_init( HeapmodelClass *class ) { HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; parent_class = g_type_class_peek_parent( class ); /* Init methods. */ icontainer_class->parent_add = heapmodel_parent_add; heapmodel_class->new_heap = heapmodel_real_new_heap; heapmodel_class->update_heap = heapmodel_real_update_heap; heapmodel_class->update_model = heapmodel_real_update_model; heapmodel_class->clear_edited = heapmodel_real_clear_edited; } static void heapmodel_init( Heapmodel *heapmodel ) { heapmodel->row = NULL; heapmodel->rhs = NULL; heapmodel->modified = FALSE; } GType heapmodel_get_type( void ) { static GType heapmodel_type = 0; if( !heapmodel_type ) { static const GTypeInfo info = { sizeof( HeapmodelClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) heapmodel_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Heapmodel ), 32, /* n_preallocs */ (GInstanceInitFunc) heapmodel_init, }; heapmodel_type = g_type_register_static( TYPE_MODEL, "Heapmodel", &info, 0 ); } return( heapmodel_type ); } void heapmodel_set_modified( Heapmodel *heapmodel, gboolean modified ) { if( heapmodel->modified != modified ) { #ifdef DEBUG { HeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel ); printf( "heapmodel_set_modified: %s::", G_OBJECT_CLASS_NAME( heapmodel_class ) ); row_name_print( heapmodel->row ); printf( " %s\n", bool_to_char( modified ) ); } #endif /*DEBUG*/ heapmodel->modified = modified; iobject_changed( IOBJECT( heapmodel ) ); } } /* Generate a descriptive name for a heapmodel. Used for captions. */ gboolean heapmodel_name( Heapmodel *heapmodel, VipsBuf *buf ) { Row *row = heapmodel->row; Expr *expr; Symbol *sym; Toolitem *toolitem; if( !row || !(expr = row->expr) || !PEISCLASS( &expr->root ) ) return( FALSE ); sym = PEGETCLASSCOMPILE( &expr->root )->sym; /* If this is an action member we should be able to look up * it's sym and get a descriptive label. */ if( (toolitem = toolitem_lookup( row->ws->kitg, sym )) ) vips_buf_appends( buf, toolitem->name ); else symbol_qualified_name_relative( row->ws->sym, sym, buf ); return( TRUE ); } /* Print the value member to a buf. */ gboolean heapmodel_value( Heapmodel *heapmodel, VipsBuf *buf ) { Expr *expr; PElement value; if( !heapmodel->row || !(expr = heapmodel->row->expr) || expr->err || expr->sym->dirty || !class_get_member( &expr->root, MEMBER_VALUE, NULL, &value ) ) return( FALSE ); itext_value( reduce_context, buf, &value ); return( TRUE ); } nip2-8.7.1/src/optionview.c0000644000175000017500000001432413351443023012460 00000000000000/* run the display for a option in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; /* Copy a gslist of strings. */ static GSList * lstring_copy( GSList *lstring ) { GSList *new; GSList *p; new = NULL; for( p = lstring; p; p = p->next ) new = g_slist_prepend( new, g_strdup( (const char *) p->data ) ); new = g_slist_reverse( new ); return( new ); } /* Are two lstrings equal? */ static gboolean lstring_equal( GSList *a, GSList *b ) { for( ; a && b; a = a->next, b = b->next ) if( strcmp( (const char *) a->data, (const char *) b->data ) != 0 ) return( FALSE ); if( a || b ) return( FALSE ); return( TRUE ); } static void optionview_destroy( GtkObject *object ) { Optionview *optionview; g_return_if_fail( object != NULL ); g_return_if_fail( IS_OPTIONVIEW( object ) ); optionview = OPTIONVIEW( object ); /* My instance destroy stuff. */ IM_FREEF( slist_free_all, optionview->labels ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void optionview_link( View *view, Model *model, View *parent ) { Optionview *optionview = OPTIONVIEW( view ); VIEW_CLASS( parent_class )->link( view, model, parent ); if( GRAPHICVIEW( view )->sview ) gtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group, optionview->label ); } /* Change to a optionview widget ... update the model. */ static void optionview_change_cb( GtkWidget *wid, Optionview *optionview ) { Option *option = OPTION( VOBJECT( optionview )->iobject ); Classmodel *classmodel = CLASSMODEL( option ); const int nvalue = gtk_combo_box_get_active( GTK_COMBO_BOX( optionview->options ) ); if( option->value != nvalue ) { option->value = nvalue; classmodel_update( classmodel ); symbol_recalculate_all(); } } static gboolean optionview_scroll_cb( GtkWidget *wid, GdkEvent *event, Optionview *optionview ) { /* Stop any other scroll handlers running. We don't want the scroll * wheel to change widgets while we're moving. */ return( TRUE ); } static void optionview_refresh( vObject *vobject ) { Optionview *optionview = OPTIONVIEW( vobject ); Option *option = OPTION( VOBJECT( optionview )->iobject ); GSList *p; int i; #ifdef DEBUG printf( "optionview_refresh: " ); row_name_print( HEAPMODEL( option )->row ); printf( "\n" ); #endif /*DEBUG*/ /* Only rebuild the menu if there's been a change. */ if( !lstring_equal( optionview->labels, option->labels ) ) { /* If the menu is currently up, we can get strange things * happening if we destroy it. */ if( optionview->options ) gtk_combo_box_popdown( GTK_COMBO_BOX( optionview->options ) ); IM_FREEF( gtk_widget_destroy, optionview->options ); optionview->options = gtk_combo_box_new_text(); for( p = option->labels, i = 0; p; p = p->next, i++ ) gtk_combo_box_append_text( GTK_COMBO_BOX( optionview->options ), (const char *) p->data ); gtk_box_pack_start( GTK_BOX( optionview->hbox ), optionview->options, TRUE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT( optionview->options ), "changed", GTK_SIGNAL_FUNC( optionview_change_cb ), optionview ); gtk_widget_show( optionview->options ); IM_FREEF( slist_free_all, optionview->labels ); optionview->labels = lstring_copy( option->labels ); g_signal_connect( GTK_OBJECT( optionview->options ), "scroll-event", GTK_SIGNAL_FUNC( optionview_scroll_cb ), optionview ); } if( optionview->options ) { gtk_signal_handler_block_by_data( GTK_OBJECT( optionview->options ), optionview ); gtk_combo_box_set_active( GTK_COMBO_BOX( optionview->options ), option->value ); gtk_signal_handler_unblock_by_data( GTK_OBJECT( optionview->options ), optionview ); } set_glabel( optionview->label, _( "%s:" ), IOBJECT( option )->caption ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void optionview_class_init( OptionviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = optionview_destroy; /* Create signals. */ /* Init methods. */ vobject_class->refresh = optionview_refresh; view_class->link = optionview_link; } static void optionview_init( Optionview *optionview ) { optionview->hbox = gtk_hbox_new( FALSE, 12 ); gtk_box_pack_start( GTK_BOX( optionview ), optionview->hbox, TRUE, FALSE, 0 ); optionview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( optionview->label ), 0, 0.5 ); gtk_box_pack_start( GTK_BOX( optionview->hbox ), optionview->label, FALSE, FALSE, 2 ); optionview->options = NULL; optionview->labels = NULL; gtk_widget_show_all( optionview->hbox ); } GtkType optionview_get_type( void ) { static GtkType optionview_type = 0; if( !optionview_type ) { static const GtkTypeInfo sinfo = { "Optionview", sizeof( Optionview ), sizeof( OptionviewClass ), (GtkClassInitFunc) optionview_class_init, (GtkObjectInitFunc) optionview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; optionview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &sinfo ); } return( optionview_type ); } View * optionview_new( void ) { Optionview *optionview = gtk_type_new( TYPE_OPTIONVIEW ); return( VIEW( optionview ) ); } nip2-8.7.1/src/toggle.h0000644000175000017500000000313513351443023011541 00000000000000/* a toggle button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TOGGLE (toggle_get_type()) #define TOGGLE( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_TOGGLE, Toggle )) #define TOGGLE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_TOGGLE, ToggleClass)) #define IS_TOGGLE( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_TOGGLE )) #define IS_TOGGLE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_TOGGLE )) #define TOGGLE_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_TOGGLE, ToggleClass )) typedef struct _Toggle { Classmodel parent_class; /* My instance vars. */ gboolean value; } Toggle; typedef struct _ToggleClass { ClassmodelClass parent_class; /* My methods. */ } ToggleClass; GType toggle_get_type( void ); nip2-8.7.1/src/class.c0000644000175000017500000006761513351443023011375 00000000000000/* Class functions ... really part of heap.c, but split out here to make it * more manageable. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG_MEMBER #define DEBUG_VERBOSE #define DEBUG #define DEBUG_BUILD */ static gboolean class_is_class( PElement *instance ) { if( !PEISCLASS( instance ) ) { char txt[50]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( !itext_value( reduce_context, &buf, instance ) ) return( FALSE ); error_top( _( "Bad argument." ) ); error_sub( _( "Object %s is not a class." ), vips_buf_all( &buf ) ); return( FALSE ); } return( TRUE ); } Compile * class_get_compile( PElement *instance ) { if( !class_is_class( instance ) ) return( NULL ); return( PEGETCLASSCOMPILE( instance ) ); } /* Look up "super" in a class ... try to do it quickly. */ gboolean class_get_super( PElement *instance, PElement *out ) { Compile *compile; if( !(compile = class_get_compile( instance )) ) return( FALSE ); g_assert( compile->super ); return( class_get_symbol( instance, compile->super, out ) ); } void * class_map( PElement *instance, class_map_fn fn, void *a, void *b ) { PElement member; HeapNode *p; if( !PEISCLASS( instance ) ) return( NULL ); /* Loop over the instance member list. */ PEGETCLASSMEMBER( &member, instance ); if( !PEISELIST( &member ) ) for( p = PEGETVAL( &member ); p; p = GETRIGHT( p ) ) { HeapNode *hn; PElement s, v; Symbol *sym; void *result; /* Get the sym/value pair, get the sym. */ hn = GETLEFT( p ); PEPOINTLEFT( hn, &s ); PEPOINTRIGHT( hn, &v ); sym = PEGETSYMREF( &s ); if( (result = fn( sym, &v, a, b )) ) return( result ); } return( NULL ); } /* Look up a member in a class instance by name. If lookup fails in this * instance, try the superclass. Don't search secrets. Point sym and value * at the symbol we found and its value. sym can be NULL for no result * required. */ gboolean class_get_member( PElement *instance, const char *name, Symbol **sym_out, PElement *out ) { PElement member; PElement super; HeapNode *p; #ifdef DEBUG_MEMBER printf( "class_get_member: looking up \"%s\" in class ", name ); pgraph( instance ); #endif /*DEBUG_MEMBER*/ if( !class_is_class( instance ) ) return( FALSE ); /* Search this instance member list. */ PEGETCLASSMEMBER( &member, instance ); if( !PEISELIST( &member ) ) for( p = PEGETVAL( &member ); p; p = GETRIGHT( p ) ) { HeapNode *hn; PElement s; Symbol *sym; /* Get the sym/value pair, get the sym. */ hn = GETLEFT( p ); PEPOINTLEFT( hn, &s ); /* Match? */ sym = PEGETSYMREF( &s ); if( strcmp( IOBJECT( sym )->name, name ) == 0 ) { /* Found! */ PEPOINTRIGHT( hn, out ); if( sym_out ) *sym_out = sym; #ifdef DEBUG_MEMBER printf( "class_get_member: found: " ); pgraph( out ); #endif /*DEBUG_MEMBER*/ return( TRUE ); } } /* Nope ... try the superclass. */ if( !class_get_super( instance, &super ) || !PEISELIST( &super ) ) { /* FIXME ... gcc 2.95.2 gets this wrong, tries to eliminate the tail recursion with -O2 and makes bad code ... guess how long that took to find ... put this back at some point return( class_get_member( &super, name, sym_out, value ) ); */ gboolean result = class_get_member( &super, name, sym_out, out ); return( result ); } error_top( _( "Member not found." ) ); error_sub( _( "Member \"%s\" not found in class \"%s\"." ), name, IOBJECT( PEGETCLASSCOMPILE( instance )->sym )->name ); return( FALSE ); } /* Look up a symbol in a class. Write to out, or FALSE for not found. Look up * by symbol pointer. Search secrets as well. Try the superclass if lookup * fails. */ gboolean class_get_symbol( PElement *instance, Symbol *sym, PElement *out ) { HeapNode *p; PElement secret; PElement super; #ifdef DEBUG_MEMBER printf( "class_get_symbol: looking up " ); symbol_name_print( sym ); printf( "in class " ); pgraph( instance ); #endif /*DEBUG_MEMBER*/ if( !class_is_class( instance ) ) return( FALSE ); PEGETCLASSSECRET( &secret, instance ); if( PEISNODE( &secret ) ) for( p = PEGETVAL( &secret ); p; p = GETRIGHT( p ) ) { PElement s; HeapNode *hn; /* Get the sym/value pair, get the sym. */ hn = GETLEFT( p ); PEPOINTLEFT( hn, &s ); /* Match? */ if( PEGETSYMREF( &s ) == sym ) { /* Found! */ PEPOINTRIGHT( hn, out ); #ifdef DEBUG_MEMBER printf( "class_get_symbol: found: " ); pgraph( out ); #endif /*DEBUG_MEMBER*/ return( TRUE ); } } /* Nope ... try the superclass. */ if( !class_get_super( instance, &super ) || !PEISELIST( &super ) ) { /* FIXME ... gcc 2.95.2 gets this wrong, tries to eliminate the tail recursion with -O2 and makes bad code ... guess how long that took to find ... put this back at some point return( class_get_member( &super, name, out ) ); */ gboolean result = class_get_symbol( &super, sym, out ); return( result ); } return( FALSE ); } /* Search back up the inheritance tree for an exact instance of this * class. */ gboolean class_get_exact( PElement *instance, const char *name, PElement *out ) { PElement pe; pe = *instance; while( !reduce_is_instanceof_exact( reduce_context, name, &pe ) ) { if( !class_get_super( &pe, &pe ) || PEISELIST( &pe ) ) return( FALSE ); } *out = pe; return( TRUE ); } /* Stuff we need for class build. */ typedef struct { Heap *heap; /* Heap to build on */ Symbol *sym; /* Sym we are local to */ PElement *arg; /* Args to constructor */ PElement *this; /* Base of instance we are building */ int i; /* Index in arg list */ Compile *compile; /* Compile for our class */ } ClassBuildInfo; /* Member sym of class pbi->sym needs secret as an argument ... add it! */ static gboolean class_member_secret( ClassBuildInfo *pbi, Symbol *sym, GSList *secret, PElement *out ) { Symbol *ssym; Heap *heap = pbi->heap; HeapNode *apl; if( !secret ) return( TRUE ); ssym = SYMBOL( secret->data ); /* Make function application for this member. */ if( NEWNODE( heap, apl ) ) return( FALSE ); apl->type = TAG_APPL; PEPUTLEFT( apl, out ); /* Is the secret "this"? Easy. */ if( ssym == pbi->sym->expr->compile->this ) { PEPUTRIGHT( apl, pbi->this ); } else { /* Look up ssym in pbi->sym's secrets ... should be there * somewhere. Use it's index to find the pbi->arg[] we need. */ int pos = g_slist_index( pbi->sym->expr->compile->secret, ssym ); /* FIXME ... may not be if we've regenerated one of these * stupid things :-( change this so we always go through * 'this'. */ if( pos < 0 || pos >= pbi->sym->expr->compile->nsecret ) { error_top( _( "No such secret." ) ); error_sub( _( "Editing local classes which reference " "non-local objects is a bit broken at the " "moment :-(" ) ); return( FALSE ); } PEPUTRIGHT( apl, &pbi->arg[pbi->sym->expr->compile->nsecret - pos - 1] ); } PEPUTP( out, ELEMENT_NODE, apl ); #ifdef DEBUG_VERBOSE { PElement p1; char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); PEPOINTRIGHT( apl, &p1 ); graph_pelement( pbi->heap, &buf, &p1, TRUE ); printf( "class_member_secret: secret arg " ); symbol_name_print( ssym ); printf( "to member " ); symbol_name_print( sym ); printf( "= %s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_VERBOSE*/ return( class_member_secret( pbi, sym, secret->next, out ) ); } /* Add a member to a class. */ static void * add_class_member( Symbol *sym, ClassBuildInfo *pbi, PElement *out ) { Heap *heap = pbi->heap; HeapNode *base, *sv; PElement v; /* Is this something that should be part of a class. */ if( sym->type != SYM_VALUE ) return( NULL ); /* Make new class-local-list element for this local. */ if( NEWNODE( heap, base ) ) return( sym ); base->type = TAG_CONS; PPUTLEFT( base, ELEMENT_ELIST, NULL ); PEPUTRIGHT( base, out ); PEPUTP( out, ELEMENT_NODE, base ); /* Make sym/value pair for this local. */ if( NEWNODE( heap, sv ) ) return( sym ); sv->type = TAG_CONS; PPUT( sv, ELEMENT_SYMREF, sym, ELEMENT_SYMBOL, sym ); PPUTLEFT( base, ELEMENT_NODE, sv ); /* Build value ... apply args to the symbol. */ PEPOINTRIGHT( sv, &v ); if( !class_member_secret( pbi, sym, sym->expr->compile->secret, &v ) ) return( sym ); #ifdef DEBUG_VERBOSE { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, &v, TRUE ); printf( "add_class_member: member \"%s\" of class \"%s\" = %s\n", IOBJECT( sym )->name, IOBJECT( pbi->sym )->name, vips_buf_all( &buf ) ); } #endif /*DEBUG_VERBOSE*/ return( NULL ); } /* Add a symbol/value pair to a class. */ static gboolean add_class_svpair( ClassBuildInfo *pbi, Symbol *sym, PElement *val, PElement *out ) { Heap *heap = pbi->heap; HeapNode *base, *sv; #ifdef DEBUG_VERBOSE { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, val, TRUE ); printf( "add_class_svpair: adding parameter \"%s\" to class " "\"%s\" = %s\n", IOBJECT( sym )->name, IOBJECT( pbi->sym )->name, vips_buf_all( &buf ) ); } #endif /*DEBUG_VERBOSE*/ /* Make new class-local-list element for this parameter. */ if( NEWNODE( heap, base ) ) return( FALSE ); base->type = TAG_CONS; PPUTLEFT( base, ELEMENT_ELIST, NULL ); PEPUTRIGHT( base, out ); PEPUTP( out, ELEMENT_NODE, base ); /* Make sym/value pair for this parameter. */ if( NEWNODE( heap, sv ) ) return( FALSE ); sv->type = TAG_CONS; PPUTLEFT( sv, ELEMENT_SYMREF, sym ) PEPUTRIGHT( sv, val ); PPUTLEFT( base, ELEMENT_NODE, sv ); return( TRUE ); } /* Add a parameter (secret or real) to a class. */ static void * add_class_parameter( Symbol *sym, ClassBuildInfo *pbi, PElement *out ) { /* Add this symbol/value pair. */ if( !add_class_svpair( pbi, sym, &pbi->arg[pbi->i], out ) ) return( sym ); /* Move arg index on. */ pbi->i += 1; return( NULL ); } /* Add the name member ... build the name string carefully. */ static void * class_new_single_name( Heap *heap, PElement *pe, ClassBuildInfo *pbi, PElement *instance ) { Symbol *snm = compile_lookup( pbi->compile, MEMBER_NAME ); char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); /* Make class name string. */ symbol_qualified_name( pbi->sym, &buf ); PEPUTP( pe, ELEMENT_ELIST, NULL ); if( !heap_managedstring_new( heap, vips_buf_all( &buf ), pe ) ) return( heap ); /* Add as a member. */ if( !add_class_svpair( pbi, snm, pe, instance ) ) return( heap ); return( NULL ); } /* Make a single level class instance ... fn below then loops over a class * hierarchy with this. */ static gboolean class_new_single( Heap *heap, Compile *compile, PElement *arg, PElement *this, PElement *out ) { Symbol *sym = compile->sym; Symbol *sths = compile->this; HeapNode *base, *sm; PElement p1; ClassBuildInfo pbi; #ifdef DEBUG { int i; printf( "class_new_single: starting for " ); symbol_name_print( sym ); printf( "%d secrets, %d params\n", compile->nsecret, compile->nparam ); for( i = 0; i < compile->nsecret; i++ ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, &arg[i], TRUE ); printf( "\tsecret %2d = %s\n", i, vips_buf_all( &buf ) ); } for( i = 0; i < compile->nparam; i++ ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, &arg[i + compile->nsecret], TRUE ); printf( "\targ %2d = %s\n", i, vips_buf_all( &buf ) ); } } #endif /*DEBUG*/ /* Make class base. */ if( NEWNODE( heap, base ) ) return( FALSE ); base->type = TAG_CLASS; PPUT( base, ELEMENT_COMPILEREF, compile, ELEMENT_ELIST, NULL ); PEPUTP( out, ELEMENT_NODE, base ); /* Make node for holding secrets and members. */ if( NEWNODE( heap, sm ) ) return( FALSE ); sm->type = TAG_CONS; PPUT( sm, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); PPUTRIGHT( base, ELEMENT_NODE, sm ); /* Build list of members. */ pbi.heap = heap; pbi.sym = sym; pbi.arg = arg; pbi.this = this; pbi.compile = compile; PEPOINTRIGHT( sm, &p1 ); if( icontainer_map_rev( ICONTAINER( compile ), (icontainer_map_fn) add_class_member, &pbi, &p1 ) ) return( FALSE ); /* Add name member. */ if( heap_safe_pointer( heap, (heap_safe_pointer_fn) class_new_single_name, &pbi, &p1, NULL, NULL ) ) return( FALSE ); /* Add this member. */ if( !add_class_svpair( &pbi, sths, this, &p1 ) ) return( FALSE ); /* Add class parameters to member list. */ pbi.i = 0; if( slist_map2_rev( compile->param, (SListMap2Fn) add_class_parameter, &pbi, &p1 ) ) return( FALSE ); /* Now ... secret list starts off pointing to head of member list. */ PEPUTLEFT( sm, &p1 ); /* Add all secret parameters to secret list. */ PEPOINTLEFT( sm, &p1 ); if( slist_map2_rev( compile->secret, (SListMap2Fn) add_class_parameter, &pbi, &p1 ) ) return( FALSE ); #ifdef DEBUG { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, out, TRUE ); printf( "class_new_single: built instance of " ); symbol_name_print( sym ); printf( ":\n%s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG*/ return( TRUE ); } /* Look at a scrap of graph and try to find a constructor it might be using. * This will only work for really basic functions :-( but it's enough to allow * us to pass extra secrets through the superclass. Used by (eg.) Colour when * it overrides Value and adds the colourspace arg. */ static Compile * class_guess_constructor( PElement *fn ) { if( PEISCONSTRUCTOR( fn ) ) return( PEGETCOMPILE( fn ) ); else if( PEISNODE( fn ) ) { HeapNode *hn = PEGETVAL( fn ); if( hn->type == TAG_APPL ) { PElement left; PEPOINTLEFT( hn, &left ); return( class_guess_constructor( &left ) ); } } return( NULL ); } /* Look at arg0 and try to extract the arguments (all the RHS of the @ nodes). * Return the number of args we found, or -1 if we find crazy stuff. */ static int class_guess_args( PElement arg[], PElement *fn ) { if( PEISCONSTRUCTOR( fn ) ) return( 0 ); else if( PEISNODE( fn ) ) { PElement left; int i; PEPOINTLEFT( PEGETVAL( fn ), &left ); if( (i = class_guess_args( arg, &left )) == -1 ) return( -1 ); if( i >= MAX_SYSTEM ) { error_top( _( "Too many arguments." ) ); error_sub( _( "You can't have more than %d " "arguments to a superclass constructor." ), MAX_SYSTEM ); return( -1 ); } PEPOINTRIGHT( PEGETVAL( fn ), &arg[i] ); return( i + 1 ); } else return( -1 ); } static void * class_new_super_sub( Heap *heap, PElement *p1, Compile *compile, PElement *arg, PElement *this, PElement *super ) { /* Build the superclass ... we overwrite the super * list with the constructed class, so make a copy of * the pointer to stop it being GCed. */ PEPUTPE( p1, super ); if( !class_new_single( heap, compile, arg, this, super ) ) return( heap ); return( NULL ); } /* Clone a class instance. Copy pointers to the the args, secrets and super; * rebuild with the specified "this". Instance and out can be equal. */ static gboolean class_clone_super( Heap *heap, Compile *compile, PElement *instance, PElement *this, PElement *out ) { PElement arg[MAX_SYSTEM]; const int nargs = compile->nsecret + compile->nparam; PElement secret; int i; g_assert( nargs <= MAX_SYSTEM ); #ifdef DEBUG_VERBOSE { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, instance, TRUE ); printf( "class_new_clone: about to clone \"%s\": %s\n", IOBJECT( compile->sym )->name, vips_buf_all( &buf ) ); } #endif /*DEBUG_VERBOSE*/ /* Pull out values of secrets and class args into arg[]. */ PEGETCLASSSECRET( &secret, instance ); for( i = 0; i < nargs; i++ ) { HeapNode *hn = PEGETVAL( &secret ); HeapNode *sv = GETLEFT( hn ); int index = nargs - i - 1; PEPOINTRIGHT( sv, &arg[index] ); PEPOINTRIGHT( hn, &secret ); } /* Build class again. */ return( class_new_single( heap, compile, arg, this, out ) ); } static void * class_clone_super_sub( Heap *heap, PElement *p1, Compile *compile, PElement *instance, PElement *this, PElement *out ) { /* instance and out can point to the same node, so save a pointer to * instance to stop it being GCed. */ PEPUTPE( p1, instance ); if( !class_clone_super( heap, compile, instance, this, out ) ) return( heap ); return( NULL ); } /* Does this class have a "super"? Build it and recurse. */ gboolean class_new_super( Heap *heap, Compile *compile, PElement *this, PElement *instance ) { PElement super; if( compile->has_super && class_get_super( instance, &super ) ) { Compile *super_compile; int len, fn_len; PElement arg0; /* It must be a list whose first element is the superclass * constructor, or a partially parameterised constructor, or * the superclass itself (if it has already * been constructed, or has no args). Other elements in the * list are the remaining args. * * We keep the list form, since we want to not build the * superclass until now if we can help it ... otherwise we * have to construct once, then construct again when we clone. */ if( (len = heap_list_length( &super )) < 1 || !heap_list_index( &super, 0, &arg0 ) || !heap_reduce_strict( &arg0 ) ) return( FALSE ); if( (super_compile = class_guess_constructor( &arg0 )) ) { PElement fn_arg[MAX_SYSTEM]; PElement arg[MAX_SYSTEM]; int i; /* How many function args are there? */ if( (fn_len = class_guess_args( fn_arg, &arg0 )) < 0 ) return( FALSE ); /* Check total arg count. */ if( super_compile->nsecret != 0 ) { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); slist_map2( super_compile->secret, (SListMap2Fn) symbol_name_error, &buf, NULL ); error_top( _( "Bad superclass." ) ); error_sub( _( "Superclass constructor \"%s\" " "refers to non-local symbols %s" ), symbol_name( super_compile->sym ), vips_buf_all( &buf ) ); return( FALSE ); } if( len - 1 + fn_len != super_compile->nparam ) { error_top( _( "Wrong number of arguments." ) ); error_sub( _( "Superclass constructor \"%s\" " "expects %d arguments, not %d." ), symbol_name( super_compile->sym ), super_compile->nparam, len - 1 + fn_len ); return( FALSE ); } /* Grab the explicit args from the super list. */ for( i = 0; i < len - 1; i++ ) { if( !heap_list_index( &super, len - 1 - i, &arg[i] ) ) return( FALSE ); } /* Append the function args, but reverse them as we * go so we get most-nested arg last. */ for( i = 0; i < fn_len; i++ ) arg[i + len - 1] = fn_arg[fn_len - 1 - i]; /* Build the superclass ... we overwrite the super * list with the constructed class, so make a copy of * the pointer to stop it being GCed. */ if( heap_safe_pointer( heap, (heap_safe_pointer_fn) class_new_super_sub, super_compile, arg, this, &super ) ) return( FALSE ); } else if( PEISCLASS( &arg0 ) ) { /* Super is a constructed class ... clone it, but with * our "this" in there. Slow, but useful. */ super_compile = PEGETCLASSCOMPILE( &arg0 ); if( heap_safe_pointer( heap, (heap_safe_pointer_fn) class_clone_super_sub, super_compile, &arg0, this, &super ) ) return( FALSE ); } else { char txt1[300]; VipsBuf buf1 = VIPS_BUF_STATIC( txt1 ); char txt2[300]; VipsBuf buf2 = VIPS_BUF_STATIC( txt2 ); error_top( _( "Bad superclass." ) ); itext_value( reduce_context, &buf1, &arg0 ); vips_buf_appendf( &buf2, _( "First element in superclass of \"%s\" " "must be class or constructor." ), symbol_name( compile->sym ) ); vips_buf_appendf( &buf2, "\n" ); vips_buf_appendf( &buf2, _( "You passed:" ) ); error_sub( "%s\n %s", vips_buf_all( &buf2 ), vips_buf_all( &buf1 ) ); return( FALSE ); } /* And recursively build any superclasses. */ if( !class_new_super( heap, super_compile, this, &super ) ) return( FALSE ); } return( TRUE ); } /* Make a class instance. */ gboolean class_new( Heap *heap, Compile *compile, HeapNode **arg, PElement *out ) { int i; PElement pe_arg[MAX_SYSTEM]; /* Make a set of arg pointers. */ if( compile->nparam + compile->nsecret >= MAX_SYSTEM ) { error_top( _( "Too many arguments." ) ); error_sub( _( "Too many arguments to class constructor \"%s\". " "No more than %d arguments are supported." ), symbol_name( compile->sym ), MAX_SYSTEM ); return( FALSE ); } for( i = 0; i < compile->nparam + compile->nsecret; i++ ) { PEPOINTRIGHT( arg[i], &pe_arg[i] ); } /* Build the base instance. */ if( !class_new_single( heap, compile, pe_arg, out, out ) ) return( FALSE ); /* And recursively build any superclasses. */ if( !class_new_super( heap, compile, out, out ) ) return( FALSE ); #ifdef DEBUG_BUILD { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, out, TRUE ); printf( "class_new: built instance of \"%s\": %s\n", IOBJECT( compile->sym )->name, vips_buf_all( &buf ) ); } #endif /*DEBUG_BUILD*/ return( TRUE ); } /* Clone a class instance. Copy pointers to the the args, secrets and super; * regenerate all the members. instance and out can be equal. */ gboolean class_clone_args( Heap *heap, PElement *instance, PElement *out ) { HeapNode *arg[MAX_SYSTEM]; Compile *compile = PEGETCLASSCOMPILE( instance ); const int nargs = compile->nsecret + compile->nparam; PElement secret; int i; g_assert( nargs <= MAX_SYSTEM ); #ifdef DEBUG_VERBOSE { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, instance, TRUE ); printf( "class_clone_args: about to clone \"%s\": %s\n", IOBJECT( compile->sym )->name, vips_buf_all( &buf ) ); } #endif /*DEBUG_VERBOSE*/ /* Pull out values of secrets and class args into RHS of arg[]. */ PEGETCLASSSECRET( &secret, instance ); for( i = 0; i < nargs; i++ ) { HeapNode *hn = PEGETVAL( &secret ); HeapNode *sv = GETLEFT( hn ); int index = nargs - i - 1; arg[index] = sv; PEPOINTRIGHT( hn, &secret ); } /* Build class again. */ return( class_new( heap, compile, &arg[0], out ) ); } /* Build a class instance picking parameters from C args ... handy for * making a new toggle instance on a click, for example. */ gboolean class_newv( Heap *heap, const char *name, PElement *out, ... ) { va_list ap; Symbol *sym; Compile *compile; HeapNode args[MAX_SYSTEM]; HeapNode *pargs[MAX_SYSTEM]; int i; if( !(sym = compile_lookup( symbol_root->expr->compile, name )) || !is_value( sym ) || !is_class( sym->expr->compile ) ) { error_top( _( "Class not found." ) ); error_sub( _( "Class \"%s\" not found." ), name ); return( FALSE ); } compile = sym->expr->compile; if( compile->nparam >= MAX_SYSTEM ) { error_top( _( "Too many arguments." ) ); error_sub( _( "Too many arguments to class constructor \"%s\". " "No more than %d arguments are supported." ), symbol_name( compile->sym ), MAX_SYSTEM ); return( FALSE ); } va_start( ap, out ); for( i = 0; i < compile->nparam; i++ ) { PElement *arg = va_arg( ap, PElement * ); PElement rhs; pargs[i] = &args[i]; PEPOINTRIGHT( pargs[i], &rhs ); PEPUTPE( &rhs, arg ); } va_end( ap ); return( class_new( heap, compile, &pargs[0], out ) ); } static void class_typecheck_error( PElement *instance, const char *name, const char *type ) { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); PElement val; vips_buf_appendf( &buf, _( "Member \"%s\" of class \"%s\" " "should be of type \"%s\", instead it's:" ), name, IOBJECT( PEGETCLASSCOMPILE( instance )->sym )->name, type ); vips_buf_appends( &buf, "\n " ); if( class_get_member( instance, name, NULL, &val ) && !itext_value( reduce_context, &buf, &val ) ) return; error_top( _( "Bad argument." ) ); error_sub( "%s", vips_buf_all( &buf ) ); } /* A function that gets a type from a class. */ typedef gboolean (*ClassGetFn)( PElement *, void * ); static gboolean class_get_member_check( PElement *instance, const char *name, const char *type, ClassGetFn fn, void *a ) { PElement val; if( !class_get_member( instance, name, NULL, &val ) ) return( FALSE ); if( !fn( &val, a ) ) { class_typecheck_error( instance, name, type ); return( FALSE ); } return( TRUE ); } gboolean class_get_member_bool( PElement *instance, const char *name, gboolean *out ) { return( class_get_member_check( instance, name, "bool", (ClassGetFn) heap_get_bool, out ) ); } gboolean class_get_member_real( PElement *instance, const char *name, double *out ) { return( class_get_member_check( instance, name, "real", (ClassGetFn) heap_get_real, out ) ); } gboolean class_get_member_int( PElement *instance, const char *name, int *out ) { double d; if( !class_get_member_check( instance, name, "real", (ClassGetFn) heap_get_real, &d ) ) return( FALSE ); *out = IM_RINT( d ); return( TRUE ); } gboolean class_get_member_class( PElement *instance, const char *name, const char *type, PElement *out ) { gboolean result; if( !class_get_member_check( instance, name, type, (ClassGetFn) heap_get_class, out ) ) return( FALSE ); if( !heap_is_instanceof( type, out, &result ) ) return( FALSE ); if( !result ) { class_typecheck_error( instance, name, type ); return( FALSE ); } return( TRUE ); } gboolean class_get_member_image( PElement *instance, const char *name, Imageinfo **out ) { return( class_get_member_check( instance, name, "image", (ClassGetFn) heap_get_image, out ) ); } gboolean class_get_member_lstring( PElement *instance, const char *name, GSList **labels ) { return( class_get_member_check( instance, name, "finite [[char]]", (ClassGetFn) heap_get_lstring, labels ) ); } gboolean class_get_member_string( PElement *instance, const char *name, char *buf, int sz ) { PElement val; if( !class_get_member( instance, name, NULL, &val ) ) return( FALSE ); if( !heap_get_string( &val, buf, sz ) ) { class_typecheck_error( instance, name, "finite [char]" ); return( FALSE ); } return( TRUE ); } gboolean class_get_member_instance( PElement *instance, const char *name, const char *klass, PElement *out ) { gboolean result; return( class_get_member( instance, name, NULL, out ) && heap_is_instanceof( klass, out, &result ) && result ); } gboolean class_get_member_matrix_size( PElement *instance, const char *name, int *xsize, int *ysize ) { PElement val; if( !class_get_member( instance, name, NULL, &val ) ) return( FALSE ); if( !heap_get_matrix_size( &val, xsize, ysize ) ) { class_typecheck_error( instance, name, "finite rectangular [[real]]" ); return( FALSE ); } return( TRUE ); } gboolean class_get_member_matrix( PElement *instance, const char *name, double *buf, int n, int *xsize, int *ysize ) { PElement val; if( !class_get_member( instance, name, NULL, &val ) ) return( FALSE ); if( !heap_get_matrix( &val, buf, n, xsize, ysize ) ) { class_typecheck_error( instance, name, "finite rectangular [[real]]" ); return( FALSE ); } return( TRUE ); } gboolean class_get_member_realvec( PElement *instance, const char *name, double *buf, int n, int *length ) { PElement val; int l; if( !class_get_member( instance, name, NULL, &val ) ) return( FALSE ); if( (l = heap_get_realvec( &val, buf, n )) < 0 ) { class_typecheck_error( instance, name, "finite [real]" ); return( FALSE ); } *length = l; return( TRUE ); } nip2-8.7.1/src/rowview.h0000644000175000017500000000423113351443023011760 00000000000000/* a rowview in a workspace ... part of a tallycolumn, not a separate widget */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_ROWVIEW (rowview_get_type()) #define ROWVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_ROWVIEW, Rowview )) #define ROWVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_ROWVIEW, RowviewClass )) #define IS_ROWVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_ROWVIEW )) #define IS_ROWVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_ROWVIEW )) struct _Rowview { View view; Subcolumnview *sview; /* Enclosing subcolumnview */ Rhsview *rhsview; /* Our rhs */ gboolean visible; /* Currently visible */ int rnum; /* Row of tallycolumn we are in */ GtkWidget *spin; /* Class display open/close widgets */ GtkWidget *but; /* Name button */ GtkWidget *led; /* Indicators */ GtkWidget *label; /* Name label */ char *last_tooltip; /* Last tooltip we set */ }; typedef struct _RowviewClass { ViewClass parent_class; /* My methods. */ } RowviewClass; guint rowview_menu_attach( Rowview *rview, GtkWidget *widget ); GtkType rowview_get_type( void ); View *rowview_new( void ); void rowview_get_position( Rowview *rview, int *x, int *y, int *w, int *h ); void rowview_set_visible( Rowview *rview, gboolean visible ); gboolean rowview_get_visible( Rowview *rview ); nip2-8.7.1/src/panechild.h0000644000175000017500000000323513351443023012210 00000000000000/* The thing that sits in a pane showing the title and close button. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PANECHILD (panechild_get_type()) #define PANECHILD( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_PANECHILD, Panechild )) #define PANECHILD_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PANECHILD, PanechildClass )) #define IS_PANECHILD( obj ) \ (GTK_CHECK_TYPE( (obj), TYPE_PANECHILD )) #define IS_PANECHILD_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PANECHILD )) struct _Panechild { vObject parent_object; Pane *pane; /* The pane we are part of */ const char *title; /* Title we display */ GtkWidget *label; /* Titlebar label */ }; typedef struct _PanechildClass { vObjectClass parent_class; } PanechildClass; GtkType panechild_get_type( void ); Panechild *panechild_new( Pane *pane, const char *title ); nip2-8.7.1/src/floatwindow.c0000644000175000017500000001077213351443023012615 00000000000000/* abstract base class for floatwindow / plotwindow etc. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static iWindowClass *parent_class = NULL; static void floatwindow_popdown( GtkWidget *widget ) { Floatwindow *floatwindow = FLOATWINDOW( widget ); Model *model = floatwindow->model; #ifdef DEBUG printf( "floatwindow_popdown\n" ); #endif /*DEBUG*/ /* We have to note position/size in popdown rather than destroy, since * the widgets have to all still be extant. */ /* Note position/size for later reuse. */ model->window_width = GTK_WIDGET( floatwindow )->allocation.width; model->window_height = GTK_WIDGET( floatwindow )->allocation.height; gdk_window_get_root_origin( gtk_widget_get_toplevel( GTK_WIDGET( floatwindow ) )->window, &model->window_x, &model->window_y ); IWINDOW_CLASS( parent_class )->popdown( widget ); } static void floatwindow_build( GtkWidget *widget ) { Floatwindow *floatwindow = FLOATWINDOW( widget ); Model *model = floatwindow->model; IWINDOW_CLASS( parent_class )->build( widget ); /* Must be set with floatmodel_link before build. */ g_assert( floatwindow->model ); /* Position and size to restore? Come here after parent build, so we * can override any default settings from there. */ if( model->window_width != -1 ) { GdkScreen *screen = gtk_widget_get_screen( GTK_WIDGET( floatwindow ) ); int screen_width = gdk_screen_get_width( screen ); int screen_height = gdk_screen_get_height( screen ); /* We need to clip x/y against the desktop size ... we may be * loading a workspace made on a machine with a big screen on * a machine with a small screen. FIXME ... we could only clip if the window will be completely off the screen? ie. ignore iimage->window_width etc. */ int window_x = IM_CLIP( 0, model->window_x, screen_width - model->window_width ); int window_y = IM_CLIP( 0, model->window_y, screen_height - model->window_height ); int window_width = IM_MIN( model->window_width, screen_width ); int window_height = IM_MIN( model->window_height, screen_height ); gtk_widget_set_uposition( GTK_WIDGET( floatwindow ), window_x, window_y ); gtk_window_set_default_size( GTK_WINDOW( floatwindow ), window_width, window_height ); } } static void floatwindow_class_init( FloatwindowClass *class ) { iWindowClass *iwindow_class = (iWindowClass *) class; parent_class = g_type_class_peek_parent( class ); iwindow_class->build = floatwindow_build; iwindow_class->popdown = floatwindow_popdown; /* Hmm, this rather negates the point of this class. If we make plot * and image windows transient for the main window, we don't get * maximise buttons :-( (on gnome and win anyway). * * Keep this class around for now, maybe it'll still be useful. */ iwindow_class->transient = FALSE; /* Create signals. */ /* Init methods. */ } static void floatwindow_init( Floatwindow *floatwindow ) { floatwindow->model = NULL; } GType floatwindow_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( FloatwindowClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) floatwindow_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Floatwindow ), 32, /* n_preallocs */ (GInstanceInitFunc) floatwindow_init, }; type = g_type_register_static( TYPE_IWINDOW, "Floatwindow", &info, 0 ); } return( type ); } void floatwindow_link( Floatwindow *floatwindow, Model *model ) { floatwindow->model = model; destroy_if_destroyed( G_OBJECT( floatwindow ), G_OBJECT( model ), (DestroyFn) gtk_widget_destroy ); } nip2-8.7.1/src/doubleclick.c0000644000175000017500000001267113351443023012540 00000000000000/* ip: display VASARI format files. * * doubleclick.c: separate single and double clicks on a widget */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include #include #ifdef HAVE_UNISTD_H #include #endif /*HAVE_UNISTD_H*/ #include #include #include #include #include #include #include "doubleclick.h" #define FREEFI( F, S ) { if( S ) { (void) F( S ); (S) = 0; } } /* For debugging. #define DEBUG */ /* The struct we hold our private stuff inside. */ typedef struct doubleclick_info { GtkWidget *wid; /* Widget we are attached to */ guint click; /* Timer for click determination */ gboolean dsingle; /* Do single click on first click of double */ GdkEvent event; /* Copy of last event for clients */ DoubleclickFunc single; /* Callback for single click */ void *clients; /* Client data for single */ DoubleclickFunc dub; /* Callback for double click */ void *clientd; /* Client data for double */ } Doubleclick; /* Allocate and free clicks. */ static Doubleclick * doubleclick_new() { Doubleclick *click; if( !(click = IM_NEW( NULL, Doubleclick )) ) return( NULL ); click->wid = NULL; click->click = 0; click->dsingle = FALSE; click->single = NULL; click->dub = NULL; return( click ); } void doubleclick_free( Doubleclick *click ) { im_free( click ); } /* Timer callback for multiclick detection. */ static gboolean doubleclick_time_cb( Doubleclick *click ) { #ifdef DEBUG g_message( "doubleclick: timeout" ); #endif /*DEBUG*/ click->click = 0; /* There has been no second click before the timeout: we do a single * click. If st->dsingle is set though, we have already delivered the * single-click event, so don't bother. */ if( !click->dsingle && click->single ) { #ifdef DEBUG g_message( "doubleclick: timeout - calling single" ); #endif /*DEBUG*/ click->single( click->wid, &click->event, click->clients ); } /* Stop timer. */ return( FALSE ); } /* There has been an event. Is it single or double? */ static gboolean doubleclick_trigger_cb( GtkWidget *wid, GdkEvent *ev, Doubleclick *click ) { gboolean handled = FALSE; /* Make sure we have a button 1 press. */ if( ev->type != GDK_BUTTON_PRESS || ev->button.button != 1 ) return( handled ); /* Note event for client. */ click->event = *ev; if( click->click ) { /* There is a timeout pending - ie. there was a click * recently. This must be the second part of a double click. * Cancel the timeout and do a double click action. */ FREEFI( g_source_remove, click->click ); if( click->dub ) { #ifdef DEBUG g_message( "doubleclick: seen double" ); #endif /*DEBUG*/ click->dub( click->wid, &click->event, click->clientd ); handled = TRUE; } } else { #ifdef DEBUG g_message( "doubleclick: starting timer" ); #endif /*DEBUG*/ /* No previous click. This may be either. Start a timeout to * help us decide. * * We aren't supposed to look at double_click_time, but * there's no access method, I think. */ click->click = g_timeout_add( gtk_widget_get_display( wid )->double_click_time, (GSourceFunc) doubleclick_time_cb, click ); /* If do-single-on-double is set, we can trigger a * single-click now. */ if( click->dsingle && click->single ) { click->single( click->wid, &click->event, click->clients ); handled = TRUE; } } return( handled ); } /* Destroy a doubleclick_info. */ /*ARGSUSED*/ static void doubleclick_destroy_cb( GtkWidget *wid, Doubleclick *click ) { #ifdef DEBUG g_message( "doubleclick: destroyed" ); #endif /*DEBUG*/ if( click->click ) { /* Don't trigger a single-click, even though there was one * recently, since our widget is being destroyed. */ FREEFI( g_source_remove, click->click ); } doubleclick_free( click ); } static void doubleclick_realize_cb( GtkWidget *wid ) { gtk_widget_add_events( wid, GDK_BUTTON_PRESS_MASK ); } /* Attach callbacks to a widget. */ void doubleclick_add( GtkWidget *wid, gboolean dsingle, DoubleclickFunc single, void *clients, DoubleclickFunc dub, void *clientd ) { Doubleclick *click = doubleclick_new(); /* Complete fields. */ click->wid = wid; click->dsingle = dsingle; click->single = single; click->dub = dub; click->clients = clients; click->clientd = clientd; /* Add callbacks. */ gtk_signal_connect( GTK_OBJECT( wid ), "destroy", GTK_SIGNAL_FUNC( doubleclick_destroy_cb ), click ); gtk_signal_connect( GTK_OBJECT( wid ), "event", GTK_SIGNAL_FUNC( doubleclick_trigger_cb ), click ); gtk_signal_connect( GTK_OBJECT( wid ), "realize", GTK_SIGNAL_FUNC( doubleclick_realize_cb ), NULL ); } nip2-8.7.1/src/classmodel.h0000644000175000017500000001132313351443023012404 00000000000000/* like a heapmodel, but we represent a class in the heap */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Member types we automate. */ typedef enum { CLASSMODEL_MEMBER_INT, CLASSMODEL_MEMBER_ENUM, /* Like int, but extent has max value */ CLASSMODEL_MEMBER_BOOLEAN, CLASSMODEL_MEMBER_DOUBLE, CLASSMODEL_MEMBER_STRING, CLASSMODEL_MEMBER_STRING_LIST, CLASSMODEL_MEMBER_REALVEC_FIXED,/* Eg. Colour's triplet */ CLASSMODEL_MEMBER_MATRIX, CLASSMODEL_MEMBER_OPTIONS, CLASSMODEL_MEMBER_IMAGE } ClassmodelMemberType; /* A matrix value. */ typedef struct _MatrixValue { double *coeff; /* Base coeffs */ int width; /* Size of matrix */ int height; } MatrixValue; /* An image value. */ typedef struct { Imageinfo *ii; /* Can get "changed" for reload if the file changes behind our backs. * Recalc the classmodel if this happens. */ guint file_changed_sid; Classmodel *classmodel; } ImageValue; /* A member needing automation. */ typedef struct { ClassmodelMemberType type; void *details; /* eg. the set of allowed options */ int extent; /* Vector length, enum max, etc. */ const char *member_name; /* Name as known in nip class defs */ const char *save_name; /* As known in save files */ const char *user_name; /* i18n'd name for dialogs */ guint offset; /* Struct offset */ } ClassmodelMember; #define TYPE_CLASSMODEL (classmodel_get_type()) #define CLASSMODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_CLASSMODEL, Classmodel )) #define CLASSMODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_CLASSMODEL, ClassmodelClass)) #define IS_CLASSMODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_CLASSMODEL )) #define IS_CLASSMODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_CLASSMODEL )) #define CLASSMODEL_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_CLASSMODEL, ClassmodelClass )) struct _Classmodel { Heapmodel parent_class; /* Set if we have graphic mods applied which should be saved. */ gboolean edited; /* xtras for Region/Arrow/etc. */ GSList *iimages; /* All the iimage we are defined on */ GSList *views; /* All the regionview we have made */ /* For things which have been loaded or saved from files (eg. image * and matrix). Used to set the filename for the "save" dialog. */ char *filename; }; typedef struct _ClassmodelClass { HeapmodelClass parent_class; /* Get a pointer to the class instance vars ... just used by * iarrow/iregion for code sharing. */ void *(*get_instance)( Classmodel * ); /* Read from heap into model, and create new heap class from model. */ gboolean (*class_get)( Classmodel *, PElement *root ); gboolean (*class_new)( Classmodel *, PElement *fn, PElement *out ); /* Save and replace graphic displays ... eg. image/matrix. */ gboolean (*graphic_save)( Classmodel *, GtkWidget *, const char * ); gboolean (*graphic_replace)( Classmodel *, GtkWidget *, const char * ); FileselFileType **filetype; const char *filetype_pref; ClassmodelMember *members; int n_members; void (*reset)( Classmodel * ); } ClassmodelClass; void image_value_init( ImageValue *image, Classmodel *classmodel ); void image_value_destroy( ImageValue *image ); void image_value_set( ImageValue *image, Imageinfo *ii ); void image_value_caption( ImageValue *value, VipsBuf *buf ); void *classmodel_get_instance( Classmodel *classmodel ); void classmodel_graphic_save( Classmodel *classmodel, GtkWidget *parent ); void classmodel_graphic_replace( Classmodel *classmodel, GtkWidget *parent ); void *classmodel_iimage_unlink( Classmodel *classmodel, iImage *iimage ); void classmodel_iimage_update( Classmodel *classmodel, Imageinfo *ii ); gboolean classmodel_update_members( Classmodel *classmodel, PElement *root ); GType classmodel_get_type( void ); void classmodel_update( Classmodel *classmodel ); void classmodel_set_edited( Classmodel *classmodel, gboolean edited ); Classmodel *classmodel_new_classmodel( GType type, Rhs *rhs ); nip2-8.7.1/src/toolkitview.c0000644000175000017500000001221513351443023012632 00000000000000/* Manage toolkitviews and their display. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* The top n items in the toolkits menu are made by the system for us ... we * pop toolkit items in after these. */ #define TOOLKITVIEW_MENU_OFFSET 3 static ViewClass *parent_class = NULL; static void toolkitview_destroy( GtkObject *object ) { Toolkitview *kview; g_return_if_fail( object != NULL ); g_return_if_fail( IS_TOOLKITVIEW( object ) ); kview = TOOLKITVIEW( object ); #ifdef DEBUG printf( "toolkitview_destroy: %p\n", object ); printf( "toolkitview_destroy: menu = %p\n", kview->menu ); printf( "toolkitview_destroy: item = %p\n", kview->item ); #endif /*DEBUG*/ DESTROY_GTK( kview->menu ); DESTROY_GTK( kview->item ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void toolkitview_finalize( GObject *gobject ) { #ifdef DEBUG printf( "toolkitview_finalize: %p\n", gobject ); #endif /*DEBUG*/ G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Our widgets have been killed ... kill us in turn. */ static void toolkitview_destroy_cb( GtkWidget *widget, Toolkitview *kview ) { /* printf( "toolkitview_destroy_cb: %p\n", kview ); */ kview->menu = NULL; kview->item = NULL; kview->destroy_sid = 0; DESTROY_GTK( kview ); } static void toolkitview_refresh( vObject *vobject ) { Toolkitview *kview = TOOLKITVIEW( vobject ); Toolkit *kit = TOOLKIT( VOBJECT( kview )->iobject ); Toolkitgroupview *kitgview = kview->kitgview; GtkWidget *menu = kitgview->menu; gboolean changed = FALSE; #ifdef DEBUG printf( "toolkitview_refresh: " ); iobject_print( VOBJECT( kview )->iobject ); #endif /*DEBUG*/ /* Make a button ready for the sub-menu. */ if( !kview->item ) { kview->item = gtk_menu_item_new_with_label( IOBJECT( kit )->name ); gtk_menu_shell_insert( GTK_MENU_SHELL( menu ), kview->item, ICONTAINER( kit )->pos + TOOLKITVIEW_MENU_OFFSET ); gtk_widget_show( kview->item ); kview->destroy_sid = g_signal_connect( kview->item, "destroy", G_CALLBACK( toolkitview_destroy_cb ), kview ); changed = TRUE; } if( !kview->menu ) { iWindow *iwnd = IWINDOW( iwindow_get_root( menu ) ); char path[256]; kview->menu = gtk_menu_new(); gtk_menu_set_accel_group( GTK_MENU( kview->menu ), iwnd->accel_group ); im_snprintf( path, 256, "/Toolkits/%s", IOBJECT( kit )->name ); gtk_menu_set_accel_path( GTK_MENU( kview->menu ), path ); changed = TRUE; } if( changed ) gtk_menu_item_set_submenu( GTK_MENU_ITEM( kview->item ), kview->menu ); widget_visible( kview->item, ICONTAINER( kit )->children != NULL ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void toolkitview_link( View *view, Model *model, View *parent ) { Toolkitview *kview = TOOLKITVIEW( view ); Toolkitgroupview *kitgview = TOOLKITGROUPVIEW( parent ); kview->kitgview = kitgview; VIEW_CLASS( parent_class )->link( view, model, parent ); #ifdef DEBUG printf( "toolkitview_link: " ); iobject_print( VOBJECT( kview )->iobject ); #endif /*DEBUG*/ } static void toolkitview_class_init( ToolkitviewClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = toolkitview_finalize; object_class->destroy = toolkitview_destroy; /* Create signals. */ /* Init methods. */ vobject_class->refresh = toolkitview_refresh; view_class->link = toolkitview_link; } static void toolkitview_init( Toolkitview *kview ) { kview->item = NULL; kview->menu = NULL; kview->destroy_sid = 0; } GtkType toolkitview_get_type( void ) { static GtkType kview_type = 0; if( !kview_type ) { static const GtkTypeInfo kview_info = { "Toolkitview", sizeof( Toolkitview ), sizeof( ToolkitviewClass ), (GtkClassInitFunc) toolkitview_class_init, (GtkObjectInitFunc) toolkitview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; kview_type = gtk_type_unique( TYPE_VIEW, &kview_info ); } return( kview_type ); } View * toolkitview_new( void ) { Toolkitview *kview = gtk_type_new( TYPE_TOOLKITVIEW ); return( VIEW( kview ) ); } nip2-8.7.1/src/iimage.h0000644000175000017500000000440113351443023011510 00000000000000/* a ip image class in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IIMAGE (iimage_get_type()) #define IIMAGE( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IIMAGE, iImage )) #define IIMAGE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IIMAGE, iImageClass)) #define IS_IIMAGE( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IIMAGE )) #define IS_IIMAGE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IIMAGE )) #define IIMAGE_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IIMAGE, iImageClass )) struct _iImage { Classmodel parent_class; /* Class fields. */ ImageValue value; /* List of classmodel which have displays on us. */ GSList *classmodels; /* List of popup imageview windows we've made. */ GSList *views; /* Track display pos/size/etc. here. */ int image_left, image_top; /* Scroll position */ int image_mag; /* Scale */ /* View attachments. */ gboolean show_status; gboolean show_paintbox; gboolean show_convert; gboolean show_rulers; /* Bar settings we remember. */ double scale, offset; gboolean falsecolour; gboolean type; /* Private ... build iobject caption here. */ VipsBuf caption_buffer; }; typedef struct _iImageClass { ClassmodelClass parent_class; /* My methods. */ } iImageClass; GType iimage_get_type( void ); gboolean iimage_replace( iImage *iimage, const char *filename ); void iimage_header( GtkWidget *parent, Model *model ); nip2-8.7.1/src/itext.c0000644000175000017500000005125713351443023011420 00000000000000/* a text item in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static HeapmodelClass *parent_class = NULL; static void itext_finalize( GObject *gobject ) { iText *itext; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_ITEXT( gobject ) ); itext = ITEXT( gobject ); #ifdef DEBUG printf( "itext_destroy\n" ); #endif /*DEBUG*/ /* My instance destroy stuff. */ IM_FREE( itext->formula ); IM_FREE( itext->formula_default ); vips_buf_destroy( &itext->value ); vips_buf_destroy( &itext->decompile ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void itext_info( iObject *iobject, VipsBuf *buf ) { iText *itext = ITEXT( iobject ); vips_buf_appends( buf, _( "Formula" ) ); vips_buf_appendf( buf, ": %s\n", NN( itext->formula ) ); } /* Fwd ref this. */ static gboolean itext_add_element( VipsBuf *buf, PElement *base, gboolean top, gboolean bracket ); /* Sub-fn of below, callback for list print. Eval and print the item into * the buffer, separating with commas as required. */ static void * itext_add_list( PElement *base, VipsBuf *buf, gboolean *first ) { Reduce *rc = reduce_context; if( *first ) *first = FALSE; else vips_buf_appends( buf, ", " ); /* Reduce the head, and print. */ if( !reduce_pelement( rc, reduce_spine, base ) ) return( base ); if( !itext_add_element( buf, base, FALSE, FALSE ) ) return( base ); /* Buffer full? Abort list print. */ if( buf->full ) return( base ); return( NULL ); } /* Sub-fn of below, callback for string print. Print the chars into the * buffer. */ static void * itext_add_string( PElement *base, VipsBuf *buf ) { Reduce *rc = reduce_context; /* Reduce the head, and add the char. */ if( !reduce_pelement( rc, reduce_spine, base ) ) return( base ); if( PEISCHAR( base ) ) /* Don't escape chars in string mode. */ vips_buf_appendf( buf, "%c", PEGETCHAR( base ) ); else { /* Help! Fall back to ordinary item print. */ vips_buf_appends( buf, ", " ); if( !itext_add_element( buf, base, FALSE, FALSE ) ) return( base ); } /* Buffer full? Abort string print. */ if( buf->full ) return( base ); return( NULL ); } /* Print a char ... we need to escape \n etc. */ static void itext_add_char( int ch, VipsBuf *buf ) { char in[2]; char out[3]; in[0] = ch; in[1] = '\0'; my_strecpy( out, in, FALSE ); vips_buf_appends( buf, out ); } /* Print a complex. */ static void itext_add_complex( double rp, double ip, VipsBuf *buf ) { if( PRINT_CARTESIAN ) vips_buf_appendf( buf, "(%.12g, %.12g)", rp, ip ); else { if( rp == 0 ) { if( ip == 0 ) vips_buf_appendf( buf, "0" ); else vips_buf_appendf( buf, "%.12gj", ip ); } else if( ip == 0 ) vips_buf_appendf( buf, "%.12g", rp ); else vips_buf_appendf( buf, "%.12g + %.12gj", rp, ip ); } } /* Try to decompile. */ static gboolean itext_decompile_element( VipsBuf *buf, PElement *base, gboolean top ) { Reduce *rc = reduce_context; gboolean result; /* Set the value label for a tally entry. */ if( PEISNOVAL( base ) ) vips_buf_appends( buf, _( "no value" ) ); else if( PEISREAL( base ) ) vips_buf_appendf( buf, "%g", PEGETREAL( base ) ); else if( PEISBOOL( base ) ) vips_buf_appends( buf, bool_to_char( PEGETBOOL( base ) ) ); else if( PEISCHAR( base ) ) { vips_buf_appends( buf, "'" ); itext_add_char( (int) PEGETCHAR( base ), buf ); vips_buf_appends( buf, "'" ); } else if( PEISCOMPLEX( base ) ) itext_add_complex( PEGETREALPART( base ), PEGETIMAGPART( base ), buf ); else if( PEISMANAGEDSTRING( base ) ) { Managedstring *managedstring = PEGETMANAGEDSTRING( base ); vips_buf_appendf( buf, "\"%s\"", managedstring->string ); } else if( PEISELIST( base ) ) { vips_buf_appends( buf, "[ ]" ); } else if( !heap_is_string( base, &result ) ) /* Eval error. */ return( FALSE ); else if( result ) { vips_buf_appends( buf, "\"" ); if( heap_map_list( base, (heap_map_list_fn) itext_add_string, buf, NULL ) ) return( FALSE ); vips_buf_appends( buf, "\"" ); } else if( PEISLIST( base ) ) { gboolean first = TRUE; vips_buf_appends( buf, "[" ); if( heap_map_list( base, (heap_map_list_fn) itext_add_list, buf, &first ) ) return( FALSE ); vips_buf_appends( buf, "]" ); } else if( PEISIMAGE( base ) ) { Imageinfo *ii = PEGETII( base ); if( !top ) vips_buf_appends( buf, "(" ); if( ii && IOBJECT( ii )->name ) vips_buf_appendf( buf, "vips_image \"%s\"", IOBJECT( ii )->name ); else vips_buf_appendf( buf, "vips_image " ); if( !top ) vips_buf_appends( buf, ")" ); } else if( PEISMANAGED( base ) ) { Managed *managed; if( !(managed = PEGETMANAGED( base )) ) vips_buf_appendf( buf, "" ); else { vips_buf_appendf( buf, "<%s ", G_OBJECT_TYPE_NAME( managed ) ); iobject_info( IOBJECT( managed ), buf ); vips_buf_appends( buf, ">" ); } } else if( PEISCLASS( base ) ) { Compile *compile = PEGETCLASSCOMPILE( base ); PElement params; int i; if( !top ) vips_buf_appends( buf, "(" ); symbol_qualified_name( compile->sym, buf ); /* Skip over the secrets, then decompile all the args. */ PEGETCLASSSECRET( ¶ms, base ); for( i = 0; i < compile->nsecret; i++ ) { HeapNode *hn = PEGETVAL( ¶ms ); PEPOINTRIGHT( hn, ¶ms ); } for( i = 0; i < compile->nparam; i++ ) { HeapNode *hn = PEGETVAL( ¶ms ); HeapNode *sv = GETLEFT( hn ); PElement value; PEPOINTRIGHT( sv, &value ); vips_buf_appends( buf, " " ); if( !itext_decompile_element( buf, &value, FALSE ) ) return( FALSE ); PEPOINTRIGHT( hn, ¶ms ); } if( !top ) vips_buf_appends( buf, ")" ); } else if( PEISSYMREF( base ) ) vips_buf_appends( buf, IOBJECT( PEGETSYMREF( base ) )->name ); else if( PEISTAG( base ) ) vips_buf_appends( buf, PEGETTAG( base ) ); else graph_pelement( rc->heap, buf, base, TRACE_FUNCTIONS ); return( TRUE ); } /* Little wrapper ... used for formatting error messages, etc. FALSE for eval * error. */ static gboolean itext_decompile( Reduce *rc, VipsBuf *buf, PElement *root ) { /* Evaluate and print off values. */ if( !reduce_pelement( rc, reduce_spine, root ) ) return( FALSE ); if( !itext_decompile_element( buf, root, TRUE ) && !buf->full ) /* Tally eval failed, and buffer is not full ... must * have been an eval error. */ return( FALSE ); return( TRUE ); } /* Print function for computed values. top is TRUE only for the very top level * output. bracket means we should bracket compound expressions. */ static gboolean itext_add_element( VipsBuf *buf, PElement *base, gboolean top, gboolean bracket ) { gboolean result; /* Set the value label for a tally entry. */ if( PEISNOVAL( base ) ) vips_buf_appends( buf, _( "no value" ) ); else if( PEISREAL( base ) ) vips_buf_appendf( buf, "%.7g", PEGETREAL( base ) ); else if( PEISBOOL( base ) ) vips_buf_appends( buf, bool_to_char( PEGETBOOL( base ) ) ); else if( PEISCHAR( base ) ) { vips_buf_appends( buf, "'" ); itext_add_char( (int) PEGETCHAR( base ), buf ); vips_buf_appends( buf, "'" ); } else if( PEISCOMPLEX( base ) ) { itext_add_complex( PEGETREALPART( base ), PEGETIMAGPART( base ), buf ); } else if( PEISMANAGEDSTRING( base ) ) { Managedstring *managedstring = PEGETMANAGEDSTRING( base ); if( !top ) vips_buf_appends( buf, "\"" ); vips_buf_appends( buf, managedstring->string ); if( !top ) vips_buf_appends( buf, "\"" ); } else if( PEISELIST( base ) ) { vips_buf_appends( buf, "[ ]" ); } else if( !heap_is_string( base, &result ) ) /* Eval error. */ return( FALSE ); else if( result ) { /* Only generate quotes for non-top-level string objects. */ if( !top ) vips_buf_appends( buf, "\"" ); /* Print string contents. */ if( heap_map_list( base, (heap_map_list_fn) itext_add_string, buf, NULL ) ) return( FALSE ); if( !top ) vips_buf_appends( buf, "\"" ); } else if( PEISLIST( base ) ) { gboolean first = TRUE; vips_buf_appends( buf, "[" ); if( heap_map_list( base, (heap_map_list_fn) itext_add_list, buf, &first ) ) return( FALSE ); vips_buf_appends( buf, "]" ); } else if( PEISIMAGE( base ) ) { vips_buf_appendf( buf, "<" ); vips_buf_appendi( buf, imageinfo_get( FALSE, PEGETII( base ) ) ); vips_buf_appendf( buf, ">" ); } else if( PEISMANAGED( base ) ) { Managed *managed = PEGETMANAGED( base ); vips_buf_appends( buf, "<" ); iobject_info( IOBJECT( managed ), buf ); vips_buf_appends( buf, ">" ); } else if( PEISCLASS( base ) ) { Compile *compile = PEGETCLASSCOMPILE( base ); PElement params; int i; if( bracket && compile->nparam ) vips_buf_appends( buf, "(" ); /* Name. */ symbol_qualified_name( compile->sym, buf ); /* Skip over the secrets, then value-ize all the args. */ PEGETCLASSSECRET( ¶ms, base ); for( i = 0; i < compile->nsecret; i++ ) { HeapNode *hn = PEGETVAL( ¶ms ); PEPOINTRIGHT( hn, ¶ms ); } for( i = 0; i < compile->nparam; i++ ) { HeapNode *hn = PEGETVAL( ¶ms ); HeapNode *sv = GETLEFT( hn ); PElement value; PEPOINTRIGHT( sv, &value ); vips_buf_appends( buf, " " ); if( !itext_add_element( buf, &value, FALSE, TRUE ) ) return( FALSE ); PEPOINTRIGHT( hn, ¶ms ); } if( bracket && compile->nparam ) vips_buf_appends( buf, ")" ); } else if( PEISSYMREF( base ) ) { Symbol *sym = PEGETSYMREF( base ); if( is_scope( sym ) ) { vips_buf_appendf( buf, "" ); } else { vips_buf_appendf( buf, "" ); } } else if( PEISTAG( base ) ) vips_buf_appendf( buf, ".%s", PEGETTAG( base ) ); else { vips_buf_appendf( buf, "<" ); vips_buf_appends( buf, _( "function" ) ); vips_buf_appendf( buf, ">" ); } return( TRUE ); } /* Little wrapper ... used for formatting error messages, etc. FALSE for eval * error. */ gboolean itext_value( Reduce *rc, VipsBuf *buf, PElement *root ) { /* Evaluate and print off values. */ if( !reduce_pelement( rc, reduce_spine, root ) ) return( FALSE ); if( !itext_add_element( buf, root, TRUE, FALSE ) && !buf->full ) /* Tally eval failed, and buffer is not full ... must * have been an eval error. */ return( FALSE ); return( TRUE ); } /* Same, but everror on eval fail. */ void itext_value_ev( Reduce *rc, VipsBuf *buf, PElement *root ) { if( !itext_value( rc, buf, root ) ) reduce_throw( rc ); } /* Decompile an Expr. */ static gboolean itext_make_decompiled_string( Expr *expr, VipsBuf *buf ) { /* Old error on this expression? */ if( expr->err ) { expr_error_get( expr ); return( FALSE ); } /* Dirty? We can't print dirty values, since we might have pointers * to deleted symbols in the heap (if we are dirty because one of our * parents has been deleted). FIXME ... this seem a bit restrictive :-( ... could just block reads of symbol pointers instead? */ if( expr->sym->dirty ) { vips_buf_appendf( buf, _( "Dirty value" ) ); return( TRUE ); } /* Evaluate and print off values. */ if( !itext_decompile( reduce_context, buf, &expr->root ) ) return( FALSE ); return( TRUE ); } /* Make a value string from an Expr. */ gboolean itext_make_value_string( Expr *expr, VipsBuf *buf ) { /* Old error on this expression? */ if( expr->err ) { expr_error_get( expr ); return( FALSE ); } /* Dirty? We can't print dirty values, since we might have pointers * to deleted symbols in the heap (if we are dirty because one of our * parents has been deleted). FIXME ... this seem a bit restrictive :-( ... could just block reads of symbol pointers instead? */ if( expr->sym->dirty ) { vips_buf_appendf( buf, _( "Dirty value" ) ); return( TRUE ); } /* Evaluate and print off values. */ if( !itext_value( reduce_context, buf, &expr->root ) ) return( FALSE ); return( TRUE ); } static void * itext_update_model( Heapmodel *heapmodel ) { iText *itext = ITEXT( heapmodel ); Row *row = HEAPMODEL( itext )->row; Expr *expr = row->expr; #ifdef DEBUG printf( "itext_update_model: " ); row_name_print( row ); if( row->sym && row->sym->dirty ) printf( " (dirty)" ); printf( "\n" ); #endif /*DEBUG*/ vips_buf_set_dynamic( &itext->value, LINELENGTH ); vips_buf_set_dynamic( &itext->decompile, LINELENGTH ); if( expr ) { if( !itext_make_value_string( expr, &itext->value ) || !itext_make_decompiled_string( expr, &itext->decompile ) ) expr_error_set( expr ); } #ifdef DEBUG printf( "itext_update_model: " ); row_name_print( row ); printf( " has value: %s\n", vips_buf_all( &itext->value ) ); #endif /*DEBUG*/ /* If this is a non-edited row, update the source. */ if( !itext->edited || row == row->top_row ) { const char *new_formula; if( expr && expr->compile && expr->compile->rhstext ) new_formula = expr->compile->rhstext; else new_formula = vips_buf_all( &itext->decompile ); IM_SETSTR( itext->formula_default, new_formula ); /* Don't use itext_set_formula(), as we don't want to set * _modified or recomp. */ IM_SETSTR( itext->formula, itext->formula_default ); } return( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ); } /* Build param lists. */ static void * itext_update_heap_sub( Symbol *sym, VipsBuf *buf ) { vips_buf_appendf( buf, "%s ", IOBJECT( sym )->name ); return( NULL ); } /* heapmodel->modified is set ... parse, compile, and mark for recomp. */ static void * itext_update_heap( Heapmodel *heapmodel ) { iText *itext = ITEXT( heapmodel ); Row *row = heapmodel->row; Expr *expr = row->expr; #ifdef DEBUG printf( "itext_update_heap: " ); row_name_print( HEAPMODEL( itext )->row ); printf( "\n" ); #endif /*DEBUG*/ /* We can have no modified text, but come here anyway. For example, we * could try eval, find an error due to an undefined symbol, and have * to retry later. Clearing the row error later will mark us modified, * even though we have no text of our own. */ if( itext->formula ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); ParseRhsSyntax syntax; if( row->sym && is_super( row->sym ) ) { /* A super member ... special syntax. */ vips_buf_appendf( &buf, "%s", itext->formula ); syntax = PARSE_SUPER; } else { /* Build a new params + '=' + rhs string. */ if( expr->compile ) (void) slist_map( expr->compile->param, (SListMapFn) itext_update_heap_sub, &buf ); vips_buf_appendf( &buf, "= %s;", itext->formula ); syntax = PARSE_PARAMS; } /* Parse and compile. */ expr_error_clear( expr ); attach_input_string( vips_buf_all( &buf ) ); if( !parse_rhs( expr, syntax ) ) { expr_error_set( expr ); return( heapmodel ); } } /* Mark for recomp. */ (void) expr_dirty( expr, link_serial_new() ); return( HEAPMODEL_CLASS( parent_class )->update_heap( heapmodel ) ); } static void * itext_clear_edited( Heapmodel *heapmodel ) { iText *itext = ITEXT( heapmodel ); #ifdef DEBUG printf( "itext_clear_edited: " ); row_name_print( HEAPMODEL( itext )->row ); printf( "\n" ); #endif /*DEBUG*/ if( itext->edited ) { itext_set_edited( itext, FALSE ); /* FIXME ... formula_default is not always set for cloned edited rows! fix this properly */ if( itext->formula_default ) itext_set_formula( itext, itext->formula_default ); else printf( "itext_clear_edited: FIXME!\n" ); if( heapmodel->row->expr ) expr_dirty( heapmodel->row->expr, link_serial_new() ); /* Don't clear HEAPMODEL( itext )->modified, we want to make * sure we re-parse and compile the default value to break any * old links we might have. */ } return( HEAPMODEL_CLASS( parent_class )->clear_edited( heapmodel ) ); } static void itext_parent_add( iContainer *child ) { iText *itext = ITEXT( child ); Row *row; g_assert( IS_RHS( child->parent ) ); ICONTAINER_CLASS( parent_class )->parent_add( child ); row = HEAPMODEL( itext )->row; #ifdef DEBUG printf( "itext_new: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ /* Top rows default to edited. */ if( row == row->top_row ) itext->edited = TRUE; } static gboolean itext_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { iText *itext = ITEXT( model ); char formula[MAX_STRSIZE]; char formula2[MAX_STRSIZE]; g_assert( IS_RHS( parent ) ); if( get_sprop( xnode, "formula", formula, MAX_STRSIZE ) ) { model_loadstate_rewrite( state, formula, formula2 ); itext_set_formula( itext, formula2 ); itext_set_edited( itext, TRUE ); } return( MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ); } static View * itext_view_new( Model *model, View *parent ) { return( itextview_new() ); } static xmlNode * itext_save( Model *model, xmlNode *xnode ) { iText *itext = ITEXT( model ); Row *row = HEAPMODEL( model )->row; xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( itext->edited || row->top_row == row ) if( !set_sprop( xthis, "formula", itext->formula ) ) return( NULL ); return( xthis ); } static void itext_class_init( iTextClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->finalize = itext_finalize; iobject_class->info = itext_info; icontainer_class->parent_add = itext_parent_add; model_class->view_new = itext_view_new; model_class->save = itext_save; model_class->load = itext_load; heapmodel_class->update_model = itext_update_model; heapmodel_class->update_heap = itext_update_heap; heapmodel_class->clear_edited = itext_clear_edited; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void itext_init( iText *itext ) { Model *model = MODEL( itext ); model->display = FALSE; itext->formula = NULL; itext->formula_default = NULL; vips_buf_init( &itext->value ); vips_buf_init( &itext->decompile ); vips_buf_set_dynamic( &itext->value, LINELENGTH ); vips_buf_set_dynamic( &itext->decompile, LINELENGTH ); itext->edited = FALSE; /* Some defaults changed in _parent_add() above. */ } GType itext_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( iTextClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) itext_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( iText ), 32, /* n_preallocs */ (GInstanceInitFunc) itext_init, }; type = g_type_register_static( TYPE_HEAPMODEL, "iText", &info, 0 ); } return( type ); } iText * itext_new( Rhs *rhs ) { iText *itext; itext = ITEXT( g_object_new( TYPE_ITEXT, NULL ) ); icontainer_child_add( ICONTAINER( rhs ), ICONTAINER( itext ), -1 ); return( itext ); } void itext_set_edited( iText *itext, gboolean edited ) { Heapmodel *heapmodel = HEAPMODEL( itext ); if( itext->edited != edited ) { #ifdef DEBUG printf( "itext_set_edited: " ); row_name_print( heapmodel->row ); printf( " %s\n", bool_to_char( edited ) ); #endif /*DEBUG*/ itext->edited = edited; iobject_changed( IOBJECT( itext ) ); } if( edited ) heapmodel_set_modified( heapmodel, TRUE ); } gboolean itext_set_formula( iText *itext, const char *formula ) { if( !itext->formula || strcmp( itext->formula, formula ) != 0 ) { #ifdef DEBUG printf( "itext_set_formula: " ); row_name_print( HEAPMODEL( itext )->row ); printf( " \"%s\"\n", formula ); #endif /*DEBUG*/ IM_SETSTR( itext->formula, formula ); heapmodel_set_modified( HEAPMODEL( itext ), TRUE ); iobject_changed( IOBJECT( itext ) ); return( TRUE ); } return( FALSE ); } nip2-8.7.1/src/managedstring.c0000644000175000017500000001341513351443023013100 00000000000000/* a managed FILE* ... for lazy file read */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static ManagedClass *parent_class = NULL; /* Track all instances here. */ static GHashTable *managedstring_all = NULL; #ifdef DEBUG /* Number of managed strings, number we have expanded to the heap. */ int managed_total = 0; int managed_expanded = 0; #endif /*DEBUG*/ static void managedstring_finalize( GObject *gobject ) { Managedstring *managedstring = MANAGEDSTRING( gobject ); #ifdef DEBUG printf( "managedstring_finalize: \"%s\", ", managedstring->string ); iobject_print( IOBJECT( managedstring ) ); #endif /*DEBUG*/ #ifdef DEBUG { PElement pe; PEPOINTE( &pe, &managedstring->e ); if( !PEISNOVAL( &pe ) ) managed_expanded -= 1; managed_total -= 1; } #endif /*DEBUG*/ heap_unregister_element( MANAGED( managedstring )->heap, &managedstring->e ); g_hash_table_remove( managedstring_all, managedstring ); IM_FREE( managedstring->string ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void managedstring_info( iObject *iobject, VipsBuf *buf ) { Managedstring *managedstring = MANAGEDSTRING( iobject ); vips_buf_appendf( buf, "managedstring->string = \"%s\"\n", managedstring->string ); IOBJECT_CLASS( parent_class )->info( iobject, buf ); } /* Hash and equality for a managed string: we need the string and the heap to * match. */ static unsigned int managedstring_hash( Managedstring *managedstring ) { return( g_str_hash( managedstring->string ) | GPOINTER_TO_UINT( ((Managed *) managedstring)->heap ) ); } static gboolean managedstring_equal( Managedstring *a, Managedstring *b ) { return( ((Managed *) a)->heap == ((Managed *) b)->heap && g_str_equal( a->string, b->string ) ); } static void managedstring_all_init( void ) { if( !managedstring_all ) managedstring_all = g_hash_table_new( (GHashFunc) managedstring_hash, (GEqualFunc) managedstring_equal ); } static void managedstring_class_init( ManagedstringClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = managedstring_finalize; iobject_class->info = managedstring_info; managedstring_all_init(); } static void managedstring_init( Managedstring *managedstring ) { #ifdef DEBUG printf( "managedstring_init: %p\n", managedstring ); #endif /*DEBUG*/ #ifdef DEBUG managed_total += 1; #endif /*DEBUG*/ managedstring->string = NULL; managedstring->e.type = ELEMENT_NOVAL; managedstring->e.ele = NULL; } GType managedstring_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ManagedstringClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) managedstring_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Managedstring ), 32, /* n_preallocs */ (GInstanceInitFunc) managedstring_init, }; type = g_type_register_static( TYPE_MANAGED, "Managedstring", &info, 0 ); } return( type ); } static Managedstring * managedstring_new( Heap *heap, const char *string ) { Managedstring *managedstring; #ifdef DEBUG printf( "managedstring_new: %p, %s\n", heap, string ); #endif /*DEBUG*/ /* Disallow "" as string, we want to represent that as []. */ g_assert( strcmp( string, "" ) != 0 ); managedstring = g_object_new( TYPE_MANAGEDSTRING, NULL ); managed_link_heap( MANAGED( managedstring ), heap ); heap_register_element( heap, &managedstring->e ); if( !(managedstring->string = im_strdup( NULL, string )) ) return( NULL ); g_assert( !g_hash_table_lookup( managedstring_all, managedstring ) ); g_hash_table_insert( managedstring_all, managedstring, managedstring ); MANAGED( managedstring )->hash = managedstring_hash( managedstring ); return( managedstring ); } Managedstring * managedstring_lookup( Heap *heap, const char *string ) { Managedstring managedstring; ((Managed *) &managedstring)->heap = heap; managedstring.string = string; managedstring_all_init(); return( g_hash_table_lookup( managedstring_all, &managedstring ) ); } Managedstring * managedstring_find( Heap *heap, const char *string ) { Managedstring *managedstring; if( !(managedstring = managedstring_lookup( heap, string )) ) if( !(managedstring = managedstring_new( heap, string )) ) return( NULL ); return( managedstring ); } gboolean managedstring_get( Managedstring *managedstring, PElement *out ) { PElement pe; PEPOINTE( &pe, &managedstring->e ); if( PEISNOVAL( &pe ) ) { if( !heap_string_new( MANAGED( managedstring )->heap, managedstring->string, &pe ) ) return( FALSE ); #ifdef DEBUG managed_expanded += 1; printf( "expanding %s to the heap\n", managedstring->string ); printf( "\t(%d of %d now expanded)\n", managed_expanded, managed_total ); #endif /*DEBUG*/ } PEPUTE( out, &managedstring->e ); return( TRUE ); } nip2-8.7.1/src/optionview.h0000644000175000017500000000332513351443023012464 00000000000000/* a optionview in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_OPTIONVIEW (optionview_get_type()) #define OPTIONVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_OPTIONVIEW, Optionview )) #define OPTIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_OPTIONVIEW, OptionviewClass )) #define IS_OPTIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_OPTIONVIEW )) #define IS_OPTIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_OPTIONVIEW )) typedef struct _Optionview { Graphicview parent_object; GtkWidget *label; GtkWidget *hbox; GtkWidget *options; /* The [[char]] we set on the previous refresh. Use this to avoid * rebuilding the optionmenu unless we have to. */ GSList *labels; } Optionview; typedef struct _OptionviewClass { GraphicviewClass parent_class; /* My methods. */ } OptionviewClass; GtkType optionview_get_type( void ); View *optionview_new( void ); nip2-8.7.1/src/imagemodel.h0000644000175000017500000001023413351443023012361 00000000000000/* All the model stuff for the widgets making up a single imageview window. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IMAGEMODEL (imagemodel_get_type()) #define IMAGEMODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IMAGEMODEL, Imagemodel )) #define IMAGEMODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IMAGEMODEL, ImagemodelClass)) #define IS_IMAGEMODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEMODEL )) #define IS_IMAGEMODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEMODEL )) #define IMAGEMODEL_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IMAGEMODEL, ImagemodelClass )) /* Input states. */ typedef enum _ImagemodelState { IMAGEMODEL_SELECT = 0, /* Pointer */ IMAGEMODEL_PAN, /* Hand panner */ IMAGEMODEL_MAGIN, /* Zoom in */ IMAGEMODEL_MAGOUT, /* Zoom out */ IMAGEMODEL_DROPPER, /* Ink dropper */ IMAGEMODEL_PEN, /* Pen */ IMAGEMODEL_LINE, /* Line drawing tool */ IMAGEMODEL_RECT, /* Rectangle tool */ IMAGEMODEL_FLOOD, /* Flood-fill tool */ IMAGEMODEL_BLOB, /* Blob flood-fill tool */ IMAGEMODEL_TEXT, /* Text tool */ IMAGEMODEL_SMUDGE, /* Blur */ IMAGEMODEL_LAST } ImagemodelState; struct _Imagemodel { iObject parent_class; /* Context. */ iImage *iimage; /* iImage we represent, if any */ guint iimage_changed_sid; guint iimage_destroy_sid; /* State held in sub-objects. */ Conversion *conv; /* Conversion to screen */ guint conv_changed_sid; guint conv_imageinfo_changed_sid; Rect visible; /* Visible part of canvas */ /* Input state. */ ImagemodelState state; ImagemodelState save_state; /* Old state, during temp actions */ ImagemodelState pend_state; /* To-be state, during delayed switch */ /* Rulers. */ gboolean show_rulers; gboolean rulers_mm; gboolean rulers_offset; /* Status bar. */ gboolean show_status; /* Paintbox. */ gboolean show_paintbox; /* Visible/not */ int nib_radius; /* Selected radius */ Imageinfo *nib; /* Generated nib mask */ Imageinfo *ink; /* 1x1 pixel ink image */ char *font_name; /* Selected font name */ char *text; /* Text to render */ Imageinfo *text_mask; /* As a bitmap */ Rect text_area; /* Text geometry */ /* Display control bar. */ gboolean show_convert; double scale; /* Contrast/brightness */ double offset; gboolean falsecolour; /* False colour display on */ gboolean type; /* Interpret type field */ }; typedef struct _ImagemodelClass { iObjectClass parent_class; /* Imagemodel has a new imageinfo. */ void (*imageinfo_changed)( Imagemodel * ); } ImagemodelClass; void *imagemodel_imageinfo_changed( Imagemodel *imagemodel ); gboolean imagemodel_state_paint( ImagemodelState state ); GType imagemodel_get_type( void ); Imagemodel *imagemodel_new( iImage *iimage ); gboolean imagemodel_set_state( Imagemodel *imagemodel, ImagemodelState state, GtkWidget *parent ); void imagemodel_set_rulers( Imagemodel *imagemodel, gboolean show_rulers ); void imagemodel_set_paintbox( Imagemodel *imagemodel, gboolean show_paintbox ); void imagemodel_set_status( Imagemodel *imagemodel, gboolean show_status ); void imagemodel_set_convert( Imagemodel *imagemodel, gboolean show_convert ); gboolean imagemodel_refresh_text( Imagemodel *imagemodel ); gboolean imagemodel_refresh_nib( Imagemodel *imagemodel ); void imagemodel_paint_recalc( Imagemodel *imagemodel ); nip2-8.7.1/src/prefcolumnview.h0000644000175000017500000000325313351443023013326 00000000000000/* view of a column in a preferences window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PREFCOLUMNVIEW (prefcolumnview_get_type()) #define PREFCOLUMNVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_PREFCOLUMNVIEW, Prefcolumnview )) #define PREFCOLUMNVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_PREFCOLUMNVIEW, PrefcolumnviewClass )) #define IS_PREFCOLUMNVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PREFCOLUMNVIEW )) #define IS_PREFCOLUMNVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PREFCOLUMNVIEW )) struct _Prefcolumnview { View view; /* Display parts. */ GtkWidget *lab; /* Prefcolumnview name label */ }; typedef struct _PrefcolumnviewClass { ViewClass parent_class; /* My methods. */ } PrefcolumnviewClass; GtkType prefcolumnview_get_type( void ); View *prefcolumnview_new( void ); nip2-8.7.1/src/rhs.h0000644000175000017500000000420613351443023011054 00000000000000/* the rhs of a row ... group together everything to the right of the * button */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_RHS (rhs_get_type()) #define RHS( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_RHS, Rhs )) #define RHS_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_RHS, RhsClass)) #define IS_RHS( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_RHS )) #define IS_RHS_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_RHS )) #define RHS_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_RHS, RhsClass )) /* Which children are visible. */ typedef enum { RHS_GRAPHIC = 1, /* Graphical display */ RHS_SCOL = 2, /* Class browser display */ RHS_ITEXT = 4 /* Textual display */ } RhsFlags; struct _Rhs { Heapmodel parent_class; int vislevel; /* Visibility level */ RhsFlags flags; /* Which children we want visible */ Model *graphic; /* Graphic display ... toggle/slider/etc */ Model *scol; /* Class display */ Model *itext; /* Text display */ }; typedef struct _RhsClass { HeapmodelClass parent_class; /* My methods. */ } RhsClass; GType rhs_get_type( void ); Rhs *rhs_new( Row *row ); void rhs_set_vislevel( Rhs *rhs, int vislevel ); void rhs_vislevel_up( Rhs *rhs ); void rhs_vislevel_down( Rhs *rhs ); gboolean rhs_child_edited( Rhs *rhs ); nip2-8.7.1/src/imageview.h0000644000175000017500000000354713351443023012244 00000000000000/* Decls for imageview.c ... display an image in a window. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IMAGEVIEW (imageview_get_type()) #define IMAGEVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_IMAGEVIEW, Imageview )) #define IMAGEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_IMAGEVIEW, ImageviewClass )) #define IS_IMAGEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IMAGEVIEW )) #define IS_IMAGEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEVIEW )) typedef struct _Imageview { Floatwindow parent_class; /* Model stuff here. */ Imagemodel *imagemodel; guint imagemodel_changed_sid; Imagepresent *ip; Conversionview *cv; Statusview *sv; Paintboxview *pbv; } Imageview; typedef struct _ImageviewClass { FloatwindowClass parent_class; /* My methods. */ } ImageviewClass; GtkType imageview_get_type( void ); void imageview_set_paint( Imageview *iv, gboolean paint ); Imageview *imageview_new( iImage *iimage, GtkWidget *parent ); Imageview *imageview_new_area( iImage *iimage, Rect *area, GtkWidget *parent ); nip2-8.7.1/src/plotmodel.c0000644000175000017500000001161613351443023012255 00000000000000/* the model parts of a plot window .. all the window components watch this */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static iObjectClass *parent_class = NULL; static void plotmodel_dispose( GObject *gobject ) { Plotmodel *plotmodel; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_PLOTMODEL( gobject ) ); plotmodel = PLOTMODEL( gobject ); #ifdef DEBUG printf( "plotmodel_dispose %p: ", plotmodel ); iobject_print( IOBJECT( plotmodel ) ); #endif /*DEBUG*/ /* My instance destroy stuff. */ FREESID( plotmodel->changed_sid, plotmodel->plot ); FREESID( plotmodel->destroy_sid, plotmodel->plot ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void plotmodel_finalize( GObject *gobject ) { #ifdef DEBUG Plotmodel *plotmodel = PLOTMODEL( gobject ); printf( "plotmodel_finalize: %p\n", plotmodel ); #endif /*DEBUG*/ G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void plotmodel_changed( iObject *iobject ) { Plotmodel *plotmodel = PLOTMODEL( iobject ); #ifdef DEBUG printf( "plotmodel_changed:\n" ); #endif /*DEBUG*/ prefs_set( "DISPLAY_STATUS", "%s", bool_to_char( plotmodel->show_status ) ); IOBJECT_CLASS( parent_class )->changed( iobject ); } static void plotmodel_class_init( PlotmodelClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = plotmodel_dispose; gobject_class->finalize = plotmodel_finalize; iobject_class->changed = plotmodel_changed; /* Create signals. */ /* Init methods. */ } static void plotmodel_init( Plotmodel *plotmodel ) { #ifdef DEBUG printf( "plotmodel_init: %p\n", plotmodel ); #endif /*DEBUG*/ plotmodel->changed_sid = 0; plotmodel->destroy_sid = 0; plotmodel->width = -1; plotmodel->height = -1; plotmodel->mag = 100; plotmodel->show_status = DISPLAY_STATUS; } GType plotmodel_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( PlotmodelClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) plotmodel_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Plotmodel ), 32, /* n_preallocs */ (GInstanceInitFunc) plotmodel_init, }; type = g_type_register_static( TYPE_IOBJECT, "Plotmodel", &info, 0 ); } return( type ); } static void plotmodel_plot_destroy_cb( Plot *plot, Plotmodel *plotmodel ) { plotmodel->plot = NULL; plotmodel->destroy_sid = 0; plotmodel->changed_sid = 0; } static void plotmodel_plot_changed_cb( Plot *plot, Plotmodel *plotmodel ) { iobject_changed( IOBJECT( plotmodel ) ); } static void plotmodel_link( Plotmodel *plotmodel, Plot *plot ) { /* Don't need to listen for "destroy": our enclosing Floatwindow does * that. */ plotmodel->plot = plot; plotmodel->destroy_sid = g_signal_connect( G_OBJECT( plot ), "destroy", G_CALLBACK( plotmodel_plot_destroy_cb ), plotmodel ); plotmodel->changed_sid = g_signal_connect( G_OBJECT( plot ), "changed", G_CALLBACK( plotmodel_plot_changed_cb ), plotmodel ); } Plotmodel * plotmodel_new( Plot *plot ) { Plotmodel *plotmodel = g_object_new( TYPE_PLOTMODEL, NULL ); plotmodel_link( plotmodel, plot ); return( plotmodel ); } void plotmodel_set_mag( Plotmodel *plotmodel, int mag ) { /* Don't let mag get too large or small. GtkPlotCanvas does not * display large magnifications at all well. */ mag = IM_CLIP( 100, mag, 800 ); if( plotmodel->mag != mag ) { #ifdef DEBUG printf( "plotmodel_set_mag: %d\n", mag ); #endif /*DEBUG*/ plotmodel->mag = mag; /* Invaidate width so the canvas is regenerated. */ plotmodel->width = -1; iobject_changed( IOBJECT( plotmodel ) ); } } void plotmodel_set_status( Plotmodel *plotmodel, gboolean show_status ) { if( plotmodel->show_status != show_status ) { #ifdef DEBUG printf( "plotmodel_set_status: %d\n", show_status ); #endif /*DEBUG*/ plotmodel->show_status = show_status; iobject_changed( IOBJECT( plotmodel ) ); } } nip2-8.7.1/src/action.h0000644000175000017500000000167013351443023011537 00000000000000/* Graph actions. */ /* A strict action on the graph. */ typedef void (*ActionFn)( Reduce *, Compile *, int, const char *, HeapNode **, PElement *, void * ); /* A sort of reducer (eg. lazy or strict, or hyperstrict) */ typedef void (*ReduceFunction)( Reduce *, PElement * ); #define OPERATOR_NAME( OP ) ( \ (int) (OP) >= 0 && (int) (OP) < noperator_table ? \ operator_table[(int) (OP)] : "" \ ) extern const char *operator_table[]; extern const int noperator_table; void action_proc_uop( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out ); void action_proc_construct( Reduce *rc, Compile *compile, HeapNode **arg, PElement *out ); void action_proc_bop( Reduce *rc, Compile *compile, BinOp bop, HeapNode **arg ); void action_dispatch( Reduce *rc, Compile *compile, ReduceFunction rfn, int op, const char *name, gboolean override, ActionFn afn, int nargs, HeapNode **arg, void *user ); nip2-8.7.1/src/icontainer.h0000644000175000017500000001333713351443023012420 00000000000000/* abstract base class for containers */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_ICONTAINER (icontainer_get_type()) #define ICONTAINER( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_ICONTAINER, iContainer )) #define ICONTAINER_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_ICONTAINER, iContainerClass)) #define IS_ICONTAINER( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_ICONTAINER )) #define IS_ICONTAINER_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_ICONTAINER )) #define ICONTAINER_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_ICONTAINER, iContainerClass )) /* Test for is C a child of P. */ #define ICONTAINER_IS_CHILD( P, C ) \ (g_slist_find( ICONTAINER( P )->children, ICONTAINER( C ) ) && \ ICONTAINER( C )->parent == ICONTAINER( P )) struct _iContainer { iObject parent_object; /* My instance vars. */ GSList *children; /* iContainers which are inside this one */ int pos; /* Position in parent */ iContainer *parent; /* iContainer we are inside */ GHashTable *child_hash; /* Optional: hash of children by their name */ /* Can have a currently selected child ... eg. the * current column in a workspace, or the current tab in a * workspacegroup. * * NULL if not relevant. */ iContainer *current; /* Track the view here during reparent. */ View *temp_view; }; typedef struct _iContainerClass { iObjectClass parent_class; /* pos_changed our pos has changed child_add a child has been added to us child_remove a child is about be removed from us parent_add parent has been attached parent_remove parent is about to be removed current make the current of parent child_detach on old parent, unlink child child_attach on new_paerent, link on child there are used as a pair to do reparent -- the old parent gets a chance to detach in ::parent_detach, the new parent attaches in ::child_attach */ void (*pos_changed)( iContainer *icontainer ); void (*child_add)( iContainer *parent, iContainer *child, int ); void (*child_remove)( iContainer *parent, iContainer *child ); void (*parent_add)( iContainer *child ); void (*parent_remove)( iContainer *child ); void (*current)( iContainer *parent, iContainer *child ); void (*child_detach)( iContainer *parent, iContainer *child ); void (*child_attach)( iContainer *parent, iContainer *child, int ); } iContainerClass; typedef void *(*icontainer_map_fn)( iContainer *, void *, void * ); typedef void *(*icontainer_map3_fn)( iContainer *, void *, void *, void * ); typedef void *(*icontainer_map4_fn)( iContainer *, void *, void *, void *, void * ); typedef void *(*icontainer_map5_fn)( iContainer *, void *, void *, void *, void *, void * ); typedef gint (*icontainer_sort_fn)( iContainer *a, iContainer *b ); int icontainer_get_n_children( iContainer *icontainer ); iContainer *icontainer_get_nth_child( iContainer *icontainer, int n ); GSList *icontainer_get_children( iContainer *icontainer ); void *icontainer_map( iContainer *icontainer, icontainer_map_fn fn, void *a, void *b ); void *icontainer_map3( iContainer *icontainer, icontainer_map3_fn fn, void *a, void *b, void *c ); void *icontainer_map4( iContainer *icontainer, icontainer_map4_fn fn, void *a, void *b, void *c, void *d ); void *icontainer_map5( iContainer *icontainer, icontainer_map5_fn fn, void *a, void *b, void *c, void *d, void *e ); void *icontainer_map_rev( iContainer *icontainer, icontainer_map_fn fn, void *a, void *b ); void *icontainer_map_all( iContainer *icontainer, icontainer_map_fn fn, void *a ); void *icontainer_map2_all( iContainer *icontainer, icontainer_map_fn fn, void *a, void *b ); void *icontainer_map3_all( iContainer *icontainer, icontainer_map3_fn fn, void *a, void *b, void *c ); void *icontainer_map4_all( iContainer *icontainer, icontainer_map4_fn fn, void *a, void *b, void *c, void *d ); void *icontainer_map_all_intrans( iContainer *icontainer, icontainer_map_fn fn, void *a ); void icontainer_sanity( iContainer *icontainer ); void icontainer_pos_sort( iContainer *icontainer ); int icontainer_pos_last( iContainer *icontainer ); void icontainer_pos_renumber( iContainer *icontainer ); void icontainer_custom_sort( iContainer *icontainer, GCompareFunc fn ); gint icontainer_name_compare( iContainer *a, iContainer *b ); void icontainer_child_add( iContainer *icontainer, iContainer *child, int pos ); void icontainer_child_add_before( iContainer *parent, iContainer *child, iContainer *before ); void icontainer_child_move( iContainer *child, int pos ); void *icontainer_child_remove( iContainer *child ); void icontainer_current( iContainer *parent, iContainer *child ); iContainer *icontainer_next( iContainer *parent ); void icontainer_reparent( iContainer *parent, iContainer *child, int pos ); GType icontainer_get_type( void ); void icontainer_set_hash( iContainer *icontainer ); iContainer *icontainer_child_lookup( iContainer *parent, const char *name ); nip2-8.7.1/src/real.h0000644000175000017500000000265213351443023011206 00000000000000/* a real in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_REAL (real_get_type()) #define REAL( obj ) (GTK_CHECK_CAST( (obj), TYPE_REAL, Real )) #define REAL_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_REAL, RealClass )) #define IS_REAL( obj ) (GTK_CHECK_TYPE( (obj), TYPE_REAL )) #define IS_REAL_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_REAL )) typedef struct _Real { Value parent_object; /* Private ... build iobject caption here. */ } Real; typedef struct _RealClass { ValueClass parent_class; /* My methods. */ } RealClass; GType real_get_type( void ); nip2-8.7.1/src/reduce.c0000644000175000017500000012560113351443023011525 00000000000000/* Graph reducer. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* trace each regeneration #define DEBUG_REGEN */ /* trace each reduction #define DEBUG_TRACE */ /* trace copies of code from compile heap to main heap. #define DEBUG_COPY */ /* trace just member regeneration #define DEBUG_REGEN_MEMBER */ /* Turn on WHNF tests. #define WHNF_DEBUG */ /* regular tests that we stay in weak head normal form #define WHNF_DEBUG */ /* State of the reduction engine. */ Reduce *reduce_context; /* Index with a CombinatorType, get the number of args that combinator takes. COMB_S = 0, COMB_SL, COMB_SR, COMB_I, COMB_K, COMB_GEN, */ static int nargs[] = {3, 3, 3, 1, 2, 3}; /* Recomps this time. */ int reduce_total_recomputations = 0; /* The current expr being reduced. Used for computation feedback messages. */ static Expr *reduce_current_expr = NULL; /* Eval error here. Longjmp back a ways. */ void reduce_throw( Reduce *rc ) { if( !rc->running ) error( "panic: uncaught exception in reduce_throw()!" ); else longjmp( rc->error[--rc->running], -1 ); } static gboolean reduce_safe_pointer_wrap( Reduce *rc, PElement *out, reduce_safe_pointer_fn fn, void *a, void *b, void *c, void *d, void **result ) { REDUCE_CATCH_START( FALSE ); *result = fn( rc, out, a, b, c, d ); REDUCE_CATCH_STOP; return( TRUE ); } /* Call a function, passing in a "safe" PElement ... ie. the PElement points * at a fresh element which will be safe from the GC. */ void * reduce_safe_pointer( Reduce *rc, reduce_safe_pointer_fn fn, void *a, void *b, void *c, void *d ) { Element e; PElement pe; void *result; e.type = ELEMENT_NOVAL; e.ele = (void *) 12; PEPOINTE( &pe, &e ); heap_register_element( rc->heap, &e ); if( !reduce_safe_pointer_wrap( rc, &pe, fn, a, b, c, d, &result ) ) { heap_unregister_element( rc->heap, &e ); reduce_throw( rc ); } heap_unregister_element( rc->heap, &e ); return( result ); } void reduce_error_typecheck( Reduce *rc, PElement *e, const char *name, const char *type ) { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); error_top( _( "Typecheck error." ) ); vips_buf_appendf( &buf, _( "%s expected %s, instead saw:" ), name, type ); vips_buf_appends( &buf, "\n " ); itext_value_ev( rc, &buf, e ); error_sub( "%s", vips_buf_all( &buf ) ); reduce_throw( rc ); } static void reduce_error_toobig( Reduce *rc, const char *name ) { error_top( _( "Overflow error." ) ); error_sub( _( "%s too long." ), name ); reduce_throw( rc ); } /* 'get' a list: convert a MANAGEDSTRING into a list, if necessary. */ void reduce_get_list( Reduce *rc, PElement *list ) { if( !heap_get_list( list ) ) reduce_throw( rc ); } /* Map over a heap list. Reduce the list spine as we go, don't reduce the * heads. */ void * reduce_map_list( Reduce *rc, PElement *base, reduce_map_list_fn fn, void *a, void *b ) { PElement e = *base; reduce_spine( rc, &e ); if( !PEISLIST( &e ) ) reduce_error_typecheck( rc, &e, "reduce_map_list", "list" ); while( PEISFLIST( &e ) ) { PElement head; void *res; reduce_get_list( rc, &e ); /* Apply user function to the head. */ PEGETHD( &head, &e ); if( (res = fn( rc, &head, a, b )) ) return( res ); /* Reduce the tail. */ PEGETTL( &e, &e ); reduce_spine( rc, &e ); } return( NULL ); } typedef struct _ReduceMapDict { reduce_map_dict_fn fn; void *a; void *b; } ReduceMapDict; static void * reduce_map_dict_entry( Reduce *rc, PElement *head, ReduceMapDict *map_dict ) { char key[256]; PElement p1, p2; void *result; reduce_spine( rc, head ); if( !PEISFLIST( head ) ) reduce_error_typecheck( rc, head, "reduce_map_dict", "[*]" ); reduce_get_list( rc, head ); PEGETHD( &p1, head ); reduce_get_string( rc, &p1, key, 256 ); PEGETTL( &p2, head ); reduce_spine( rc, &p2 ); if( !PEISFLIST( &p2 ) ) reduce_error_typecheck( rc, &p2, "reduce_map_dict", "[*]" ); reduce_get_list( rc, &p2 ); PEGETHD( &p1, &p2 ); if( (result = map_dict->fn( rc, key, &p1, map_dict->a, map_dict->b )) ) return( result ); PEGETTL( &p1, &p2 ); reduce_spine( rc, &p1 ); if( !PEISELIST( &p1 ) ) reduce_error_typecheck( rc, &p1, "reduce_map_dict", "[]" ); return( NULL ); } /* Map over a list of ["key", value] pairs. */ void * reduce_map_dict( Reduce *rc, PElement *base, reduce_map_dict_fn fn, void *a, void *b ) { ReduceMapDict map_dict; map_dict.fn = fn; map_dict.a = a; map_dict.b = b; return( reduce_map_list( rc, base, (reduce_map_list_fn) reduce_map_dict_entry, &map_dict, NULL ) ); } static void * reduce_clone_list_sub( Reduce *rc, PElement *head, PElement *out ) { PElement lhs; if( !heap_list_add( rc->heap, out, &lhs ) ) reduce_throw( rc ); PEPUTPE( &lhs, head ); heap_list_next( out ); return( NULL ); } /* Clone a list ... just clone the spine, copy pointers to the heads. Reduce * the list as we go (strict shallow clone). We update out as we go, so that * on return it points to the tail (always []) of the cloned list. */ void reduce_clone_list( Reduce *rc, PElement *base, PElement *out ) { heap_list_init( out ); (void) reduce_map_list( rc, base, (reduce_map_list_fn) reduce_clone_list_sub, out, NULL ); } /* Sub-fn of below. Add a character to the buffer. */ static void * reduce_add_char( Reduce *rc, PElement *base, char **buf, int *sz ) { /* Overflow? */ if( *sz == 0 ) reduce_error_toobig( rc, "[char]" ); /* Reduce this list element. */ reduce_spine( rc, base ); /* Should be a char. */ if( !PEISCHAR( base ) ) reduce_error_typecheck( rc, base, "reduce_add_char", "char" ); /* Add to buffer. */ **buf = PEGETCHAR( base ); (*buf)++; (*sz)--; return( NULL ); } /* Evaluate a PElement into a string buffer. Return the number of characters * in string, not including '\0' terminator. */ int reduce_get_string( Reduce *rc, PElement *base, char *buf, int n ) { int sz = n - 1; reduce_spine( rc, base ); if( PEISMANAGEDSTRING( base ) ) { /* A static string ... rather than expanding to a list and * parsing, we can copy directly. */ Managedstring *managedstring = PEGETMANAGEDSTRING( base ); im_strncpy( buf, managedstring->string, n ); sz -= strlen( buf ); } else { (void) reduce_map_list( rc, base, (reduce_map_list_fn) reduce_add_char, &buf, &sz ); /* Add '\0' terminator. */ *buf = '\0'; } return( n - sz - 1 ); } static void * reduce_get_lstring_sub( Reduce *rc, PElement *base, GSList **labels, int *n ) { char buf[MAX_STRSIZE]; (void) reduce_get_string( rc, base, buf, MAX_STRSIZE ); *labels = g_slist_append( *labels, g_strdup( buf ) ); return( NULL ); } /* Evaluate to [[char]]. Return the number of strings we read. */ int reduce_get_lstring( Reduce *rc, PElement *base, GSList **labels ) { int n; n = 0; *labels = NULL; (void) reduce_map_list( rc, base, (reduce_map_list_fn) reduce_get_lstring_sub, labels, &n ); return( n ); } /* Get an element as a boolean. */ gboolean reduce_get_bool( Reduce *rc, PElement *base ) { reduce_spine( rc, base ); if( !PEISBOOL( base ) ) reduce_error_typecheck( rc, base, "reduce_get_bool", "bool" ); return( PEGETBOOL( base ) ); } /* Get an element as a real. */ double reduce_get_real( Reduce *rc, PElement *base ) { /* Reduce this element. */ reduce_spine( rc, base ); /* Should be a real. */ if( !PEISREAL( base ) ) reduce_error_typecheck( rc, base, "reduce_get_real", "real" ); return( PEGETREAL( base ) ); } /* Get an element as a class. */ void reduce_get_class( Reduce *rc, PElement *base ) { /* Reduce this element. */ reduce_spine( rc, base ); /* Should be a class. */ if( !PEISCLASS( base ) ) reduce_error_typecheck( rc, base, "reduce_get_class", "class" ); } /* Get an element as an image. */ Imageinfo * reduce_get_image( Reduce *rc, PElement *base ) { /* Reduce this element. */ reduce_spine( rc, base ); /* Should be an image. */ if( !PEISIMAGE( base ) ) reduce_error_typecheck( rc, base, "reduce_get_image", "image" ); return( PEGETII( base ) ); } /* Sub-fn of below. Add a real to the buffer. */ static void * reduce_add_real( Reduce *rc, PElement *base, double **buf, int *sz ) { /* Overflow? */ if( *sz == 0 ) reduce_error_toobig( rc, "[real]" ); /* Add to buffer. */ **buf = reduce_get_real( rc, base ); (*buf)++; (*sz)--; return( NULL ); } /* Get an element as a realvec. Return length of vector. */ int reduce_get_realvec( Reduce *rc, PElement *base, double *buf, int n ) { int sz = n; (void) reduce_map_list( rc, base, (reduce_map_list_fn) reduce_add_real, &buf, &sz ); return( n - sz ); } /* Sub-fn of below. Add an ii to the buffer. */ static void * reduce_add_image( Reduce *rc, PElement *base, Imageinfo ***buf, int *sz ) { /* Overflow? */ if( *sz == 0 ) reduce_error_toobig( rc, "[image]" ); /* Add to buffer. */ **buf = reduce_get_image( rc, base ); (*buf)++; (*sz)--; return( NULL ); } /* Get an element as a realvec. Return length of vector. */ int reduce_get_imagevec( Reduce *rc, PElement *base, Imageinfo **buf, int n ) { int sz = n; (void) reduce_map_list( rc, base, (reduce_map_list_fn) reduce_add_image, &buf, &sz ); return( n - sz ); } /* Test for 1st sz elements are reals. Init sz < 0 for unlimited test. */ static void * reduce_test_real( Reduce *rc, PElement *base, int *sz ) { /* Tested enough? */ if( *sz == 0 ) return( NULL ); (void) reduce_get_real( rc, base ); (*sz)--; return( NULL ); } /* Sub fn ... get the length of a list of real. */ int reduce_get_real_size( Reduce *rc, PElement *base ) { int n; n = -1; (void) reduce_map_list( rc, base, (reduce_map_list_fn) reduce_test_real, &n, NULL ); return( -1 - n ); } /* Sub fn of below ... get the length of one line from a matrix. */ static void * reduce_get_line_size( Reduce *rc, PElement *base, int *w, int *h ) { int l; l = reduce_get_real_size( rc, base ); if( *w == 0 ) *w = l; else if( *w != l ) { error_top( _( "Not rectangular." ) ); error_sub( _( "Matrix of real is not rectangular. " "Found row of length %d, should be %d." ), l, *w ); reduce_throw( rc ); } *h += 1; return( NULL ); } /* Find the size of a matrix. Write xsize/ysize to args. */ void reduce_get_matrix_size( Reduce *rc, PElement *base, int *xsize, int *ysize ) { int w, h; w = 0; h = 0; (void) reduce_map_list( rc, base, (reduce_map_list_fn) reduce_get_line_size, &w, &h ); if( w == 0 || h == 0 ) { error_top( _( "Zero dimension." ) ); error_sub( _( "Matrix has width %d, height %d." ), w, h ); reduce_throw( rc ); } *xsize = w; *ysize = h; } /* Track stuff during a get_matrix in one of these. */ typedef struct { double *buf; /* Start of output buffer */ int mx; /* Size of output buffer */ int w, h; /* Size of matrix we have generated */ int i; /* Current write point */ } GetMatrixInfo; /* Sub-fn of below ... get another line of the matrix. */ static void * reduce_get_line( Reduce *rc, PElement *base, GetMatrixInfo *gmi ) { int l; int remain = gmi->mx - gmi->i; /* Read next line from matrix. */ l = reduce_get_realvec( rc, base, gmi->buf + gmi->i, remain ); /* Overflow? */ if( l > remain ) reduce_error_toobig( rc, "Matrix" ); /* 1st line? */ if( gmi->h == 0 ) gmi->w = l; else if( l != gmi->w ) { error_top( _( "Not rectangular." ) ); error_sub( _( "Matrix of real is not rectangular. " "Found row of length %d, should be %d." ), l, gmi->w ); reduce_throw( rc ); } /* Move pointers on! */ gmi->h++; gmi->i += l; return( NULL ); } /* Get an element as a matrix. Return length of buffer used. * Write xsize/ysize to args. */ int reduce_get_matrix( Reduce *rc, PElement *base, double *buf, int n, int *xsize, int *ysize ) { GetMatrixInfo gmi; gmi.buf = buf; gmi.mx = n; gmi.w = gmi.h = 0; gmi.i = 0; (void) reduce_map_list( rc, base, (reduce_map_list_fn) reduce_get_line, &gmi, NULL ); *xsize = gmi.w; *ysize = gmi.h; return( gmi.i ); } /* Test for object is the empty list. */ gboolean reduce_is_elist( Reduce *rc, PElement *base ) { reduce_spine( rc, base ); if( PEISELIST( base ) ) return( TRUE ); return( FALSE ); } /* Test for object is any list. */ gboolean reduce_is_list( Reduce *rc, PElement *base ) { reduce_spine( rc, base ); if( PEISLIST( base ) ) return( TRUE ); return( FALSE ); } /* Sub-fn of below. Test for 1st sz elements are char. We have several * possible return values :-( * * - evaluation error ... we can throw an exception * - we find a non-char in the first n elements ... return -1 * - we have tested the first n and want to stop looking ... return -2 * - all OK so far, but we want to keep looking ... return NULL */ static void * reduce_test_char( Reduce *rc, PElement *base, int *sz ) { /* Tested enough? */ if( *sz == 0 ) return( (void *) -2 ); /* Reduce this list element. */ reduce_spine( rc, base ); /* Should be a char. */ if( !PEISCHAR( base ) ) return( (void *) -1 ); /* Move on. */ (*sz)--; return( NULL ); } /* Test the first n elements of a list are char. n < 0 means test all * elements. */ static gboolean reduce_n_is_string( Reduce *rc, PElement *base, int sz ) { void *result; reduce_spine( rc, base ); /* We know managedstrings are strings without needing to expand them. */ if( PEISMANAGEDSTRING( base ) ) return( TRUE ); /* reduce_map_list() will throw an exeception if we give it a * non-list. */ if( !PEISLIST( base ) ) return( FALSE ); result = reduce_map_list( rc, base, (reduce_map_list_fn) reduce_test_char, &sz, NULL ); if( result == (void *) -1 ) return( FALSE ); return( TRUE ); } /* Test for object is string. Just test the first few elements, so we * allow infinite strings. */ gboolean reduce_is_string( Reduce *rc, PElement *base ) { return( reduce_n_is_string( rc, base, 4 ) ); } /* Test for list is a finite string. */ gboolean reduce_is_finitestring( Reduce *rc, PElement *base ) { return( reduce_n_is_string( rc, base, -1 ) ); } /* Test for list is realvec. */ gboolean reduce_is_realvec( Reduce *rc, PElement *base ) { int sz = 4; reduce_spine( rc, base ); if( !PEISLIST( base ) ) return( FALSE ); if( reduce_map_list( rc, base, (reduce_map_list_fn) reduce_test_real, &sz, NULL ) ) return( FALSE ); return( TRUE ); } /* Test for 1st sz elements are reals. Init sz < 0 for unlimited test. */ static void * reduce_test_image( Reduce *rc, PElement *base, int *sz ) { /* Tested enough? */ if( *sz == 0 ) return( NULL ); (void) reduce_get_image( rc, base ); (*sz)--; return( NULL ); } /* Test for list is imagevec. */ gboolean reduce_is_imagevec( Reduce *rc, PElement *base ) { int sz = 4; reduce_spine( rc, base ); if( !PEISLIST( base ) ) return( FALSE ); if( reduce_map_list( rc, base, (reduce_map_list_fn) reduce_test_image, &sz, NULL ) ) return( FALSE ); return( TRUE ); } /* Sub-fn of below ... test another line of the matrix. */ static void * reduce_test_line( Reduce *rc, PElement *base, int *w, int *h ) { /* Test next line from matrix. */ if( !reduce_is_realvec( rc, base ) ) return( base ); return( NULL ); } /* Test for object is [[real]] .. don't test for rectangularness. */ gboolean reduce_is_matrix( Reduce *rc, PElement *base ) { reduce_spine( rc, base ); if( !PEISLIST( base ) ) return( FALSE ); if( reduce_map_list( rc, base, (reduce_map_list_fn) reduce_test_line, NULL, NULL ) ) return( FALSE ); return( TRUE ); } /* Test for object is a class. */ gboolean reduce_is_class( Reduce *rc, PElement *klass ) { reduce_spine( rc, klass ); if( PEISCLASS( klass ) ) return( TRUE ); return( FALSE ); } /* Test for instance is an exact instance ... ie. no inheritance. FIXME ... yuk! strcmp()!! */ gboolean reduce_is_instanceof_exact( Reduce *rc, const char *name, PElement *instance ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( !reduce_is_class( rc, instance ) ) return( FALSE ); symbol_qualified_name( PEGETCLASSCOMPILE( instance )->sym, &buf ); if( strcmp( name, vips_buf_all( &buf ) ) == 0 ) return( TRUE ); return( FALSE ); } /* Test for thing is an instance of the named class symbol. */ gboolean reduce_is_instanceof( Reduce *rc, const char *name, PElement *instance ) { PElement super; reduce_spine( rc, instance ); if( !PEISCLASS( instance ) ) return( FALSE ); if( reduce_is_instanceof_exact( rc, name, instance ) ) return( TRUE ); if( class_get_super( instance, &super ) && !PEISELIST( &super ) ) return( reduce_is_instanceof( rc, name, &super ) ); return( FALSE ); } /* Find the length of a list, with a bailout for the largest size we test. * Handy for avoiding finding the length of "[1..]". */ int reduce_list_length_max( Reduce *rc, PElement *base, int max_length ) { PElement p; int i; /* Reduce to first element. */ p = *base; reduce_spine( rc, &p ); /* Does it look like the start of a list? */ if( !PEISLIST( &p ) ) reduce_error_typecheck( rc, &p, _( "List length" ), "list" ); if( PEISMANAGEDSTRING( &p ) ) { Managedstring *managedstring = PEGETMANAGEDSTRING( &p ); i = strlen( managedstring->string ); } else { /* Loop down list. */ for( i = 0; PEISFLIST( &p ); i++ ) { HeapNode *hn; if( max_length != -1 && i > max_length ) reduce_error_toobig( rc, "list" ); reduce_get_list( rc, &p ); hn = PEGETVAL( &p ); PEPOINTRIGHT( hn, &p ); reduce_spine( rc, &p ); } g_assert( PEISELIST( &p ) ); } return( i ); } /* Find the length of a list. */ int reduce_list_length( Reduce *rc, PElement *base ) { return( reduce_list_length_max( rc, base, -1 ) ); } /* Point "out" at the nth element of a list. Index from 0. */ void reduce_list_index( Reduce *rc, PElement *base, int n, PElement *out ) { PElement p; int i; HeapNode *hn; if( n < 0 ) { error_top( _( "Bad argument." ) ); error_sub( _( "List index must be positive, not %d" ), n ); reduce_throw( rc ); } p = *base; reduce_spine( rc, &p ); if( !PEISLIST( &p ) ) reduce_error_typecheck( rc, &p, _( "List index" ), "list" ); for( i = n;; ) { if( PEISELIST( &p ) ) { error_top( _( "Bad argument." ) ); error_sub( _( "List only has %d elements, " "unable to get element %d." ), n - i, n ); reduce_throw( rc ); } g_assert( PEISFLIST( &p ) ); reduce_get_list( rc, &p ); hn = PEGETVAL( &p ); PEPOINTRIGHT( hn, &p ); if( --i < 0 ) break; reduce_spine( rc, &p ); } if( trace_flags & TRACE_OPERATOR ) { VipsBuf *buf = trace_push(); trace_pelement( base ); vips_buf_appendf( buf, " \"?\" %d ->\n", n ); } PEPOINTLEFT( hn, out ); if( trace_flags & TRACE_OPERATOR ) { trace_result( TRACE_OPERATOR, out ); trace_pop(); } } /* No args allowed error. */ static void argserror( Reduce *rc, PElement *a ) { char txt[MAX_ERROR_FRAG]; VipsBuf buf = VIPS_BUF_STATIC( txt ); itext_value_ev( rc, &buf, a ); error_top( _( "No arguments allowed." ) ); error_sub( _( "Object \"%s\" should have no arguments." ), vips_buf_all( &buf ) ); reduce_throw( rc ); } #ifdef WHNF_DEBUG /* Test for PElement is in weak head-normal form. */ static gboolean is_WHNF( PElement *out ) { PElement spine; int i; HeapNode *hn; Symbol *sym; Compile *compile; int na; /* Might be a base type ... */ if( PEISREAL( out ) || PEISCOMPLEX( out ) || PEISNUM( out ) || PEISCHAR( out ) || PEISBOOL( out ) || PEISTAG( out ) || PEISIMAGE( out ) || PEISLIST( out ) || PEISCLASS( out ) || PEISSYMREF( out ) || PEISCOMPILEREF( out ) || PEISNOVAL( out ) ) return( TRUE ); /* Must be a function or generator ... loop down the spine, counting * args. */ for( spine = *out, i = 0; PEGETTYPE( &spine ) == ELEMENT_NODE; i++ ) { hn = PEGETVAL( &spine ); if( hn->type != TAG_APPL ) break; PEPOINTLEFT( PEGETVAL( &spine ), &spine ); } if( PEISBINOP( &spine ) ) { if( i > 1 ) return( FALSE ); } else if( PEISUNOP( &spine ) ) { if( i > 0 ) return( FALSE ); } else if( PEISCOMB( &spine ) ) { if( i > nargs[(int) PEGETCOMB( &spine )] - 1 ) return( FALSE ); } else if( PEISCONSTRUCTOR( &spine ) ) { compile = PEGETCOMPILE( &spine ); na = compile->nparam + compile->nsecret; if( i > na ) { printf( "constructor %s with %d args ", symbol_name( sym ), i ); printf( "should have %d args\n", compile->nparam ); return( FALSE ); } } else if( PEISSYMBOL( &spine ) ) { /* If it's a VIPS or a builtin with too few args, it's OK. */ sym = SYMBOL( PEGETVAL( &spine ) ); if( sym->type == SYM_EXTERNAL ) { if( i < sym->fn_nargs ) return( TRUE ); } else if( sym->type == SYM_BUILTIN ) { if( i < sym->builtin->nargs ) return( TRUE ); } /* Nope ... should have been reduced. */ return( FALSE ); } else { return( FALSE ); } return( TRUE ); } #endif /*WHNF_DEBUG*/ /* Main reduction machine loop. */ void reduce_spine( Reduce *rc, PElement *out ) { Heap *heap = rc->heap; PElement np; /* Check for possible C stack overflow ... can't go over 2M on most * systems if we're using (or any of our libs are using) threads. */ if( (char *) main_c_stack_base - (char *) &rc > 2000000 ) { error_top( _( "Overflow error." ) ); error_sub( _( "C stack overflow. Expression too complex." ) ); reduce_throw( rc ); } /* Point node pointer at reduction start. */ np = *out; /* Start a new frame. */ RSPUSHFRAME( rc, out ); reduce_start: reduce_total_recomputations += 1; if( (reduce_total_recomputations % 100000) == 0 ) { if( progress_update_expr( reduce_current_expr ) ) { error_top( _( "Cancelled." ) ); error_sub( _( "Evaluation cancelled." ) ); reduce_throw( rc ); } } #ifdef DEBUG_TRACE { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( rc->heap, &buf, out, TRUE ); printf( "reduce_spine: %s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_TRACE*/ switch( PEGETTYPE( &np ) ) { case ELEMENT_CHAR: case ELEMENT_BOOL: case ELEMENT_ELIST: case ELEMENT_TAG: case ELEMENT_SYMREF: case ELEMENT_COMPILEREF: case ELEMENT_MANAGED: /* Base type .. no more reduction needed. */ /* Should have no args. */ if( RSFRAMESIZE( rc ) != 0 ) argserror( rc, &np ); break; case ELEMENT_CONSTRUCTOR: { Compile *compile; HeapNode **arg; PElement rhs1; int na; /* Class constructor. */ compile = PEGETCOMPILE( &np ); g_assert( is_class( compile ) ); /* Class args ... real params, secret params. */ na = compile->nparam + compile->nsecret; /* Get args. */ if( !RSCHECKARGS( rc, na ) ) break; arg = &RSGET( rc, na - 1 ); if( na == 0 ) { /* Zero args ... just construct on top of the current * node pointer. */ action_proc_construct( rc, compile, arg, &np ); goto reduce_start; } /* Overwrite RHS of arg[0], make LHS into COMB_I. */ PEPOINTRIGHT( arg[0], &rhs1 ); action_proc_construct( rc, compile, arg, &rhs1 ); PPUTLEFT( arg[0], ELEMENT_COMB, COMB_I ); RSPOP( rc, na ); if( RSFRAMEEMPTY( rc ) ) np = RSGETWB( rc ); else PEPOINTLEFT( RSGET( rc, 0 ), &np ); PEPUTP( &np, GETRT( arg[0] ), GETRIGHT( arg[0] ) ); goto reduce_start; } case ELEMENT_SYMBOL: { Symbol *sym = PEGETSYMBOL( &np ); g_assert( sym ); switch( sym->type ) { case SYM_VALUE: { Compile *compile = sym->expr->compile; /* Make sure it's clean ... we can get * links to dirty syms through dynamic dependencies. */ if( sym->dirty ) { error_top( _( "No value." ) ); error_sub( _( "Symbol \"%s\" has no value." ), symbol_name( sym ) ); reduce_throw( rc ); } /* We copy code, but link to values. We have to take a * fresh copy of code as (together with any args our * context might supply) it will expand to a value, * which we might then edit in a row. We want to make * sure any edits do not zap the original code. */ if( compile->nparam + compile->nsecret == 0 ) { /* Make sure the value has copied to the main * heap. */ if( PEISNOVAL( &sym->expr->root ) ) { gboolean res; res = reduce_regenerate( sym->expr, &sym->expr->root ); expr_new_value( sym->expr ); if( !res ) reduce_throw( rc ); } /* Link to this sym's value. */ PEPUTPE( &np, &sym->expr->root ); } else /* Copy compiled code from the private compile * heap. */ if( !heap_copy( rc->heap, compile, &np ) ) reduce_throw( rc ); goto reduce_start; } case SYM_PARAM: /* All params should be taken out by var abstract. */ printf( "sym-param found, argh: " ); symbol_name_print( sym ); printf( "\n" ); g_assert( FALSE ); break; case SYM_EXTERNAL: { HeapNode **arg; int na; /* A VIPS function. */ na = sym->fn_nargs; /* Get args. */ if( !RSCHECKARGS( rc, na ) ) /* Not enough ... function result. */ break; /* Run strictly. */ arg = &RSGET( rc, na - 1 ); action_dispatch( rc, NULL, reduce_spine, -1, sym->function->name, FALSE, (ActionFn) call_run, na, arg, sym->function ); /* Find output element. */ RSPOP( rc, na ); if( RSFRAMEEMPTY( rc ) ) np = RSGETWB( rc ); else PEPOINTLEFT( RSGET( rc, 0 ), &np ); /* Write to node above. */ PEPUTP( &np, GETRT( arg[0] ), GETRIGHT( arg[0] ) ); goto reduce_start; } case SYM_BUILTIN: { HeapNode **arg; int na; /* A builtin function. */ na = sym->builtin->nargs; /* Get args. */ if( !RSCHECKARGS( rc, na ) ) /* Not enough ... function result. */ break; /* Run strictly. */ arg = &RSGET( rc, na - 1 ); action_dispatch( rc, NULL, reduce_spine, -1, sym->builtin->name, sym->builtin->override, (ActionFn) builtin_run, na, arg, sym->builtin ); /* Find output element. */ RSPOP( rc, na ); if( RSFRAMEEMPTY( rc ) ) np = RSGETWB( rc ); else PEPOINTLEFT( RSGET( rc, 0 ), &np ); /* Write to node above. */ PEPUTP( &np, GETRT( arg[0] ), GETRIGHT( arg[0] ) ); goto reduce_start; } case SYM_ZOMBIE: { Symbol *new_sym; /* Could be defined on an enclosing scope. Search * outwards for a definition. */ if( !(new_sym = compile_resolve_top( sym )) ) { symbol_not_defined( sym ); reduce_throw( rc ); } /* Zap linked symbol into graph. */ PEPUTP( &np, ELEMENT_SYMBOL, new_sym ); goto reduce_start; } case SYM_ROOT: case SYM_WORKSPACE: case SYM_WORKSPACEROOT: /* Becomes a symref ... base type. */ PEPUTP( &np, ELEMENT_SYMREF, sym ); /* Should have no args. */ if( RSFRAMESIZE( rc ) != 0 ) argserror( rc, &np ); break; default: g_assert( FALSE ); } break; } case ELEMENT_NODE: { HeapNode *hn; /* Get the node that np points to. */ hn = PEGETVAL( &np ); switch( hn->type ) { case TAG_CONS: case TAG_DOUBLE: case TAG_COMPLEX: case TAG_CLASS: /* Base type ... reduction all done! We don't test * that class's superclasses are base, as they aren't * always for non-top-level base types ... see * reduce_pelement(). */ /* Should have no args. */ if( RSFRAMESIZE( rc ) != 0 ) argserror( rc, &np ); break; case TAG_APPL: /* Function application ... push this node and loop * down the LHS looking for a combinator. */ /* Push this node. */ RSPUSH( rc, hn ); /* Move down left branch. */ PEPOINTLEFT( hn, &np ); goto reduce_start; case TAG_GEN: { double d1; double d2; double d3 = 0.0; /* keeps gcc happy */ gboolean limit; HeapNode *hn1, *hn2; /* Extract next, step, final. */ d1 = GETLEFT( hn )->body.num; d2 = GETLEFT( GETRIGHT( hn ) )->body.num; limit = GETRT( GETRIGHT( hn ) ) != ELEMENT_ELIST; if( limit ) d3 = GETRIGHT( GETRIGHT( hn ) )->body.num; if( trace_flags & TRACE_OPERATOR ) { VipsBuf *buf = trace_push(); if( limit ) vips_buf_appendf( buf, "generator %g %g %g ->\n", d1, d2, d3 ); else vips_buf_appendf( buf, "generator %g %g ->\n", d1, d2 ); } /* At end? */ if( GETRT( GETRIGHT( hn ) ) != ELEMENT_ELIST && ((d2 > 0 && d1 > d3) || (d2 < 0 && d1 < d3)) ) { /* Make I node for end. */ hn->type = TAG_APPL; PPUT( hn, ELEMENT_COMB, COMB_I, ELEMENT_ELIST, NULL ); /* Write back to node above. */ PEPUTP( &np, ELEMENT_ELIST, NULL ); if( trace_flags & TRACE_OPERATOR ) { trace_result( TRACE_OPERATOR, &np ); trace_pop(); } /* All done! */ break; } /* Not at end, or no final. Generate new gen node. */ if( NEWNODE( heap, hn1 ) ) reduce_throw( rc ); *hn1 = *hn; /* Change hn into CONS node. */ hn->type = TAG_CONS; PPUTRIGHT( hn, ELEMENT_NODE, hn1 ); /* Generate new number. */ if( NEWNODE( heap, hn2 ) ) reduce_throw( rc ); hn2->type = TAG_DOUBLE; hn2->body.num = d1 + d2; PPUTLEFT( hn1, ELEMENT_NODE, hn2 ); if( trace_flags & TRACE_OPERATOR ) { trace_result( TRACE_OPERATOR, &np ); trace_pop(); } /* And loop! */ goto reduce_start; } case TAG_FILE: { Managedfile *managedfile = MANAGEDFILE( GETLEFT( hn ) ); int ch = managedfile_getc( managedfile ); /* -1 means error, 0 means EOF. */ if( ch == -1 ) reduce_throw( rc ); else if( ch == 0 ) { /* Turn us into []. */ hn->type = TAG_APPL; PPUT( hn, ELEMENT_COMB, COMB_I, ELEMENT_ELIST, NULL ); } else { HeapNode *hn1; /* Not at end ... make another CONS. */ if( NEWNODE( heap, hn1 ) ) reduce_throw( rc ); *hn1 = *hn; hn->type = TAG_CONS; PPUT( hn, ELEMENT_CHAR, GUINT_TO_POINTER( ch ), ELEMENT_NODE, hn1 ); } /* Loop again with new np. */ goto reduce_start; } case TAG_FREE: g_assert( FALSE ); default: g_assert( FALSE ); } break; } case ELEMENT_COMB: { CombinatorType comb = PEGETCOMB( &np ); HeapNode *hn1, *hn2; HeapNode **arg; int na; na = nargs[(int) comb]; /* Get args. */ if( !RSCHECKARGS( rc, na ) ) /* Not enough ... function result. */ break; /* Extract args. */ arg = &RSGET( rc, na - 1 ); switch( comb ) { case COMB_S: /* Rewrite graph for S a b c => (a c) (b c). */ /* Make (b c) appl node. */ if( NEWNODE( heap, hn1 ) ) reduce_throw( rc ); *hn1 = *arg[0]; PPUTLEFT( hn1, GETRT( arg[1] ), GETRIGHT( arg[1] ) ); PPUTRIGHT( arg[0], ELEMENT_NODE, hn1 ); /* Make (a c) appl node. */ if( NEWNODE( heap, hn2 ) ) reduce_throw( rc ); *hn2 = *hn1; PPUTLEFT( hn2, GETRT( arg[2] ), GETRIGHT( arg[2] ) ); PPUTLEFT( arg[0], ELEMENT_NODE, hn2 ); /* End of S ... now pop three, push 1 and loop. */ RSPOP( rc, 2 ); PEPOINTLEFT( arg[0], &np ); goto reduce_start; case COMB_SL: /* Rewrite graph for Sl a b c => (a c) b. */ /* Make (a c) appl node. */ if( NEWNODE( heap, hn1 ) ) reduce_throw( rc ); *hn1 = *arg[0]; PPUTLEFT( hn1, GETRT( arg[2] ), GETRIGHT( arg[2] ) ); PPUT( arg[0], ELEMENT_NODE, hn1, GETRT( arg[1] ), GETRIGHT( arg[1] ) ); /* End of SL ... now pop three, push 1 and loop. */ RSPOP( rc, 2 ); PEPOINTLEFT( arg[0], &np ); goto reduce_start; case COMB_SR: /* Rewrite graph for Sr a b c => a (b c). */ /* Make (b c) appl node. */ if( NEWNODE( heap, hn1 ) ) reduce_throw( rc ); *hn1 = *arg[0]; PPUTLEFT( hn1, GETRT( arg[1] ), GETRIGHT( arg[1] ) ); PPUT( arg[0], GETRT( arg[2] ), GETRIGHT( arg[2] ), ELEMENT_NODE, hn1 ); /* End of SR ... now pop three, push 1 and loop. */ RSPOP( rc, 2 ); PEPOINTLEFT( arg[0], &np ); goto reduce_start; case COMB_I: /* No action necessary. */ break; case COMB_K: /* Make I node. */ PPUT( arg[0], ELEMENT_COMB, COMB_I, GETRT( arg[1] ), GETRIGHT( arg[1] ) ); break; case COMB_GEN: { double d1; double d2 = 0.0; /* Don't need to init, but */ double d3 = 0.0; /* keeps gcc happy */ PElement rhs1, rhs2, rhs3; PEPOINTRIGHT( arg[2], &rhs1 ); PEPOINTRIGHT( arg[1], &rhs2 ); PEPOINTRIGHT( arg[0], &rhs3 ); reduce_spine_strict( rc, &rhs1 ); reduce_spine_strict( rc, &rhs2 ); reduce_spine_strict( rc, &rhs3 ); /* May have done ourselves in the process. */ if( arg[0]->type != TAG_APPL ) break; /* Typecheck. */ if( !PEISREAL( &rhs1 ) ) reduce_error_typecheck( rc, &rhs1, _( "List generator" ), "real" ); d1 = PEGETREAL( &rhs1 ); if( !PEISELIST( &rhs2 ) && !PEISREAL( &rhs2 ) ) reduce_error_typecheck( rc, &rhs2, _( "List generator" ), "real" ); if( PEISREAL( &rhs2 ) ) d2 = PEGETREAL( &rhs2 ); if( !PEISELIST( &rhs3 ) && !PEISREAL( &rhs3 ) ) reduce_error_typecheck( rc, &rhs3, _( "List generator" ), "real" ); if( PEISREAL( &rhs3 ) ) d3 = PEGETREAL( &rhs3 ); if( trace_flags & TRACE_OPERATOR ) { VipsBuf *buf = trace_push(); vips_buf_appends( buf, "generator constructor " ); trace_args( arg, 3 ); } /* If next is missing, set default. */ if( PEISREAL( &rhs2 ) ) /* Next is there, calculate step. */ d2 = d2 - d1; else { /* If final is missing, default is 1. */ if( PEISELIST( &rhs3 ) ) d2 = 1; else { /* Final is there, choose 1 or -1. */ if( d1 < d3 ) d2 = 1; else d2 = -1; } } /* Make node for pairing next and final fields. */ if( NEWNODE( heap, hn1 ) ) reduce_throw( rc ); hn1->type = TAG_COMPLEX; PPUT( hn1, GETRT( arg[1] ), GETRIGHT( arg[1] ), GETRT( arg[0] ), GETRIGHT( arg[0] ) ); /* Link to old root, make gen node. */ arg[0]->type = TAG_GEN; PPUT( arg[0], GETRT( arg[2] ), GETRIGHT( arg[2] ), ELEMENT_NODE, hn1 ); /* Make step node. */ if( NEWNODE( heap, hn2 ) ) reduce_throw( rc ); hn2->type = TAG_DOUBLE; hn2->body.num = d2; PPUTLEFT( hn1, ELEMENT_NODE, hn2 ); if( trace_flags & TRACE_OPERATOR ) { VipsBuf *buf = trace_current(); vips_buf_appends( buf, " " ); trace_node( arg[0] ); vips_buf_appends( buf, "\n" ); trace_text( TRACE_OPERATOR, "%s", vips_buf_all( buf ) ); trace_pop(); } /* Find output element. */ RSPOP( rc, 3 ); if( RSFRAMEEMPTY( rc ) ) np = RSGETWB( rc ); else PEPOINTLEFT( RSGET( rc, 0 ), &np ); /* Restart from there. */ goto reduce_start; } default: g_assert( FALSE ); } /* Find output element. */ RSPOP( rc, na ); if( RSFRAMEEMPTY( rc ) ) np = RSGETWB( rc ); else PEPOINTLEFT( RSGET( rc, 0 ), &np ); /* Write to above node. */ PEPUTP( &np, GETRT( arg[0] ), GETRIGHT( arg[0] ) ); /* Loop again with new np. */ goto reduce_start; /*NOTREACHED*/ } case ELEMENT_BINOP: { BinOp bop = PEGETBINOP( &np ); HeapNode **arg; Compile *compile; PElement rhs1, rhs2; /* Three args to binops ... first is the Compile that built us * (for error messages), other two are actual args. */ if( !RSCHECKARGS( rc, 3 ) ) /* Not enough ... function result. */ break; /* Extract args. */ arg = &RSGET( rc, 2 ); compile = COMPILE( GETRIGHT( arg[2] ) ); /* CONS is very, very lazy ... more like a combinator. */ if( bop == BI_CONS ) { PEPOINTRIGHT( arg[1], &rhs1 ); if( trace_flags & TRACE_OPERATOR ) { trace_push(); PEPOINTRIGHT( arg[0], &rhs2 ); trace_binop( compile, &rhs1, bop, &rhs2 ); } arg[0]->type = TAG_CONS; PPUTLEFT( arg[0], PEGETTYPE( &rhs1 ), PEGETVAL( &rhs1 ) ); if( trace_flags & TRACE_OPERATOR ) { VipsBuf *buf = trace_current(); vips_buf_appends( buf, " " ); trace_node( arg[0] ); vips_buf_appends( buf, "\n" ); trace_text( TRACE_OPERATOR, "%s", vips_buf_all( buf ) ); trace_pop(); } RSPOP( rc, 3 ); break; } action_proc_bop( rc, compile, bop, arg ); /* Find output element. */ RSPOP( rc, 3 ); if( RSFRAMEEMPTY( rc ) ) np = RSGETWB( rc ); else PEPOINTLEFT( RSGET( rc, 0 ), &np ); /* Write to node above. */ PEPUTP( &np, GETRT( arg[0] ), GETRIGHT( arg[0] ) ); /* Loop again with new np. */ goto reduce_start; } case ELEMENT_UNOP: { HeapNode **arg; Compile *compile; /* Some unary operator. First arg is the compile that built * us, 2nd is the actual arg that might need reducing. */ if( !RSCHECKARGS( rc, 2 ) ) /* Not enough ... function result. */ break; /* Extract arg. */ arg = &RSGET( rc, 1 ); compile = COMPILE( GETRIGHT( arg[1] ) ); action_dispatch( rc, compile, reduce_spine, PEGETUNOP( &np ), OPERATOR_NAME( PEGETUNOP( &np ) ), TRUE, (ActionFn) action_proc_uop, 1, arg, NULL ); /* Find output element. */ RSPOP( rc, 2 ); if( RSFRAMEEMPTY( rc ) ) np = RSGETWB( rc ); else PEPOINTLEFT( RSGET( rc, 0 ), &np ); /* Write to above node. */ PEPUTP( &np, GETRT( arg[0] ), GETRIGHT( arg[0] ) ); /* Loop again with new np. */ goto reduce_start; } case ELEMENT_NOVAL: break; default: g_assert( FALSE ); } /* Unwind stack, restore frame pointer. */ RSPOPFRAME( rc ); #ifdef WHNF_DEBUG /* Should now be in WHNF ... test! */ if( !is_WHNF( out ) ) { char txt[1000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, out, TRUE ); printf( "*** internal error:\n" ); printf( "result of reduce_spine not in WHNF: " ); printf( "%s\n", vips_buf_all( &buf ) ); reduce_throw( rc ); } #endif /*WHNF_DEBUG*/ } /* Strict reduction ... fully eval all lists etc. */ void reduce_spine_strict( Reduce *rc, PElement *np ) { PElement rhs, lhs; /* Make sure this element is reduced. */ reduce_spine( rc, np ); /* If it's a non-empty list, may need to reduce inside. Not managed * strings though, we can leave them unevaluated. */ if( PEISFLIST( np ) && !PEISMANAGEDSTRING( np ) ) { /* Recurse for head and tail. */ HeapNode *hn = PEGETVAL( np ); PEPOINTLEFT( hn, &lhs ); PEPOINTRIGHT( hn, &rhs ); reduce_spine_strict( rc, &lhs ); reduce_spine_strict( rc, &rhs ); } } /* Free a Reduce. */ void reduce_destroy( Reduce *rc ) { heap_unregister_reduce( rc->heap, rc ); UNREF( rc->heap ); IM_FREE( rc ); } /* Max cells function for main reduce engine. Read from Preferences, and scale * by the number of workspaces we have open. */ static int reduce_heap_max_fn( Heap *heap ) { return( workspace_number() * MAX_HEAPSIZE ); } /* Build a Reduce. */ Reduce * reduce_new( void ) { /* Initial heap size. Big enough that we won't need to grow just * loading prefs and standard stuff. */ const int stsz = 100000; /* Heap increment.. */ const int incr = 2000; Reduce *rc = INEW( NULL, Reduce ); if( !rc ) return( NULL ); rc->sp = 0; rc->fsp = 0; rc->heap = NULL; rc->running = 0; rc->heap = heap_new( NULL, reduce_heap_max_fn, stsz, incr ); g_object_ref( G_OBJECT( rc->heap ) ); iobject_sink( IOBJECT( rc->heap ) ); heap_register_reduce( rc->heap, rc ); iobject_set( IOBJECT( rc->heap ), "reduce-heap", NULL ); return( rc ); } /* Reduce a PElement to a base type. Return TRUE/FALSE, no longjmp. */ gboolean reduce_pelement( Reduce *rc, ReduceFunction fn, PElement *out ) { gboolean res = TRUE; REDUCE_CATCH_START( FALSE ); fn( reduce_context, out ); REDUCE_CATCH_STOP; return( res ); } /* Make sure a symbol's value is registered with the main GC. */ void reduce_register( Symbol *sym ) { Reduce *rc = reduce_context; Heap *heap = rc->heap; heap_register_element( heap, &sym->base ); } /* Make sure a symbol's value is not registered with the main GC. */ void reduce_unregister( Symbol *sym ) { Reduce *rc = reduce_context; Heap *heap = rc->heap; heap_unregister_element( heap, &sym->base ); } /* Copy and evaluate compiled code into element pointed to by out. */ gboolean reduce_regenerate( Expr *expr, PElement *out ) { Reduce *rc = reduce_context; Heap *heap = rc->heap; /* Clear any run state from old expr value. */ expr_error_clear( expr ); if( slist_map( expr->dynamic_links, (SListMapFn) link_expr_destroy, NULL ) ) return( FALSE ); /* Copy new code in. */ if( !heap_copy( heap, expr->compile, out ) ) { expr_error_set( expr ); return( FALSE ); } #ifdef DEBUG_REGEN { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, out, TRUE ); printf( "reduce_regenerate: reducing " ); expr_name_print( expr ); printf( "graph: %s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_REGEN*/ reduce_current_expr = expr; if( !reduce_pelement( rc, reduce_spine, out ) ) { reduce_current_expr = NULL; expr_error_set( expr ); (void) heap_gc( heap ); return( FALSE ); } reduce_current_expr = NULL; #ifdef DEBUG_REGEN { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); /* Force immediate GC to pick up any stray pointers. */ if( !heap_gc( heap ) ) { expr_error_set( expr ); return( FALSE ); } graph_pelement( heap, &buf, out, TRUE ); printf( "reduce_regenerate: reduced " ); expr_name_print( expr ); printf( " to: %s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_REGEN*/ return( TRUE ); } /* Regenerate an (expr this) pair. */ gboolean reduce_regenerate_member( Expr *expr, PElement *ths, PElement *out ) { Reduce *rc = reduce_context; Heap *heap = rc->heap; PElement e; HeapNode *apl; /* New (NULL this) pair. */ if( NEWNODE( heap, apl ) ) { expr_error_set( expr ); return( FALSE ); } apl->type = TAG_APPL; PPUT( apl, ELEMENT_NOVAL, (void *) 10, PEGETTYPE( ths ), PEGETVAL( ths ) ); PEPUTP( out, ELEMENT_NODE, apl ); /* Link code to node. */ PEPOINTLEFT( apl, &e ); if( !reduce_regenerate( expr, &e ) ) return( FALSE ); #ifdef DEBUG_REGEN_MEMBER { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( heap, &buf, out, TRUE ); printf( "reduce_regenerate_member: " ); expr_name_print( expr ); printf( " new code: %s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG_REGEN_MEMBER*/ /* Do initial reduction. */ if( !reduce_pelement( rc, reduce_spine, out ) ) { /* Failure! Junk the half-made value. */ expr_error_set( expr ); (void) heap_gc( heap ); return( FALSE ); } /* Special case: if this is a "super" row, we need to rebuild the * class. */ if( is_super( expr->compile->sym ) ) { Compile *parent = compile_get_parent( expr->compile ); PElement instance; PEPOINTE( &instance, &expr->row->scol->base ); if( !class_new_super( heap, parent, ths, &instance ) ) return( FALSE ); } return( TRUE ); } nip2-8.7.1/src/iregionview.c0000644000175000017500000000366313351443023012610 00000000000000/* display a region in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static iImageviewClass *parent_class = NULL; static void iregionview_class_init( iRegionviewClass *class ) { parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ } static void iregionview_init( iRegionview *iregionview ) { #ifdef DEBUG printf( "iregionview_init\n" ); #endif /*DEBUG*/ } GtkType iregionview_get_type( void ) { static GtkType iregionview_type = 0; if( !iregionview_type ) { static const GtkTypeInfo info = { "iRegionview", sizeof( iRegionview ), sizeof( iRegionviewClass ), (GtkClassInitFunc) iregionview_class_init, (GtkObjectInitFunc) iregionview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; iregionview_type = gtk_type_unique( TYPE_IIMAGEVIEW, &info ); } return( iregionview_type ); } View * iregionview_new( void ) { iRegionview *iregionview = gtk_type_new( TYPE_IREGIONVIEW ); #ifdef DEBUG printf( "iregionview_new\n" ); #endif /*DEBUG*/ return( VIEW( iregionview ) ); } nip2-8.7.1/src/iwindow.c0000644000175000017500000006053413351443023011741 00000000000000/* make and manage base windows ... dialog (messagebox, file box), top * level windows */ /* Copyright (C) 1991-2001, The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* build interface: iwnd = iwindow_new( type ); iwindow_set_*( iwnd, ... ); iwindow_build( iwnd ); destroy interface: iwindow_kill() 'cancellable' kill ... user popdown can return IWINDOW_ERROR or IWINDOW_NO to prevent popdown gtk_widget_destroy() non-cancellable ... popdown is not called so ... don't free() in popdown, subclass iwnd and free() in _destroy() */ /* #define DEBUG */ #include "ip.h" /* Cursor bitmaps. */ #include "BITMAPS/dropper_src.xbm" #include "BITMAPS/dropper_msk.xbm" #include "BITMAPS/magin_src.xbm" #include "BITMAPS/magout_src.xbm" #include "BITMAPS/mag_msk.xbm" #include "BITMAPS/watch_1.xbm" #include "BITMAPS/watch_2.xbm" #include "BITMAPS/watch_3.xbm" #include "BITMAPS/watch_4.xbm" #include "BITMAPS/watch_5.xbm" #include "BITMAPS/watch_6.xbm" #include "BITMAPS/watch_7.xbm" #include "BITMAPS/watch_8.xbm" #include "BITMAPS/watch_msk.xbm" static GtkWindowClass *parent_class = NULL; /* List of all iwindows. */ static GSList *iwindow_all = NULL; /* All our cursors. */ static GdkCursor *iwindow_cursor[IWINDOW_SHAPE_LAST] = { NULL }; #ifdef DEBUG /* Human-readable names for cursor shapes. */ static const char *iwindow_cursor_name[] = { "IWINDOW_SHAPE_DROPPER", "IWINDOW_SHAPE_PEN", "IWINDOW_SHAPE_SMUDGE", "IWINDOW_SHAPE_SMEAR", "IWINDOW_SHAPE_TEXT", "IWINDOW_SHAPE_RECT", "IWINDOW_SHAPE_FLOOD", "IWINDOW_SHAPE_MOVE", "IWINDOW_SHAPE_EDIT", "IWINDOW_SHAPE_MAGIN", "IWINDOW_SHAPE_MAGOUT", "IWINDOW_SHAPE_TOP", "IWINDOW_SHAPE_BOTTOM", "IWINDOW_SHAPE_LEFT", "IWINDOW_SHAPE_RIGHT", "IWINDOW_SHAPE_TOPRIGHT", "IWINDOW_SHAPE_TOPLEFT", "IWINDOW_SHAPE_BOTTOMRIGHT", "IWINDOW_SHAPE_BOTTOMLEFT", "IWINDOW_SHAPE_HGLASS1", "IWINDOW_SHAPE_HGLASS2", "IWINDOW_SHAPE_HGLASS3", "IWINDOW_SHAPE_HGLASS4", "IWINDOW_SHAPE_HGLASS5", "IWINDOW_SHAPE_HGLASS6", "IWINDOW_SHAPE_HGLASS7", "IWINDOW_SHAPE_HGLASS8", "IWINDOW_SHAPE_NONE" }; #endif /*DEBUG*/ int iwindow_number( void ) { return( g_slist_length( iwindow_all ) ); } /* Pick an iwindow at random. Used if we need a window for a dialog, and we're * not sure which to pick. During shutdown we can have no windows. */ iWindow * iwindow_pick_one( void ) { if( !iwindow_all ) return( NULL ); return( IWINDOW( iwindow_all->data ) ); } /* Over all windows. */ void * iwindow_map_all( iWindowMapFn fn, void *a ) { return( slist_map( iwindow_all, (SListMapFn) fn, a ) ); } /* Make a custom cursor ... source, mask, width, height and hot spot position. */ static GdkCursor * iwindow_make_cursor_data( guchar *src_bits, guchar *msk_bits, int w, int h, int x, int y ) { GdkPixmap *src; GdkPixmap *msk; GdkCursor *cursor; GdkColor fg = { 0, 255 << 8, 255 << 8, 255 << 8 }; GdkColor bg = { 0, 0, 0, 0 }; src = gdk_bitmap_create_from_data( NULL, (const char *) src_bits, w, h ); msk = gdk_bitmap_create_from_data( NULL, (const char *) msk_bits, w, h ); cursor = gdk_cursor_new_from_pixmap( src, msk, &fg, &bg, x, y ); gdk_pixmap_unref( src ); gdk_pixmap_unref( msk ); return( cursor ); } /* Build all the cursors. */ static void iwindow_make_cursors( void ) { /* Init standard cursors with this table. */ static GdkCursorType standards[] = { GDK_CURSOR_IS_PIXMAP, /* IWINDOW_SHAPE_DROPPER */ GDK_PENCIL, /* IWINDOW_SHAPE_PEN */ GDK_HAND2, /* IWINDOW_SHAPE_SMUDGE */ GDK_SPIDER, /* IWINDOW_SHAPE_SMEAR */ GDK_GOBBLER, /* IWINDOW_SHAPE_TEXT */ GDK_SIZING, /* IWINDOW_SHAPE_RECT */ GDK_TREK, /* IWINDOW_SHAPE_FLOOD */ GDK_FLEUR, /* IWINDOW_SHAPE_MOVE */ GDK_CROSSHAIR, /* IWINDOW_SHAPE_EDIT */ GDK_CURSOR_IS_PIXMAP, /* IWINDOW_SHAPE_MAGIN */ GDK_CURSOR_IS_PIXMAP, /* IWINDOW_SHAPE_MAGOUT */ GDK_TOP_SIDE, /* IWINDOW_SHAPE_TOP */ GDK_BOTTOM_SIDE, /* IWINDOW_SHAPE_BOTTOM */ GDK_LEFT_SIDE, /* IWINDOW_SHAPE_LEFT */ GDK_RIGHT_SIDE, /* IWINDOW_SHAPE_RIGHT */ GDK_TOP_RIGHT_CORNER, /* IWINDOW_SHAPE_TOPRIGHT */ GDK_TOP_LEFT_CORNER, /* IWINDOW_SHAPE_TOPLEFT */ GDK_BOTTOM_RIGHT_CORNER,/* IWINDOW_SHAPE_BOTTOMRIGHT, */ GDK_BOTTOM_LEFT_CORNER, /* IWINDOW_SHAPE_BOTTOMLEFT */ }; /* All the bits for the rotating cursor. */ static guchar *watch_bits[] = { watch_1_bits, watch_2_bits, watch_3_bits, watch_4_bits, watch_5_bits, watch_6_bits, watch_7_bits, watch_8_bits, }; int i; if( iwindow_cursor[0] ) return; /* Easy ones first. */ for( i = 0; i < IM_NUMBER( standards ); i++ ) if( standards[i] != GDK_CURSOR_IS_PIXMAP ) iwindow_cursor[i] = gdk_cursor_new( standards[i] ); /* Custom cursors. */ iwindow_cursor[IWINDOW_SHAPE_DROPPER] = iwindow_make_cursor_data( dropper_src_bits, dropper_msk_bits, dropper_src_width, dropper_src_height, 0, 15 ); iwindow_cursor[IWINDOW_SHAPE_MAGIN] = iwindow_make_cursor_data( magin_src_bits, mag_msk_bits, mag_msk_width, mag_msk_height, 6, 6 ); iwindow_cursor[IWINDOW_SHAPE_MAGOUT] = iwindow_make_cursor_data( magout_src_bits, mag_msk_bits, mag_msk_width, mag_msk_height, 6, 6 ); /* The hglasses. */ for( i = 0; i < IM_NUMBER( watch_bits ); i++ ) iwindow_cursor[IWINDOW_SHAPE_HGLASS1 + i] = iwindow_make_cursor_data( watch_bits[i], watch_msk_bits, watch_1_width, watch_1_height, 7, 7 ); } /* Get the work window. */ static GdkWindow * iwindow_get_work_window( iWindow *iwnd ) { if( iwnd->work_window ) return( iwnd->work_window ); else return( GTK_WIDGET( iwnd )->window ); } /* Update the cursor for a window. */ static void * iwindow_cursor_update( iWindow *iwnd ) { if( GTK_WIDGET_REALIZED( GTK_WIDGET( iwnd ) ) ) { GSList *p; iWindowShape best_shape; int best_priority; /* Global shape set? Use that for the whole window. */ if( iwnd->shape != IWINDOW_SHAPE_NONE ) { gdk_window_set_cursor( GTK_WIDGET( iwnd )->window, iwindow_cursor[iwnd->shape] ); gdk_window_set_cursor( iwindow_get_work_window( iwnd ), iwindow_cursor[iwnd->shape] ); gdk_flush(); return( NULL ); } /* No global shape ... make sure there's no global cursor on * this window. */ gdk_window_set_cursor( GTK_WIDGET( iwnd )->window, NULL ); gdk_window_set_cursor( iwindow_get_work_window( iwnd ), NULL ); /* And set the work area to the highest priority non-NONE * shape we can find . FIXME ... could avoid the search if we sorted the context list by priority on each context_new(), but not very important. */ best_shape = IWINDOW_SHAPE_NONE; best_priority = -1; for( p = iwnd->contexts; p; p = p->next ) { iWindowCursorContext *cntxt = (iWindowCursorContext *) p->data; if( cntxt->shape != IWINDOW_SHAPE_NONE && cntxt->priority > best_priority ) { best_shape = cntxt->shape; best_priority = cntxt->priority; } } /* Pref to disable crosshair. */ if( best_shape == IWINDOW_SHAPE_EDIT && !DISPLAY_CROSSHAIR ) best_shape = IWINDOW_SHAPE_NONE; gdk_window_set_cursor( iwindow_get_work_window( iwnd ), iwindow_cursor[best_shape] ); gdk_flush(); } return( NULL ); } /* Set a global cursor for a window. */ static void * iwindow_cursor_set( iWindow *iwnd, iWindowShape *shape ) { if( iwnd->shape != *shape ) { iwnd->shape = *shape; iwindow_cursor_update( iwnd ); } return( NULL ); } static gboolean hourglass_showing = FALSE; static void hourglass_begin( void ) { hourglass_showing = TRUE; } static void hourglass_update( void ) { if( hourglass_showing ) { static iWindowShape shape = IWINDOW_SHAPE_HGLASS1; iwindow_map_all( (iWindowMapFn) iwindow_cursor_set, &shape ); shape += 1; if( shape > IWINDOW_SHAPE_HGLASS8 ) shape = IWINDOW_SHAPE_HGLASS1; } } static void hourglass_end( void ) { if( hourglass_showing ) { iWindowShape shape = IWINDOW_SHAPE_NONE; iwindow_map_all( (iWindowMapFn) iwindow_cursor_set, &shape ); hourglass_showing = FALSE; } } iWindowCursorContext * iwindow_cursor_context_new( iWindow *iwnd, int priority, const char *name ) { iWindowCursorContext *cntxt = INEW( NULL, iWindowCursorContext ); #ifdef DEBUG printf( "iwindow_cursor_context_new: %s\n", name ); #endif /*DEBUG*/ cntxt->iwnd = iwnd; cntxt->priority = priority; cntxt->name = name; cntxt->shape = IWINDOW_SHAPE_NONE; iwnd->contexts = g_slist_prepend( iwnd->contexts, cntxt ); return( cntxt ); } void iwindow_cursor_context_destroy( iWindowCursorContext *cntxt ) { iWindow *iwnd = cntxt->iwnd; iwnd->contexts = g_slist_remove( iwnd->contexts, cntxt ); IM_FREE( cntxt ); iwindow_cursor_update( iwnd ); } void iwindow_cursor_context_set_cursor( iWindowCursorContext *cntxt, iWindowShape shape ) { if( cntxt->shape != shape ) { #ifdef DEBUG printf( "iwindow_cursor_context_set_cursor: %s = %s\n", cntxt->name, iwindow_cursor_name[shape] ); #endif /*DEBUG*/ cntxt->shape = shape; iwindow_cursor_update( cntxt->iwnd ); } } iWindowSusp * iwindow_susp_new( iWindowFn fn, iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { iWindowSusp *susp; if( !(susp = INEW( NULL, iWindowSusp )) ) return( NULL ); susp->fn = fn; susp->iwnd = iwnd; susp->client = client; susp->nfn = nfn; susp->sys = sys; return( susp ); } /* Trigger a suspension's reply, and free it. */ void iwindow_susp_return( void *sys, iWindowResult result ) { iWindowSusp *susp = IWINDOW_SUSP( sys ); susp->nfn( susp->sys, result ); im_free( susp ); } void iwindow_susp_trigger( iWindowSusp *susp ) { susp->fn( susp->iwnd, susp->client, susp->nfn, susp->sys ); im_free( susp ); } /* Compose two iWindowFns ... if this one succeeded, trigger the next in turn. * Otherwise bail out. */ void iwindow_susp_comp( void *sys, iWindowResult result ) { iWindowSusp *susp = IWINDOW_SUSP( sys ); if( result == IWINDOW_YES ) iwindow_susp_trigger( susp ); else iwindow_susp_return( sys, result ); } /* Null window callback. */ void iwindow_true_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { nfn( sys, IWINDOW_YES ); } void iwindow_false_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { nfn( sys, IWINDOW_NO ); } /* Null notify callback. */ void iwindow_notify_null( void *client, iWindowResult result ) { } /* Final end of a window. Destroy! */ static void iwindow_final_death( iWindow *iwnd ) { #ifdef DEBUG printf( "iwindow_final_death: %s\n", iwnd->title ); #endif /*DEBUG*/ g_assert( iwnd->pending == 0 && iwnd->destroy ); /* Clean up. */ gtk_widget_destroy( GTK_WIDGET( iwnd ) ); } /* A notify comes back ... adjust the pending count. If this is a zombie and * this is the final pending, it's final death. */ void iwindow_notify_return( iWindow *iwnd ) { #ifdef DEBUG printf( "iwindow_notify_return: %s (pending = %d)\n", iwnd->title, iwnd->pending ); #endif /*DEBUG*/ g_assert( iwnd->pending > 0 ); iwnd->pending--; if( iwnd->destroy && iwnd->pending == 0 ) { #ifdef DEBUG printf( "iwindow_notify_return: zombie death %s\n", iwnd->title ); #endif /*DEBUG*/ iwindow_final_death( iwnd ); } } /* Send a notify off, tell the client to come back to back. */ void iwindow_notify_send( iWindow *iwnd, iWindowFn fn, void *client, iWindowNotifyFn back, void *sys ) { #ifdef DEBUG printf( "iwindow_notify_send: %s (pending = %d)\n", iwnd->title, iwnd->pending ); #endif /*DEBUG*/ iwnd->pending++; if( fn ) fn( iwnd, client, back, sys ); else back( sys, IWINDOW_YES ); } static void iwindow_finalize( GObject *gobject ) { iWindow *iwnd = IWINDOW( gobject ); #ifdef DEBUG printf( "iwindow_finalize: %s\n", iwnd->title ); #endif /*DEBUG*/ /* My instance destroy stuff. */ iwindow_all = g_slist_remove( iwindow_all, iwnd ); IM_FREE( iwnd->title ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); /* Last window and we've got through startup? Quit the application. */ if( iwindow_number() == 0 && !main_starting ) main_quit_test(); } static void iwindow_destroy( GtkObject *gobject ) { iWindow *iwnd = IWINDOW( gobject ); #ifdef DEBUG printf( "iwindow_destroy: %s\n", iwnd->title ); #endif /*DEBUG*/ /* My instance destroy stuff. */ FREESID( iwnd->parent_unmap_sid, iwnd->parent_window ); UNREF( iwnd->action_group ); UNREF( iwnd->ui_manager ); /* Now we've destroyed, we must stop popdown from being called, since * the view will have junked a lot of stuff. */ iwnd->destroy = TRUE; GTK_OBJECT_CLASS( parent_class )->destroy( gobject ); } static void iwindow_popdown_notify( iWindow *iwnd, iWindowResult result ) { #ifdef DEBUG printf( "iwindow_popdown_notify: %p %s\n", iwnd, iwnd->title ); #endif /*DEBUG*/ if( result == IWINDOW_ERROR ) iwindow_alert( GTK_WIDGET( iwnd ), GTK_MESSAGE_ERROR ); else if( result == IWINDOW_YES ) iwindow_kill( iwnd ); if( result != IWINDOW_YES ) { #ifdef DEBUG printf( "iwindow_popdown_notify: %s: kill cancelled!\n", iwnd->title ); #endif /*DEBUG*/ /* Cancel popdown. */ iwnd->destroy = FALSE; } else { /* Popdown confirmed! Trigger class popdown. _real_popdown() * does an unmap to hide the window during the rest of the * destroy. */ IWINDOW_GET_CLASS( iwnd )->popdown( GTK_WIDGET( iwnd ) ); } calli_string_filenamef( (calli_string_fn) gtk_accel_map_save, "%s" G_DIR_SEPARATOR_S "accel_map", get_savedir() ); /* If this is the final pending response and ->destroy is true, this * will destroy the window. */ iwindow_notify_return( iwnd ); } static gboolean iwindow_delete_event( GtkWidget *widget, GdkEventAny *event ) { iWindow *iwnd = IWINDOW( widget ); #ifdef DEBUG printf( "iwindow_delete_event: %s\n", iwnd->title ); #endif /*DEBUG*/ if( !iwnd->destroy ) { #ifdef DEBUG printf( "iwindow_delete_event: starting destroy\n" ); #endif /*DEBUG*/ iwindow_kill( iwnd ); } /* Never delete here ... wait for iwindow_popdown_notify to * confirm the kill. */ return( TRUE ); } static gboolean iwindow_configure_event( GtkWidget *widget, GdkEventConfigure *event ) { iWindow *iwnd = IWINDOW( widget ); if( iwnd->width_pref ) { /* Save window size in global prefs. */ prefs_set( iwnd->width_pref, "%d", event->width ); prefs_set( iwnd->height_pref, "%d", event->height ); } return( GTK_WIDGET_CLASS( parent_class )-> configure_event( widget, event ) ); } /* Our parent has been destroyed, kill us too. */ static void iwindow_parent_unmap_cb( GtkWidget *par, iWindow *iwnd ) { #ifdef DEBUG printf( "iwindow_parent_unmap_cb: %s\n", iwnd->title ); #endif /*DEBUG*/ /* Here for dead parent ... if parent is dead, we won't need to remove * the dead-dad signal. */ iwnd->parent_unmap_sid = 0; iwindow_kill( iwnd ); } static GtkActionEntry iwnd_actions[] = { /* Common menus. */ { "FileMenu", NULL, N_( "_File" ) }, { "NewMenu", NULL, N_( "_New" ) }, { "EditMenu", NULL, N_( "_Edit" ) }, { "ViewMenu", NULL, N_( "_View" ) }, { "HelpMenu", NULL, N_( "_Help" ) }, /* Common items. */ { "Close", GTK_STOCK_CLOSE, N_( "_Close" ), NULL, N_( "Close" ), G_CALLBACK( iwindow_kill_action_cb ) }, { "Quit", GTK_STOCK_QUIT, N_( "_Quit" ), "q", N_( "Quit nip2" ), G_CALLBACK( main_quit_test ) }, { "Guide", GTK_STOCK_HELP, N_( "_Contents" ), "F1", N_( "Open the users guide" ), G_CALLBACK( mainw_guide_action_cb ) }, { "About", NULL, N_( "_About" ), NULL, N_( "About this program" ), G_CALLBACK( mainw_about_action_cb ) }, { "Homepage", NULL, N_( "_Website" ), NULL, N_( "Open the VIPS Homepage" ), G_CALLBACK( mainw_homepage_action_cb ) } }; static void iwindow_real_build( GtkWidget *widget ) { iWindow *iwnd = IWINDOW( widget ); GdkScreen *screen = gtk_widget_get_screen( GTK_WIDGET( iwnd ) ); GtkAccelGroup *accel_group; #ifdef DEBUG printf( "iwindow_real_build: %s\n", iwnd->title ); #endif /*DEBUG*/ gtk_container_set_border_width( GTK_CONTAINER( iwnd ), 0 ); iwnd->work = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( iwnd ), iwnd->work ); /* Use the type name (eg. "Imageview") for the name of the * actiongroup. */ iwnd->action_group = gtk_action_group_new( G_OBJECT_TYPE_NAME( iwnd ) ); gtk_action_group_set_translation_domain( iwnd->action_group, GETTEXT_PACKAGE ); gtk_action_group_add_actions( iwnd->action_group, iwnd_actions, G_N_ELEMENTS( iwnd_actions ), GTK_WINDOW( iwnd ) ); iwnd->ui_manager = gtk_ui_manager_new(); gtk_ui_manager_insert_action_group( iwnd->ui_manager, iwnd->action_group, 0 ); accel_group = gtk_ui_manager_get_accel_group( iwnd->ui_manager ); gtk_window_add_accel_group( GTK_WINDOW( iwnd ), accel_group ); /* Call per-instance build. */ if( iwnd->build ) iwnd->build( iwnd, iwnd->work, iwnd->build_a, iwnd->build_b, iwnd->build_c ); if( iwnd->title ) gtk_window_set_title( GTK_WINDOW( iwnd ), iwnd->title ); if( iwnd->width_pref ) { int width = watch_int_get( main_watchgroup, iwnd->width_pref, 640 ); int height = watch_int_get( main_watchgroup, iwnd->height_pref, 480 ); gtk_window_set_default_size( GTK_WINDOW( iwnd ), IM_MIN( width, gdk_screen_get_width( screen ) ), IM_MIN( height, gdk_screen_get_height( screen ) ) ); } /* Link to parent. */ if( iwnd->parent_window ) { if( IWINDOW_GET_CLASS( iwnd )->transient && iwnd->parent_window && iwnd != iwnd->parent_window ) gtk_window_set_transient_for( GTK_WINDOW( iwnd ), GTK_WINDOW( iwnd->parent_window ) ); /* We watch our parent's "unmap" rather than "destroy" since * we use gtk_widget_unmap() to hide killed windows during * popdown (see iwindow_popdown_notify()). */ iwnd->parent_unmap_sid = gtk_signal_connect( GTK_OBJECT( iwnd->parent_window ), "unmap", GTK_SIGNAL_FUNC( iwindow_parent_unmap_cb ), iwnd ); /* Show the parent. For example, if this is the ^Q * save-or-quit dialog and the parent is a mainw, we want to * pop the mainw up. */ gtk_window_present( GTK_WINDOW( iwnd->parent_window ) ); } gtk_widget_show( iwnd->work ); } static void iwindow_real_popdown( GtkWidget *widget ) { gtk_widget_unmap( widget ); } static void iwindow_class_init( iWindowClass *class ) { GObjectClass *object_class = (GObjectClass *) class; GtkObjectClass *gobject_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; parent_class = g_type_class_peek_parent( class ); /* Init methods. */ object_class->finalize = iwindow_finalize; gobject_class->destroy = iwindow_destroy; widget_class->delete_event = iwindow_delete_event; widget_class->configure_event = iwindow_configure_event; class->build = iwindow_real_build; class->popdown = iwindow_real_popdown; class->transient = FALSE; /* Create signals. */ /* Static class data init. */ iwindow_make_cursors(); /* Link to busy signals. */ g_signal_connect( progress_get(), "begin", hourglass_begin, NULL ); g_signal_connect( progress_get(), "update", hourglass_update, NULL ); g_signal_connect( progress_get(), "end", hourglass_end, NULL ); } static void iwindow_init( iWindow *iwnd ) { #ifdef DEBUG printf( "iwindow_init: %s\n", iwnd->title ); #endif /*DEBUG*/ iwnd->work = NULL; iwnd->parent = NULL; iwnd->parent_window = NULL; iwnd->parent_unmap_sid = 0; /* Might as well. */ iwnd->accel_group = gtk_accel_group_new(); gtk_window_add_accel_group( GTK_WINDOW( iwnd ), iwnd->accel_group ); g_object_unref( iwnd->accel_group ); iwnd->infobar = NULL; iwnd->title = NULL; iwnd->build = NULL; iwnd->popdown = iwindow_true_cb; iwnd->destroy = FALSE; iwnd->pending = 0; iwnd->shape = IWINDOW_SHAPE_NONE; iwnd->contexts = NULL; iwnd->work_window = NULL; iwnd->width_pref = NULL; iwnd->height_pref = NULL; iwindow_all = g_slist_prepend( iwindow_all, iwnd ); } GtkType iwindow_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "iWindow", sizeof( iWindow ), sizeof( iWindowClass ), (GtkClassInitFunc) iwindow_class_init, (GtkObjectInitFunc) iwindow_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( GTK_TYPE_WINDOW, &info ); } return( type ); } GtkWidget * iwindow_new( GtkWindowType type ) { iWindow *iwnd = gtk_type_new( TYPE_IWINDOW ); GtkWindow *gwnd = GTK_WINDOW( iwnd ); /* Init superclass. */ gwnd->type = type; return( GTK_WIDGET( iwnd ) ); } void iwindow_set_title( iWindow *iwnd, const char *title, ... ) { va_list ap; char buf[1024]; va_start( ap, title ); (void) im_vsnprintf( buf, 1024, title, ap ); va_end( ap ); if( !iwnd->title || strcmp( iwnd->title, buf ) != 0 ) { IM_SETSTR( iwnd->title, buf ); gtk_window_set_title( GTK_WINDOW( iwnd ), iwnd->title ); } } void iwindow_set_build( iWindow *iwnd, iWindowBuildFn build, void *build_a, void *build_b, void *build_c ) { iwnd->build = build; iwnd->build_a = build_a; iwnd->build_b = build_b; iwnd->build_c = build_c; } void iwindow_set_popdown( iWindow *iwnd, iWindowFn popdown, void *popdown_a ) { iwnd->popdown = popdown; iwnd->popdown_a = popdown_a; } void iwindow_set_size_prefs( iWindow *iwnd, const char *width_pref, const char *height_pref ) { iwnd->width_pref = width_pref; iwnd->height_pref = height_pref; } void iwindow_set_work_window( iWindow *iwnd, GdkWindow *work_window ) { iwnd->work_window = work_window; iwindow_cursor_update( iwnd ); } void iwindow_set_parent( iWindow *iwnd, GtkWidget *parent ) { g_assert( !iwnd->parent ); iwnd->parent = parent; /* Get parent window now, we sometimes need it after parent has been * destroyed. */ if( parent ) iwnd->parent_window = IWINDOW( iwindow_get_root( GTK_WIDGET( parent ) ) ); } void * iwindow_kill( iWindow *iwnd ) { #ifdef DEBUG printf( "iwindow_kill: %p %s\n", iwnd, iwnd->title ); #endif /*DEBUG*/ if( !iwnd->destroy ) { #ifdef DEBUG printf( "... starting destroy for %s\n", iwnd->title ); #endif /*DEBUG*/ iwnd->destroy = TRUE; /* Don't kill directly, wait for popdown_notify to do it. */ iwindow_notify_send( iwnd, iwnd->popdown, iwnd->popdown_a, (iWindowNotifyFn) iwindow_popdown_notify, iwnd ); } return( NULL ); } /* ... as an action. */ void iwindow_kill_action_cb( GtkAction *action, iWindow *iwnd ) { iwindow_kill( iwnd ); } void iwindow_build( iWindow *iwnd ) { #ifdef DEBUG printf( "iwindow_build: %s\n", iwnd->title ); #endif /*DEBUG*/ IWINDOW_GET_CLASS( iwnd )->build( GTK_WIDGET( iwnd ) ); } /* Get the enclosing window for a widget. */ GtkWidget * iwindow_get_root( GtkWidget *widget ) { GtkWidget *toplevel = gtk_widget_get_toplevel( widget ); GtkWidget *child = gtk_bin_get_child( GTK_BIN( toplevel ) ); /* If this is a menu pane, get the widget that popped this menu up. */ if( GTK_IS_MENU( child ) ) { GtkWidget *parent = gtk_menu_get_attach_widget( GTK_MENU( child ) ); return( iwindow_get_root( parent ) ); } else return( toplevel ); } /* Get the enclosing no-parent window for a widget. */ GtkWidget * iwindow_get_root_noparent( GtkWidget *widget ) { GtkWidget *toplevel = iwindow_get_root( widget ); /* If this is a transient, get the window we popped up from. */ if( IS_IWINDOW( toplevel ) && IWINDOW( toplevel )->parent ) return( iwindow_get_root_noparent( IWINDOW( toplevel )->parent ) ); else return( toplevel ); } void iwindow_alert( GtkWidget *parent, GtkMessageType type ) { GtkWidget *toplevel; if( !parent ) parent = GTK_WIDGET( mainw_pick_one() ); if( parent && (toplevel = iwindow_get_root( parent )) && IS_IWINDOW( toplevel ) && IWINDOW( toplevel )->infobar ) infobar_set( IWINDOW( toplevel )->infobar, type, error_get_top(), "%s", error_get_sub() ); else switch( type ) { case GTK_MESSAGE_INFO: box_info( parent, error_get_top(), "%s", error_get_sub() ); break; case GTK_MESSAGE_ERROR: box_alert( parent ); break; default: break; } } nip2-8.7.1/src/workspaceview.h0000644000175000017500000000577413351443023013164 00000000000000/* a view of a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_WORKSPACEVIEW (workspaceview_get_type()) #define WORKSPACEVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_WORKSPACEVIEW, Workspaceview )) #define WORKSPACEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_WORKSPACEVIEW, WorkspaceviewClass )) #define IS_WORKSPACEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_WORKSPACEVIEW )) #define IS_WORKSPACEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEVIEW )) /* Column margins. */ #define WORKSPACEVIEW_MARGIN_LEFT (5) #define WORKSPACEVIEW_MARGIN_TOP (5) struct _Workspaceview { View view; GtkWidget *fixed; /* GtkFixed for tally */ GtkWidget *window; /* ScrolledWindow holding fixed */ Toolkitbrowser *toolkitbrowser; Workspacedefs *workspacedefs; GtkWidget *label; /* Tab label */ GtkWidget *padlock; /* The padlock icon */ GtkWidget *alert; /* The alert icon */ /* Left and right panes ... program window and toolkit browser. */ Pane *lpane; Pane *rpane; GtkWidget *popup; GtkWidget *popup_jump; /* Background window scroll. */ guint timer; int u; /* Set by columnview for bg scroll */ int v; /* Middle button drag scroll. */ gboolean dragging; int drag_x; int drag_y; /* Geometry. */ Rect vp; /* Viewport pos and size */ int width; /* Size of fixed area */ int height; Rect bounding; /* Bounding box of columnviews */ /* Placement hints for new columns. */ int next_x; int next_y; /* Context we use to change cursor shape. */ iWindowCursorContext *context; /* Follow prefs changes. */ guint watch_changed_sid; /* Only show the compat warning once. */ gboolean popped_compat; }; typedef struct _WorkspaceviewClass { ViewClass parent_class; /* My methods. */ } WorkspaceviewClass; void workspaceview_scroll( Workspaceview *wview, int x, int y, int w, int h ); void workspaceview_scroll_background( Workspaceview *wview, int u, int v ); void workspaceview_set_cursor( Workspaceview *wview, iWindowShape shape ); GtkType workspaceview_get_type( void ); View *workspaceview_new( void ); void workspaceview_set_label( Workspaceview *wview, GtkWidget *label, GtkWidget *padlock, GtkWidget *alert ); nip2-8.7.1/src/workspaceroot.c0000644000175000017500000000746213351443023013164 00000000000000/* The root of all workspaces. A singleton all workspaces are children of. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ModelClass *parent_class = NULL; static void workspaceroot_dispose( GObject *gobject ) { Workspaceroot *wsr; #ifdef DEBUG printf( "workspaceroot_dispose\n" ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_WORKSPACEROOT( gobject ) ); wsr = WORKSPACEROOT( gobject ); wsr->sym = NULL; G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void workspaceroot_child_add( iContainer *parent, iContainer *child, int pos ) { ICONTAINER_CLASS( parent_class )->child_add( parent, child, pos ); #ifdef DEBUG printf( "workspaceroot_child_add: added %s\n", IOBJECT( child )->name ); #endif /*DEBUG*/ } static void workspaceroot_child_remove( iContainer *parent, iContainer *child ) { ICONTAINER_CLASS( parent_class )->child_remove( parent, child ); } static void workspaceroot_class_init( WorkspacerootClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->dispose = workspaceroot_dispose; icontainer_class->child_add = workspaceroot_child_add; icontainer_class->child_remove = workspaceroot_child_remove; } static void workspaceroot_init( Workspaceroot *wsr ) { wsr->sym = NULL; } GType workspaceroot_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( WorkspacerootClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) workspaceroot_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Workspaceroot ), 32, /* n_preallocs */ (GInstanceInitFunc) workspaceroot_init, }; type = g_type_register_static( TYPE_MODEL, "Workspaceroot", &info, 0 ); } return( type ); } static void workspaceroot_link( Workspaceroot *wsr, const char *name ) { Symbol *sym; iobject_set( IOBJECT( wsr ), name, NULL ); wsr->sym = sym = symbol_new( symbol_root->expr->compile, name ); sym->type = SYM_WORKSPACEROOT; sym->wsr = wsr; sym->expr = expr_new( sym ); (void) compile_new( sym->expr ); symbol_made( sym ); } Workspaceroot * workspaceroot_new( const char *name ) { Workspaceroot *wsr; if( compile_lookup( symbol_root->expr->compile, name ) ) { error_top( _( "Name clash." ) ); error_sub( _( "Can't create workspaceroot \"%s\". " "A symbol with that name already exists." ), name ); return( NULL ); } wsr = WORKSPACEROOT( g_object_new( TYPE_WORKSPACEROOT, NULL ) ); workspaceroot_link( wsr, name ); return( wsr ); } /* Make up a new workspace name. */ void workspaceroot_name_new( Workspaceroot *wsr, char *name ) { Compile *compile = wsr->sym->expr->compile; strcpy( name, "tab1" ); while( compile_lookup( compile, name ) ) increment_name( name ); } nip2-8.7.1/src/compile.h0000644000175000017500000001052413351443023011710 00000000000000/* Stuff to parse and compile text. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Maximum number of shared sections of code in a copy. */ #define MAX_RELOC (1000) #define TYPE_COMPILE (compile_get_type()) #define COMPILE( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_COMPILE, Compile )) #define COMPILE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_COMPILE, CompileClass)) #define IS_COMPILE( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_COMPILE )) #define IS_COMPILE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_COMPILE )) #define COMPILE_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_COMPILE, CompileClass )) /* What we track to parse and compile some text. Our children are our locals. */ struct _Compile { iContainer parent_object; Symbol *sym; /* We are part of this symbol, scopewise */ GSList *exprs; /* We are used by these expressions */ gboolean is_klass; /* True if this is a class */ gboolean has_super; /* True if has a super-class */ char *text; /* The original text */ char *prhstext; /* Parameters plus the RHS of the definition */ char *rhstext; /* Just the RHS of the definition */ ParseNode *tree; /* Parse tree we built */ GSList *treefrag; /* List of tree bits for easy freeing */ Symbol *last_sym; /* The last child we added in this context */ int nparam; /* Number of real parameters */ GSList *param; /* Pointers into locals for real params */ int nsecret; /* Number of secret parameters */ GSList *secret; /* Pointers into locals for secret params */ Symbol *this; /* If we are a class, the "this" local */ Symbol *super; /* If we are a class, the "super" local */ GSList *children; /* Symbols which we directly refer to */ Element base; /* Base of compiled code */ Heap *heap; /* Heap containing compiled code */ GSList *statics; /* Static strings we built */ }; typedef struct _CompileClass { iContainerClass parent_class; /* My methods. */ } CompileClass; Compile *compile_get_parent( Compile *compile ); void *compile_name_print( Compile *compile ); void compile_name( Compile *compile, VipsBuf *buf ); typedef void *(*map_compile_fn)( Compile *, void * ); Compile *compile_map_all( Compile *compile, map_compile_fn fn, void *a ); Symbol *compile_lookup( Compile *compile, const char *name ); void compile_link_make( Compile *compile, Symbol *child ); void *compile_link_break( Compile *compile, Symbol *child ); GtkType compile_get_type( void ); void *compile_expr_link_break( Compile *compile, Expr *expr ); void *compile_expr_link_break_rev( Expr *expr, Compile *compile ); void compile_expr_link_make( Compile *compile, Expr *expr ); Compile *compile_new( Expr *expr ); Compile *compile_new_toplevel( Expr *expr ); Compile *compile_new_local( Expr *expr ); void *compile_object( Compile *compile ); void *compile_toolkit( Toolkit *kit ); void compile_error_set( Compile *compile ); gboolean compile_check( Compile *compile ); void compile_resolve_names( Compile *inner, Compile *outer ); Symbol *compile_resolve_top( Symbol *sym ); void compile_resolve_dynamic( Compile *tab, Compile *context ); Symbol *compile_get_member( Compile *compile, const char *name ); const char *compile_get_member_string( Compile *compile, const char *name ); ParseNode *compile_copy_tree( Compile *fromscope, ParseNode *tree, Compile *toscope ); void compile_lcomp( Compile *compile ); GSList *compile_pattern_lhs( Compile *compile, Symbol *sym, ParseNode *node ); gboolean compile_pattern_has_leaf( ParseNode *node ); gboolean compile_pattern_has_args( Compile *compile ); nip2-8.7.1/src/regionview.h0000644000175000017500000001014213351443023012432 00000000000000/* draw a view of a region in an imageview */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_REGIONVIEW (regionview_get_type()) #define REGIONVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_REGIONVIEW, Regionview )) #define REGIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_REGIONVIEW, RegionviewClass )) #define IS_REGIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_REGIONVIEW )) #define IS_REGIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_REGIONVIEW )) #define REGIONVIEW_LABEL_MAX (256) /* States for the region view. */ typedef enum { REGIONVIEW_WAIT, /* Waiting for left down */ REGIONVIEW_MOVE, /* Dragging on label */ REGIONVIEW_RESIZE /* Dragging on resize handle */ } RegionviewState; /* Draw types. */ typedef enum { REGIONVIEW_REGION, /* width & height > 0 */ REGIONVIEW_AREA, /* width & height > 0 and locked */ REGIONVIEW_MARK, /* width & height == 0 */ REGIONVIEW_ARROW, /* width & height unconstrained */ REGIONVIEW_HGUIDE, /* width == image width, height == 0 */ REGIONVIEW_VGUIDE, /* width == 0, height == image height */ REGIONVIEW_LINE, /* floating dashed line for paintbox */ REGIONVIEW_BOX /* floating dashed box for paintbox */ } RegionviewType; /* Resize types. */ typedef enum { REGIONVIEW_RESIZE_NONE, REGIONVIEW_RESIZE_MOVE, REGIONVIEW_RESIZE_EDIT, REGIONVIEW_RESIZE_TOPLEFT, REGIONVIEW_RESIZE_TOP, REGIONVIEW_RESIZE_TOPRIGHT, REGIONVIEW_RESIZE_RIGHT, REGIONVIEW_RESIZE_BOTTOMRIGHT, REGIONVIEW_RESIZE_BOTTOM, REGIONVIEW_RESIZE_BOTTOMLEFT, REGIONVIEW_RESIZE_LEFT, REGIONVIEW_RESIZE_LAST } RegionviewResize; struct _Regionview { View view; RegionviewType type; gboolean frozen; /* type is frozen ... not rethought on resize */ /* State for resize/move etc. */ RegionviewState state; RegionviewResize resize;/* Resize type */ int dx, dy; /* Drag offset */ gboolean grabbed; /* Currently tracking with mouse */ /* The model we show. */ Classmodel *classmodel; Rect *model_area; /* What we read/write to talk to the model */ Rect our_area; /* Same, but our copy ... origin top left */ /* The imagepresent we draw on. */ Imagepresent *ip; iWindowCursorContext *cntxt; /* The signals we've connected to. */ guint expose_sid; guint destroy_sid; guint event_sid; guint changed_sid; guint conv_destroy_sid; guint model_changed_sid; /* Model info we read for display. */ GtkStateType paint_state;/* prelight/normal/etc. */ /* What's on the screen. */ gboolean unpainting; /* We are unpainting */ Rect area; /* Area of region ... image coordinates */ Rect label; /* Area covered by label ... canvas cods */ int ascent; /* Height of ascenders for text */ int dash_offset; guint dash_crawl; /* Timer for dash crawl animation */ GtkStateType last_paint_state; RegionviewType last_type; gboolean first; /* Initial draw (no old pos to remove) */ gboolean label_geo; /* Redo the label geo on refresh, please */ /* Text of label we display */ VipsBuf caption; }; typedef struct _RegionviewClass { ViewClass parent_class; /* My methods. */ } RegionviewClass; void regionview_attach( Regionview *regionview, int x, int y ); GtkType regionview_get_type( void ); Regionview *regionview_new( Classmodel *classmodel, Rect *model_area, Imagepresent *ip ); void regionview_set_type( Regionview *regionview, PElement *root ); nip2-8.7.1/src/tool.c0000644000175000017500000005325613351443023011241 00000000000000/* Manage toolkits and their display. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG_MENUS #define DEBUG #define DEBUG_TOOLITEM */ #include "ip.h" static FilemodelClass *parent_class = NULL; /* Largest string we let the user set for name/tip/etc. */ #define MAX_NAME (256) void tool_error( Tool *tool, VipsBuf *buf ) { if( tool->lineno != -1 ) { vips_buf_appends( buf, " (" ); if( FILEMODEL( tool->kit )->filename ) vips_buf_appends( buf, FILEMODEL( tool->kit )->filename ); else vips_buf_appends( buf, IOBJECT( tool->kit )->name ); vips_buf_appendf( buf, ":%d)", tool->lineno ); } } static void * tool_linkreport_sym_sym( Symbol *child, Symbol *parent, VipsBuf *buf, gboolean *found ) { /* Don't report generated syms eg. from lcomps or pattern * matches. */ if( child->type == SYM_ZOMBIE && !child->generated && !parent->generated && !compile_resolve_top( child ) ) { symbol_name_error( parent, buf ); vips_buf_appendf( buf, " " ); /* used as in "fred refers to undefined symbol jim" */ vips_buf_appendf( buf, _( "refers to undefined symbol" ) ); vips_buf_appendf( buf, " " ); symbol_qualified_name( child, buf ); vips_buf_appendf( buf, "\n" ); *found = TRUE; } return( NULL ); } static void * tool_linkreport_sym( Symbol *sym, VipsBuf *buf, gboolean *found ) { if( sym->expr ) return( slist_map3( sym->expr->compile->children, (SListMap3Fn) tool_linkreport_sym_sym, sym, buf, found ) ); return( NULL ); } void * tool_linkreport_tool( Tool *tool, VipsBuf *buf, gboolean *found ) { if( tool->type != TOOL_SYM ) return( NULL ); return( symbol_map_all( tool->sym, (symbol_map_fn) tool_linkreport_sym, buf, found ) ); } static void tool_finalize( GObject *gobject ) { Tool *tool; #ifdef DEBUG printf( "tool_finalize: %p %s\n", gobject, NN( IOBJECT( gobject )->name ) ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_TOOL( gobject ) ); tool = TOOL( gobject ); IM_FREE( tool->help ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void *toolitem_free( Toolitem *toolitem ); /* Remove a tool. Also strip the sym, if any. */ static void tool_dispose( GObject *gobject ) { Tool *tool = TOOL( gobject ); #ifdef DEBUG printf( "tool_dispose: destroying tool for " ); if( tool->sym ) symbol_name_print( tool->sym ); else printf( "anonymous-tool" ); printf( "at addr %p\n", tool ); #endif /*DEBUG*/ FREESID( tool->new_value_sid, tool->link_sym ); /* Unlink from symbol and toolkit. This changes the kit - mark it as * dirty. */ if( tool->sym ) { Symbol *sym = tool->sym; sym->tool = NULL; tool->sym = NULL; symbol_strip( sym ); /* Anything that referred to this symbol is going to need a * recalc. */ } if( tool->kit ) { filemodel_set_modified( FILEMODEL( tool->kit ), TRUE ); tool->kit = NULL; } IM_FREEF( toolitem_free, tool->toolitem ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static View * tool_view_new( Model *model, View *parent ) { return( toolview_new() ); } /* Save a tool's definition to a file. */ static gboolean tool_save_text( Model *model, iOpenFile *of ) { Tool *tool = TOOL( model ); Symbol *sym = tool->sym; switch( tool->type ) { case TOOL_SYM: if( sym->expr ) if( !ifile_write( of, "%s;\n\n", sym->expr->compile->text ) ) return( FALSE ); break; case TOOL_SEP: if( !ifile_write( of, "#separator\n\n" ) ) return( FALSE ); break; case TOOL_DIA: if( !ifile_write( of, "#dialog \"%s\" \"%s\"\n\n", IOBJECT( tool )->name, FILEMODEL( tool )->filename ) ) return( FALSE ); break; default: g_assert( FALSE ); } return( TRUE ); } static char * tool_type_to_char( Tooltype type ) { switch( type ) { case TOOL_SYM: return( "symbol" ); case TOOL_DIA: return( "dialog" ); case TOOL_SEP: return( "separator" ); default: g_assert( FALSE ); /* Keep gcc happy. */ return( FALSE ); } } static void tool_info( iObject *iobject, VipsBuf *buf ) { Tool *tool = TOOL( iobject ); IOBJECT_CLASS( parent_class )->info( iobject, buf ); vips_buf_appendf( buf, "type = \"%s\"\n", tool_type_to_char( tool->type ) ); if( tool->type == TOOL_SYM ) vips_buf_appendf( buf, "symbol = \"%s\"\n", IOBJECT( tool->sym )->name ); if( tool->lineno != -1 ) vips_buf_appendf( buf, "lineno = %d\n", tool->lineno ); if( tool->kit ) vips_buf_appendf( buf, "toolkit = \"%s\"\n", IOBJECT( tool->kit )->name ); } static void tool_parent_add( iContainer *child ) { Tool *tool = TOOL( child ); Toolkit *kit = TOOLKIT( child->parent ); tool->kit = kit; ICONTAINER_CLASS( parent_class )->parent_add( child ); } static void tool_class_init( ToolClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->finalize = tool_finalize; gobject_class->dispose = tool_dispose; iobject_class->info = tool_info; icontainer_class->parent_add = tool_parent_add; model_class->view_new = tool_view_new; model_class->save_text = tool_save_text; } static void tool_init( Tool *tool ) { tool->type = TOOL_SEP; tool->sym = NULL; tool->kit = NULL; tool->lineno = -1; } GType tool_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ToolClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) tool_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Tool ), 32, /* n_preallocs */ (GInstanceInitFunc) tool_init, }; type = g_type_register_static( TYPE_FILEMODEL, "Tool", &info, 0 ); } return( type ); } /* Add a tool to a toolkit. */ static void tool_link( Tool *tool, Toolkit *kit, int pos, const char *name ) { #ifdef DEBUG printf( "tool_link: %s\n", name ); #endif /*DEBUG*/ filemodel_set_modified( FILEMODEL( kit ), TRUE ); iobject_set( IOBJECT( tool ), name, NULL ); icontainer_child_add( ICONTAINER( kit ), ICONTAINER( tool ), pos ); } static void * toolitem_free( Toolitem *toolitem ) { Toolitem *parent = toolitem->parent; #ifdef DEBUG_TOOLITEM printf( "toolitem_free: %s\n", toolitem->name ); #endif /*DEBUG_TOOLITEM*/ slist_map( toolitem->children, (SListMapFn) toolitem_free, NULL ); g_assert( !toolitem->children ); if( parent ) { parent->children = g_slist_remove( parent->children, toolitem ); toolitem->parent = NULL; } IM_FREE( toolitem->label ); IM_FREE( toolitem->name ); IM_FREE( toolitem->icon ); IM_FREE( toolitem->tooltip ); IM_FREE( toolitem->help ); IM_FREE( toolitem->action ); IM_FREE( toolitem->path ); IM_FREE( toolitem->user_path ); IM_FREE( toolitem ); return( NULL ); } static Toolitem * toolitem_new( Toolitem *parent, Compile *compile, Tool *tool ) { Toolitem *toolitem; if( !(toolitem = INEW( NULL, Toolitem )) ) return( NULL ); toolitem->compile = compile; toolitem->tool = tool; toolitem->action_sym = NULL; toolitem->is_separator = FALSE; toolitem->is_pullright = FALSE; toolitem->children = NULL; toolitem->parent = parent; toolitem->is_action = FALSE; toolitem->label = NULL; toolitem->name = NULL; toolitem->icon = NULL; toolitem->tooltip = NULL; toolitem->help = NULL; toolitem->action = NULL; toolitem->path = NULL; toolitem->user_path = NULL; if( parent ) parent->children = g_slist_append( parent->children, toolitem ); return( toolitem ); } /* Set label & name & icon. FIXME ... we will do repeated heap_is_instanceof() during item build, do it once and set a flag instead */ static void toolitem_set_name( Toolitem *toolitem, PElement *root ) { gboolean result; char value[MAX_NAME]; int i; if( root && heap_is_instanceof( CLASS_MENUITEM, root, &result ) && result ) { if( class_get_member_string( root, MEMBER_LABEL, value, MAX_NAME ) ) { char *p, *q; /* Save the i18n-ed version. */ IM_SETSTR( toolitem->label, _( value ) ); /* Strip underscores (they mark mnemonics). Can't use * strrcpy() or memccpy(), we have overlapping blocks. */ im_strncpy( value, toolitem->label, MAX_NAME ); for( p = q = value; *p; p++ ) if( *p != '_' ) *q++ = *p; *q = '\0'; IM_SETSTR( toolitem->name, value ); } if( class_get_member_string( root, MEMBER_ICON, value, MAX_NAME ) ) IM_SETSTR( toolitem->icon, value ); } else { /* Remove underscores from the object name ... we don't want * them to be mnemonics. */ im_strncpy( value, IOBJECT( toolitem->compile->sym )->name, MAX_NAME ); for( i = 0; value[i]; i++ ) if( value[i] == '_' ) value[i] = ' '; IM_SETSTR( toolitem->label, value ); IM_SETSTR( toolitem->name, toolitem->label ); } if( root && heap_is_instanceof( CLASS_MENUSEPARATOR, root, &result ) && result ) toolitem->is_separator = TRUE; } static void toolitem_set_tooltip( Toolitem *toolitem, PElement *root ) { gboolean result; char value[MAX_NAME]; if( root && heap_is_instanceof( CLASS_MENUITEM, root, &result ) && result && class_get_member_string( root, MEMBER_TOOLTIP, value, MAX_NAME ) ) { IM_SETSTR( toolitem->tooltip, _( value ) ); } else if( toolitem->tool && toolitem->tool->help ) IM_SETSTR( toolitem->tooltip, toolitem->tool->help ); } static void toolitem_set_pullright( Toolitem *toolitem, PElement *root ) { gboolean result; /* New-style pullright? */ if( root && heap_is_instanceof( CLASS_MENUPULLRIGHT, root, &result ) && result ) toolitem->is_pullright = TRUE; /* Old-style pullright? */ else if( is_value( toolitem->compile->sym ) && is_class( toolitem->compile ) && !toolitem->compile->has_super && toolitem->compile->nparam == 0 ) toolitem->is_pullright = TRUE; } static void toolitem_set_action( Toolitem *toolitem, PElement *root ) { gboolean result; char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( toolitem->parent ) vips_buf_appendf( &buf, "%s.", toolitem->parent->action ); vips_buf_appendf( &buf, "%s", IOBJECT( toolitem->compile->sym )->name ); /* If this is a Menuaction, we need the action member. */ if( root && heap_is_instanceof( CLASS_MENUACTION, root, &result ) && result ) { PElement out; toolitem->is_action = TRUE; (void) class_get_member( root, MEMBER_ACTION, &toolitem->action_sym, &out ); } /* If there's an action member, use that. */ if( toolitem->is_action ) vips_buf_appends( &buf, "." MEMBER_ACTION ); IM_SETSTR( toolitem->action, vips_buf_all( &buf ) ); /* No action member found and this is an item (ie. not a pullright)? * Default to the sym itself. */ if( !toolitem->action_sym && !toolitem->is_pullright ) toolitem->action_sym = toolitem->compile->sym; } static void toolitem_set_path( Toolitem *toolitem ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( toolitem->parent ) vips_buf_appendf( &buf, "%s", toolitem->parent->path ); else vips_buf_appendf( &buf, "/Toolkits/%s", IOBJECT( toolitem->tool->kit )->name ); vips_buf_appendf( &buf, "/%s", toolitem->name ); IM_SETSTR( toolitem->path, vips_buf_all( &buf ) ); } static void toolitem_set_user_path( Toolitem *toolitem ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( toolitem->parent ) vips_buf_appends( &buf, toolitem->parent->user_path ); else vips_buf_appends( &buf, IOBJECT( toolitem->tool->kit )->name ); vips_buf_appendf( &buf, " / %s", toolitem->name ); IM_SETSTR( toolitem->user_path, vips_buf_all( &buf ) ); } static void * toolitem_set_help_sub( Symbol *param, VipsBuf *buf ) { vips_buf_appends( buf, " " ); vips_buf_appends( buf, IOBJECT( param )->name ); return( NULL ); } static void toolitem_set_help( Toolitem *toolitem ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_appends( &buf, toolitem->name ); /* Get the params from the action member if we can. */ if( toolitem->action_sym && toolitem->action_sym->expr && toolitem->action_sym->expr->compile->param ) slist_map( toolitem->action_sym->expr->compile->param, (SListMapFn) toolitem_set_help_sub, &buf ); vips_buf_appends( &buf, ": " ); if( toolitem->tooltip ) vips_buf_appends( &buf, toolitem->tooltip ); IM_SETSTR( toolitem->help, vips_buf_firstline( &buf ) ); } static Toolitem * toolitem_build( Tool *tool, Compile *compile, PElement *root, Toolitem *parent ) { Toolitem *toolitem; if( !(toolitem = toolitem_new( parent, compile, tool )) ) return( NULL ); toolitem_set_name( toolitem, root ); toolitem_set_tooltip( toolitem, root ); toolitem_set_pullright( toolitem, root ); toolitem_set_action( toolitem, root ); toolitem_set_path( toolitem ); toolitem_set_user_path( toolitem ); toolitem_set_help( toolitem ); #ifdef DEBUG_TOOLITEM printf( "toolitem_build: %s\n", toolitem->name ); #endif /*DEBUG_TOOLITEM*/ #ifdef DEBUG_VERBOSE printf( "toolitem_build:\n" ); printf( "\tpullright = %d\n", toolitem->is_pullright ); printf( "\tlabel = \"%s\"\n", toolitem->label ); printf( "\tname = \"%s\"\n", toolitem->name ); printf( "\ticon = \"%s\"\n", toolitem->icon ); printf( "\ttooltip = \"%s\"\n", toolitem->tooltip ); printf( "\thelp = \"%s\"\n", toolitem->help ); printf( "\taction = \"%s\"\n", toolitem->action ); printf( "\tpath = \"%s\"\n", toolitem->path ); printf( "\tuser_path = \"%s\"\n", toolitem->user_path ); #endif /*DEBUG_VERBOSE*/ return( toolitem ); } static Toolitem * toolitem_build_all( Tool *tool, Compile *compile, PElement *root, Toolitem *parent ); static void * toolitem_build_all_sub( Symbol *sym, Toolitem *parent ) { if( is_menuable( sym ) ) (void) toolitem_build_all( parent->tool, sym->expr->compile, NULL, parent ); return( NULL ); } static Toolitem * toolitem_build_all( Tool *tool, Compile *compile, PElement *root, Toolitem *parent ) { Toolitem *toolitem; gboolean result; if( !(toolitem = toolitem_build( tool, compile, root, parent )) ) return( NULL ); /* If this is a dynamic pullright, walk the heap to find the members. */ if( toolitem->is_pullright && root && heap_is_instanceof( CLASS_MENUPULLRIGHT, root, &result ) && result ) { PElement member; HeapNode *p; PEGETCLASSMEMBER( &member, root ); if( PEISNODE( &member ) ) for( p = PEGETVAL( &member ); p; p = GETRIGHT( p ) ) { PElement s, v; HeapNode *hn; Symbol *sym; /* Get the sym/value pair. */ hn = GETLEFT( p ); PEPOINTLEFT( hn, &s ); PEPOINTRIGHT( hn, &v ); sym = SYMBOL( PEGETSYMREF( &s ) ); /* Ignore this/super/check etc. */ if( !is_menuable( sym ) ) continue; /* For dynamic menus, only make items for * things which are subclasses of menu. */ if( !heap_is_instanceof( CLASS_MENU, &v, &result ) || !result ) continue; (void) toolitem_build_all( tool, sym->expr->compile, &v, toolitem ); } } else if( toolitem->is_pullright ) { /* A static pullright... just walk the container. */ (void) icontainer_map( ICONTAINER( compile ), (icontainer_map_fn) toolitem_build_all_sub, toolitem, NULL ); } return( toolitem ); } #ifdef DEBUG_MENUS static void toolitem_print( Toolitem *toolitem ) { if( toolitem->is_separator ) printf( "-----------\n" ); else printf( "%s --- %s\n", NN( toolitem->user_path ), NN( toolitem->help ) ); } static void * toolitem_print_all( Toolitem *toolitem ) { if( toolitem->is_pullright ) slist_map( toolitem->children, (SListMapFn) toolitem_print_all, NULL ); else toolitem_print( toolitem ); return( NULL ); } #endif /*DEBUG_MENUS*/ /* Rebuild the toolitem tree. */ static void tool_toolitem_rebuild( Tool *tool ) { IM_FREEF( toolitem_free, tool->toolitem ); switch( tool->type ) { case TOOL_SYM: if( is_menuable( tool->sym ) ) tool->toolitem = toolitem_build_all( tool, tool->sym->expr->compile, &tool->sym->expr->root, NULL ); break; case TOOL_DIA: if( (tool->toolitem = toolitem_new( NULL, NULL, tool )) ) IM_SETSTR( tool->toolitem->label, IOBJECT( tool )->name ); break; case TOOL_SEP: if( (tool->toolitem = toolitem_new( NULL, NULL, tool )) ) tool->toolitem->is_separator = TRUE; break; default: g_assert( 0 ); } iobject_changed( IOBJECT( tool ) ); #ifdef DEBUG_MENUS if( tool->toolitem ) toolitem_print_all( tool->toolitem ); #endif /*DEBUG_MENUS*/ } /* The expr has a new value. */ static void tool_new_value_cb( Symbol *sym, Tool *tool ) { #ifdef DEBUG printf( "tool_new_value_cb: new value for " ); symbol_name_print( sym ); printf( "\n" ); #endif /*DEBUG*/ tool_toolitem_rebuild( tool ); } static void tool_set_help( Tool *tool ) { char *p; char value[MAX_NAME]; if( tool->sym && tool->sym->expr && tool->sym->expr->compile && (p = tool->sym->expr->compile->text) ) { /* Skip leading whitespace. */ while( isspace( (int)(*p) ) ) p++; /* Skip leading comment, if any. */ if( p[0] == '/' && p[1] == '*' ) p += 2; else if( p[0] == '/' && p[1] == '/' ) p += 2; /* Skip more whitespace. */ while( isspace( (int)(*p) ) ) p++; /* Limit to MAX_NAME chars or 1st line. Strip trailing * whitespace. */ im_strncpy( value, p, MAX_NAME ); if( (p = strchr( value, '\n' )) ) *p = '\0'; *((char *) my_strrspn( value, WHITESPACE )) = '\0'; IM_SETSTR( tool->help, value ); } else if( tool->sym && tool->sym->type == SYM_EXTERNAL ) IM_SETSTR( tool->help, tool->sym->function->desc ); else if( tool->sym && tool->sym->type == SYM_BUILTIN ) IM_SETSTR( tool->help, tool->sym->builtin->desc ); else IM_SETSTR( tool->help, NULL ); } /* Add a symbol to a toolkit. */ Tool * tool_new_sym( Toolkit *kit, int pos, Symbol *sym ) { Tool *tool; g_assert( kit && sym ); /* Is there a tool we can reuse? Don't update pos .. assume we want to * keep the old one. */ if( (tool = sym->tool) && tool->kit == kit ) { tool->lineno = -1; tool_set_help( tool ); return( tool ); } /* Junk any existing tool for this sym. */ if( (tool = sym->tool) ) { sym->tool = NULL; tool->sym = NULL; IDESTROY( tool ); } tool = TOOL( g_object_new( TYPE_TOOL, NULL ) ); tool->type = TOOL_SYM; tool->sym = sym; sym->tool = tool; tool->new_value_sid = g_signal_connect( sym, "new_value", G_CALLBACK( tool_new_value_cb ), tool ); tool->link_sym = sym; tool_link( tool, kit, pos, IOBJECT( sym )->name ); tool_set_help( tool ); #ifdef DEBUG printf( "tool_new_sym: new tool for " ); symbol_name_print( sym ); printf( "at %p\n", tool ); #endif /*DEBUG*/ return( tool ); } /* Add a separator to a toolkit. */ Tool * tool_new_sep( Toolkit *kit, int pos ) { Tool *tool; g_assert( kit ); tool = TOOL( g_object_new( TYPE_TOOL, NULL ) ); tool->type = TOOL_SEP; iobject_set( IOBJECT( tool ), "separator", NULL ); tool_link( tool, kit, pos, NULL ); tool_toolitem_rebuild( tool ); return( tool ); } /* Search a kit for a tool by tool name. Used for searching for dialogs ... we * can't use the symtable stuff, as they're not syms. */ static Tool * tool_find( Toolkit *kit, const char *name ) { return( (Tool *) icontainer_map( ICONTAINER( kit ), (icontainer_map_fn) iobject_test_name, (char *) name, NULL ) ); } /* Add a dialog entry to a toolkit. */ Tool * tool_new_dia( Toolkit *kit, int pos, const char *name, const char *filename ) { Tool *tool; g_assert( kit && name && filename ); if( (tool = tool_find( kit, name )) ) { if( tool->type != TOOL_DIA ) { error_top( _( "Name clash." ) ); error_sub( _( "Can't create dialog with name \"%s\", " "an object with that name already exists in " "kit \"%s\"." ), name, IOBJECT( kit )->name ); return( NULL ); } /* Just update the filename. */ filemodel_set_filename( FILEMODEL( tool ), filename ); tool->lineno = -1; } else { tool = TOOL( g_object_new( TYPE_TOOL, NULL ) ); tool->type = TOOL_DIA; filemodel_set_filename( FILEMODEL( tool ), filename ); iobject_set( IOBJECT( tool ), name, NULL ); tool_link( tool, kit, pos, NULL ); } tool_toolitem_rebuild( tool ); return( tool ); } static Toolitem * toolitem_lookup_toolitem( Toolitem *toolitem, Symbol *action ) { if( toolitem->action_sym == action ) return( toolitem ); else return( (Toolitem *) slist_map( toolitem->children, (SListMapFn) toolitem_lookup_toolitem, action ) ); } static Toolitem * toolitem_lookup_tool( Tool *tool, Symbol *action ) { if( tool->toolitem ) return( toolitem_lookup_toolitem( tool->toolitem, action ) ); else return( NULL ); } static Toolitem * toolitem_lookup_toolkit( Toolkit *kit, Symbol *action ) { return( (Toolitem *) toolkit_map( kit, (tool_map_fn) toolitem_lookup_tool, action, NULL ) ); } /* Just walk the whole kit. Could use a hash in kitg, but we don't call this * so often. */ Toolitem * toolitem_lookup( Toolkitgroup *kitg, Symbol *action ) { return( (Toolitem *) toolkitgroup_map( kitg, (toolkit_map_fn) toolitem_lookup_toolkit, action, NULL ) ); } nip2-8.7.1/src/workspace.c0000644000175000017500000012205413351443023012253 00000000000000/* Manage workspace objects. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_VERBOSE #define DEBUG */ #include "ip.h" static ModelClass *parent_class = NULL; static GSList *workspace_all = NULL; static GSList *workspace_needs_layout = NULL; void workspace_set_needs_layout( Workspace *ws, gboolean needs_layout ) { #ifdef DEBUG_VERBOSE printf( "workspace_set_needs_layout: %p %s %d\n", ws, NN( IOBJECT( ws )->name ), needs_layout ); #endif /*DEBUG_VERBOSE*/ if( !ws->needs_layout && needs_layout && !ws->in_dispose ) { g_assert( !g_slist_find( workspace_needs_layout, ws ) ); ws->needs_layout = TRUE; workspace_needs_layout = g_slist_prepend( workspace_needs_layout, ws ); } if( ws->needs_layout && !needs_layout ) { g_assert( g_slist_find( workspace_needs_layout, ws ) ); ws->needs_layout = FALSE; workspace_needs_layout = g_slist_remove( workspace_needs_layout, ws ); } } GSList * workspace_get_needs_layout() { return( workspace_needs_layout ); } Workspacegroup * workspace_get_workspacegroup( Workspace *ws ) { iContainer *parent; if( (parent = ICONTAINER( ws )->parent) ) return( WORKSPACEGROUP( parent ) ); return( NULL ); } Workspaceroot * workspace_get_workspaceroot( Workspace *ws ) { return( workspace_get_workspacegroup( ws )->wsr ); } void workspace_set_modified( Workspace *ws, gboolean modified ) { Workspacegroup *wsg; if( (wsg = workspace_get_workspacegroup( ws )) ) filemodel_set_modified( FILEMODEL( wsg ), modified ); } static void * workspace_map_sub( Workspacegroup *wsg, workspace_map_fn fn, void *a, void *b ) { g_assert( IS_WORKSPACEGROUP( wsg ) ); return( icontainer_map( ICONTAINER( wsg ), (icontainer_map_fn) fn, a, b ) ); } /* Over all workspaces. */ void * workspace_map( workspace_map_fn fn, void *a, void *b ) { return( icontainer_map3( ICONTAINER( main_workspaceroot ), (icontainer_map3_fn) workspace_map_sub, fn, a, b ) ); } /* Map across the columns in a workspace. */ void * workspace_map_column( Workspace *ws, column_map_fn fn, void *a ) { return( icontainer_map( ICONTAINER( ws ), (icontainer_map_fn) fn, a, NULL ) ); } /* Map across a Workspace, applying to the symbols of the top-level rows. */ void * workspace_map_symbol( Workspace *ws, symbol_map_fn fn, void *a ) { return( icontainer_map( ICONTAINER( ws ), (icontainer_map_fn) column_map_symbol, (void *) fn, a ) ); } static void * workspace_is_empty_sub( Symbol *sym ) { return( sym ); } /* Does a workspace contain no rows? */ gboolean workspace_is_empty( Workspace *ws ) { return( workspace_map_symbol( ws, (symbol_map_fn) workspace_is_empty_sub, NULL ) == NULL ); } /* Map a function over all selected rows in a workspace. */ void * workspace_selected_map( Workspace *ws, row_map_fn fn, void *a, void *b ) { return( slist_map2( ws->selected, (SListMap2Fn) fn, a, b ) ); } static void * workspace_selected_map_sym_sub( Row *row, symbol_map_fn fn, void *a ) { return( fn( row->sym, a, NULL, NULL ) ); } /* Map a function over all selected symbols in a workspace. */ void * workspace_selected_map_sym( Workspace *ws, symbol_map_fn fn, void *a, void *b ) { return( workspace_selected_map( ws, (row_map_fn) workspace_selected_map_sym_sub, (void *) fn, a ) ); } /* Are there any selected rows? */ gboolean workspace_selected_any( Workspace *ws ) { return( ws->selected != NULL ); } /* Number of selected rows. */ int workspace_selected_num( Workspace *ws ) { return( g_slist_length( ws->selected ) ); } static void * workspace_selected_sym_sub( Row *row, Symbol *sym ) { if( row->sym == sym ) return( row ); return( NULL ); } /* Is sym selected? */ gboolean workspace_selected_sym( Workspace *ws, Symbol *sym ) { return( workspace_selected_map( ws, (row_map_fn) workspace_selected_sym_sub, sym, NULL ) != NULL ); } /* Is just one row selected? If yes, return it. */ Row * workspace_selected_one( Workspace *ws ) { int len = g_slist_length( ws->selected ); if( len == 1 ) return( (Row *)(ws->selected->data) ); else if( len == 0 ) { error_top( _( "No objects selected." ) ); error_sub( _( "Select exactly one object and try again." ) ); return( NULL ); } else { error_top( _( "More than one object selected." ) ); error_sub( _( "Select exactly one object and try again." ) ); return( NULL ); } } static void * workspace_deselect_all_sub( Column *col ) { col->last_select = NULL; return( NULL ); } /* Deselect all rows. */ void workspace_deselect_all( Workspace *ws ) { (void) workspace_selected_map( ws, (row_map_fn) row_deselect, NULL, NULL ); (void) workspace_map_column( ws, (column_map_fn) workspace_deselect_all_sub, NULL ); } /* Track this while we build a names list. */ typedef struct { VipsBuf *buf; const char *separator; gboolean first; } NamesInfo; /* Add a name to a string for a symbol. */ static void * workspace_selected_names_sub( Row *row, NamesInfo *names ) { if( !names->first ) vips_buf_appends( names->buf, names->separator ); /* Hack: if this is a matrix with selected cells, use an extract to * get those cells out. We should really have a row method for this I * guess :-( */ if( row->child_rhs && row->child_rhs->graphic && IS_MATRIX( row->child_rhs->graphic ) && MATRIX( row->child_rhs->graphic )->selected ) { Matrix *matrix = MATRIX( row->child_rhs->graphic ); vips_buf_appends( names->buf, "(" ); row_qualified_name( row, names->buf ); vips_buf_appendf( names->buf, ".extract %d %d %d %d)", matrix->range.left, matrix->range.top, matrix->range.width, matrix->range.height ); } else row_qualified_name( row, names->buf ); names->first = FALSE; return( NULL ); } /* Add a list of selected symbol names to a string. */ void workspace_selected_names( Workspace *ws, VipsBuf *buf, const char *separator ) { NamesInfo names; names.buf = buf; names.separator = separator; names.first = TRUE; (void) workspace_selected_map( ws, (row_map_fn) workspace_selected_names_sub, &names, NULL ); } void workspace_column_names( Column *col, VipsBuf *buf, const char *separator ) { NamesInfo names; names.buf = buf; names.separator = separator; names.first = TRUE; (void) column_map( col, (row_map_fn) workspace_selected_names_sub, &names, NULL ); } /* Select all objects in all columns. */ void workspace_select_all( Workspace *ws ) { (void) icontainer_map( ICONTAINER( ws ), (icontainer_map_fn) column_select_symbols, NULL, NULL ); } /* Is there just one column, and is it empty? */ Column * workspace_is_one_empty( Workspace *ws ) { GSList *children = ICONTAINER( ws )->children; Column *col; if( g_slist_length( children ) != 1 ) return( NULL ); col = COLUMN( children->data ); if( !column_is_empty( col ) ) return( NULL ); return( col ); } /* Search for a column by name. */ Column * workspace_column_find( Workspace *ws, const char *name ) { Model *model; if( !(model = icontainer_map( ICONTAINER( ws ), (icontainer_map_fn) iobject_test_name, (void *) name, NULL )) ) return( NULL ); return( COLUMN( model ) ); } /* Return the column for a name ... an existing column, or a new one. */ Column * workspace_column_get( Workspace *ws, const char *name ) { Column *col; /* Exists? */ if( (col = workspace_column_find( ws, name )) ) return( col ); /* No - build new column and return a pointer to that. */ return( column_new( ws, name ) ); } /* Make up a new column name. Check for not already in workspace. */ void workspace_column_name_new( Workspace *ws, char *name ) { do { number_to_string( ws->next++, name ); } while( workspace_column_find( ws, name ) ); } Column * workspace_get_column( Workspace *ws ) { if( ICONTAINER( ws )->current ) return( COLUMN( ICONTAINER( ws )->current ) ); return( NULL ); } /* Select a column. Can select NULL for no current col in this ws. */ void workspace_column_select( Workspace *ws, Column *col ) { icontainer_current( ICONTAINER( ws ), ICONTAINER( col ) ); } /* Make sure we have a column selected ... pick one of the existing columns; if * there are none, make a column. */ Column * workspace_column_pick( Workspace *ws ) { Column *col; if( (col = workspace_get_column( ws )) ) return( col ); if( (col = COLUMN( icontainer_get_nth_child( ICONTAINER( ws ), 0 ) )) ) { workspace_column_select( ws, col ); return( col ); } /* Make an empty column ... always at the top left. */ col = column_new( ws, "A" ); col->x = WORKSPACEVIEW_MARGIN_LEFT; col->y = WORKSPACEVIEW_MARGIN_TOP; workspace_column_select( ws, col ); return( col ); } /* Make and select a column. Used for "new column" UI actions. */ Column * workspace_column_new( Workspace *ws ) { char new_name[MAX_STRSIZE]; Column *old_col; Column *col; workspace_column_name_new( ws, new_name ); if( !(col = column_new( ws, new_name )) ) return( NULL ); /* Position just to right of currently selected column. */ if( (old_col = workspace_get_column( ws )) ) { col->x = old_col->x + 50; col->y = old_col->y; } workspace_column_select( ws, col ); column_scrollto( col, MODEL_SCROLL_TOP ); return( col ); } /* Make a new symbol, part of the current column. */ static Symbol * workspace_add_symbol( Workspace *ws ) { Column *col = workspace_column_pick( ws ); Symbol *sym; char *name; name = column_name_new( col ); sym = symbol_new( ws->sym->expr->compile, name ); IM_FREE( name ); return( sym ); } /* Make up a new definition. */ Symbol * workspace_add_def( Workspace *ws, const char *str ) { Column *col = workspace_column_pick( ws ); Symbol *sym; char *name; #ifdef DEBUG printf( "workspace_add_def: %s\n", str ); #endif /*DEBUG*/ if( !str || strspn( str, WHITESPACE ) == strlen( str ) ) return( NULL ); /* Try parsing as a "fred = 12" style def. */ attach_input_string( str ); if( (name = parse_test_define()) ) { sym = symbol_new( ws->sym->expr->compile, name ); IM_FREE( name ); attach_input_string( str + IM_CLIP( 0, input_state.charpos - 1, strlen( str ) ) ); } else { /* That didn't work. Make a sym from the col name. */ sym = workspace_add_symbol( ws ); attach_input_string( str ); } if( !symbol_user_init( sym ) || !parse_rhs( sym->expr, PARSE_RHS ) ) { /* Another parse error. */ expr_error_get( sym->expr ); /* Block changes to error_string ... symbol_destroy() * can set this for compound objects. */ error_block(); IDESTROY( sym ); error_unblock(); return( NULL ); } /* If we're redefining a sym, it might have a row already. */ if( !sym->expr->row ) (void) row_new( col->scol, sym, &sym->expr->root ); symbol_made( sym ); workspace_set_modified( ws, TRUE ); return( sym ); } /* Make up a new definition, recalc and scroll to make it visible. */ Symbol * workspace_add_def_recalc( Workspace *ws, const char *str ) { Column *col = workspace_column_pick( ws ); Symbol *sym; #ifdef DEBUG printf( "workspace_add_def_recalc: %s\n", str ); #endif /*DEBUG*/ if( !(sym = workspace_add_def( ws, str )) ) return( NULL ); if( !symbol_recalculate_check( sym ) ) { /* Eval error. */ expr_error_get( sym->expr ); error_block(); IDESTROY( sym ); error_unblock(); return( NULL ); } /* Jump to column containing object. */ column_scrollto( col, MODEL_SCROLL_BOTTOM ); return( sym ); } gboolean workspace_load_file_buf( VipsBuf *buf, const char *filename ) { if( callv_string_filenamef( (callv_string_fn) vips_format_for_file, "%s", filename ) ) vips_buf_appends( buf, "Image_file" ); else vips_buf_appends( buf, "Matrix_file" ); vips_buf_appends( buf, " \"" ); vips_buf_appendsc( buf, TRUE, filename ); vips_buf_appends( buf, "\"" ); return( TRUE ); } /* Load a matrix or image. Don't recalc: you need to recalc later to test for * success/fail. See eg. workspace_add_def_recalc() */ Symbol * workspace_load_file( Workspace *ws, const char *filename ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); Symbol *sym; if( !workspace_load_file_buf( &buf, filename ) ) return( NULL ); if( !(sym = workspace_add_def( ws, vips_buf_all( &buf ) )) ) return( NULL ); mainw_recent_add( &mainw_recent_image, filename ); return( sym ); } static void workspace_dispose( GObject *gobject ) { Workspace *ws; #ifdef DEBUG printf( "workspace_dispose: %p %s\n", gobject, NN( IOBJECT( gobject )->name ) ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_WORKSPACE( gobject ) ); ws = WORKSPACE( gobject ); workspace_set_needs_layout( ws, FALSE ); ws->in_dispose = TRUE; UNREF( ws->kitg ); UNREF( ws->local_kitg ); IDESTROY( ws->sym ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void workspace_finalize( GObject *gobject ) { Workspace *ws; #ifdef DEBUG printf( "workspace_finalize: %p %s\n", gobject, NN( IOBJECT( gobject )->name ) ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_WORKSPACE( gobject ) ); ws = WORKSPACE( gobject ); IM_FREE( ws->status ); IM_FREE( ws->local_defs ); workspace_all = g_slist_remove( workspace_all, ws ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void workspace_changed( iObject *iobject ) { Workspace *ws; Workspacegroup *wsg; #ifdef DEBUG_VERBOSE printf( "workspace_changed: %s\n", NN( iobject->name ) ); #endif /*DEBUG_VERBOSE*/ g_return_if_fail( iobject != NULL ); g_return_if_fail( IS_WORKSPACE( iobject ) ); ws = WORKSPACE( iobject ); wsg = workspace_get_workspacegroup( ws ); /* Signal changed on our workspacegroup, if we're the current object. */ if( wsg && ICONTAINER( wsg )->current == ICONTAINER( iobject ) ) iobject_changed( IOBJECT( wsg ) ); IOBJECT_CLASS( parent_class )->changed( iobject ); } static void workspace_child_add( iContainer *parent, iContainer *child, int pos ) { Workspace *ws = WORKSPACE( parent ); Column *col = COLUMN( child ); ICONTAINER_CLASS( parent_class )->child_add( parent, child, pos ); if( col->selected ) workspace_column_select( ws, col ); } static void workspace_child_remove( iContainer *parent, iContainer *child ) { Workspace *ws = WORKSPACE( parent ); workspace_set_modified( ws, TRUE ); ICONTAINER_CLASS( parent_class )->child_remove( parent, child ); } static void workspace_current( iContainer *parent, iContainer *child ) { Workspace *ws = WORKSPACE( parent ); Column *col = COLUMN( child ); Column *current = workspace_get_column( ws ); if( current ) current->selected = FALSE; if( col ) col->selected = TRUE; ICONTAINER_CLASS( parent_class )->current( parent, child ); } static void workspace_link( Workspace *ws, Workspacegroup *wsg, const char *name ) { Workspaceroot *wsr = wsg->wsr; Symbol *sym; #ifdef DEBUG printf( "workspace_link: naming ws %p as %s\n", ws, name ); #endif /*DEBUG*/ sym = symbol_new_defining( wsr->sym->expr->compile, name ); ws->sym = sym; sym->type = SYM_WORKSPACE; sym->ws = ws; sym->expr = expr_new( sym ); (void) compile_new( sym->expr ); symbol_made( sym ); iobject_set( IOBJECT( ws ), name, NULL ); ws->local_kitg = toolkitgroup_new( ws->sym ); g_object_ref( G_OBJECT( ws->local_kitg ) ); iobject_sink( IOBJECT( ws->local_kitg ) ); } static const char * workspacemode_to_char( WorkspaceMode mode ) { switch( mode ) { case WORKSPACE_MODE_REGULAR: return( "WORKSPACE_MODE_REGULAR" ); case WORKSPACE_MODE_FORMULA: return( "WORKSPACE_MODE_FORMULA" ); case WORKSPACE_MODE_NOEDIT: return( "WORKSPACE_MODE_NOEDIT" ); default: return( NULL ); } } static WorkspaceMode char_to_workspacemode( const char *mode ) { if( strcasecmp( mode, "WORKSPACE_MODE_REGULAR" ) == 0 ) return( WORKSPACE_MODE_REGULAR ); else if( strcasecmp( mode, "WORKSPACE_MODE_FORMULA" ) == 0 ) return( WORKSPACE_MODE_FORMULA ); else if( strcasecmp( mode, "WORKSPACE_MODE_NOEDIT" ) == 0 ) return( WORKSPACE_MODE_NOEDIT ); else return( (WorkspaceMode) -1 ); } static View * workspace_view_new( Model *model, View *parent ) { return( workspaceview_new() ); } static gboolean workspace_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { Workspace *ws = WORKSPACE( model ); char buf[FILENAME_MAX]; char *txt; g_assert( IS_WORKSPACEGROUP( parent ) ); /* "view" is optional, for backwards compatibility. */ if( get_sprop( xnode, "view", buf, FILENAME_MAX ) ) { WorkspaceMode mode = char_to_workspacemode( buf ); if( (int) mode >= 0 ) /* Could call workspace_set_mode(), but this is only a * load, so so what. */ ws->mode = mode; } /* Also optional. */ (void) get_dprop( xnode, "scale", &ws->scale ); (void) get_dprop( xnode, "offset", &ws->offset ); (void) get_bprop( xnode, "locked", &ws->locked ); (void) get_bprop( xnode, "lpane_open", &ws->lpane_open ); (void) get_iprop( xnode, "lpane_position", &ws->lpane_position ); (void) get_bprop( xnode, "rpane_open", &ws->rpane_open ); (void) get_iprop( xnode, "rpane_position", &ws->rpane_position ); if( get_sprop( xnode, "name", buf, FILENAME_MAX ) ) { IM_SETSTR( IOBJECT( ws )->name, buf ); } if( get_sprop( xnode, "caption", buf, FILENAME_MAX ) ) { IM_SETSTR( IOBJECT( ws )->caption, buf ); } /* Don't use get_sprop() and avoid a limit on def size. */ if( (txt = (char *) xmlGetProp( xnode, (xmlChar *) "local_defs" )) ) { (void) workspace_local_set( ws, txt ); IM_FREEF( xmlFree, txt ); } (void) get_iprop( xnode, "major", &ws->major ); (void) get_iprop( xnode, "minor", &ws->minor ); if( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ) return( FALSE ); return( TRUE ); } static xmlNode * workspace_save( Model *model, xmlNode *xnode ) { Workspace *ws = WORKSPACE( model ); Workspacegroup *wsg = workspace_get_workspacegroup( ws ); xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( !set_sprop( xthis, "view", workspacemode_to_char( ws->mode ) ) || !set_dprop( xthis, "scale", ws->scale ) || !set_dprop( xthis, "offset", ws->offset ) || !set_sprop( xthis, "locked", bool_to_char( ws->locked ) ) || !set_iprop( xthis, "lpane_position", ws->lpane_position ) || !set_sprop( xthis, "lpane_open", bool_to_char( ws->lpane_open ) ) || !set_iprop( xthis, "rpane_position", ws->rpane_position ) || !set_sprop( xthis, "rpane_open", bool_to_char( ws->rpane_open ) ) || !set_sprop( xthis, "local_defs", ws->local_defs ) || !set_sprop( xthis, "name", IOBJECT( ws )->name ) || !set_sprop( xthis, "caption", IOBJECT( ws )->caption ) ) return( NULL ); /* We have to save our workspacegroup's filename here for compt with * older nip2. */ if( !set_sprop( xthis, "filename", FILEMODEL( wsg )->filename ) ) return( NULL ); if( !set_iprop( xthis, "major", ws->major ) || !set_iprop( xthis, "minor", ws->minor ) ) return( NULL ); return( xthis ); } static void workspace_empty( Model *model ) { Workspace *ws = WORKSPACE( model ); /* Make sure this gets reset. */ ws->area.left = 0; ws->area.top = 0; ws->area.width = 0; ws->area.height = 0; MODEL_CLASS( parent_class )->empty( model ); } static void * workspace_load_toolkit( const char *filename, Toolkitgroup *toolkitgroup ) { if( !toolkit_new_from_file( toolkitgroup, filename ) ) iwindow_alert( NULL, GTK_MESSAGE_ERROR ); return( NULL ); } /* The compat modes this version of nip2 has. Search the compat dir and make a * list of these things. */ #define MAX_COMPAT (100) static int compat_major[MAX_COMPAT]; static int compat_minor[MAX_COMPAT]; static int n_compat = 0; static void * workspace_build_compat_fn( const char *filename ) { char *basename; int major; int minor; basename = g_path_get_basename( filename ); if( sscanf( basename, "%d.%d", &major, &minor ) != 2 ) { g_free( basename ); return( NULL ); } g_free( basename ); compat_major[n_compat] = major; compat_minor[n_compat] = minor; n_compat += 1; #ifdef DEBUG printf( "workspace_build_compat_fn: found major = %d, minor = %d\n", major, minor ); #endif /*DEBUG*/ return( NULL ); } /* Build the list of ws compatibility defs we have. */ static void workspace_build_compat( void ) { if( n_compat > 0 ) return; path_map_dir( "$VIPSHOME/share/" PACKAGE "/compat", "*.*", (path_map_fn) workspace_build_compat_fn, NULL ); } /* Given a major/minor (eg. read from a ws header), return non-zero if we have * a set of compat defs. */ int workspace_have_compat( int major, int minor, int *best_major, int *best_minor ) { int i; int best; #ifdef DEBUG printf( "workspace_have_compat: searching for %d.%d\n", major, minor ); #endif /*DEBUG*/ /* Sets of ws compatibility defs cover themselves and any earlier * releases, as far back as the next set of compat defs. We need to * search for the smallest compat version that's greater than the * version number in the file. */ workspace_build_compat(); best = -1; for( i = 0; i < n_compat; i++ ) if( major <= compat_major[i] && minor <= compat_minor[i] ) /* Found a possible compat set, is it better than the * best we've seen so far? */ if( best == -1 || compat_major[i] < compat_major[best] || compat_minor[i] < compat_minor[best] ) best = i; if( best == -1 ) return( 0 ); #ifdef DEBUG printf( "\tfound %d.%d\n", compat_major[best], compat_minor[best] ); #endif /*DEBUG*/ if( best_major ) *best_major = compat_major[best]; if( best_minor ) *best_minor = compat_minor[best]; return( 1 ); } void workspace_get_version( Workspace *ws, int *major, int *minor ) { *major = ws->major; *minor = ws->minor; } gboolean workspace_load_compat( Workspace *ws, int major, int minor ) { char pathname[FILENAME_MAX]; GSList *path; int best_major; int best_minor; if( workspace_have_compat( major, minor, &best_major, &best_minor ) ) { /* Make a private toolkitgroup local to this workspace to * hold the compatibility defs we are planning to load. */ UNREF( ws->kitg ); ws->kitg = toolkitgroup_new( ws->sym ); g_object_ref( G_OBJECT( ws->kitg ) ); iobject_sink( IOBJECT( ws->kitg ) ); im_snprintf( pathname, FILENAME_MAX, "$VIPSHOME/share/" PACKAGE "/compat/%d.%d", best_major, best_minor ); path = path_parse( pathname ); if( path_map( path, "*.def", (path_map_fn) workspace_load_toolkit, ws->kitg ) ) { path_free2( path ); return( FALSE ); } path_free2( path ); #ifdef DEBUG printf( "workspace_load_compat: loaded %d.%d\n", best_major, best_minor ); #endif /*DEBUG*/ ws->compat_major = best_major; ws->compat_minor = best_minor; } else { #ifdef DEBUG printf( "workspace_load_compat: no compat necessary\n" ); #endif /*DEBUG*/ /* No compat defs necessary for this ws. */ ws->compat_major = 0; ws->compat_minor = 0; } return( TRUE ); } static void workspace_class_init( WorkspaceClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->dispose = workspace_dispose; gobject_class->finalize = workspace_finalize; iobject_class->changed = workspace_changed; iobject_class->user_name = _( "Tab" ); icontainer_class->child_add = workspace_child_add; icontainer_class->child_remove = workspace_child_remove; icontainer_class->current = workspace_current; model_class->view_new = workspace_view_new; model_class->load = workspace_load; model_class->save = workspace_save; model_class->empty = workspace_empty; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void workspace_init( Workspace *ws ) { ws->sym = NULL; /* We default to using the main toolkitgroup for our definitions. * Unref and load private defs if we need compatibility. */ ws->kitg = main_toolkitgroup; g_object_ref( G_OBJECT( ws->kitg ) ); ws->next = 0; ws->selected = NULL; ws->errors = NULL; ws->mode = WORKSPACE_MODE_REGULAR; ws->major = MAJOR_VERSION; ws->minor = MINOR_VERSION; ws->compat_major = 0; ws->compat_minor = 0; ws->area.left = 0; ws->area.top = 0; ws->area.width = 0; ws->area.height = 0; ws->vp = ws->area; ws->lpane_open = WORKSPACE_LPANE_OPEN; ws->lpane_position = WORKSPACE_LPANE_POSITION; ws->rpane_open = WORKSPACE_RPANE_OPEN; ws->rpane_position = WORKSPACE_RPANE_POSITION; ws->status = NULL; ws->scale = 1.0; ws->offset = 0.0; ws->local_defs = im_strdupn( _( "// private definitions for this tab\n" ) ); ws->local_kitg = NULL; ws->local_kit = NULL; workspace_all = g_slist_prepend( workspace_all, ws ); } GType workspace_get_type( void ) { static GType workspace_type = 0; if( !workspace_type ) { static const GTypeInfo info = { sizeof( WorkspaceClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) workspace_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Workspace ), 32, /* n_preallocs */ (GInstanceInitFunc) workspace_init, }; workspace_type = g_type_register_static( TYPE_MODEL, "Workspace", &info, 0 ); } return( workspace_type ); } Workspace * workspace_new( Workspacegroup *wsg, const char *name ) { Workspaceroot *wsr = wsg->wsr; Workspace *ws; #ifdef DEBUG printf( "workspace_new: %s\n", name ); #endif /*DEBUG*/ if( compile_lookup( wsr->sym->expr->compile, name ) ) { error_top( _( "Name clash." ) ); error_sub( _( "Can't create workspace \"%s\". " "A symbol with that name already exists." ), name ); return( NULL ); } ws = WORKSPACE( g_object_new( TYPE_WORKSPACE, NULL ) ); workspace_link( ws, wsg, name ); icontainer_child_add( ICONTAINER( wsg ), ICONTAINER( ws ), -1 ); return( ws ); } /* Make the blank workspace we present the user with (in the absence of * anything else). */ Workspace * workspace_new_blank( Workspacegroup *wsg ) { char name[256]; Workspace *ws; workspaceroot_name_new( wsg->wsr, name ); if( !(ws = workspace_new( wsg, name )) ) return( NULL ); /* Make an empty column. */ (void) workspace_column_pick( ws ); icontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) ); iobject_set( IOBJECT( ws ), NULL, _( "Default empty tab" ) ); return( ws ); } /* Get the bottom row from the current column. */ static Row * workspace_get_bottom( Workspace *ws ) { return( column_get_bottom( workspace_column_pick( ws ) ) ); } gboolean workspace_add_action( Workspace *ws, const char *name, const char *action, int nparam ) { Column *col = workspace_column_pick( ws ); char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); /* Are there any selected symbols? */ vips_buf_appends( &buf, action ); if( nparam > 0 && workspace_selected_any( ws ) ) { if( nparam != workspace_selected_num( ws ) ) { error_top( _( "Wrong number of arguments." ) ); error_sub( _( "%s needs %d arguments, " "there are %d selected." ), name, nparam, workspace_selected_num( ws ) ); return( FALSE ); } vips_buf_appends( &buf, " " ); workspace_selected_names( ws, &buf, " " ); if( vips_buf_is_full( &buf ) ) { error_top( _( "Overflow error." ) ); error_sub( _( "Too many names selected." ) ); return( FALSE ); } if( !workspace_add_def_recalc( ws, vips_buf_all( &buf ) ) ) return( FALSE ); workspace_deselect_all( ws ); } else { /* Try to use the previous n items in this column as the * arguments. */ if( !column_add_n_names( col, name, &buf, nparam ) || !workspace_add_def_recalc( ws, vips_buf_all( &buf ) ) ) return( FALSE ); } return( TRUE ); } int workspace_number( void ) { return( g_slist_length( workspace_all ) ); } static void * workspace_row_dirty( Row *row, int serial ) { return( expr_dirty( row->expr, serial ) ); } /* Recalculate selected items. */ gboolean workspace_selected_recalc( Workspace *ws ) { if( workspace_selected_map( ws, (row_map_fn) workspace_row_dirty, GINT_TO_POINTER( link_serial_new() ), NULL ) ) return( FALSE ); /* Recalc even if autorecomp is off. */ symbol_recalculate_all_force( TRUE ); workspace_deselect_all( ws ); return( TRUE ); } static void * workspace_selected_remove2( Row *row ) { if( row != row->top_row ) return( row ); return( NULL ); } static void * workspace_selected_remove3( Row *row, int *nsel ) { if( row->selected ) *nsel += 1; return( NULL ); } static void * workspace_selected_remove4( Column *col, GSList **cs ) { int nsel = 0; (void) column_map( col, (row_map_fn) workspace_selected_remove3, &nsel, NULL ); if( nsel > 0 ) *cs = g_slist_prepend( *cs, col ); return( NULL ); } static void * workspace_selected_remove5( Column *col ) { Subcolumn *scol = col->scol; int nmembers = g_slist_length( ICONTAINER( scol )->children ); if( nmembers > 0 ) icontainer_pos_renumber( ICONTAINER( scol ) ); else IDESTROY( col ); return( NULL ); } /* Remove selected items. * * 0. check all objects to be destroyed are top level rows * 1. look for and note all columns containing items we are going to delete * 2. loop over selected items, and delete them one-by-one. * 3. loop over the columns we noted in 1 and delete empty ones * 4. renumber affected columns */ static gboolean workspace_selected_remove( Workspace *ws ) { Row *row; GSList *cs = NULL; if( (row = (Row *) workspace_selected_map( ws, (row_map_fn) workspace_selected_remove2, NULL, NULL )) ) { error_top( _( "You can only remove top level rows." ) ); error_sub( _( "Not all selected objects are top level " "rows." ) ); return( FALSE ); } (void) workspace_map_column( ws, (column_map_fn) workspace_selected_remove4, &cs ); (void) workspace_selected_map_sym( ws, (symbol_map_fn) iobject_destroy, NULL, NULL ); (void) slist_map( cs, (SListMapFn) workspace_selected_remove5, NULL ); IM_FREEF( g_slist_free, cs ); symbol_recalculate_all(); workspace_set_modified( ws, TRUE ); return( TRUE ); } /* Callback for workspace_selected_remove_yesno. Remove selected items. */ static void workspace_selected_remove_yesno_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Workspace *ws = WORKSPACE( client ); if( workspace_selected_remove( ws ) ) nfn( sys, IWINDOW_YES ); else nfn( sys, IWINDOW_ERROR ); } /* Ask before removing selected. */ void workspace_selected_remove_yesno( Workspace *ws, GtkWidget *parent ) { char txt[30]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( !workspace_selected_any( ws ) ) return; workspace_selected_names( ws, &buf, ", " ); box_yesno( parent, workspace_selected_remove_yesno_cb, iwindow_true_cb, ws, iwindow_notify_null, NULL, GTK_STOCK_DELETE, _( "Delete selected objects?" ), _( "Are you sure you want to delete %s?" ), vips_buf_all( &buf ) ); } /* Sub fn of below ... add a new index expression. */ static gboolean workspace_ungroup_add_index( Row *row, const char *fmt, int i ) { static char txt[200]; static VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_rewind( &buf ); row_qualified_name( row, &buf ); vips_buf_appendf( &buf, fmt, i ); if( !workspace_add_def_recalc( row->ws, vips_buf_all( &buf ) ) ) return( FALSE ); return( TRUE ); } static void * workspace_ungroup_row( Row *row ) { PElement *root = &row->expr->root; gboolean result; PElement value; int length; int i; if( !heap_is_instanceof( CLASS_GROUP, root, &result ) ) return( row ); if( result ) { if( !class_get_member( root, MEMBER_VALUE, NULL, &value ) || (length = heap_list_length_max( &value, 100 )) < 0 ) return( row ); for( i = 0; i < length; i++ ) if( !workspace_ungroup_add_index( row, ".value?%d", i ) ) return( row ); } else { if( !heap_is_list( root, &result ) ) return( row ); if( result ) { if( (length = heap_list_length_max( root, 100 )) < 0 ) return( row ); for( i = 0; i < length; i++ ) if( !workspace_ungroup_add_index( row, "?%d", i ) ) return( row ); } else { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); row_qualified_name( row, &buf ); error_top( _( "Unable to ungroup." ) ); error_sub( _( "Row \"%s\" is not a Group or a list." ), vips_buf_all( &buf ) ); return( row ); } } return( NULL ); } /* Ungroup the selected object(s), or the bottom object. */ gboolean workspace_selected_ungroup( Workspace *ws ) { if( !workspace_selected_any( ws ) ) { Row *row; if( (row = workspace_get_bottom( ws )) ) { if( workspace_ungroup_row( row ) ) return( FALSE ); symbol_recalculate_all(); } } else { /* Ungroup selected symbols. */ if( workspace_selected_map( ws, (row_map_fn) workspace_ungroup_row, NULL, NULL ) ) { symbol_recalculate_all(); return( FALSE ); } symbol_recalculate_all(); workspace_deselect_all( ws ); } return( TRUE ); } /* Group the selected object(s). */ gboolean workspace_selected_group( Workspace *ws ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( !workspace_selected_any( ws ) ) { Row *row; if( (row = workspace_get_bottom( ws )) ) row_select( row ); } vips_buf_appends( &buf, "Group [" ); workspace_selected_names( ws, &buf, "," ); vips_buf_appends( &buf, "]" ); if( !workspace_add_def_recalc( ws, vips_buf_all( &buf ) ) ) return( FALSE ); workspace_deselect_all( ws ); return( TRUE ); } static Row * workspace_test_error( Row *row, Workspace *ws, int *found ) { g_assert( row->err ); /* Found next? */ if( *found ) return( row ); if( row == ws->last_error ) { /* Found the last one ... return the next one. */ *found = 1; return( NULL ); } return( NULL ); } /* FALSE for no errors. */ gboolean workspace_next_error( Workspace *ws ) { char txt[MAX_LINELENGTH]; VipsBuf buf = VIPS_BUF_STATIC( txt ); int found; if( !ws->errors ) return( FALSE ); /* Search for the one after the last one. */ found = 0; ws->last_error = (Row *) slist_map2( ws->errors, (SListMap2Fn) workspace_test_error, ws, &found ); /* NULL? We've hit end of table, start again. */ if( !ws->last_error ) { found = 1; ws->last_error = (Row *) slist_map2( ws->errors, (SListMap2Fn) workspace_test_error, ws, &found ); } /* *must* have one now. */ g_assert( ws->last_error && ws->last_error->err ); model_scrollto( MODEL( ws->last_error ), MODEL_SCROLL_TOP ); row_qualified_name( ws->last_error->expr->row, &buf ); vips_buf_appends( &buf, ": " ); vips_buf_appends( &buf, ws->last_error->expr->error_top ); workspace_set_status( ws, "%s", vips_buf_firstline( &buf ) ); return( TRUE ); } void workspace_set_status( Workspace *ws, const char *fmt, ... ) { va_list ap; char buf[256]; va_start( ap, fmt ); (void) im_vsnprintf( buf, 256, fmt, ap ); va_end( ap ); IM_SETSTR( ws->status, buf ); iobject_changed( IOBJECT( ws ) ); } void workspace_set_mode( Workspace *ws, WorkspaceMode mode ) { if( ws->mode != mode ) { ws->mode = mode; /* Rebuild all the views. Yuk! It would be better to get the * views that change with workspace mode to watch the * enclosing workspace and update on that. But we'd have * connections from almost every object in the ws. We don't * change mode very often, so just loop over them all. */ icontainer_map_all( ICONTAINER( ws ), (icontainer_map_fn) iobject_changed, NULL ); } } /* New ws private defs. */ gboolean workspace_local_set( Workspace *ws, const char *txt ) { /* New kit for defs ... will destroy any old defs, since we can't have * two kits with the same name. Don't register it, we don't want it * to be autosaved on quit. */ ws->local_kit = toolkit_new( ws->local_kitg, "Workspace Locals" ); filemodel_unregister( FILEMODEL( ws->local_kit ) ); IM_SETSTR( ws->local_defs, txt ); iobject_changed( IOBJECT( ws ) ); workspace_set_modified( ws, TRUE ); attach_input_string( txt ); if( !parse_toplevel( ws->local_kit, 0 ) ) return( FALSE ); return( TRUE ); } gboolean workspace_local_set_from_file( Workspace *ws, const char *fname ) { iOpenFile *of; char *txt; if( !(of = ifile_open_read( "%s", fname )) ) return( FALSE ); if( !(txt = ifile_read( of )) ) { ifile_close( of ); return( FALSE ); } if( !workspace_local_set( ws, txt ) ) { g_free( txt ); ifile_close( of ); return( FALSE ); } filemodel_set_filename( FILEMODEL( ws->local_kit ), fname ); g_free( txt ); ifile_close( of ); return( TRUE ); } static gint workspace_jump_name_compare( iContainer *a, iContainer *b ) { int la = strlen( IOBJECT( a )->name ); int lb = strlen( IOBJECT( b )->name ); /* Smaller names first. */ if( la == lb ) return( strcmp( IOBJECT( a )->name, IOBJECT( b )->name ) ); else return( la - lb ); } static void workspace_jump_column_cb( GtkWidget *item, Column *column ) { column_scrollto( column, MODEL_SCROLL_TOP ); } static void * workspace_jump_build( Column *column, GtkWidget *menu ) { GtkWidget *item; char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_appendf( &buf, "%s - %s", IOBJECT( column )->name, IOBJECT( column )->caption ); item = gtk_menu_item_new_with_label( vips_buf_all( &buf ) ); g_signal_connect( item, "activate", G_CALLBACK( workspace_jump_column_cb ), column ); gtk_menu_append( GTK_MENU( menu ), item ); gtk_widget_show( item ); return( NULL ); } /* Update a menu with the set of current columns. */ void workspace_jump_update( Workspace *ws, GtkWidget *menu ) { GSList *columns; gtk_container_foreach( GTK_CONTAINER( menu ), (GtkCallback) gtk_widget_destroy, NULL ); columns = icontainer_get_children( ICONTAINER( ws ) ); columns = g_slist_sort( columns, (GCompareFunc) workspace_jump_name_compare ); slist_map( columns, (SListMapFn) workspace_jump_build, menu ); g_slist_free( columns ); } /* Merge file into this workspace. */ gboolean workspace_merge_file( Workspace *ws, const char *filename ) { Workspacegroup *wsg = workspace_get_workspacegroup( ws ); icontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) ); return( workspacegroup_merge_columns( wsg, filename ) ); } /* Duplicate selected rows in this workspace. */ gboolean workspace_selected_duplicate( Workspace *ws ) { Workspacegroup *wsg = workspace_get_workspacegroup( ws ); char filename[FILENAME_MAX]; if( !workspace_selected_any( ws ) ) { Row *row; if( (row = workspace_get_bottom( ws )) ) row_select( row ); } if( !temp_name( filename, "ws" ) ) return( FALSE ); if( !workspace_selected_save( ws, filename ) ) return( FALSE ); progress_begin(); if( !workspacegroup_merge_rows( wsg, filename ) ) { progress_end(); unlinkf( "%s", filename ); return( FALSE ); } unlinkf( "%s", filename ); symbol_recalculate_all(); workspace_deselect_all( ws ); column_scrollto( workspace_get_column( ws ), MODEL_SCROLL_BOTTOM ); progress_end(); return( TRUE ); } /* Bounding box of columns to be saved. Though we only really set top/left. */ static void * workspace_selected_save_box( Column *col, Rect *box ) { if( model_save_test( MODEL( col ) ) ) { if( im_rect_isempty( box ) ) { box->left = col->x; box->top = col->y; box->width = 100; box->height = 100; } else { box->left = IM_MIN( box->left, col->x ); box->top = IM_MIN( box->top, col->y ); } } return( NULL ); } /* Save just the selected objects. */ gboolean workspace_selected_save( Workspace *ws, const char *filename ) { Workspacegroup *wsg = workspace_get_workspacegroup( ws ); Rect box = { 0 }; icontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) ); workspace_map_column( ws, (column_map_fn) workspace_selected_save_box, &box ); filemodel_set_offset( FILEMODEL( wsg ), box.left, box.top ); if( !workspacegroup_save_selected( wsg, filename ) ) return( FALSE ); return( TRUE ); } gboolean workspace_rename( Workspace *ws, const char *name, const char *caption ) { if( !symbol_rename( ws->sym, name ) ) return( FALSE ); iobject_set( IOBJECT( ws ), IOBJECT( ws->sym )->name, caption ); workspace_set_modified( ws, TRUE ); symbol_recalculate_all(); return( TRUE ); } void workspace_set_locked( Workspace *ws, gboolean locked ) { if( ws->locked != locked ) { ws->locked = locked; iobject_changed( IOBJECT( ws ) ); workspace_set_modified( ws, TRUE ); } } gboolean workspace_duplicate( Workspace *ws ) { Workspacegroup *wsg = workspace_get_workspacegroup( ws ); char filename[FILENAME_MAX]; if( !temp_name( filename, "ws" ) ) return( FALSE ); icontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) ); if( !workspacegroup_save_current( wsg, filename ) ) return( FALSE ); progress_begin(); if( !workspacegroup_merge_workspaces( wsg, filename ) ) { progress_end(); unlinkf( "%s", filename ); return( FALSE ); } unlinkf( "%s", filename ); symbol_recalculate_all(); progress_end(); return( TRUE ); } nip2-8.7.1/src/editview.c0000644000175000017500000001114313351443023012071 00000000000000/* a view of a text thingy */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; static void editview_link( View *view, Model *model, View *parent ) { Editview *editview = EDITVIEW( view ); VIEW_CLASS( parent_class )->link( view, model, parent ); if( GRAPHICVIEW( view )->sview ) gtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group, editview->label ); } static void editview_refresh( vObject *vobject ) { Editview *editview = EDITVIEW( vobject ); #ifdef DEBUG printf( "editview_refresh:\n" ); #endif /*DEBUG*/ if( vobject->iobject->caption ) set_glabel( editview->label, _( "%s:" ), vobject->iobject->caption ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void editview_class_init( EditviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = editview_refresh; view_class->link = editview_link; } /* Detect cancel in a text field. */ static gboolean editview_event_cb( GtkWidget *widget, GdkEvent *ev, Editview *editview ) { gboolean handled; handled = FALSE; if( ev->key.keyval == GDK_Escape ) { handled = TRUE; /* Zap model value back into edit box. */ vobject_refresh_queue( VOBJECT( editview ) ); } return( handled ); } static void editview_activate_cb( GtkWidget *wid, Editview *editview ) { Expr *expr = HEAPMODEL( VOBJECT( editview )->iobject )->row->expr; /* If we've been changed, we'll be on the scannable list ... just * recomp. */ symbol_recalculate_all(); if( expr->err ) { expr_error_get( expr ); iwindow_alert( wid, GTK_MESSAGE_ERROR ); } } static void editview_init( Editview *editview ) { GtkWidget *hbox; gtk_container_set_border_width( GTK_CONTAINER( editview ), 2 ); hbox = gtk_hbox_new( FALSE, 12 ); gtk_box_pack_start( GTK_BOX( editview ), hbox, TRUE, FALSE, 0 ); editview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( editview->label ), 0, 0.5 ); gtk_box_pack_start( GTK_BOX( hbox ), editview->label, FALSE, FALSE, 2 ); editview->text = gtk_entry_new(); gtk_box_pack_start( GTK_BOX( hbox ), editview->text, TRUE, TRUE, 0 ); set_tooltip( editview->text, _( "Escape to cancel edit, " "press Return to accept edit and recalculate" ) ); gtk_signal_connect_object( GTK_OBJECT( editview->text ), "changed", GTK_SIGNAL_FUNC( view_changed_cb ), GTK_OBJECT( editview ) ); gtk_signal_connect( GTK_OBJECT( editview->text ), "activate", GTK_SIGNAL_FUNC( editview_activate_cb ), editview ); gtk_signal_connect( GTK_OBJECT( editview->text ), "event", GTK_SIGNAL_FUNC( editview_event_cb ), editview ); gtk_widget_show_all( hbox ); } GtkType editview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Editview", sizeof( Editview ), sizeof( EditviewClass ), (GtkClassInitFunc) editview_class_init, (GtkObjectInitFunc) editview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( type ); } void editview_set_entry( Editview *editview, const char *fmt, ... ) { va_list ap; char buf[1000]; va_start( ap, fmt ); (void) im_vsnprintf( buf, 1000, fmt, ap ); va_end( ap ); /* Make sure we don't trigger "changed" when we zap in the * text. */ gtk_signal_handler_block_by_data( GTK_OBJECT( editview->text ), editview ); set_gentry( editview->text, "%s", buf ); gtk_signal_handler_unblock_by_data( GTK_OBJECT( editview->text ), editview ); } nip2-8.7.1/src/toolview.h0000644000175000017500000000310713351443023012127 00000000000000/* View a tool as a menu item. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TOOLVIEW (toolview_get_type()) #define TOOLVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_TOOLVIEW, Toolview )) #define TOOLVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_TOOLVIEW, ToolviewClass )) #define IS_TOOLVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TOOLVIEW )) #define IS_TOOLVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOOLVIEW )) /* One of these for each top-level menu. */ struct _Toolview { View parent_class; Toolkitview *kview; GtkWidget *item; /* Menu item we made for this tool */ }; typedef struct _ToolviewClass { ViewClass parent_class; /* My methods. */ } ToolviewClass; GtkType toolview_get_type( void ); View *toolview_new( void ); nip2-8.7.1/src/toggle.c0000644000175000017500000000501113351443023011527 00000000000000/* a toggle button ... put/get methods */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static ClassmodelClass *parent_class = NULL; static View * toggle_view_new( Model *model, View *parent ) { return( toggleview_new() ); } /* Members of toggle we automate. */ static ClassmodelMember toggle_members[] = { { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_CAPTION, "caption", N_( "Caption" ), G_STRUCT_OFFSET( iObject, caption ) }, { CLASSMODEL_MEMBER_BOOLEAN, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Toggle, value ) } }; static void toggle_class_init( ToggleClass *class ) { ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ model_class->view_new = toggle_view_new; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = toggle_members; classmodel_class->n_members = IM_NUMBER( toggle_members ); } static void toggle_init( Toggle *toggle ) { toggle->value = FALSE; iobject_set( IOBJECT( toggle ), CLASS_TOGGLE, NULL ); } GType toggle_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ToggleClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) toggle_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Toggle ), 32, /* n_preallocs */ (GInstanceInitFunc) toggle_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Toggle", &info, 0 ); } return( type ); } nip2-8.7.1/src/prefs.h0000644000175000017500000000333413351443023011400 00000000000000/* Declarations for the preferences dialog. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PREFS (prefs_get_type()) #define PREFS( obj ) (GTK_CHECK_CAST( (obj), TYPE_PREFS, Prefs )) #define PREFS_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PREFS, PrefsClass )) #define IS_PREFS( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PREFS )) #define IS_PREFS_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PREFS )) typedef struct _Prefs { iDialog parent_object; /* Workspace we display. */ Workspace *ws; guint destroy_sid; Prefworkspaceview *pwview; /* (optionally) filter prefs with this. */ char *caption_filter; } Prefs; typedef struct _PrefsClass { iWindowClass parent_class; /* My methods. */ } PrefsClass; GType prefs_get_type( void ); Prefs *prefs_new( const char *caption_filter ); gboolean prefs_set( const char *name, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); nip2-8.7.1/src/secret.c0000644000175000017500000001705013351443023011541 00000000000000/* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Just show secrets we added #define DEBUG_ADD */ #include "ip.h" /* build secret sets for exprs cases: fred a = jim 12 { jim b = a + b; } jim refers to a parameter in an enclosing scope ... we add extra secret parameters to jim like this: fred a = jim [a] 12 { jim [a] b = a + b; } across class boundaries: fred a = jim { jim = class { b = a; } } now fred.jim.b refers to fred.a ... a needs to be added to the secrets on jim's constructor like this: fred a = jim [a] { jim [a] = class { b = a; } } if the secret is a class member, pass "this" instead and the inner thing then gets from that fred a = class { jim [fred.this] b = fred.this.a + b; } if the inner thing is also a class, need to get in two stages ... first get the right this, then get from that fred a = class { jim [fred.this] = class { b = jim.this.fred.this.a; } } need to work for any sort of nesting of functions and classes fred = class { b = c { c = this; } } not just params ... can involve locals of parents */ /* Add a secret. Set changed if we make a change. */ static void * secret_add( Symbol *secret, Compile *compile, gboolean *changed ) { Compile *parent = compile_get_parent( compile ); #ifdef DEBUG printf( "secret_add: considering secret " ); symbol_name_print( secret ); printf( "for " ); compile_name_print( compile ); printf( " ...\n" ); #endif /*DEBUG*/ /* If expr is a class, don't add our own this. */ if( is_class( compile ) && secret == compile->this ) return( NULL ); /* If expr already has secret as a param or secret, don't add again. */ if( g_slist_find( compile->secret, secret ) || g_slist_find( compile->param, secret ) ) return( NULL ); /* If secret is a member (param, func, whatever), add secret's * enclosing "this" instead ... expr can then get secret from there. * Unless the secret is already a "this", of course. */ if( is_class( COMPILE( ICONTAINER( secret )->parent ) ) && !is_this( secret ) ) secret = COMPILE( ICONTAINER( secret )->parent )->this; /* If compile is a member (and not a class itself), add the secret to * compile's constructor instead ... compile can get from "this". */ if( is_class( parent ) && secret != parent->this && !is_class( compile ) ) compile = parent; /* We may have moved stuff about ... check for dupes again. */ if( g_slist_find( compile->secret, secret ) || g_slist_find( compile->param, secret ) ) return( NULL ); #ifdef DEBUG_ADD printf( "secret_add: adding secret " ); symbol_name_print( secret ); printf( "to " ); compile_name_print( compile ); printf( "\n" ); #endif /*DEBUG_ADD*/ compile->secret = g_slist_append( compile->secret, secret ); compile->nsecret += 1; *changed = TRUE; return( NULL ); } /* If compile is a member, then secret lists are easy ... just use "this". */ static void * secret_set_class( Compile *compile ) { if( is_class( compile_get_parent( compile ) ) ) { Compile *parent = compile_get_parent( compile ); Symbol *ths = parent->this; gboolean changed; if( secret_add( ths, compile, &changed ) ) return( (void *) ths ); } return( NULL ); } /* child is one of compile's children ... is it reference to a parameter * in an enclosing scope? If yes, we've found a secret! */ static void * secret_is_nonlocal( Symbol *child, Compile *compile ) { gboolean changed; if( child->type == SYM_PARAM && COMPILE( ICONTAINER( child )->parent ) != compile ) { if( secret_add( child, compile, &changed ) ) return( child ); } return( NULL ); } /* Make initial secret list ... if this is a member/function, search for * references to symbols in an enclosing scope. */ static void * secret_find_nonlocal( Compile *compile ) { /* Look for any secrets. */ if( slist_map( compile->children, (SListMapFn) secret_is_nonlocal, compile ) ) return( compile ); return( NULL ); } /* Does child have any secrets that compile does not? */ static void * secret_test( Symbol *child, Compile *compile, gboolean *changed ) { /* If this is a parameter or a zombie, nothing to do. */ if( !is_value( child ) ) return( NULL ); if( child->expr->compile ) if( slist_map2( child->expr->compile->secret, (SListMap2Fn) secret_add, compile, changed ) ) return( child ); return( NULL ); } /* Close secret list ... if sym has a child with a secret sym does not have, * sym needs child's secret too. */ static void * secret_close( Compile *compile, gboolean *changed ) { if( is_class( compile ) ) { /* For classes, need to consider all of their locals. Any * secrets our locals have, we need too. */ if( icontainer_map( ICONTAINER( compile ), (icontainer_map_fn) secret_test, compile, changed ) ) return( compile ); } else { /* Look at our immediate children, any of them have secrets * we don't? */ if( slist_map2( compile->children, (SListMap2Fn) secret_test, compile, changed ) ) return( compile ); } return( NULL ); } #ifdef DEBUG /* Sub-fn of below ... add param as a secret to sym. */ static void * secret_all_add( Compile *compile, Symbol *param ) { gboolean changed; return( secret_add( param, compile, &changed ) ); } /* Sub-fn of below ... add param as a secret for all of compile's locals. */ static void * secret_all_sym( Symbol *param, Compile *compile ) { return( compile_map_all( compile, (map_compile_fn) secret_all_add, param ) ); } /* Make syms params and secrets secrets for all sub-syms. Only handy for * debugging. */ static void * secret_all( Compile *compile ) { if( slist_map( compile->param, (SListMapFn) secret_all_sym, compile ) || slist_map( compile->secret, (SListMapFn) secret_all_sym, compile ) ) return( compile ); return( NULL ); } #endif /*DEBUG*/ /* Make secret param lists for compile and all of it's sub-defs. */ void secret_build( Compile *compile ) { gboolean changed; #ifdef DEBUG_ADD printf( "secret_build: " ); symbol_name_print( compile->sym ); printf( "\n" ); #endif /*DEBUG_ADD*/ /* Look for class definitions ... all members of a * class should take a single secret, their "this" parameter. * When they in turn call their locals, they can get the * secrets they need from "this". */ (void) compile_map_all( compile, (map_compile_fn) secret_set_class, NULL ); /* Now look for non-member functions ... if they reference * parameters in an enclosing scope, add that parameter to * the secret list. */ (void) compile_map_all( compile, (map_compile_fn) secret_find_nonlocal, NULL ); /* Now take the closure of the secret lists ... have to * fix() this to get limit of secret_close(). */ do { changed = FALSE; (void) compile_map_all( compile, (map_compile_fn) secret_close, &changed ); } while( changed ); } nip2-8.7.1/src/imageview.c0000644000175000017500000006375113351443023012242 00000000000000/* display an image in a window ... watching an iImage model. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Define to trace button press events. #define EVENT */ #include "ip.h" static FloatwindowClass *parent_class = NULL; /* All the magnification menus we have. */ typedef struct _ImageviewMagmenu { const char *name; int mag; } ImageviewMagmenu; static const ImageviewMagmenu imageview_mags[] = { { "Zoom6Mode", -16 }, { "Zoom12Mode", -8 }, { "Zoom25Mode", -4 }, { "Zoom50Mode", -2 }, { "Zoom100Mode", 1 }, { "Zoom200Mode", 2 }, { "Zoom400Mode", 4 }, { "Zoom800Mode", 8 }, { "Zoom1600Mode", 16 } }; static void imageview_destroy( GtkObject *object ) { Imageview *iv; g_return_if_fail( object != NULL ); g_return_if_fail( IS_IMAGEVIEW( object ) ); iv = IMAGEVIEW( object ); #ifdef DEBUG printf( "imageview_destroy\n" ); #endif /*DEBUG*/ /* My instance destroy stuff. */ UNREF( iv->imagemodel ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void imageview_class_init( ImageviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = imageview_destroy; /* Create signals. */ /* Init methods. */ } static void imageview_init( Imageview *iv ) { iv->imagemodel = NULL; } GtkType imageview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Imageview", sizeof( Imageview ), sizeof( ImageviewClass ), (GtkClassInitFunc) imageview_class_init, (GtkObjectInitFunc) imageview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_FLOATWINDOW, &info ); } return( type ); } static void imageview_refresh_title( Imageview *iv ) { Imagemodel *imagemodel = iv->imagemodel; iImage *iimage = imagemodel->iimage; Row *row = HEAPMODEL( iimage )->row; Workspace *ws = row_get_workspace( row ); /* Can come here during ws destroy. */ if( ws ) { Conversion *conv = imagemodel->conv; Imageinfo *ii = iimage->value.ii; char txt[512]; VipsBuf buf = VIPS_BUF_STATIC( txt ); row_qualified_name_relative( ws->sym, row, &buf ); if( ii && imageinfo_is_from_file( ii ) ) vips_buf_appendf( &buf, " - %s", IOBJECT( ii )->name ); vips_buf_appendf( &buf, " - %.0f%%", 100.0 * conversion_dmag( conv->mag ) ); iwindow_set_title( IWINDOW( iv ), "%s", vips_buf_all( &buf ) ); } } /* The model has changed ... update our menus and titlebar. */ static void imageview_imagemodel_changed_cb( Imagemodel *imagemodel, Imageview *iv ) { iWindow *iwnd = IWINDOW( iv ); Conversion *conv = imagemodel->conv; GtkAction *action; int i; action = gtk_action_group_get_action( iwnd->action_group, "Status" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), imagemodel->show_status ); action = gtk_action_group_get_action( iwnd->action_group, "Control" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), imagemodel->show_convert ); action = gtk_action_group_get_action( iwnd->action_group, "Paint" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), imagemodel->show_paintbox ); action = gtk_action_group_get_action( iwnd->action_group, "Rulers" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), imagemodel->show_rulers ); for( i = 0; i < IM_NUMBER( imageview_mags ); i++ ) if( conv->mag == imageview_mags[i].mag ) { action = gtk_action_group_get_action( iwnd->action_group, imageview_mags[i].name ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), TRUE ); break; } imageview_refresh_title( iv ); } /* Region class names indexed by iRegionType. */ static const char *imageview_region_name[] = { CLASS_MARK, CLASS_HGUIDE, CLASS_VGUIDE, CLASS_ARROW, CLASS_REGION, CLASS_AREA }; /* Look up a iRegionType from an action name. */ static iRegionType imageview_get_region_type( GtkAction *action ) { /* Action names indexed by iRegionType. */ static const char *action_names[] = { "NewMark", "NewHGuide", "NewVGuide", "NewArrow", "NewRegion" }; const char *name = gtk_action_get_name( action ); int i; for( i = 0; i < IM_NUMBER( action_names ); i++ ) if( strcmp( name, action_names[i] ) == 0 ) return( (iRegionType) i ); g_assert( FALSE ); /* Keep gcc happy. */ return( FALSE ); } static void imageview_new_arrow2_action_cb( GtkAction *action, Imageview *iv ) { iRegionType rt = imageview_get_region_type( action ); Imagemodel *imagemodel = iv->imagemodel; iImage *iimage = imagemodel->iimage; Row *row = HEAPMODEL( iimage )->row; Workspace *ws = row_get_workspace( row ); Conversion *conv = imagemodel->conv; int dx = imagemodel->visible.left + imagemodel->visible.width / 2; int dy = imagemodel->visible.top + imagemodel->visible.height / 2; char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); Symbol *sym; int ix, iy; conversion_disp_to_im( conv, dx, dy, &ix, &iy ); vips_buf_appendf( &buf, "%s ", imageview_region_name[rt] ); row_qualified_name_relative( ws->sym, row, &buf ); switch( rt ) { case IREGION_MARK: vips_buf_appendf( &buf, " (%d) (%d)", ix, iy ); break; case IREGION_HGUIDE: vips_buf_appendf( &buf, " (%d)", iy ); break; case IREGION_VGUIDE: vips_buf_appendf( &buf, " (%d)", ix ); break; default: g_assert( FALSE ); } if( !(sym = workspace_add_def_recalc( ws, vips_buf_all( &buf ) )) ) { iwindow_alert( GTK_WIDGET( iv ), GTK_MESSAGE_ERROR ); return; } workspace_deselect_all( ws ); } static void imageview_new_arrow4_action_cb( GtkAction *action, Imageview *iv ) { iRegionType rt = imageview_get_region_type( action ); Imagemodel *imagemodel = iv->imagemodel; iImage *iimage = imagemodel->iimage; Row *row = HEAPMODEL( iimage )->row; Workspace *ws = row_get_workspace( row ); Conversion *conv = imagemodel->conv; Rect dr, ir; char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); Symbol *sym; Column *col; dr.left = imagemodel->visible.left + imagemodel->visible.width / 4; dr.top = imagemodel->visible.top + imagemodel->visible.height / 4; dr.width = imagemodel->visible.width / 2; dr.height = imagemodel->visible.height / 2; conversion_disp_to_im_rect( conv, &dr, &ir ); vips_buf_appendf( &buf, "%s ", imageview_region_name[rt] ); row_qualified_name_relative( ws->sym, row, &buf ); vips_buf_appendf( &buf, " (%d) (%d) %d %d", ir.left, ir.top, ir.width, ir.height ); if( !(sym = workspace_add_def_recalc( ws, vips_buf_all( &buf ) )) ) { iwindow_alert( GTK_WIDGET( iv ), GTK_MESSAGE_ERROR ); return; } col = sym->expr->row->top_col; column_scrollto( col, MODEL_SCROLL_BOTTOM ); } static void imageview_replace_action_cb( GtkAction *action, Imageview *iv ) { Imagemodel *imagemodel = iv->imagemodel; iImage *iimage = imagemodel->iimage; classmodel_graphic_replace( CLASSMODEL( iimage ), GTK_WIDGET( iv ) ); } static void imageview_save_action_cb( GtkAction *action, Imageview *iv ) { Imagemodel *imagemodel = iv->imagemodel; iImage *iimage = imagemodel->iimage; classmodel_graphic_save( CLASSMODEL( iimage ), GTK_WIDGET( iv ) ); } static void imageview_recalc_action_cb( GtkAction *action, Imageview *iv ) { Imagemodel *imagemodel = iv->imagemodel; iImage *iimage = imagemodel->iimage; Row *row = HEAPMODEL( iimage )->row; workspace_deselect_all( row->ws ); row_select( row ); if( !workspace_selected_recalc( row->ws ) ) iwindow_alert( GTK_WIDGET( iv ), GTK_MESSAGE_ERROR ); workspace_deselect_all( row->ws ); } static void imageview_header_action_cb( GtkAction *action, Imageview *iv ) { Imagemodel *imagemodel = iv->imagemodel; iImage *iimage = imagemodel->iimage; iimage_header( GTK_WIDGET( iv ), MODEL( iimage ) ); } static void imageview_zoom_in_action_cb( GtkAction *action, Imageview *iv ) { Imagemodel *imagemodel = iv->imagemodel; Conversion *conv = imagemodel->conv; conversion_set_mag( conv, conversion_double( conv->mag ) ); } static void imageview_zoom_out_action_cb( GtkAction *action, Imageview *iv ) { Imagemodel *imagemodel = iv->imagemodel; Conversion *conv = imagemodel->conv; conversion_set_mag( conv, conversion_halve( conv->mag ) ); } static void imageview_zoom_100_action_cb( GtkAction *action, Imageview *iv ) { if( iv->ip ) imagepresent_zoom_to( iv->ip, 1 ); } static void imageview_zoom_fit_action_cb( GtkAction *action, Imageview *iv ) { imagepresent_zoom_to( iv->ip, 0 ); } static void imageview_show_status_action_cb( GtkToggleAction *action, Imageview *iv ) { imagemodel_set_status( iv->imagemodel, gtk_toggle_action_get_active( action ) ); } static void imageview_show_convert_action_cb( GtkToggleAction *action, Imageview *iv ) { imagemodel_set_convert( iv->imagemodel, gtk_toggle_action_get_active( action ) ); } static void imageview_show_paintbox_action_cb( GtkToggleAction *action, Imageview *iv ) { imagemodel_set_paintbox( iv->imagemodel, gtk_toggle_action_get_active( action ) ); } static void imageview_show_rulers_action_cb( GtkToggleAction *action, Imageview *iv ) { imagemodel_set_rulers( iv->imagemodel, gtk_toggle_action_get_active( action ) ); } static void imageview_mode_action_cb( GtkRadioAction *action, GtkRadioAction *current, Imageview *iv ) { ImagemodelState state = (ImagemodelState) gtk_radio_action_get_current_value( action ); imagemodel_set_state( iv->imagemodel, state, GTK_WIDGET( iv ) ); } static void imageview_mag_action_cb( GtkRadioAction *action, GtkRadioAction *current, Imageview *iv ) { if( iv->ip ) imagepresent_zoom_to( iv->ip, gtk_radio_action_get_current_value( action ) ); } /* Our actions. */ static GtkActionEntry imageview_actions[] = { /* Menu items. */ { "ViewToolbarMenu", NULL, "_Toolbar" }, { "ViewModeMenu", NULL, "M_ode" }, { "ViewZoomMenu", NULL, "_Zoom" }, /* Actions. */ { "NewMark", NULL, N_( "_Mark" ), NULL, N_( "Create a new mark" ), G_CALLBACK( imageview_new_arrow2_action_cb ) }, { "NewHGuide", NULL, N_( "_Horizontal Guide" ), NULL, N_( "Create a new horizontal guide" ), G_CALLBACK( imageview_new_arrow2_action_cb ) }, { "NewVGuide", NULL, N_( "_Vertical Guide" ), NULL, N_( "Create a new vertical guide" ), G_CALLBACK( imageview_new_arrow2_action_cb ) }, { "NewArrow", NULL, N_( "_Arrow" ), NULL, N_( "Create a new arrow" ), G_CALLBACK( imageview_new_arrow4_action_cb ) }, { "NewRegion", NULL, N_( "_Region" ), NULL, N_( "Create a new region" ), G_CALLBACK( imageview_new_arrow4_action_cb ) }, { "Replace", NULL, N_( "Replace Image" ), NULL, N_( "Replace image from file" ), G_CALLBACK( imageview_replace_action_cb ) }, { "SaveAs", GTK_STOCK_SAVE_AS, N_( "Save Image As" ), NULL, N_( "Save image to file" ), G_CALLBACK( imageview_save_action_cb ) }, { "Recalculate", NULL, N_( "Recalculate" ), "C", N_( "Recalculate image" ), G_CALLBACK( imageview_recalc_action_cb ) }, { "Header", NULL, N_( "_Header" ), NULL, N_( "View image header" ), G_CALLBACK( imageview_header_action_cb ) }, { "ZoomIn", GTK_STOCK_ZOOM_IN, N_( "Zoom _In" ), "plus", N_( "Zoom in on mouse cursor" ), G_CALLBACK( imageview_zoom_in_action_cb ) }, { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_( "Zoom _Out" ), "minus", N_( "Zoom out" ), G_CALLBACK( imageview_zoom_out_action_cb ) }, { "Zoom100", GTK_STOCK_ZOOM_100, N_( "Zoom _100%" ), "equal", N_( "Zoom to 100%" ), G_CALLBACK( imageview_zoom_100_action_cb ) }, { "ZoomFit", GTK_STOCK_ZOOM_FIT, N_( "Zoom to _Fit" ), NULL, N_( "Zoom to fit image to window" ), G_CALLBACK( imageview_zoom_fit_action_cb ) } }; static GtkToggleActionEntry imageview_toggle_actions[] = { { "Status", NULL, N_( "_Status" ), NULL, N_( "Show status bar" ), G_CALLBACK( imageview_show_status_action_cb ), TRUE }, { "Control", NULL, N_( "_Display Control" ), NULL, N_( "Show display control bar" ), G_CALLBACK( imageview_show_convert_action_cb ), TRUE }, { "Paint", NULL, N_( "_Paint" ), NULL, N_( "Show paint bar" ), G_CALLBACK( imageview_show_paintbox_action_cb ), FALSE }, { "Rulers", NULL, N_( "_Rulers" ), NULL, N_( "Show rulers" ), G_CALLBACK( imageview_show_rulers_action_cb ), FALSE } }; static GtkRadioActionEntry imageview_mode_radio_actions[] = { { "SelectMode", NULL, N_( "_Select" ), NULL, N_( "Select and modify selections" ), IMAGEMODEL_SELECT }, { "PanMode", NULL, N_( "_Pan" ), NULL, N_( "Pan image" ), IMAGEMODEL_PAN }, { "ZoomInMode", NULL, N_( "Zoom _In" ), NULL, N_( "Zoom in on mouse cursor" ), IMAGEMODEL_MAGIN }, { "ZoomOutMode", NULL, N_( "Zoom _Out" ), NULL, N_( "Zoom out" ), IMAGEMODEL_MAGOUT } }; static GtkRadioActionEntry imageview_zoom_radio_actions[] = { { "Zoom6Mode", NULL, N_( "6%" ), NULL, N_( "Zoom to 6%" ), -16 }, { "Zoom12Mode", NULL, N_( "12%" ), NULL, N_( "Zoom to 12%" ), -8 }, { "Zoom25Mode", NULL, N_( "25%" ), NULL, N_( "Zoom to 25%" ), -4 }, { "Zoom50Mode", NULL, N_( "50%" ), NULL, N_( "Zoom to 50%" ), -2 }, { "Zoom100Mode", NULL, N_( "100%" ), NULL, N_( "Zoom to 100%" ), 1 }, { "Zoom200Mode", NULL, N_( "200%" ), NULL, N_( "Zoom to 200%" ), 2 }, { "Zoom400Mode", NULL, N_( "400%" ), NULL, N_( "Zoom to 400%" ), 4 }, { "Zoom800Mode", NULL, N_( "800%" ), NULL, N_( "Zoom to 800%" ), 8 }, { "Zoom1600Mode", NULL, N_( "1600%" ), NULL, N_( "Zoom to 1600%" ), 16 } }; static const char *imageview_menubar_ui_description = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static gint imageview_event( GtkWidget *widget, GdkEvent *event, Imageview *iv ) { gboolean handled = FALSE; #ifdef EVENT if( event->type == GDK_BUTTON_PRESS ) printf( "imageview_event: GDK_BUTTON_PRESS\n" ); #endif /*EVENT*/ switch( event->type ) { case GDK_MOTION_NOTIFY: { Imagemodel *imagemodel = iv->imagemodel; Conversion *conv = imagemodel->conv; int ix, iy; conversion_disp_to_im( conv, event->button.x, event->button.y, &ix, &iy ); statusview_mouse( iv->sv, ix, iy ); } break; case GDK_BUTTON_PRESS: switch( event->button.button ) { case 3: { iWindow *iwnd = IWINDOW( iv ); GtkWidget *popup; popup = gtk_ui_manager_get_widget( iwnd->ui_manager, "/ImageviewPopup" ); gtk_menu_popup( GTK_MENU( popup ), NULL, NULL, (GtkMenuPositionFunc) NULL, NULL, 3, event->button.time ); handled = TRUE; } break; default: break; } break; default: break; } return( handled ); } static gboolean imageview_filedrop( Imageview *iv, const char *file ) { gboolean result; if( (result = iimage_replace( iv->imagemodel->iimage, file )) ) symbol_recalculate_all(); return( result ); } static void imageview_build( Imageview *iv, GtkWidget *vbox, iImage *iimage ) { iWindow *iwnd = IWINDOW( iv ); GError *error; GtkWidget *mbar; GtkWidget *frame; GList *focus_chain; /* All the model parts for our set of views. */ iv->imagemodel = imagemodel_new( iimage ); g_object_ref( G_OBJECT( iv->imagemodel ) ); iobject_sink( IOBJECT( iv->imagemodel ) ); iv->imagemodel_changed_sid = g_signal_connect( G_OBJECT( iv->imagemodel ), "changed", G_CALLBACK( imageview_imagemodel_changed_cb ), iv ); /* Make main menu bar */ gtk_action_group_add_actions( iwnd->action_group, imageview_actions, G_N_ELEMENTS( imageview_actions ), GTK_WINDOW( iv ) ); gtk_action_group_add_toggle_actions( iwnd->action_group, imageview_toggle_actions, G_N_ELEMENTS( imageview_toggle_actions ), GTK_WINDOW( iv ) ); gtk_action_group_add_radio_actions( iwnd->action_group, imageview_mode_radio_actions, G_N_ELEMENTS( imageview_mode_radio_actions ), IMAGEMODEL_SELECT, G_CALLBACK( imageview_mode_action_cb ), GTK_WINDOW( iv ) ); gtk_action_group_add_radio_actions( iwnd->action_group, imageview_zoom_radio_actions, G_N_ELEMENTS( imageview_zoom_radio_actions ), 1, G_CALLBACK( imageview_mag_action_cb ), GTK_WINDOW( iv ) ); error = NULL; if( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager, imageview_menubar_ui_description, -1, &error ) ) { g_message( "building menus failed: %s", error->message ); g_error_free( error ); exit( EXIT_FAILURE ); } mbar = gtk_ui_manager_get_widget( iwnd->ui_manager, "/ImageviewMenubar" ); gtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 ); gtk_widget_show( mbar ); /* This will set to NULL if we don't have infobar support. */ if( (IWINDOW( iv )->infobar = infobar_new()) ) gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( IWINDOW( iv )->infobar ), FALSE, FALSE, 0 ); /* Status bar. */ iv->sv = statusview_new( iv->imagemodel ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( iv->sv ), FALSE, FALSE, 0 ); /* Conversion bar. */ iv->cv = conversionview_new( iv->imagemodel ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( iv->cv ), FALSE, FALSE, 0 ); /* Paintbox bar. */ iv->pbv = paintboxview_new( iv->imagemodel ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( iv->pbv ), FALSE, FALSE, 0 ); /* Image area. */ frame = gtk_frame_new( NULL ); gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_OUT ); gtk_widget_show( frame ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 ); iv->ip = imagepresent_new( iv->imagemodel ); gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( iv->ip ) ); gtk_widget_show( GTK_WIDGET( iv->ip ) ); gtk_signal_connect_after( GTK_OBJECT( iv->ip->id ), "event", GTK_SIGNAL_FUNC( imageview_event ), iv ); /* Position and size to restore? */ if( MODEL( iimage )->window_width != -1 ) { /* Floatwindow will set pos/size. */ iv->imagemodel->show_status = iimage->show_status; iv->imagemodel->show_paintbox = iimage->show_paintbox; iv->imagemodel->show_convert = iimage->show_convert; iv->imagemodel->show_rulers = iimage->show_rulers; iv->imagemodel->scale = iimage->scale; iv->imagemodel->offset = iimage->offset; iv->imagemodel->falsecolour = iimage->falsecolour; iv->imagemodel->type = iimage->type; /* Our caller must call imagepresent_set_mag_pos() after * _show(). Not accurate if we set it here. */ } else { int w, h; /* Set initial size. This is really hard to do right :-( These * magic numbers will break with different themes. FIXME ... maybe realize the window but don't map it, calculate border size, then set default size and map? yuk! the magic numbers here are hard to derive, there are many, many widgets piled up together to make this window last set correctly for clearlooks */ w = IM_MIN( IMAGE_WINDOW_WIDTH, iv->imagemodel->conv->image.width + 14 ); h = IM_MIN( IMAGE_WINDOW_HEIGHT, iv->imagemodel->conv->image.height + 39 ); gtk_window_set_default_size( GTK_WINDOW( iv ), w, h ); conversion_set_mag( iv->imagemodel->conv, 1 ); } /* Set as file drop destination */ filedrop_register( GTK_WIDGET( iv ), (FiledropFunc) imageview_filedrop, iv ); /* Override the focus_chain ... we want the imagedisplay first. */ focus_chain = NULL; focus_chain = g_list_append( focus_chain, iv->ip ); focus_chain = g_list_append( focus_chain, iv->cv ); focus_chain = g_list_append( focus_chain, iv->pbv ); gtk_container_set_focus_chain( GTK_CONTAINER( vbox ), focus_chain ); g_list_free( focus_chain ); gtk_widget_grab_focus( GTK_WIDGET( iv->ip->id ) ); } static void * imageview_add_region( Classmodel *classmodel, Imageview *iv ) { iRegionInstance *instance; if( MODEL( classmodel )->display && (instance = classmodel_get_instance( classmodel )) ) { Regionview *regionview = regionview_new( classmodel, &instance->area, iv->ip ); PElement *root = &HEAPMODEL( classmodel )->row->expr->root; /* Look at the class we are drawing, set the display type. */ regionview_set_type( regionview, root ); } return( NULL ); } static void imageview_popdown( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Imageview *iv = IMAGEVIEW( iwnd ); Imagemodel *imagemodel = iv->imagemodel; iImage *iimage = imagemodel->iimage; Conversion *conv = imagemodel->conv; /* We have to note position/size in popdown rather than destroy, since * the widgets have to all still be extant. */ /* Save the centre of the window in image cods. */ conversion_disp_to_im( conv, imagemodel->visible.left + imagemodel->visible.width / 2, imagemodel->visible.top + imagemodel->visible.height / 2, &iimage->image_left, &iimage->image_top ); iimage->image_mag = conv->mag; iimage->show_status = imagemodel->show_status; iimage->show_paintbox = imagemodel->show_paintbox; iimage->show_rulers = imagemodel->show_rulers; /* Signal changed on iimage if we save the convert settings. This will * make the thumbnail update. */ if( iimage->show_convert != imagemodel->show_convert || iimage->scale != imagemodel->scale || iimage->offset != imagemodel->offset || iimage->falsecolour != imagemodel->falsecolour || iimage->type != imagemodel->type ) { iimage->show_convert = imagemodel->show_convert; iimage->scale = imagemodel->scale; iimage->offset = imagemodel->offset; iimage->falsecolour = imagemodel->falsecolour; iimage->type = imagemodel->type; iobject_changed( IOBJECT( iimage ) ); } nfn( sys, IWINDOW_YES ); } static void imageview_link( Imageview *iv, iImage *iimage, GtkWidget *parent ) { iwindow_set_build( IWINDOW( iv ), (iWindowBuildFn) imageview_build, iimage, NULL, NULL ); iwindow_set_popdown( IWINDOW( iv ), imageview_popdown, NULL ); iwindow_set_parent( IWINDOW( iv ), parent ); floatwindow_link( FLOATWINDOW( iv ), MODEL( iimage ) ); iwindow_build( IWINDOW( iv ) ); slist_map( iimage->classmodels, (SListMapFn) imageview_add_region, iv ); /* Initial "changed" on the model to get all views to init. */ iobject_changed( IOBJECT( iv->imagemodel ) ); } Imageview * imageview_new( iImage *iimage, GtkWidget *parent ) { Imageview *iv = gtk_type_new( TYPE_IMAGEVIEW ); imageview_link( iv, iimage, parent ); /* This is odd ... we wouldn't normally _show() the widget in _new(), * but restoring the scroll position doesn't work unless the window is * visible. We have to show here. */ gtk_widget_show( GTK_WIDGET( iv ) ); if( MODEL( iimage )->window_width != -1 ) imagepresent_set_mag_pos( iv->ip, iimage->image_mag, iimage->image_left, iimage->image_top ); return( iv ); } /* Make an imageview, and try to make area (image cods) visible. width/height * can be -ve */ Imageview * imageview_new_area( iImage *iimage, Rect *area, GtkWidget *parent ) { Imageview *iv = imageview_new( iimage, parent ); Imagemodel *imagemodel = iv->imagemodel; Conversion *conv = imagemodel->conv; int shrink_x, shrink_y, shrink; /* Calculate a shrink factor which should make all the region * visible ... don't zoom. */ shrink_x = (abs( area->width ) + conv->canvas.width) / conv->canvas.width; shrink_y = (abs( area->height ) + conv->canvas.height) / conv->canvas.height; shrink = -IM_MAX( 1, IM_MAX( shrink_x, shrink_y ) ); if( shrink == -1 ) shrink = 1; imagepresent_set_mag_pos( iv->ip, shrink, area->left + area->width / 2, area->top + area->height / 2 ); return( iv ); } nip2-8.7.1/src/imagepresent.h0000644000175000017500000000650213351443023012744 00000000000000/* Imagepresent widget stuff. */ /* Copyright (C) 1991-2001 The Natoinal Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IMAGEPRESENT (imagepresent_get_type()) #define IMAGEPRESENT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IMAGEPRESENT, Imagepresent )) #define IMAGEPRESENT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_IMAGEPRESENT, ImagepresentClass)) #define IS_IMAGEPRESENT( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEPRESENT )) #define IS_IMAGEPRESENT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEPRESENT )) #define IMAGEPRESENT_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_IMAGEPRESENT, ImagepresentClass )) /* Track an image view canvas in one of these. */ struct _Imagepresent { GtkBin parent_object; /* Context. */ Imagemodel *imagemodel; /* Keep model parts of widgets here */ /* Sub-widgets. */ Imagedisplay *id; /* Image we display */ GtkScrolledWindow *swin; GtkAdjustment *hadj; GtkAdjustment *vadj; GtkHRuler *hrule; /* Rulers */ GtkVRuler *vrule; GtkEventBox *heb; /* EventBoxes holding rulers */ GtkEventBox *veb; iWindowCursorContext *cntxt; GtkWidget *ruler_menu; /* Panning stuff. */ guint dx, dy; /* Drag start position */ /* Last known mouse position, mouse in window. */ int last_x, last_y; gboolean inside; /* Background scroll stuff. */ guint scroll_tid; int u, v; /* Rubberbanding. */ Regionview *regionview; /* region rubberband display */ Rect floating; /* rubberband area */ /* Painting stuff. */ int paint_last_x; int paint_last_y; /* Regionviews drawing on us. Used for snap-to-guide stuff. */ GSList *regionviews; /* The regionview that's currently grabbed ... maintained for us by * regionview.c ... see regionview_attach()/_detach() */ Regionview *grabbed; }; /* Class structure. */ typedef struct _ImagepresentClass { /* Our parent. */ GtkBinClass parent_class; } ImagepresentClass; gboolean imagepresent_snap_point( Imagepresent *ip, int x, int y, int *sx, int *sy ); gboolean imagepresent_snap_rect( Imagepresent *ip, Rect *in, Rect *out ); void imagepresent_paint_recalc( Imagepresent *ip ); GType imagepresent_get_type( void ); Imagepresent *imagepresent_new( Imagemodel *imagemodel ); void imagepresent_set_position( Imagepresent *ip, int x, int w ); void imagepresent_set_mag_pos( Imagepresent *ip, int mag, int ix, int iy ); void imagepresent_zoom_to( Imagepresent *ip, int mag ); void imagepresent_scroll_start( Imagepresent *ip, int u, int v ); void imagepresent_scroll_stop( Imagepresent *ip ); nip2-8.7.1/src/subcolumn.h0000644000175000017500000000532313351443023012270 00000000000000/* a column of rows in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_SUBCOLUMN (subcolumn_get_type()) #define SUBCOLUMN( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_SUBCOLUMN, Subcolumn )) #define SUBCOLUMN_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_SUBCOLUMN, SubcolumnClass)) #define IS_SUBCOLUMN( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_SUBCOLUMN )) #define IS_SUBCOLUMN_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_SUBCOLUMN )) #define SUBCOLUMN_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_SUBCOLUMN, SubcolumnClass )) /* Predicate on a row. */ typedef gboolean (*RowPred)( Row * ); /* Control class member visibility with these. */ typedef struct { const char *name; RowPred pred; } SubcolumnVisibility; struct _Subcolumn { Heapmodel parent_class; /* Our context. */ Column *col; /* Enclosing column (or NULL) */ Subcolumn *scol; /* Enclosing subcolumn (or NULL) */ Column *top_col; /* Topmost enclosing column */ Subcolumn *top_scol; /* Topmost enclosing subcolumn */ int vislevel; /* Visibility level */ gboolean is_top; /* TRUE if parent is a column */ Element base; /* "this" for our members */ gboolean known_private; /* TRUE after top-level clone .. can write! */ /* For subcolumns representing a class instance, the rows for the * "this" and "super" members. */ Row *this; Row *super; }; typedef struct _SubcolumnClass { HeapmodelClass parent_class; /* My methods. */ } SubcolumnClass; extern const SubcolumnVisibility subcolumn_visibility[]; extern const int subcolumn_nvisibility; void *subcolumn_map( Subcolumn *scol, row_map_fn fn, void *a, void *b ); GType subcolumn_get_type( void ); void *subcolumn_new_view( Subcolumn *scol ); Subcolumn *subcolumn_new( Rhs *rhs, Column *col ); void subcolumn_set_vislevel( Subcolumn *scol, int vislevel ); gboolean subcolumn_make_private( Subcolumn *scol ); nip2-8.7.1/src/number.h0000644000175000017500000000270413351443023011551 00000000000000/* a colour number in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_NUMBER (number_get_type()) #define NUMBER( obj ) (GTK_CHECK_CAST( (obj), TYPE_NUMBER, Number )) #define NUMBER_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_NUMBER, NumberClass )) #define IS_NUMBER( obj ) (GTK_CHECK_TYPE( (obj), TYPE_NUMBER )) #define IS_NUMBER_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_NUMBER )) struct _Number { Classmodel parent_class; /* Class fields. */ double value; }; typedef struct _NumberClass { ClassmodelClass parent_class; /* My methods. */ } NumberClass; GType number_get_type( void ); nip2-8.7.1/src/program.h0000644000175000017500000000562313351443023011733 00000000000000/* Decls for program.c ... edit window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PROGRAM (program_get_type()) #define PROGRAM( obj ) (GTK_CHECK_CAST( (obj), TYPE_PROGRAM, Program )) #define PROGRAM_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PROGRAM, ProgramClass )) #define IS_PROGRAM( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PROGRAM )) #define IS_PROGRAM_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PROGRAM )) struct _Program { iWindow parent_class; /* The set of kits we manage. */ Toolkitgroup *kitg; GtkWidget *text; gboolean dirty; /* Has the text changed since we set it */ guint text_hash; /* Hash of the last text we set */ GtkWidget *tree; Pane *lpane; int pane_position; Pane *rpane; int rpane_position; gboolean rpane_open; Defbrowser *defbrowser; guint refresh_timeout; /* Timeout for UI refresh */ guint select_changed_sid; guint row_inserted_sid; guint row_deleted_sid; /* Track during drags. */ Toolkit *to_kit; int to_pos; /* Store for kit/tool view. */ GtkTreeStore *store; /* Listen for all kit changes here. */ guint kitgroup_changed_sid; guint kitgroup_destroy_sid; /* The current kit. */ Toolkit *kit; guint kit_destroy_sid; /* The selected tool. */ Tool *tool; int pos; /* Position of tool in kit */ guint tool_destroy_sid; /* Current search settings. */ char *search; gboolean csens; /* Case sensitive */ gboolean fromtop; /* Start search from beginning again */ #ifdef HAVE_GREGEX gboolean regexp; /* Interpret as regexp */ GRegex *comp; /* Compiled pattern */ #endif /*HAVE_GREGEX*/ /* Current search position. */ Symbol *find_sym; /* Tool containing search point */ size_t find_start; /* Offset into tool text of found string */ size_t find_end; guint find_sym_destroy_sid;/* Watch for find_sym death here */ }; typedef struct _ProgramClass { iWindowClass parent_class; /* My methods. */ } ProgramClass; GtkType program_get_type( void ); GtkWidget *program_text_new( void ); Program *program_new( Toolkitgroup *kitg ); gboolean program_select( Program *program, Model *model ); nip2-8.7.1/src/popupbutton.c0000644000175000017500000001125513351443023012654 00000000000000/* a button that displays a popup menu * * quick hack from totem-plugin-viewer.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GtkToggleButtonClass *popupbutton_parent_class = NULL; static void popupbutton_class_init( PopupbuttonClass *class ) { popupbutton_parent_class = g_type_class_peek_parent( class ); } static void popupbutton_init( Popupbutton *popupbutton ) { popupbutton->menu = NULL; } GType popupbutton_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( PopupbuttonClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) popupbutton_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Popupbutton ), 32, /* n_preallocs */ (GInstanceInitFunc) popupbutton_init, }; type = g_type_register_static( GTK_TYPE_TOGGLE_BUTTON, "Popupbutton", &info, 0 ); } return( type ); } static void popupbutton_position_func( GtkMenu *menu, gint *x, gint *y, gboolean *push_in, GtkWidget *button ) { GtkRequisition menu_req; GtkTextDirection direction; GtkAllocation allocation; gtk_widget_size_request( GTK_WIDGET( menu ), &menu_req ); direction = gtk_widget_get_direction( button ); gdk_window_get_origin( gtk_widget_get_window( button ), x, y ); gtk_widget_get_allocation( button, &allocation ); *x += allocation.x; *y += allocation.y; if( direction == GTK_TEXT_DIR_LTR ) *x += VIPS_MAX( allocation.width - menu_req.width, 0 ); else if( menu_req.width > allocation.width ) *x -= menu_req.width - allocation.width; *y += allocation.height; *push_in = FALSE; } static void popupbutton_over_arrow( Popupbutton *popupbutton, GdkEventButton *event ) { GtkWidget *menu = popupbutton->menu; gtk_menu_popup( GTK_MENU( menu ), NULL, NULL, (GtkMenuPositionFunc) popupbutton_position_func, popupbutton, event ? event->button : 0, event ? event->time : gtk_get_current_event_time() ); } static void popupbutton_toggled_cb( Popupbutton *popupbutton ) { GtkWidget *menu = popupbutton->menu; if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( popupbutton ) ) && !gtk_widget_get_visible( menu ) ) { /* We get here only when the menu is activated by a key * press, so that we can select the first menu item. */ popupbutton_over_arrow( popupbutton, NULL ); gtk_menu_shell_select_first( GTK_MENU_SHELL( menu ), FALSE ); } } static gboolean popupbutton_button_press_event_cb( Popupbutton *popupbutton, GdkEventButton *event ) { if( event->button == 1 ) { GtkWidget *menu = popupbutton->menu; if( !gtk_widget_get_visible( menu ) ) { popupbutton_over_arrow( popupbutton, event ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( popupbutton ), TRUE ); } else { gtk_menu_popdown( GTK_MENU( menu ) ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( popupbutton ), FALSE ); } return TRUE; } return FALSE; } Popupbutton * popupbutton_new( void ) { Popupbutton *popupbutton; GtkWidget *image; popupbutton = g_object_new( TYPE_POPUPBUTTON, NULL ); image = gtk_image_new_from_stock( GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU ); gtk_container_add( GTK_CONTAINER( popupbutton ), image ); gtk_widget_show( image ); g_signal_connect( popupbutton, "toggled", G_CALLBACK( popupbutton_toggled_cb ), NULL ); g_signal_connect( popupbutton, "button-press-event", G_CALLBACK( popupbutton_button_press_event_cb ), NULL ); return( popupbutton ); } static void popupbutton_menu_unmap_cb( GtkWidget *menu, Popupbutton *popupbutton ) { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( popupbutton ), FALSE ); } void popupbutton_set_menu( Popupbutton *popupbutton, GtkWidget *menu ) { g_assert( !popupbutton->menu ); popupbutton->menu = menu; g_signal_connect( menu, "unmap", G_CALLBACK( popupbutton_menu_unmap_cb ), popupbutton ); } nip2-8.7.1/src/prefcolumnview.c0000644000175000017500000000603713351443023013324 00000000000000/* a view of a column */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; static void prefcolumnview_refresh( vObject *vobject ) { Prefcolumnview *pcview = PREFCOLUMNVIEW( vobject ); Column *col = COLUMN( VOBJECT( pcview )->iobject ); char buf[256]; char buf2[256]; escape_markup( IOBJECT( col )->caption, buf2, 256 ); im_snprintf( buf, 256, "%s", buf2 ); gtk_label_set_markup( GTK_LABEL( pcview->lab ), buf ); /* Closed columns are hidden. */ widget_visible( GTK_WIDGET( pcview ), col->open ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void prefcolumnview_child_add( View *parent, View *child ) { Prefcolumnview *pcview = PREFCOLUMNVIEW( parent ); Subcolumnview *sview = SUBCOLUMNVIEW( child ); VIEW_CLASS( parent_class )->child_add( parent, child ); gtk_box_pack_end( GTK_BOX( pcview ), GTK_WIDGET( sview ), FALSE, FALSE, 0 ); } static void prefcolumnview_class_init( PrefcolumnviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = prefcolumnview_refresh; view_class->child_add = prefcolumnview_child_add; } static void prefcolumnview_init( Prefcolumnview *pcview ) { pcview->lab = gtk_label_new( "" ); gtk_box_pack_start( GTK_BOX( pcview ), pcview->lab, FALSE, FALSE, 2 ); gtk_misc_set_padding( GTK_MISC( pcview->lab ), 2, 6 ); gtk_misc_set_alignment( GTK_MISC( pcview->lab ), 0, 0.5 ); gtk_widget_show_all( GTK_WIDGET( pcview ) ); } GtkType prefcolumnview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Prefcolumnview", sizeof( Prefcolumnview ), sizeof( PrefcolumnviewClass ), (GtkClassInitFunc) prefcolumnview_class_init, (GtkObjectInitFunc) prefcolumnview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VIEW, &info ); } return( type ); } View * prefcolumnview_new( void ) { Prefcolumnview *pcview = gtk_type_new( TYPE_PREFCOLUMNVIEW ); return( VIEW( pcview ) ); } nip2-8.7.1/src/managedgobject.c0000644000175000017500000000602113351443023013202 00000000000000/* a managed gobject */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static ManagedClass *parent_class = NULL; static void managedgobject_dispose( GObject *gobject ) { Managedgobject *managedgobject = MANAGEDGOBJECT( gobject ); #ifdef DEBUG printf( "managedgobject_dispose: " ); iobject_print( IOBJECT( managedgobject ) ); #endif /*DEBUG*/ IM_FREEF( g_object_unref, managedgobject->object ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void managedgobject_info( iObject *iobject, VipsBuf *buf ) { Managedgobject *managedgobject = MANAGEDGOBJECT( iobject ); if( VIPS_IS_OBJECT( managedgobject->object ) ) vips_object_summary( VIPS_OBJECT( managedgobject->object ), buf ); else IOBJECT_CLASS( parent_class )->info( iobject, buf ); } static void managedgobject_class_init( ManagedgobjectClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = managedgobject_dispose; iobject_class->info = managedgobject_info; } static void managedgobject_init( Managedgobject *managedgobject ) { #ifdef DEBUG printf( "managedgobject_init: %p\n", managedgobject ); #endif /*DEBUG*/ managedgobject->object = NULL; } GType managedgobject_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ManagedgobjectClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) managedgobject_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Managedgobject ), 32, /* n_preallocs */ (GInstanceInitFunc) managedgobject_init, }; type = g_type_register_static( TYPE_MANAGED, "Managedgobject", &info, 0 ); } return( type ); } Managedgobject * managedgobject_new( Heap *heap, GObject *object ) { Managedgobject *managedgobject = g_object_new( TYPE_MANAGEDGOBJECT, NULL ); managed_link_heap( MANAGED( managedgobject ), heap ); managedgobject->object = object; g_object_ref( object ); MANAGED( managedgobject )->hash = GPOINTER_TO_UINT( object ); return( managedgobject ); } nip2-8.7.1/src/plotwindow.h0000644000175000017500000000323613351443023012470 00000000000000/* a plotpresent in a floating window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PLOTWINDOW (plotwindow_get_type()) #define PLOTWINDOW( obj ) (GTK_CHECK_CAST( (obj), TYPE_PLOTWINDOW, Plotwindow )) #define PLOTWINDOW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTWINDOW, PlotwindowClass )) #define IS_PLOTWINDOW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTWINDOW )) #define IS_PLOTWINDOW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTWINDOW )) struct _Plotwindow { Floatwindow parent_class; /* The model we watch. */ Plotmodel *plotmodel; /* Widgets. */ Plotstatus *plotstatus; Plotpresent *plotpresent; }; typedef struct _PlotwindowClass { FloatwindowClass parent_class; /* My methods. */ } PlotwindowClass; GtkType plotwindow_get_type( void ); Plotwindow *plotwindow_new( Plot *plot, GtkWidget *parent ); nip2-8.7.1/src/view.c0000644000175000017500000005334013351443023011230 00000000000000/* abstract base class for items which can form a row in a tally */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define DEBUG_VIEWCHILD */ /* Time each refresh #define DEBUG_TIME */ #include "ip.h" static vObjectClass *parent_class = NULL; static GSList *view_scannable = NULL; static GSList *view_resettable = NULL; void view_scannable_register( View *view ) { /* Must have a scan method. */ g_assert( VIEW_GET_CLASS( view )->scan ); if( !view->scannable ) { view_scannable = g_slist_prepend( view_scannable, view ); view->scannable = TRUE; } } void view_scannable_unregister( View *view ) { if( view->scannable ) { view_scannable = g_slist_remove( view_scannable, view ); view->scannable = FALSE; } } gboolean view_scan_all( void ) { if( slist_map( view_scannable, (SListMapFn) view_scan, NULL ) ) return( FALSE ); view_reset_all(); return( TRUE ); } void view_resettable_register( View *view ) { /* Must have a reset method. */ g_assert( VIEW_GET_CLASS( view )->reset ); if( !view->resettable ) { view_resettable = g_slist_prepend( view_resettable, view ); view->resettable = TRUE; } } void view_resettable_unregister( View *view ) { if( view->resettable ) { view_resettable = g_slist_remove( view_resettable, view ); view->resettable = FALSE; } } void view_reset_all( void ) { (void) slist_map( view_resettable, (SListMapFn) view_reset, NULL ); } /* Should a viewchild be displayed? If model->display is true, also give the * enclosing view a chance to filter. */ static gboolean view_viewchild_display( ViewChild *viewchild ) { View *parent_view = viewchild->parent_view; Model *child_model = viewchild->child_model; ViewClass *parent_view_class = VIEW_GET_CLASS( parent_view ); if( child_model->display && parent_view_class->display ) return( parent_view_class->display( parent_view, child_model ) ); return( child_model->display ); } /* One of the children of the model we watch has changed ... create or destroy * the child view as required. */ static void view_viewchild_changed( Model *model, ViewChild *viewchild ) { gboolean display = view_viewchild_display( viewchild ); View *child = viewchild->child_view; if( !display && child ) { #ifdef DEBUG_VIEWCHILD printf( "view_viewchild_changed: %s \"%s\", removing view\n", G_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) ); printf( "view_viewchild_changed: %s\n", G_OBJECT_TYPE_NAME( child ) ); #endif /*DEBUG_VIEWCHILD*/ DESTROY_GTK( child ); } else if( display && !child ) { #ifdef DEBUG_VIEWCHILD printf( "view_viewchild_changed: %s \"%s\", adding view\n", G_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) ); #endif /*DEBUG_VIEWCHILD*/ model_view_new( model, viewchild->parent_view ); } } static ViewChild * view_viewchild_new( View *parent_view, Model *child_model ) { ViewChild *viewchild; #ifdef DEBUG_VIEWCHILD printf( "view_viewchild_new: view \"%s\" watching %s \"%s\"\n", G_OBJECT_TYPE_NAME( parent_view ), G_OBJECT_TYPE_NAME( child_model ), NN( IOBJECT( child_model )->name ) ); #endif /*DEBUG_VIEWCHILD*/ if( !(viewchild = INEW( NULL, ViewChild )) ) return( NULL ); viewchild->parent_view = parent_view; viewchild->child_model = child_model; viewchild->child_model_changed_sid = g_signal_connect( child_model, "changed", G_CALLBACK( view_viewchild_changed ), viewchild ); viewchild->child_view = NULL; parent_view->managed = g_slist_append( parent_view->managed, viewchild ); return( viewchild ); } static void * view_viewchild_destroy( ViewChild *viewchild ) { View *parent_view = viewchild->parent_view; View *child_view = viewchild->child_view; #ifdef DEBUG_VIEWCHILD printf( "view_viewchild_destroy: view %s watching model %s\n", G_OBJECT_TYPE_NAME( viewchild->parent_view ), G_OBJECT_TYPE_NAME( viewchild->child_model ) ); #endif /*DEBUG_VIEWCHILD*/ if( child_view ) { g_assert( child_view->parent == parent_view ); child_view->parent = NULL; } FREESID( viewchild->child_model_changed_sid, viewchild->child_model ); parent_view->managed = g_slist_remove( parent_view->managed, viewchild ); im_free( viewchild ); return( NULL ); } static void * view_viewchild_test_child_model( ViewChild *viewchild, Model *child_model ) { #ifdef DEBUG printf( "view_viewchild_test_child_model: model %s \"%s\"\n", G_OBJECT_TYPE_NAME( child_model ), NN( IOBJECT( child_model )->name ) ); #endif /*DEBUG*/ if( viewchild->child_model == child_model ) return( viewchild ); return( NULL ); } /* Do we have a model? */ gboolean view_hasmodel( View *view ) { return( VOBJECT( view )->iobject != NULL ); } void * view_model_test( View *view, Model *model ) { if( VOBJECT( view )->iobject == IOBJECT( model ) ) return( view ); return( NULL ); } /* Link to enclosing model and view. */ void view_link( View *view, Model *model, View *parent ) { VIEW_GET_CLASS( view )->link( view, model, parent ); } /* Add a child. */ void view_child_add( View *parent, View *child ) { VIEW_GET_CLASS( parent )->child_add( parent, child ); } /* Remove a child. */ void view_child_remove( View *child ) { View *parent = child->parent; VIEW_GET_CLASS( parent )->child_remove( parent, child ); } /* Child needs repositioning. */ void view_child_position( View *child ) { View *parent = child->parent; VIEW_GET_CLASS( parent )->child_position( parent, child ); } /* Pop child to front of stacking order. */ void view_child_front( View *child ) { View *parent = child->parent; if( parent ) VIEW_GET_CLASS( parent )->child_front( parent, child ); } /* Break link to model. */ void view_unlink( View *view ) { g_assert( view != NULL ); g_assert( VOBJECT( view )->iobject != NULL ); g_assert( IS_VIEW( view ) && IS_MODEL( VOBJECT( view )->iobject ) ); FREESID( view->pos_changed_sid, VOBJECT( view )->iobject ); FREESID( view->scrollto_sid, VOBJECT( view )->iobject ); FREESID( view->layout_sid, VOBJECT( view )->iobject ); FREESID( view->reset_sid, VOBJECT( view )->iobject ); FREESID( view->front_sid, VOBJECT( view )->iobject ); FREESID( view->child_add_sid, VOBJECT( view )->iobject ); FREESID( view->child_remove_sid, VOBJECT( view )->iobject ); FREESID( view->child_detach_sid, VOBJECT( view )->iobject ); FREESID( view->child_attach_sid, VOBJECT( view )->iobject ); } static void view_destroy( GtkObject *object ) { View *view; g_return_if_fail( object != NULL ); g_return_if_fail( IS_VIEW( object ) ); view = VIEW( object ); #ifdef DEBUG printf( "view_destroy: \"%s\"\n", G_OBJECT_TYPE_NAME( object ) ); #endif /*DEBUG*/ /* We're probably changing the size of our enclosing column. */ view_resize( view ); if( view->scannable ) view_scannable_unregister( view ); if( view->resettable ) view_resettable_unregister( view ); if( VOBJECT( view )->iobject ) view_unlink( view ); if( view->parent ) view_child_remove( view ); slist_map( view->managed, (SListMapFn) view_viewchild_destroy, NULL ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void view_finalize( GObject *gobject ) { #ifdef DEBUG printf( "view_finalize: \"%s\"\n", G_OBJECT_TYPE_NAME( gobject ) ); #endif /*DEBUG*/ G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Called for model pos_changed signal ... queue a refresh. */ static void view_model_pos_changed( Model *model, View *view ) { g_assert( IS_MODEL( model ) ); g_assert( IS_VIEW( view ) ); #ifdef DEBUG printf( "view_model_pos_changed: %s %s \"%s\"\n", G_OBJECT_TYPE_NAME( view ), G_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) ); #endif /*DEBUG*/ vobject_refresh_queue( VOBJECT( view ) ); } /* Called for model scrollto signal ... try scrolling. */ static void view_model_scrollto( Model *model, ModelScrollPosition position, View *view ) { g_assert( IS_MODEL( model ) ); g_assert( IS_VIEW( view ) ); #ifdef DEBUG printf( "view_model_scrollto: %s\n", IOBJECT( model )->name ); #endif /*DEBUG*/ view_scrollto( view, position ); } /* Called for model layout signal ... try to lay out children. */ static void view_model_layout( Model *model, View *view ) { g_assert( IS_MODEL( model ) ); g_assert( IS_VIEW( view ) ); #ifdef DEBUG printf( "view_model_layout: %s\n", IOBJECT( model )->name ); #endif /*DEBUG*/ view_layout( view ); } /* Called for model reset signal ... try resetting. */ static void view_model_reset( Model *model, View *view ) { g_assert( IS_MODEL( model ) ); g_assert( IS_VIEW( view ) ); #ifdef DEBUG printf( "view_model_reset: %s\n", IOBJECT( model )->name ); #endif /*DEBUG*/ view_reset( view ); } /* Called for model front signal ... bring view to front. */ static void view_model_front( Model *model, View *view ) { g_assert( IS_MODEL( model ) ); g_assert( IS_VIEW( view ) ); #ifdef DEBUG printf( "view_model_front: model %s \"%s\"\n", G_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) ); printf( "\tview %s\n", G_OBJECT_TYPE_NAME( view ) ); #endif /*DEBUG*/ view_child_front( view ); } /* Called for model child_add signal ... start watching that child. */ static void view_model_child_add( Model *parent, Model *child, int pos, View *parent_view ) { ViewChild *viewchild; #ifdef DEBUG printf( "view_model_child_add: parent %s \"%s\"\n", G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) ); #endif /*DEBUG*/ g_assert( IS_MODEL( parent ) ); g_assert( IS_MODEL( child ) ); g_assert( IS_VIEW( parent_view ) ); #ifdef DEBUG viewchild = slist_map( parent_view->managed, (SListMapFn) view_viewchild_test_child_model, child ); g_assert( !viewchild ); #endif /*DEBUG*/ viewchild = view_viewchild_new( parent_view, child ); view_viewchild_changed( child, viewchild ); } /* Called for model child_remove signal ... stop watching that child. child * may have been finalized already. */ static void view_model_child_remove( iContainer *parent, iContainer *child, View *parent_view ) { ViewChild *viewchild; #ifdef DEBUG { printf( "view_model_child_remove: child %s \"%s\"; " "parent %s \"%s\"\n", G_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ), G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) ); printf( "view_model_child_remove: parent_view = view of %s \"%s\"\n", G_OBJECT_TYPE_NAME( VOBJECT( parent_view )->iobject ), NN( IOBJECT( VOBJECT( parent_view )->iobject )->name ) ); } #endif /*DEBUG*/ viewchild = slist_map( parent_view->managed, (SListMapFn) view_viewchild_test_child_model, child ); g_assert( viewchild ); (void) view_viewchild_destroy( viewchild ); } /* Called for model parent_detach signal ... remove the viewchild for this * child. child_attach will build a new one. */ static void view_model_child_detach( iContainer *old_parent, iContainer *child, View *old_parent_view ) { ViewChild *viewchild; #ifdef DEBUG { printf( "view_model_child_detach: child %s \"%s\"; " "old_parent %s \"%s\"\n", G_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ), G_OBJECT_TYPE_NAME( old_parent ), NN( IOBJECT( old_parent )->name ) ); printf( "view_model_child_detach: old_parent_view = " "view of %s \"%s\"\n", G_OBJECT_TYPE_NAME( VOBJECT( old_parent_view )->iobject ), NN( IOBJECT( VOBJECT( old_parent_view )->iobject )->name ) ); } #endif /*DEBUG*/ viewchild = slist_map( old_parent_view->managed, (SListMapFn) view_viewchild_test_child_model, child ); g_assert( viewchild ); g_assert( !child->temp_view ); child->temp_view = viewchild->child_view; (void) view_viewchild_destroy( viewchild ); } /* Called for model child_attach signal ... make a new viewchild on the new * parent view. */ static void view_model_child_attach( iContainer *new_parent, iContainer *child, int pos, View *new_parent_view ) { ViewChild *viewchild; g_assert( !slist_map( new_parent_view->managed, (SListMapFn) view_viewchild_test_child_model, child ) ); viewchild = view_viewchild_new( new_parent_view, MODEL( child ) ); g_assert( child->temp_view && IS_VIEW( child->temp_view ) ); viewchild->child_view = child->temp_view; child->temp_view = NULL; viewchild->child_view->parent = new_parent_view; } static void * view_real_link_sub( Model *child_model, View *parent_view ) { ViewChild *viewchild; viewchild = view_viewchild_new( parent_view, child_model ); view_viewchild_changed( child_model, viewchild ); return( NULL ); } /* Link to model and to enclosing view. */ static void view_real_link( View *view, Model *model, View *parent_view ) { g_assert( view != NULL ); g_assert( IS_VIEW( view ) && IS_MODEL( model ) ); g_assert( !VOBJECT( view )->iobject ); #ifdef DEBUG printf( "view_real_link: linking %s to model %s \"%s\"\n", G_OBJECT_TYPE_NAME( view ), G_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) ); #endif /*DEBUG*/ vobject_link( VOBJECT( view ), IOBJECT( model ) ); if( parent_view ) view_child_add( parent_view, view ); view->pos_changed_sid = g_signal_connect( model, "pos_changed", G_CALLBACK( view_model_pos_changed ), view ); view->scrollto_sid = g_signal_connect( model, "scrollto", G_CALLBACK( view_model_scrollto ), view ); view->layout_sid = g_signal_connect( model, "layout", G_CALLBACK( view_model_layout ), view ); view->reset_sid = g_signal_connect( model, "reset", G_CALLBACK( view_model_reset ), view ); view->front_sid = g_signal_connect( model, "front", G_CALLBACK( view_model_front ), view ); view->child_add_sid = g_signal_connect( model, "child_add", G_CALLBACK( view_model_child_add ), view ); view->child_remove_sid = g_signal_connect( model, "child_remove", G_CALLBACK( view_model_child_remove ), view ); view->child_detach_sid = g_signal_connect( model, "child_detach", G_CALLBACK( view_model_child_detach ), view ); view->child_attach_sid = g_signal_connect( model, "child_attach", G_CALLBACK( view_model_child_attach ), view ); icontainer_map( ICONTAINER( model ), (icontainer_map_fn) view_real_link_sub, view, NULL ); gtk_widget_show( GTK_WIDGET( view ) ); } static void view_real_child_add( View *parent, View *child ) { ViewChild *viewchild; g_assert( IS_VIEW( parent ) && IS_VIEW( child ) ); g_assert( child->parent == NULL ); #ifdef DEBUG printf( "view_real_child_add: parent %p %s, child %p %s\n", parent, G_OBJECT_TYPE_NAME( parent ), child, G_OBJECT_TYPE_NAME( child ) ); #endif /*DEBUG*/ viewchild = slist_map( parent->managed, (SListMapFn) view_viewchild_test_child_model, VOBJECT( child)->iobject ); g_assert( viewchild ); g_assert( viewchild->child_view == NULL ); /* Not all views are true widgets (ie. get _ref()'s and _sink()'d by a * parent in gtk_container()). Ref and sink ourselves to ensure that * even these odd views get unfloated. See also * view_real_child_remove(). Affects the tool/toolkit views, and * rowview at least. */ child->parent = parent; viewchild->child_view = child; g_object_ref( GTK_OBJECT( child ) ); gtk_object_sink( GTK_OBJECT( child ) ); } static void view_real_child_remove( View *parent, View *child ) { ViewChild *viewchild; #ifdef DEBUG printf( "view_real_child_remove: parent %s, child %s\n", G_OBJECT_TYPE_NAME( parent ), G_OBJECT_TYPE_NAME( child ) ); #endif /*DEBUG*/ viewchild = slist_map( parent->managed, (SListMapFn) view_viewchild_test_child_model, VOBJECT( child )->iobject ); /* Can have floating views which are not part of the viewchild system. */ if( viewchild && viewchild->child_view == child ) { viewchild->child_view = NULL; g_object_unref( G_OBJECT( child ) ); } child->parent = NULL; } static void view_real_child_position( View *parent, View *child ) { } static void view_real_child_front( View *parent, View *child ) { } static void view_real_reset( View *view ) { view_resettable_unregister( view ); } static void * view_real_scan( View *view ) { Model *model = MODEL( VOBJECT( view )->iobject ); Heapmodel *heapmodel; view_scannable_unregister( view ); /* If we've changed something in this model, mark it for recomp. */ if( model && IS_HEAPMODEL( model ) && (heapmodel = HEAPMODEL( model ))->modified && heapmodel->row ) { Expr *expr = heapmodel->row->expr; if( expr ) (void) expr_dirty( expr, link_serial_new() ); } return( NULL ); } static void view_class_init( ViewClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); GtkObjectClass *object_class = (GtkObjectClass*) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = view_finalize; object_class->destroy = view_destroy; /* Create signals. */ /* Init default methods. */ class->link = view_real_link; class->child_add = view_real_child_add; class->child_remove = view_real_child_remove; class->child_position = view_real_child_position; class->child_front = view_real_child_front; class->display = NULL; class->reset = view_real_reset; class->scan = view_real_scan; class->scrollto = NULL; class->layout = NULL; } static void view_init( View *view ) { /* Init our instance fields. */ view->pos_changed_sid = 0; view->scrollto_sid = 0; view->layout_sid = 0; view->reset_sid = 0; view->front_sid = 0; view->child_add_sid = 0; view->child_remove_sid = 0; view->child_detach_sid = 0; view->child_attach_sid = 0; view->parent = NULL; view->scannable = FALSE; view->resettable = FALSE; } GtkType view_get_type( void ) { static GtkType view_type = 0; if( !view_type ) { static const GtkTypeInfo view_info = { "View", sizeof( View ), sizeof( ViewClass ), (GtkClassInitFunc) view_class_init, (GtkObjectInitFunc) view_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; view_type = gtk_type_unique( TYPE_VOBJECT, &view_info ); } return( view_type ); } /* Trigger the reset method for a view. */ void * view_reset( View *view ) { ViewClass *view_class = VIEW_GET_CLASS( view ); if( view_class->reset ) view_class->reset( view ); return( NULL ); } /* Trigger the scan method for a view. */ void * view_scan( View *view ) { ViewClass *view_class = VIEW_GET_CLASS( view ); if( view_class->scan ) return( view_class->scan( view ) ); return( NULL ); } /* Trigger the scrollto method for a view. */ void * view_scrollto( View *view, ModelScrollPosition position ) { ViewClass *view_class = VIEW_GET_CLASS( view ); if( view_class->scrollto ) view_class->scrollto( view, position ); return( NULL ); } /* Trigger the layout method for a view. */ void * view_layout( View *view ) { ViewClass *view_class = VIEW_GET_CLASS( view ); if( view_class->layout ) view_class->layout( view ); return( NULL ); } static void * view_map_sub( ViewChild *viewchild, view_map_fn fn, void *a, void *b ) { if( viewchild->child_view ) return( fn( viewchild->child_view, a, b ) ); return( NULL ); } /* Map over a view's children. */ void * view_map( View *view, view_map_fn fn, void *a, void *b ) { return( slist_map3( view->managed, (SListMap3Fn) view_map_sub, (void *) fn, a, b ) ); } /* Apply a function to view, and to all it's children. */ void * view_map_all( View *view, view_map_fn fn, void *a ) { View *result; if( (result = fn( view, a, NULL )) ) return( result ); return( view_map( view, (view_map_fn) view_map_all, (void *) fn, a ) ); } void view_save_as_cb( GtkWidget *menu, GtkWidget *host, View *view ) { Model *model = MODEL( VOBJECT( view )->iobject ); if( IS_FILEMODEL( model ) ) { iWindow *iwnd = IWINDOW( view_get_toplevel( view ) ); filemodel_inter_saveas( iwnd, FILEMODEL( model ) ); } } void view_save_cb( GtkWidget *menu, GtkWidget *host, View *view ) { Model *model = MODEL( VOBJECT( view )->iobject ); if( IS_FILEMODEL( model ) ) { iWindow *iwnd = IWINDOW( view_get_toplevel( view ) ); filemodel_inter_save( iwnd, FILEMODEL( model ) ); } } void view_close_cb( GtkWidget *menu, GtkWidget *host, View *view ) { Model *model = MODEL( VOBJECT( view )->iobject ); if( IS_FILEMODEL( model ) ) { iWindow *iwnd = IWINDOW( view_get_toplevel( view ) ); filemodel_inter_savenclose( iwnd, FILEMODEL( model ) ); } } /* Callback for "activate" on a view. */ void view_activate_cb( View *view ) { view_scannable_register( view ); symbol_recalculate_all(); } /* Callback for "changed" on a view. */ void view_changed_cb( View *view ) { /* Make sure it's on the scannable list. */ view_scannable_register( view ); } void view_not_implemented_cb( GtkWidget *menu, GtkWidget *host, View *view ) { error_top( _( "Not implemented." ) ); iwindow_alert( GTK_WIDGET( view ), GTK_MESSAGE_ERROR ); } GtkWidget * view_get_toplevel( View *view ) { while( IS_VIEW( view ) && view->parent ) view = view->parent; return( gtk_widget_get_toplevel( GTK_WIDGET( view ) ) ); } Columnview * view_get_columnview( View *child ) { View *view; for( view = child; view && !IS_COLUMNVIEW( view ); view = view->parent ) ; if( !view ) return( NULL ); return( COLUMNVIEW( view ) ); } /* A view has changed size ... rethink the enclosing column geo. Helps table * to not break. */ void * view_resize( View *view ) { Columnview *cview = view_get_columnview( view ); if( cview ) gtk_widget_queue_resize( GTK_WIDGET( cview ) ); return( NULL ); } nip2-8.7.1/src/helpindex.h0000644000175000017500000001313613351443023012242 00000000000000{ "sec:object", "nipguidese34.html#nip_label_sec:object" }, { "sec:menu-colour", "nipguidese14.html#nip_label_sec:menu-colour" }, { "tb:colour", "nipguidese14.html#nip_label_tb:colour" }, { "sec:pattern", "nipguidese30.html#nip_label_sec:pattern" }, { "sec:nerdtour", "nipguidese3.html#nip_label_sec:nerdtour" }, { "fg:Fred", "nipguidese3.html#nip_label_fg:Fred" }, { "fg:mainFred", "nipguidese3.html#nip_label_fg:mainFred" }, { "fg:slideFred", "nipguidese3.html#nip_label_fg:slideFred" }, { "fg:Jim", "nipguidese3.html#nip_label_fg:Jim" }, { "fg:twomoreregions", "nipguidese3.html#nip_label_fg:twomoreregions" }, { "fg:myjoin", "nipguidese3.html#nip_label_fg:myjoin" }, { "sec:menu-object", "nipguidese20.html#nip_label_sec:menu-object" }, { "sec:operators", "nipguidese27.html#nip_label_sec:operators" }, { "tb:precedence", "nipguidese27.html#nip_label_tb:precedence" }, { "sec:listsyntax", "nipguidese27.html#nip_label_sec:listsyntax" }, { "sec:func", "nipguidese27.html#nip_label_sec:func" }, { "sec:vidpref", "nipguidese4.html#nip_label_sec:vidpref" }, { "fg:vidpref", "nipguidese4.html#nip_label_fg:vidpref" }, { "sec:imcap", "nipguidese4.html#nip_label_sec:imcap" }, { "sec:grey", "nipguidese4.html#nip_label_sec:grey" }, { "sec:linuxgrey", "nipguidese4.html#nip_label_sec:linuxgrey" }, { "sec:wingrey", "nipguidese4.html#nip_label_sec:wingrey" }, { "sec:lists", "nipguidese28.html#nip_label_sec:lists" }, { "tb:list", "nipguidese28.html#nip_label_tb:list" }, { "sec:cmdline", "nipguidese13.html#nip_label_sec:cmdline" }, { "sec:menu-histogram", "nipguidese16.html#nip_label_sec:menu-histogram" }, { "sec:menu-matrix", "nipguidese19.html#nip_label_sec:menu-matrix" }, { "sec:quicktour", "nipguidese1.html#nip_label_sec:quicktour" }, { "fg:loadedimage", "nipguidese1.html#nip_label_fg:loadedimage" }, { "fg:imageview", "nipguidese1.html#nip_label_fg:imageview" }, { "tb:shortcuts", "nipguidese1.html#nip_label_tb:shortcuts" }, { "fg:imageviewregion", "nipguidese1.html#nip_label_fg:imageviewregion" }, { "fg:main2regions", "nipguidese1.html#nip_label_fg:main2regions" }, { "fg:rotate", "nipguidese1.html#nip_label_fg:rotate" }, { "fg:join", "nipguidese1.html#nip_label_fg:join" }, { "fg:browse", "nipguidese1.html#nip_label_fg:browse" }, { "tb:builtin", "nipguidese24.html#nip_label_tb:builtin" }, { "tb:toolkits", "nipguidese31.html#nip_label_tb:toolkits" }, { "sec:menu-filter", "nipguidese15.html#nip_label_sec:menu-filter" }, { "sec:progwin", "nipguidese12.html#nip_label_sec:progwin" }, { "sec:trace", "nipguidese12.html#nip_label_sec:trace" }, { "sec:menu-tasks", "nipguidese21.html#nip_label_sec:menu-tasks" }, { "sec:menu-capture", "nipguidese21.html#nip_label_sec:menu-capture" }, { "sec:menu-mosaic", "nipguidese21.html#nip_label_sec:menu-mosaic" }, { "sec:menu-picture-frame", "nipguidese21.html#nip_label_sec:menu-picture-frame" }, { "sec:menu-print", "nipguidese21.html#nip_label_sec:menu-print" }, { "sec:bowser", "nipguidese33.html#nip_label_sec:bowser" }, { "sec:tools", "nipguidese33.html#nip_label_sec:tools" }, { "fg:toolkit", "nipguidese33.html#nip_label_fg:toolkit" }, { "fg:toolkit2", "nipguidese33.html#nip_label_fg:toolkit2" }, { "fg:toolkit3", "nipguidese33.html#nip_label_fg:toolkit3" }, { "sec:workspaces", "nipguidese33.html#nip_label_sec:workspaces" }, { "fg:row2", "nipguidese33.html#nip_label_fg:row2" }, { "tb:classes", "nipguidese33.html#nip_label_tb:classes" }, { "sec:Image", "nipguidese33.html#nip_label_sec:Image" }, { "sec:colour", "nipguidese33.html#nip_label_sec:colour" }, { "sec:loadsave", "nipguidese10.html#nip_label_sec:loadsave" }, { "fg:open", "nipguidese10.html#nip_label_fg:open" }, { "fg:save", "nipguidese10.html#nip_label_fg:save" }, { "sec:view", "nipguidese9.html#nip_label_sec:view" }, { "fg:scr3", "nipguidese9.html#nip_label_fg:scr3" }, { "fg:scr4", "nipguidese9.html#nip_label_fg:scr4" }, { "sec:paintbox", "nipguidese9.html#nip_label_sec:paintbox" }, { "fg:paint", "nipguidese9.html#nip_label_fg:paint" }, { "sec:program", "nipguidech6.html#nip_label_sec:program" }, { "sec:lazy", "nipguidese29.html#nip_label_sec:lazy" }, { "sec:optimise", "nipguidese35.html#nip_label_sec:optimise" }, { "sec:menus", "nipguidech5.html#nip_label_sec:menus" }, { "sec:ipwindow", "nipguidese11.html#nip_label_sec:ipwindow" }, { "fg:startup", "nipguidese11.html#nip_label_fg:startup" }, { "sec:column", "nipguidese11.html#nip_label_sec:column" }, { "sec:row", "nipguidese11.html#nip_label_sec:row" }, { "fg:row", "nipguidese11.html#nip_label_fg:row" }, { "sec:apply", "nipguidese11.html#nip_label_sec:apply" }, { "sec:batch", "nipguidese11.html#nip_label_sec:batch" }, { "sec:error", "nipguidese11.html#nip_label_sec:error" }, { "sec:diaref", "nipguidese11.html#nip_label_sec:diaref" }, { "sec:menu-math", "nipguidese18.html#nip_label_sec:menu-math" }, { "sec:ir", "nipguidech3.html#nip_label_sec:ir" }, { "sec:mosaicing", "nipguidese5.html#nip_label_sec:mosaicing" }, { "sec:pieces", "nipguidese5.html#nip_label_sec:pieces" }, { "sec:tutorial", "nipguidech2.html#nip_label_sec:tutorial" }, { "sec:reference", "nipguidech4.html#nip_label_sec:reference" }, { "sec:class", "nipguidese32.html#nip_label_sec:class" }, { "sec:inheritance", "nipguidese32.html#nip_label_sec:inheritance" }, { "sec:balance", "nipguidese6.html#nip_label_sec:balance" }, { "sec:irtut", "nipguidese2.html#nip_label_sec:irtut" }, { "fg:loadsamples", "nipguidese2.html#nip_label_fg:loadsamples" }, { "fg:readyjoin", "nipguidese2.html#nip_label_fg:readyjoin" }, { "fg:joined", "nipguidese2.html#nip_label_fg:joined" }, { "sec:config", "nipguideap1.html#nip_label_sec:config" }, { "sec:menu-image", "nipguidese17.html#nip_label_sec:menu-image" }, { "sec:callvips", "nipguidese36.html#nip_label_sec:callvips" }, nip2-8.7.1/src/dump.h0000644000175000017500000000317113351443023011225 00000000000000/* Decls for dump.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ char *decode_BinOp( BinOp op ); char *decode_UnOp( UnOp op ); char *decode_NodeType( NodeType tag ); char *decode_CombinatorType( CombinatorType comb ); char *decode_SymbolType( SymbolType t ); char *decode_SymbolType_user( SymbolType t ); void *dump_tiny( Symbol *sym ); void *dump_symbol( Symbol *sym ); void dump_expr( Expr *expr ); void dump_compile( Compile *compile ); void dump_symbol_table( void ); void *dump_kit( Toolkit *kit ); Symbol *sym( char *name ); void psym( char *name ); void psymv( char *name ); void pgraph( PElement *graph ); void graph_heap( int nsp, HeapNode *hn ); void graph_test( Heap *heap ); void *dump_tree( ParseNode *n ); void dump_links( Symbol *sym ); void *dump_link( Link *link ); void dump_symbol_heap( Symbol *sym ); nip2-8.7.1/src/vipsobject.c0000644000175000017500000002474513351443023012435 00000000000000/* Interface to VipsObject. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ /* Maxiumum number of args to constructor. */ #define MAX_VIPS_ARGS (100) /* What we track during construct. */ typedef struct _Vo { Reduce *rc; /* Object we are building. */ VipsObject *object; const char *name; /* Required args supplied to us from nip. */ PElement args[MAX_VIPS_ARGS]; int nargs_supplied; /* Number of required input args the object has. */ int nargs_required; /* Number of output args the object has. */ int nargs_output; /* A place to build the output, safe from the GC. */ Element out; } Vo; static void vo_free( Vo *vo ) { heap_unregister_element( vo->rc->heap, &vo->out ); VIPS_UNREF( vo->object ); im_free( vo ); } static Vo * vo_new( Reduce *rc, const char *name ) { const VipsObjectClass *class; Vo *vo; if( !(class = vips_class_find( "VipsObject", name )) ) return( NULL ); if( !(vo = INEW( NULL, Vo )) ) return( NULL ); vo->rc = rc; vo->object = g_object_new( G_OBJECT_CLASS_TYPE( class ), NULL ); vo->name = class->nickname; vo->nargs_supplied = 0; vo->nargs_required = 0; vo->nargs_output = 0; vo->out.type = ELEMENT_NOVAL; vo->out.ele = (void *) 12; heap_register_element( rc->heap, &vo->out ); return( vo ); } static void * vo_gather_required( PElement *item, Vo *vo ) { if( vo->nargs_supplied >= MAX_VIPS_ARGS ) { error_top( _( "Too many arguments." ) ); error_sub( _( "No more than %d arguments allowed." ), MAX_VIPS_ARGS ); return( item ); } vo->args[vo->nargs_supplied] = *item; vo->nargs_supplied += 1; return( NULL ); } static int vo_set_property( Vo *vo, const char *name, GParamSpec *pspec, GValue *value ) { /* If we're setting an enum from a string, look up the enum nickname. */ if( G_IS_PARAM_SPEC_ENUM( pspec ) && G_VALUE_TYPE( value ) == VIPS_TYPE_REF_STRING ) { const char *str = vips_value_get_ref_string( value, NULL ); if( vips_object_set_argument_from_string( vo->object, name, str ) ) return( -1 ); } else g_object_set_property( G_OBJECT( vo->object ), name, value ); return( 0 ); } static void * vo_set_required_input( VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, Vo *vo ) { /* Looking for required input args ... these are the ones we can set * from the supplied required list. */ if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_INPUT) && !argument_instance->assigned && vo->nargs_required < vo->nargs_supplied ) { const char *name = g_param_spec_get_name( pspec ); int i = vo->nargs_required; GValue gvalue = { 0 }; if( !heap_ip_to_gvalue( &vo->args[i], &gvalue ) ) return( object ); if( vo_set_property( vo, name, pspec, &gvalue ) ) { g_value_unset( &gvalue ); return( object ); } g_value_unset( &gvalue ); vo->nargs_required += 1; } return( NULL ); } static void * vo_set_optional_arg( const char *name, PElement *value, Vo *vo ) { GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; /* Looking for construct-time optional input args. */ /* For optional args, we should ignore properties that don't exist. For * example, we might supply ($sharpening => 12) to all interpolators, * though only one interpolator uses this property. */ if( vips_object_get_argument( vo->object, name, &pspec, &argument_class, &argument_instance ) ) return( NULL ); if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) && (argument_class->flags & VIPS_ARGUMENT_INPUT) && !argument_instance->assigned ) { GValue gvalue = { 0 }; if( !heap_ip_to_gvalue( value, &gvalue ) ) { g_value_unset( &gvalue ); return( value ); } if( vo_set_property( vo, name, pspec, &gvalue ) ) { g_value_unset( &gvalue ); return( value ); } g_value_unset( &gvalue ); } return( NULL ); } /* Set a set of optional args ... of the form [["caption", 12], ["label", 42]] * etc. */ static gboolean vo_set_optional( Vo *vo, PElement *optional ) { if( heap_map_dict( optional, (heap_map_dict_fn) vo_set_optional_arg, vo, NULL ) ) return( FALSE ); return( TRUE ); } /* Make a vo and supply args from nip2. */ static gboolean vo_args( Vo *vo, PElement *required, PElement *optional ) { /* Gather supplied required input args list. */ if( heap_map_list( required, (heap_map_list_fn) vo_gather_required, vo, NULL ) ) return( FALSE ); /* Set required input arguments. */ if( vips_argument_map( VIPS_OBJECT( vo->object ), (VipsArgumentMapFn) vo_set_required_input, vo, NULL ) ) return( FALSE ); if( vo->nargs_supplied != vo->nargs_required ) { error_top( _( "Wrong number of required arguments." ) ); error_sub( _( "Operation \"%s\" has %d required arguments, " "you supplied %d." ), vo->name, vo->nargs_required, vo->nargs_supplied ); return( FALSE ); } /* Set all optional input args. */ if( !vo_set_optional( vo, optional ) ) return( FALSE ); return( TRUE ); } /* Make a VipsObject. */ void vo_object_new( Reduce *rc, const char *name, PElement *required, PElement *optional, PElement *out ) { Vo *vo; Managedgobject *managedgobject; if( !(vo = vo_new( rc, name )) ) reduce_throw( rc ); if( !vo_args( vo, required, optional ) ) { vo_free( vo ); reduce_throw( rc ); } /* Ask the object to construct. */ if( vips_object_build( vo->object ) ) { error_top( _( "VIPS library error." ) ); error_sub( "%s", im_error_buffer() ); im_error_clear(); vo_free( vo ); reduce_throw( rc ); } /* Return the constructed object. */ if( !(managedgobject = managedgobject_new( vo->rc->heap, G_OBJECT( vo->object ) )) ) { vo_free( vo ); reduce_throw( rc ); } PEPUTP( out, ELEMENT_MANAGED, managedgobject ); #ifdef DEBUG { char txt[1000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_object_to_string( vo->object, &buf ); printf( "vo_object_new: built %s\n", vips_buf_all( &buf ) ); } #endif /*DEBUG*/ vo_free( vo ); } /* Looking for required output args ... append to out. */ static void * vo_get_required_output( VipsObject *object, GParamSpec *pspec, VipsArgumentClass *argument_class, VipsArgumentInstance *argument_instance, Vo *vo, PElement *out ) { if( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_OUTPUT) && argument_instance->assigned ) { const char *name = g_param_spec_get_name( pspec ); GType type = G_PARAM_SPEC_VALUE_TYPE( pspec ); PElement lhs; GValue value = { 0 }; if( !heap_list_add( vo->rc->heap, out, &lhs ) ) return( object ); g_value_init( &value, type ); g_object_get_property( G_OBJECT( object ), name, &value ); if( !heap_gvalue_to_ip( &value, &lhs ) ) { g_value_unset( &value ); return( object ); } g_value_unset( &value ); (void) heap_list_next( out ); } return( NULL ); } /* Looking for construct-time optional output args. Append them to out. */ static void * vo_get_optional_arg( const char *name, PElement *value, Vo *vo, PElement *out ) { GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if( vips_object_get_argument( vo->object, name, &pspec, &argument_class, &argument_instance ) ) return( NULL ); if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) && (argument_class->flags & VIPS_ARGUMENT_OUTPUT) && argument_instance->assigned ) { GType type = G_PARAM_SPEC_VALUE_TYPE( pspec ); GValue gvalue = { 0 }; PElement lhs; if( !heap_list_add( vo->rc->heap, out, &lhs ) ) return( value ); g_value_init( &gvalue, type ); g_object_get_property( G_OBJECT( vo->object ), name, &gvalue ); if( !heap_gvalue_to_ip( &gvalue, &lhs ) ) { g_value_unset( &gvalue ); return( value ); } g_value_unset( &gvalue ); (void) heap_list_next( out ); } return( NULL ); } /* Get a set of optional args ... of the form [["caption", []], ["label", []]] * etc. */ static gboolean vo_get_optional( Vo *vo, PElement *optional, PElement *out ) { if( heap_map_dict( optional, (heap_map_dict_fn) vo_get_optional_arg, vo, out ) ) return( FALSE ); return( TRUE ); } /* Run a VipsOperation. Like vo_object_new(), but we return the output args * rather than the operation. */ void vo_call( Reduce *rc, const char *name, PElement *required, PElement *optional, PElement *out ) { Vo *vo; PElement pe; if( !(vo = vo_new( rc, name )) ) reduce_throw( rc ); if( !vo_args( vo, required, optional ) ) { vo_free( vo ); reduce_throw( rc ); } /* Ask the object to construct. This can update vo->operation with an * old one from the cache. */ if( vips_cache_operation_buildp( (VipsOperation **) &vo->object ) ) { error_top( _( "VIPS library error." ) ); error_sub( "%s", im_error_buffer() ); im_error_clear(); vips_object_unref_outputs( vo->object ); vo_free( vo ); reduce_throw( rc ); } /* We can't build the output object directly on out, since it might be * one of our inputs. We use the safe Element in vo for the build, * then copy at the end. */ /* Empty output list. */ PEPOINTE( &pe, &vo->out ); heap_list_init( &pe ); /* Append required outputs. */ if( vips_argument_map( VIPS_OBJECT( vo->object ), (VipsArgumentMapFn) vo_get_required_output, vo, &pe ) ) { vips_object_unref_outputs( vo->object ); vo_free( vo ); reduce_throw( rc ); } /* Append optional outputs. */ if( !vo_get_optional( vo, optional, &pe ) ) { vips_object_unref_outputs( vo->object ); vo_free( vo ); reduce_throw( rc ); } /* Now write the output object to out. */ PEPUTE( out, &vo->out ); vips_object_unref_outputs( vo->object ); vo_free( vo ); } nip2-8.7.1/src/boxes.c0000644000175000017500000007746313351443023011412 00000000000000/* Make various little popup dialogs ... error, info, question. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Max amount of text in a info/error/question dialog. */ #define MAX_DIALOG_TEXT (2000) /* Find a window to use as dialog parent. */ static GtkWidget * box_pick_parent( GtkWidget *par ) { if( !par ) return( GTK_WIDGET( mainw_pick_one() ) ); else return( par ); } /* Make the insides of a error, info or question dialog. */ static void box_build( iDialog *idlg, GtkWidget *work, char *s, const char *stock_id ) { GtkWidget *icon; GtkWidget *hb; GtkWidget *lab; hb = gtk_hbox_new( FALSE, 12 ); gtk_container_border_width( GTK_CONTAINER( hb ), 0 ); gtk_container_add( GTK_CONTAINER( work ), hb ); gtk_widget_show( hb ); icon = gtk_image_new_from_stock( stock_id, GTK_ICON_SIZE_DIALOG ); gtk_misc_set_alignment( GTK_MISC( icon ), 0.0, 0.0 ); gtk_box_pack_start( GTK_BOX( hb ), icon, FALSE, FALSE, 0 ); gtk_widget_show( icon ); lab = gtk_label_new( NULL ); gtk_label_set_markup( GTK_LABEL( lab ), s ); gtk_label_set_justify( GTK_LABEL( lab ), GTK_JUSTIFY_LEFT ); gtk_label_set_selectable( GTK_LABEL( lab ), TRUE ); gtk_label_set_line_wrap( GTK_LABEL( lab ), TRUE ); gtk_box_pack_start( GTK_BOX( hb ), lab, FALSE, FALSE, 0 ); gtk_widget_show( lab ); } /* Make an error dialog. */ /*VARARGS2*/ static void box_error( GtkWidget *par, const char *fmt, ... ) { va_list ap; char buf[MAX_DIALOG_TEXT]; GtkWidget *idlg; va_start( ap, fmt ); (void) im_vsnprintf( buf, MAX_DIALOG_TEXT, fmt, ap ); va_end( ap ); idlg = idialog_new(); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) box_build, buf, GTK_STOCK_DIALOG_ERROR, NULL ); idialog_set_callbacks( IDIALOG( idlg ), NULL, NULL, NULL, NULL ); idialog_add_ok( IDIALOG( idlg ), iwindow_true_cb, GTK_STOCK_OK ); iwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); } /* Mark up a top/sub pair for a dialog box. */ static void box_vmarkup( char *out, const char *top, const char *sub, va_list ap ) { char buf1[MAX_DIALOG_TEXT]; char buf2[MAX_DIALOG_TEXT]; char buf3[MAX_DIALOG_TEXT]; escape_markup( top, buf1, MAX_DIALOG_TEXT ); (void) im_vsnprintf( buf2, MAX_DIALOG_TEXT, sub, ap ); escape_markup( buf2, buf3, MAX_DIALOG_TEXT ); (void) im_snprintf( out, MAX_DIALOG_TEXT, "%s", buf1 ); if( strcmp( buf3, "" ) != 0 ) { int len = strlen( out ); (void) im_snprintf( out + len, MAX_DIALOG_TEXT - len, "\n\n%s", buf3 ); } } static void box_markup( char *out, const char *top, const char *sub, ... ) { va_list ap; va_start( ap, sub ); box_vmarkup( out, top, sub, ap ); va_end( ap ); } /* Display buffered errors in an error dialog. */ void box_alert( GtkWidget *par ) { char buf[MAX_DIALOG_TEXT]; if( main_option_batch ) { /* No X, just print. */ fprintf( stderr, "%s\n", error_get_top() ); fprintf( stderr, "%s\n", error_get_sub() ); return; } box_markup( buf, error_get_top(), "%s", error_get_sub() ); box_error( par, "%s", buf ); } /* Make an information dialog. */ void box_vinfo( GtkWidget *par, const char *top, const char *sub, va_list ap ) { char buf[MAX_DIALOG_TEXT]; GtkWidget *idlg; box_vmarkup( buf, top, sub, ap ); idlg = idialog_new(); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) box_build, buf, GTK_STOCK_DIALOG_INFO, NULL ); idialog_set_callbacks( IDIALOG( idlg ), NULL, NULL, NULL, NULL ); idialog_add_ok( IDIALOG( idlg ), iwindow_true_cb, GTK_STOCK_OK ); iwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); } /* Make an information dialog. */ void box_info( GtkWidget *par, const char *top, const char *sub, ... ) { va_list ap; va_start( ap, sub ); box_vinfo( par, top, sub, ap ); va_end( ap ); } /* Pop up an 'Are you sure?' window. */ iDialog * box_yesno( GtkWidget *par, iWindowFn okcb, iWindowFn cancelcb, void *client, /* Call client */ iWindowNotifyFn nfn, void *sys, /* Call parent */ const char *yes_label, const char *top, const char *sub, ... ) { va_list ap; char buf[MAX_DIALOG_TEXT]; GtkWidget *idlg; va_start( ap, sub ); box_vmarkup( buf, top, sub, ap ); va_end( ap ); idlg = idialog_new(); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) box_build, buf, GTK_STOCK_DIALOG_QUESTION, NULL ); idialog_set_callbacks( IDIALOG( idlg ), cancelcb, NULL, NULL, client ); idialog_add_ok( IDIALOG( idlg ), okcb, "%s", yes_label ); idialog_set_notify( IDIALOG( idlg ), nfn, sys ); iwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); return( IDIALOG( idlg ) ); } /* Pop up a `save'/`don't save'/`cancel' dialog. */ void box_savenosave( GtkWidget *par, iWindowFn save, iWindowFn nosave, void *client, /* Call client */ iWindowNotifyFn nfn, void *sys, /* Call parent */ const char *top, const char *sub, ... ) { va_list ap; char buf[MAX_DIALOG_TEXT]; GtkWidget *idlg; va_start( ap, sub ); box_vmarkup( buf, top, sub, ap ); va_end( ap ); idlg = idialog_new(); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) box_build, buf, GTK_STOCK_DIALOG_QUESTION, NULL ); idialog_set_callbacks( IDIALOG( idlg ), iwindow_true_cb, NULL, NULL, client ); idialog_add_ok( IDIALOG( idlg ), nosave, _( "Close _without Saving" ) ); idialog_add_ok( IDIALOG( idlg ), save, GTK_STOCK_SAVE ); idialog_set_notify( IDIALOG( idlg ), nfn, sys ); iwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); } #define ABOUT(A) ((About *) (A)) /* Make the insides of an about box. */ static void about_build( iDialog *idlg, GtkWidget *work ) { /* Translators: translate this to a credit for you, and it'll appear in * the About box. */ char *translator_credits = _( "translator_credits" ); GtkWidget *hb; GtkWidget *lab; char txt[MAX_DIALOG_TEXT]; char txt2[MAX_DIALOG_TEXT]; VipsBuf buf = VIPS_BUF_STATIC( txt ); GtkWidget *image; im_snprintf( txt2, MAX_DIALOG_TEXT, _( "About %s." ), PACKAGE ); vips_buf_appendf( &buf, "%s\n\n", txt2 ); im_snprintf( txt2, MAX_DIALOG_TEXT, _( "%s is an image processing package." ), PACKAGE ); vips_buf_appendf( &buf, "%s\n\n", txt2 ); im_snprintf( txt2, MAX_DIALOG_TEXT, _( "%s comes with ABSOLUTELY NO WARRANTY. This is " "free software and you are welcome to redistribute " "it under certain conditions, see http://www.gnu.org." ), PACKAGE ); vips_buf_appendf( &buf, "%s\n\n", txt2 ); im_snprintf( txt2, MAX_DIALOG_TEXT, _( NIP_COPYRIGHT ), PACKAGE ); vips_buf_appendf( &buf, "%s\n\n", txt2 ); { char buf1[FILENAME_MAX]; char buf2[FILENAME_MAX]; im_snprintf( buf1, FILENAME_MAX, "%s" G_DIR_SEPARATOR_S "start", get_savedir() ); expand_variables( buf1, buf2 ); nativeize_path( buf2 ); escape_markup( buf2, buf1, FILENAME_MAX ); vips_buf_appendf( &buf, "%s: %s\n", _( "Personal start folder" ), buf1 ); } vips_buf_appendf( &buf, "%s: %s\n", _( "Homepage" ), VIPS_HOMEPAGE ); escape_markup( im_version_string(), txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "%s: %s\n", _( "Linked to VIPS" ), txt2 ); escape_markup( IM_VERSION_STRING, txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "%s: %s\n", _( "Built against VIPS" ), txt2 ); escape_markup( PACKAGE, txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "$PACKAGE: %s\n", txt2 ); escape_markup( VERSION, txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "$VERSION: %s\n", txt2 ); escape_markup( NN( g_getenv( "VIPSHOME" ) ), txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "$VIPSHOME: %s\n", txt2 ); escape_markup( NN( g_getenv( "HOME" ) ), txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "$HOME: %s\n", txt2 ); escape_markup( NN( g_getenv( "SAVEDIR" ) ), txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "$SAVEDIR: %s\n", txt2 ); escape_markup( PATH_TMP, txt2, MAX_DIALOG_TEXT ); vips_buf_appendf( &buf, "%s: %s\n", _( "Temp files in" ), txt2 ); if( strcmp( translator_credits, "translator_credits" ) != 0 ) { vips_buf_appendf( &buf, "\n" ); vips_buf_appends( &buf, translator_credits ); } vips_buf_appendf( &buf, "\n" ); mainw_find_disc( &buf ); /* Expands to (eg.) "14GB free in /pics/tmp" */ vips_buf_appendf( &buf, _( " in \"%s\"" ), PATH_TMP ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%d cells in heap, %d cells free, %d cells maximum" ), reduce_context->heap->ncells, reduce_context->heap->nfree, reduce_context->heap->max_fn( reduce_context->heap ) ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%d vips calls cached by nip2" ), cache_history_size ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%d vips operations cached by libvips" ), vips_cache_get_size() ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "using %d threads" ), im_concurrency_get() ); vips_buf_appends( &buf, "\n" ); vips_buf_appendf( &buf, _( "%d pixel buffers in vips" ), vips_tracked_get_allocs() ); vips_buf_appends( &buf, "\n" ); vips_buf_append_size( &buf, vips_tracked_get_mem() ); vips_buf_appendf( &buf, _( " of ram in pixel buffers" ) ); vips_buf_appends( &buf, "\n" ); vips_buf_append_size( &buf, vips_tracked_get_mem_highwater() ); vips_buf_appendf( &buf, _( " of ram highwater mark" ) ); vips_buf_appends( &buf, "\n" ); hb = gtk_hbox_new( FALSE, 0 ); gtk_container_border_width( GTK_CONTAINER( hb ), 10 ); gtk_container_add( GTK_CONTAINER( work ), hb ); gtk_widget_show( hb ); image = image_new_from_file( "$VIPSHOME/share/$PACKAGE/data/vips-128.png" ); gtk_box_pack_start( GTK_BOX( hb ), image, FALSE, FALSE, 2 ); gtk_widget_show( image ); lab = gtk_label_new( "" ); gtk_label_set_markup( GTK_LABEL( lab ), vips_buf_all( &buf ) ); gtk_label_set_justify( GTK_LABEL( lab ), GTK_JUSTIFY_LEFT ); gtk_label_set_selectable( GTK_LABEL( lab ), TRUE ); gtk_label_set_line_wrap( GTK_LABEL( lab ), TRUE ); gtk_box_pack_start( GTK_BOX( hb ), lab, FALSE, FALSE, 2 ); gtk_widget_show( lab ); } /* Pop up an "about" window. */ void box_about( GtkWidget *par ) { GtkWidget *idlg; idlg = idialog_new(); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) about_build, NULL, NULL, NULL ); idialog_add_ok( IDIALOG( idlg ), iwindow_true_cb, GTK_STOCK_OK ); iwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); } /* A big list of all the help tags, plus the file and anchor they are defined * in. See makehelpindex.pl. */ static const char *box_helpindex[][2] = { #include "helpindex.h" }; /* Pop up a help window for a tag. */ void box_help( GtkWidget *par, const char *name ) { int i; for( i = 0; i < IM_NUMBER( box_helpindex ); i++ ) if( strcmp( name, box_helpindex[i][0] ) == 0 ) { char url[512]; im_snprintf( url, 512, "file://%s/%s", NIP_DOCPATH, box_helpindex[i][1] ); box_url( par, url ); return; } error_top( _( "Help page not found." ) ); error_sub( _( "No indexed help page found for tag \"%s\"" ), name ); iwindow_alert( par, GTK_MESSAGE_ERROR ); } /* Name + caption dialog ... for new workspace / new column. */ static iDialogClass *stringset_parent_class = NULL; void * stringset_child_destroy( StringsetChild *ssc ) { ssc->ss->children = g_slist_remove( ssc->ss->children, ssc ); IM_FREE( ssc->label ); IM_FREE( ssc->text ); IM_FREE( ssc->tooltip ); IM_FREE( ssc ); return( NULL ); } StringsetChild * stringset_child_new( Stringset *ss, const char *label, const char *text, const char *tooltip ) { StringsetChild *ssc = INEW( NULL, StringsetChild ); ssc->ss = ss; ssc->label = im_strdup( NULL, label ); ssc->text = im_strdup( NULL, text ); ssc->tooltip = im_strdup( NULL, tooltip ); ss->children = g_slist_append( ss->children, ssc ); return( ssc ); } static void stringset_destroy( GtkObject *object ) { Stringset *ss; g_return_if_fail( object != NULL ); g_return_if_fail( IS_STRINGSET( object ) ); ss = STRINGSET( object ); slist_map( ss->children, (SListMapFn) stringset_child_destroy, NULL ); UNREF( ss->group ); if( GTK_OBJECT_CLASS( stringset_parent_class )->destroy ) GTK_OBJECT_CLASS( stringset_parent_class )->destroy( object ); } static void * stringset_build_set_default( StringsetChild *ssc, iDialog *idlg ) { idialog_set_default_entry( idlg, GTK_ENTRY( ssc->entry ) ); return( NULL ); } static void stringset_build( GtkWidget *widget ) { Stringset *ss = STRINGSET( widget ); iDialog *idlg = IDIALOG( widget ); GSList *p; #ifdef DEBUG printf( "stringset_build: %s\n", IWINDOW( ss )->title ); #endif /*DEBUG*/ /* Call all builds in superclasses. */ if( IWINDOW_CLASS( stringset_parent_class )->build ) IWINDOW_CLASS( stringset_parent_class )->build( widget ); ss->group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL ); for( p = ss->children; p; p = p->next ) { StringsetChild *ssc = (StringsetChild *) p->data; ssc->entry = build_glabeltext4( idlg->work, ss->group, ssc->label ); if( ssc->text ) set_gentry( ssc->entry, "%s", ssc->text ); if( ssc->tooltip ) set_tooltip( ssc->entry, "%s", ssc->tooltip ); } /* Set defaults in reverse, so we get top item with focus. */ (void) slist_map_rev( ss->children, (SListMapFn) stringset_build_set_default, idlg ); gtk_widget_show_all( idlg->work ); } static void stringset_class_init( StringsetClass *class ) { GtkObjectClass *object_class; iWindowClass *iwindow_class; object_class = (GtkObjectClass *) class; iwindow_class = (iWindowClass *) class; object_class->destroy = stringset_destroy; iwindow_class->build = stringset_build; stringset_parent_class = g_type_class_peek_parent( class ); } static void stringset_init( Stringset *ss ) { #ifdef DEBUG printf( "stringset_init: %s\n", IWINDOW( ss )->title ); #endif /*DEBUG*/ ss->children = NULL; } GtkType stringset_get_type( void ) { static GtkType stringset_type = 0; if( !stringset_type ) { static const GtkTypeInfo info = { "Stringset", sizeof( Stringset ), sizeof( StringsetClass ), (GtkClassInitFunc) stringset_class_init, (GtkObjectInitFunc) stringset_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; stringset_type = gtk_type_unique( TYPE_IDIALOG, &info ); } return( stringset_type ); } GtkWidget * stringset_new( void ) { Stringset *ss = gtk_type_new( TYPE_STRINGSET ); return( GTK_WIDGET( ss ) ); } StringsetChild * stringset_child_get( Stringset *ss, const char *label ) { GSList *p; for( p = ss->children; p; p = p->next ) { StringsetChild *ssc = (StringsetChild *) p->data; if( strcmp( label, ssc->label ) == 0 ) return( ssc ); } return( NULL ); } /* Find dialog. */ static iDialogClass *find_parent_class = NULL; static void find_build( GtkWidget *widget ) { Find *find = FIND( widget ); iDialog *idlg = IDIALOG( widget ); #ifdef DEBUG printf( "find_build: %s\n", IWINDOW( find )->title ); #endif /*DEBUG*/ /* Call all builds in superclasses. */ if( IWINDOW_CLASS( find_parent_class )->build ) (*IWINDOW_CLASS( find_parent_class )->build)( widget ); find->search = build_glabeltext4( idlg->work, NULL, _( "Search for" ) ); find->csens = build_gtoggle( idlg->work, _( "Case sensitive" ) ); #ifdef HAVE_GREGEX find->regexp = build_gtoggle( idlg->work, _( "Regular expression" ) ); #endif /*HAVE_GREGEX*/ find->fromtop = build_gtoggle( idlg->work, _( "Search from start" ) ); idialog_set_default_entry( idlg, GTK_ENTRY( find->search ) ); gtk_widget_show_all( idlg->work ); } static void find_class_init( FindClass *class ) { iWindowClass *iwindow_class = (iWindowClass *) class; iwindow_class->build = find_build; find_parent_class = g_type_class_peek_parent( class ); } static void find_init( Find *find ) { #ifdef DEBUG printf( "find_init: %s\n", IWINDOW( find )->title ); #endif /*DEBUG*/ idialog_set_pinup( IDIALOG( find ), TRUE ); } GtkType find_get_type( void ) { static GtkType find_type = 0; if( !find_type ) { static const GtkTypeInfo info = { "Find", sizeof( Find ), sizeof( FindClass ), (GtkClassInitFunc) find_class_init, (GtkObjectInitFunc) find_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; find_type = gtk_type_unique( TYPE_IDIALOG, &info ); } return( find_type ); } GtkWidget * find_new( void ) { Find *find = gtk_type_new( TYPE_FIND ); return( GTK_WIDGET( find ) ); } /* Launch a viewer on a URL. */ void box_url( GtkWidget *par, const char *url ) { #ifdef OS_WIN32 char url2[FILENAME_MAX]; int v; expand_variables( url, url2 ); v = (int) ShellExecute( NULL, "open", url2, NULL, NULL, SW_SHOWNORMAL ); if( v <= 32 ) { error_top( _( "Unable to view help file." ) ); error_sub( _( "Unable to open URL \"%s\", " "windows error code = %d." ), url, v ); iwindow_alert( par, GTK_MESSAGE_ERROR ); } #elif defined OS_DARWIN (void) systemf( "open %s", url ); #elif defined HAVE_XDG_OPEN static gboolean shown = FALSE; if( systemf( "%s %s", XDG_OPEN, url ) ) { error_top( _( "Unable to view help file." ) ); error_sub( _( "Attempt to view URL with xdg-open failed\n%s" ), url ); iwindow_alert( par, GTK_MESSAGE_ERROR ); } else if( !shown ) { error_top( _( "Browser window opened." ) ); error_sub( "%s", _( "You may need to switch desktops to see the " "new window." ) ); iwindow_alert( par, GTK_MESSAGE_INFO ); shown = TRUE; } #else /*default unix-y*/ static gboolean shown = FALSE; char txt[512]; VipsBuf buf = VIPS_BUF_STATIC( txt ); char txt2[512]; VipsBuf buf2 = VIPS_BUF_STATIC( txt2 ); char url2[FILENAME_MAX]; expand_variables( url, url2 ); vips_buf_appendf( &buf, "%s %s", BOX_BROWSER, BOX_BROWSER_REMOTE ); vips_buf_appendf( &buf2, vips_buf_all( &buf ), url2 ); if( systemf( "%s", vips_buf_all( &buf2 ) ) ) { error_top( _( "Unable to view help file." ) ); error_sub( _( "Attempted to launch browser with command:\n" " %s\n" "You can change this command in Preferences." ), vips_buf_all( &buf2 ) ); iwindow_alert( par, GTK_MESSAGE_ERROR ); } else if( !shown ) { error_top( _( "Browser window opened." ) ); error_sub( "%s", _( "You may need to switch desktops to see the " "new window." ) ); iwindow_alert( par, GTK_MESSAGE_INFO ); shown = TRUE; } #endif /*lots*/ } /* Fontchooser dialog. */ static iDialogClass *fontchooser_parent_class = NULL; static void fontchooser_build( GtkWidget *widget ) { Fontchooser *fontchooser = FONTCHOOSER( widget ); iDialog *idlg = IDIALOG( widget ); #ifdef DEBUG printf( "fontchooser_build: %s\n", IWINDOW( fontchooser )->title ); #endif /*DEBUG*/ /* Call all builds in superclasses. */ if( IWINDOW_CLASS( fontchooser_parent_class )->build ) (*IWINDOW_CLASS( fontchooser_parent_class )->build)( widget ); fontchooser->fontchooser = gtk_font_selection_new(); gtk_box_pack_start( GTK_BOX( idlg->work ), fontchooser->fontchooser, TRUE, TRUE, 2 ); iwindow_set_title( IWINDOW( idlg ), _( "Select Font" ) ); gtk_widget_show_all( idlg->work ); } static void fontchooser_class_init( FontchooserClass *class ) { iWindowClass *iwindow_class; fontchooser_parent_class = g_type_class_peek_parent( class ); iwindow_class = (iWindowClass *) class; iwindow_class->build = fontchooser_build; } static void fontchooser_init( Fontchooser *fontchooser ) { } GtkType fontchooser_get_type( void ) { static GtkType fontchooser_type = 0; if( !fontchooser_type ) { static const GtkTypeInfo info = { "Fontchooser", sizeof( Fontchooser ), sizeof( FontchooserClass ), (GtkClassInitFunc) fontchooser_class_init, (GtkObjectInitFunc) fontchooser_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; fontchooser_type = gtk_type_unique( TYPE_IDIALOG, &info ); } return( fontchooser_type ); } Fontchooser * fontchooser_new( void ) { Fontchooser *fontchooser = gtk_type_new( TYPE_FONTCHOOSER ); return( fontchooser ); } gboolean fontchooser_set_font_name( Fontchooser *fontchooser, const char *font_name ) { if( !gtk_font_selection_set_font_name( GTK_FONT_SELECTION( fontchooser->fontchooser ), font_name ) ) { error_top( _( "Font not found." ) ); error_sub( _( "Font \"%s\" not found on system." ), font_name ); return( FALSE ); } return( TRUE ); } char * fontchooser_get_font_name( Fontchooser *fontchooser ) { return( gtk_font_selection_get_font_name( GTK_FONT_SELECTION( fontchooser->fontchooser ) ) ); } /* Fontbutton. */ /* Our signals. */ enum { SIG_CHANGED, /* New font selected */ SIG_LAST }; static GtkButtonClass *fontbutton_parent_class = NULL; static guint fontbutton_signals[SIG_LAST] = { 0 }; static void fontbutton_finalize( GObject *gobject ) { Fontbutton *fontbutton; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_FONTBUTTON( gobject ) ); fontbutton = FONTBUTTON( gobject ); IM_FREE( fontbutton->font_name ); G_OBJECT_CLASS( fontbutton_parent_class )->finalize( gobject ); } static void fontbutton_ok_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Fontchooser *fontchooser = FONTCHOOSER( iwnd ); Fontbutton *fontbutton = FONTBUTTON( client ); char *font_name; font_name = fontchooser_get_font_name( fontchooser ); fontbutton_set_font_name( fontbutton, font_name ); g_free( font_name ); nfn( sys, IWINDOW_YES ); } static void fontbutton_popdown_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Fontbutton *fontbutton = FONTBUTTON( client ); fontbutton->fontchooser = NULL; nfn( sys, IWINDOW_YES ); } static void fontbutton_clicked( GtkButton *button ) { Fontbutton *fontbutton = FONTBUTTON( button ); if( fontbutton->fontchooser ) gtk_window_present( GTK_WINDOW( fontbutton->fontchooser ) ); else { fontbutton->fontchooser = fontchooser_new(); iwindow_set_title( IWINDOW( fontbutton->fontchooser ), _( "Pick a font" ) ); idialog_set_callbacks( IDIALOG( fontbutton->fontchooser ), iwindow_true_cb, fontbutton_popdown_cb, NULL, fontbutton ); idialog_add_ok( IDIALOG( fontbutton->fontchooser ), fontbutton_ok_cb, _( "Set Font" ) ); iwindow_set_parent( IWINDOW( fontbutton->fontchooser ), GTK_WIDGET( button ) ); idialog_set_pinup( IDIALOG( fontbutton->fontchooser ), TRUE ); iwindow_build( IWINDOW( fontbutton->fontchooser ) ); fontchooser_set_font_name( fontbutton->fontchooser, fontbutton->font_name ); gtk_widget_show( GTK_WIDGET( fontbutton->fontchooser ) ); } } static void fontbutton_real_changed( Fontbutton *fontbutton ) { } static void fontbutton_class_init( FontbuttonClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; GtkButtonClass *bobject_class = (GtkButtonClass *) class; fontbutton_parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = fontbutton_finalize; bobject_class->clicked = fontbutton_clicked; class->changed = fontbutton_real_changed; fontbutton_signals[SIG_CHANGED] = g_signal_new( "changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( FontbuttonClass, changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); } static void fontbutton_init( Fontbutton *fontbutton ) { fontbutton->font_name = NULL; fontbutton->fontchooser = NULL; set_tooltip( GTK_WIDGET( fontbutton ), _( "Click to select font" ) ); } GtkType fontbutton_get_type( void ) { static GtkType fontbutton_type = 0; if( !fontbutton_type ) { static const GtkTypeInfo info = { "Fontbutton", sizeof( Fontbutton ), sizeof( FontbuttonClass ), (GtkClassInitFunc) fontbutton_class_init, (GtkObjectInitFunc) fontbutton_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; fontbutton_type = gtk_type_unique( GTK_TYPE_BUTTON, &info ); } return( fontbutton_type ); } Fontbutton * fontbutton_new( void ) { Fontbutton *fontbutton = g_object_new( TYPE_FONTBUTTON, "label", "Sans 12", NULL ); return( fontbutton ); } void fontbutton_set_font_name( Fontbutton *fontbutton, const char *font_name ) { char font[256]; char button_text[256]; int i; if( !fontbutton->font_name || strcmp( fontbutton->font_name, font_name ) != 0 ) { IM_SETSTR( fontbutton->font_name, font_name ); im_strncpy( font, font_name, 256 ); for( i = strlen( font ) - 1; i > 0 && isdigit( font[i] ); i-- ) font[i] = '\0'; im_snprintf( button_text, 256, "%s", font, font_name ); gtk_label_set_markup( GTK_LABEL( gtk_bin_get_child( GTK_BIN( fontbutton ) ) ), button_text ); if( fontbutton->fontchooser ) fontchooser_set_font_name( fontbutton->fontchooser, font_name ); g_signal_emit( G_OBJECT( fontbutton ), fontbutton_signals[SIG_CHANGED], 0 ); } } const char * fontbutton_get_font_name( Fontbutton *fontbutton ) { return( fontbutton->font_name ); } /* Infobar. Optional: it's only in quite recent gtk. */ #ifdef USE_INFOBAR static GtkInfoBarClass *infobar_parent_class = NULL; static void infobar_destroy( GtkObject *object ) { Infobar *infobar; g_return_if_fail( object != NULL ); g_return_if_fail( IS_INFOBAR( object ) ); infobar = INFOBAR( object ); IM_FREEF( g_source_remove, infobar->close_timeout ); IM_FREEF( g_source_remove, infobar->close_animation_timeout ); GTK_OBJECT_CLASS( infobar_parent_class )->destroy( object ); } static void infobar_class_init( InfobarClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; infobar_parent_class = g_type_class_peek_parent( class ); object_class->destroy = infobar_destroy; } static void infobar_init( Infobar *infobar ) { infobar->top = NULL; infobar->sub = NULL; infobar->close_timeout = 0; infobar->close_animation_timeout = 0; infobar->height = 0; } GType infobar_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( InfobarClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) infobar_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Infobar ), 32, /* n_preallocs */ (GInstanceInitFunc) infobar_init, }; type = g_type_register_static( GTK_TYPE_INFO_BAR, "Infobar", &info, 0 ); } return( type ); } static void infobar_cancel_close( Infobar *infobar ) { IM_FREEF( g_source_remove, infobar->close_timeout ); IM_FREEF( g_source_remove, infobar->close_animation_timeout ); gtk_widget_set_size_request( GTK_WIDGET( infobar ), -1, -1 ); } static void infobar_hide( Infobar *infobar ) { infobar_cancel_close( infobar ); gtk_widget_hide( GTK_WIDGET( infobar ) ); gtk_widget_hide( GTK_WIDGET( infobar->sub ) ); gtk_widget_set_sensitive( GTK_WIDGET( infobar->info ), TRUE ); } static gboolean infobar_close_animation_timeout( Infobar *infobar ) { infobar->height -= 20; if( infobar->height <= 0 ) { infobar_hide( infobar ); return( FALSE ); } gtk_widget_set_size_request( GTK_WIDGET( infobar ), -1, infobar->height ); return( TRUE ); } static void infobar_start_close( Infobar *infobar ) { infobar_cancel_close( infobar ); infobar->height = GTK_WIDGET( infobar )->allocation.height; infobar->close_animation_timeout = g_timeout_add( 50, (GSourceFunc) infobar_close_animation_timeout, infobar ); } static gboolean infobar_close_timeout( Infobar *infobar ) { infobar_start_close( infobar ); return( FALSE ); } static void infobar_show( Infobar *infobar ) { infobar_cancel_close( infobar ); infobar->close_timeout = g_timeout_add( 5000, (GSourceFunc) infobar_close_timeout, infobar ); gtk_widget_show( GTK_WIDGET( infobar ) ); } static void infobar_info_cb( GtkWidget *button, Infobar *infobar ) { infobar_cancel_close( infobar ); gtk_widget_show( GTK_WIDGET( infobar->sub ) ); gtk_widget_set_sensitive( GTK_WIDGET( infobar->info ), FALSE ); } static void infobar_close_cb( GtkWidget *button, Infobar *infobar ) { infobar_start_close( infobar ); } Infobar * infobar_new( void ) { Infobar *infobar; GtkWidget *vbox; GtkWidget *content_area; GtkWidget *hbox; GtkWidget *action_area; GtkWidget *button; infobar = g_object_new( TYPE_INFOBAR, NULL ); vbox = gtk_vbox_new( FALSE, 10 ); content_area = gtk_info_bar_get_content_area( GTK_INFO_BAR( infobar ) ); gtk_container_add( GTK_CONTAINER( content_area ), vbox ); gtk_widget_show( vbox ); infobar->top = gtk_label_new( "" ); gtk_label_set_justify( GTK_LABEL( infobar->top ), GTK_JUSTIFY_LEFT ); gtk_label_set_selectable( GTK_LABEL( infobar->top ), TRUE ); gtk_label_set_line_wrap( GTK_LABEL( infobar->top ), TRUE ); gtk_container_add( GTK_CONTAINER( vbox ), infobar->top ); gtk_widget_show( infobar->top ); infobar->sub = gtk_label_new( "" ); gtk_label_set_justify( GTK_LABEL( infobar->sub ), GTK_JUSTIFY_LEFT ); gtk_label_set_selectable( GTK_LABEL( infobar->sub ), TRUE ); gtk_label_set_line_wrap( GTK_LABEL( infobar->sub ), TRUE ); gtk_container_add( GTK_CONTAINER( vbox ), infobar->sub ); /* We can't use gtk_info_bar_add_button(), we need the buttons * horizontally. */ hbox = gtk_hbox_new( FALSE, 2 ); action_area = gtk_info_bar_get_action_area( GTK_INFO_BAR( infobar ) ); gtk_container_add( GTK_CONTAINER( action_area ), hbox ); gtk_widget_show( hbox ); button = gtk_button_new_from_stock( GTK_STOCK_CLOSE ); gtk_box_pack_end( GTK_BOX( hbox ), button, TRUE, TRUE, 2 ); g_signal_connect( button, "clicked", G_CALLBACK( infobar_close_cb ), infobar ); gtk_widget_show( button ); infobar->info = gtk_button_new_from_stock( GTK_STOCK_INFO ); gtk_box_pack_end( GTK_BOX( hbox ), infobar->info, TRUE, TRUE, 2 ); g_signal_connect( infobar->info, "clicked", G_CALLBACK( infobar_info_cb ), infobar ); gtk_widget_show( infobar->info ); return( infobar ); } #else /*!USE_INFOBAR*/ Infobar * infobar_new( void ) { return( NULL ); } #endif /*USE_INFOBAR*/ /* Set the label on an infobar to some marked-up text. */ void infobar_vset( Infobar *infobar, GtkMessageType type, const char *top, const char *sub, va_list ap ) { #ifdef USE_INFOBAR char buf1[MAX_DIALOG_TEXT]; char buf2[MAX_DIALOG_TEXT]; char *p; escape_markup( top, buf1, MAX_DIALOG_TEXT ); im_snprintf( buf2, MAX_DIALOG_TEXT, "%s", buf1 ); gtk_label_set_markup( GTK_LABEL( infobar->top ), buf2 ); (void) im_vsnprintf( buf1, MAX_DIALOG_TEXT, sub, ap ); escape_markup( buf1, buf2, MAX_DIALOG_TEXT ); /* Remove any trailing newlines, they make infobars rather large. */ while( (p = buf2 + strlen( buf2 )) > buf2 && p[-1] == '\n' ) p[-1] = '\0'; gtk_label_set_markup( GTK_LABEL( infobar->sub ), buf2 ); gtk_info_bar_set_message_type( GTK_INFO_BAR( infobar ), type ); infobar_show( infobar ); #endif /*USE_INFOBAR*/ } /* Set the label on an infobar to some marked-up text. */ void infobar_set( Infobar *infobar, GtkMessageType type, const char *top, const char *sub, ... ) { va_list ap; va_start( ap, sub ); infobar_vset( infobar, type, top, sub, ap ); va_end( ap ); } nip2-8.7.1/src/iregiongroup.c0000644000175000017500000000610513351443023012764 00000000000000/* base model for a client regions on an imageview */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void * iregiongroup_update_model( Heapmodel *heapmodel ) { #ifdef DEBUG printf( "iregiongroup_update_model: " ); row_name_print( heapmodel->row ); printf( "\n" ); #endif /*DEBUG*/ if( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ) return( heapmodel ); /* Only display most-derived classes. Don't display "this". */ if( heapmodel->row->sym ) model_display( MODEL( heapmodel ), !is_super( heapmodel->row->sym ) && !is_this( heapmodel->row->sym ) ); return( NULL ); } static View * iregiongroup_view_new( Model *model, View *parent ) { return( iregiongroupview_new() ); } static void iregiongroup_class_init( iRegiongroupClass *class ) { ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ heapmodel_class->update_model = iregiongroup_update_model; model_class->view_new = iregiongroup_view_new; } static void iregiongroup_init( iRegiongroup *iregiongroup ) { /* Display turned on in _update_model() above. */ MODEL( iregiongroup )->display = FALSE; } GType iregiongroup_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( iRegiongroupClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) iregiongroup_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( iRegiongroup ), 32, /* n_preallocs */ (GInstanceInitFunc) iregiongroup_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "iRegiongroup", &info, 0 ); } return( type ); } iRegiongroup * iregiongroup_new( Classmodel *classmodel ) { iRegiongroup *iregiongroup; iregiongroup = IREGIONGROUP( g_object_new( TYPE_IREGIONGROUP, NULL ) ); icontainer_child_add( ICONTAINER( classmodel ), ICONTAINER( iregiongroup ), -1 ); #ifdef DEBUG printf( "iregiongroup_new: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( "\n" ); #endif /*DEBUG*/ return( iregiongroup ); } nip2-8.7.1/src/workspacegroupview.c0000644000175000017500000004675413351443023014237 00000000000000/* main processing window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static ViewClass *parent_class = NULL; static void workspacegroupview_realize( GtkWidget *widget ) { #ifdef DEBUG { Workspacegroupview *wsgview = WORKSPACEGROUPVIEW( widget ); Workspace *ws = WORKSPACE( VOBJECT( wsgview )->iobject ); printf( "workspacegroupview_realize: %s\n", IOBJECT( ws )->name ); } #endif /*DEBUG*/ GTK_WIDGET_CLASS( parent_class )->realize( widget ); /* Mark us as a symbol drag-to widget. */ set_symbol_drag_type( widget ); } static void workspacegroupview_rename_sub( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Workspace *ws = WORKSPACE( client ); Stringset *ss = STRINGSET( iwnd ); StringsetChild *name = stringset_child_get( ss, _( "Name" ) ); StringsetChild *caption = stringset_child_get( ss, _( "Caption" ) ); char name_text[1024]; char caption_text[1024]; if( !get_geditable_name( name->entry, name_text, 1024 ) || !get_geditable_string( caption->entry, caption_text, 1024 ) ) { nfn( sys, IWINDOW_ERROR ); return; } if( !workspace_rename( ws, name_text, caption_text ) ) { nfn( sys, IWINDOW_ERROR ); return; } nfn( sys, IWINDOW_YES ); } static void workspacegroupview_rename_cb( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); GtkWidget *ss = stringset_new(); if( ws->locked ) return; stringset_child_new( STRINGSET( ss ), _( "Name" ), IOBJECT( ws )->name, _( "Set tab name here" ) ); stringset_child_new( STRINGSET( ss ), _( "Caption" ), IOBJECT( ws )->caption, _( "Set tab caption here" ) ); iwindow_set_title( IWINDOW( ss ), _( "Rename Tab \"%s\"" ), IOBJECT( ws )->name ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, ws ); idialog_add_ok( IDIALOG( ss ), workspacegroupview_rename_sub, _( "Rename Tab" ) ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( wview ) ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); } static void workspacegroupview_rename_cb2( GtkWidget *wid, GdkEvent *event, Workspaceview *wview ) { workspacegroupview_rename_cb( wid, NULL, wview ); } static void workspacegroupview_child_add( View *parent, View *child ) { Workspacegroupview *wsgview = WORKSPACEGROUPVIEW( parent ); Workspaceview *wview = WORKSPACEVIEW( child ); Workspace *ws = WORKSPACE( VOBJECT( child )->iobject ); GtkWidget *ebox; GtkWidget *hbox; GtkWidget *label; GtkWidget *padlock; GtkWidget *alert; VIEW_CLASS( parent_class )->child_add( parent, child ); ebox = gtk_event_box_new(); gtk_widget_add_events( GTK_WIDGET( ebox ), GDK_BUTTON_PRESS_MASK ); hbox = gtk_hbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( ebox ), hbox ); gtk_widget_show( GTK_WIDGET( hbox ) ); padlock = gtk_image_new(); gtk_box_pack_start( GTK_BOX( hbox ), padlock, FALSE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( padlock ) ); set_tooltip( padlock, "%s", _( "unlock from Edit menu" ) ); alert = gtk_image_new(); gtk_box_pack_start( GTK_BOX( hbox ), alert, FALSE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( alert ) ); set_tooltip( alert, "%s", _( "errors in tab" ) ); label = gtk_label_new( NN( IOBJECT( ws->sym )->name ) ); gtk_box_pack_end( GTK_BOX( hbox ), label, FALSE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( label ) ); workspaceview_set_label( wview, label, padlock, alert ); popup_attach( ebox, wsgview->tab_menu, wview ); doubleclick_add( ebox, FALSE, NULL, NULL, DOUBLECLICK_FUNC( workspacegroupview_rename_cb2 ), wview ); gtk_notebook_insert_page( GTK_NOTEBOOK( wsgview->notebook ), GTK_WIDGET( wview ), ebox, ICONTAINER( ws )->pos ); gtk_notebook_set_tab_reorderable( GTK_NOTEBOOK( wsgview->notebook ), GTK_WIDGET( wview ), TRUE ); gtk_notebook_set_tab_detachable( GTK_NOTEBOOK( wsgview->notebook ), GTK_WIDGET( wview ), TRUE ); } static void workspacegroupview_child_remove( View *parent, View *child ) { /* Stuff. Workspacegroupview *wsgview = WORKSPACEGROUPVIEW( parent ); Workspaceview *wview = WORKSPACEVIEW( child ); */ VIEW_CLASS( parent_class )->child_remove( parent, child ); } static void workspacegroupview_child_position( View *parent, View *child ) { Workspacegroupview *wsgview = WORKSPACEGROUPVIEW( parent ); Workspaceview *wview = WORKSPACEVIEW( child ); gtk_notebook_reorder_child( GTK_NOTEBOOK( wsgview->notebook ), GTK_WIDGET( wview ), ICONTAINER( wview )->pos ); VIEW_CLASS( parent_class )->child_position( parent, child ); } static void workspacegroupview_child_front( View *parent, View *child ) { Workspacegroupview *wsgview = WORKSPACEGROUPVIEW( parent ); Workspaceview *wview = WORKSPACEVIEW( child ); int page; GtkWidget *current_front; page = gtk_notebook_get_current_page( GTK_NOTEBOOK( wsgview->notebook ) ); current_front = gtk_notebook_get_nth_page( GTK_NOTEBOOK( wsgview->notebook ), page ); if( current_front != GTK_WIDGET( wview ) ) { page = gtk_notebook_page_num( GTK_NOTEBOOK( wsgview->notebook ), GTK_WIDGET( wview ) ); gtk_notebook_set_current_page( GTK_NOTEBOOK( wsgview->notebook ), page ); } } static void workspacegroupview_class_init( WorkspacegroupviewClass *class ) { GtkWidgetClass *widget_class = (GtkWidgetClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); widget_class->realize = workspacegroupview_realize; view_class->child_add = workspacegroupview_child_add; view_class->child_remove = workspacegroupview_child_remove; view_class->child_position = workspacegroupview_child_position; view_class->child_front = workspacegroupview_child_front; } typedef struct _nip2GtkNotebookPage { GtkWidget *child; /* A lot of stuff follows in the real struct, which we ignore. */ } nip2GtkNotebookPage; /* gtk+-2.20 and earlier had a bug whereby switch_page would be given a * GtkNotebookPage rather than the actual page widget. */ static Workspaceview * notebookpage_get_workspaceview( GtkWidget *page ) { #ifdef USE_NOTEBOOK_GROUP_NAME return( WORKSPACEVIEW( page ) ); #else /*!USE_NOTEBOOK_GROUP_NAME*/ /* Buggy argh. */ return( WORKSPACEVIEW( ((nip2GtkNotebookPage *) page)->child ) ); #endif } /* Called for switching the current page, and for page drags between * notebooks. */ static void workspacegroupview_switch_page_cb( GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data ) { Workspaceview *wview = notebookpage_get_workspaceview( page ); Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); Workspacegroup *old_wsg = WORKSPACEGROUP( ICONTAINER( ws )->parent ); Workspacegroupview *wsgview = WORKSPACEGROUPVIEW( user_data ); Workspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject ); if( ICONTAINER( ws )->parent != ICONTAINER( wsg ) ) { icontainer_reparent( ICONTAINER( wsg ), ICONTAINER( ws ), -1 ); filemodel_set_modified( FILEMODEL( wsg ), TRUE ); filemodel_set_modified( FILEMODEL( old_wsg ), TRUE ); /* If dragging the tab has emptied the old wsg, we can junk * the window. */ mainw_cull(); } icontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) ); if( ws->compat_major ) { error_top( _( "Compatibility mode." ) ); error_sub( _( "This workspace was created by version %d.%d. " "A set of compatibility menus have been loaded " "for this window." ), ws->compat_major, ws->compat_minor ); iwindow_alert( GTK_WIDGET( wview ), GTK_MESSAGE_INFO ); } /* How bizarre, pages sometimes fail to set up correctly. Force a * resize to get everything to init. */ if( wview && wview->fixed ) gtk_container_check_resize( GTK_CONTAINER( wview->fixed ) ); } static void workspacegroupview_page_added_cb( GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data ) { Workspacegroupview *wsgview = WORKSPACEGROUPVIEW( user_data ); Workspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject ); Mainw *mainw = MAINW( iwindow_get_root( GTK_WIDGET( notebook ) ) ); filemodel_set_window_hint( FILEMODEL( wsg ), IWINDOW( mainw ) ); } static GtkNotebook * workspacegroupview_create_window_cb( GtkNotebook *notebook, GtkWidget *page, int x, int y, gpointer user_data ) { Workspaceview *wview = WORKSPACEVIEW( page ); Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); Workspacegroup *wsg = WORKSPACEGROUP( ICONTAINER( ws )->parent ); Workspaceroot *wsr = wsg->wsr; Mainw *new_mainw; Workspacegroup *new_wsg; char name[256]; /* printf( "workspacegroupview_create_window_cb: wsg = %s, ws = %s\n", NN( IOBJECT( wsg )->name ), NN( IOBJECT( ws )->name ) ); printf( "workspacegroupview_create_window_cb: x = %d, y = %d\n", x, y ); */ workspaceroot_name_new( wsr, name ); new_wsg = workspacegroup_new( wsr ); /* printf( "workspacegroupview_create_window_cb: new wsg = %s\n", name ); */ iobject_set( IOBJECT( new_wsg ), name, NULL ); new_mainw = mainw_new( new_wsg ); gtk_window_move( GTK_WINDOW( new_mainw ), x, y ); gtk_widget_show( GTK_WIDGET( new_mainw ) ); return( GTK_NOTEBOOK( new_mainw->wsgview->notebook ) ); } static void workspacegroupview_page_reordered_cb( GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer user_data ) { Workspaceview *wview = WORKSPACEVIEW( page ); Workspacegroupview *wsgview = WORKSPACEGROUPVIEW( VIEW( wview )->parent ); Workspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject ); int i; gboolean changed; changed = FALSE; for( i = 0; i < gtk_notebook_get_n_pages( notebook ); i++ ) { GtkWidget *page_n = gtk_notebook_get_nth_page( notebook, i ); Workspaceview *wview = WORKSPACEVIEW( page_n ); Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); if( ICONTAINER( ws )->pos != i ) { ICONTAINER( ws )->pos = i; changed = TRUE; } } if( changed ) { icontainer_pos_sort( ICONTAINER ( wsg ) ); filemodel_set_modified( FILEMODEL( wsg ), TRUE ); } } static void workspacegroupview_tab_double_cb( GtkNotebook *notebook, GdkEvent *event, Workspacegroupview *wsgview ) { Workspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject ); int i; GtkWidget *page; GtkWidget *tab; /* Doubleclick in a tab row background. This could be the gutter or * the edge of a label. Get the position of the right-most tab and * check our click x against that. */ i = gtk_notebook_get_n_pages( notebook ); page = gtk_notebook_get_nth_page( notebook, i - 1 ); tab = gtk_notebook_get_tab_label( notebook, page ); if( event->button.x > tab->allocation.x + tab->allocation.width && !workspace_new_blank( wsg ) ) iwindow_alert( GTK_WIDGET( wsgview ), GTK_MESSAGE_ERROR ); } static void workspacegroupview_add_workspace_cb( GtkWidget *wid, Workspacegroupview *wsgview ) { Workspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject ); if( !workspace_new_blank( wsg ) ) iwindow_alert( GTK_WIDGET( wsgview ), GTK_MESSAGE_ERROR ); } static void workspacegroupview_add_workspace_cb2( GtkWidget *wid, GtkWidget *host, Workspacegroupview *wsgview ) { workspacegroupview_add_workspace_cb( wid, wsgview ); } static void workspacegroupview_load_workspace_cb2( GtkWidget *wid, GtkWidget *host, Workspacegroupview *wsgview ) { Mainw *mainw = MAINW( iwindow_get_root( GTK_WIDGET( wsgview ) ) ); mainw_workspace_merge( mainw ); } static void workspacegroupview_select_all_cb( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); if( !ws->locked ) workspace_select_all( ws ); } static void workspacegroupview_duplicate_cb( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); if( !workspace_duplicate( ws ) ) { iwindow_alert( host, GTK_MESSAGE_ERROR ); return; } } static void workspacegroupview_merge_sub( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Workspace *ws = WORKSPACE( client ); Workspacegroup *wsg = workspace_get_workspacegroup( ws ); char *filename; Column *col; if( (filename = filesel_get_filename( filesel )) ) { icontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) ); progress_begin(); column_clear_last_new(); if( !workspace_merge_file( ws, filename ) ) nfn( sys, IWINDOW_ERROR ); else { symbol_recalculate_all(); nfn( sys, IWINDOW_YES ); } if( (col = column_get_last_new()) ) column_scrollto( col, MODEL_SCROLL_TOP ); progress_end(); g_free( filename ); } else nfn( sys, IWINDOW_ERROR ); } static void workspacegroupview_merge_cb( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); iWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( wview ) ) ); GtkWidget *filesel = filesel_new(); if( ws->locked ) return; iwindow_set_title( IWINDOW( filesel ), _( "Merge Into Tab \"%s\"" ), IOBJECT( ws )->name ); filesel_set_flags( FILESEL( filesel ), FALSE, FALSE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) ); idialog_set_iobject( IDIALOG( filesel ), IOBJECT( ws ) ); filesel_set_done( FILESEL( filesel ), workspacegroupview_merge_sub, ws ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } static void workspacegroupview_save_as_sub( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Workspace *ws = WORKSPACE( client ); Workspacegroup *wsg = workspace_get_workspacegroup( ws ); char *filename; if( (filename = filesel_get_filename( filesel )) ) { icontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) ); if( !workspacegroup_save_current( wsg, filename ) ) nfn( sys, IWINDOW_ERROR ); else nfn( sys, IWINDOW_YES ); g_free( filename ); } else nfn( sys, IWINDOW_ERROR ); } static void workspacegroupview_save_as_cb( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); iWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( wview ) ) ); GtkWidget *filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Save Tab \"%s\"" ), IOBJECT( ws )->name ); filesel_set_flags( FILESEL( filesel ), FALSE, TRUE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) ); idialog_set_iobject( IDIALOG( filesel ), IOBJECT( ws ) ); filesel_set_done( FILESEL( filesel ), workspacegroupview_save_as_sub, ws ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } /* ws has been destroyed. */ static void workspacegroupview_delete_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { mainw_cull(); nfn( sys, IWINDOW_YES ); } static void workspacegroupview_delete_cb( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); if( !ws->locked ) model_check_destroy( view_get_toplevel( VIEW( wview ) ), MODEL( ws ), workspacegroupview_delete_done_cb ); } static void workspacegroupview_init( Workspacegroupview *wsgview ) { wsgview->notebook = gtk_notebook_new(); gtk_notebook_set_scrollable( GTK_NOTEBOOK( wsgview->notebook ), TRUE ); #ifdef USE_NOTEBOOK_GROUP_NAME gtk_notebook_set_group_name( GTK_NOTEBOOK( wsgview->notebook ), "wsgview" ); #endif /*USE_NOTEBOOK_GROUP_NAME*/ gtk_notebook_set_tab_pos( GTK_NOTEBOOK( wsgview->notebook ), GTK_POS_TOP ); g_signal_connect( wsgview->notebook, "switch_page", G_CALLBACK( workspacegroupview_switch_page_cb ), wsgview ); g_signal_connect( wsgview->notebook, "page_added", G_CALLBACK( workspacegroupview_page_added_cb ), wsgview ); g_signal_connect( wsgview->notebook, "page_reordered", G_CALLBACK( workspacegroupview_page_reordered_cb ), wsgview ); g_signal_connect( wsgview->notebook, "create_window", G_CALLBACK( workspacegroupview_create_window_cb ), wsgview ); doubleclick_add( wsgview->notebook, FALSE, NULL, NULL, DOUBLECLICK_FUNC( workspacegroupview_tab_double_cb ), wsgview ); wsgview->gutter_menu = popup_build( _( "Tab gutter menu" ) ); popup_add_but( wsgview->gutter_menu, _( "New Tab" ), POPUP_FUNC( workspacegroupview_add_workspace_cb2 ) ); popup_add_but( wsgview->gutter_menu, _( "Merge Into Workspace" ), POPUP_FUNC( workspacegroupview_load_workspace_cb2 ) ); popup_attach( wsgview->notebook, wsgview->gutter_menu, wsgview ); #ifdef USE_NOTEBOOK_ACTION { GtkWidget *but; GtkWidget *icon; but = gtk_button_new(); gtk_button_set_relief( GTK_BUTTON( but ), GTK_RELIEF_NONE ); set_tooltip( but, _( "Add a workspace" ) ); icon = gtk_image_new_from_stock( GTK_STOCK_ADD, GTK_ICON_SIZE_MENU ); gtk_container_add( GTK_CONTAINER( but ), icon ); gtk_widget_show( icon ); gtk_widget_show( but ); gtk_notebook_set_action_widget( GTK_NOTEBOOK( wsgview->notebook ), but, GTK_PACK_END ); g_signal_connect( but, "clicked", G_CALLBACK( workspacegroupview_add_workspace_cb ), wsgview ); } #endif /*USE_NOTEBOOK_ACTION*/ gtk_box_pack_start( GTK_BOX( wsgview ), wsgview->notebook, TRUE, TRUE, 0 ); gtk_widget_show( wsgview->notebook ); wsgview->tab_menu = popup_build( _( "Tab menu" ) ); popup_add_but( wsgview->tab_menu, _( "Rename" ), POPUP_FUNC( workspacegroupview_rename_cb ) ); popup_add_but( wsgview->tab_menu, _( "Select All" ), POPUP_FUNC( workspacegroupview_select_all_cb ) ); popup_add_but( wsgview->tab_menu, STOCK_DUPLICATE, POPUP_FUNC( workspacegroupview_duplicate_cb ) ); popup_add_but( wsgview->tab_menu, _( "Merge Into Tab" ), POPUP_FUNC( workspacegroupview_merge_cb ) ); popup_add_but( wsgview->tab_menu, GTK_STOCK_SAVE_AS, POPUP_FUNC( workspacegroupview_save_as_cb ) ); menu_add_sep( wsgview->tab_menu ); popup_add_but( wsgview->tab_menu, GTK_STOCK_DELETE, POPUP_FUNC( workspacegroupview_delete_cb ) ); } GtkType workspacegroupview_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( WorkspacegroupviewClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) workspacegroupview_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Workspacegroupview ), 32, /* n_preallocs */ (GInstanceInitFunc) workspacegroupview_init, }; type = g_type_register_static( TYPE_VIEW, "Workspacegroupview", &info, 0 ); } return( type ); } View * workspacegroupview_new( void ) { Workspacegroupview *wsgview = gtk_type_new( TYPE_WORKSPACEGROUPVIEW ); return( VIEW( wsgview ) ); } nip2-8.7.1/src/plotpresent.h0000644000175000017500000000365613351443023012647 00000000000000/* a plot widget, plus some navigation stuff */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PLOTPRESENT (plotpresent_get_type()) #define PLOTPRESENT( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_PLOTPRESENT, Plotpresent )) #define PLOTPRESENT_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTPRESENT, PlotpresentClass )) #define IS_PLOTPRESENT( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTPRESENT )) #define IS_PLOTPRESENT_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTPRESENT )) struct _Plotpresent { GtkBin parent_class; /* Context. */ Plotmodel *plotmodel; /* Keep model parts of widgets here */ /* Widgets. */ GtkWidget *canvas; #ifdef HAVE_LIBGOFFICE GogRenderer *grend; GogChart *gchart; GogGraph *ggraph; GogPlot *gplot; #endif /*HAVE_LIBGOFFICE*/ }; typedef struct _PlotpresentClass { GtkBinClass parent_class; /* My methods. */ /* A mouse movement within the plot area. xy are in axies coordinates. */ void (*mouse_move)( Plotpresent *, double, double ); } PlotpresentClass; GtkType plotpresent_get_type( void ); Plotpresent *plotpresent_new( Plotmodel *plotmodel ); nip2-8.7.1/src/imagemodel.c0000644000175000017500000003406713351443023012366 00000000000000/* All the model stuff for an imageview window. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Our signals. */ enum { SIG_IMAGEINFO_CHANGED, /* Imageinfo we hold has been replaced */ SIG_LAST }; static iObjectClass *parent_class = NULL; static guint imagemodel_signals[SIG_LAST] = { 0 }; void * imagemodel_imageinfo_changed( Imagemodel *imagemodel ) { #ifdef DEBUG printf( "imagemodel_imageinfo_changed: " ); iobject_print( IOBJECT( imagemodel ) ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( imagemodel ), imagemodel_signals[SIG_IMAGEINFO_CHANGED], 0 ); return( NULL ); } /* Is a state a paint state, ie. one which might alter the image? We warn * before going to one of these. */ gboolean imagemodel_state_paint( ImagemodelState state ) { static gboolean state_paint[IMAGEMODEL_LAST] = { FALSE, /* IMAGEMODEL_SELECT */ FALSE, /* IMAGEMODEL_PAN */ FALSE, /* IMAGEMODEL_MAGIN */ FALSE, /* IMAGEMODEL_MAGOUT */ FALSE, /* IMAGEMODEL_DROPPER */ TRUE, /* IMAGEMODEL_PEN */ TRUE, /* IMAGEMODEL_LINE */ TRUE, /* IMAGEMODEL_RECT */ TRUE, /* IMAGEMODEL_FLOOD */ TRUE, /* IMAGEMODEL_BLOB */ TRUE, /* IMAGEMODEL_TEXT */ TRUE /* IMAGEMODEL_SMUDGE */ }; g_assert( state < IMAGEMODEL_LAST ); return( state_paint[state] ); } #ifdef DEBUG static const char * imagemodel_state( ImagemodelState state ) { switch( state ) { case IMAGEMODEL_SELECT: return( "IMAGEMODEL_SELECT" ); case IMAGEMODEL_PAN: return( "IMAGEMODEL_PAN" ); case IMAGEMODEL_MAGIN: return( "IMAGEMODEL_MAGIN" ); case IMAGEMODEL_MAGOUT: return( "IMAGEMODEL_MAGOUT" ); case IMAGEMODEL_DROPPER: return( "IMAGEMODEL_DROPPER" ); case IMAGEMODEL_PEN: return( "IMAGEMODEL_PEN" ); case IMAGEMODEL_LINE: return( "IMAGEMODEL_LINE" ); case IMAGEMODEL_RECT: return( "IMAGEMODEL_RECT" ); case IMAGEMODEL_FLOOD: return( "IMAGEMODEL_FLOOD" ); case IMAGEMODEL_BLOB: return( "IMAGEMODEL_BLOB" ); case IMAGEMODEL_TEXT: return( "IMAGEMODEL_TEXT" ); case IMAGEMODEL_SMUDGE: return( "IMAGEMODEL_SMUDGE" ); default: g_assert( FALSE ); } } #endif /*DEBUG*/ static void imagemodel_dispose( GObject *gobject ) { Imagemodel *imagemodel; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_IMAGEMODEL( gobject ) ); imagemodel = IMAGEMODEL( gobject ); #ifdef DEBUG printf( "imagemodel_dispose %p: ", imagemodel ); iobject_print( IOBJECT( imagemodel ) ); #endif /*DEBUG*/ FREESID( imagemodel->iimage_changed_sid, imagemodel->iimage ); FREESID( imagemodel->iimage_destroy_sid, imagemodel->iimage ); FREESID( imagemodel->conv_changed_sid, imagemodel->conv ); FREESID( imagemodel->conv_imageinfo_changed_sid, imagemodel->conv ); UNREF( imagemodel->conv ); MANAGED_UNREF( imagemodel->ink ); IM_FREE( imagemodel->font_name ); IM_FREE( imagemodel->text ); MANAGED_UNREF( imagemodel->text_mask ); MANAGED_UNREF( imagemodel->nib ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void imagemodel_changed( iObject *iobject ) { Imagemodel *imagemodel = IMAGEMODEL( iobject ); #ifdef DEBUG printf( "imagemodel_changed: state = %s ", imagemodel_state( imagemodel->state ) ); iobject_print( IOBJECT( imagemodel ) ); #endif /*DEBUG*/ conversion_set_params( imagemodel->conv, imagemodel->show_convert, imagemodel->scale, imagemodel->offset, imagemodel->falsecolour, imagemodel->type ); /* Update prefs. */ prefs_set( "DISPLAY_RULERS", "%s", bool_to_char( imagemodel->show_rulers ) ); prefs_set( "DISPLAY_STATUS", "%s", bool_to_char( imagemodel->show_status ) ); prefs_set( "DISPLAY_CONVERSION", "%s", bool_to_char( imagemodel->show_convert ) ); /* If the paint bar is on, we want to be in synchronous paint * mode. Even if we're not painting, we need this for * undo/redo to work. */ conversion_set_synchronous( imagemodel->conv, imagemodel->show_paintbox ); IOBJECT_CLASS( parent_class )->changed( iobject ); } static void imagemodel_class_init( ImagemodelClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = imagemodel_dispose; iobject_class->changed = imagemodel_changed; imagemodel_signals[SIG_IMAGEINFO_CHANGED] = g_signal_new( "imageinfo_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ImagemodelClass, imageinfo_changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); } /* Remake the ink image to match ii. */ static void imagemodel_refresh_ink( Imagemodel *imagemodel, Imageinfo *ii ) { IMAGE *main_im = imageinfo_get( FALSE, ii ); IMAGE *ink_im = imageinfo_get( FALSE, imagemodel->ink ); if( ink_im && ink_im->Bands == main_im->Bands && ink_im->BandFmt == main_im->BandFmt && ink_im->Coding == main_im->Coding && ink_im->Type == main_im->Type ) return; MANAGED_UNREF( imagemodel->ink ); if( (imagemodel->ink = imageinfo_new_temp( main_imageinfogroup, reduce_context->heap, NULL, "t" )) ) { MANAGED_REF( imagemodel->ink ); im_initdesc( imagemodel->ink->im, 1, 1, main_im->Bands, main_im->Bbits, main_im->BandFmt, main_im->Coding, main_im->Type, 1.0, 1.0, 0, 0 ); if( im_setupout( imagemodel->ink->im ) ) MANAGED_UNREF( imagemodel->ink ); } if( imagemodel->ink && imagemodel->ink->im && imagemodel->ink->im->data ) memset( imagemodel->ink->im->data, 0, IM_IMAGE_SIZEOF_LINE( imagemodel->ink->im ) ); } static void imagemodel_conv_changed_cb( Conversion *conv, Imagemodel *imagemodel ) { if( conv->ii ) imagemodel_refresh_ink( imagemodel, conv->ii ); iobject_changed( IOBJECT( imagemodel ) ); } static void imagemodel_conv_imageinfo_changed_cb( Conversion *conv, Imagemodel *imagemodel ) { imagemodel_imageinfo_changed( imagemodel ); } static void imagemodel_init( Imagemodel *imagemodel ) { imagemodel->iimage = NULL; imagemodel->iimage_changed_sid = 0; imagemodel->iimage_destroy_sid = 0; imagemodel->conv = conversion_new( NULL ); g_object_ref( G_OBJECT( imagemodel->conv ) ); iobject_sink( IOBJECT( imagemodel->conv ) ); imagemodel->conv_changed_sid = g_signal_connect( G_OBJECT( imagemodel->conv ), "changed", G_CALLBACK( imagemodel_conv_changed_cb ), imagemodel ); imagemodel->conv_imageinfo_changed_sid = g_signal_connect( G_OBJECT( imagemodel->conv ), "imageinfo_changed", G_CALLBACK( imagemodel_conv_imageinfo_changed_cb ), imagemodel ); imagemodel->conv->priority = 1; imagemodel->show_rulers = DISPLAY_RULERS; imagemodel->rulers_mm = FALSE; imagemodel->rulers_offset = FALSE; imagemodel->show_status = DISPLAY_STATUS; imagemodel->show_paintbox = FALSE; imagemodel->nib_radius = 0; imagemodel->nib = NULL; imagemodel->ink = NULL; imagemodel->font_name = im_strdup( NULL, PAINTBOX_FONT ); imagemodel->text = NULL; imagemodel->text_mask = NULL; imagemodel->show_convert = DISPLAY_CONVERSION; imagemodel->scale = 1.0; imagemodel->offset = 0.0; imagemodel->falsecolour = FALSE; imagemodel->type = TRUE; } GType imagemodel_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ImagemodelClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) imagemodel_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Imagemodel ), 32, /* n_preallocs */ (GInstanceInitFunc) imagemodel_init, }; type = g_type_register_static( TYPE_IOBJECT, "Imagemodel", &info, 0 ); } return( type ); } static void imagemodel_iimage_destroy_cb( iImage *iimage, Imagemodel *imagemodel ) { imagemodel->iimage = NULL; imagemodel->iimage_destroy_sid = 0; imagemodel->iimage_changed_sid = 0; } static void imagemodel_iimage_changed_cb( iImage *iimage, Imagemodel *imagemodel ) { conversion_set_image( imagemodel->conv, iimage->value.ii ); } static void imagemodel_link( Imagemodel *imagemodel, iImage *iimage ) { Row *row = HEAPMODEL( iimage )->row; imagemodel->iimage = iimage; imagemodel->iimage_destroy_sid = g_signal_connect( G_OBJECT( iimage ), "destroy", G_CALLBACK( imagemodel_iimage_destroy_cb ), imagemodel ); imagemodel->iimage_changed_sid = g_signal_connect( G_OBJECT( iimage ), "changed", G_CALLBACK( imagemodel_iimage_changed_cb ), imagemodel ); imagemodel->scale = row->ws->scale; imagemodel->offset = row->ws->offset; /* Install image. */ conversion_set_image( imagemodel->conv, iimage->value.ii ); /* Set name ... handy for debugging. */ iobject_set( IOBJECT( imagemodel ), row_name( HEAPMODEL( iimage )->row ), NULL ); } Imagemodel * imagemodel_new( iImage *iimage ) { Imagemodel *imagemodel; imagemodel = g_object_new( TYPE_IMAGEMODEL, NULL ); if( iimage ) imagemodel_link( imagemodel, iimage ); #ifdef DEBUG printf( "imagemodel_new: " ); iobject_print( IOBJECT( imagemodel ) ); #endif /*DEBUG*/ return( imagemodel ); } /* Callback for check_paintable() in imagemodel_set_state. */ static void imagemodel_set_paintbox_cb( void *client, iWindowResult result ) { Imagemodel *imagemodel = IMAGEMODEL( client ); #ifdef DEBUG printf( "imagemodel_set_paintbox_cb: pend_state = %s\n", imagemodel_state( imagemodel->pend_state ) ); #endif /*DEBUG*/ if( result == IWINDOW_YES ) { imagemodel_set_paintbox( imagemodel, TRUE ); if( imagemodel->state != imagemodel->pend_state ) { imagemodel->state = imagemodel->pend_state; iobject_changed( IOBJECT( imagemodel ) ); } } } /* Set the viewer state. We can't always do this immediately, we may need to * ask the user if the change is OK. Return TRUE if we were able to make the * change now. */ gboolean imagemodel_set_state( Imagemodel *imagemodel, ImagemodelState state, GtkWidget *parent ) { gboolean changed = FALSE; #ifdef DEBUG printf( "imagemodel_set_state: %s\n", imagemodel_state( state ) ); #endif /*DEBUG*/ if( state != imagemodel->state && imagemodel_state_paint( state ) ) { /* Check and warn on this image first. */ imagemodel->pend_state = state; imageinfo_check_paintable( imagemodel->conv->ii, parent, imagemodel_set_paintbox_cb, imagemodel ); /* We may not have set the state yet ... signal "changed" * to flick whatever asked for this change (eg. View * menu) back to the old state. */ changed = TRUE; } else if( state != imagemodel->state ) { imagemodel->state = state; changed = TRUE; } if( changed ) iobject_changed( IOBJECT( imagemodel ) ); return( imagemodel->state == state ); } void imagemodel_set_rulers( Imagemodel *imagemodel, gboolean show_rulers ) { if( imagemodel->show_rulers != show_rulers ) { imagemodel->show_rulers = show_rulers; iobject_changed( IOBJECT( imagemodel ) ); } } void imagemodel_set_paintbox( Imagemodel *imagemodel, gboolean show_paintbox ) { if( imagemodel->show_paintbox != show_paintbox ) { #ifdef DEBUG printf( "imagemodel_set_paintbox: " ); iobject_print( IOBJECT( imagemodel ) ); #endif /*DEBUG*/ imagemodel->show_paintbox = show_paintbox; /* If the paint bar is off, we want to not be in a paint mode. */ if( !imagemodel->show_paintbox && imagemodel_state_paint( imagemodel->state ) ) imagemodel_set_state( imagemodel, IMAGEMODEL_SELECT, NULL ); iobject_changed( IOBJECT( imagemodel ) ); } } void imagemodel_set_status( Imagemodel *imagemodel, gboolean show_status ) { if( imagemodel->show_status != show_status ) { imagemodel->show_status = show_status; iobject_changed( IOBJECT( imagemodel ) ); } } void imagemodel_set_convert( Imagemodel *imagemodel, gboolean show_convert ) { if( imagemodel->show_convert != show_convert ) { imagemodel->show_convert = show_convert; iobject_changed( IOBJECT( imagemodel ) ); } } /* Update the text_mask. imagemodel->text is kept up to date with what's in the * paintbox text widget, call this just before a paint action to render the * mask. */ gboolean imagemodel_refresh_text( Imagemodel *imagemodel ) { const char *text = imagemodel->text; if( !text || strspn( text, WHITESPACE ) == strlen( text ) ) { error_top( _( "No text specified." ) ); error_sub( _( "Enter some text to paint in the entry widget at " "the top of the window." ) ); return( FALSE ); } MANAGED_UNREF( imagemodel->text_mask ); if( !(imagemodel->text_mask = imageinfo_new_temp( main_imageinfogroup, reduce_context->heap, NULL, "t" )) ) return( FALSE ); MANAGED_REF( imagemodel->text_mask ); if( !imageinfo_paint_text( imagemodel->text_mask, imagemodel->font_name, imagemodel->text, &imagemodel->text_area ) ) return( FALSE ); return( TRUE ); } gboolean imagemodel_refresh_nib( Imagemodel *imagemodel ) { MANAGED_UNREF( imagemodel->nib ); if( !(imagemodel->nib = imageinfo_new_temp( main_imageinfogroup, reduce_context->heap, NULL, "t" )) ) return( FALSE ); MANAGED_REF( imagemodel->nib ); if( !imageinfo_paint_nib( imagemodel->nib, imagemodel->nib_radius ) ) return( FALSE ); return( TRUE ); } /* After a paint action: mark all subsequent things dirty, recalc if prefs say * so. */ void imagemodel_paint_recalc( Imagemodel *imagemodel ) { Classmodel *classmodel = CLASSMODEL( imagemodel->iimage ); Row *row = HEAPMODEL( classmodel )->row; #ifdef DEBUG printf( "imagemodel_paint_recalc: " ); iobject_print( IOBJECT( imagemodel ) ); #endif /*DEBUG*/ expr_dirty_intrans( row->expr, link_serial_new() ); if( PAINTBOX_RECOMP ) symbol_recalculate_all(); } nip2-8.7.1/src/row.h0000644000175000017500000000704413351443023011072 00000000000000/* a row in a workspace ... part of a subcolumn */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_ROW (row_get_type()) #define ROW( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_ROW, Row )) #define ROW_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_ROW, RowClass)) #define IS_ROW( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_ROW )) #define IS_ROW_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_ROW )) #define ROW_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_ROW, RowClass )) /* For when we're flashing the showstate up. */ typedef enum { ROW_SHOW_NONE, ROW_SHOW_PARENT, ROW_SHOW_CHILD } RowShowState; struct _Row { Heapmodel parent_class; /* Our context. */ Subcolumn *scol; /* Enclosing subcolumn */ Rhs *child_rhs; /* Child RHS */ Column *top_col; /* Enclosing top level column */ Workspace *ws; /* Enclosing workspace */ Row *top_row; /* Enclosing root row */ Symbol *sym; /* Symbol we represent */ Expr *expr; /* The expr we edit */ gboolean err; /* Set if this row is on the error list */ gboolean selected; /* Selected or not */ gboolean is_class; /* Display spin buttons */ gboolean popup; /* Set to pop up view on 1st display */ gboolean to_save; /* Should be saved (part of only-save-modded) */ GSList *parents; /* rows which depend on us */ GSList *children; /* rows we depend on */ gboolean dirty; /* If we're marked for recomp */ GSList *recomp; /* If root of class display, subs to recomp */ GSList *recomp_save; /* Previous recomp list */ gboolean depend; /* For spotting dependency loops */ RowShowState show; /* For showing parent/child stuff */ }; typedef struct _RowClass { HeapmodelClass parent_class; /* My methods. */ } RowClass; const char *row_name( Row *row ); void row_qualified_name_relative( Symbol *context, Row *row, VipsBuf *buf ); void row_qualified_name( Row *row, VipsBuf *buf ); void *row_name_print( Row *row ); void row_error_set( Row *row ); void row_error_clear( Row *row ); Workspace *row_get_workspace( Row *row ); GType row_get_type( void ); void row_link_symbol( Row *row, Symbol *sym, PElement *root ); Row *row_new( Subcolumn *scol, Symbol *sym, PElement *root ); void *row_dirty( Row *row, gboolean clear_dirty ); void *row_dirty_intrans( Row *row, gboolean clear_dirty ); void row_recomp( Row *row ); void *row_is_selected( Row *row ); void *row_deselect( Row *row ); void *row_select_ensure( Row *row ); void *row_select( Row *row ); void *row_select_extend( Row *row ); void *row_select_toggle( Row *row ); void row_select_modifier( Row *row, guint state ); void row_show_dependents( Row *row ); void row_hide_dependents( Row *row ); void row_set_status( Row *row ); Row *row_parse_name( Symbol *context, const char *path ); nip2-8.7.1/src/itextview.c0000644000175000017500000001542613351443023012311 00000000000000/* a view of a text thingy */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; static void itextview_refresh( vObject *vobject ) { iTextview *itextview = ITEXTVIEW( vobject ); iText *itext = ITEXT( VOBJECT( itextview )->iobject ); Row *row = HEAPMODEL( itext )->row; const char *display; #ifdef DEBUG printf( "itextview_refresh: " ); row_name_print( row ); printf( " (%p)\n", vobject ); #endif /*DEBUG*/ /* Only reset edit mode if the text hasn't been changed. We * don't want the user to lose work. */ if( !itextview->formula->changed ) switch( row->ws->mode ) { case WORKSPACE_MODE_REGULAR: formula_set_edit( itextview->formula, FALSE ); formula_set_sensitive( itextview->formula, TRUE ); break; case WORKSPACE_MODE_FORMULA: formula_set_edit( itextview->formula, TRUE ); formula_set_sensitive( itextview->formula, TRUE ); break; case WORKSPACE_MODE_NOEDIT: formula_set_edit( itextview->formula, FALSE ); formula_set_sensitive( itextview->formula, FALSE ); break; default: g_assert_not_reached(); } /* We display the formula if this is a class ... we assume the members * and/or the graphic will represent the value. */ if( row->is_class ) display = itext->formula; else display = vips_buf_all( &itext->value ); if( itextview->formula && itext->value.base ) formula_set_value_expr( itextview->formula, display, itext->formula ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void itextview_link( View *view, Model *model, View *parent ) { iTextview *itextview = ITEXTVIEW( view ); iText *itext = ITEXT( model ); Row *row = HEAPMODEL( itext )->row; #ifdef DEBUG printf( "itextview_link: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ VIEW_CLASS( parent_class )->link( view, model, parent ); /* Edit mode defaults to edit mode for workspace. */ formula_set_edit( itextview->formula, row->ws->mode == WORKSPACE_MODE_FORMULA ); } /* Reset edit mode ... go back to whatever is set for this ws. */ static void itextview_reset( View *view ) { iTextview *itextview = ITEXTVIEW( view ); iText *itext = ITEXT( VOBJECT( itextview )->iobject ); Row *row = HEAPMODEL( itext )->row; #ifdef DEBUG printf( "itextview_reset: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ formula_set_edit( ITEXTVIEW( view )->formula, row->ws->mode == WORKSPACE_MODE_FORMULA ); VIEW_CLASS( parent_class )->reset( view ); } /* Re-read the text in a tally entry. */ static void * itextview_scan( View *view ) { iTextview *itextview = ITEXTVIEW( view ); iText *itext = ITEXT( VOBJECT( itextview )->iobject ); #ifdef DEBUG Row *row = HEAPMODEL( itext )->row; printf( "itextview_scan: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ if( formula_scan( itextview->formula ) && itext_set_formula( itext, itextview->formula->expr ) ) itext_set_edited( itext, TRUE ); return( VIEW_CLASS( parent_class )->scan( view ) ); } static void itextview_class_init( iTextviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = itextview_refresh; view_class->link = itextview_link; view_class->reset = itextview_reset; view_class->scan = itextview_scan; } void itextview_edit_cb( Formula *formula, iTextview *itextview ) { view_resettable_register( VIEW( itextview ) ); } void itextview_activate_cb( Formula *formula, iTextview *itextview ) { iText *itext = ITEXT( VOBJECT( itextview )->iobject ); Row *row = HEAPMODEL( itext )->row; /* Reset edits on this row and all children. Our (potentially) next * text will invlidate all of them. */ (void) icontainer_map_all( ICONTAINER( row ), (icontainer_map_fn) heapmodel_clear_edited, NULL ); /* Make sure we scan this text, even if it's not been edited. */ view_scannable_register( VIEW( itextview ) ); workspace_set_modified( row->ws, TRUE ); symbol_recalculate_all(); } static void itextview_enter_cb( Formula *formula, iTextview *itextview ) { iText *itext = ITEXT( VOBJECT( itextview )->iobject ); Row *row = HEAPMODEL( itext )->row; row_set_status( row ); row_show_dependents( row ); } static void itextview_leave_cb( Formula *formula, iTextview *itextview ) { iText *itext = ITEXT( VOBJECT( itextview )->iobject ); Row *row = HEAPMODEL( itext )->row; row_hide_dependents( row ); } static void itextview_init( iTextview *itextview ) { itextview->formula = formula_new(); gtk_signal_connect( GTK_OBJECT( itextview->formula ), "edit", GTK_SIGNAL_FUNC( itextview_edit_cb ), itextview ); gtk_signal_connect_object( GTK_OBJECT( itextview->formula ), "changed", GTK_SIGNAL_FUNC( view_changed_cb ), itextview ); gtk_signal_connect( GTK_OBJECT( itextview->formula ), "activate", GTK_SIGNAL_FUNC( itextview_activate_cb ), itextview ); gtk_signal_connect( GTK_OBJECT( itextview->formula ), "enter", GTK_SIGNAL_FUNC( itextview_enter_cb ), itextview ); gtk_signal_connect( GTK_OBJECT( itextview->formula ), "leave", GTK_SIGNAL_FUNC( itextview_leave_cb ), itextview ); gtk_box_pack_start( GTK_BOX( itextview ), GTK_WIDGET( itextview->formula ), TRUE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( itextview->formula ) ); } GtkType itextview_get_type( void ) { static GtkType itextview_type = 0; if( !itextview_type ) { static const GtkTypeInfo itextview_info = { "iTextview", sizeof( iTextview ), sizeof( iTextviewClass ), (GtkClassInitFunc) itextview_class_init, (GtkObjectInitFunc) itextview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; itextview_type = gtk_type_unique( TYPE_VIEW, &itextview_info ); } return( itextview_type ); } View * itextview_new( void ) { iTextview *itextview = gtk_type_new( TYPE_ITEXTVIEW ); return( VIEW( itextview ) ); } nip2-8.7.1/src/error.h0000644000175000017500000000300213351443023011402 00000000000000/* Decls for ierror.c ... show all ierrors */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IERROR (ierror_get_type()) #define IERROR( obj ) (GTK_CHECK_CAST( (obj), TYPE_IERROR, iError )) #define IERROR_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_IERROR, iErrorClass )) #define IS_IERROR( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IERROR )) #define IS_IERROR_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_IERROR )) struct _iError { Log parent_class; Toolkitgroup *kitg; /* Where we search for link ierrors */ }; typedef struct _iErrorClass { LogClass parent_class; /* My methods. */ } iErrorClass; GtkType ierror_get_type( void ); iError *ierror_new( Toolkitgroup *kitg ); nip2-8.7.1/src/paintboxview.c0000644000175000017500000003360113351443023012773 00000000000000/* widgets for the paintbox bar */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GtkFrameClass *parent_class = NULL; /* The popup menu. */ static GtkWidget *paintboxview_menu = NULL; static void paintboxview_destroy( GtkObject *object ) { Paintboxview *pbv; g_return_if_fail( object != NULL ); g_return_if_fail( IS_PAINTBOXVIEW( object ) ); pbv = PAINTBOXVIEW( object ); #ifdef DEBUG printf( "paintboxview_destroy: %p\n", pbv ); #endif /*DEBUG*/ /* My instance destroy stuff. */ FREESID( pbv->ii_undo_changed_sid, pbv->ii ); FREESID( pbv->ii_destroy_sid, pbv->ii ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void paintboxview_realize( GtkWidget *widget ) { Paintboxview *pbv = PAINTBOXVIEW( widget ); iWindow *iwnd = IWINDOW( iwindow_get_root( widget ) ); guint key; GdkModifierType mods; gtk_accelerator_parse( "z", &key, &mods ); gtk_widget_add_accelerator( GTK_WIDGET( pbv->undo ), "clicked", iwnd->accel_group, key, mods, 0 ); gtk_accelerator_parse( "z", &key, &mods ); gtk_widget_add_accelerator( GTK_WIDGET( pbv->redo ), "clicked", iwnd->accel_group, key, mods, 0 ); GTK_WIDGET_CLASS( parent_class )->realize( widget ); } /* Hide this paintboxview. */ static void paintboxview_hide_cb( GtkWidget *menu, GtkWidget *host, Paintboxview *pbv ) { imagemodel_set_paintbox( pbv->imagemodel, FALSE ); } static void paintboxview_class_init( PaintboxviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; GtkWidget *pane; parent_class = g_type_class_peek_parent( class ); object_class->destroy = paintboxview_destroy; widget_class->realize = paintboxview_realize; /* Create signals. */ /* Init methods. */ pane = paintboxview_menu = popup_build( _( "Paintbox bar menu" ) ); popup_add_but( pane, GTK_STOCK_CLOSE, POPUP_FUNC( paintboxview_hide_cb ) ); } /* "toggled" on a tool select button */ static void paintboxview_tool_toggled_cb( GtkWidget *wid, Paintboxview *pbv ) { if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( wid ) ) ) { Imagemodel *imagemodel = pbv->imagemodel; int i; for( i = 0; i < IMAGEMODEL_LAST; i++ ) if( wid == pbv->tool[i] ) break; if( i != (int) IMAGEMODEL_LAST ) imagemodel_set_state( imagemodel, i, wid ); } } /* New nib selected. */ static void paintboxview_scale_change_cb( Tslider *tslider, Paintboxview *pbv ) { Imagemodel *imagemodel = pbv->imagemodel; if( imagemodel->nib_radius != tslider->value ) { imagemodel->nib_radius = tslider->value; iobject_changed( IOBJECT( imagemodel ) ); } } static void paintboxview_double_cb( GtkWidget *wid, GdkEvent *event, Paintboxview *pbv ) { imageinfo_colour_edit( wid, IMAGEDISPLAY( pbv->ink )->conv->ii ); } static void paintboxview_font_changed_cb( GtkWidget *widget, Paintboxview *pbv ) { Fontbutton *fontbutton = FONTBUTTON( widget ); Imagemodel *imagemodel = pbv->imagemodel; const char *font_name; font_name = fontbutton_get_font_name( fontbutton ); if( strcmp( font_name, imagemodel->font_name ) != 0 ) { IM_SETSTR( imagemodel->font_name, font_name ); iobject_changed( IOBJECT( imagemodel ) ); } } static void paintboxview_undo_cb( GtkWidget *widget, Paintboxview *pbv ) { if( !imageinfo_undo( pbv->ii ) ) iwindow_alert( widget, GTK_MESSAGE_ERROR ); /* Ask everyone to drop cache, the image has changed. */ im_invalidate( imageinfo_get( FALSE, pbv->ii ) ); imagemodel_paint_recalc( pbv->imagemodel ); } static void paintboxview_redo_cb( GtkWidget *widget, Paintboxview *pbv ) { if( !imageinfo_redo( pbv->ii ) ) iwindow_alert( widget, GTK_MESSAGE_ERROR ); /* Ask everyone to drop cache, the image has changed. */ im_invalidate( imageinfo_get( FALSE, pbv->ii ) ); imagemodel_paint_recalc( pbv->imagemodel ); } static void paintboxview_clear_cb2( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Paintboxview *pbv = PAINTBOXVIEW( client ); imageinfo_undo_clear( pbv->ii ); nfn( sys, IWINDOW_YES ); } static void paintboxview_clear_cb( GtkWidget *widget, Paintboxview *pbv ) { box_yesno( GTK_WIDGET( widget ), paintboxview_clear_cb2, iwindow_true_cb, pbv, iwindow_notify_null, NULL, GTK_STOCK_CLEAR, _( "Clear undo history?" ), _( "Are you sure you want to clear all undo and redo? " "This will free up memory, but you will no longer be " "able to undo or redo any of the painting you have " "done so far." ) ); } static void paintboxview_text_changed_cb( GtkWidget *widget, Paintboxview *pbv ) { const char *text = gtk_entry_get_text( GTK_ENTRY( pbv->text ) ); IM_SETSTR( pbv->imagemodel->text, text ); } static void paintboxview_init( Paintboxview *pbv ) { /* Order important! Keep in sync with ImagemodelState. */ static const char *tool_names[IMAGEMODEL_LAST] = { STOCK_SELECT, /* IMAGEMODEL_SELECT */ STOCK_MOVE, /* IMAGEMODEL_PAN */ GTK_STOCK_ZOOM_IN, /* IMAGEMODEL_MAGIN */ GTK_STOCK_ZOOM_OUT, /* IMAGEMODEL_MAGOUT*/ STOCK_DROPPER, /* IMAGEMODEL_DROPPER */ STOCK_PAINTBRUSH, /* IMAGEMODEL_PEN */ STOCK_LINE, /* IMAGEMODEL_LINE */ STOCK_RECT, /* IMAGEMODEL_RECT */ STOCK_FLOOD, /* IMAGEMODEL_FLOOD */ STOCK_FLOOD_BLOB, /* IMAGEMODEL_BLOB */ STOCK_TEXT, /* IMAGEMODEL_TEXT */ STOCK_SMUDGE /* IMAGEMODEL_SMUDGE */ }; static const char *tool_tooltips[] = { N_( "Manipulate regions" ), /* IMAGEMODEL_SELECT */ N_( "Pan window" ), /* IMAGEMODEL_PAN */ N_( "Zoom in on mouse" ), /* IMAGEMODEL_MAGIN */ N_( "Zoom out" ), /* IMAGEMODEL_MAGOUT*/ N_( "Read pixel into inkwell" ), /* IMAGEMODEL_DROPPER */ N_( "Freehand draw " ), /* IMAGEMODEL_PEN */ N_( "Draw straight lines" ), /* IMAGEMODEL_LINE */ N_( "Fill rectangles" ), /* IMAGEMODEL_RECT */ N_( "Flood while pixel not equal to ink" ), /* IMAGEMODEL_FLOOD */ N_( "Flood while pixel equal to click" ), /* IMAGEMODEL_BLOB */ N_( "Draw text" ), /* IMAGEMODEL_TEXT */ N_( "Smudge" ) /* IMAGEMODEL_SMUDGE */ }; GtkWidget *eb; GtkWidget *hb, *hb2; GtkWidget *image; int i; pbv->imagemodel = NULL; pbv->ii_undo_changed_sid = 0; pbv->ii_destroy_sid = 0; pbv->ii = NULL; gtk_frame_set_shadow_type( GTK_FRAME( pbv ), GTK_SHADOW_OUT ); eb = gtk_event_box_new(); gtk_container_add( GTK_CONTAINER( pbv ), eb ); popup_attach( eb, paintboxview_menu, pbv ); hb = gtk_hbox_new( FALSE, 4 ); gtk_container_set_border_width( GTK_CONTAINER( hb ), 1 ); gtk_container_add( GTK_CONTAINER( eb ), hb ); /* The first 4 tools are harmless (region, move, zoom in, zoom out) * and not linked to the paint actions .. so have them first on their * own. */ hb2 = gtk_hbox_new( FALSE, 0 ); for( i = 0; i < 4; i++ ) { pbv->tool[i] = gtk_toggle_button_new(); gtk_signal_connect( GTK_OBJECT( pbv->tool[i] ), "toggled", GTK_SIGNAL_FUNC( paintboxview_tool_toggled_cb ), pbv ); image = gtk_image_new_from_stock( tool_names[i], GTK_ICON_SIZE_BUTTON ); set_tooltip( pbv->tool[i], "%s", tool_tooltips[i] ); gtk_container_add( GTK_CONTAINER( pbv->tool[i] ), image ); gtk_box_pack_start( GTK_BOX( hb2 ), pbv->tool[i], FALSE, FALSE, 0 ); } gtk_box_pack_start( GTK_BOX( hb ), hb2, FALSE, FALSE, 0 ); hb2 = gtk_hbox_new( FALSE, 0 ); pbv->undo = gtk_button_new(); image = gtk_image_new_from_stock( GTK_STOCK_UNDO, GTK_ICON_SIZE_BUTTON ); gtk_container_add( GTK_CONTAINER( pbv->undo ), image ); gtk_signal_connect( GTK_OBJECT( pbv->undo ), "clicked", GTK_SIGNAL_FUNC( paintboxview_undo_cb ), pbv ); set_tooltip( pbv->undo, _( "Undo last paint action" ) ); gtk_box_pack_start( GTK_BOX( hb2 ), pbv->undo, FALSE, FALSE, 0 ); pbv->redo = gtk_button_new(); image = gtk_image_new_from_stock( GTK_STOCK_REDO, GTK_ICON_SIZE_BUTTON ); gtk_container_add( GTK_CONTAINER( pbv->redo ), image ); gtk_signal_connect( GTK_OBJECT( pbv->redo ), "clicked", GTK_SIGNAL_FUNC( paintboxview_redo_cb ), pbv ); set_tooltip( pbv->redo, _( "Redo last paint action" ) ); gtk_box_pack_start( GTK_BOX( hb2 ), pbv->redo, FALSE, FALSE, 0 ); pbv->clear = gtk_button_new(); image = gtk_image_new_from_stock( GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON ); gtk_container_add( GTK_CONTAINER( pbv->clear ), image ); gtk_signal_connect( GTK_OBJECT( pbv->clear ), "clicked", GTK_SIGNAL_FUNC( paintboxview_clear_cb ), pbv ); set_tooltip( pbv->clear, _( "Clear all undo and redo buffers" ) ); gtk_box_pack_start( GTK_BOX( hb2 ), pbv->clear, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( hb ), hb2, FALSE, FALSE, 0 ); hb2 = gtk_hbox_new( FALSE, 0 ); for( i = 4; i < IM_NUMBER( tool_names ); i++ ) { pbv->tool[i] = gtk_toggle_button_new(); gtk_signal_connect( GTK_OBJECT( pbv->tool[i] ), "toggled", GTK_SIGNAL_FUNC( paintboxview_tool_toggled_cb ), pbv ); image = gtk_image_new_from_stock( tool_names[i], GTK_ICON_SIZE_BUTTON ); set_tooltip( pbv->tool[i], "%s", tool_tooltips[i] ); gtk_container_add( GTK_CONTAINER( pbv->tool[i] ), image ); gtk_box_pack_start( GTK_BOX( hb2 ), pbv->tool[i], FALSE, FALSE, 0 ); } gtk_box_pack_start( GTK_BOX( hb ), hb2, FALSE, FALSE, 0 ); pbv->nib = tslider_new(); pbv->nib->from = 0; pbv->nib->to = 64; pbv->nib->value = 0; pbv->nib->svalue = 1; pbv->nib->digits = 2; tslider_changed( pbv->nib ); gtk_box_pack_start( GTK_BOX( hb ), GTK_WIDGET( pbv->nib ), FALSE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT( pbv->nib ), "changed", GTK_SIGNAL_FUNC( paintboxview_scale_change_cb ), pbv ); tslider_set_ignore_scroll( pbv->nib, FALSE ); pbv->ink = (GtkWidget *) colourdisplay_new( NULL ); doubleclick_add( GTK_WIDGET( pbv->ink ), FALSE, NULL, NULL, DOUBLECLICK_FUNC( paintboxview_double_cb ), pbv ); gtk_widget_set_size_request( GTK_WIDGET( pbv->ink ), 20, 10 ); gtk_box_pack_start( GTK_BOX( hb ), pbv->ink, FALSE, TRUE, 0 ); pbv->font = GTK_WIDGET( fontbutton_new() ); gtk_box_pack_start( GTK_BOX( hb ), pbv->font, FALSE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT( pbv->font ), "changed", GTK_SIGNAL_FUNC( paintboxview_font_changed_cb ), pbv ); pbv->text = gtk_entry_new(); gtk_box_pack_start( GTK_BOX( hb ), pbv->text, TRUE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT( pbv->text ), "changed", GTK_SIGNAL_FUNC( paintboxview_text_changed_cb ), pbv ); set_tooltip( pbv->text, _( "Enter text for text tool" ) ); gtk_widget_show_all( eb ); } GtkType paintboxview_get_type( void ) { static GtkType paintboxview_type = 0; if( !paintboxview_type ) { static const GtkTypeInfo sinfo = { "Paintboxview", sizeof( Paintboxview ), sizeof( PaintboxviewClass ), (GtkClassInitFunc) paintboxview_class_init, (GtkObjectInitFunc) paintboxview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; paintboxview_type = gtk_type_unique( GTK_TYPE_FRAME, &sinfo ); } return( paintboxview_type ); } static void paintboxview_ii_undo_changed_cb( Imageinfo *imageinfo, Paintboxview *pbv ) { gtk_widget_set_sensitive( GTK_WIDGET( pbv->undo ), imageinfo->undo != NULL ); gtk_widget_set_sensitive( GTK_WIDGET( pbv->redo ), imageinfo->redo != NULL ); gtk_widget_set_sensitive( GTK_WIDGET( pbv->clear ), imageinfo->undo != NULL || imageinfo->redo != NULL ); } static void paintboxview_ii_destroy_cb( Imageinfo *imageinfo, Paintboxview *pbv ) { pbv->ii_destroy_sid = 0; pbv->ii_undo_changed_sid = 0; pbv->ii = NULL; } /* Our model has changed ... update. */ static void paintboxview_changed_cb( Imagemodel *imagemodel, Paintboxview *pbv ) { Conversion *conv = imagemodel->conv; Colourdisplay *ink = COLOURDISPLAY( pbv->ink ); int i; #ifdef DEBUG printf( "paintboxview_conv_changed_cb: %p\n", conv ); #endif /*DEBUG*/ /* Has the ii changed? Link to it for undo/redo changes. */ if( pbv->ii != conv->ii ) { FREESID( pbv->ii_undo_changed_sid, pbv->ii ); FREESID( pbv->ii_destroy_sid, pbv->ii ); pbv->ii = conv->ii; if( conv->ii ) { pbv->ii_undo_changed_sid = g_signal_connect( G_OBJECT( conv->ii ), "undo_changed", G_CALLBACK( paintboxview_ii_undo_changed_cb ), pbv ); pbv->ii_destroy_sid = g_signal_connect( G_OBJECT( conv->ii ), "destroy", G_CALLBACK( paintboxview_ii_destroy_cb ), pbv ); paintboxview_ii_undo_changed_cb( conv->ii, pbv ); } /* Update ink display for the new image. */ conversion_set_image( IMAGEDISPLAY( ink )->conv, imagemodel->ink ); } widget_visible( GTK_WIDGET( pbv ), imagemodel->show_paintbox ); if( !imagemodel->show_paintbox ) return; for( i = 0; i < IMAGEMODEL_LAST; i++ ) gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( pbv->tool[i] ), i == (int) imagemodel->state ); fontbutton_set_font_name( FONTBUTTON( pbv->font ), pbv->imagemodel->font_name ); } static void paintboxview_link( Paintboxview *pbv, Imagemodel *imagemodel ) { #ifdef DEBUG printf( "paintboxview_link: %p\n", pbv ); #endif /*DEBUG*/ pbv->imagemodel = imagemodel; g_signal_connect( G_OBJECT( imagemodel ), "changed", G_CALLBACK( paintboxview_changed_cb ), pbv ); } Paintboxview * paintboxview_new( Imagemodel *imagemodel ) { Paintboxview *pbv = gtk_type_new( TYPE_PAINTBOXVIEW ); paintboxview_link( pbv, imagemodel ); return( pbv ); } nip2-8.7.1/src/vipsobject.h0000644000175000017500000000213613351443023012430 00000000000000/* Links to VipsObject. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ void vo_object_new( Reduce *rc, const char *name, PElement *required, PElement *optional, PElement *out ); void vo_call( Reduce *rc, const char *name, PElement *required, PElement *optional, PElement *out ); nip2-8.7.1/src/real.c0000644000175000017500000000335113351443023011176 00000000000000/* an input real ... put/get methods */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ValueClass *parent_class = NULL; static void real_class_init( RealClass *class ) { parent_class = g_type_class_peek_parent( class ); /* Create signals. */ model_register_loadable( MODEL_CLASS( class ) ); } static void real_init( Real *real ) { iobject_set( IOBJECT( real ), CLASS_REAL, NULL ); } GType real_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( RealClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) real_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Real ), 32, /* n_preallocs */ (GInstanceInitFunc) real_init, }; type = g_type_register_static( TYPE_VALUE, "Real", &info, 0 ); } return( type ); } nip2-8.7.1/src/pathnameview.h0000644000175000017500000000314213351443023012746 00000000000000/* a pathname view in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PATHNAMEVIEW (pathnameview_get_type()) #define PATHNAMEVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_PATHNAMEVIEW, Pathnameview )) #define PATHNAMEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PATHNAMEVIEW, PathnameviewClass )) #define IS_PATHNAMEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PATHNAMEVIEW )) #define IS_PATHNAMEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PATHNAMEVIEW )) typedef struct _Pathnameview { Graphicview parent_object; GtkWidget *label; GtkWidget *button; } Pathnameview; typedef struct _PathnameviewClass { GraphicviewClass parent_class; /* My methods. */ } PathnameviewClass; GtkType pathnameview_get_type( void ); View *pathnameview_new( void ); nip2-8.7.1/src/workspaceview.c0000644000175000017500000010035613351443023013147 00000000000000/* a workspaceview button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Define to trace button press events. #define EVENT */ #include "ip.h" static ViewClass *parent_class = NULL; /* Params for "Align Columns" function. */ static const int workspaceview_layout_snap_threshold = 30; static const int workspaceview_layout_hspacing = 10; static const int workspaceview_layout_vspacing = 10; static const int workspaceview_layout_left = WORKSPACEVIEW_MARGIN_LEFT; static const int workspaceview_layout_top = WORKSPACEVIEW_MARGIN_TOP; static void workspaceview_scroll_to( Workspaceview *wview, int x, int y ) { GtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW( wview->window ) ); GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW( wview->window ) ); int nx, ny; nx = IM_CLIP( 0, x, wview->width - wview->vp.width ); ny = IM_CLIP( 0, y, wview->height - wview->vp.height ); adjustments_set_value( hadj, vadj, nx, ny ); } /* Scroll by an amount horizontally and vertically. */ static void workspaceview_displace( Workspaceview *wview, int u, int v ) { workspaceview_scroll_to( wview, wview->vp.left + u, wview->vp.top + v ); } /* Scroll to make an xywh area visible. If the area is larger than the * viewport, position the view at the bottom left if the xywh area ... * this is usually right for workspaces. */ void workspaceview_scroll( Workspaceview *wview, int x, int y, int w, int h ) { GtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW( wview->window ) ); GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW( wview->window ) ); Rect *vp = &wview->vp; int nx, ny; nx = hadj->value; if( x + w > IM_RECT_RIGHT( vp ) ) nx = IM_MAX( 0, (x + w) - vp->width ); if( x < nx ) nx = x; ny = vadj->value; if( y + h > IM_RECT_BOTTOM( vp ) ) ny = IM_MAX( 0, (y + h) - vp->height ); if( y < ny ) ny = y; #ifdef DEBUG printf( "workspaceview_scroll: x=%d, y=%d, w=%d, h=%d, " "nx = %d, ny = %d\n", x, y, w, h, nx, ny ); #endif /*DEBUG*/ adjustments_set_value( hadj, vadj, nx, ny ); } /* Update our geometry from the fixed widget. */ static void workspaceview_scroll_update( Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); GtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW( wview->window ) ); GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW( wview->window ) ); wview->vp.left = hadj->value; wview->vp.top = vadj->value; wview->vp.width = hadj->page_size; wview->vp.height = vadj->page_size; wview->width = hadj->upper; wview->height = vadj->upper; /* Update vp hint in model too. */ ws->vp = wview->vp; #ifdef DEBUG printf( "workspaceview_scroll_update: %s\n", IOBJECT( ws )->name ); printf( " wview->vp: l=%d, t=%d, w=%d, h=%d; fixed w=%d; h=%d\n", wview->vp.left, wview->vp.top, wview->vp.width, wview->vp.height, wview->width, wview->height ); #endif /*DEBUG*/ } static void workspaceview_watch_changed_cb( Watchgroup *watchgroup, Watch *watch, Workspaceview *wview ) { /* Names of prefs we watch. These are really rowview preferences, but * we follow them here to prevent every rowview having to have it's * own connection. */ static char *watch_names[] = { "CALC_DISPLAY_LED" }; int i; for( i = 0; i < IM_NUMBER( watch_names ); i++ ) if( strcmp( IOBJECT( watch )->name, watch_names[i] ) == 0 ) { view_map_all( VIEW( wview ), (view_map_fn) vobject_refresh_queue, NULL ); break; } } /* Scroll events ... handle mousewheel shortcuts here. Do this ourselves * (rather than just relying on the scrollbars) so we can do shift + wheel == * left/right. */ static gboolean workspaceview_scroll_event_cb( GtkWidget *widget, GdkEventScroll *ev, Workspaceview *wview ) { gboolean handled = FALSE; /* Gimp uses page_incr / 4 I think, but then scroll speed varies with * window size, which is pretty odd. Just use a constant. */ const int incr = 50; if( ev->direction == GDK_SCROLL_UP || ev->direction == GDK_SCROLL_DOWN ) { if( ev->state & GDK_SHIFT_MASK ) { if( ev->direction == GDK_SCROLL_UP ) workspaceview_scroll_to( wview, wview->vp.left + incr, wview->vp.top ); else workspaceview_scroll_to( wview, wview->vp.left - incr, wview->vp.top ); handled = TRUE; } else { if( ev->direction == GDK_SCROLL_UP ) workspaceview_scroll_to( wview, wview->vp.left, wview->vp.top - incr ); else workspaceview_scroll_to( wview, wview->vp.left, wview->vp.top + incr ); handled = TRUE; } } return( handled ); } static void workspaceview_realize_cb( GtkWidget *wid, Workspaceview *wview ) { g_assert( wid->window ); gtk_widget_add_events( wid, GDK_BUTTON_PRESS_MASK ); } void workspaceview_set_cursor( Workspaceview *wview, iWindowShape shape ) { if( !wview->context ) wview->context = iwindow_cursor_context_new( IWINDOW( view_get_toplevel( VIEW( wview ) ) ), 0, "workspaceview" ); iwindow_cursor_context_set_cursor( wview->context, shape ); } typedef struct _WorkspaceviewFindColumnview { Workspaceview *wview; int x; int y; } WorkspaceviewFindColumnview; static void * workspaceview_find_columnview_sub( View *view, WorkspaceviewFindColumnview *args ) { Columnview *cview = COLUMNVIEW( view ); Rect col; int x, y, w, h; columnview_get_position( cview, &x, &y, &w, &h ); col.left = x; col.top = y; col.width = w; col.height = h; if( im_rect_includespoint( &col, args->x, args->y ) ) return( cview ); return( NULL ); } /* Test for a point is workspaceview background ... ie. is not enclosed by one * of our columns. */ static Columnview * workspaceview_find_columnview( Workspaceview *wview, int x, int y ) { WorkspaceviewFindColumnview args; void *res; args.wview = wview; args.x = x; args.y = y; res = view_map( VIEW( wview ), (view_map_fn) workspaceview_find_columnview_sub, &args, NULL ); if( res ) return( COLUMNVIEW( res ) ); else return( NULL ); } /* Is this event on the workspaceview background. */ static gboolean workspaceview_is_background( Workspaceview *wview, GdkWindow *window, int x, int y ) { /* If the event window is not our window, it must have occured in a * sub-GdkWindow (eg. an image thumbnail), so can't be a background * click. */ if( window != wview->fixed->window ) return( FALSE ); /* Could be a click in a non-window widget (eg. a label); search * all columnviews for a hit. */ return( !workspaceview_find_columnview( wview, x, y ) ); } static gboolean workspaceview_fixed_event_cb( GtkWidget *widget, GdkEvent *ev, Workspaceview *wview ) { gboolean handled = FALSE; #ifdef EVENT printf( "workspaceview_fixed_event_cb: %d\n", ev->type ); #endif /*EVENT*/ switch( ev->type ) { case GDK_BUTTON_PRESS: if( ev->button.button == 1 ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); if( workspaceview_is_background( wview, ev->button.window, ev->button.x, ev->button.y ) ) { workspace_deselect_all( ws ); handled = TRUE; } } else if( ev->button.button == 2 ) { #ifdef EVENT printf( "workspaceview_fixed_event_cb: start drag\n" ); #endif /*EVENT*/ wview->drag_x = ev->button.x_root + wview->vp.left; wview->drag_y = ev->button.y_root + wview->vp.top; workspaceview_set_cursor( wview, IWINDOW_SHAPE_MOVE ); wview->dragging = TRUE; handled = TRUE; } break; case GDK_BUTTON_RELEASE: if( ev->button.button == 2 ) { #ifdef EVENT printf( "workspaceview_fixed_event_cb: stop drag\n" ); #endif /*EVENT*/ workspaceview_set_cursor( wview, IWINDOW_SHAPE_NONE ); wview->dragging = FALSE; handled = TRUE; } break; case GDK_MOTION_NOTIFY: if( wview->dragging && ev->motion.state & GDK_BUTTON2_MASK ) { #ifdef EVENT printf( "workspaceview_fixed_event_cb: motion\n" ); #endif /*EVENT*/ /* We're using hints. */ widget_update_pointer( GTK_WIDGET( wview ), ev ); workspaceview_scroll_to( wview, wview->drag_x - ev->motion.x_root, wview->drag_y - ev->motion.y_root ); handled = TRUE; } break; default: break; } return( handled ); } static void workspaceview_scroll_adjustment_cb( GtkAdjustment *adj, Workspaceview *wview ) { workspaceview_scroll_update( wview ); } /* Timer callback for background scroll. */ static gboolean workspaceview_scroll_time_cb( Workspaceview *wview ) { /* Perform scroll. */ workspaceview_scroll_update( wview ); if( wview->u != 0 || wview->v != 0 ) workspaceview_displace( wview, wview->u, wview->v ); /* Start timer again. */ return( TRUE ); } /* Stop the tally_scroll timer. */ static void workspaceview_scroll_stop( Workspaceview *wview ) { IM_FREEF( g_source_remove, wview->timer ); } /* Start the tally_scroll timer. */ static void workspaceview_scroll_start( Workspaceview *wview ) { workspaceview_scroll_stop( wview ); wview->timer = g_timeout_add( 30, (GSourceFunc) workspaceview_scroll_time_cb, wview ); } /* Set a background scroll. Pass both zero to stop scroll. */ void workspaceview_scroll_background( Workspaceview *wview, int u, int v ) { wview->u = u; wview->v = v; if( u == 0 && v == 0 ) workspaceview_scroll_stop( wview ); else workspaceview_scroll_start( wview ); } static void workspaceview_destroy( GtkObject *object ) { Workspaceview *wview; #ifdef DEBUG printf( "workspaceview_destroy: %p\n", object ); #endif /*DEBUG*/ g_return_if_fail( object != NULL ); g_return_if_fail( IS_WORKSPACEVIEW( object ) ); wview = WORKSPACEVIEW( object ); /* Instance destroy. */ workspaceview_scroll_stop( wview ); IM_FREEF( iwindow_cursor_context_destroy, wview->context ); FREESID( wview->watch_changed_sid, main_watchgroup ); DESTROY_GTK( wview->popup ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void workspaceview_realize( GtkWidget *widget ) { #ifdef DEBUG { Workspaceview *wview = WORKSPACEVIEW( widget ); Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); printf( "workspaceview_realize: %s\n", IOBJECT( ws )->name ); } #endif /*DEBUG*/ GTK_WIDGET_CLASS( parent_class )->realize( widget ); /* Mark us as a symbol drag-to widget. */ set_symbol_drag_type( widget ); } static void workspaceview_drag_data_received( GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time ) { Workspaceview *wview = WORKSPACEVIEW( widget ); Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); const char *from_row_path = (const char *) selection_data->data; Row *from_row; #ifdef DEBUG printf( "workspaceview_drag_data_received:\n" ); #endif /*DEBUG*/ /* We seem to rx drag events with x/y relative to the viewport. */ x += wview->vp.left; y += wview->vp.top; if( info == TARGET_SYMBOL && selection_data->length > 0 && selection_data->format == 8 && workspaceview_is_background( wview, GTK_WIDGET( wview->fixed )->window, x, y ) && (from_row = row_parse_name( main_workspaceroot->sym, from_row_path )) ) { char new_name[MAX_STRSIZE]; Column *col; char vips_buf_text[256]; VipsBuf buf = VIPS_BUF_STATIC( vips_buf_text ); Symbol *sym; workspace_column_name_new( ws, new_name ); col = column_new( ws, new_name ); col->x = x; col->y = y; workspace_column_select( ws, col ); /* Qualify relative to us. We don't want to embed * workspace names unless we have to. */ row_qualified_name_relative( ws->sym, from_row, &buf ); if( !(sym = workspace_add_def( ws, vips_buf_all( &buf ) )) ) iwindow_alert( widget, GTK_MESSAGE_ERROR ); symbol_recalculate_all(); /* Usually the drag-from row will be selected, very * annoying. Select the drag-to row. */ if( sym && sym->expr && sym->expr->row ) row_select( sym->expr->row ); } } static void * workspaceview_child_size_sub( Columnview *cview, Rect *area ) { int x, y, w, h; Rect col; columnview_get_position( cview, &x, &y, &w, &h ); col.left = x; col.top = y; col.width = w; col.height = h; im_rect_unionrect( area, &col, area ); return( NULL ); } static void workspaceview_child_size_cb( Columnview *cview, GtkAllocation *allocation, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); Workspacegroup *wsg = workspace_get_workspacegroup( ws ); int right, bottom; g_assert( IS_WORKSPACEVIEW( wview ) ); /* Compute a new bounding box for our children. */ wview->bounding.left = 0; wview->bounding.top = 0; wview->bounding.width = 0; wview->bounding.height = 0; (void) view_map( VIEW( wview ), (view_map_fn) workspaceview_child_size_sub, &wview->bounding, NULL ); wview->bounding.width += 1000; wview->bounding.height += 1000; #ifdef DEBUG { Column *col = COLUMN( VOBJECT( cview )->iobject ); printf( "workspaceview_child_size_cb: cview %s " "bb left=%d, top=%d, width=%d, height=%d\n", IOBJECT( col )->name, wview->bounding.left, wview->bounding.top, wview->bounding.width, wview->bounding.height ); } #endif /*DEBUG*/ /* Resize our fixed if necessary. */ right = IM_RECT_RIGHT( &wview->bounding ); bottom = IM_RECT_BOTTOM( &wview->bounding ); if( right != wview->width || bottom != wview->height ) { gtk_widget_set_size_request( GTK_WIDGET( wview->fixed ), right, bottom ); /* Update the model hints ... it uses bounding to position * loads and saves. */ ws->area = wview->bounding; filemodel_set_offset( FILEMODEL( wsg ), ws->area.left, ws->area.top ); } } /* Pick an xy position for the next column. */ static void workspaceview_pick_xy( Workspaceview *wview, int *x, int *y ) { /* Position already set? No change. */ if( *x >= 0 ) return; /* Set this position. */ *x = wview->next_x + wview->vp.left; *y = wview->next_y + wview->vp.top; /* And move on. */ wview->next_x += 30; wview->next_y += 30; if( wview->next_x > 300 ) wview->next_x = 3; if( wview->next_y > 200 ) wview->next_y = 3; } static void workspaceview_link( View *view, Model *model, View *parent ) { Workspaceview *wview = WORKSPACEVIEW( view ); Workspace *ws = WORKSPACE( model ); VIEW_CLASS( parent_class )->link( view, model, parent ); vobject_link( VOBJECT( wview->toolkitbrowser ), IOBJECT( ws->kitg ) ); vobject_link( VOBJECT( wview->workspacedefs ), IOBJECT( ws ) ); toolkitbrowser_set_workspace( wview->toolkitbrowser, ws ); pane_set_state( wview->rpane, ws->rpane_open, ws->rpane_position ); pane_set_state( wview->lpane, ws->lpane_open, ws->lpane_position ); } static void workspaceview_child_add( View *parent, View *child ) { Columnview *cview = COLUMNVIEW( child ); Column *column = COLUMN( VOBJECT( cview )->iobject ); Workspaceview *wview = WORKSPACEVIEW( parent ); gtk_signal_connect( GTK_OBJECT( child ), "size_allocate", GTK_SIGNAL_FUNC( workspaceview_child_size_cb ), parent ); VIEW_CLASS( parent_class )->child_add( parent, child ); /* Pick start xy pos. */ workspaceview_pick_xy( wview, &column->x, &column->y ); gtk_fixed_put( GTK_FIXED( wview->fixed ), GTK_WIDGET( cview ), column->x, column->y ); cview->lx = column->x; cview->ly = column->y; } static void workspaceview_child_position( View *parent, View *child ) { Workspaceview *wview = WORKSPACEVIEW( parent ); Columnview *cview = COLUMNVIEW( child ); gtk_fixed_move( GTK_FIXED( wview->fixed ), GTK_WIDGET( cview ), cview->lx, cview->ly ); VIEW_CLASS( parent_class )->child_position( parent, child ); } static void workspaceview_child_front( View *parent, View *child ) { Workspaceview *wview = WORKSPACEVIEW( parent ); Columnview *cview = COLUMNVIEW( child ); gtk_widget_ref( GTK_WIDGET( cview ) ); gtk_container_remove( GTK_CONTAINER( wview->fixed ), GTK_WIDGET( cview ) ); gtk_fixed_put( GTK_FIXED( wview->fixed ), GTK_WIDGET( cview ), cview->lx, cview->ly ); gtk_widget_unref( GTK_WIDGET( cview ) ); } static void workspaceview_refresh( vObject *vobject ) { Workspaceview *wview = WORKSPACEVIEW( vobject ); Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); #ifdef DEBUG printf( "workspaceview_refresh: %p %s\n", ws, IOBJECT( ws )->name ); #endif /*DEBUG*/ gtk_widget_set_sensitive( GTK_WIDGET( wview ), !ws->locked ); workspace_jump_update( ws, wview->popup_jump ); if( ws->rpane_open && !wview->rpane->open ) pane_animate_open( wview->rpane ); if( !ws->rpane_open && wview->rpane->open ) pane_animate_closed( wview->rpane ); if( ws->lpane_open && !wview->lpane->open ) pane_animate_open( wview->lpane ); if( !ws->lpane_open && wview->lpane->open ) pane_animate_closed( wview->lpane ); if( wview->label ) { gtk_label_set_text( GTK_LABEL( wview->label ), IOBJECT( ws )->name ); if( IOBJECT( ws )->caption ) set_tooltip( wview->label, "%s", IOBJECT( ws )->caption ); if( ws->locked ) gtk_image_set_from_stock( GTK_IMAGE( wview->padlock ), STOCK_LOCK, GTK_ICON_SIZE_MENU ); else gtk_image_clear( GTK_IMAGE( wview->padlock ) ); if( ws->errors ) gtk_image_set_from_stock( GTK_IMAGE( wview->alert ), STOCK_ALERT, GTK_ICON_SIZE_MENU ); else gtk_image_clear( GTK_IMAGE( wview->alert ) ); } VOBJECT_CLASS( parent_class )->refresh( vobject ); } /* What we track during a layout. */ typedef struct _WorkspaceLayout { /* Context. */ Workspaceview *wview; /* Set of columnviews still to be laid out. */ GSList *undone_columns; /* Track the current set of columns here. */ GSList *current_columns; /* Current position for write. */ int out_x, out_y; /* Accumulate the size of the current set of columns here. */ Rect area; /* Track the current columnview here. */ Columnview *cview; } WorkspaceLayout; static void * workspaceview_layout_add( View *view, WorkspaceLayout *layout ) { layout->undone_columns = g_slist_prepend( layout->undone_columns, view ); return( NULL ); } static void * workspaceview_layout_find_leftmost( Columnview *cview, WorkspaceLayout *layout ) { if( GTK_WIDGET( cview )->allocation.x < layout->area.left ) { layout->area.left = GTK_WIDGET( cview )->allocation.x; layout->cview = cview; } return( NULL ); } static void * workspaceview_layout_find_similar_x( Columnview *cview, WorkspaceLayout *layout ) { int x = GTK_WIDGET( cview )->allocation.x; gboolean snap; snap = FALSE; /* Special case: a colum at zero makes a new column on the far left. */ if( layout->area.left == 0 && x == 0 ) snap = TRUE; if( layout->area.left > 0 && ABS( x - layout->area.left ) < workspaceview_layout_snap_threshold ) snap = TRUE; if( snap ) { layout->current_columns = g_slist_prepend( layout->current_columns, cview ); layout->area.width = IM_MAX( layout->area.width, GTK_WIDGET( cview )->allocation.width ); } return( NULL ); } /* Compare func for row recomp sort. */ static int workspaceview_layout_sort_y( Columnview *a, Columnview *b ) { return( GTK_WIDGET( a )->allocation.y - GTK_WIDGET( b )->allocation.y ); } static void * workspaceview_layout_set_pos( Columnview *cview, WorkspaceLayout *layout ) { Column *column = COLUMN( VOBJECT( cview )->iobject ); gboolean changed; changed = FALSE; /* If this column is being dragged, put the xy we allocate into the * shadow instead. */ if( cview->shadow ) { if( cview->shadow->lx != layout->out_x || cview->shadow->ly != layout->out_y ) { cview->shadow->lx = layout->out_x; cview->shadow->ly = layout->out_y; changed = TRUE; } } else { if( column->x != layout->out_x || column->y != layout->out_y ) { column->x = layout->out_x; column->y = layout->out_y; changed = TRUE; } } layout->out_y += GTK_WIDGET( cview )->allocation.height + workspaceview_layout_vspacing; if( changed ) iobject_changed( IOBJECT( column ) ); return( NULL ); } static void * workspaceview_layout_strike( Columnview *cview, WorkspaceLayout *layout ) { layout->undone_columns = g_slist_remove( layout->undone_columns, cview ); return( NULL ); } static void workspaceview_layout_loop( WorkspaceLayout *layout ) { layout->cview = NULL; layout->area.left = INT_MAX; slist_map( layout->undone_columns, (SListMapFn) workspaceview_layout_find_leftmost, layout ); layout->current_columns = NULL; layout->area.width = GTK_WIDGET( layout->cview )->allocation.width; slist_map( layout->undone_columns, (SListMapFn) workspaceview_layout_find_similar_x, layout ); layout->current_columns = g_slist_sort( layout->current_columns, (GCompareFunc) workspaceview_layout_sort_y ); layout->out_y = workspaceview_layout_top; slist_map( layout->current_columns, (SListMapFn) workspaceview_layout_set_pos, layout ); layout->out_x += layout->area.width + workspaceview_layout_hspacing; slist_map( layout->current_columns, (SListMapFn) workspaceview_layout_strike, layout ); IM_FREEF( g_slist_free, layout->current_columns ); } /* Autolayout ... try to rearrange columns so they don't overlap. Strategy: search for left-most column search for all columns with a 'small' overlap lay those columns out vertically with some space between them ... keep the vertical ordering we had before find the width of the widest, move output over that much strike that set of columns from the list of columns to be laid out */ static void workspaceview_layout( View *view ) { Workspaceview *wview = WORKSPACEVIEW( view ); WorkspaceLayout layout; layout.wview = wview; layout.undone_columns = NULL; layout.current_columns = NULL; layout.out_x = workspaceview_layout_left; view_map( VIEW( wview ), (view_map_fn) workspaceview_layout_add, &layout, NULL ); while( layout.undone_columns ) workspaceview_layout_loop( &layout ); } static void workspaceview_class_init( WorkspaceviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = workspaceview_destroy; widget_class->realize = workspaceview_realize; widget_class->drag_data_received = workspaceview_drag_data_received; vobject_class->refresh = workspaceview_refresh; view_class->link = workspaceview_link; view_class->child_add = workspaceview_child_add; view_class->child_position = workspaceview_child_position; view_class->child_front = workspaceview_child_front; view_class->layout = workspaceview_layout; } /* Can't use main_load(), we want to select wses after load. */ static gboolean workspaceview_load( Workspace *ws, const char *filename ) { Workspacegroup *wsg = workspace_get_workspacegroup( ws ); Workspaceroot *wsr = wsg->wsr; Workspacegroup *new_wsg; if( (new_wsg = mainw_open_workspace( wsr, filename )) ) return( TRUE ); error_clear(); /* workspace_load_file() needs to recalc to work, try to avoid that by * doing .defs first. */ if( is_file_type( &filesel_dfile_type, filename ) ) { if( toolkit_new_from_file( main_toolkitgroup, filename ) ) return( TRUE ); error_clear(); } /* Try as matrix or image. Have to do these via definitions. */ if( workspace_load_file( ws, filename ) ) return( TRUE ); error_clear(); error_top( _( "Unknown file type." ) ); error_sub( _( "Unable to load \"%s\"." ), filename ); return( FALSE ); } static void workspaceview_lpane_changed_cb( Pane *pane, Workspaceview *wview ) { Workspace *ws; if( (ws = WORKSPACE( VOBJECT( wview )->iobject )) ) if( ws->lpane_open != pane->open || ws->lpane_position != pane->user_position ) { ws->lpane_open = pane->open; ws->lpane_position = pane->user_position; prefs_set( "WORKSPACE_LPANE_OPEN", "%d", ws->lpane_open ); prefs_set( "WORKSPACE_LPANE_POSITION", "%d", ws->lpane_position ); iobject_changed( IOBJECT( ws ) ); } } static void workspaceview_rpane_changed_cb( Pane *pane, Workspaceview *wview ) { Workspace *ws; if( (ws = WORKSPACE( VOBJECT( wview )->iobject )) ) if( ws->rpane_open != pane->open || ws->rpane_position != pane->user_position ) { ws->rpane_open = pane->open; ws->rpane_position = pane->user_position; prefs_set( "WORKSPACE_RPANE_OPEN", "%d", ws->rpane_open ); prefs_set( "WORKSPACE_RPANE_POSITION", "%d", ws->rpane_position ); iobject_changed( IOBJECT( ws ) ); } } static gboolean workspaceview_filedrop( Workspaceview *wview, const char *filename ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); gboolean result; result = workspaceview_load( ws, filename ); if( result ) symbol_recalculate_all(); return( result ); } static void workspaceview_column_new_action_cb2( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); if( !workspace_column_new( ws ) ) iwindow_alert( GTK_WIDGET( wview ), GTK_MESSAGE_ERROR ); } static void workspaceview_group_action_cb2( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); workspace_selected_group( ws ); } static void workspaceview_next_error_action_cb2( GtkWidget *wid, GtkWidget *host, Workspaceview *wview ) { Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject ); if( !workspace_next_error( ws ) ) { error_top( _( "No errors in tab." ) ); error_sub( "%s", _( "There are no errors (that I can see) " "in this tab." ) ); iwindow_alert( GTK_WIDGET( wview ), GTK_MESSAGE_INFO ); } } static void workspaceview_init( Workspaceview *wview ) { GtkAdjustment *hadj; GtkAdjustment *vadj; Panechild *panechild; GtkWidget *ebox; wview->fixed = NULL; wview->window = NULL; wview->timer = 0; wview->u = 0; wview->v = 0; wview->dragging = FALSE; wview->drag_x = 0; wview->drag_y = 0; wview->vp.left = 0; wview->vp.top = 0; wview->vp.width = 0; wview->vp.height = 0; wview->width = -1; wview->height = -1; wview->bounding.left = 0; wview->bounding.top = 0; wview->bounding.width = 0; wview->bounding.height = 0; wview->next_x = 3; wview->next_y = 3; wview->context = NULL; wview->watch_changed_sid = g_signal_connect( main_watchgroup, "watch_changed", G_CALLBACK( workspaceview_watch_changed_cb ), wview ); wview->rpane = pane_new( PANE_HIDE_RIGHT ); g_signal_connect( wview->rpane, "changed", G_CALLBACK( workspaceview_rpane_changed_cb ), wview ); gtk_box_pack_start( GTK_BOX( wview ), GTK_WIDGET( wview->rpane ), TRUE, TRUE, 2 ); gtk_widget_show( GTK_WIDGET( wview->rpane ) ); wview->lpane = pane_new( PANE_HIDE_LEFT ); g_signal_connect( wview->lpane, "changed", G_CALLBACK( workspaceview_lpane_changed_cb ), wview ); gtk_paned_pack1( GTK_PANED( wview->rpane ), GTK_WIDGET( wview->lpane ), TRUE, FALSE ); gtk_widget_show( GTK_WIDGET( wview->lpane ) ); /* Ask for our own window so we can spot events on the window * background. */ wview->fixed = gtk_fixed_new(); gtk_widget_add_events( GTK_WIDGET( wview->fixed ), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK ); gtk_fixed_set_has_window( GTK_FIXED( wview->fixed ), TRUE ); wview->window = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( wview->window ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( wview->window ), wview->fixed ); gtk_viewport_set_shadow_type( GTK_VIEWPORT( GTK_BIN( wview->window )->child ), GTK_SHADOW_NONE ); gtk_signal_connect( GTK_OBJECT( wview->window ), "scroll_event", GTK_SIGNAL_FUNC( workspaceview_scroll_event_cb ), wview ); gtk_signal_connect( GTK_OBJECT( wview->fixed ), "realize", GTK_SIGNAL_FUNC( workspaceview_realize_cb ), wview ); gtk_signal_connect( GTK_OBJECT( wview->fixed ), "event", GTK_SIGNAL_FUNC( workspaceview_fixed_event_cb ), wview ); gtk_widget_add_events( GTK_WIDGET( wview->fixed ), GDK_BUTTON_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK ); hadj = gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW( wview->window ) ); vadj = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW( wview->window ) ); gtk_signal_connect( GTK_OBJECT( hadj ), "value_changed", GTK_SIGNAL_FUNC( workspaceview_scroll_adjustment_cb ), wview ); gtk_signal_connect( GTK_OBJECT( hadj ), "changed", GTK_SIGNAL_FUNC( workspaceview_scroll_adjustment_cb ), wview ); gtk_signal_connect( GTK_OBJECT( vadj ), "value_changed", GTK_SIGNAL_FUNC( workspaceview_scroll_adjustment_cb ), wview ); gtk_signal_connect( GTK_OBJECT( vadj ), "changed", GTK_SIGNAL_FUNC( workspaceview_scroll_adjustment_cb ), wview ); /* We can't use gtk_container_set_focus_hadjustment() etc. since our * workspace contains a lot of nested structures, and hadjustment() * only works for single-layer things. Instead, do focus scrolling * ourselves .. see rowview.c. */ gtk_paned_pack2( GTK_PANED( wview->lpane ), GTK_WIDGET( wview->window ), TRUE, FALSE ); /* Toolkit Browser pane. */ panechild = panechild_new( wview->rpane, _( "Toolkit Browser" ) ); /* Have to put toolkitbrowser in an ebox so the search entry gets * clipped to the pane size. */ ebox = gtk_event_box_new(); gtk_container_add( GTK_CONTAINER( panechild ), GTK_WIDGET( ebox ) ); gtk_widget_show( ebox ); wview->toolkitbrowser = toolkitbrowser_new(); gtk_container_add( GTK_CONTAINER( ebox ), GTK_WIDGET( wview->toolkitbrowser ) ); gtk_widget_show( GTK_WIDGET( wview->toolkitbrowser ) ); /* Workspace-local defs pane. */ panechild = panechild_new( wview->lpane, _( "Tab Definitions" ) ); wview->workspacedefs = workspacedefs_new(); gtk_container_add( GTK_CONTAINER( panechild ), GTK_WIDGET( wview->workspacedefs ) ); gtk_widget_show( GTK_WIDGET( wview->workspacedefs ) ); filedrop_register( GTK_WIDGET( wview ), (FiledropFunc) workspaceview_filedrop, wview ); wview->popup = popup_build( _( "Workspace menu" ) ); popup_add_but( wview->popup, _( "New C_olumn" ), POPUP_FUNC( workspaceview_column_new_action_cb2 ) ); wview->popup_jump = popup_add_pullright( wview->popup, _( "Jump to _Column" ) ); menu_add_sep( wview->popup ); popup_add_but( wview->popup, _( "_Group Selected" ), POPUP_FUNC( workspaceview_group_action_cb2 ) ); menu_add_sep( wview->popup ); popup_add_but( wview->popup, STOCK_NEXT_ERROR, POPUP_FUNC( workspaceview_next_error_action_cb2 ) ); popup_attach( wview->fixed, wview->popup, wview ); gtk_widget_show_all( wview->window ); } GtkType workspaceview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Workspaceview", sizeof( Workspaceview ), sizeof( WorkspaceviewClass ), (GtkClassInitFunc) workspaceview_class_init, (GtkObjectInitFunc) workspaceview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VIEW, &info ); } return( type ); } View * workspaceview_new( void ) { Workspaceview *wview = gtk_type_new( TYPE_WORKSPACEVIEW ); return( VIEW( wview ) ); } void workspaceview_set_label( Workspaceview *wview, GtkWidget *label, GtkWidget *padlock, GtkWidget *alert ) { g_assert( !wview->label ); g_assert( !wview->padlock ); g_assert( !wview->alert ); wview->label = label; wview->padlock = padlock; wview->alert = alert; } nip2-8.7.1/src/plotstatus.h0000644000175000017500000000357213351443023012507 00000000000000/* display plot info and mouse posn */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PLOTSTATUS (plotstatus_get_type()) #define PLOTSTATUS( obj ) (GTK_CHECK_CAST( (obj), TYPE_PLOTSTATUS, Plotstatus )) #define PLOTSTATUS_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTSTATUS, PlotstatusClass )) #define IS_PLOTSTATUS( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTSTATUS )) #define IS_PLOTSTATUS_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTSTATUS )) struct _Plotstatus { GtkFrame parent_class; Plotmodel *plotmodel; GtkWidget *top; /* Top label */ GtkWidget *pos; /* Position */ GtkWidget *hb; /* Band element hbox */ GtkWidget *mag; /* Magnification display */ GtkWidget **label; /* A label for displaying each series */ int columns; /* Last number of columns we saw */ }; typedef struct _PlotstatusClass { GtkFrameClass parent_class; /* My methods. */ } PlotstatusClass; GtkType plotstatus_get_type( void ); Plotstatus *plotstatus_new( Plotmodel *plotmodel ); void plotstatus_mouse( Plotstatus *plotstatus, double x, double y ); nip2-8.7.1/src/vector.c0000644000175000017500000000336113351443023011556 00000000000000/* display a vector */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ValueClass *parent_class = NULL; static void vector_class_init( VectorClass *class ) { parent_class = g_type_class_peek_parent( class ); /* Create signals. */ model_register_loadable( MODEL_CLASS( class ) ); } static void vector_init( Vector *vector ) { iobject_set( IOBJECT( vector ), CLASS_VECTOR, NULL ); } GType vector_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( VectorClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) vector_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Vector ), 32, /* n_preallocs */ (GInstanceInitFunc) vector_init, }; type = g_type_register_static( TYPE_VALUE, "Vector", &info, 0 ); } return( type ); } nip2-8.7.1/src/iregion.h0000644000175000017500000000535713351443023011724 00000000000000/* a ip region class in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IREGION (iregion_get_type()) #define IREGION( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IREGION, iRegion )) #define IREGION_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IREGION, iRegionClass)) #define IS_IREGION( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IREGION )) #define IS_IREGION_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IREGION )) #define IREGION_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IREGION, iRegionClass )) /* Handy for indexing arrays. */ typedef enum iRegionType { IREGION_MARK = 0, IREGION_HGUIDE, IREGION_VGUIDE, IREGION_ARROW, IREGION_REGION, IREGION_AREA } iRegionType; /* Our instance vars ... packaged up for code sharing. */ typedef struct { /* Stuff from the heap. */ Element image_class; /* Child image class */ Imageinfo *ii; Rect area; /* Client display stuff. */ Classmodel *classmodel; iRegiongroup *iregiongroup; } iRegionInstance; struct _iRegion { iImage parent_class; /* Class fields shared with iarrow.c. */ iRegionInstance instance; }; typedef struct _iRegionClass { iImageClass parent_class; /* My methods. */ } iRegionClass; void iregion_instance_destroy( iRegionInstance *instance ); void iregion_instance_init( iRegionInstance *instance, Classmodel *classmodel ); gboolean iregion_instance_update( iRegionInstance *instance, PElement *root ); void iregion_edit( GtkWidget *parent, Model *model ); void iregion_parent_add( iContainer *child ); xmlNode *iregion_save( Model *model, xmlNode *xnode ); gboolean iregion_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ); void *iregion_update_heap( Heapmodel *heapmodel ); gboolean iregion_class_get( Classmodel *classmodel, PElement *root ); gboolean iregion_class_new( Classmodel *classmodel, PElement *fn, PElement *out ); GType iregion_get_type( void ); nip2-8.7.1/src/plot.h0000644000175000017500000000530213351443023011234 00000000000000/* a plot in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PLOT (plot_get_type()) #define PLOT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_PLOT, Plot )) #define PLOT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_PLOT, PlotClass)) #define IS_PLOT( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_PLOT )) #define IS_PLOT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_PLOT )) #define PLOT_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_PLOT, PlotClass )) typedef enum { PLOT_FORMAT_YYYY = 0, PLOT_FORMAT_XYYY, PLOT_FORMAT_XYXY, PLOT_FORMAT_LAST } PlotFormat; typedef enum { PLOT_STYLE_POINT = 0, PLOT_STYLE_LINE, PLOT_STYLE_SPLINE, PLOT_STYLE_BAR, PLOT_STYLE_LAST } PlotStyle; /* Magic number for 'range value unset' (ie. should auto-range). */ #define PLOT_RANGE_UNSET (-999999) struct _Plot { Classmodel model; /* Base class fields. */ ImageValue value; PlotFormat format; PlotStyle style; char *caption; char *xcaption; char *ycaption; GSList *series_captions; double xmin; double xmax; double ymin; double ymax; /* Unpack image to a set of xy columns here. */ double **xcolumn; double **ycolumn; int rows; int columns; /* Save x/y/mag/status here. Init plot windows from this, save and * load from workspaces. */ gboolean show_status; int mag; int left, top; /* Private ... build iobject caption here. */ VipsBuf caption_buffer; }; typedef struct _PlotClass { ClassmodelClass parent_class; /* My methods. */ } PlotClass; GType plot_get_type( void ); char *plot_f2c( PlotFormat format ); char *plot_s2c( PlotStyle style ); #ifdef HAVE_LIBGOFFICE GogPlot *plot_new_gplot( Plot *plot ); void plot_style_main( Plot *plot, GogChart *gchart ); void plot_style_thumbnail( Plot *plot, GogChart *gchart ); Imageinfo *plot_to_image( Plot *plot, Reduce *rc, double dpi ); #endif /*HAVE_LIBGOFFICE*/ nip2-8.7.1/src/link.h0000644000175000017500000000520213351443023011212 00000000000000/* Links between top-level syms and the exprs which reference them */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* A sub-link ... the expr in parent that actually references child, plus * the number of times it makes the reference. */ struct _LinkExpr { Link *link; /* Link we are part of */ Expr *expr; /* Expr that references child */ int count; /* Number of times expr references child */ gboolean dynamic; /* True for dynamic link */ }; /* A link object! */ struct _Link { Symbol *parent; /* This top-level symbol contains exprs ... */ Symbol *child; /* ... which reference this symbol */ /* Link serial number ... when we walk the symbol graph marking * stuff dirty, use this to stop repeat trips along links, and * avoid getting stuck in cycles. */ int serial; /* The expressions inside parent which contain direct references to * child. If parent is in the tally, there can be lots of these. * * Two sort of links: static links, which we can deduce from * compile-time analysis of the expr and which only change when * the user edits and we recompile, and dynamic links which we * clear when we regenerate the heap image of the function, and add * to during evaluation. */ GSList *static_links; GSList *dynamic_links; }; void *link_expr_destroy( LinkExpr *le ); void *link_destroy( Link *link ); void *link_add( Symbol *child, Expr *expr, gboolean dynamic ); void *link_remove( Symbol *child, Expr *expr, gboolean dynamic ); int symbol_ndirty( Symbol *sym ); void *symbol_fix_counts( Symbol *sym ); void symbol_link_destroy( Symbol *sym ); void symbol_link_build( Symbol *sym ); int link_serial_new( void ); void *symbol_dirty_intrans( Symbol *sym, int serial ); void *symbol_dirty( Symbol *sym, int serial ); void *symbol_dirty_total( Symbol *sym, int serial ); void *symbol_dirty_clear( Symbol *sym ); nip2-8.7.1/src/paintboxview.h0000644000175000017500000000366013351443023013002 00000000000000/* Decls for paintboxview.c ... widgets in the paint bar */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ extern iWindowShape paintboxview_shape[]; #define TYPE_PAINTBOXVIEW (paintboxview_get_type()) #define PAINTBOXVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_PAINTBOXVIEW, Paintboxview )) #define PAINTBOXVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PAINTBOXVIEW, PaintboxviewClass )) #define IS_PAINTBOXVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PAINTBOXVIEW )) #define IS_PAINTBOXVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PAINTBOXVIEW )) struct _Paintboxview { GtkFrame parent_class; Imagemodel *imagemodel; /* Spot undo/redo changes on imagemodel->conv->ii. */ Imageinfo *ii; guint ii_undo_changed_sid; guint ii_destroy_sid; GtkWidget *undo; GtkWidget *redo; GtkWidget *clear; GtkWidget *tool[IMAGEMODEL_LAST]; Tslider *nib; GtkWidget *ink; GtkWidget *font; GtkWidget *text; }; typedef struct _PaintboxviewClass { GtkFrameClass parent_class; /* My methods. */ } PaintboxviewClass; GtkType paintboxview_get_type( void ); Paintboxview *paintboxview_new( Imagemodel *imagemodel ); nip2-8.7.1/src/subcolumnview.h0000644000175000017500000000362313351443023013164 00000000000000/* a column of tallyrows in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_SUBCOLUMNVIEW (subcolumnview_get_type()) #define SUBCOLUMNVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_SUBCOLUMNVIEW, Subcolumnview )) #define SUBCOLUMNVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_SUBCOLUMNVIEW, SubcolumnviewClass )) #define IS_SUBCOLUMNVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_SUBCOLUMNVIEW )) #define IS_SUBCOLUMNVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_SUBCOLUMNVIEW )) struct _Subcolumnview { View view; /* Enclosing rhsview, if any. */ Rhsview *rhsview; /* My instance vars. */ GtkWidget *align; /* Alignment widget */ GtkWidget *table; /* Central tally area for column */ int rows; /* Number of rows atm */ int nvis; /* Number of children currently visible */ GtkSizeGroup *group; /* Align captions with this */ }; typedef struct _SubcolumnviewClass { ViewClass parent_class; /* My methods. */ } SubcolumnviewClass; GtkType subcolumnview_get_type( void ); View *subcolumnview_new( void ); nip2-8.7.1/src/iregiongroupview.c0000644000175000017500000001362213351443023013661 00000000000000/* coordinate the display of regionviews on imageviews */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; static iRegiongroup * iregiongroupview_get_iregiongroup( iRegiongroupview *iregiongroupview ) { return( IREGIONGROUP( VOBJECT( iregiongroupview )->iobject ) ); } static Classmodel * iregiongroupview_get_classmodel( iRegiongroupview *iregiongroupview ) { iRegiongroup *iregiongroup; if( (iregiongroup = iregiongroupview_get_iregiongroup( iregiongroupview )) ) return( CLASSMODEL( ICONTAINER( iregiongroup )->parent ) ); return( NULL ); } static void iregiongroupview_destroy( GtkObject *object ) { iRegiongroupview *iregiongroupview; #ifdef DEBUG printf( "iregiongroupview_destroy: %p\n", object ); #endif /*DEBUG*/ g_return_if_fail( object != NULL ); g_return_if_fail( IS_IREGIONGROUPVIEW( object ) ); iregiongroupview = IREGIONGROUPVIEW( object ); /* Destroy all regionviews we manage. */ slist_map( iregiongroupview->classmodel->views, (SListMapFn) object_destroy, NULL ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } /* What we track during a refresh. */ typedef struct { GSList *notused; iRegiongroupview *iregiongroupview; Classmodel *classmodel; iImage *iimage; Imagepresent *ip; } iRegiongroupviewRefreshState; static Regionview * iregiongroupview_refresh_imageview_test( Regionview *regionview, iRegiongroupviewRefreshState *irs ) { if( regionview->classmodel == irs->classmodel && regionview->ip == irs->ip ) return( regionview ); return( NULL ); } static void * iregiongroupview_refresh_imageview( Imagepresent *ip, iRegiongroupviewRefreshState *irs ) { Regionview *regionview; irs->ip = ip; /* Do we have a Regionview for this iv already? */ if( (regionview = slist_map( irs->notused, (SListMapFn) iregiongroupview_refresh_imageview_test, irs )) ) { /* Yes ... reuse. */ irs->notused = g_slist_remove( irs->notused, regionview ); } else { /* Nope ... make a new one. */ iRegionInstance *instance = classmodel_get_instance( irs->classmodel ); PElement *root = &HEAPMODEL( irs->classmodel )->row->expr->root; if( instance ) { Regionview *regionview = regionview_new( irs->classmodel, &instance->area, ip ); #ifdef DEBUG printf( "iregiongroupview_refresh_imageview: " "creating new regionview\n" ); #endif /*DEBUG*/ /* Set the display type from the heap class name. */ regionview_set_type( regionview, root ); } } return( NULL ); } static void * iregiongroupview_refresh_iimage( iImage *iimage, iRegiongroupviewRefreshState *irs ) { irs->iimage = iimage; slist_map( iimage->views, (SListMapFn) iregiongroupview_refresh_imageview, irs ); return( NULL ); } static void iregiongroupview_refresh( vObject *vobject ) { iRegiongroupview *iregiongroupview = IREGIONGROUPVIEW( vobject ); iRegiongroupviewRefreshState irs; #ifdef DEBUG printf( "iregiongroupview_refresh\n" ); printf( "watching model %s %s\n", G_OBJECT_TYPE_NAME( vobject->iobject ), NN( IOBJECT( vobject->iobject )->name ) ); #endif /*DEBUG*/ iregiongroupview->classmodel = iregiongroupview_get_classmodel( iregiongroupview ); if( iregiongroupview->classmodel ) { /* Make a note of all the displays we have now, loop over the * displays we should have, reusing when possible ... remove * any unused displays at the end. */ irs.classmodel = iregiongroupview->classmodel; irs.notused = g_slist_copy( irs.classmodel->views ); irs.iregiongroupview = iregiongroupview; slist_map( irs.classmodel->iimages, (SListMapFn) iregiongroupview_refresh_iimage, &irs ); /* Remove all the regionviews we've not used. */ slist_map( irs.notused, (SListMapFn) object_destroy, NULL ); IM_FREEF( g_slist_free, irs.notused ); } VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void iregiongroupview_class_init( iRegiongroupviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = iregiongroupview_destroy; /* Create signals. */ /* Init methods. */ vobject_class->refresh = iregiongroupview_refresh; } static void iregiongroupview_init( iRegiongroupview *iregiongroupview ) { #ifdef DEBUG printf( "iregiongroupview_init\n" ); #endif /*DEBUG*/ } GtkType iregiongroupview_get_type( void ) { static GtkType iregiongroupview_type = 0; if( !iregiongroupview_type ) { static const GtkTypeInfo info = { "iRegiongroupview", sizeof( iRegiongroupview ), sizeof( iRegiongroupviewClass ), (GtkClassInitFunc) iregiongroupview_class_init, (GtkObjectInitFunc) iregiongroupview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; iregiongroupview_type = gtk_type_unique( TYPE_VIEW, &info ); } return( iregiongroupview_type ); } View * iregiongroupview_new( void ) { iRegiongroupview *iregiongroupview = gtk_type_new( TYPE_IREGIONGROUPVIEW ); #ifdef DEBUG printf( "iregiongroupview_new\n" ); #endif /*DEBUG*/ return( VIEW( iregiongroupview ) ); } nip2-8.7.1/src/doubleclick.h0000644000175000017500000000223313351443023012536 00000000000000/* Declarations for doubleclick determiner. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ typedef void (*DoubleclickFunc)( GtkWidget *, GdkEvent *, void * ); #define DOUBLECLICK_FUNC( fn ) ((DoubleclickFunc) (fn)) void doubleclick_add( GtkWidget *wid, gboolean dsingle, DoubleclickFunc single, void *clients, DoubleclickFunc dub, void *clientd ); nip2-8.7.1/src/vobject.h0000644000175000017500000000443413351443023011717 00000000000000/* abstract base class for a view ... watch an iobject and call _refresh in * idle if it changes. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_VOBJECT (vobject_get_type()) #define VOBJECT( obj ) (GTK_CHECK_CAST( (obj), TYPE_VOBJECT, vObject )) #define VOBJECT_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_VOBJECT, vObjectClass )) #define IS_VOBJECT( obj ) (GTK_CHECK_TYPE( (obj), TYPE_VOBJECT )) #define IS_VOBJECT_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_VOBJECT )) #define VOBJECT_GET_CLASS( obj ) \ (GTK_CHECK_GET_CLASS( (obj), TYPE_VOBJECT, vObjectClass )) struct _vObject { GtkVBox vbox; /* My instance vars. */ iObject *iobject; /* iObject we are watching */ guint changed_sid; /* Signals we use to watch model */ guint destroy_sid; gboolean dirty; /* In need of refreshment */ }; typedef struct _vObjectClass { GtkVBoxClass parent_class; /* State change refresh refresh widgets (don't look at heap value, look at model) link this vobject has been linked to an iobject we also have View::link() -- vObject::link is a lower-level link which is handy for views which are not Views, eg. toolkitbrowser */ void (*refresh)( vObject * ); void (*link)( vObject *, iObject * ); } vObjectClass; void *vobject_refresh_queue( vObject *vobject ); GtkType vobject_get_type( void ); void vobject_base_init( void ); void vobject_link( vObject *vobject, iObject *iobject ); void *vobject_refresh( vObject *vobject ); nip2-8.7.1/src/popupbutton.h0000644000175000017500000000325613351443023012663 00000000000000/* a button that displays a popup menu * * quick hack from totem-plugin-viewer.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_POPUPBUTTON (popupbutton_get_type()) #define POPUPBUTTON( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_POPUPBUTTON, Popupbutton )) #define POPUPBUTTON_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_POPUPBUTTON, PopupbuttonClass )) #define IS_POPUPBUTTON( obj ) (GTK_CHECK_TYPE( (obj), TYPE_POPUPBUTTON )) #define IS_POPUPBUTTON_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_POPUPBUTTON )) typedef struct _Popupbutton { GtkToggleButton parent_object; GtkWidget *menu; } Popupbutton; typedef struct _PopupbuttonClass { GtkToggleButtonClass parent_class; } PopupbuttonClass; GtkType popupbutton_get_type( void ); Popupbutton *popupbutton_new( void ); void popupbutton_set_menu( Popupbutton *Popupbutton, GtkWidget *menu ); nip2-8.7.1/src/value.c0000644000175000017500000000572413351443023011375 00000000000000/* an input value ... put/get methods */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void value_finalize( GObject *gobject ) { Value *value; #ifdef DEBUG printf( "value_finalize\n" ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_VALUE( gobject ) ); value = VALUE( gobject ); /* My instance finalize stuff. */ vips_buf_destroy( &value->caption_buffer ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Default caption: just "class-name class.value". */ static const char * value_generate_caption( iObject *iobject ) { Value *value = VALUE( iobject ); ValueClass *value_class = VALUE_GET_CLASS( value ); VipsBuf *buf = &value->caption_buffer; vips_buf_rewind( buf ); if( !heapmodel_name( HEAPMODEL( value ), buf ) ) vips_buf_appends( buf, G_OBJECT_CLASS_NAME( value_class ) ); vips_buf_appends( buf, " " ); heapmodel_value( HEAPMODEL( value ), buf ); return( vips_buf_all( buf ) ); } static View * value_view_new( Model *model, View *parent ) { return( valueview_new() ); } static void value_class_init( ValueClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ gobject_class->finalize = value_finalize; iobject_class->generate_caption = value_generate_caption; model_class->view_new = value_view_new; } static void value_init( Value *value ) { vips_buf_init_dynamic( &value->caption_buffer, MAX_LINELENGTH ); } GType value_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ValueClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) value_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Value ), 32, /* n_preallocs */ (GInstanceInitFunc) value_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Value", &info, 0 ); } return( type ); } nip2-8.7.1/src/filesel.c0000644000175000017500000007544013351443023011706 00000000000000/* ip's file selectors. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* Define for debugging output. #define DEBUG */ /* TIFF save possibilities. Needs to be kept in sync with the Option in * preferences. */ typedef enum { TIFF_COMPRESSION_NONE = 0, /* No compression */ TIFF_COMPRESSION_LZW, /* Lempel-Ziv compression */ TIFF_COMPRESSION_DEFLATE, /* Zip (deflate) compression */ TIFF_COMPRESSION_PACKBITS, /* Packbits compression */ TIFF_COMPRESSION_JPEG, /* JPEG compression */ TIFF_COMPRESSION_CCITTFAX4 /* Fax compression */ } TiffCompression; typedef enum { TIFF_LAYOUT_STRIP = 0, /* Strip TIFF */ TIFF_LAYOUT_TILE /* Tiled TIFF */ } TiffLayout; typedef enum { TIFF_MULTIRES_FLAT = 0, /* Flat file */ TIFF_MULTIRES_PYRAMID /* Pyramidal TIFF */ } TiffMultires; typedef enum { TIFF_FORMAT_MANYBIT = 0, /* No bit reduction */ TIFF_FORMAT_ONEBIT /* Reduce to 1 bit, where poss */ } TiffFormat; /* Keep a list of all filesels currently active ... we use this for refresh on * new file. */ static GSList *filesel_all = NULL; static iDialogClass *parent_class = NULL; /* For filesels which don't have a suggested filename, track the last dir we * went to and use that as the start dir next time. */ static char *filesel_last_dir = NULL; static const char *icc_suffs[] = { ".icc", ".icm", NULL }; static const char *workspace_suffs[] = { ".ws", NULL }; static const char *rec_suffs[] = { ".rec", NULL }; static const char *mor_suffs[] = { ".mor", NULL }; static const char *con_suffs[] = { ".con", NULL }; static const char *mat_suffs[] = { ".mat", NULL }; static const char *def_suffs[] = { ".def", NULL }; static const char *all_suffs[] = { "", NULL }; FileselFileType filesel_wfile_type = { N_( "Workspace files (*.ws)" ), workspace_suffs }, filesel_rfile_type = { N_( "Recombination matrix files (*.rec)" ), rec_suffs }, filesel_mfile_type = { N_( "Morphology matrix files (*.mor)" ), mor_suffs }, filesel_cfile_type = { N_( "Convolution matrix files (*.con)" ), con_suffs }, filesel_xfile_type = { N_( "Matrix files (*.mat)" ), mat_suffs }, filesel_dfile_type = { N_( "Definition files (*.def)" ), def_suffs }, filesel_ifile_type = { N_( "ICC profiles (*.icc, *.icm)" ), icc_suffs }, filesel_allfile_type = { N_( "All files (*)" ), all_suffs }; FileselFileType *filesel_type_definition[] = { &filesel_dfile_type, NULL }, *filesel_type_workspace[] = { &filesel_wfile_type, NULL }, *filesel_type_matrix[] = { &filesel_xfile_type, &filesel_cfile_type, &filesel_rfile_type, &filesel_mfile_type, NULL }, /* Set during startup. */ **filesel_type_image = NULL, **filesel_type_mainw = NULL, **filesel_type_any = NULL; static void * build_vips_formats_sub( VipsFormatClass *format, GSList **types ) { FileselFileType *type = g_new( FileselFileType, 1 ); char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); const char **i; vips_buf_appendf( &buf, "%s ", VIPS_OBJECT_CLASS( format )->description ); /* Used as eg. "VIPS image files (*.v)" */ vips_buf_appends( &buf, _( "image files" ) ); vips_buf_appends( &buf, " (" ); if( *format->suffs ) for( i = format->suffs; *i; i++ ) { vips_buf_appendf( &buf, "*%s", *i ); if( i[1] ) vips_buf_appends( &buf, "; " ); } else /* No suffix means any allowed. */ vips_buf_appendf( &buf, "*" ); vips_buf_appends( &buf, ")" ); type->name = g_strdup( vips_buf_all( &buf ) ); type->suffixes = format->suffs; *types = g_slist_append( *types, type ); return( NULL ); } /* Look at the registered VIPS formats, build a file type list. Call from * filesel class init. */ static FileselFileType ** build_image_file_type( void ) { GSList *types; FileselFileType **type_array; types = NULL; vips_format_map( (VSListMap2Fn) build_vips_formats_sub, &types, NULL ); type_array = (FileselFileType **) slist_to_array( types ); g_slist_free( types ); return( type_array ); } /* Combine a NULL-terminated list of FileselFileType arrays into one. */ static FileselFileType ** build_file_type_va( FileselFileType **first, ... ) { va_list args; int len; FileselFileType **i; FileselFileType **array; int j; int k; /* Count total number of items. */ len = 0; va_start( args, first ); for( i = first; i; i = va_arg( args, FileselFileType ** ) ) len += array_len( (void **) i ); va_end( args ); /* Copy and NULL-terminate. */ array = g_new( FileselFileType *, len + 1 ); va_start( args, first ); j = 0; for( i = first; i; i = va_arg( args, FileselFileType ** ) ) for( k = 0; i[k]; k++ ) array[j++] = i[k]; va_end( args ); array[j] = NULL; return( array ); } /* Here from main() during startup. We can't just put this in class_init, * because we want to be sure this happens early on. */ void filesel_startup( void ) { filesel_type_image = build_image_file_type(); filesel_type_mainw = build_file_type_va( filesel_type_image, filesel_type_matrix, filesel_type_workspace, NULL ); filesel_type_any = build_file_type_va( filesel_type_mainw, filesel_type_definition, NULL ); } /* Is a file of type ... just look at the suffix. */ gboolean is_file_type( const FileselFileType *type, const char *filename ) { const char **p; const char *suf; if( (suf = strrchr( filename, '.' )) ) { for( p = type->suffixes; *p; p++ ) if( strcasecmp( suf, *p ) == 0 ) return( TRUE ); } return( FALSE ); } /* Map TIFF formats to char* for VIPS. */ static char * decode_tiff_compression( TiffCompression tc ) { switch( tc ) { case TIFF_COMPRESSION_LZW: return( "lzw" ); case TIFF_COMPRESSION_DEFLATE: return( "deflate" ); case TIFF_COMPRESSION_PACKBITS: return( "packbits" ); case TIFF_COMPRESSION_JPEG: return( "jpeg" ); case TIFF_COMPRESSION_CCITTFAX4:return( "ccittfax4" ); case TIFF_COMPRESSION_NONE: default: return( "none" ); } } static char * decode_tiff_layout( TiffLayout tf ) { switch( tf ) { case TIFF_LAYOUT_TILE: return( "tile" ); case TIFF_LAYOUT_STRIP: default: return( "strip" ); } } static char * decode_tiff_multires( TiffMultires tm ) { switch( tm ) { case TIFF_MULTIRES_PYRAMID: return( "pyramid" ); case TIFF_MULTIRES_FLAT: default: return( "flat" ); } } static char * decode_tiff_format( TiffFormat tm ) { switch( tm ) { case TIFF_FORMAT_ONEBIT: return( "onebit" ); case TIFF_FORMAT_MANYBIT: default: return( "manybit" ); } } /* Make a TIFF save format string. */ static void filesel_tiff_mode( char *out ) { char ctype[FILENAME_MAX]; char ltype[FILENAME_MAX]; char buf[FILENAME_MAX]; strcpy( ctype, decode_tiff_compression( IP_TIFF_COMPRESSION ) ); if( IP_TIFF_COMPRESSION == TIFF_COMPRESSION_JPEG ) { im_snprintf( buf, FILENAME_MAX, ":%d", IP_TIFF_JPEG_Q ); strcat( ctype, buf ); } if( IP_TIFF_COMPRESSION == TIFF_COMPRESSION_DEFLATE || IP_TIFF_COMPRESSION == TIFF_COMPRESSION_LZW ) { im_snprintf( buf, FILENAME_MAX, ":%d", IP_TIFF_PREDICTOR + 1 ); strcat( ctype, buf ); } strcpy( ltype, decode_tiff_layout( IP_TIFF_LAYOUT ) ); if( IP_TIFF_LAYOUT == TIFF_LAYOUT_TILE ) { im_snprintf( buf, FILENAME_MAX, ":%dx%d", IP_TIFF_TILE_WIDTH, IP_TIFF_TILE_WIDTH ); strcat( ltype, buf ); } im_snprintf( out, 256, "%s,%s,%s,%s,,,%s", ctype, ltype, decode_tiff_multires( IP_TIFF_MULTI_RES ), decode_tiff_format( IP_TIFF_FORMAT ), IP_TIFF_BIGTIFF ? "8" : "" ); } /* Make a JPEG save format string. */ static void filesel_jpeg_mode( char *out ) { char profile[FILENAME_MAX]; switch( IP_JPEG_ICC_PROFILE ) { case 0: /* Use embedded profile ... do nothing. */ strcpy( profile, "" ); break; case 1: { /* Embed from file. */ char buf[FILENAME_MAX]; char buf2[FILENAME_MAX]; im_strncpy( buf, IP_JPEG_ICC_PROFILE_FILE, FILENAME_MAX ); expand_variables( buf, buf2 ); nativeize_path( buf2 ); im_snprintf( profile, FILENAME_MAX, ",%s", buf2 ); break; } case 2: /* Don't attach a profile. */ im_snprintf( profile, FILENAME_MAX, ",none" ); break; default: /* Again, do nothing. */ strcpy( profile, "" ); break; } im_snprintf( out, 256, "%d%s", IP_JPEG_Q, profile ); } /* Make a PNG save format string. */ static void filesel_png_mode( char *out ) { im_snprintf( out, 256, "%d,%d", IP_PNG_COMPRESSION, IP_PNG_INTERLACE ); } /* Make a PPM save format string. */ static void filesel_ppm_mode( char *out ) { switch( IP_PPM_MODE ) { case 0: im_snprintf( out, 256, "binary" ); break; default: im_snprintf( out, 256, "ascii" ); break; } } /* Make a CSV save format string. */ static void filesel_csv_mode( char *out ) { /* We have to escape ":" and "," characters in the separator string. */ char separator[256]; escape_mode( IP_CSV_SEPARATOR, separator, 256 ); im_snprintf( out, 256, "sep:%s", separator ); } typedef void (*make_mode_fn)( char *buf ); typedef struct { const char *caption_filter; /* nip2 column name for the format */ const char *name; /* vips nickname for the format */ make_mode_fn mode_fn; /* Build a mode string */ } FileselMode; static FileselMode filesel_mode_table[] = { { "JPEG", "jpeg", filesel_jpeg_mode }, { "PNG", "png", filesel_png_mode }, { "TIFF", "tiff", filesel_tiff_mode }, { "CSV", "csv", filesel_csv_mode }, { "PPM", "ppm", filesel_ppm_mode } }; static FileselMode * filesel_get_mode( const char *filename ) { int i; VipsFormatClass *format; if( (format = vips_format_for_name( filename )) ) { VipsObjectClass *object_class = VIPS_OBJECT_CLASS( format ); for( i = 0; i < IM_NUMBER( filesel_mode_table ); i++ ) if( strcmp( filesel_mode_table[i].name, object_class->nickname ) == 0 ) return( &filesel_mode_table[i] ); } else im_error_clear(); return( NULL ); } /* Add our image save settings to the end of a filename. filename must be * at least FILENAME_MAX characters in size. */ void filesel_add_mode( char *filename ) { FileselMode *mode; if( (mode = filesel_get_mode( filename )) ) { char ext[256]; int l = strlen( filename ); mode->mode_fn( ext ); im_snprintf( filename + l, FILENAME_MAX - l, ":%s", ext ); } } static const char * filesel_get_filter( const char *filename ) { FileselMode *mode; if( (mode = filesel_get_mode( filename )) ) return( mode->caption_filter ); return( NULL ); } static void filesel_destroy( GtkObject *object ) { Filesel *filesel; g_return_if_fail( object != NULL ); g_return_if_fail( IS_FILESEL( object ) ); filesel = FILESEL( object ); filesel_all = g_slist_remove( filesel_all, filesel ); IM_FREEF( g_free, filesel->current_dir ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } /* Update `space free' label. */ static void filesel_space_update( Filesel *filesel, const char *dirname ) { double sz = find_space( dirname ); if( filesel->space ) { if( sz < 0 ) set_glabel( filesel->space, _( "Unable to determine " "space free in \"%s\"." ), dirname ); else { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_append_size( &buf, sz ); vips_buf_appendf( &buf, " " ); /* Expands to (eg.) '6GB free in "/pics/tmp"' */ vips_buf_appendf( &buf, _( "free in \"%s\"" ), dirname ); set_glabel( filesel->space, "%s", vips_buf_all( &buf ) ); } } } static void * filesel_add_volume( const char *dir, Filesel *filesel ) { char buf[FILENAME_MAX]; im_strncpy( buf, dir, FILENAME_MAX ); path_expand( buf ); gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER( filesel->chooser ), buf, NULL ); return( NULL ); } static void filesel_suffix_to_glob( const char *suffix, VipsBuf *patt ) { int i; char ch; vips_buf_appends( patt, "*" ); for( i = 0; (ch = suffix[i]); i++ ) { if( isalpha( ch ) ) { vips_buf_appends( patt, "[" ); vips_buf_appendf( patt, "%c", toupper( ch ) ); vips_buf_appendf( patt, "%c", tolower( ch ) ); vips_buf_appends( patt, "]" ); } else vips_buf_appendf( patt, "%c", ch ); } } /* Make a shell glob from a filetype. */ void filesel_make_patt( FileselFileType *type, VipsBuf *patt ) { int i; /* Only use {} braces if there's more than one suffix to match. */ if( type->suffixes[1] ) vips_buf_appends( patt, "{" ); for( i = 0; type->suffixes[i]; i++ ) { if( i > 0 ) vips_buf_appends( patt, "," ); filesel_suffix_to_glob( type->suffixes[i], patt ); } if( type->suffixes[1] ) vips_buf_appends( patt, "}" ); } static char * filesel_get_dir( Filesel *filesel ) { return( gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( filesel->chooser ) ) ); } static void filesel_dir_enter( Filesel *filesel ) { char *dir = filesel_get_dir( filesel ); if( !filesel->current_dir || (dir && strcmp( filesel->current_dir, dir ) != 0) ) { filesel_space_update( filesel, dir ); if( !filesel->start_name ) IM_SETSTR( filesel_last_dir, dir ); filesel->current_dir = dir; dir = NULL; } g_free( dir ); } /* New dir entered signal. */ static void filesel_current_folder_changed_cb( GtkWidget *widget, gpointer data ) { filesel_dir_enter( FILESEL( data ) ); } /* Update file info display. */ static void filesel_info_update( Filesel *filesel, const char *name ) { if( filesel->info ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); get_image_info( &buf, name ); set_glabel( filesel->info, "%s", vips_buf_firstline( &buf ) ); } } int filesel_get_filetype( Filesel *filesel ) { int type; GtkFileFilter *filter; type = filesel->default_type; if( filesel->chooser && (filter = gtk_file_chooser_get_filter( GTK_FILE_CHOOSER( filesel->chooser ) )) ) { int i; for( i = 0; filesel->filter[i]; i++ ) if( filter == filesel->filter[i] ) break; g_assert( filesel->filter[i] ); type = i; } #ifdef DEBUG printf( "filesel_get_filetype: %d\n", type ); #endif /*DEBUG*/ return( type ); } /* Find the index of the type which matches this filename. */ static int filesel_find_file_type( FileselFileType **type, const char *filename ) { int i, j; for( i = 0; type[i]; i++ ) for( j = 0; type[i]->suffixes[j]; j++ ) if( is_casepostfix( type[i]->suffixes[j], filename ) ) return( i ); return( -1 ); } static void filesel_set_filter( Filesel *filesel, GtkFileFilter *filter ) { #ifdef DEBUG printf( "filesel_set_filter: %p\n", filter ); #endif /*DEBUG*/ g_assert( filter ); gtk_file_chooser_set_filter( GTK_FILE_CHOOSER( filesel->chooser ), filter ); } static void filesel_set_filetype_from_filename( Filesel *filesel, const char *name ) { int type; int i; char *p; /* If we're showing "all", any filename is OK, so don't change the file * type. */ type = filesel_get_filetype( filesel ); if( type == filesel->ntypes - 1 ) return; /* If we've not got a sensible filename, don't bother. */ if( (p = strrchr( name, G_DIR_SEPARATOR )) && strspn( p + 1, " \n\t" ) == strlen( p + 1 ) ) return; if( (i = filesel_find_file_type( filesel->type, name )) >= 0 ) filesel_set_filter( filesel, filesel->filter[i] ); else /* No match, or no suffix. Set the last type (should be "All"). */ filesel_set_filter( filesel, filesel->filter[filesel->ntypes - 1] ); } gboolean filesel_set_filename( Filesel *filesel, const char *name ) { char buf[FILENAME_MAX]; if( !is_valid_filename( name ) ) return( FALSE ); im_strncpy( buf, name, FILENAME_MAX ); path_expand( buf ); #ifdef DEBUG printf( "filesel_set_filename: %s\n", buf ); #endif /*DEBUG*/ /* set_filename() will only select existing files, we need to be able * to set any filename (eg. for increment filename), so we have to * set_current_name() as well. */ gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( filesel->chooser ), buf ); if( filesel->save ) gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER( filesel->chooser ), im_skip_dir( buf ) ); filesel->start_name = TRUE; /* We have to set this after setting the filename. */ filesel_set_filetype_from_filename( filesel, buf ); return( TRUE ); } /* Read the filename out ... test for sanity. */ char * filesel_get_filename( Filesel *filesel ) { char *name; char tmp[FILENAME_MAX]; name = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( filesel->chooser ) ); #ifdef DEBUG printf( "filesel_get_filename: %s\n", name ); #endif /*DEBUG*/ if( !name ) { error_top( _( "Bad filename." ) ); error_sub( _( "No file selected." ) ); return( NULL ); } if( !is_valid_filename( name ) ) { g_free( name ); return( NULL ); } /* Rewrite to compact form, eg. "$HOME/fred". */ im_strncpy( tmp, name, FILENAME_MAX ); path_compact( tmp ); g_free( name ); return( g_strdup( tmp ) ); } /* Get filename multi ... map over the selected filenames. */ void * filesel_map_filename_multi( Filesel *filesel, FileselMapFn fn, void *a, void *b ) { GSList *names = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER( filesel->chooser ) ); GSList *p; for( p = names; p; p = p->next ) { char *filename = (char *) p->data; char tmp[FILENAME_MAX]; void *res; im_strncpy( tmp, filename, FILENAME_MAX ); path_compact( tmp ); if( (res = fn( filesel, tmp, a, b )) ) { IM_FREEF( slist_free_all, names ); return( res ); } } IM_FREEF( slist_free_all, names ); return( NULL ); } /* New file selected signal. */ static void filesel_selection_changed_cb( GtkWidget *widget, gpointer data ) { Filesel *filesel = FILESEL( data ); char *filename; #ifdef DEBUG printf( "filesel_selection_changed_cb: %s\n", NN( IWINDOW( filesel )->title ) ); #endif /*DEBUG*/ if( (filename = filesel_get_filename( filesel )) ) { #ifdef DEBUG printf( "filesel_selection_changed_cb: %s - \"%s\"\n", NN( IWINDOW( filesel )->title ), filename ); #endif /*DEBUG*/ filesel_info_update( filesel, filename ); g_free( filename ); } } static void filesel_file_activated_cb( GtkWidget *widget, gpointer data ) { idialog_done_trigger( IDIALOG( data ), 0 ); } /* Increment filename on OK. */ static void filesel_auto_incr_cb( GtkWidget *tog, Filesel *filesel ) { filesel->incr = GTK_TOGGLE_BUTTON( tog )->active; if( filesel->incr ) idialog_set_pinup( IDIALOG( filesel ), TRUE ); } static void filesel_update_preview_cb( GtkFileChooser *chooser, Filesel *filesel ) { char *filename; if( (filename = gtk_file_chooser_get_preview_filename( GTK_FILE_CHOOSER( filesel->chooser ) )) ) { preview_set_filename( filesel->preview, filename ); g_free( filename ); } } static GtkFileFilter * file_filter_from_file_type( FileselFileType *type ) { GtkFileFilter *filter; int j; filter = gtk_file_filter_new(); gtk_file_filter_set_name( filter, _( type->name ) ); if( type->suffixes[0] ) for( j = 0; type->suffixes[j]; j++ ) { char txt[FILENAME_MAX]; VipsBuf buf = VIPS_BUF_STATIC( txt ); filesel_suffix_to_glob( type->suffixes[j], &buf ); gtk_file_filter_add_pattern( filter, vips_buf_all( &buf ) ); } else /* No suffix list means any suffix allowed. */ gtk_file_filter_add_pattern( filter, "*" ); return( filter ); } static void filesel_add_filter( Filesel *filesel, FileselFileType *type, int i ) { filesel->filter[i] = file_filter_from_file_type( type ); #ifdef DEBUG printf( "filesel_add_filter: %p (%d)\n", filesel->filter[i], i ); #endif /*DEBUG*/ gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( filesel->chooser ), filesel->filter[i] ); if( i == filesel->default_type ) filesel_set_filter( filesel, filesel->filter[i] ); } static void filesel_build( GtkWidget *widget ) { Filesel *filesel = FILESEL( widget ); iDialog *idlg = IDIALOG( widget ); int i; FileselFileType *type; GtkWidget *vb; GtkWidget *tog; #ifdef DEBUG printf( "filesel_build: %s\n", NN( IWINDOW( filesel )->title ) ); #endif /*DEBUG*/ /* Call all builds in superclasses. */ if( IWINDOW_CLASS( parent_class )->build ) IWINDOW_CLASS( parent_class )->build( widget ); filesel->chooser = gtk_file_chooser_widget_new( filesel->save ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN ); gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( filesel->chooser ), filesel->multi ); gtk_box_pack_start( GTK_BOX( idlg->work ), filesel->chooser, TRUE, TRUE, 0 ); gtk_widget_show( filesel->chooser ); /* Add data path to volumes. */ slist_map( PATH_SEARCH, (SListMapFn) filesel_add_volume, filesel ); /* Add all the supported file types. Add "all" to the end. */ for( i = 0; (type = filesel->type[i]); i++ ) filesel_add_filter( filesel, type, i ); filesel_add_filter( filesel, &filesel_allfile_type, i ); /* Spot changes. */ gtk_signal_connect( GTK_OBJECT( filesel->chooser ), "current-folder-changed", GTK_SIGNAL_FUNC( filesel_current_folder_changed_cb ), filesel ); gtk_signal_connect( GTK_OBJECT( filesel->chooser ), "selection-changed", GTK_SIGNAL_FUNC( filesel_selection_changed_cb ), filesel ); gtk_signal_connect( GTK_OBJECT( filesel->chooser ), "file-activated", GTK_SIGNAL_FUNC( filesel_file_activated_cb ), filesel ); /* Pack extra widgets. */ vb = gtk_vbox_new( FALSE, 6 ); gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( filesel->chooser ), vb ); gtk_widget_show( vb ); /* Space free label. */ if( filesel->save ) { filesel->space = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( filesel->space ), 0, 0.5 ); gtk_box_pack_start( GTK_BOX( vb ), filesel->space, FALSE, FALSE, 0 ); gtk_widget_show( filesel->space ); } /* File info label. */ if( !filesel->save ) { filesel->info = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( filesel->info ), 0, 0.5 ); gtk_box_pack_start( GTK_BOX( vb ), filesel->info, FALSE, FALSE, 0 ); gtk_widget_show( filesel->info ); } /* Auto-increment toggle. */ if( filesel->save ) { tog = gtk_check_button_new_with_label( _( "Increment filename" ) ); gtk_signal_connect( GTK_OBJECT( tog ), "toggled", GTK_SIGNAL_FUNC( filesel_auto_incr_cb ), filesel ); gtk_box_pack_start( GTK_BOX( vb ), tog, FALSE, FALSE, 0 ); gtk_widget_show( tog ); set_tooltip( tog, _( "After Save, add 1 to the last number in the " "file name" ) ); } if( filesel->imls ) { filesel->preview = preview_new(); gtk_file_chooser_set_preview_widget( GTK_FILE_CHOOSER( filesel->chooser ), GTK_WIDGET( filesel->preview ) ); gtk_signal_connect( GTK_OBJECT( filesel->chooser ), "update-preview", GTK_SIGNAL_FUNC( filesel_update_preview_cb ), filesel ); gtk_widget_show( GTK_WIDGET( filesel->preview ) ); gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER( filesel->chooser ), TRUE ); } if( filesel_last_dir ) gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( filesel->chooser ), filesel_last_dir ); /* Save boxes can be much smaller. */ if( !filesel->save ) gtk_window_set_default_size( GTK_WINDOW( filesel ), 600, 500 ); } static void filesel_class_init( FileselClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; iWindowClass *iwindow_class = (iWindowClass *) class; object_class->destroy = filesel_destroy; iwindow_class->build = filesel_build; parent_class = g_type_class_peek_parent( class ); } /* Increment filename. If there's no number there now, assume zero. */ static void filesel_increment_filename( Filesel *filesel ) { char *filename; if( (filename = filesel_get_filename( filesel )) ) { char name[FILENAME_MAX]; im_strncpy( name, filename, FILENAME_MAX ); g_free( filename ); increment_filename( name ); (void) filesel_set_filename( filesel, name ); } } static void * filesel_refresh( Filesel *filesel ) { char *dir; if( (dir = gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER( filesel->chooser ) )) ) { gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER( filesel->chooser ), dir ); g_free( dir ); } return( NULL ); } /* There may be a new file ... ask all fsb's to refresh. */ void filesel_refresh_all( void ) { (void) slist_map( filesel_all, (SListMapFn) filesel_refresh, NULL ); } static void filesel_init( Filesel *filesel ) { int i; #ifdef DEBUG printf( "filesel_init: %s\n", NN( IWINDOW( filesel )->title ) ); #endif /*DEBUG*/ filesel->chooser = NULL; filesel->space = NULL; filesel->info = NULL; filesel->preview = NULL; for( i = 0; i < FILESEL_MAX_FILTERS; i++ ) filesel->filter[i] = NULL; filesel->incr = FALSE; filesel->imls = FALSE; filesel->save = FALSE; filesel->multi = FALSE; filesel->start_name = FALSE; filesel->type = NULL; filesel->default_type = 0; filesel->type_pref = NULL; filesel->current_dir = NULL; filesel->done_cb = NULL; filesel->client = NULL; idialog_set_callbacks( IDIALOG( filesel ), iwindow_true_cb, NULL, NULL, NULL ); idialog_set_pinup( IDIALOG( filesel ), TRUE ); idialog_set_nosep( IDIALOG( filesel ), TRUE ); idialog_set_button_focus( IDIALOG( filesel ), FALSE ); idialog_set_help_tag( IDIALOG( filesel ), "sec:loadsave" ); filesel_all = g_slist_prepend( filesel_all, filesel ); } GtkType filesel_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Filesel", sizeof( Filesel ), sizeof( FileselClass ), (GtkClassInitFunc) filesel_class_init, (GtkObjectInitFunc) filesel_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_IDIALOG, &info ); } return( type ); } GtkWidget * filesel_new( void ) { Filesel *filesel = (Filesel *) gtk_type_new( TYPE_FILESEL ); iwindow_set_size_prefs( IWINDOW( filesel ), "FILESEL_WINDOW_WIDTH", "FILESEL_WINDOW_HEIGHT" ); return( GTK_WIDGET( filesel ) ); } void filesel_set_done( Filesel *filesel, iWindowFn done_cb, void *client ) { filesel->done_cb = done_cb; filesel->client = client; } /* Back from the user function ... unset the hourglass, and update. */ static void filesel_trigger2( void *sys, iWindowResult result ) { iWindowSusp *susp = (iWindowSusp *) sys; Filesel *filesel = FILESEL( susp->client ); progress_end(); /* If this is a save, assume that there is now a new file, * and ask all fsb's to update. */ if( filesel->save && result != IWINDOW_ERROR ) filesel_refresh_all(); if( result != IWINDOW_YES ) { /* Failure ... bomb out. */ iwindow_susp_return( susp, result ); return; } /* Increment the filename, if required. */ if( filesel->incr ) { filesel_increment_filename( filesel ); filesel_refresh( filesel ); } /* Success! */ iwindow_susp_return( susp, result ); } /* Start of user done ... shut down our suspension, and set the hglass. */ static void filesel_trigger( Filesel *filesel, iWindow *iwnd, iWindowNotifyFn nfn, void *sys ) { /* Suspend the callback for a bit. */ iWindowSusp *susp = iwindow_susp_new( NULL, iwnd, filesel, nfn, sys ); /* If there's a filetype pref, update it. */ if( filesel->type_pref ) prefs_set( filesel->type_pref, "%d", filesel_get_filetype( filesel ) ); progress_begin(); filesel->done_cb( IWINDOW( filesel ), filesel->client, filesel_trigger2, susp ); } static void filesel_prefs_ok_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( client ); /* Force a recalc, in case we've changed the autorecalc * settings. Also does a scan on any widgets. */ symbol_recalculate_all_force( TRUE ); filesel_trigger( filesel, iwnd, nfn, sys ); } static void filesel_prefs( Filesel *filesel, iWindow *iwnd, const char *caption_filter, iWindowNotifyFn nfn, void *sys ) { Prefs *prefs; if( !(prefs = prefs_new( caption_filter )) ) { nfn( sys, IWINDOW_ERROR ); return; } /* Expands to (eg.) "TIFF Save Preferences". */ iwindow_set_title( IWINDOW( prefs ), _( "%s Save Preferences" ), caption_filter ); iwindow_set_parent( IWINDOW( prefs ), GTK_WIDGET( iwnd ) ); idialog_set_callbacks( IDIALOG( prefs ), iwindow_true_cb, NULL, NULL, filesel ); idialog_add_ok( IDIALOG( prefs ), filesel_prefs_ok_cb, GTK_STOCK_SAVE ); idialog_set_notify( IDIALOG( prefs ), nfn, sys ); iwindow_build( IWINDOW( prefs ) ); gtk_widget_show( GTK_WIDGET( prefs ) ); } /* We have a filename and it's OK to overwrite. Is it a type for which we have * to offer preferences? */ static void filesel_yesno_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( client ); char *filename; const char *caption_filter; if( filesel->save ) { if( !(filename = filesel_get_filename( filesel )) ) nfn( sys, IWINDOW_ERROR ); else { if( (caption_filter = filesel_get_filter( filename )) ) filesel_prefs( filesel, iwnd, caption_filter, nfn, sys ); else filesel_trigger( filesel, iwnd, nfn, sys ); g_free( filename ); } } else filesel_trigger( filesel, iwnd, nfn, sys ); } static void filesel_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); char *filename; #ifdef DEBUG printf( "filesel_done\n" ); #endif /*DEBUG*/ if( !(filename = filesel_get_filename( filesel )) ) nfn( sys, IWINDOW_ERROR ); else if( isdir( "%s", filename ) ) { nfn( sys, IWINDOW_NO ); } else { /* File exists and we are saving? Do a yesno before we carry on. */ if( filesel->save && existsf( "%s", filename ) ) { box_yesno( GTK_WIDGET( filesel ), filesel_yesno_cb, iwindow_true_cb, filesel, nfn, sys, _( "Overwrite" ), _( "Overwrite file?" ), _( "File \"%s\" exists. " "OK to overwrite?" ), filename ); } else /* Just call the user function directly. */ filesel_yesno_cb( iwnd, filesel, nfn, sys ); g_free( filename ); } } void filesel_set_flags( Filesel *filesel, gboolean imls, gboolean save ) { filesel->imls = imls; filesel->save = save; idialog_add_ok( IDIALOG( filesel ), filesel_done_cb, save ? GTK_STOCK_SAVE : GTK_STOCK_OPEN ); } void filesel_set_filetype( Filesel *filesel, FileselFileType **type, int default_type ) { /* Reset the widget, if it's there. */ if( filesel->chooser ) filesel_set_filter( filesel, filesel->filter[default_type] ); filesel->type = type; filesel->ntypes = array_len( (void **) type ); filesel->default_type = default_type; } void filesel_set_filetype_pref( Filesel *filesel, const char *type_pref ) { filesel->type_pref = type_pref; } void filesel_set_multi( Filesel *filesel, gboolean multi ) { filesel->multi = multi; } nip2-8.7.1/src/subcolumn.c0000644000175000017500000003766513351443023012301 00000000000000/* a subcolumn */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static HeapmodelClass *parent_class = NULL; static gboolean subcolumn_row_pred_none( Row *row ) { return( FALSE ); } /* No params, no super. */ static gboolean subcolumn_row_pred_members( Row *row ) { if( row->sym && is_system( row->sym ) ) return( FALSE ); if( row->sym && is_super( row->sym ) ) return( FALSE ); if( row->sym && row->sym->type == SYM_PARAM ) return( FALSE ); return( TRUE ); } static gboolean subcolumn_row_pred_params( Row *row ) { return( row->sym && row->sym->type == SYM_PARAM ); } /* Everything but empty superclasses. */ static gboolean subcolumn_row_pred_super( Row *row ) { if( row->sym && is_super( row->sym ) && PEISELIST( &row->expr->root ) ) return( FALSE ); return( TRUE ); } /* Array of these guys control member visibility, scol->vislevel indexes this * array, one of preds from vislevel down has to be TRUE for the row to be * visible. */ const SubcolumnVisibility subcolumn_visibility[] = { { "none", subcolumn_row_pred_none }, { "members", subcolumn_row_pred_members }, { "params", subcolumn_row_pred_params }, { "super", subcolumn_row_pred_super } }; const int subcolumn_nvisibility = IM_NUMBER( subcolumn_visibility ); /* Map down a Subcolumn. */ void * subcolumn_map( Subcolumn *scol, row_map_fn fn, void *a, void *b ) { return( icontainer_map( ICONTAINER( scol ), (icontainer_map_fn) fn, a, b ) ); } static void subcolumn_dispose( GObject *gobject ) { Subcolumn *scol; #ifdef DEBUG printf( "subcolumn_dispose\n" ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_SUBCOLUMN( gobject ) ); scol = SUBCOLUMN( gobject ); scol->col = NULL; scol->scol = NULL; scol->top_col = NULL; heap_unregister_element( reduce_context->heap, &scol->base ); scol->base.type = ELEMENT_NOVAL; scol->base.ele = (void *) 13; scol->this = NULL; scol->super = NULL; G_OBJECT_CLASS( parent_class )->dispose( gobject ); } /* Stuff we track during class instance display update. */ typedef struct { Subcolumn *scol; /* Enclosing column */ GSList *notused; /* List of row we've not used */ } ClassRefreshInfo; /* Test for row represents a sym. */ static void * subcolumn_test_sym( Row *row, Symbol *sym ) { if( row->sym == sym ) return( row ); return( NULL ); } /* Test for row has a zombie of the same name. */ static void * subcolumn_test_row_name( Row *row, Symbol *sym ) { if( !row->sym && strcmp( IOBJECT( row )->name, IOBJECT( sym )->name ) == 0 ) return( row ); return( NULL ); } /* Refresh one line of a subcolumn. */ static void subcolumn_class_new_heap_sub( ClassRefreshInfo *cri, Symbol *sym, PElement *value ) { Row *row; #ifdef DEBUG char txt[200]; VipsBuf buf = VIPS_BUF_STATIC( txt ); symbol_qualified_name( sym, &buf ); printf( "subcolumn_class_new_heap_sub: %s\n", vips_buf_all( &buf ) ); #endif /*DEBUG*/ /* Do we have a row for this symbol? */ if( (row = (Row *) slist_map( cri->notused, (SListMapFn) subcolumn_test_sym, sym )) ) { /* Update it. */ if( heapmodel_new_heap( HEAPMODEL( row ), value ) ) expr_error_set( row->expr ); cri->notused = g_slist_remove( cri->notused, row ); } else if( (row = (Row *) slist_map( cri->notused, (SListMapFn) subcolumn_test_row_name, sym )) ) { /* There's a blank row of the same name, left for us by XML * load. Update the row with the correct symbol. */ row_link_symbol( row, sym, NULL ); if( heapmodel_new_heap( HEAPMODEL( row ), value ) ) expr_error_set( row->expr ); cri->notused = g_slist_remove( cri->notused, row ); } else { row = row_new( cri->scol, sym, value ); if( heapmodel_new_heap( HEAPMODEL( row ), value ) ) expr_error_set( row->expr ); } } #ifdef DEBUG static void * subcolumn_class_dump_tiny_row( Row *row ) { row_name_print( row ); printf( " " ); return( NULL ); } #endif /*DEBUG*/ /* A new scrap of heap for a subcolumn. */ static gboolean subcolumn_class_new_heap( Subcolumn *scol, PElement *root ) { PElement instance = *root; Expr *expr; Row *row; gboolean result; PElement base, member; HeapNode *p; ClassRefreshInfo cri; /* Must be a class display. */ g_assert( !scol->is_top ); row = HEAPMODEL( scol )->row; expr = row->expr; #ifdef DEBUG printf( "subcolumn_class_new_heap: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ /* Can loop here for some recursive classes. FIXME if( mainw_countdown_animate( 99 ) ) return( FALSE ); */ /* No displays for system rows. */ if( row->sym && is_system( row->sym ) ) return( TRUE ); /* If we are the top of a class instance display, get a new serial. * As we recurse down refreshing our contents, this should stop * circular structures looping the browser. FIXME ... clear flags for a whole class, then do a complete redisplay? more reliable, but even slower :-( */ if( scol->scol->is_top ) heap_serial_new( reduce_context->heap ); /* Is it a class with a typecheck member? Go through * that. Do an isclass first to force eval. */ if( !heap_is_class( &instance, &result ) ) return( FALSE ); if( result && class_get_member( &instance, MEMBER_CHECK, NULL, &member ) ) { #ifdef DEBUG printf( "subcolumn_class_new_heap: invoking arg checker\n" ); #endif /* Force eval of the typecheck member. */ if( !heap_is_class( &member, &result ) || !result ) return( FALSE ); } /* Have we already displayed this class? */ if( (PEGETVAL( &instance )->flgs & FLAG_SERIAL) == reduce_context->heap->serial ) { /* FIXME ... display something here? "circular"? */ return( TRUE ); } SETSERIAL( PEGETVAL( &instance )->flgs, reduce_context->heap->serial ); /* Note the heap root ... if this is the top of a row tree, then we * clone the class and use that private copy. */ PEPOINTE( &base, &(SUBCOLUMN( scol ))->base ); PEPUTPE( &base, &instance ); PEPUTPE( &expr->root, &base ); /* Init rebuild params. We make a list of all the existing * row objects for this class display, and every time we * manage to reuse one of them, we knock it off the list. At the * end, remove all unused rows. */ cri.scol = scol; cri.notused = g_slist_copy( ICONTAINER( scol )->children ); #ifdef DEBUG printf( "subcolumn_class_new_heap: existing rows: " ); icontainer_map( ICONTAINER( scol ), (icontainer_map_fn) subcolumn_class_dump_tiny_row, NULL, NULL ); printf( "\n" ); #endif /*DEBUG*/ /* Loop along the members, updating row entries. */ PEGETCLASSMEMBER( &member, &base ); if( PEISNODE( &member ) ) for( p = PEGETVAL( &member ); p; p = GETRIGHT( p ) ) { PElement s, v; HeapNode *hn; Symbol *sym; /* Get the sym/value pair. */ hn = GETLEFT( p ); PEPOINTLEFT( hn, &s ); PEPOINTRIGHT( hn, &v ); sym = SYMBOL( PEGETSYMREF( &s ) ); /* We don't make rows for the default constructor, or * for ".name". These things don't change, so there's * no point (and the default constructor has no text * equivalent anyway). */ if( strcmp( IOBJECT( sym )->name, MEMBER_NAME ) == 0 ) continue; if( is_member( sym ) && strcmp( IOBJECT( sym )->name, IOBJECT( symbol_get_parent( sym ) )->name ) == 0 ) continue; /* Display! */ subcolumn_class_new_heap_sub( &cri, sym, &v ); } /* Remove all the rows we've not used. */ slist_map( cri.notused, (SListMapFn) iobject_destroy, NULL ); IM_FREEF( g_slist_free, cri.notused ); return( TRUE ); } static void * subcolumn_new_heap( Heapmodel *heapmodel, PElement *root ) { Subcolumn *scol = SUBCOLUMN( heapmodel ); /* New heap for a class display? CLear known_private, we've no idea * where this heap came from. */ if( scol == scol->top_scol ) scol->known_private = FALSE; /* A bunch of locals? Update them all. */ if( !scol->is_top && !subcolumn_class_new_heap( scol, root ) ) return( scol ); return( HEAPMODEL_CLASS( parent_class )->new_heap( heapmodel, root ) ); } static void subcolumn_child_add( iContainer *parent, iContainer *child, int pos ) { Subcolumn *scol = SUBCOLUMN( parent ); Row *row = ROW( child ); /* May not have a symbol yet during ws load. * * Can't use is_this()/is_super(), not everything has been built yet. * We don't do this often, so strcmp() it. */ const char *name = row->sym ? IOBJECT( row->sym )->name : IOBJECT( row )->name; if( strcmp( name, MEMBER_THIS ) == 0 ) scol->this = row; if( strcmp( name, MEMBER_SUPER ) == 0 ) scol->super = row; ICONTAINER_CLASS( parent_class )->child_add( parent, child, pos ); } static void subcolumn_child_remove( iContainer *parent, iContainer *child ) { Subcolumn *scol = SUBCOLUMN( parent ); Row *row = ROW( child ); ICONTAINER_CLASS( parent_class )->child_remove( parent, child ); if( scol->this == row ) scol->this = NULL; if( scol->super == row ) scol->super = NULL; } /* If this is a top-level subcolumn, get the enclosing column. */ static Column * subcolumn_get_column( Subcolumn *scol ) { g_assert( scol->is_top ); return( COLUMN( ICONTAINER( scol )->parent ) ); } /* If this is a nested subcolumn, get the enclosing subcolumn. */ static Subcolumn * subcolumn_get_subcolumn( Subcolumn *scol ) { Rhs *rhs; Row *row; Subcolumn *escol; g_assert( !scol->is_top ); rhs = HEAPMODEL( scol )->rhs; row = HEAPMODEL( rhs )->row; escol = row->scol; return( escol ); } /* Return the enclosing column for a Subcolumn. */ static Column * subcolumn_get_top_column( Subcolumn *scol ) { if( !scol->is_top ) return( subcolumn_get_top_column( subcolumn_get_subcolumn( scol ) ) ); return( subcolumn_get_column( scol ) ); } /* Return the enclosing subcolumn ... but not the is_top one. Ie. the enclosing * subcolumn which has the base for this class tree. */ static Subcolumn * subcolumn_get_top_subcolumn( Subcolumn *scol ) { Subcolumn *enclosing; if( scol->is_top ) return( NULL ); enclosing = subcolumn_get_subcolumn( scol ); if( enclosing->is_top ) return( scol ); else return( subcolumn_get_top_subcolumn( enclosing ) ); } static void subcolumn_parent_add( iContainer *child ) { Subcolumn *scol = SUBCOLUMN( child ); ICONTAINER_CLASS( parent_class )->parent_add( child ); g_assert( IS_COLUMN( child->parent ) || IS_RHS( child->parent ) ); g_assert( !IS_COLUMN( child->parent ) || g_slist_length( child->parent->children ) == 1 ); scol->is_top = IS_COLUMN( child->parent ); /* For sub-columns, default to nothing visible. */ if( !scol->is_top ) scol->vislevel = 0; /* Update context pointers. */ if( scol->is_top ) scol->col = subcolumn_get_column( scol ); else scol->col = NULL; if( !scol->is_top ) scol->scol = subcolumn_get_subcolumn( scol ); else scol->scol = NULL; scol->top_col = subcolumn_get_top_column( scol ); scol->top_scol = subcolumn_get_top_subcolumn( scol ); /* Top level subcolumns default to display on, others to display off. */ MODEL( scol )->display = scol->is_top; } static View * subcolumn_view_new( Model *model, View *parent ) { return( subcolumnview_new() ); } static void subcolumn_display( Model *model, gboolean display ) { /* printf( "subcolumn_display: " ); row_name_print( HEAPMODEL( model )->row ); printf( " %d\n", display ); */ MODEL_CLASS( parent_class )->display( model, display ); } static gboolean subcolumn_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { Subcolumn *scol = SUBCOLUMN( model ); g_assert( IS_COLUMN( parent ) || IS_RHS( parent ) ); if( !get_iprop( xnode, "vislevel", &scol->vislevel ) ) return( FALSE ); if( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ) return( FALSE ); return( TRUE ); } static xmlNode * subcolumn_save( Model *model, xmlNode *xnode ) { Subcolumn *scol = SUBCOLUMN( model ); xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( !set_iprop( xthis, "vislevel", scol->vislevel ) ) return( NULL ); return( xthis ); } static void subcolumn_class_init( SubcolumnClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->dispose = subcolumn_dispose; icontainer_class->child_add = subcolumn_child_add; icontainer_class->child_remove = subcolumn_child_remove; icontainer_class->parent_add = subcolumn_parent_add; model_class->view_new = subcolumn_view_new; model_class->display = subcolumn_display; model_class->load = subcolumn_load; model_class->save = subcolumn_save; heapmodel_class->new_heap = subcolumn_new_heap; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void subcolumn_init( Subcolumn *scol ) { #ifdef DEBUG printf( "subcolumn_init\n" ); #endif /*DEBUG*/ scol->col = NULL; scol->scol = NULL; scol->top_col = NULL; scol->vislevel = subcolumn_nvisibility - 1; scol->base.type = ELEMENT_NOVAL; scol->base.ele = (void *) 14; heap_register_element( reduce_context->heap, &scol->base ); scol->known_private = FALSE; scol->this = NULL; scol->super = NULL; } GType subcolumn_get_type( void ) { static GType subcolumn_type = 0; if( !subcolumn_type ) { static const GTypeInfo info = { sizeof( SubcolumnClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) subcolumn_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Subcolumn ), 32, /* n_preallocs */ (GInstanceInitFunc) subcolumn_init, }; subcolumn_type = g_type_register_static( TYPE_HEAPMODEL, "Subcolumn", &info, 0 ); } return( subcolumn_type ); } static void subcolumn_link( Subcolumn *scol, Rhs *rhs, Column *col ) { g_assert( rhs == NULL || col == NULL ); /* parent_add() sets is_top for us. */ if( rhs ) icontainer_child_add( ICONTAINER( rhs ), ICONTAINER( scol ), -1 ); else icontainer_child_add( ICONTAINER( col ), ICONTAINER( scol ), -1 ); } Subcolumn * subcolumn_new( Rhs *rhs, Column *col ) { Subcolumn *scol; scol = SUBCOLUMN( g_object_new( TYPE_SUBCOLUMN, NULL ) ); subcolumn_link( scol, rhs, col ); return( scol ); } void subcolumn_set_vislevel( Subcolumn *scol, int vislevel ) { scol->vislevel = IM_CLIP( 0, vislevel, subcolumn_nvisibility - 1 ); #ifdef DEBUG printf( "subcolumn_set_vislevel: %d\n", scol->vislevel ); #endif /*DEBUG*/ iobject_changed( IOBJECT( scol ) ); } /* Make sure we have a private copy of the graph for this tree of stuff. */ gboolean subcolumn_make_private( Subcolumn *scol ) { Subcolumn *top_scol = scol->top_scol; PElement base; if( !top_scol || top_scol->known_private ) return( TRUE ); #ifdef DEBUG { Row *row = HEAPMODEL( top_scol )->row; printf( "subcolumn_make_private: cloning " ); row_name_print( row ); printf( "\n" ); } #endif /*DEBUG*/ /* Clone from the class args and rebuild our tree. */ PEPOINTE( &base, &top_scol->base ); if( !class_clone_args( reduce_context->heap, &base, &base ) || heapmodel_new_heap( HEAPMODEL( top_scol ), &base ) ) return( FALSE ); top_scol->known_private = TRUE; return( TRUE ); } nip2-8.7.1/src/filemodel.c0000644000175000017500000006063113351443023012217 00000000000000/* abstract base class for things which form the filemodel half of a * filemodel/view pair */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Don't compress save files. FIXME ... some prebuilt libxml2s on win32 don't support libz compression, so don't turn this off */ #define DEBUG_SAVEFILE #include "ip.h" static ModelClass *parent_class = NULL; static GSList *filemodel_registered = NULL; /* Register a file model. Registered models are part of the "xxx has been * modified, save before quit?" check. */ void filemodel_register( Filemodel *filemodel ) { if( !filemodel->registered ) { filemodel->registered = TRUE; filemodel_registered = g_slist_prepend( filemodel_registered, filemodel ); #ifdef DEBUG printf( "filemodel_register: %s \"%s\" (%p)\n", G_OBJECT_TYPE_NAME( filemodel ), IOBJECT( filemodel )->name, filemodel ); #endif /*DEBUG*/ } } void filemodel_unregister( Filemodel *filemodel ) { if( filemodel->registered ) { filemodel->registered = FALSE; filemodel_registered = g_slist_remove( filemodel_registered, filemodel ); #ifdef DEBUG printf( "filemodel_unregister: %s \"%s\" (%p)\n", G_OBJECT_TYPE_NAME( filemodel ), IOBJECT( filemodel )->name, filemodel ); #endif /*DEBUG*/ } } /* Trigger the top_load method for a filemodel. */ void * filemodel_top_load( Filemodel *filemodel, ModelLoadState *state, Model *parent, xmlNode *xnode ) { FilemodelClass *filemodel_class = FILEMODEL_GET_CLASS( filemodel ); if( filemodel_class->top_load ) { if( !filemodel_class->top_load( filemodel, state, parent, xnode ) ) return( filemodel ); } else { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() not implemented for class \"%s\"." ), "top_load", G_OBJECT_CLASS_NAME( filemodel_class ) ); return( filemodel ); } return( NULL ); } /* Trigger the set_modified method for a filemodel. */ void filemodel_set_modified( Filemodel *filemodel, gboolean modified ) { FilemodelClass *filemodel_class = FILEMODEL_GET_CLASS( filemodel ); if( filemodel_class->set_modified ) filemodel_class->set_modified( filemodel, modified ); } void filemodel_set_window_hint( Filemodel *filemodel, iWindow *iwnd ) { /* This can be called repeatedly if objects are moved between windows. */ filemodel->window_hint = iwnd; } iWindow * filemodel_get_window_hint( Filemodel *filemodel ) { if( filemodel->window_hint ) return( filemodel->window_hint ); else return( IWINDOW( mainw_pick_one() ) ); } gboolean filemodel_top_save( Filemodel *filemodel, const char *filename ) { FilemodelClass *filemodel_class = FILEMODEL_GET_CLASS( filemodel ); if( filemodel_class->top_save ) { char *old_filename; int result; /* We must always have the new filename in the save file or * auto path rewriting will get confused on reload. * * Equally, we must not change the filename on the model, in * case this save is not something initiated by the user, for * example, an auto-backup of the workspace. * * Save and restore the filename. Our caller must set the * final filename, if required (after save-as, for example). */ old_filename = g_strdup( filemodel->filename ); filemodel_set_filename( filemodel, filename ); result = filemodel_class->top_save( filemodel, filename ); filemodel_set_filename( filemodel, old_filename ); g_free( old_filename ); return( result ); } else { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() not implemented for class \"%s\"." ), "top_save", G_OBJECT_CLASS_NAME( filemodel_class ) ); return( FALSE ); } } static void filemodel_info( iObject *iobject, VipsBuf *buf ) { Filemodel *filemodel = FILEMODEL( iobject ); IOBJECT_CLASS( parent_class )->info( iobject, buf ); vips_buf_appendf( buf, "filename = \"%s\"\n", NN( filemodel->filename ) ); vips_buf_appendf( buf, "modified = \"%s\"\n", bool_to_char( filemodel->modified ) ); vips_buf_appendf( buf, "registered = \"%s\"\n", bool_to_char( filemodel->registered ) ); vips_buf_appendf( buf, "auto_load = \"%s\"\n", bool_to_char( filemodel->auto_load ) ); } /* filename can be NULL for unset. */ void filemodel_set_filename( Filemodel *filemodel, const char *filename ) { if( filemodel->filename != filename ) { char buf[FILENAME_MAX]; /* We want to keep the absolute, compact form of the filename * inside the object so we don't get a dependency on CWD. */ if( filename ) { im_strncpy( buf, filename, FILENAME_MAX ); path_compact( buf ); filename = buf; } IM_SETSTR( filemodel->filename, filename ); iobject_changed( IOBJECT( filemodel ) ); } } static void filemodel_finalize( GObject *gobject ) { Filemodel *filemodel; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_FILEMODEL( gobject ) ); filemodel = FILEMODEL( gobject ); #ifdef DEBUG printf( "filemodel_finalize: %s \"%s\" (%s)\n", G_OBJECT_TYPE_NAME( filemodel ), NN( IOBJECT( filemodel )->name ), NN( filemodel->filename ) ); #endif /*DEBUG*/ IM_FREE( filemodel->filename ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void filemodel_dispose( GObject *gobject ) { Filemodel *filemodel; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_FILEMODEL( gobject ) ); filemodel = FILEMODEL( gobject ); #ifdef DEBUG printf( "filemodel_dispose: %s \"%s\" (%s)\n", G_OBJECT_TYPE_NAME( filemodel ), NN( IOBJECT( filemodel )->name ), NN( filemodel->filename ) ); #endif /*DEBUG*/ filemodel_unregister( filemodel ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static xmlNode * filemodel_save( Model *model, xmlNode *xnode ) { Filemodel *filemodel = FILEMODEL( model ); xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( !set_sprop( xthis, "filename", filemodel->filename ) ) return( NULL ); return( xthis ); } static gboolean filemodel_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { Filemodel *filemodel = FILEMODEL( model ); char buf[MAX_STRSIZE]; if( get_sprop( xnode, "filename", buf, MAX_STRSIZE ) ) filemodel_set_filename( filemodel, buf ); if( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ) return( FALSE ); return( TRUE ); } static gboolean filemodel_real_top_load( Filemodel *filemodel, ModelLoadState *state, Model *parent, xmlNode *xnode ) { return( TRUE ); } static void filemodel_real_set_modified( Filemodel *filemodel, gboolean modified ) { if( filemodel->modified != modified ) { #ifdef DEBUG printf( "filemodel_real_set_modified: %s \"%s\" (%s) %s\n", G_OBJECT_TYPE_NAME( filemodel ), NN( IOBJECT( filemodel )->name ), NN( filemodel->filename ), bool_to_char( modified ) ); #endif /*DEBUG*/ filemodel->modified = modified; iobject_changed( IOBJECT( filemodel ) ); } } static int filemodel_xml_save_format_file( const char *filename, xmlDoc *doc ) { return( xmlSaveFormatFile( filename, doc, 1 ) == -1 ); } /* Save to filemodel->filename. */ static gboolean filemodel_top_save_xml( Filemodel *filemodel, const char *filename ) { xmlDoc *xdoc; char namespace[256]; if( !(xdoc = xmlNewDoc( (xmlChar *) "1.0" )) ) { error_top( _( "XML library error." ) ); error_sub( _( "model_save_filename: xmlNewDoc() failed" ) ); return( FALSE ); } #ifndef DEBUG_SAVEFILE xmlSetDocCompressMode( xdoc, 1 ); #endif /*!DEBUG_SAVEFILE*/ im_snprintf( namespace, 256, "%s/%d.%d.%d", NAMESPACE, filemodel->major, filemodel->minor, filemodel->micro ); if( !(xdoc->children = xmlNewDocNode( xdoc, NULL, (xmlChar *) "root", NULL )) || !set_sprop( xdoc->children, "xmlns", namespace ) ) { error_top( _( "XML library error." ) ); error_sub( _( "model_save_filename: xmlNewDocNode() failed" ) ); xmlFreeDoc( xdoc ); return( FALSE ); } column_set_offset( filemodel->x_off, filemodel->y_off ); if( model_save( MODEL( filemodel ), xdoc->children ) ) { xmlFreeDoc( xdoc ); return( FALSE ); } if( calli_string_filename( (calli_string_fn) filemodel_xml_save_format_file, filename, xdoc, NULL, NULL ) ) { error_top( _( "Save failed." ) ); error_sub( _( "Save of %s \"%s\" to file \"%s\" failed.\n%s" ), IOBJECT_GET_CLASS_NAME( filemodel ), NN( IOBJECT( filemodel )->name ), NN( filename ), g_strerror( errno ) ); xmlFreeDoc( xdoc ); return( FALSE ); } xmlFreeDoc( xdoc ); return( TRUE ); } static gboolean filemodel_top_save_text( Filemodel *filemodel, const char *filename ) { iOpenFile *of; if( !(of = ifile_open_write( "%s", filename )) ) return( FALSE ); column_set_offset( filemodel->x_off, filemodel->y_off ); if( model_save_text( MODEL( filemodel ), of ) ) { ifile_close( of ); return( FALSE ); } ifile_close( of ); return( TRUE ); } static gboolean filemodel_real_top_save( Filemodel *filemodel, const char *filename ) { ModelClass *model_class = MODEL_GET_CLASS( filemodel ); #ifdef DEBUG printf( "filemodel_real_top_save: save %s \"%s\" to file \"%s\"\n", G_OBJECT_TYPE_NAME( filemodel ), NN( IOBJECT( filemodel )->name ), filename ); #endif /*DEBUG*/ if( model_class->save_text ) { if( !filemodel_top_save_text( filemodel, filename ) ) return( FALSE ); } else if( model_class->save ) { if( !filemodel_top_save_xml( filemodel, filename ) ) return( FALSE ); } else { error_top( _( "Not implemented." ) ); error_sub( _( "filemodel_real_top_save: no save method" ) ); return( FALSE ); } return( TRUE ); } static void filemodel_class_init( FilemodelClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); ModelClass *model_class = (ModelClass*) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = filemodel_finalize; gobject_class->dispose = filemodel_dispose; iobject_class->info = filemodel_info; model_class->save = filemodel_save; model_class->load = filemodel_load; class->top_load = filemodel_real_top_load; class->set_modified = filemodel_real_set_modified; class->top_save = filemodel_real_top_save; /* NULL isn't an allowed value -- this gets overridden by our * subclasses. */ class->filetype = NULL; class->filetype_pref = NULL; } static void filemodel_init( Filemodel *filemodel ) { /* Init our instance fields. */ filemodel->filename = NULL; filemodel->modified = FALSE; filemodel->registered = FALSE; filemodel->auto_load = FALSE; filemodel->x_off = 0; filemodel->y_off = 0; /* Default version. */ filemodel->versioned = FALSE; filemodel->major = MAJOR_VERSION; filemodel->minor = MINOR_VERSION; filemodel->micro = MICRO_VERSION; filemodel->window_hint = NULL; } GtkType filemodel_get_type( void ) { static GtkType filemodel_type = 0; if( !filemodel_type ) { static const GTypeInfo info = { sizeof( FilemodelClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) filemodel_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Filemodel ), 32, /* n_preallocs */ (GInstanceInitFunc) filemodel_init, }; filemodel_type = g_type_register_static( TYPE_MODEL, "Filemodel", &info, 0 ); } return( filemodel_type ); } void filemodel_set_offset( Filemodel *filemodel, int x_off, int y_off ) { #ifdef DEBUG printf( "filemodel_set_offset: %s \"%s\" %d x %d\n", G_OBJECT_TYPE_NAME( filemodel ), NN( IOBJECT( filemodel )->name ), x_off, y_off ); #endif /*DEBUG*/ filemodel->x_off = x_off; filemodel->y_off = y_off; } static gboolean filemodel_load_all_xml( Filemodel *filemodel, Model *parent, ModelLoadState *state ) { xmlNode *xnode; /* Check the root element for type/version compatibility. */ if( !(xnode = xmlDocGetRootElement( state->xdoc )) || !xnode->nsDef || !is_prefix( NAMESPACE, (char *) xnode->nsDef->href ) ) { error_top( _( "Load failed." ) ); error_sub( _( "Can't load XML file \"%s\", " "it's not a %s save file." ), state->filename, PACKAGE ); return( FALSE ); } if( sscanf( (char *) xnode->nsDef->href + strlen( NAMESPACE ) + 1, "%d.%d.%d", &state->major, &state->minor, &state->micro ) != 3 ) { error_top( _( "Load failed." ) ); error_sub( _( "Can't load XML file \"%s\", " "unable to extract version information from " "namespace." ), state->filename ); return( FALSE ); } #ifdef DEBUG printf( "filemodel_load_all_xml: major = %d, minor = %d, micro = %d\n", state->major, state->minor, state->micro ); #endif /*DEBUG*/ if( filemodel_top_load( filemodel, state, parent, xnode ) ) return( FALSE ); return( TRUE ); } static gboolean filemodel_load_all_xml_file( Filemodel *filemodel, Model *parent, const char *filename, const char *filename_user ) { ModelLoadState *state; if( !(state = model_loadstate_new( filename, filename_user )) ) return( FALSE ); if( !filemodel_load_all_xml( filemodel, parent, state ) ) { model_loadstate_destroy( state ); return( FALSE ); } model_loadstate_destroy( state ); return( TRUE ); } static gboolean filemodel_load_all_xml_openfile( Filemodel *filemodel, Model *parent, iOpenFile *of ) { ModelLoadState *state; if( !(state = model_loadstate_new_openfile( of )) ) return( FALSE ); if( !filemodel_load_all_xml( filemodel, parent, state ) ) { model_loadstate_destroy( state ); return( FALSE ); } model_loadstate_destroy( state ); return( TRUE ); } static gboolean filemodel_load_all_text( Filemodel *filemodel, Model *parent, const char *filename, const char *filename_user ) { iOpenFile *of; if( !(of = ifile_open_read( "%s", filename )) ) return( FALSE ); if( model_load_text( MODEL( filemodel ), parent, of ) ) { ifile_close( of ); return( FALSE ); } ifile_close( of ); return( TRUE ); } /* Load filename into filemodel ... can mean merge as well as init. * * We load from @filename. If @filename_user is non-NULL, that's the filename * we should record in the model. */ gboolean filemodel_load_all( Filemodel *filemodel, Model *parent, const char *filename, const char *filename_user ) { ModelClass *model_class = MODEL_GET_CLASS( filemodel ); const char *tname = G_OBJECT_CLASS_NAME( model_class ); #ifdef DEBUG printf( "filemodel_load_all: load file \"%s\" into parent %s \"%s\"\n", filename, G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) ); #endif /*DEBUG*/ if( model_class->load_text ) { if( !filemodel_load_all_text( filemodel, parent, filename, filename_user ) ) return( FALSE ); } else if( model_class->load ) { if( !filemodel_load_all_xml_file( filemodel, parent, filename, filename_user ) ) return( FALSE ); } else { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() not implemented for class \"%s\"." ), "load", tname ); return( FALSE ); } /* Don't recomp here, we may be loading a bunch of interdependent * files. */ return( TRUE ); } /* Load iOpenFile into filemodel ... can mean merge as well as init. */ gboolean filemodel_load_all_openfile( Filemodel *filemodel, Model *parent, iOpenFile *of ) { ModelClass *model_class = MODEL_GET_CLASS( filemodel ); const char *tname = G_OBJECT_CLASS_NAME( model_class ); #ifdef DEBUG printf( "filemodel_load_all_openfile: load \"%s\" " "into parent %s \"%s\"\n", of->fname, G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) ); #endif /*DEBUG*/ if( model_class->load_text ) { if( model_load_text( MODEL( filemodel ), parent, of ) ) return( FALSE ); } else if( model_class->load ) { if( !filemodel_load_all_xml_openfile( filemodel, parent, of ) ) return( FALSE ); } else { error_top( _( "Not implemented." ) ); error_sub( _( "_%s() not implemented for class \"%s\"." ), "load", tname ); return( FALSE ); } /* Don't recomp here, we may be loading a bunch of interdependent * files. */ return( TRUE ); } /* Interactive stuff ... save first. */ static void filemodel_inter_saveas_sub_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Filemodel *filemodel = FILEMODEL( client ); char *filename; if( (filename = filesel_get_filename( filesel )) ) { if( filemodel_top_save( filemodel, filename ) ) { filemodel_set_filename( filemodel, filename ); filemodel_set_modified( filemodel, FALSE ); nfn( sys, IWINDOW_YES ); } else nfn( sys, IWINDOW_ERROR ); g_free( filename ); } else nfn( sys, IWINDOW_ERROR ); } static void filemodel_inter_saveas_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filemodel *filemodel = FILEMODEL( client ); FilemodelClass *class = FILEMODEL_GET_CLASS( filemodel ); Filesel *filesel = FILESEL( filesel_new() ); /* Expands to (eg.) "Save Column A2". */ iwindow_set_title( IWINDOW( filesel ), _( "Save %s %s" ), IOBJECT_GET_CLASS_NAME( filemodel ), NN( IOBJECT( filemodel )->name ) ); filesel_set_flags( filesel, FALSE, TRUE ); filesel_set_filetype( filesel, class->filetype, watch_int_get( main_watchgroup, class->filetype_pref, 0 ) ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) ); filesel_set_done( filesel, filemodel_inter_saveas_sub_cb, filemodel ); idialog_set_notify( IDIALOG( filesel ), nfn, sys ); iwindow_build( IWINDOW( filesel ) ); if( filemodel->filename ) filesel_set_filename( filesel, filemodel->filename ); gtk_widget_show( GTK_WIDGET( filesel ) ); } void filemodel_inter_saveas( iWindow *parent, Filemodel *filemodel ) { filemodel_inter_saveas_cb( parent, filemodel, iwindow_notify_null, NULL ); } void filemodel_inter_save( iWindow *parent, Filemodel *filemodel ) { if( filemodel->filename ) { if( !filemodel_top_save( filemodel, filemodel->filename ) ) iwindow_alert( GTK_WIDGET( parent ), GTK_MESSAGE_ERROR ); else filemodel_set_modified( filemodel, FALSE ); } else filemodel_inter_saveas( parent, filemodel ); } /* Now "empty" ... do an 'are you sure' check if modified has been set. */ static void filemodel_inter_empty_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filemodel *filemodel = FILEMODEL( client ); (void) model_empty( MODEL( filemodel ) ); filemodel_set_modified( filemodel, FALSE ); nfn( sys, IWINDOW_YES ); } static void filemodel_inter_savenempty_ok_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { iWindowSusp *susp = iwindow_susp_new( filemodel_inter_empty_cb, iwnd, client, nfn, sys ); filemodel_inter_saveas_cb( iwnd, client, iwindow_susp_comp, susp ); } void filemodel_inter_savenempty_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filemodel *filemodel = FILEMODEL( client ); const char *tname = IOBJECT_GET_CLASS_NAME( filemodel ); if( filemodel->modified ) { if( filemodel->filename ) box_savenosave( GTK_WIDGET( iwnd ), filemodel_inter_savenempty_ok_cb, filemodel_inter_empty_cb, filemodel, nfn, sys, _( "Object has been modified." ), _( "%s has been modified since you " "loaded it from file \"%s\".\n\n" "Do you want to save your changes?" ), tname, NN( filemodel->filename ) ); else box_savenosave( GTK_WIDGET( iwnd ), filemodel_inter_savenempty_ok_cb, filemodel_inter_empty_cb, filemodel, nfn, sys, _( "Object has been modified." ), _( "%s has been modified. " "Do you want to save your changes?" ), tname ); } else filemodel_inter_empty_cb( NULL, filemodel, nfn, sys ); } void filemodel_inter_savenempty( iWindow *parent, Filemodel *filemodel ) { filemodel_inter_savenempty_cb( parent, filemodel, iwindow_notify_null, NULL ); } /* Now "close" ... easy: just savenempty, then destroy. */ static void filemodel_inter_close_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filemodel *filemodel = FILEMODEL( client ); iwindow_kill( filemodel_get_window_hint( filemodel ) ); nfn( sys, IWINDOW_YES ); } void filemodel_inter_savenclose_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { iWindowSusp *susp = iwindow_susp_new( filemodel_inter_close_cb, iwnd, client, nfn, sys ); filemodel_inter_savenempty_cb( iwnd, client, iwindow_susp_comp, susp ); } void filemodel_inter_savenclose( iWindow *parent, Filemodel *filemodel ) { filemodel_inter_savenclose_cb( parent, filemodel, iwindow_notify_null, NULL ); } /* Now "load" ... add stuff to a model from a file. */ static void filemodel_inter_load_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Filemodel *filemodel = FILEMODEL( client ); iContainer *parent = ICONTAINER( filemodel )->parent; char *filename; if( (filename = filesel_get_filename( filesel )) ) { filemodel_set_filename( filemodel, filename ); if( filemodel_load_all( filemodel, MODEL( parent ), filename, NULL ) ) nfn( sys, IWINDOW_YES ); else nfn( sys, IWINDOW_ERROR ); g_free( filename ); } else nfn( sys, IWINDOW_ERROR ); } static void filemodel_inter_loadas_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filemodel *filemodel = FILEMODEL( client ); FilemodelClass *class = FILEMODEL_GET_CLASS( filemodel ); Filesel *filesel = FILESEL( filesel_new() ); iwindow_set_title( IWINDOW( filesel ), "Load %s", IOBJECT_GET_CLASS_NAME( filemodel ) ); filesel_set_flags( filesel, FALSE, TRUE ); filesel_set_filetype( filesel, class->filetype, watch_int_get( main_watchgroup, class->filetype_pref, 0 ) ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) ); filesel_set_done( filesel, filemodel_inter_load_cb, filemodel ); idialog_set_notify( IDIALOG( filesel ), nfn, sys ); iwindow_build( IWINDOW( filesel ) ); if( filemodel->filename ) filesel_set_filename( filesel, filemodel->filename ); gtk_widget_show( GTK_WIDGET( filesel ) ); } void filemodel_inter_loadas( iWindow *parent, Filemodel *filemodel ) { filemodel_inter_loadas_cb( parent, filemodel, iwindow_notify_null, NULL ); } /* Finally "replace" ... empty, then load. */ static void filemodel_inter_replace_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { iWindowSusp *susp = iwindow_susp_new( filemodel_inter_loadas_cb, iwnd, client, nfn, sys ); filemodel_inter_savenempty_cb( iwnd, client, iwindow_susp_comp, susp ); } void filemodel_inter_replace( iWindow *parent, Filemodel *filemodel ) { filemodel_inter_replace_cb( parent, filemodel, iwindow_notify_null, NULL ); } /* Close all registered filemodels. */ /* The first registered, modified filemodel the user hasn't said "ok!!! ffs" * to. */ static Filemodel * filemodel_inter_close_get_filemodel( void ) { GSList *p; for( p = filemodel_registered; p; p = p->next ) { Filemodel *filemodel = FILEMODEL( p->data ); if( filemodel->modified ) return( filemodel ); } return( NULL ); } void filemodel_inter_close_registered_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filemodel *filemodel; if( (filemodel = filemodel_inter_close_get_filemodel()) ) { iWindowSusp *susp = iwindow_susp_new( filemodel_inter_close_registered_cb, iwnd, client, nfn, sys ); filemodel_inter_savenclose_cb( filemodel_get_window_hint( filemodel ), filemodel, iwindow_susp_comp, susp ); } else nfn( sys, IWINDOW_YES ); } /* Mark something as having been loaded (or made) during startup. If we loaded * from one of the system areas, zap the filename so that we will save to the * user's area on changes. */ void filemodel_set_auto_load( Filemodel *filemodel ) { filemodel->auto_load = TRUE; /* FIXME ... not very futureproof */ if( filemodel->filename && strstr( filemodel->filename, "share" G_DIR_SEPARATOR_S PACKAGE ) ) { char *p = strrchr( filemodel->filename, G_DIR_SEPARATOR ); char buf[FILENAME_MAX]; g_assert( p ); im_snprintf( buf, FILENAME_MAX, "$SAVEDIR" G_DIR_SEPARATOR_S "start" G_DIR_SEPARATOR_S "%s", p + 1 ); filemodel_set_filename( filemodel, buf ); } } nip2-8.7.1/src/imagepresent.c0000644000175000017500000012257113351443023012744 00000000000000/* Imagepresent widget code. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ /* Define to trace button press events. #define EVENT */ /* Snap if closer than this. */ const int imagepresent_snap_threshold = 10; /* Cursor shape in id for each state. */ iWindowShape imagepresent_cursors[IMAGEMODEL_LAST] = { IWINDOW_SHAPE_EDIT, /* IMAGEMODEL_SELECT */ IWINDOW_SHAPE_MOVE, /* IMAGEMODEL_PAN */ IWINDOW_SHAPE_MAGIN, /* IMAGEMODEL_MAGIN */ IWINDOW_SHAPE_MAGOUT, /* IMAGEMODEL_MAGOUT */ IWINDOW_SHAPE_DROPPER, /* IMAGEMODEL_DROPPER */ IWINDOW_SHAPE_PEN, /* IMAGEMODEL_PEN */ IWINDOW_SHAPE_PEN, /* IMAGEMODEL_LINE */ IWINDOW_SHAPE_RECT, /* IMAGEMODEL_RECT */ IWINDOW_SHAPE_FLOOD, /* IMAGEMODEL_FLOOD */ IWINDOW_SHAPE_FLOOD, /* IMAGEMODEL_BLOB */ IWINDOW_SHAPE_TEXT, /* IMAGEMODEL_TEXT */ IWINDOW_SHAPE_SMUDGE /* IMAGEMODEL_SMUDGE */ }; /* Gdk keysyms, and the zooms we set for each. */ typedef struct _ImagepresentKeymap { guint keyval; int zoom; } ImagepresentKeymap; static ImagepresentKeymap imagepresent_keymap[] = { { GDK_1, 1 }, { GDK_2, 2 }, { GDK_3, 3 }, { GDK_4, 4 }, { GDK_5, 5 }, { GDK_6, 6 }, { GDK_7, 7 }, { GDK_8, 8 }, { GDK_9, 9 } }; /* Parent class. */ static GtkBinClass *parent_class = NULL; static void imagepresent_destroy( GtkObject *object ) { Imagepresent *ip = IMAGEPRESENT( object ); #ifdef DEBUG printf( "imagepresent_destroy\n" ); #endif /*DEBUG*/ IM_FREEF( g_source_remove, ip->scroll_tid ); IM_FREEF( iwindow_cursor_context_destroy, ip->cntxt ); DESTROY_GTK( ip->ruler_menu ); if( ip->imagemodel ) { iImage *iimage = ip->imagemodel->iimage; if( iimage ) iimage->views = g_slist_remove( iimage->views, ip ); UNREF( ip->imagemodel ); } GTK_OBJECT_CLASS( parent_class )->destroy( object ); /* Child views should all have removed themselves. */ g_assert( ip->regionviews == NULL ); } static void imagepresent_size_request( GtkWidget *widget, GtkRequisition *requisition ) { GtkBin *bin = GTK_BIN( widget ); gint focus_width; gint focus_pad; gtk_widget_style_get( widget, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL ); requisition->width = 2 * (focus_width + focus_pad); requisition->height = 2 * (focus_width + focus_pad); if( bin->child && GTK_WIDGET_VISIBLE( bin->child ) ) { GtkRequisition child_requisition; gtk_widget_size_request( bin->child, &child_requisition ); requisition->width += child_requisition.width; requisition->height += child_requisition.height; } } static void imagepresent_size_allocate( GtkWidget *widget, GtkAllocation *allocation ) { GtkBin *bin = GTK_BIN( widget ); widget->allocation = *allocation; if( bin->child && GTK_WIDGET_VISIBLE( bin->child ) ) { gint focus_width; gint focus_pad; GtkAllocation child_allocation; gtk_widget_style_get( widget, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL ); child_allocation.x = allocation->x + focus_width + focus_pad; child_allocation.y = allocation->y + focus_width + focus_pad; child_allocation.width = IM_MAX( 1, allocation->width - 2 * (focus_width + focus_pad) ); child_allocation.height = IM_MAX( 1, allocation->height - 2 * (focus_width + focus_pad) ); gtk_widget_size_allocate( bin->child, &child_allocation ); } } static gboolean imagepresent_expose_event( GtkWidget *widget, GdkEventExpose *event ) { if( GTK_WIDGET_DRAWABLE( widget ) ) { if( GTK_WIDGET_HAS_FOCUS( widget ) ) { gint focus_pad; int x, y, width, height; gtk_widget_style_get( widget, "focus-padding", &focus_pad, NULL ); x = widget->allocation.x + focus_pad; y = widget->allocation.y + focus_pad; width = widget->allocation.width - 2 * focus_pad; height = widget->allocation.height - 2 * focus_pad; gtk_paint_focus( widget->style, widget->window, GTK_WIDGET_STATE( widget ), &event->area, widget, "imagepresent", x, y, width, height ); } GTK_WIDGET_CLASS( parent_class )->expose_event( widget, event ); } return( FALSE ); } /* Connect to our enclosing iwnd on realize. */ static void imagepresent_realize( GtkWidget *widget ) { Imagepresent *ip = IMAGEPRESENT( widget ); iWindow *iwnd = IWINDOW( gtk_widget_get_toplevel( widget ) ); if( !ip->cntxt ) ip->cntxt = iwindow_cursor_context_new( iwnd, 0, "imagepresent" ); /* Set initial state. _realize() is too late ... the _refresh() has * already happened. */ iwindow_cursor_context_set_cursor( ip->cntxt, imagepresent_cursors[ip->imagemodel->state] ); GTK_WIDGET_CLASS( parent_class )->realize( widget ); } static void imagepresent_class_init( ImagepresentClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; /* Init parent class. */ parent_class = g_type_class_peek_parent( class ); object_class->destroy = imagepresent_destroy; widget_class->size_request = imagepresent_size_request; widget_class->size_allocate = imagepresent_size_allocate; widget_class->expose_event = imagepresent_expose_event; widget_class->realize = imagepresent_realize; /* Init default methods. */ /* Static class init. */ } /* Rethink rulers. */ static void imagepresent_hruler_rethink( Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; IMAGE *im = imageinfo_get( FALSE, conv->ii ); /* Try to get the ruler width: same as the whole of the scrolled * window. */ int ruler_width = GTK_WIDGET( ip->swin )->allocation.width; double from = imagemodel->visible.left; double to = from + ruler_width; double pos = ip->last_x; double scale; if( imagemodel->rulers_offset && im ) { from -= im->Xoffset; to -= im->Xoffset; pos -= im->Xoffset; } scale = conversion_dmag( conv->mag ); if( imagemodel->rulers_mm && im ) scale *= im->Xres; from /= scale; to /= scale; pos /= scale; gtk_ruler_set_range( GTK_RULER( ip->hrule ), from, to, pos, to - from ); } static void imagepresent_vruler_rethink( Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; IMAGE *im = imageinfo_get( FALSE, conv->ii ); /* Try to get the ruler height: same as the whole of the scrolled * window. */ int ruler_height = GTK_WIDGET( ip->swin )->allocation.height; double from = imagemodel->visible.top; double to = from + ruler_height; double pos = ip->last_y; double scale; if( imagemodel->rulers_offset && im ) { from -= im->Yoffset; to -= im->Yoffset; pos -= im->Yoffset; } scale = conversion_dmag( conv->mag ); if( imagemodel->rulers_mm && im ) scale *= im->Yres; from /= scale; to /= scale; pos /= scale; gtk_ruler_set_range( GTK_RULER( ip->vrule ), from, to, pos, to - from ); } /* Zoom with the mouse clicked at position x, y in canvas coordinates. */ static void imagepresent_zoom_in( Imagepresent *ip, int x, int y ) { Conversion *conv = ip->imagemodel->conv; int ix, iy; conversion_disp_to_im( conv, x, y, &ix, &iy ); imagepresent_set_mag_pos( ip, conversion_double( conv->mag ), ix, iy ); } static void imagepresent_zoom_in_centre( Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; imagepresent_zoom_in( ip, IM_RECT_HCENTRE( &imagemodel->visible ), IM_RECT_VCENTRE( &imagemodel->visible ) ); } static void imagepresent_zoom_out( Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; int ix, iy; /* Current centre of window, image cods. */ conversion_disp_to_im( conv, IM_RECT_HCENTRE( &imagemodel->visible ), IM_RECT_VCENTRE( &imagemodel->visible ), &ix, &iy ); imagepresent_set_mag_pos( ip, conversion_halve( conv->mag ), ix, iy ); } /* Scroll events ... handle mousewheel shortcuts here. */ static gboolean imagepresent_scroll_event_cb( GtkWidget *widget, GdkEventScroll *ev, Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Rect *visible = &imagemodel->visible; gboolean handled; /* Gimp uses page_incr / 4 I think, but then scroll speed varies with * window size, which is pretty odd. Just use a constant. */ const int incr = 50; handled = FALSE; if( ev->direction == GDK_SCROLL_UP || ev->direction == GDK_SCROLL_DOWN ) { if( ev->state & GDK_CONTROL_MASK ) { if( ev->direction == GDK_SCROLL_UP ) imagepresent_zoom_in_centre( ip ); else imagepresent_zoom_out( ip ); handled = TRUE; } else if( ev->state & GDK_SHIFT_MASK ) { if( ev->direction == GDK_SCROLL_UP ) imagepresent_set_position( ip, visible->left + incr, visible->top ); else imagepresent_set_position( ip, visible->left - incr, visible->top ); handled = TRUE; } else { if( ev->direction == GDK_SCROLL_UP ) imagepresent_set_position( ip, visible->left, visible->top - incr ); else imagepresent_set_position( ip, visible->left, visible->top + incr ); handled = TRUE; } } return( handled ); } /* Our adjustments have changed (scroll or resize). */ static void imagepresent_hadj_changed_cb( GtkAdjustment *adj, Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; imagemodel->visible.left = adj->value; imagemodel->visible.width = adj->page_size; /* Update the visible hint on the conversion. */ conv->visible = imagemodel->visible; #ifdef DEBUG printf( "imagepresent_hadj_changed_cb: left = %d, width = %d\n", imagemodel->visible.left, imagemodel->visible.width ); #endif /*DEBUG*/ imagepresent_hruler_rethink( ip ); } static void imagepresent_vadj_changed_cb( GtkAdjustment *adj, Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; imagemodel->visible.top = adj->value; imagemodel->visible.height = adj->page_size; /* Update the visible hint on the conversion. */ conv->visible = imagemodel->visible; #ifdef DEBUG printf( "imagepresent_vadj_changed_cb: top = %d, height = %d\n", imagemodel->visible.top, imagemodel->visible.height ); #endif /*DEBUG*/ imagepresent_vruler_rethink( ip ); } static void imagepresent_floating_new( Imagepresent *ip, int left, int top, int width, int height, gboolean frozen, RegionviewType type, RegionviewResize resize, int x, int y ) { g_assert( !ip->regionview ); ip->floating.left = left; ip->floating.top = top; ip->floating.width = width; ip->floating.height = height; ip->regionview = regionview_new( NULL, &ip->floating, ip ); ip->regionview->frozen = frozen; ip->regionview->type = type; ip->regionview->resize = resize; regionview_attach( ip->regionview, x, y ); } /* Need to fwd ref this. */ static void imagepresent_left_release( Imagepresent *ip, GdkEvent *ev, int x, int y ); static gint imagepresent_hruler_event( GtkWidget *widget, GdkEvent *ev, Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; IMAGE *im = imageinfo_get( FALSE, conv->ii ); gboolean handled = FALSE; switch( ev->type ) { case GDK_BUTTON_PRESS: switch( ev->button.button ) { case 1: (void) imagemodel_set_state( imagemodel, IMAGEMODEL_SELECT, NULL ); imagepresent_floating_new( ip, 0, 0, im->Xsize, 0, TRUE, REGIONVIEW_HGUIDE, REGIONVIEW_RESIZE_BOTTOM, ev->button.x, ev->button.y ); /* The pointer will be grabbed for the drag on the * ruler window. We want to track in the main image * display window, so we have to explicitly ungrab. */ gdk_pointer_ungrab( ev->button.time ); handled = TRUE; break; default: break; } break; case GDK_BUTTON_RELEASE: switch( ev->button.button ) { case 1: imagepresent_left_release( ip, ev, ev->button.x, ev->button.y ); handled = TRUE; break; default: break; } break; default: break; } return( handled ); } static gint imagepresent_vruler_event( GtkWidget *widget, GdkEvent *ev, Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; IMAGE *im = imageinfo_get( FALSE, conv->ii ); gboolean handled = FALSE; switch( ev->type ) { case GDK_BUTTON_PRESS: switch( ev->button.button ) { case 1: (void) imagemodel_set_state( imagemodel, IMAGEMODEL_SELECT, NULL ); imagepresent_floating_new( ip, 0, 0, 0, im->Ysize, TRUE, REGIONVIEW_VGUIDE, REGIONVIEW_RESIZE_RIGHT, ev->button.x, ev->button.y ); gdk_pointer_ungrab( ev->button.time ); handled = TRUE; break; default: break; } break; case GDK_BUTTON_RELEASE: switch( ev->button.button ) { case 1: imagepresent_left_release( ip, ev, ev->button.x, ev->button.y ); handled = TRUE; break; default: break; } break; default: break; } return( handled ); } /* Track this during a snap. */ typedef struct { Imagepresent *ip; int x; /* Start point */ int y; int off_x; /* Current snap offset */ int off_y; int best_x; /* 'Closeness' of best snap so far */ int best_y; } ImagepresentSnap; static void * imagepresent_snap_sub( Regionview *regionview, ImagepresentSnap *snap, gboolean *snapped ) { Imagemodel *imagemodel = snap->ip->imagemodel; Conversion *conv = imagemodel->conv; Rect area; /* Only static h/v guides. */ if( regionview->type != REGIONVIEW_HGUIDE && regionview->type != REGIONVIEW_VGUIDE ) return( NULL ); if( regionview->state != REGIONVIEW_WAIT ) return( NULL ); /* Work in display cods. */ conversion_im_to_disp_rect( conv, ®ionview->area, &area ); if( regionview->type == REGIONVIEW_HGUIDE ) { int score = abs( area.top - snap->y ); if( score < snap->best_y ) { snap->off_y = area.top - snap->y; snap->best_y = score; *snapped = TRUE; } } else { int score = abs( area.left - snap->x ); if( score < snap->best_x ) { snap->off_x = area.left - snap->x; snap->best_x = score; *snapped = TRUE; } } return( NULL ); } static gboolean imagepresent_snap( Imagepresent *ip, ImagepresentSnap *snap ) { gboolean snapped; snap->ip = ip; snap->off_x = 0; snap->off_y = 0; snap->best_x = imagepresent_snap_threshold; snap->best_y = imagepresent_snap_threshold; snapped = FALSE; slist_map2( ip->regionviews, (SListMap2Fn) imagepresent_snap_sub, snap, &snapped ); return( snapped ); } gboolean imagepresent_snap_point( Imagepresent *ip, int x, int y, int *sx, int *sy ) { ImagepresentSnap snap; gboolean snapped; snap.x = x; snap.y = y; snapped = imagepresent_snap( ip, &snap ); *sx = x + snap.off_x; *sy = y + snap.off_y; return( snapped ); } gboolean imagepresent_snap_rect( Imagepresent *ip, Rect *in, Rect *out ) { ImagepresentSnap snap[8]; int i, best, best_score; gboolean snapped; /* Snap the corners plus the edge centres, take the best score. */ snap[0].x = in->left; snap[0].y = in->top; snap[1].x = in->left + in->width; snap[1].y = in->top; snap[2].x = in->left + in->width; snap[2].y = in->top + in->height; snap[3].x = in->left; snap[3].y = in->top + in->height; snap[4].x = in->left + in->width / 2; snap[4].y = in->top; snap[5].x = in->left + in->width; snap[5].y = in->top + in->height / 2; snap[6].x = in->left + in->width / 2; snap[6].y = in->top + in->height; snap[7].x = in->left; snap[7].y = in->top + in->height / 2; for( snapped = FALSE, i = 0; i < 8; i++ ) snapped |= imagepresent_snap( ip, &snap[i] ); best = 0; best_score = snap[0].best_x; for( i = 1; i < 7; i++ ) if( snap[i].best_x < best_score ) { best = i; best_score = snap[i].best_x; } out->left = in->left + snap[best].off_x; best = 0; best_score = snap[0].best_y; for( i = 1; i < 7; i++ ) if( snap[i].best_y < best_score ) { best = i; best_score = snap[i].best_y; } out->top = in->top + snap[best].off_y; out->width = in->width; out->height = in->height; return( snapped ); } /* Set position x, y in canvas coordinates as the top left of the window. */ void imagepresent_set_position( Imagepresent *ip, int x, int y ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; int maxx = conv->canvas.width - imagemodel->visible.width; int maxy = conv->canvas.height - imagemodel->visible.height; #ifdef DEBUG printf( "imagepresent_set_position: %d x %d\n", x, y ); #endif /*DEBUG*/ adjustments_set_value( ip->hadj, ip->vadj, IM_CLIP( 0, x, maxx ), IM_CLIP( 0, y, maxy ) ); } /* Set a new magnification, and scroll for the passed x/y position in image * coordinates to be in the centre of the screen. */ void imagepresent_set_mag_pos( Imagepresent *ip, int mag, int ix, int iy ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; int nx, ny; int last_x, last_y; #ifdef DEBUG printf( "imagepresent_set_mag_pos: %d, %d x %d\n", mag, ix, iy ); #endif /*DEBUG*/ /* Need to update last_x/y as well ... go to image cods around zoom * operation. */ conversion_disp_to_im( conv, ip->last_x, ip->last_y, &last_x, &last_y ); /* Take mouse pos to image cods around zoom operation. */ conversion_set_mag( conv, mag ); conversion_im_to_disp( conv, ix, iy, &nx, &ny ); /* ... and try to get that point in the centre of the window. We need * to zap in the new adjustment upper value, since this won't * otherwise get set until we get back to idle. */ ip->hadj->upper = conv->canvas.width; ip->vadj->upper = conv->canvas.height; imagepresent_set_position( ip, nx - imagemodel->visible.width / 2, ny - imagemodel->visible.height / 2 ); conversion_im_to_disp( conv, last_x, last_y, &ip->last_x, &ip->last_y ); } /* Set a magnification, keeping the centre of the screen in the centre. */ void imagepresent_zoom_to( Imagepresent *ip, int mag ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; /* If window is larger than image. */ int w = IM_MIN( imagemodel->visible.width, conv->canvas.width ); int h = IM_MIN( imagemodel->visible.height, conv->canvas.height ); int ix, iy; conversion_disp_to_im( conv, imagemodel->visible.left + w / 2, imagemodel->visible.top + h / 2, &ix, &iy ); imagepresent_set_mag_pos( ip, mag, ix, iy ); } /* Left button press event. */ static gboolean imagepresent_left_press( Imagepresent *ip, GdkEvent *ev, int x, int y ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; gboolean handled = FALSE; IMAGE *im2; int ix, iy; /* If there's a regionview grabbed already, block other actions. This * can happen with, for example, the win32 backend where we don't * always see a RELEASE for every PRESS. */ if( ip->regionview ) return( FALSE ); switch( imagemodel->state ) { case IMAGEMODEL_SELECT: if( ev->button.state & GDK_CONTROL_MASK ) { imagepresent_snap_point( ip, x, y, &x, &y ); conversion_disp_to_im( conv, x, y, &ix, &iy ); imagepresent_floating_new( ip, ix, iy, 0, 0, FALSE, REGIONVIEW_MARK, REGIONVIEW_RESIZE_BOTTOMRIGHT, x, y ); handled = TRUE; } break; case IMAGEMODEL_PAN: /* Save how much we have to add to x_root to get x. */ ip->dx = ev->button.x_root + imagemodel->visible.left; ip->dy = ev->button.y_root + imagemodel->visible.top; break; case IMAGEMODEL_MAGIN: imagepresent_zoom_in( ip, x, y ); handled = TRUE; break; case IMAGEMODEL_MAGOUT: imagepresent_zoom_out( ip ); handled = TRUE; break; case IMAGEMODEL_DROPPER: case IMAGEMODEL_FLOOD: case IMAGEMODEL_BLOB: break; case IMAGEMODEL_PEN: case IMAGEMODEL_SMUDGE: imagepresent_snap_point( ip, x, y, &x, &y ); conversion_disp_to_im( conv, x, y, &ix, &iy ); ip->paint_last_x = ix; ip->paint_last_y = iy; handled = TRUE; /* This can take ages and, via progress, actually process a * few events. Do it at the end. */ imagemodel_refresh_nib( imagemodel ); break; case IMAGEMODEL_LINE: imagepresent_snap_point( ip, x, y, &x, &y ); conversion_disp_to_im( conv, x, y, &ix, &iy ); ip->paint_last_x = ix; ip->paint_last_y = iy; imagepresent_floating_new( ip, ix, iy, 0, 0, TRUE, REGIONVIEW_LINE, REGIONVIEW_RESIZE_BOTTOMRIGHT, x, y ); handled = TRUE; /* This can take ages and, via progress, actually process a * few events. Do it at the end. */ imagemodel_refresh_nib( imagemodel ); break; case IMAGEMODEL_RECT: imagepresent_snap_point( ip, x, y, &x, &y ); conversion_disp_to_im( conv, x, y, &ix, &iy ); imagepresent_floating_new( ip, ix, iy, 0, 0, TRUE, REGIONVIEW_BOX, REGIONVIEW_RESIZE_BOTTOMRIGHT, x, y ); handled = TRUE; break; case IMAGEMODEL_TEXT: imagepresent_snap_point( ip, x, y, &x, &y ); conversion_disp_to_im( conv, x, y, &ix, &iy ); ip->paint_last_x = ix; ip->paint_last_y = iy; if( !imagemodel_refresh_text( imagemodel ) ) { iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); break; } im2 = imageinfo_get( FALSE, imagemodel->text_mask ); imagepresent_floating_new( ip, ix, iy + imagemodel->text_area.top, im2->Xsize, im2->Ysize, TRUE, REGIONVIEW_BOX, REGIONVIEW_RESIZE_EDIT, x, y ); handled = TRUE; break; default: break; } return( handled ); } static void imagepresent_paint_stop( Imagepresent *ip, int x, int y ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; Imageinfo *imageinfo = conv->ii; Rect oper; int ix, iy; imagepresent_snap_point( ip, x, y, &x, &y ); conversion_disp_to_im( conv, x, y, &ix, &iy ); switch( imagemodel->state ) { case IMAGEMODEL_DROPPER: if( im_rect_includespoint( &conv->underlay, ix, iy ) ) if( !imageinfo_paint_dropper( imageinfo, imagemodel->ink, ix, iy ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); break; case IMAGEMODEL_PEN: if( !imageinfo_paint_line( imageinfo, imagemodel->ink, imagemodel->nib, ip->paint_last_x, ip->paint_last_y, ix, iy ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); break; case IMAGEMODEL_LINE: if( ip->regionview ) { DESTROY_GTK( ip->regionview ); if( !imageinfo_paint_line( imageinfo, imagemodel->ink, imagemodel->nib, ip->floating.left, ip->floating.top, IM_RECT_RIGHT( &ip->floating ), IM_RECT_BOTTOM( &ip->floating ) ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); } break; case IMAGEMODEL_RECT: if( ip->regionview ) { DESTROY_GTK( ip->regionview ); im_rect_normalise( &ip->floating ); if( !imageinfo_paint_rect( imageinfo, imagemodel->ink, &ip->floating ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); } break; case IMAGEMODEL_FLOOD: if( !imageinfo_paint_flood( imageinfo, imagemodel->ink, ix, iy, FALSE ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); break; case IMAGEMODEL_BLOB: if( !imageinfo_paint_flood( imageinfo, imagemodel->ink, ix, iy, TRUE ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); break; case IMAGEMODEL_TEXT: if( ip->regionview ) { DESTROY_GTK( ip->regionview ); if( !imageinfo_paint_mask( imageinfo, imagemodel->ink, imagemodel->text_mask, ip->floating.left, ip->floating.top ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); } break; case IMAGEMODEL_SMUDGE: /* Area to smudge in display cods. */ oper.left = -10; oper.top = -10; oper.width = 20; oper.height = 20; /* Translate to IMAGE cods. */ conversion_disp_to_im_rect( conv, &oper, &oper ); if( !imageinfo_paint_smudge( imageinfo, &oper, ip->paint_last_x, ip->paint_last_y, ix, iy ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); break; default: break; } imagemodel_paint_recalc( imagemodel ); imageinfo_undo_mark( imageinfo ); /* Ask everyone to drop cache, the image has changed. */ im_invalidate( imageinfo_get( FALSE, imageinfo ) ); } /* Left button release event. */ static void imagepresent_left_release( Imagepresent *ip, GdkEvent *ev, int x, int y ) { Imagemodel *imagemodel = ip->imagemodel; Row *row = imagemodel->iimage ? HEAPMODEL( imagemodel->iimage )->row : NULL; switch( imagemodel->state ) { case IMAGEMODEL_SELECT: if( ip->regionview && row ) { /* Make a new region. */ char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); Symbol *sym; switch( ip->regionview->type ) { case REGIONVIEW_MARK: vips_buf_appendf( &buf, "%s ", CLASS_MARK ); row_qualified_name( row, &buf ); vips_buf_appendd( &buf, ip->floating.left ); vips_buf_appendd( &buf, ip->floating.top ); break; case REGIONVIEW_REGION: vips_buf_appendf( &buf, "%s ", CLASS_REGION ); row_qualified_name( row, &buf ); vips_buf_appendd( &buf, ip->floating.left ); vips_buf_appendd( &buf, ip->floating.top ); vips_buf_appendd( &buf, ip->floating.width ); vips_buf_appendd( &buf, ip->floating.height ); break; case REGIONVIEW_ARROW: vips_buf_appendf( &buf, "%s ", CLASS_ARROW ); row_qualified_name( row, &buf ); vips_buf_appendd( &buf, ip->floating.left ); vips_buf_appendd( &buf, ip->floating.top ); vips_buf_appendd( &buf, ip->floating.width ); vips_buf_appendd( &buf, ip->floating.height ); break; case REGIONVIEW_HGUIDE: vips_buf_appendf( &buf, "%s ", CLASS_HGUIDE ); row_qualified_name( row, &buf ); vips_buf_appendd( &buf, ip->floating.top ); break; case REGIONVIEW_VGUIDE: vips_buf_appendf( &buf, "%s ", CLASS_VGUIDE ); row_qualified_name( row, &buf ); vips_buf_appendd( &buf, ip->floating.left ); break; default: g_assert( FALSE ); } DESTROY_GTK( ip->regionview ); if( !(sym = workspace_add_def_recalc( row->ws, vips_buf_all( &buf ) )) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); workspace_deselect_all( row->ws ); } break; case IMAGEMODEL_DROPPER: case IMAGEMODEL_PEN: case IMAGEMODEL_LINE: case IMAGEMODEL_RECT: case IMAGEMODEL_FLOOD: case IMAGEMODEL_BLOB: case IMAGEMODEL_TEXT: case IMAGEMODEL_SMUDGE: imagepresent_paint_stop( ip, x, y ); break; default: break; } } /* Button motion event. */ static void imagepresent_button_motion( Imagepresent *ip, GdkEvent *ev ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; Imageinfo *imageinfo = conv->ii; Rect oper; int x, y; int ix, iy; imagepresent_snap_point( ip, ev->motion.x, ev->motion.y, &x, &y ); conversion_disp_to_im( conv, x, y, &ix, &iy ); switch( imagemodel->state ) { case IMAGEMODEL_SELECT: break; case IMAGEMODEL_PAN: imagepresent_set_position( ip, (int) ip->dx - ev->motion.x_root, (int) ip->dy - ev->motion.y_root ); break; case IMAGEMODEL_MAGIN: break; case IMAGEMODEL_MAGOUT: break; case IMAGEMODEL_DROPPER: if( im_rect_includespoint( &conv->underlay, ix, iy ) ) if( !imageinfo_paint_dropper( imageinfo, imagemodel->ink, ix, iy ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); break; case IMAGEMODEL_PEN: if( !imageinfo_paint_line( imageinfo, imagemodel->ink, imagemodel->nib, ip->paint_last_x, ip->paint_last_y, ix, iy ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); im_invalidate( imageinfo_get( FALSE, imageinfo ) ); ip->paint_last_x = ix; ip->paint_last_y = iy; break; case IMAGEMODEL_LINE: /* rubberband */ break; case IMAGEMODEL_SMUDGE: /* Area to smudge in display cods. */ oper.left = -10; oper.top = -10; oper.width = 20; oper.height = 20; /* Translate to IMAGE cods. */ conversion_disp_to_im_rect( conv, &oper, &oper ); if( !imageinfo_paint_smudge( imageinfo, &oper, ip->paint_last_x, ip->paint_last_y, ix, iy ) ) iwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR ); im_invalidate( imageinfo_get( FALSE, imageinfo ) ); ip->paint_last_x = ix; ip->paint_last_y = iy; break; default: break; } } /* Main event loop. */ static gboolean imagepresent_event_cb( GtkWidget *widget, GdkEvent *ev, Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; gboolean handled; #ifdef EVENT printf( "imagepresent_event_cb %d\n", ev->type ); #endif /*EVENT*/ handled = FALSE; switch( ev->type ) { case GDK_BUTTON_PRESS: if( !GTK_WIDGET_HAS_FOCUS( GTK_WIDGET( ip ) ) ) gtk_widget_grab_focus( GTK_WIDGET( ip ) ); switch( ev->button.button ) { case 1: handled = imagepresent_left_press( ip, ev, ev->button.x, ev->button.y ); break; case 2: #ifdef EVENT printf( "button2 press: at %gx%g\n", ev->button.x, ev->button.y ); #endif /*EVENT*/ /* Switch to pan, for this drag. */ imagemodel->save_state = imagemodel->state; (void) imagemodel_set_state( imagemodel, IMAGEMODEL_PAN, NULL ); handled = imagepresent_left_press( ip, ev, ev->button.x, ev->button.y ); break; default: break; } break; case GDK_BUTTON_RELEASE: switch( ev->button.button ) { case 1: imagepresent_left_release( ip, ev, ev->button.x, ev->button.y ); break; case 2: #ifdef EVENT printf( "button2 release: at %gx%g\n", ev->button.x, ev->button.y ); #endif /*EVENT*/ /* Should always succeed. */ (void) imagemodel_set_state( imagemodel, imagemodel->save_state, NULL ); break; default: break; } break; case GDK_MOTION_NOTIFY: /* We're using motion hints, so we need to read the pointer to * get the next one. */ widget_update_pointer( GTK_WIDGET( ip ), ev ); ip->last_x = ev->motion.x; ip->last_y = ev->motion.y; if( ev->motion.state & GDK_BUTTON1_MASK || ev->motion.state & GDK_BUTTON2_MASK ) imagepresent_button_motion( ip, ev ); /* Update tick marks on rulers, if they're being drawn. */ if( GTK_WIDGET_VISIBLE( ip->hrule ) ) { imagepresent_hruler_rethink( ip ); imagepresent_vruler_rethink( ip ); } break; case GDK_ENTER_NOTIFY: ip->inside = TRUE; break; case GDK_LEAVE_NOTIFY: ip->inside = FALSE; break; default: break; } return( handled ); } static gboolean imagepresent_key_press_event_cb( GtkWidget *widget, GdkEventKey *event, Imagepresent *ip ) { Imagemodel *imagemodel = ip->imagemodel; Conversion *conv = imagemodel->conv; Rect *visible = &imagemodel->visible; GtkAdjustment *hadj = ip->hadj; GtkAdjustment *vadj = ip->vadj; gboolean handled; int i; #ifdef DEBUG printf( "imagepresent_key_press_event_cb\n" ); #endif /*DEBUG*/ handled = FALSE; switch( event->keyval ) { case GDK_Left: if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ) imagepresent_set_position( ip, visible->left - hadj->step_increment, visible->top ); else if( event->state & GDK_SHIFT_MASK ) imagepresent_set_position( ip, visible->left - hadj->page_increment, visible->top ); else if( event->state & GDK_CONTROL_MASK ) imagepresent_set_position( ip, 0, visible->top ); handled = TRUE; break; case GDK_Right: if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ) imagepresent_set_position( ip, visible->left + hadj->step_increment, visible->top ); else if( event->state & GDK_SHIFT_MASK ) imagepresent_set_position( ip, visible->left + hadj->page_increment, visible->top ); else if( event->state & GDK_CONTROL_MASK ) imagepresent_set_position( ip, conv->canvas.width, visible->top ); handled = TRUE; break; case GDK_Up: if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ) imagepresent_set_position( ip, visible->left, visible->top - vadj->step_increment ); else if( event->state & GDK_SHIFT_MASK ) imagepresent_set_position( ip, visible->left, visible->top - vadj->page_increment ); else if( event->state & GDK_CONTROL_MASK ) imagepresent_set_position( ip, visible->left, 0 ); handled = TRUE; break; case GDK_Down: if( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ) imagepresent_set_position( ip, visible->left, visible->top + vadj->step_increment ); else if( event->state & GDK_SHIFT_MASK ) imagepresent_set_position( ip, visible->left, visible->top + vadj->page_increment ); else if( event->state & GDK_CONTROL_MASK ) imagepresent_set_position( ip, visible->left, conv->canvas.height ); handled = TRUE; break; /* FIXME + and = are not always on the same key, of course :( */ case GDK_i: case GDK_plus: case GDK_equal: if( ip->inside ) imagepresent_zoom_in( ip, ip->last_x, ip->last_y ); else imagepresent_zoom_in_centre( ip ); handled = TRUE; break; case GDK_o: case GDK_minus: imagepresent_zoom_out( ip ); handled = TRUE; break; case GDK_0: conversion_set_mag( conv, 0 ); handled = TRUE; break; default: break; } /* Check the number zoom keys too. */ if( !handled ) for( i = 0; i < IM_NUMBER( imagepresent_keymap ); i++ ) if( event->keyval == imagepresent_keymap[i].keyval ) { int mask = event->state & GDK_CONTROL_MASK; int zoom = imagepresent_keymap[i].zoom; imagepresent_zoom_to( ip, mask ? -zoom : zoom ); handled = TRUE; break; } return( handled ); } /* ... and set the work window once that's there. */ static void imagepresent_realize_id_cb( Imagedisplay *id ) { iWindow *iwnd = IWINDOW( gtk_widget_get_toplevel( GTK_WIDGET( id ) ) ); iwindow_set_work_window( iwnd, GTK_WIDGET( id )->window ); } static void imagepresent_rulers_mm_cb( GtkWidget *wid, GtkWidget *host, Imagepresent *ip ) { ip->imagemodel->rulers_mm = gtk_check_menu_item_get_active( GTK_CHECK_MENU_ITEM( wid ) ); iobject_changed( IOBJECT( ip->imagemodel ) ); } static void imagepresent_rulers_offset_cb( GtkWidget *wid, GtkWidget *host, Imagepresent *ip ) { ip->imagemodel->rulers_offset = gtk_check_menu_item_get_active( GTK_CHECK_MENU_ITEM( wid ) ); iobject_changed( IOBJECT( ip->imagemodel ) ); } static void imagepresent_ruler_hide_cb( GtkWidget *wid, GtkWidget *host, Imagepresent *ip ) { imagemodel_set_rulers( ip->imagemodel, FALSE ); } static void imagepresent_init( Imagepresent *ip ) { GtkWidget *bar; GtkWidget *table; /* Basic init. */ ip->imagemodel = NULL; ip->dx = 0; ip->dy = 0; ip->last_x = 0; ip->last_y = 0; ip->inside = FALSE; ip->scroll_tid = 0; ip->u = 0; ip->v = 0; ip->regionview = NULL; ip->paint_last_x = 0; ip->paint_last_y = 0; ip->regionviews = NULL; ip->grabbed = NULL; /* Make main imagedisplay table. */ table = GTK_WIDGET( gtk_table_new( 2, 2, FALSE ) ); gtk_container_add( GTK_CONTAINER( ip ), table ); gtk_widget_show( table ); /* Make canvas. */ ip->id = imagedisplay_new( NULL ); GTK_WIDGET_SET_FLAGS( ip, GTK_CAN_FOCUS ); gtk_signal_connect( GTK_OBJECT( ip->id ), "realize", GTK_SIGNAL_FUNC( imagepresent_realize_id_cb ), NULL ); /* Press/release/motion-notify stuff. */ gtk_widget_add_events( GTK_WIDGET( ip->id ), GDK_KEY_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK ); gtk_signal_connect_after( GTK_OBJECT( ip->id ), "event", GTK_SIGNAL_FUNC( imagepresent_event_cb ), ip ); gtk_signal_connect( GTK_OBJECT( ip ), "key_press_event", GTK_SIGNAL_FUNC( imagepresent_key_press_event_cb ), ip ); ip->swin = GTK_SCROLLED_WINDOW( gtk_scrolled_window_new( NULL, NULL ) ); gtk_scrolled_window_add_with_viewport( ip->swin, GTK_WIDGET( ip->id ) ); gtk_scrolled_window_set_policy( ip->swin, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); ip->hadj = gtk_scrolled_window_get_hadjustment( ip->swin ); ip->vadj = gtk_scrolled_window_get_vadjustment( ip->swin ); gtk_signal_connect( GTK_OBJECT( ip->swin ), "scroll_event", GTK_SIGNAL_FUNC( imagepresent_scroll_event_cb ), ip ); gtk_signal_connect( GTK_OBJECT( ip->hadj ), "changed", GTK_SIGNAL_FUNC( imagepresent_hadj_changed_cb ), ip ); gtk_signal_connect( GTK_OBJECT( ip->hadj ), "value_changed", GTK_SIGNAL_FUNC( imagepresent_hadj_changed_cb ), ip ); gtk_signal_connect( GTK_OBJECT( ip->vadj ), "changed", GTK_SIGNAL_FUNC( imagepresent_vadj_changed_cb ), ip ); gtk_signal_connect( GTK_OBJECT( ip->vadj ), "value_changed", GTK_SIGNAL_FUNC( imagepresent_vadj_changed_cb ), ip ); bar = ip->swin->hscrollbar; g_assert( GTK_IS_SCROLLBAR( bar ) ); GTK_WIDGET_UNSET_FLAGS( bar, GTK_CAN_FOCUS ); bar = ip->swin->vscrollbar; g_assert( GTK_IS_SCROLLBAR( bar ) ); GTK_WIDGET_UNSET_FLAGS( bar, GTK_CAN_FOCUS ); /* Need one menu per image window (could have a single menu for all * windows, but then we'd have to set the state of the toggle buttons * before mapping) */ ip->ruler_menu = popup_build( _( "Ruler menu" ) ); popup_add_tog( ip->ruler_menu, _( "Rulers In _mm" ), POPUP_FUNC( imagepresent_rulers_mm_cb ) ); popup_add_tog( ip->ruler_menu, _( "Show _Offset" ), POPUP_FUNC( imagepresent_rulers_offset_cb ) ); menu_add_sep( ip->ruler_menu ); popup_add_but( ip->ruler_menu, GTK_STOCK_CLOSE, POPUP_FUNC( imagepresent_ruler_hide_cb ) ); /* Make rulers. */ ip->hrule = GTK_HRULER( gtk_hruler_new() ); gtk_ruler_set_metric( GTK_RULER( ip->hrule ), GTK_PIXELS ); GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( ip->hrule ), GTK_CAN_FOCUS ); gtk_widget_show( GTK_WIDGET( ip->hrule ) ); ip->vrule = GTK_VRULER( gtk_vruler_new() ); gtk_ruler_set_metric( GTK_RULER( ip->vrule ), GTK_PIXELS ); GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( ip->vrule ), GTK_CAN_FOCUS ); gtk_widget_show( GTK_WIDGET( ip->vrule ) ); ip->heb = GTK_EVENT_BOX( gtk_event_box_new() ); gtk_container_add( GTK_CONTAINER( ip->heb ), GTK_WIDGET( ip->hrule ) ); gtk_signal_connect( GTK_OBJECT( ip->heb ), "event", GTK_SIGNAL_FUNC( imagepresent_hruler_event ), ip ); popup_attach( GTK_WIDGET( ip->heb ), ip->ruler_menu, ip ); ip->veb = GTK_EVENT_BOX( gtk_event_box_new() ); gtk_container_add( GTK_CONTAINER( ip->veb ), GTK_WIDGET( ip->vrule ) ); gtk_signal_connect( GTK_OBJECT( ip->veb ), "event", GTK_SIGNAL_FUNC( imagepresent_vruler_event ), ip ); popup_attach( GTK_WIDGET( ip->veb ), ip->ruler_menu, ip ); /* Attach all widgets to table. */ gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( ip->heb ), 1, 2, 0, 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_FILL, 2, 2 ); gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( ip->veb ), 0, 1, 1, 2, GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 2, 2 ); gtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( ip->swin ), 1, 2, 1, 2, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 2, 2 ); gtk_widget_show( GTK_WIDGET( ip->id ) ); gtk_widget_show( GTK_WIDGET( ip->swin ) ); /* Set initial ruler visibility on first refresh from imagemodel. */ } GType imagepresent_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ImagepresentClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) imagepresent_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Imagepresent ), 32, /* n_preallocs */ (GInstanceInitFunc) imagepresent_init, }; type = g_type_register_static( GTK_TYPE_BIN, "Imagepresent", &info, 0 ); } return( type ); } /* The model has changed ... update! */ static void imagepresent_imagemodel_changed_cb( Imagemodel *imagemodel, Imagepresent *ip ) { if( ip->cntxt ) iwindow_cursor_context_set_cursor( ip->cntxt, imagepresent_cursors[imagemodel->state] ); widget_visible( GTK_WIDGET( ip->heb ), imagemodel->show_rulers ); widget_visible( GTK_WIDGET( ip->veb ), imagemodel->show_rulers ); imagepresent_hruler_rethink( ip ); imagepresent_vruler_rethink( ip ); } /* The model has a new imageinfo. */ static void imagepresent_imagemodel_imageinfo_changed_cb( Imagemodel *imagemodel, Imagepresent *ip ) { /* Reset our mode. We don't want to stay painting. */ if( imagemodel_state_paint( imagemodel->state ) ) imagemodel_set_state( imagemodel, IMAGEMODEL_SELECT, NULL ); } static void imagepresent_link( Imagepresent *ip, Imagemodel *imagemodel ) { ip->imagemodel = imagemodel; g_object_ref( G_OBJECT( ip->imagemodel ) ); iobject_sink( IOBJECT( ip->imagemodel ) ); g_signal_connect( G_OBJECT( imagemodel ), "changed", G_CALLBACK( imagepresent_imagemodel_changed_cb ), ip ); g_signal_connect( G_OBJECT( imagemodel ), "imageinfo_changed", G_CALLBACK( imagepresent_imagemodel_imageinfo_changed_cb ), ip ); imagedisplay_set_conversion( ip->id, imagemodel->conv ); if( imagemodel->iimage ) imagemodel->iimage->views = g_slist_prepend( imagemodel->iimage->views, ip ); } /* Make a new Imagepresent. */ Imagepresent * imagepresent_new( Imagemodel *imagemodel ) { Imagepresent *ip = g_object_new( TYPE_IMAGEPRESENT, NULL ); imagepresent_link( ip, imagemodel ); return( ip ); } /* Background scroller. */ static gboolean imagepresent_scroll_cb( Imagepresent *ip ) { imagepresent_set_position( ip, ip->imagemodel->visible.left + ip->u, ip->imagemodel->visible.top + ip->v ); return( TRUE ); } void imagepresent_scroll_start( Imagepresent *ip, int u, int v ) { if( !ip->scroll_tid ) ip->scroll_tid = g_timeout_add( 100, (GSourceFunc) imagepresent_scroll_cb, ip ); ip->u = u; ip->v = v; } void imagepresent_scroll_stop( Imagepresent *ip ) { IM_FREEF( g_source_remove, ip->scroll_tid ); ip->u = 0; ip->v = 0; } nip2-8.7.1/src/fontnameview.c0000644000175000017500000001013713351443023012755 00000000000000/* run the display for an arrow in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; static void fontnameview_link( View *view, Model *model, View *parent ) { Fontnameview *fontnameview = FONTNAMEVIEW( view ); VIEW_CLASS( parent_class )->link( view, model, parent ); if( GRAPHICVIEW( view )->sview ) gtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group, fontnameview->label ); } static void fontnameview_refresh( vObject *vobject ) { Fontnameview *fontnameview = FONTNAMEVIEW( vobject ); Fontname *fontname = FONTNAME( VOBJECT( vobject )->iobject ); #ifdef DEBUG printf( "fontnameview_refresh: " ); row_name_print( HEAPMODEL( fontname )->row ); printf( "\n" ); #endif /*DEBUG*/ if( vobject->iobject->caption ) set_glabel( fontnameview->label, _( "%s:" ), vobject->iobject->caption ); if( fontname->value ) fontbutton_set_font_name( fontnameview->fontbutton, fontname->value ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void fontnameview_class_init( FontnameviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = fontnameview_refresh; view_class->link = fontnameview_link; } static void fontnameview_changed_cb( Fontbutton *fontbutton, Fontnameview *fontnameview ) { Fontname *fontname = FONTNAME( VOBJECT( fontnameview )->iobject ); const char *font_name = fontbutton_get_font_name( fontbutton ); if( strcmp( font_name, fontname->value ) != 0 ) { IM_SETSTR( fontname->value, font_name ); classmodel_update( CLASSMODEL( fontname ) ); symbol_recalculate_all(); } } static void fontnameview_init( Fontnameview *fontnameview ) { GtkWidget *hbox; #ifdef DEBUG printf( "fontnameview_init\n" ); #endif /*DEBUG*/ hbox = gtk_hbox_new( FALSE, 12 ); gtk_box_pack_start( GTK_BOX( fontnameview ), hbox, TRUE, FALSE, 0 ); fontnameview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( fontnameview->label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( fontnameview->label ), 2, 7 ); gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( fontnameview->label ), FALSE, FALSE, 2 ); fontnameview->fontbutton = fontbutton_new(); gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( fontnameview->fontbutton ), TRUE, TRUE, 0 ); g_signal_connect( fontnameview->fontbutton, "changed", G_CALLBACK( fontnameview_changed_cb ), fontnameview ); gtk_widget_show_all( GTK_WIDGET( hbox ) ); } GtkType fontnameview_get_type( void ) { static GtkType fontnameview_type = 0; if( !fontnameview_type ) { static const GtkTypeInfo info = { "Fontnameview", sizeof( Fontnameview ), sizeof( FontnameviewClass ), (GtkClassInitFunc) fontnameview_class_init, (GtkObjectInitFunc) fontnameview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; fontnameview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( fontnameview_type ); } View * fontnameview_new( void ) { Fontnameview *fontnameview = gtk_type_new( TYPE_FONTNAMEVIEW ); return( VIEW( fontnameview ) ); } nip2-8.7.1/src/fontnameview.h0000644000175000017500000000314713351443023012765 00000000000000/* a fontname view in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_FONTNAMEVIEW (fontnameview_get_type()) #define FONTNAMEVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_FONTNAMEVIEW, Fontnameview )) #define FONTNAMEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_FONTNAMEVIEW, FontnameviewClass )) #define IS_FONTNAMEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FONTNAMEVIEW )) #define IS_FONTNAMEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_FONTNAMEVIEW )) typedef struct _Fontnameview { Graphicview parent_object; GtkWidget *label; Fontbutton *fontbutton; } Fontnameview; typedef struct _FontnameviewClass { GraphicviewClass parent_class; /* My methods. */ } FontnameviewClass; GtkType fontnameview_get_type( void ); View *fontnameview_new( void ); nip2-8.7.1/src/nipmarshal.h0000644000175000017500000000260413351443023012416 00000000000000 #ifndef __nip_MARSHAL_H__ #define __nip_MARSHAL_H__ #include G_BEGIN_DECLS /* VOID:OBJECT,INT (nipmarshal.list:25) */ extern void nip_VOID__OBJECT_INT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); /* VOID:DOUBLE,DOUBLE (nipmarshal.list:26) */ extern void nip_VOID__DOUBLE_DOUBLE (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); /* BOOLEAN:INT,INT (nipmarshal.list:27) */ extern void nip_BOOLEAN__INT_INT (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); G_END_DECLS #endif /* __nip_MARSHAL_H__ */ nip2-8.7.1/src/program.c0000644000175000017500000017042113351443023011725 00000000000000/* program window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG #define DEBUG_TREE */ #include "ip.h" /* Keep tools/kits in a treestore. Also pointers to managed objects. */ enum { NAME_COLUMN, /* Kit or tool name */ TOOL_POINTER_COLUMN, /* Pointer to tool */ KIT_POINTER_COLUMN, /* Pointer to kit (if no tool) */ N_COLUMNS }; static iWindowClass *parent_class = NULL; static GSList *program_all = NULL; static GtkWidget *program_menu = NULL; static Model * program_get_selected( Program *program ) { Model *model; if( program->tool ) model = MODEL( program->tool ); else if( program->kit ) model = MODEL( program->kit ); else model = NULL; return( model ); } static void program_info( Program *program, VipsBuf *buf ) { Model *model = program_get_selected( program ); vips_buf_appendf( buf, _( "Edit window" ) ); vips_buf_appendf( buf, "\n" ); vips_buf_appendf( buf, "dirty = \"%s\"\n", bool_to_char( program->dirty ) ); vips_buf_appendf( buf, "\n" ); if( model ) { iobject_info( IOBJECT( model ), buf ); vips_buf_appendf( buf, "\n" ); } } gboolean my_strcmp( const char *a, const char *b ) { if( a == b ) return( 0 ); if( !a ) return( -1 ); if( !b ) return( -1 ); return( strcmp( a, b ) ); } /* Remove this and any subsequent nodes at this level. */ static void program_refresh_trim( Program *program, GtkTreePath *path ) { GtkTreeIter iter; while( gtk_tree_model_get_iter( GTK_TREE_MODEL( program->store ), &iter, path ) ) { #ifdef DEBUG_TREE printf( "program_refresh_trim: removing %s\n", gtk_tree_path_to_string ( path ) ); #endif /*DEBUG_TREE*/ gtk_tree_store_remove( program->store, &iter ); } } static void program_refresh_update( Program *program, GtkTreePath *path, const char *name, Tool *tool, Toolkit *kit ) { GtkTreeIter iter; /* Update, or append if there's nothing to update. */ if( gtk_tree_model_get_iter( GTK_TREE_MODEL( program->store ), &iter, path ) ) { /* Node exists. */ char *store_name; Tool *store_tool; Toolkit *store_kit; gtk_tree_model_get( GTK_TREE_MODEL( program->store ), &iter, NAME_COLUMN, &store_name, TOOL_POINTER_COLUMN, &store_tool, KIT_POINTER_COLUMN, &store_kit, -1 ); if( tool != store_tool || kit != store_kit || my_strcmp( name, store_name ) != 0 ) { #ifdef DEBUG_TREE printf( "program_refresh_update: updating \"%s\"\n", name ); #endif /*DEBUG_TREE*/ gtk_tree_store_set( program->store, &iter, NAME_COLUMN, name, TOOL_POINTER_COLUMN, tool, KIT_POINTER_COLUMN, kit, -1 ); } g_free( store_name ); /* Make sure tool nodes have no children ... this can happen * after some drags. */ if( tool && gtk_tree_model_iter_has_child( GTK_TREE_MODEL( program->store ), &iter ) ) { GtkTreePath *child_path; child_path = gtk_tree_path_copy( path ); gtk_tree_path_down( child_path ); program_refresh_trim( program, child_path ); gtk_tree_path_free( child_path ); } } else { GtkTreeIter parent_iter; GtkTreeIter *piter; #ifdef DEBUG_TREE printf( "program_refresh_update: creating \"%s\"\n", name ); #endif /*DEBUG_TREE*/ /* Get an iter for the parent node, if it exists. */ if( gtk_tree_path_get_depth( path ) > 1 ) { GtkTreePath *parent_path; parent_path = gtk_tree_path_copy( path ); gtk_tree_path_up( parent_path ); gtk_tree_model_get_iter( GTK_TREE_MODEL( program->store ), &parent_iter, parent_path ); gtk_tree_path_free( parent_path ); piter = &parent_iter; } else piter = NULL; gtk_tree_store_append( program->store, &iter, piter ); gtk_tree_store_set( program->store, &iter, NAME_COLUMN, name, TOOL_POINTER_COLUMN, tool, KIT_POINTER_COLUMN, kit, -1 ); } } static void * program_refresh_tool( Tool *tool, Program *program, GtkTreePath *path ) { if( tool->toolitem ) program_refresh_update( program, path, IOBJECT( tool )->name, tool, tool->kit ); else program_refresh_update( program, path, IOBJECT( tool )->name, tool, tool->kit ); gtk_tree_path_next( path ); return( NULL ); } static void * program_refresh_kit( Toolkit *kit, Program *program, GtkTreePath *path ) { program_refresh_update( program, path, IOBJECT( kit )->name, NULL, kit ); gtk_tree_path_down( path ); toolkit_map( kit, (tool_map_fn) program_refresh_tool, program, path ); /* Remove any unused tool nodes. */ program_refresh_trim( program, path ); gtk_tree_path_up( path ); gtk_tree_path_next( path ); return( NULL ); } /* Update the title. */ static void program_title( Program *program ) { char txt[512]; VipsBuf buf = VIPS_BUF_STATIC( txt ); if( program->kit && FILEMODEL( program->kit )->modified ) vips_buf_appendf( &buf, "*" ); vips_buf_appends( &buf, IOBJECT( program->kitg )->name ); if( program->kit ) vips_buf_appendf( &buf, " - %s", IOBJECT( program->kit )->name ); if( program->tool ) { vips_buf_appendf( &buf, " - %s", IOBJECT( program->tool )->name ); if( program->dirty ) { vips_buf_appendf( &buf, " [" ); vips_buf_appendf( &buf, _( "modified" ) ); vips_buf_appendf( &buf, "]" ); } } iwindow_set_title( IWINDOW( program ), "%s", vips_buf_all( &buf ) ); } typedef struct _ProgramRowLookupInfo { Program *program; Model *model; GtkTreeIter *return_iter; gboolean found; } ProgramRowLookupInfo; static gboolean program_row_lookup_sub( GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, ProgramRowLookupInfo *info ) { Tool *tool; Toolkit *kit; gtk_tree_model_get( model, iter, TOOL_POINTER_COLUMN, &tool, KIT_POINTER_COLUMN, &kit, -1 ); if( (void *) tool == (void *) info->model || (void *) kit == (void *) info->model ) { *info->return_iter = *iter; info->found = TRUE; return( TRUE ); } return( FALSE ); } /* Point return_iter at the row containing a pointer to the Model. */ static gboolean program_row_lookup( Program *program, Model *model, GtkTreeIter *return_iter ) { ProgramRowLookupInfo info; info.program = program; info.model = model; info.return_iter = return_iter; info.found = FALSE; gtk_tree_model_foreach( GTK_TREE_MODEL( program->store ), (GtkTreeModelForeachFunc) program_row_lookup_sub, &info ); return( info.found ); } static gboolean program_refresh_timeout( gpointer user_data ) { Program *program = PROGRAM( user_data ); iWindow *iwnd = IWINDOW( program ); Model *model = program_get_selected( program ); GtkTreeSelection *select = gtk_tree_view_get_selection( GTK_TREE_VIEW( program->tree ) ); GtkTreePath *path; GtkTreeIter iter; GtkAction *action; program->refresh_timeout = 0; #ifdef DEBUG printf( "program_refresh_timeout\n" ); #endif /*DEBUG*/ /* Block insert/delete/select signals. */ g_signal_handler_block( G_OBJECT( program->store ), program->row_deleted_sid ); g_signal_handler_block( G_OBJECT( program->store ), program->row_inserted_sid ); g_signal_handler_block( G_OBJECT( select ), program->select_changed_sid ); /* Rebuild the tree widget. */ path = gtk_tree_path_new(); gtk_tree_path_down( path ); toolkitgroup_map( program->kitg, (toolkit_map_fn) program_refresh_kit, program, path ); /* Remove any unused kit nodes. */ program_refresh_trim( program, path ); gtk_tree_path_free( path ); g_signal_handler_unblock( G_OBJECT( program->store ), program->row_inserted_sid ); g_signal_handler_unblock( G_OBJECT( program->store ), program->row_deleted_sid ); /* Update title bar. */ program_title( program ); /* Scroll to current kit or tool. */ if( model && program_row_lookup( program, model, &iter ) ) { path = gtk_tree_model_get_path( GTK_TREE_MODEL( program->store ), &iter ); /* Only expand tools ... we want to be able to select kits * without expansion. */ if( IS_TOOL( model ) ) gtk_tree_view_expand_to_path( GTK_TREE_VIEW( program->tree ), path ); gtk_tree_view_set_cursor( GTK_TREE_VIEW( program->tree ), path, NULL, FALSE ); gtk_tree_path_free( path ); } else gtk_tree_selection_unselect_all( select ); g_signal_handler_unblock( G_OBJECT( select ), program->select_changed_sid ); action = gtk_action_group_get_action( iwnd->action_group, "DefBrowser" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), program->rpane->open ); return( FALSE ); } /* Schedule an update for all our widgets. */ static void program_refresh( Program *program ) { IM_FREEF( g_source_remove, program->refresh_timeout ); /* 10ms to make sure we run after idle (is this right?) */ program->refresh_timeout = g_timeout_add( 10, (GSourceFunc) program_refresh_timeout, program ); } /* Break the tool & kit links. */ static void program_detach( Program *program ) { if( program->tool ) { program->pos = -1; FREESID( program->tool_destroy_sid, program->tool ); program->tool = NULL; } if( program->kit ) { FREESID( program->kit_destroy_sid, program->kit ); program->kit = NULL; } program_refresh( program ); } static void program_find_reset( Program *program ) { FREESID( program->find_sym_destroy_sid, program->find_sym ); program->find_sym = NULL; program->find_start = 0; program->find_end = 0; } static void program_find_destroy_cb( Symbol *sym, Program *program ) { program_find_reset( program ); } static void program_find_note( Program *program, Symbol *sym, int start, int end ) { program_find_reset( program ); program->find_sym = sym; program->find_sym_destroy_sid = g_signal_connect( G_OBJECT( sym ), "destroy", G_CALLBACK( program_find_destroy_cb ), program ); program->find_start = start; program->find_end = end; } static gboolean program_find_pos( Program *program, const char *text, int *start, int *end ) { #ifdef HAVE_GREGEX if( program->regexp ) { GMatchInfo *match; g_regex_match( program->comp, text, 0, &match ); if( g_match_info_fetch_pos( match, 0, start, end ) ) { g_match_info_free( match ); return( TRUE ); } g_match_info_free( match ); } else #endif /*HAVE_GREGEX*/ if( program->csens ) { char *p; if( (p = strstr( text, program->search )) ) { *start = p - text; *end = *start + strlen( program->search ); return( TRUE ); } } else { char *p; if( (p = my_strcasestr( text, program->search )) ) { *start = p - text; *end = *start + strlen( program->search ); return( TRUE ); } } return( FALSE ); } static void * program_find_tool( Tool *tool, Program *program, gboolean *skipping ) { Symbol *sym; if( tool->type != TOOL_SYM ) return( NULL ); sym = tool->sym; /* In search mode? Check if we've found the start point. */ if( *skipping ) { if( sym == program->find_sym || !program->find_sym ) *skipping = FALSE; } /* Reached start point? Check from start onwards. */ if( !*skipping ) { if( sym->expr && sym->expr->compile && program->find_start < strlen( sym->expr->compile->text ) ) { int start, end; if( program_find_pos( program, sym->expr->compile->text + program->find_start, &start, &end ) ) { program_find_note( program, sym, start + program->find_start, end + program->find_start ); return( tool ); } } program_find_reset( program ); } return( NULL ); } static void * program_find_toolkit( Toolkit *kit, Program *program, gboolean *skipping ) { return( icontainer_map( ICONTAINER( kit ), (icontainer_map_fn) program_find_tool, program, &skipping ) ); } static gboolean program_find( Program *program ) { gboolean skipping = TRUE; if( toolkitgroup_map( program->kitg, (toolkit_map_fn) program_find_toolkit, program, &skipping ) ) return( TRUE ); return( FALSE ); } static void program_destroy( GtkObject *object ) { Program *program; g_return_if_fail( object != NULL ); g_return_if_fail( IS_PROGRAM( object ) ); program = PROGRAM( object ); #ifdef DEBUG printf( "program_destroy\n" ); #endif /*DEBUG*/ /* My instance destroy stuff. */ program_detach( program ); UNREF( program->store ); FREESID( program->kitgroup_changed_sid, program->kitg ); FREESID( program->kitgroup_destroy_sid, program->kitg ); IM_FREEF( g_free, program->search ); #ifdef HAVE_GREGEX IM_FREEF( g_regex_unref, program->comp ); #endif /*HAVE_GREGEX*/ program_find_reset( program ); IM_FREEF( g_source_remove, program->refresh_timeout ); program_all = g_slist_remove( program_all, program ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void program_edit_dia_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Tool *tool = TOOL( client ); Stringset *ss = STRINGSET( iwnd ); StringsetChild *name = stringset_child_get( ss, _( "Name" ) ); StringsetChild *file = stringset_child_get( ss, _( "Filename" ) ); char name_text[1024]; char file_text[1024]; if( !get_geditable_string( name->entry, name_text, 1024 ) || !get_geditable_filename( file->entry, file_text, 1024 ) ) { nfn( sys, IWINDOW_ERROR ); return; } if( !tool_new_dia( tool->kit, ICONTAINER( tool )->pos, name_text, file_text ) ) { nfn( sys, IWINDOW_ERROR ); return; } nfn( sys, IWINDOW_YES ); } static void program_edit_dia( Program *program, Tool *tool ) { GtkWidget *ss = stringset_new(); g_assert( tool && tool->type == TOOL_DIA ); stringset_child_new( STRINGSET( ss ), _( "Name" ), IOBJECT( tool )->name, _( "Menu item text" ) ); stringset_child_new( STRINGSET( ss ), _( "Filename" ), FILEMODEL( tool )->filename, _( "Load column from this file" ) ); iwindow_set_title( IWINDOW( ss ), _( "Edit Column Item \"%s\"" ), IOBJECT( tool )->name ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, tool ); idialog_add_ok( IDIALOG( ss ), program_edit_dia_done_cb, _( "Set column item" ) ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( program ) ); idialog_set_iobject( IDIALOG( ss ), IOBJECT( tool ) ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); } static void program_edit_object_cb( GtkWidget *menu, Program *program ) { Model *model = program_get_selected( program ); if( model && IS_TOOL( model ) && TOOL( model )->type == TOOL_DIA ) program_edit_dia( program, program->tool ); } static gboolean program_is_saveable( Model *model ) { if( !IS_TOOLKIT( model ) ) { error_top( _( "Unable to save." ) ); error_sub( _( "You can only save toolkits, not tools." ) ); return( FALSE ); } if( IS_TOOLKIT( model ) && TOOLKIT( model )->pseudo ) { error_top( _( "Unable to save." ) ); error_sub( _( "You can't save auto-generated toolkits." ) ); return( FALSE ); } return( TRUE ); } static void program_save_object_cb( GtkWidget *menu, Program *program ) { Model *model = program_get_selected( program ); if( model ) { if( program_is_saveable( model ) ) filemodel_inter_save( IWINDOW( program ), FILEMODEL( model ) ); else iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_ERROR ); } } static void program_saveas_object_cb( GtkWidget *menu, Program *program ) { Model *model = program_get_selected( program ); if( model ) { if( program_is_saveable( model ) ) filemodel_inter_saveas( IWINDOW( program ), FILEMODEL( model ) ); else iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_ERROR ); } } static void program_remove_object_cb( GtkWidget *menu, Program *program ) { Model *model = program_get_selected( program ); if( model ) model_check_destroy( GTK_WIDGET( program ), model, NULL ); } static void program_class_init( ProgramClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidget *pane; parent_class = g_type_class_peek_parent( class ); object_class->destroy = program_destroy; /* Create signals. */ /* Init methods. */ pane = program_menu = popup_build( _( "Toolkit menu" ) ); popup_add_but( pane, _( "_Edit" ), POPUP_FUNC( program_edit_object_cb ) ); popup_add_but( pane, GTK_STOCK_SAVE, POPUP_FUNC( program_save_object_cb ) ); popup_add_but( pane, GTK_STOCK_SAVE_AS, POPUP_FUNC( program_saveas_object_cb ) ); menu_add_sep( pane ); popup_add_but( pane, GTK_STOCK_DELETE, POPUP_FUNC( program_remove_object_cb ) ); } /* Some kit/tool has changed ... update everything. */ static void program_kitgroup_changed( Model *model, Program *program ) { #ifdef DEBUG printf( "program_kitgroup_changed:\n" ); #endif /*DEBUG*/ program_refresh( program ); } static void program_kitgroup_destroy( Model *model, Program *program ) { #ifdef DEBUG printf( "program_kitgroup_destroy:\n" ); #endif /*DEBUG*/ /* Our toolkitgroup has gone! Give up on the world. */ program->kitgroup_changed_sid = 0; program->kitgroup_destroy_sid = 0; iwindow_kill( IWINDOW( program ) ); } static void program_init( Program *program ) { program->kitg = NULL; program->text = NULL; program->dirty = FALSE; program->text_hash = 0; program->tree = NULL; program->store = NULL; program->pane_position = PROGRAM_PANE_POSITION; program->rpane_open = FALSE; program->rpane_position = 500; program->refresh_timeout = 0; program->kitgroup_changed_sid = 0; program->kitgroup_destroy_sid = 0; program->kit = NULL; program->kit_destroy_sid = 0; program->tool = NULL; program->pos = -1; program->tool_destroy_sid = 0; program->search = NULL; program->csens = FALSE; program->fromtop = TRUE; #ifdef HAVE_GREGEX program->regexp = FALSE; program->comp = NULL; #endif /*HAVE_GREGEX*/ } GtkType program_get_type( void ) { static GtkType program_type = 0; if( !program_type ) { static const GtkTypeInfo info = { "Program", sizeof( Program ), sizeof( ProgramClass ), (GtkClassInitFunc) program_class_init, (GtkObjectInitFunc) program_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; program_type = gtk_type_unique( TYPE_IWINDOW, &info ); } return( program_type ); } /* The kit we have selected has been destroyed. */ static void program_kit_destroy( Toolkit *kit, Program *program ) { #ifdef DEBUG printf( "program_kit_destroy:\n" ); #endif /*DEBUG*/ g_assert( program->kit == kit ); program_detach( program ); program_refresh( program ); } /* Is a character one of those allowed in nip2 identifers? */ static gboolean is_ident( int ch ) { if( isalnum( ch ) || ch == '_' || ch == '\'' ) return( TRUE ); return( FALSE ); } static void program_text_cursor_position( GtkTextBuffer *buffer, GParamSpec *pspec, Program *program ) { gboolean editable = !program->kit || !program->kit->pseudo; if( program->rpane_open && editable ) { /* Fetch characters left of the cursor while we have stuff * that could be an identifier. */ GtkTextIter start; GtkTextIter cursor; GtkTextIter end; char *line; char *p, *q, *r; /* Get iters for start / cursor / end of line. */ gtk_text_buffer_get_iter_at_mark( buffer, &cursor, gtk_text_buffer_get_insert( buffer ) ); gtk_text_buffer_get_iter_at_line_index( buffer, &start, gtk_text_iter_get_line( &cursor ), 0 ); gtk_text_buffer_get_iter_at_line_index( buffer, &end, gtk_text_iter_get_line( &cursor ), 0 ); gtk_text_iter_forward_to_line_end( &end ); line = gtk_text_buffer_get_text( buffer, &start, &end, FALSE ); p = line + gtk_text_iter_get_line_index( &cursor ); /* Search back from the cursor for the first non-identifier * char. */ for( q = p - 1; q >= line && is_ident( *q ); q-- ) ; q += 1; for( r = p; r < line + strlen( line ) && is_ident( *r ); r++ ) ; *r= '\0'; if( strlen( q ) > 1 ) defbrowser_set_filter( program->defbrowser, q ); g_free( line ); } } static void program_text_changed( GtkTextBuffer *buffer, Program *program ) { if( !program->dirty ) { program->dirty = TRUE; program_refresh( program ); } } static void program_set_text( Program *program, const char *text, gboolean editable ) { GtkTextView *text_view = GTK_TEXT_VIEW( program->text ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); guint text_hash = g_str_hash( text ); if( text_hash != program->text_hash ) { /* Stop ::changed from firing, we don't want it to update the * def browser filter. */ g_signal_handlers_block_by_func( text_buffer, G_CALLBACK( program_text_cursor_position ), program ); text_view_set_text( text_view, text, editable ); program->text_hash = text_hash; g_signal_handlers_unblock_by_func( text_buffer, G_CALLBACK( program_text_cursor_position ), program ); } program->dirty = FALSE; } /* Swap text for text for tool. */ static void program_set_text_tool( Program *program, Tool *tool ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); switch( tool->type ) { case TOOL_DIA: case TOOL_SEP: program_set_text( program, "", FALSE ); break; case TOOL_SYM: switch( tool->sym->type ) { case SYM_EXTERNAL: call_usage( &buf, tool->sym->function ); program_set_text( program, vips_buf_all( &buf ), FALSE ); break; case SYM_BUILTIN: builtin_usage( &buf, tool->sym->builtin ); program_set_text( program, vips_buf_all( &buf ), FALSE ); break; case SYM_VALUE: program_set_text( program, tool->sym->expr->compile->text, TRUE ); break; default: g_assert( FALSE ); } break; default: g_assert( FALSE ); } } /* The sym we are editing has been destroyed. */ static void program_tool_destroy( Tool *tool, Program *program ) { #ifdef DEBUG printf( "program_tool_destroy:\n" ); #endif /*DEBUG*/ g_assert( program->tool == tool ); program_detach( program ); program_set_text( program, "", TRUE ); program_refresh( program ); } /* Pick a kit ... but don't touch the text yet. */ static void program_select_kit_sub( Program *program, Toolkit *kit ) { /* None? Pick "untitled". */ if( !kit ) kit = toolkit_by_name( program->kitg, "untitled" ); program_detach( program ); if( kit ) { program->kit = kit; program->kit_destroy_sid = g_signal_connect( G_OBJECT( kit ), "destroy", G_CALLBACK( program_kit_destroy ), program ); } program_refresh( program ); } /* Select a new kit in the tree. */ static void program_select_kit( Program *program, Toolkit *kit ) { program_select_kit_sub( program, kit ); program_set_text( program, "", TRUE ); program_refresh( program ); } /* Select a tool in the tree. */ static void program_select_tool( Program *program, Tool *tool ) { program_detach( program ); if( tool ) { program_select_kit_sub( program, tool->kit ); program->tool = tool; program->pos = ICONTAINER( tool )->pos; program->tool_destroy_sid = g_signal_connect( G_OBJECT( tool ), "destroy", G_CALLBACK( program_tool_destroy ), program ); program_set_text_tool( program, tool ); } program_refresh( program ); } static char * program_get_text( Program *program ) { GtkTextView *text_view = GTK_TEXT_VIEW( program->text ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); GtkTextIter start_iter; GtkTextIter end_iter; char *text; gtk_text_buffer_get_start_iter( text_buffer, &start_iter ); gtk_text_buffer_get_end_iter( text_buffer, &end_iter ); text = gtk_text_buffer_get_text( text_buffer, &start_iter, &end_iter, FALSE ); return( text ); } /* Read and parse the text. */ static gboolean program_parse( Program *program ) { char *txt; char buffer[MAX_STRSIZE]; Compile *compile; if( !program->dirty ) return( TRUE ); /* Irritatingly, we need to append a ';'. Also, update the hash, so we * don't set the same text back again if we can help it. */ txt = program_get_text( program ); program->text_hash = g_str_hash( txt ); im_snprintf( buffer, MAX_STRSIZE, "%s;", txt ); IM_FREEF( g_free, txt ); if( strspn( buffer, WHITESPACE ";" ) == strlen( buffer ) ) return( TRUE ); /* Make sure we've got a kit. */ if( !program->kit ) program_select_kit_sub( program, program->kit ); compile = program->kit->kitg->root->expr->compile; #ifdef DEBUG printf( "program_parse: parsing to kit \"%s\", pos %d\n", IOBJECT( program->kit )->name, program->pos ); #endif /*DEBUG*/ /* ... and parse the new text into it. */ attach_input_string( buffer ); if( !parse_onedef( program->kit, program->pos ) ) { text_view_select_text( GTK_TEXT_VIEW( program->text ), input_state.charpos - yyleng, input_state.charpos ); return( FALSE ); } program->dirty = FALSE; if( program->kit ) filemodel_set_modified( FILEMODEL( program->kit ), TRUE ); /* Reselect last_sym, the last thing the parser saw. */ if( compile->last_sym && compile->last_sym->tool ) program_select_tool( program, compile->last_sym->tool ); symbol_recalculate_all(); return( TRUE ); } static void program_tool_new_action_cb( GtkAction *action, Program *program ) { /* Existing text changed? Parse it. */ if( program->dirty && !program_parse( program ) ) { iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_ERROR ); return; } program_select_kit( program, program->kit ); } static void program_toolkit_new_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Stringset *ss = STRINGSET( iwnd ); StringsetChild *name = stringset_child_get( ss, _( "Name" ) ); StringsetChild *caption = stringset_child_get( ss, _( "Caption" ) ); Program *program = PROGRAM( client ); Toolkit *kit; char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); char name_text[1024]; char caption_text[1024]; if( !get_geditable_name( name->entry, name_text, 1024 ) || !get_geditable_string( caption->entry, caption_text, 1024 ) ) { nfn( sys, IWINDOW_ERROR ); return; } /* Make a filename from the name ... user start directory. */ vips_buf_appendf( &buf, "$SAVEDIR" G_DIR_SEPARATOR_S "start" G_DIR_SEPARATOR_S "%s.def", name_text ); kit = toolkit_new_filename( main_toolkitgroup, vips_buf_all( &buf ) ); /* Set caption. */ if( strspn( caption_text, WHITESPACE ) != strlen( caption_text ) ) iobject_set( IOBJECT( kit ), NULL, caption_text ); else iobject_set( IOBJECT( kit ), NULL, "untitled" ); program_select_kit( program, kit ); nfn( sys, IWINDOW_YES ); } static void program_toolkit_new_action_cb( GtkAction *action, Program *program ) { GtkWidget *ss = stringset_new(); stringset_child_new( STRINGSET( ss ), _( "Name" ), "", _( "Set toolkit name here" ) ); stringset_child_new( STRINGSET( ss ), _( "Caption" ), "", _( "Set toolkit caption here" ) ); iwindow_set_title( IWINDOW( ss ), _( "New Toolkit" ) ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, program ); idialog_add_ok( IDIALOG( ss ), program_toolkit_new_done_cb, _( "Create" ) ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( program ) ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); } static gboolean program_check_kit( Program *program ) { if( !program->kit ) { error_top( _( "Nothing selected." ) ); error_sub( "%s", _( "No toolkit selected." ) ); iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO ); return( FALSE ); } return( TRUE ); } static void program_separator_new_action_cb( GtkAction *action, Program *program ) { Tool *tool; int pos; if( !program_check_kit( program ) ) return; pos = icontainer_pos_last( ICONTAINER( program->kit ) ); tool = tool_new_sep( program->kit, pos + 1 ); program_select_tool( program, tool ); } static void program_column_item_new_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Stringset *ss = STRINGSET( iwnd ); StringsetChild *name = stringset_child_get( ss, _( "Name" ) ); StringsetChild *file = stringset_child_get( ss, _( "Filename" ) ); Program *program = PROGRAM( client ); Tool *tool; int pos; char name_text[1024]; char file_text[1024]; if( !get_geditable_name( name->entry, name_text, 1024 ) || !get_geditable_filename( file->entry, file_text, 1024 ) ) { nfn( sys, IWINDOW_ERROR ); return; } pos = icontainer_pos_last( ICONTAINER( program->kit ) ); tool = tool_new_dia( program->kit, pos + 1, name_text, file_text ); program_select_tool( program, tool ); nfn( sys, IWINDOW_YES ); } static void program_column_item_new_action_cb( GtkAction *action, Program *program ) { GtkWidget *ss; if( !program_check_kit( program ) ) return; ss = stringset_new(); stringset_child_new( STRINGSET( ss ), _( "Name" ), "", _( "Display this name" ) ); stringset_child_new( STRINGSET( ss ), _( "Filename" ), "", _( "Load this file" ) ); iwindow_set_title( IWINDOW( ss ), "New Column Item" ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, program ); idialog_add_ok( IDIALOG( ss ), program_column_item_new_done_cb, _( "Create" ) ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( program ) ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); } static void program_program_new_action_cb( GtkAction *action, Program *program ) { Program *program2; program2 = program_new( program->kitg ); gtk_widget_show( GTK_WIDGET( program2 ) ); } static void * program_load_file_fn( Filesel *filesel, const char *filename, Program *program, void *b ) { Toolkit *kit; if( !(kit = toolkit_new_from_file( main_toolkitgroup, filename )) ) return( filesel ); program_select_kit( program, kit ); return( NULL ); } /* Callback from load browser. */ static void program_load_file_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Program *program = PROGRAM( client ); if( filesel_map_filename_multi( filesel, (FileselMapFn) program_load_file_fn, program, NULL ) ) { nfn( sys, IWINDOW_ERROR ); return; } symbol_recalculate_all(); nfn( sys, IWINDOW_YES ); } static void program_open_action_cb( GtkAction *action, Program *program ) { GtkWidget *filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Load Definition" ) ); filesel_set_flags( FILESEL( filesel ), FALSE, FALSE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_definition, 0 ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( program ) ); filesel_set_done( FILESEL( filesel ), program_load_file_cb, program ); filesel_set_multi( FILESEL( filesel ), TRUE ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } static void program_save_action_cb( GtkAction *action, Program *program ) { if( !program_check_kit( program ) ) return; filemodel_inter_save( IWINDOW( program ), FILEMODEL( program->kit ) ); } static void program_save_as_action_cb( GtkAction *action, Program *program ) { if( !program_check_kit( program ) ) return; filemodel_inter_saveas( IWINDOW( program ), FILEMODEL( program->kit ) ); } static void program_process_action_cb( GtkAction *action, Program *program ) { if( !program_parse( program ) ) iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_ERROR ); } static void program_reload_menus_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { main_reload(); symbol_recalculate_all(); nfn( sys, IWINDOW_YES ); } /* Reload all menus. */ static void program_reload_action_cb( GtkAction *action, Program *program ) { box_yesno( GTK_WIDGET( program ), program_reload_menus_cb, iwindow_true_cb, NULL, iwindow_notify_null, NULL, _( "Reload" ), _( "Reload startup objects?" ), _( "Would you like to reload all startup menus, workspaces " "and plugins now? This may take a few seconds." ) ); } static void program_cut_action_cb( GtkAction *action, Program *program ) { GtkTextView *text_view = GTK_TEXT_VIEW( program->text ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); GtkClipboard *clipboard = gtk_widget_get_clipboard( GTK_WIDGET( text_view ), GDK_SELECTION_CLIPBOARD ); gboolean editable = !program->kit || !program->kit->pseudo; gtk_text_buffer_cut_clipboard( text_buffer, clipboard, editable ); } static void program_copy( Program *program ) { GtkTextView *text_view = GTK_TEXT_VIEW( program->text ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); GtkClipboard *clipboard = gtk_widget_get_clipboard( GTK_WIDGET( text_view ), GDK_SELECTION_CLIPBOARD ); gtk_text_buffer_copy_clipboard( text_buffer, clipboard ); } static void program_copy_action_cb( GtkAction *action, Program *program ) { program_copy( program ); } static void program_paste_action_cb( GtkAction *action, Program *program ) { GtkTextView *text_view = GTK_TEXT_VIEW( program->text ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); GtkClipboard *clipboard = gtk_widget_get_clipboard( GTK_WIDGET( text_view ), GDK_SELECTION_CLIPBOARD ); gboolean editable = !program->kit || !program->kit->pseudo; gtk_text_buffer_paste_clipboard( text_buffer, clipboard, NULL, editable ); } static void program_delete_action_cb( GtkAction *action, Program *program ) { GtkTextView *text_view = GTK_TEXT_VIEW( program->text ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); gboolean editable = !program->kit || !program->kit->pseudo; gtk_text_buffer_delete_selection( text_buffer, TRUE, editable ); } static void program_select_all_action_cb( GtkAction *action, Program *program ) { text_view_select_text( GTK_TEXT_VIEW( program->text ), 0, -1 ); } static void program_deselect_all_action_cb( GtkAction *action, Program *program ) { GtkTextView *text_view = GTK_TEXT_VIEW( program->text ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); GtkTextMark *mark = gtk_text_buffer_get_insert( text_buffer ); GtkTextIter iter; gtk_text_buffer_get_iter_at_mark( text_buffer, &iter, mark ); gtk_text_buffer_select_range( text_buffer, &iter, &iter ); } static void program_remove_tool_action_cb( GtkAction *action, Program *program ) { Model *model = program_get_selected( program ); if( model && IS_TOOL( model ) ) model_check_destroy( GTK_WIDGET( program ), model, NULL ); else { error_top( _( "No tool selected" ) ); iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO ); } } static void program_remove_toolkit_action_cb( GtkAction *action, Program *program ) { if( !program_check_kit( program ) ) return; model_check_destroy( GTK_WIDGET( program ), MODEL( program->kit ), NULL ); } static void program_find_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Find *find = FIND( iwnd ); Program *program = PROGRAM( client ); IM_FREEF( g_free, program->search ); program->search = gtk_editable_get_chars( GTK_EDITABLE( find->search ), 0, -1 ); program->csens = GTK_TOGGLE_BUTTON( find->csens )->active; program->fromtop = GTK_TOGGLE_BUTTON( find->fromtop )->active; #ifdef HAVE_GREGEX program->regexp = GTK_TOGGLE_BUTTON( find->regexp )->active; if( program->regexp ) { GRegexCompileFlags cflags = 0; GRegexMatchFlags mflags = 0; if( !program->csens ) cflags |= G_REGEX_CASELESS; IM_FREEF( g_regex_unref, program->comp ); if( !(program->comp = g_regex_new( program->search, cflags, mflags, NULL )) ) { error_top( _( "Parse error." ) ); error_sub( _( "Bad regular expression." ) ); nfn( sys, IWINDOW_ERROR ); return; } } #endif /*HAVE_GREGEX*/ if( program->fromtop ) program_find_reset( program ); else program->find_start += 1; if( program_find( program ) ) { program_select_tool( program, program->find_sym->tool ); text_view_select_text( GTK_TEXT_VIEW( program->text ), program->find_start, program->find_end ); } else { error_top( _( "Not found." ) ); error_sub( _( "No match found for \"%s\"." ), program->search ); nfn( sys, IWINDOW_ERROR ); return; } nfn( sys, IWINDOW_YES ); } static void program_find_action_cb( GtkAction *action, Program *program ) { GtkWidget *find = find_new(); iwindow_set_title( IWINDOW( find ), _( "Find in all Toolkits" ) ); idialog_set_callbacks( IDIALOG( find ), iwindow_true_cb, NULL, NULL, program ); idialog_add_ok( IDIALOG( find ), program_find_done_cb, GTK_STOCK_FIND ); iwindow_set_parent( IWINDOW( find ), GTK_WIDGET( program ) ); idialog_set_cancel_text( IDIALOG( find ), GTK_STOCK_CLOSE ); iwindow_build( IWINDOW( find ) ); if( program->search ) set_gentry( FIND( find )->search, "%s", program->search ); set_tooltip( FIND( find )->search, _( "Enter search string here" ) ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( FIND( find )->csens ), program->csens ); #ifdef HAVE_GREGEX gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( FIND( find )->regexp ), program->regexp ); #endif /*HAVE_GREGEX*/ gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( FIND( find )->fromtop ), program->fromtop ); gtk_widget_show( find ); } static void program_find_again_action_cb( GtkAction *action, Program *program ) { if( !program->search ) return; if( program->find_sym ) program->find_start += 1; if( program_find( program ) ) { program_select_tool( program, program->find_sym->tool ); text_view_select_text( GTK_TEXT_VIEW( program->text ), program->find_start, program->find_end ); } else { error_top( _( "Not found." ) ); iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO ); } } static void program_goto_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Program *program = PROGRAM( client ); Stringset *ss = STRINGSET( iwnd ); StringsetChild *name = stringset_child_get( ss, _( "Name" ) ); Symbol *sym; char name_text[1024]; if( !get_geditable_string( name->entry, name_text, 1024 ) ) { nfn( sys, IWINDOW_ERROR ); return; } if( !(sym = compile_lookup( program->kitg->root->expr->compile, name_text )) ) { error_top( _( "Not found." ) ); error_sub( _( "No top-level symbol called \"%s\"." ), name_text ); nfn( sys, IWINDOW_ERROR ); return; } if( !sym->tool ) { error_top( _( "Not found." ) ); error_sub( _( "Symbol \"%s\" has no tool inforation." ), name_text ); nfn( sys, IWINDOW_ERROR ); return; } if( !program_select( program, MODEL( sym->tool ) ) ) { nfn( sys, IWINDOW_ERROR ); return; } nfn( sys, IWINDOW_YES ); } static void program_goto_action_cb( GtkAction *action, Program *program ) { GtkWidget *ss = stringset_new(); StringsetChild *name; name = stringset_child_new( STRINGSET( ss ), _( "Name" ), "", _( "Go to definition of this symbol" ) ); iwindow_set_title( IWINDOW( ss ), _( "Go to Definition" ) ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, program ); idialog_add_ok( IDIALOG( ss ), program_goto_done_cb, GTK_STOCK_JUMP_TO ); idialog_set_pinup( IDIALOG( ss ), TRUE ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( program ) ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); /* Now try to paste the selection into the name widget. FIXME ... get rid of this, have a right-button menu on the text widget which includes a 'go to def' item. or could make sym names into hyperlinks? see text demo example */ program_copy( program ); gtk_editable_paste_clipboard( GTK_EDITABLE( name->entry ) ); } static void program_info_action_cb( GtkAction *action, Program *program ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); program_info( program, &buf ); error_top( _( "Object information." ) ); error_sub( "%s", vips_buf_all( &buf ) ); iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO ); } static void program_trace_action_cb( GtkAction *action, Program *program ) { (void) trace_new(); } static void program_errorreport_action_cb( GtkAction *action, Program *program ) { iError *ierror; ierror = ierror_new( program->kitg ); gtk_widget_show( GTK_WIDGET( ierror ) ); #ifdef DEBUG /* Dump VIPS memory usage info for debugging. */ im__print_all(); #endif /*DEBUG*/ } static void program_tool_help_action_cb( GtkAction *action, Program *program ) { if( program->tool && program->tool->type == TOOL_SYM && program->kit && program->kit->pseudo ) { switch( program->tool->sym->type ) { case SYM_EXTERNAL: /* With vips7 we displayed the man page. When we go * properly vips8, display the API docs. * char txt[512]; VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_appendf( &buf, "file://" VIPS_DOCPATH "/man/%s.3.html", IOBJECT( program->tool->sym )->name ); box_url( GTK_WIDGET( program ), vips_buf_all( &buf ) ); * */ break; case SYM_BUILTIN: box_help( GTK_WIDGET( program ), "tb:builtin" ); break; default: break; } } else { error_top( _( "No documentation available." ) ); error_sub( "%s", _( "On-line documentation is only currently " "available for VIPS functions and nip builtins." ) ); iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO ); } } /* Expose/hide the definition browser. */ static void program_defbrowser_action_cb( GtkToggleAction *action, Program *program ) { if( gtk_toggle_action_get_active( action ) ) pane_animate_open( program->rpane ); else pane_animate_closed( program->rpane ); } /* Our actions. */ static GtkActionEntry program_actions[] = { /* Menu items. */ { "DebugMenu", NULL, "_Debug" }, /* Actions. */ { "NewTool", GTK_STOCK_NEW, N_( "New _Tool" ), NULL, N_( "Make a new tool" ), G_CALLBACK( program_tool_new_action_cb ) }, { "NewToolkit", GTK_STOCK_NEW, N_( "New Tool_kit" ), NULL, N_( "Make a new toolkit" ), G_CALLBACK( program_toolkit_new_action_cb ) }, { "NewSeparator", GTK_STOCK_NEW, N_( "New _Separator" ), NULL, N_( "Make a new separator" ), G_CALLBACK( program_separator_new_action_cb ) }, { "NewColumnItem", GTK_STOCK_NEW, N_( "New _Column Item" ), NULL, N_( "Make a new column item" ), G_CALLBACK( program_column_item_new_action_cb ) }, { "NewProgram", GTK_STOCK_NEW, N_( "New _Program Window" ), NULL, N_( "Make a new program window" ), G_CALLBACK( program_program_new_action_cb ) }, { "Open", GTK_STOCK_OPEN, N_( "_Open Toolkit" ), NULL, N_( "_Open toolkit" ), G_CALLBACK( program_open_action_cb ) }, { "Save", GTK_STOCK_SAVE, N_( "Save Toolkit" ), NULL, N_( "_Save toolkit" ), G_CALLBACK( program_save_action_cb ) }, { "SaveAs", GTK_STOCK_SAVE_AS, N_( "Save Toolkit _As" ), NULL, N_( "Save toolkit as" ), G_CALLBACK( program_save_as_action_cb ) }, { "Process", NULL, N_( "_Process" ), NULL, N_( "Process text" ), G_CALLBACK( program_process_action_cb ) }, { "Reload", NULL, N_( "_Reload All Toolkits" ), NULL, N_( "Remove and reload all startup data" ), G_CALLBACK( program_reload_action_cb ) }, { "Cut", GTK_STOCK_CUT, N_( "C_ut" ), NULL, N_( "Cut selected text" ), G_CALLBACK( program_cut_action_cb ) }, { "Copy", GTK_STOCK_COPY, N_( "_Copy" ), NULL, N_( "Copy selected text" ), G_CALLBACK( program_copy_action_cb ) }, { "Paste", GTK_STOCK_PASTE, N_( "_Paste" ), NULL, N_( "Paste selected text" ), G_CALLBACK( program_paste_action_cb ) }, { "Delete", GTK_STOCK_DELETE, N_( "_Delete" ), NULL, N_( "Delete selected text" ), G_CALLBACK( program_delete_action_cb ) }, { "SelectAll", NULL, N_( "Select _All" ), NULL, N_( "Select all text" ), G_CALLBACK( program_select_all_action_cb ) }, { "DeselectAll", NULL, N_( "Dese_lect All" ), NULL, N_( "Deselect all text" ), G_CALLBACK( program_deselect_all_action_cb ) }, { "DeleteTool", NULL, N_( "Delete _Tool" ), NULL, N_( "Delete current tool" ), G_CALLBACK( program_remove_tool_action_cb ) }, { "DeleteToolkit", NULL, N_( "Delete Tool_kit" ), NULL, N_( "Delete current toolkit" ), G_CALLBACK( program_remove_toolkit_action_cb ) }, { "Find", GTK_STOCK_FIND, N_( "_Find" ), NULL, N_( "Find text in toolkits" ), G_CALLBACK( program_find_action_cb ) }, { "FindNext", NULL, N_( "Find _Next" ), "G", N_( "Find text again" ), G_CALLBACK( program_find_again_action_cb ) }, { "JumpTo", GTK_STOCK_JUMP_TO, N_( "_Jump To Definition" ), NULL, N_( "Jump to definition" ), G_CALLBACK( program_goto_action_cb ) }, { "Info", NULL, N_( "_Info" ), NULL, N_( "Info on selected object" ), G_CALLBACK( program_info_action_cb ) }, { "Trace", NULL, N_( "_Trace" ), NULL, N_( "Make a new trace window" ), G_CALLBACK( program_trace_action_cb ) }, { "Errors", NULL, N_( "_Errors" ), NULL, N_( "Show all errors" ), G_CALLBACK( program_errorreport_action_cb ) }, { "HelpTool", NULL, N_( "Help on _Tool" ), NULL, N_( "View docs for this tool" ), G_CALLBACK( program_tool_help_action_cb ) } }; static GtkToggleActionEntry program_toggle_actions[] = { { "DefBrowser", NULL, N_( "Definition _Browser" ), NULL, N_( "Show definition browser" ), G_CALLBACK( program_defbrowser_action_cb ), FALSE } }; static const char *program_menubar_ui_description = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static void program_lpane_changed_cb( Pane *pane, Program *program ) { } static void program_rpane_changed_cb( Pane *pane, Program *program ) { if( program->rpane_open != pane->open || program->rpane_position != pane->user_position ) { program->rpane_open = pane->open; program->rpane_position = pane->user_position; program_refresh( program ); } } gboolean program_select( Program *program, Model *model ) { /* Existing text changed? Parse it. */ if( program->dirty && !program_parse( program ) ) return( FALSE ); if( model ) { if( IS_TOOL( model ) ) program_select_tool( program, TOOL( model ) ); else if( IS_TOOLKIT( model ) ) program_select_kit( program, TOOLKIT( model ) ); } return( TRUE ); } /* Select a row from an iter. */ static void program_select_row( Program *program, GtkTreeIter *iter ) { Tool *tool; Toolkit *kit; Model *model; gtk_tree_model_get( GTK_TREE_MODEL( program->store ), iter, TOOL_POINTER_COLUMN, &tool, KIT_POINTER_COLUMN, &kit, -1 ); if( tool ) model = MODEL( tool ); else model = MODEL( kit ); if( !program_select( program, model ) ) iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_ERROR ); } static void program_row_collapsed_cb( GtkTreeView *tree, GtkTreeIter *iter, GtkTreePath *path, Program *program ) { Toolkit *kit; #ifdef DEBUG printf( "program_row_collapsed_cb:\n" ); printf( " path = %s\n", gtk_tree_path_to_string( path ) ); #endif /*DEBUG*/ gtk_tree_model_get( GTK_TREE_MODEL( program->store ), iter, KIT_POINTER_COLUMN, &kit, -1 ); /* If we have collapsed the kit containing the currently selected * tool, the kit will just bounce open again when we refresh the tree. * Unselect the tool. */ if( program->kit == kit ) program_select_kit( program, kit ); } static void program_selection_changed_cb( GtkTreeSelection *select, Program *program ) { GtkTreeIter iter; GtkTreeModel *model; #ifdef DEBUG printf( "program_selection_changed_cb:\n" ); #endif /*DEBUG*/ if( gtk_tree_selection_get_selected( select, &model, &iter ) ) { #ifdef DEBUG printf( " selection = %s\n", gtk_tree_path_to_string ( gtk_tree_model_get_path( model, &iter ) ) ); #endif /*DEBUG*/ program_select_row( program, &iter ); } program_refresh( program ); } static gboolean program_tree_event_cb( GtkTreeView *tree, GdkEvent *ev, Program *program ) { GtkTreePath *path; gboolean handled = FALSE; if( ev->type == GDK_BUTTON_PRESS && ev->button.button == 3 && gtk_tree_view_get_path_at_pos( tree, ev->button.x, ev->button.y, &path, NULL, NULL, NULL ) ) { GtkTreeIter iter; gtk_tree_model_get_iter( GTK_TREE_MODEL( program->store ), &iter, path ); program_select_row( program, &iter ); gtk_tree_path_free( path ); popup_link( GTK_WIDGET( program ), program_menu, NULL ); popup_show( GTK_WIDGET( program ), ev ); handled = TRUE; } return( handled ); } static void program_row_inserted_cb( GtkTreeModel *treemodel, GtkTreePath *path, GtkTreeIter *iter, Program *program ) { GtkTreeIter iter2; GtkTreeIter iter3; #ifdef DEBUG printf( "program_row_inserted_cb:\n" ); printf( " path = %s\n", gtk_tree_path_to_string( path ) ); #endif /*DEBUG*/ program->to_pos = -1; program->to_kit = NULL; switch( gtk_tree_path_get_depth( path ) ) { case 3: program->to_pos = gtk_tree_path_get_indices( path )[1]; gtk_tree_model_iter_parent( GTK_TREE_MODEL( program->store ), &iter2, iter ); gtk_tree_model_iter_parent( GTK_TREE_MODEL( program->store ), &iter3, &iter2 ); gtk_tree_model_get( GTK_TREE_MODEL( program->store ), &iter3, KIT_POINTER_COLUMN, &program->to_kit, -1 ); break; case 2: program->to_pos = gtk_tree_path_get_indices( path )[1]; gtk_tree_model_iter_parent( GTK_TREE_MODEL( program->store ), &iter2, iter ); gtk_tree_model_get( GTK_TREE_MODEL( program->store ), &iter2, KIT_POINTER_COLUMN, &program->to_kit, -1 ); break; case 1: program->to_pos = -1; gtk_tree_model_get( GTK_TREE_MODEL( program->store ), iter, KIT_POINTER_COLUMN, &program->to_kit, -1 ); break; } #ifdef DEBUG if( program->to_kit ) { printf( " to_kit = " ); iobject_print( IOBJECT( program->to_kit ) ); } else printf( " to_kit = NULL\n" ); printf( " to_pos = %d\n", program->to_pos ); #endif /*DEBUG*/ } static void program_row_deleted_cb( GtkTreeModel *treemodel, GtkTreePath *path, Program *program ) { #ifdef DEBUG printf( "program_row_deleted_cb:\n" ); printf( " delete path = %s\n", gtk_tree_path_to_string( path ) ); #endif /*DEBUG*/ if( !program->to_kit || !program->tool ) { error_top( _( "Bad drag." ) ); error_sub( "%s", _( "Sorry, you can only drag tools between toolkits. " "You can't reorder toolkits, you can't nest toolkits " "and you can't drag tools to the top level." ) ); iwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO ); return; } #ifdef DEBUG printf( " to_kit = " ); iobject_print( IOBJECT( program->to_kit ) ); printf( " to_pos = %d\n", program->to_pos ); printf( " selected tool = " ); iobject_print( IOBJECT( program->tool ) ); #endif /*DEBUG*/ /* Move tool. */ g_object_ref( G_OBJECT( program->tool ) ); icontainer_child_remove( ICONTAINER( program->tool ) ); icontainer_child_add( ICONTAINER( program->to_kit ), ICONTAINER( program->tool ), program->to_pos ); g_object_unref( G_OBJECT( program->tool ) ); filemodel_set_modified( FILEMODEL( program->to_kit ), TRUE ); iobject_changed( IOBJECT( program->tool ) ); } static void program_edit_map_cb( GtkWidget *widget, Program *program ) { iWindow *iwnd = IWINDOW( program ); GtkClipboard *clipboard = gtk_widget_get_clipboard( GTK_WIDGET( program ), GDK_SELECTION_CLIPBOARD ); GtkTextView *text_view = GTK_TEXT_VIEW( program->text ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); gboolean editable = !program->kit || !program->kit->pseudo; gboolean available = gtk_clipboard_wait_is_text_available( clipboard ); gboolean selected = gtk_text_buffer_get_selection_bounds( text_buffer, NULL, NULL ); GtkAction *action; action = gtk_action_group_get_action( iwnd->action_group, "Paste" ); g_object_set( G_OBJECT( action ), "sensitive", available && editable, NULL ); action = gtk_action_group_get_action( iwnd->action_group, "Copy" ); g_object_set( G_OBJECT( action ), "sensitive", selected, NULL ); action = gtk_action_group_get_action( iwnd->action_group, "Cut" ); g_object_set( G_OBJECT( action ), "sensitive", selected && editable, NULL ); action = gtk_action_group_get_action( iwnd->action_group, "Delete" ); g_object_set( G_OBJECT( action ), "sensitive", selected && editable, NULL ); action = gtk_action_group_get_action( iwnd->action_group, "DeselectAll" ); g_object_set( G_OBJECT( action ), "sensitive", selected, NULL ); } static PangoTabArray * program_tabs_new( void ) { const int ntabs = 20; const int tab_width = 30; /* in pixels, about 4 chars */ PangoTabArray *tabs = pango_tab_array_new( ntabs, TRUE ); int i; for( i = 0; i < ntabs; i++ ) pango_tab_array_set_tab( tabs, i, PANGO_TAB_LEFT, i * tab_width ); return( tabs ); } GtkWidget * program_text_new( void ) { PangoFontDescription *font_desc; PangoTabArray *tabs; GtkWidget *text; text = gtk_text_view_new(); font_desc = pango_font_description_from_string( "Monospace" ); gtk_widget_modify_font( text, font_desc ); pango_font_description_free( font_desc ); tabs = program_tabs_new(); gtk_text_view_set_tabs( GTK_TEXT_VIEW( text ), tabs ); pango_tab_array_free( tabs ); return( text ); } static void program_build( Program *program, GtkWidget *vbox ) { iWindow *iwnd = IWINDOW( program ); GError *error; GtkWidget *mbar; GtkWidget *item; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *select; GtkWidget *swin; Panechild *panechild; GtkWidget *ebox; /* Make main menu bar */ gtk_action_group_add_actions( iwnd->action_group, program_actions, G_N_ELEMENTS( program_actions ), GTK_WINDOW( program ) ); gtk_action_group_add_toggle_actions( iwnd->action_group, program_toggle_actions, G_N_ELEMENTS( program_toggle_actions ), GTK_WINDOW( program ) ); error = NULL; if( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager, program_menubar_ui_description, -1, &error ) ) { g_message( "building menus failed: %s", error->message ); g_error_free( error ); exit( EXIT_FAILURE ); } mbar = gtk_ui_manager_get_widget( iwnd->ui_manager, "/ProgramMenubar" ); gtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 ); gtk_widget_show( mbar ); /* On map of the edit menu, rethink cut/copy/paste sensitivity. */ item = gtk_ui_manager_get_widget( iwnd->ui_manager, "/ProgramMenubar/EditMenu/Cut" ); item = gtk_widget_get_parent( GTK_WIDGET( item ) ); gtk_signal_connect( GTK_OBJECT( item ), "map", GTK_SIGNAL_FUNC( program_edit_map_cb ), program ); /* This will set to NULL if we don't have infobar support. */ if( (IWINDOW( program )->infobar = infobar_new()) ) gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( IWINDOW( program )->infobar ), FALSE, FALSE, 0 ); program->rpane = pane_new( PANE_HIDE_RIGHT ); g_signal_connect( program->rpane, "changed", G_CALLBACK( program_rpane_changed_cb ), program ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( program->rpane ), TRUE, TRUE, 0 ); gtk_widget_show( GTK_WIDGET( program->rpane ) ); program->lpane = pane_new( PANE_HIDE_LEFT ); g_signal_connect( program->lpane, "changed", G_CALLBACK( program_lpane_changed_cb ), program ); gtk_paned_set_position( GTK_PANED( program->lpane ), program->pane_position ); gtk_paned_pack1( GTK_PANED( program->rpane ), GTK_WIDGET( program->lpane ), TRUE, FALSE ); gtk_widget_show( GTK_WIDGET( program->lpane ) ); swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_paned_pack1( GTK_PANED( program->lpane ), swin, FALSE, FALSE ); gtk_widget_show( swin ); program->store = gtk_tree_store_new( N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER ); program->row_inserted_sid = g_signal_connect( G_OBJECT( program->store ), "row_inserted", G_CALLBACK( program_row_inserted_cb ), program ); program->row_deleted_sid = g_signal_connect( G_OBJECT( program->store ), "row_deleted", G_CALLBACK( program_row_deleted_cb ), program ); program->tree = gtk_tree_view_new_with_model( GTK_TREE_MODEL( program->store ) ); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( _( "Tool" ), renderer, "text", NAME_COLUMN, NULL ); gtk_tree_view_append_column( GTK_TREE_VIEW( program->tree ), column ); g_signal_connect( G_OBJECT( program->tree ), "row_collapsed", G_CALLBACK( program_row_collapsed_cb ), program ); gtk_container_add( GTK_CONTAINER( swin ), program->tree ); gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( program->tree ), FALSE ); gtk_tree_view_set_enable_search( GTK_TREE_VIEW( program->tree ), TRUE ); gtk_tree_view_set_reorderable( GTK_TREE_VIEW( program->tree ), TRUE ); select = gtk_tree_view_get_selection( GTK_TREE_VIEW( program->tree ) ); gtk_tree_selection_set_mode( select, GTK_SELECTION_SINGLE ); program->select_changed_sid = g_signal_connect( G_OBJECT( select ), "changed", G_CALLBACK( program_selection_changed_cb ), program ); gtk_signal_connect( GTK_OBJECT( program->tree ), "event", GTK_SIGNAL_FUNC( program_tree_event_cb ), program ); gtk_widget_show( program->tree ); /* Toolkit Browser pane. */ panechild = panechild_new( program->rpane, _( "Definition Browser" ) ); /* Have to put toolkitbrowser in an ebox so the search entry gets * clipped to the pane size. */ ebox = gtk_event_box_new(); gtk_container_add( GTK_CONTAINER( panechild ), GTK_WIDGET( ebox ) ); gtk_widget_show( ebox ); program->defbrowser = defbrowser_new(); vobject_link( VOBJECT( program->defbrowser ), IOBJECT( program->kitg ) ); defbrowser_set_program( program->defbrowser, program ); gtk_container_add( GTK_CONTAINER( ebox ), GTK_WIDGET( program->defbrowser ) ); gtk_widget_show( GTK_WIDGET( program->defbrowser ) ); swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_paned_pack2( GTK_PANED( program->lpane ), swin, TRUE, TRUE ); gtk_widget_show( swin ); program->text = program_text_new(); g_signal_connect( gtk_text_view_get_buffer( GTK_TEXT_VIEW( program->text ) ), "notify::cursor-position", G_CALLBACK( program_text_cursor_position ), program ); g_signal_connect( gtk_text_view_get_buffer( GTK_TEXT_VIEW( program->text ) ), "changed", G_CALLBACK( program_text_changed ), program ); gtk_container_add( GTK_CONTAINER( swin ), program->text ); gtk_widget_show( program->text ); gtk_widget_grab_focus( program->text ); } static void program_popdown( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Program *program = PROGRAM( iwnd ); prefs_set( "PROGRAM_PANE_POSITION", "%d", gtk_paned_get_position( GTK_PANED( program->lpane ) ) ); /* We can't parse in popdown, we may have lost too much of the rest of * nip2 before here. */ nfn( sys, IWINDOW_YES ); } static void program_link( Program *program, Toolkitgroup *kitg ) { program->kitg = kitg; program_title( program ); iwindow_set_size_prefs( IWINDOW( program ), "PROGRAM_WIDTH", "PROGRAM_HEIGHT" ); iwindow_set_build( IWINDOW( program ), (iWindowBuildFn) program_build, NULL, NULL, NULL ); iwindow_set_popdown( IWINDOW( program ), program_popdown, NULL ); iwindow_build( IWINDOW( program ) ); program_all = g_slist_prepend( program_all, program ); program_refresh( program ); program->kitgroup_changed_sid = g_signal_connect( G_OBJECT( program->kitg ), "changed", G_CALLBACK( program_kitgroup_changed ), program ); program->kitgroup_destroy_sid = g_signal_connect( G_OBJECT( program->kitg ), "destroy", G_CALLBACK( program_kitgroup_destroy ), program ); pane_set_state( program->rpane, program->rpane_open, program->rpane_position ); } Program * program_new( Toolkitgroup *kitg ) { Program *program = gtk_type_new( TYPE_PROGRAM ); program_link( program, kitg ); return( program ); } nip2-8.7.1/src/iobject.h0000644000175000017500000000644113351443023011702 00000000000000/* abstract base class for all nip objects */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IOBJECT (iobject_get_type()) #define IOBJECT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IOBJECT, iObject )) #define IOBJECT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IOBJECT, iObjectClass)) #define IS_IOBJECT( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IOBJECT )) #define IS_IOBJECT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IOBJECT )) #define IOBJECT_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IOBJECT, iObjectClass )) /* Handy iobject_destroy() shortcut. */ #define IDESTROY( O ) { \ if( O ) { \ (void) iobject_destroy( IOBJECT( O ) ); \ ( O ) = NULL; \ } \ } struct _iObject { GObject parent_object; /* My instance vars. */ char *name; /* iObject name */ char *caption; /* Comment of some sort */ /* True when created ... the 1 reference that gobject makes is * 'floating' and not owned by anyone. Do _sink() after every _ref() * to transfer ownership to the parent container. Upshot: no need to * _unref() after _add() in _new(). */ gboolean floating; /* Stop destroy loops with this. */ gboolean in_destruction; }; typedef struct _iObjectClass { GObjectClass parent_class; /* End object's lifetime, just like gtk_object_destroy. */ void (*destroy)( iObject * ); /* Something about the object has changed. Should use glib's properties * but fix this later. */ void (*changed)( iObject * ); /* Try and say something useful about us. */ void (*info)( iObject *, VipsBuf * ); /* Called on _changed() to update the caption. Define this if you want * the caption to be an explanatory note about the object. */ const char *(*generate_caption)( iObject * ); /* The i18n name for this class we show the user. FOr example, * Workspace is referred to as "tab" by the user. */ const char *user_name; } iObjectClass; #define IOBJECT_GET_CLASS_NAME( obj ) \ ((G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_IOBJECT, iObjectClass ))->user_name) void *iobject_destroy( iObject *iobject ); void *iobject_changed( iObject *iobject ); void *iobject_info( iObject *iobject, VipsBuf * ); GType iobject_get_type( void ); void *iobject_test_name( iObject *iobject, const char *name ); void *iobject_print( iObject *iobject ); void iobject_set( iObject *iobject, const char *name, const char *caption ); void iobject_sink( iObject *iobject ); void iobject_dump( iObject *iobject ); nip2-8.7.1/src/pane.h0000644000175000017500000000530413351443023011203 00000000000000/* a side panel that can slide in and out of view */ /* Copyright (C) 2007 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PANE (pane_get_type()) #define PANE( obj ) (GTK_CHECK_CAST( (obj), TYPE_PANE, Pane )) #define PANE_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PANE, PaneClass )) #define IS_PANE( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PANE )) #define IS_PANE_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PANE )) /* Can hide on the left or the right hand side of a window. */ typedef enum { PANE_HIDE_LEFT, PANE_HIDE_RIGHT } PaneHandedness; typedef struct _Pane { GtkHPaned parent_object; PaneHandedness handedness; /* Hide on left or right */ /* The child pane we show on left or right. */ Panechild *panechild; /* Are we visible or not. */ gboolean open; /* The position of the divider. This changes as the pane is animated * open and closed and does not reflect the position the user has * selected by dragging. */ int position; /* The position the user wants the pane to sit at. */ int user_position; /* Animating towards this position. If close_on_end is true, close the * pane at the end of animation. */ int target_position; gboolean close_on_end; /* Set animation speed with this. */ int last_set_position; /* Timeout for animation. */ guint animate_timeout; } Pane; typedef struct _PaneClass { GtkHPanedClass parent_class; /* Either position or open have changed. */ void (*changed)( Pane * ); } PaneClass; GType pane_get_type( void ); Pane *pane_new( PaneHandedness handedness ); void pane_set_position( Pane *pane, int position ); void pane_set_user_position( Pane *pane, int user_position ); void pane_set_open( Pane *pane, gboolean open ); void pane_set_state( Pane *pane, gboolean open, int user_position ); void pane_set_child( Pane *pane, Panechild *panechild ); void pane_animate_closed( Pane *pane ); void pane_animate_open( Pane *pane ); nip2-8.7.1/src/column.c0000644000175000017500000002551713351443023011560 00000000000000/* a column button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static FilemodelClass *parent_class = NULL; /* Offset for this column load/save. */ static int column_left_offset = 0; static int column_top_offset = 0; /* When we merge workspaces we need to scroll to position the last new column * in view. */ static Column *column_last_new = NULL; /* Map down a column. */ void * column_map( Column *col, row_map_fn fn, void *a, void *b ) { Subcolumn *scol = col->scol; return( subcolumn_map( scol, fn, a, b ) ); } void * column_map_symbol_sub( Row *row, symbol_map_fn fn, void *a ) { return( fn( row->sym, a, NULL, NULL ) ); } /* Map down a column, applying to the symbol of the row. */ void * column_map_symbol( Column *col, symbol_map_fn fn, void *a ) { return( column_map( col, (row_map_fn) column_map_symbol_sub, (void *) fn, a ) ); } static void column_finalize( GObject *gobject ) { Column *col; #ifdef DEBUG printf( "column_finalize\n" ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_COLUMN( gobject ) ); col = COLUMN( gobject ); if( col == column_last_new ) column_last_new = NULL; IM_FREEF( g_source_remove, col->scrollto_timeout ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Select all things in a column. */ void * column_select_symbols( Column *col ) { return( column_map( col, (row_map_fn) row_select_extend, NULL, NULL ) ); } static Subcolumn * column_get_subcolumn( Column *col ) { g_assert( g_slist_length( ICONTAINER( col )->children ) == 1 ); return( SUBCOLUMN( ICONTAINER( col )->children->data ) ); } static void column_child_add( iContainer *parent, iContainer *child, int pos ) { Column *col = COLUMN( parent ); ICONTAINER_CLASS( parent_class )->child_add( parent, child, pos ); /* Update our context. */ col->scol = column_get_subcolumn( col ); } static void column_child_remove( iContainer *parent, iContainer *child ) { Column *col = COLUMN( parent ); workspace_set_modified( col->ws, TRUE ); ICONTAINER_CLASS( parent_class )->child_remove( parent, child ); } static Workspace * column_get_workspace( Column *col ) { return( WORKSPACE( ICONTAINER( col )->parent ) ); } static void column_parent_add( iContainer *child ) { Column *col = COLUMN( child ); g_assert( IS_WORKSPACE( child->parent ) ); ICONTAINER_CLASS( parent_class )->parent_add( child ); g_assert( IS_WORKSPACE( child->parent ) ); /* Update our context. */ col->ws = column_get_workspace( col ); g_assert( IS_WORKSPACE( child->parent ) ); } static View * column_view_new( Model *model, View *parent ) { if( IS_PREFWORKSPACEVIEW( parent ) ) return( prefcolumnview_new() ); else return( columnview_new() ); } static xmlNode * column_save( Model *model, xmlNode *xnode ) { Column *col = COLUMN( model ); int x = IM_MAX( 0, col->x - column_left_offset ); int y = IM_MAX( 0, col->y - column_top_offset ); xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); /* Save sform for backwards compat with nip 7.8 ... now a workspace * property. */ if( !set_iprop( xthis, "x", x ) || !set_iprop( xthis, "y", y ) || !set_sprop( xthis, "open", bool_to_char( col->open ) ) || !set_sprop( xthis, "selected", bool_to_char( col->selected ) ) || !set_sprop( xthis, "sform", bool_to_char( FALSE ) ) || !set_iprop( xthis, "next", col->next ) || !set_sprop( xthis, "name", IOBJECT( col )->name ) ) return( NULL ); /* Caption can be NULL for untitled columns. */ if( IOBJECT( col )->caption ) if( !set_sprop( xthis, "caption", IOBJECT( col )->caption ) ) return( NULL ); return( xthis ); } static gboolean column_save_test( Model *model ) { Column *col = COLUMN( model ); Workspace *ws = col->ws; Workspacegroup *wsg = workspace_get_workspacegroup( ws ); if( wsg->save_type == WORKSPACEGROUP_SAVE_SELECTED ) /* Only save columns containing selected rows. */ return( column_map( col, (row_map_fn) row_is_selected, NULL, NULL ) != NULL ); return( TRUE ); } static void column_set_last_new( Column *col ) { if( !column_last_new ) column_last_new = col; } static gboolean column_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { Column *col = COLUMN( model ); int x = col->x; int y = col->y; char buf[256]; g_assert( IS_WORKSPACE( parent ) ); if( !get_iprop( xnode, "x", &x ) || !get_iprop( xnode, "y", &y ) || !get_bprop( xnode, "open", &col->open ) || !get_bprop( xnode, "selected", &col->selected ) || !get_iprop( xnode, "next", &col->next ) ) return( FALSE ); col->x = x + column_left_offset; col->y = y + column_top_offset; /* Don't use iobject_set(): we don't want to trigger _changed during * load. */ if( get_sprop( xnode, "caption", buf, 256 ) ) { IM_SETSTR( IOBJECT( col )->caption, buf ); } if( get_sprop( xnode, "name", buf, 256 ) ) { IM_SETSTR( IOBJECT( col )->name, buf ); } column_set_last_new( col ); return( MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ); } static void column_class_init( ColumnClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; FilemodelClass *filemodel_class = (FilemodelClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = column_finalize; /* Create signals. */ /* Init methods. */ iobject_class->user_name = _( "Column" ); icontainer_class->child_add = column_child_add; icontainer_class->child_remove = column_child_remove; icontainer_class->parent_add = column_parent_add; model_class->view_new = column_view_new; model_class->save = column_save; model_class->save_test = column_save_test; model_class->load = column_load; filemodel_class->filetype = filesel_type_workspace; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void column_init( Column *col ) { #ifdef DEBUG printf( "column_init\n" ); #endif /*DEBUG*/ col->scol = NULL; col->ws = NULL; col->x = 0; col->y = 0; col->open = TRUE; col->selected = FALSE; col->next = 1; col->last_select = NULL; } GType column_get_type( void ) { static GType column_type = 0; if( !column_type ) { static const GTypeInfo info = { sizeof( ColumnClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) column_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Column ), 32, /* n_preallocs */ (GInstanceInitFunc) column_init, }; column_type = g_type_register_static( TYPE_FILEMODEL, "Column", &info, 0 ); } return( column_type ); } Column * column_new( Workspace *ws, const char *name ) { Column *col; if( workspace_column_find( ws, name ) ) { error_top( _( "Name clash." ) ); error_sub( _( "Can't create column \"%s\". A column with that " "name already exists." ), name ); return( NULL ); } col = COLUMN( g_object_new( TYPE_COLUMN, NULL ) ); iobject_set( IOBJECT( col ), name, NULL ); icontainer_child_add( ICONTAINER( ws ), ICONTAINER( col ), -1 ); subcolumn_new( NULL, col ); col->x = ws->vp.left + 50; col->y = ws->vp.top; column_set_last_new( col ); return( col ); } Column * column_get_last_new( void ) { return( column_last_new ); } void column_clear_last_new( void ) { column_last_new = NULL; } /* Find the bottom of the column. */ Row * column_get_bottom( Column *col ) { Subcolumn *scol = col->scol; GSList *children = ICONTAINER( scol )->children; if( children ) { Row *row = ROW( g_slist_last( children )->data ); return( row ); } return( NULL ); } /* Add the last n names from a column to a buffer. Error if there are too few * there. */ gboolean column_add_n_names( Column *col, const char *name, VipsBuf *buf, int nparam ) { Subcolumn *scol = col->scol; GSList *children = ICONTAINER( scol )->children; int len = g_slist_length( children ); GSList *i; g_assert( nparam >= 0 ); if( nparam > 0 && nparam > len ) { error_top( _( "Too few items." ) ); error_sub( _( "This column only has %d items, " "but %s needs %d items." ), len, name, nparam ); return( FALSE ); } for( i = g_slist_nth( children, len - nparam ); i; i = i->next ) { Row *row = ROW( i->data ); if( row->sym ) { vips_buf_appends( buf, " " ); vips_buf_appends( buf, IOBJECT( row->sym )->name ); } } return( TRUE ); } /* Is a column empty? */ gboolean column_is_empty( Column *col ) { Subcolumn *scol = col->scol; GSList *children = ICONTAINER( scol )->children; return( children == NULL ); } /* Set the load/save offsets. */ void column_set_offset( int x_off, int y_off ) { #ifdef DEBUG printf( "column_set_offset: load offset %d x %d\n", x_off, y_off ); #endif /*DEBUG*/ column_left_offset = x_off; column_top_offset = y_off; } char * column_name_new( Column *col ) { char buf[256]; do { im_snprintf( buf, 256, "%s%d", IOBJECT( col )->name, col->next++ ); } while( compile_lookup( col->ws->sym->expr->compile, buf ) ); return( im_strdup( NULL, buf ) ); } void column_set_open( Column *col, gboolean open ) { if( col->open != open ) { Workspace *ws = col->ws; col->open = open; workspace_set_modified( ws, TRUE ); iobject_changed( IOBJECT( col ) ); } } static gboolean column_scrollto_timeout_cb( Column *col ) { #ifdef DEBUG printf( "column_scrollto_timeout_cb: %p\n", col ); #endif /*DEBUG*/ col->scrollto_timeout = 0; model_scrollto( MODEL( col ), col->pending_position ); return( FALSE ); } void column_scrollto( Column *col, ModelScrollPosition position ) { #ifdef DEBUG printf( "column_scrollto: %p %s\n", col, IOBJECT( col )->name ); #endif /*DEBUG*/ IM_FREEF( g_source_remove, col->scrollto_timeout ); col->pending_position = position; /* We need a longer timeout here than the one in mainw_layout(). */ col->scrollto_timeout = g_timeout_add( 400, (GSourceFunc) column_scrollto_timeout_cb, col ); } nip2-8.7.1/src/matrix.h0000644000175000017500000000565313351443023011573 00000000000000/* a matrix in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_MATRIX (matrix_get_type()) #define MATRIX( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MATRIX, Matrix )) #define MATRIX_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_MATRIX, MatrixClass)) #define IS_MATRIX( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MATRIX )) #define IS_MATRIX_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MATRIX )) #define MATRIX_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_MATRIX, MatrixClass )) /* What kind of ui bits have we asked for for this matrix? */ typedef enum { MATRIX_DISPLAY_TEXT = 0, /* Set of text widgets */ MATRIX_DISPLAY_SLIDER, /* Set of sliders */ MATRIX_DISPLAY_TOGGLE, /* Set of 3 value toggles */ MATRIX_DISPLAY_TEXT_SCALE_OFFSET,/* Text, with scale/offset widgets */ MATRIX_DISPLAY_LAST } MatrixDisplayType; typedef struct _Matrix { Classmodel model; /* Base class fields. */ MatrixValue value; /* Other class fields. */ MatrixDisplayType display; /* Display as */ double scale; double offset; /* Is there a current selection on the matrixview? And if there is, * the cells it covers. */ gboolean selected; Rect range; } Matrix; typedef struct _MatrixClass { ClassmodelClass parent_class; /* My methods. */ } MatrixClass; gboolean matrix_value_resize( MatrixValue *value, int width, int height ); GType matrix_get_type( void ); /* Select rectangular areas of matricies. */ void matrix_select( Matrix *matrix, int left, int top, int width, int height ); void matrix_deselect( Matrix *matrix ); void matrix_dmask_to_ip( DOUBLEMASK *dmask, VipsBuf *buf ); gboolean matrix_dmask_to_heap( Heap *heap, DOUBLEMASK *dmask, PElement *out ); DOUBLEMASK *matrix_imask_to_dmask( INTMASK *imask ); INTMASK *matrix_dmask_to_imask( DOUBLEMASK *dmask ); gboolean matrix_imask_to_heap( Heap *heap, INTMASK *imask, PElement *out ); DOUBLEMASK *matrix_ip_to_dmask( PElement *root ); INTMASK *matrix_ip_to_imask( PElement *root ); DOUBLEMASK *matrix_model_to_dmask( Matrix *matrix ); gboolean matrix_dmask_to_model( Matrix *matrix, DOUBLEMASK *dmask ); nip2-8.7.1/src/workspaceroot.h0000644000175000017500000000362613351443023013167 00000000000000/* The root of all workspaces. A singleton all workspaces are children of. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_WORKSPACEROOT (workspaceroot_get_type()) #define WORKSPACEROOT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WORKSPACEROOT, \ Workspaceroot )) #define WORKSPACEROOT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WORKSPACEROOT, \ WorkspacerootClass)) #define IS_WORKSPACEROOT( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WORKSPACEROOT )) #define IS_WORKSPACEROOT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEROOT )) #define WORKSPACEROOT_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WORKSPACEROOT, \ WorkspacerootClass )) /* A workspaceroot. */ struct _Workspaceroot { Model parent_object; Symbol *sym; /* Workspace in this group in this */ }; typedef struct _WorkspacerootClass { ModelClass parent_class; /* Methods. */ } WorkspacerootClass; GType workspaceroot_get_type( void ); Workspaceroot *workspaceroot_new( const char *name ); void workspaceroot_name_new( Workspaceroot *wsr, char *name ); nip2-8.7.1/src/lex.l0000644000175000017500000001725113351443023011060 00000000000000%{ /* Lexer for image processing expressions. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" #ifdef HAVE_FLEX /* Flex has a different input mechanism :( */ #define YY_INPUT(buf,result,max_size) { \ extern int ip_input( void ); \ int c = ip_input(); \ result = (c == 0) ? YY_NULL : (buf[0] = c, 1); \ } #undef unput #define unput ip_unput #else /*HAVE_FLEX*/ /* Assume this is plain lex. */ /* Redefine input, output, unput and yywrap. */ #undef input #undef output #undef unput #undef YYLMAX /* See parse.y for input and unput. */ #define output(A) (error( "output called by lex" )) #define YYLMAX MAX_STRSIZE #define unput ip_unput #define input ip_input #endif /*HAVE_FLEX*/ /* Stuff from bison. */ #include "parse.h" /* Read a string into a buffer. Read up to the " character, " can be * escaped with '\'. */ static void read_string( char *buf ) { int ch; int i; /* Read up to \n, ", EOF, ignoring \" * Don't forget about "\\" though. */ for( i = 0; (ch = ip_input()); i++ ) { if( ch == EOF || ch == '\n' || ch == '"' || ch == '\0' ) break; if( i >= MAX_STRSIZE ) yyerror( _( "line too long" ) ); buf[i] = ch; if( ch == '\\' ) { ch = ip_input(); if( ch == EOF || ch == '\n' || ch == '\0' ) break; if( i >= MAX_STRSIZE ) yyerror( _( "line too long" ) ); buf[++i] = ch; } } buf[i] = '\0'; if( ch == '\n' ) yyerror( _( "end of line inside string" ) ); if( ch == EOF || ch == '\0' ) yyerror( _( "no end of string" ) ); } /* Read a char constant. The leading ' has already been seen. Cases to consider: * '\n' * '\\' * ''' (illegal in C, but I think we allow it) * '\'' */ static int read_char( void ) { int ch; ch = ip_input(); if( ch == EOF || ch == '\n' || ch == '\0' ) yyerror( _( "bad char constant" ) ); if( ch == '\\' ) { char buf[3]; char buf2[3]; buf[0] = ch; buf[1] = ch = ip_input(); buf[2] = '\0'; if( ch == EOF || ch == '\n' || ch == '\0' ) yyerror( _( "bad char constant" ) ); my_strccpy( buf2, buf ); ch = buf2[0]; } if( '\'' != ip_input() ) yyerror( _( "bad char constant" ) ); return( ch ); } %} %Start DOT %Start BINARY %option noyywrap %% \/\* { int ch; while( (ch = input()) != EOF ) if( ch == '*' ) { if( (ch = input()) == '/' ) break; else unput( ch ); } else if( ch == '/' ) { if( (ch = input()) == '*' ) yyerror( _( "nested comment" ) ); else unput( ch ); } if( ch == EOF ) yyerror( _( "no end of comment" ) ); } # | (\/\/) { int ch; /* Read string up to \n, EOF. */ while( (ch = input()) != EOF && ch != '\n' ) ; } \#separator { BEGIN 0; return( TK_SEPARATOR ); } \#dialog { BEGIN 0; return( TK_DIALOG ); } class { BEGIN 0; return( TK_CLASS ); } scope { BEGIN 0; return( TK_SCOPE ); } char { BEGIN 0; return( TK_CHAR ); } short { BEGIN 0; return( TK_SHORT ); } int { BEGIN 0; return( TK_INT ); } float { BEGIN 0; return( TK_FLOAT ); } double { BEGIN 0; return( TK_DOUBLE ); } signed { BEGIN 0; return( TK_SIGNED ); } unsigned { BEGIN 0; return( TK_UNSIGNED ); } complex { BEGIN 0; return( TK_COMPLEX ); } if { BEGIN 0; return( TK_IF ); } then { BEGIN 0; return( TK_THEN ); } else { BEGIN 0; return( TK_ELSE ); } \.\.\. { BEGIN 0; return( TK_DOTDOTDOT ); } \.\. { BEGIN 0; return( TK_DOTDOTDOT ); } true | TRUE { BEGIN BINARY; yylval.yy_const.type = PARSE_CONST_BOOL; yylval.yy_const.val.bool = TRUE; return( TK_CONST ); } false | FALSE { BEGIN BINARY; yylval.yy_const.type = PARSE_CONST_BOOL; yylval.yy_const.val.bool = FALSE; return( TK_CONST ); } [a-zA-Z_][a-zA-Z0-9_']* { BEGIN BINARY; yylval.yy_name = im_strdupn( yytext ); return( TK_TAG ); } [a-zA-Z_][a-zA-Z0-9_']* { char *name = model_loadstate_rewrite_name( yytext ); BEGIN BINARY; if( name ) { yylval.yy_name = im_strdupn( name ); vips_buf_change( &lex_text, yytext, name ); } else yylval.yy_name = im_strdupn( yytext ); return( TK_IDENT ); } \$[a-zA-Z_][a-zA-Z0-9_']* { BEGIN BINARY; yylval.yy_const.type = PARSE_CONST_STR; yylval.yy_const.val.str = im_strdupn( yytext + 1 ); return( TK_CONST ); } \( { BEGIN 0; return( '(' ); } \) { BEGIN BINARY; return( ')' ); } \+\+ { BEGIN 0; return( TK_JOIN ); } \-\- { BEGIN 0; return( TK_DIFF ); } \+ | \- { BEGIN 0; return( *yytext ); } \- { BEGIN 0; return( TK_UMINUS ); } \+ { BEGIN 0; return( TK_UPLUS ); } \< { BEGIN 0; return( TK_LESS ); } \<\= { BEGIN 0; return( TK_LESSEQ ); } \> { BEGIN 0; return( TK_MORE ); } \>\= { BEGIN 0; return( TK_MOREEQ ); } \=\> { BEGIN 0; return( TK_TO ); } \& { BEGIN 0; return( TK_BAND ); } \&\& { BEGIN 0; return( TK_LAND ); } \:\: { BEGIN 0; return( TK_SUCHTHAT ); } \*\* { BEGIN 0; return( TK_POW ); } \>\> { BEGIN 0; return( TK_RSHIFT ); } \<\< { BEGIN 0; return( TK_LSHIFT ); } \<\- { BEGIN 0; return( TK_FROM ); } \| { BEGIN 0; return( TK_BOR ); } \|\| { BEGIN 0; return( TK_LOR ); } \=\= { BEGIN 0; return( TK_EQ ); } \=\=\= { BEGIN 0; return( TK_PEQ ); } \!\= { BEGIN 0; return( TK_NOTEQ ); } \!\=\= { BEGIN 0; return( TK_PNOTEQ ); } \\ { BEGIN 0; return( TK_LAMBDA ); } \^ | \? | \* | \/ | \% | \, | \! | \; | \[ | \: | \= | \~ | \@ | \{ | \} { BEGIN 0; return( *yytext ); } \. { BEGIN DOT; return( *yytext ); } \] { BEGIN BINARY; return( *yytext ); } 0x[0-9a-fA-F]+ { unsigned int i; BEGIN BINARY; if( sscanf( yytext, "0x%x", &i ) != 1 ) nip2yyerror( _( "bad number %s" ), yytext ); yylval.yy_const.type = PARSE_CONST_NUM; yylval.yy_const.val.num = i; return( TK_CONST ); } [0-9]*(\.[0-9]+)?([eE][+-]?[0-9]+)?[ij]? { double d; int ch; BEGIN BINARY; d = g_ascii_strtod( yytext, NULL ); yylval.yy_const.type = PARSE_CONST_NUM; yylval.yy_const.val.num = d; ch = yytext[strlen( yytext ) - 1]; if( ch == 'i' || ch == 'j' ) yylval.yy_const.type = PARSE_CONST_COMPLEX; return( TK_CONST ); } \' { BEGIN BINARY; yylval.yy_const.type = PARSE_CONST_CHAR; yylval.yy_const.val.ch = read_char(); return( TK_CONST ); } \" { ModelLoadState *state = model_loadstate; char buf[MAX_STRSIZE]; char buf2[MAX_STRSIZE]; BEGIN BINARY; read_string( buf ); /* We need to keep buf as exactly the string in the source, * including before interpretation of \ escapes, for the * vips_buf_change() to work. */ my_strccpy( buf2, buf ); if( state && state->rewrite_path ) { char buf3[FILENAME_MAX]; path_compact( buf2 ); /* We've interpreted \n etc. in my_strccpy() above, plus we * have nativised paths from / to \ and therefore introduced * backslashes that weren't there before. * * Before we write source code out again, we must reescape * everything. */ my_strecpy( buf3, buf2, TRUE ); vips_buf_change( &lex_text, buf, buf3 ); } if( strcmp( buf2, "" ) == 0 ) yylval.yy_const.type = PARSE_CONST_ELIST; else { yylval.yy_const.type = PARSE_CONST_STR; yylval.yy_const.val.str = im_strdupn( buf2 ); } return( TK_CONST ); } [ \t\n\r\m\01] ; . { nip2yyerror( _( "illegal character \"%c\"" ), *yytext ); } nip2-8.7.1/src/expr.h0000644000175000017500000000650513351443023011242 00000000000000/* Expressions. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_EXPR (expr_get_type()) #define EXPR( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_EXPR, Expr )) #define EXPR_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_EXPR, ExprClass)) #define IS_EXPR( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_EXPR )) #define IS_EXPR_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_EXPR )) #define EXPR_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_EXPR, ExprClass )) /* What we track to parse and compile some text. Can have several * of these for a symbol, all with different values. */ struct _Expr { /* We don't contain anything, but we are contained by Symbol, so we * need to be an iContainer subclass. */ iContainer parent_object; Symbol *sym; /* We are an expr for this symbol, scopewise */ Row *row; /* (optional) we have this display */ Compile *compile; /* Our compiled code */ GSList *static_links; /* Static LinkExprs which reference us */ GSList *dynamic_links; /* Dynamic LinkExprs which reference us */ PElement root; /* Pointer to value of this expr */ /* Are we recorded as having an Imageinfo as a value? Use this to * unlink us from the last ii we were linked to. */ Imageinfo *imageinfo; gboolean err; /* TRUE if there is an error in this expr */ char *error_top; char *error_sub; }; typedef struct _ExprClass { iContainerClass parent_class; /* new_value expr has been recalced and root points to a new piece of graph */ void (*new_value)( Expr *expr ); } ExprClass; extern GSList *expr_error_all; void *expr_error_print( Expr *expr, VipsBuf *buf ); typedef void *(*map_expr_fn)( Expr *, void *, void * ); Expr *expr_map_all( Expr *expr, map_expr_fn fn, void *a ); void *expr_name_print( Expr *expr ); void expr_name( Expr *expr, VipsBuf *buf ); Expr *expr_get_parent( Expr *expr ); Expr *expr_get_root( Expr *expr ); Expr *expr_get_root_dynamic( Expr *expr ); GType expr_get_type( void ); void *expr_strip( Expr *expr ); Expr *expr_new( Symbol *sym ); Expr *expr_clone( Symbol *sym ); /* Set and clear error state. */ void *expr_error_set( Expr *expr ); void expr_error_clear( Expr *expr ); void expr_error_get( Expr *expr ); void expr_link_make( Expr *expr, Symbol *child ); void *expr_link_break( Expr *expr, Symbol *child ); void *expr_dirty( Expr *expr, int serial ); void *expr_dirty_intrans( Expr *expr, int serial ); void expr_tip( Expr *expr, VipsBuf *buf ); void expr_new_value( Expr *expr ); void expr_resolve( Expr *expr ); nip2-8.7.1/src/panechild.c0000644000175000017500000000744113351443023012206 00000000000000/* The thing that sits in a pane showing the title and close button. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; static void panechild_finalize( GObject *gobject ) { Panechild *panechild = PANECHILD( gobject ); #ifdef DEBUG printf( "panechild_finalize\n" ); #endif /*DEBUG*/ /* My instance finalize stuff. */ IM_FREE( panechild->title ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void panechild_refresh( vObject *vobject ) { Panechild *panechild = PANECHILD( vobject ); #ifdef DEBUG printf( "panechild_refresh:\n" ); #endif /*DEBUG*/ set_glabel( panechild->label, "%s", panechild->title ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void panechild_class_init( PanechildClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = panechild_finalize; vobject_class->refresh = panechild_refresh; } static void panechild_hide_cb( GtkWidget *wid, Panechild *panechild ) { pane_animate_closed( panechild->pane ); } static void panechild_init( Panechild *panechild ) { GtkWidget *hbox; GtkWidget *but; GtkWidget *icon; #ifdef DEBUG printf( "panechild_init:\n" ); #endif /*DEBUG*/ panechild->pane = NULL; panechild->title = NULL; panechild->label = NULL; hbox = gtk_hbox_new( FALSE, 7 ); gtk_box_pack_start( GTK_BOX( panechild ), hbox, FALSE, FALSE, 0 ); but = gtk_button_new(); gtk_button_set_relief( GTK_BUTTON( but ), GTK_RELIEF_NONE ); gtk_box_pack_end( GTK_BOX( hbox ), but, FALSE, FALSE, 0 ); set_tooltip( but, _( "Close the pane" ) ); icon = gtk_image_new_from_stock( GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU ); gtk_container_add( GTK_CONTAINER( but ), icon ); gtk_signal_connect( GTK_OBJECT( but ), "clicked", GTK_SIGNAL_FUNC( panechild_hide_cb ), panechild ); panechild->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( panechild->label ), 0.0, 0.5 ); gtk_box_pack_start( GTK_BOX( hbox ), panechild->label, TRUE, TRUE, 2 ); gtk_widget_show_all( hbox ); } GtkType panechild_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( PanechildClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) panechild_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Panechild ), 32, /* n_preallocs */ (GInstanceInitFunc) panechild_init, }; type = g_type_register_static( TYPE_VOBJECT, "Panechild", &info, 0 ); } return( type ); } Panechild * panechild_new( Pane *pane, const char *title ) { Panechild *panechild = gtk_type_new( TYPE_PANECHILD ); IM_SETSTR( panechild->title, title ); panechild->pane = pane; pane_set_child( pane, panechild ); return( panechild ); } nip2-8.7.1/src/option.c0000644000175000017500000000607213351443023011566 00000000000000/* an input option ... put/get methods */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void option_finalize( GObject *gobject ) { Option *option; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_OPTION( gobject ) ); option = OPTION( gobject ); /* My instance finalize stuff. */ IM_FREEF( slist_free_all, option->labels ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static View * option_view_new( Model *model, View *parent ) { return( optionview_new() ); } /* Members of option we automate. */ static ClassmodelMember option_members[] = { { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_CAPTION, "caption", N_( "Caption" ), G_STRUCT_OFFSET( iObject, caption ) }, { CLASSMODEL_MEMBER_STRING_LIST, NULL, 0, MEMBER_LABELS, "labels", N_( "Labels" ), G_STRUCT_OFFSET( Option, labels ) }, { CLASSMODEL_MEMBER_INT, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Option, value ) } }; static void option_class_init( OptionClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->finalize = option_finalize; model_class->view_new = option_view_new; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = option_members; classmodel_class->n_members = IM_NUMBER( option_members ); } static void option_init( Option *option ) { option->labels = NULL; option->value = 0; iobject_set( IOBJECT( option ), CLASS_OPTION, NULL ); } GType option_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( OptionClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) option_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Option ), 32, /* n_preallocs */ (GInstanceInitFunc) option_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Option", &info, 0 ); } return( type ); } nip2-8.7.1/src/tslider.c0000644000175000017500000002742013351443023011724 00000000000000/* a slider with an entry widget */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Our signals. */ enum { CHANGED, ACTIVATE, SLIDER_CHANGED, TEXT_CHANGED, LAST_SIGNAL }; static GtkHBoxClass *parent_class = NULL; static guint tslider_signals[LAST_SIGNAL] = { 0 }; /* Are two doubles more or less equal. We need this when we check the sliders * for update to stop loops. The 0.0001 is a bit of a fudge :-( */ #define DEQ( A, B ) (ABS((A) - (B)) < 0.0001) static void tslider_destroy( GtkObject *object ) { Tslider *tslider; g_return_if_fail( object != NULL ); g_return_if_fail( IS_TSLIDER( object ) ); tslider = TSLIDER( object ); #ifdef DEBUG printf( "tslider_destroy: %p\n", tslider ); #endif /*DEBUG*/ /* My instance destroy stuff. */ if( tslider->adj ) { gtk_signal_disconnect_by_data( GTK_OBJECT( tslider->adj ), (gpointer) tslider ); tslider->adj = NULL; } GTK_OBJECT_CLASS( parent_class )->destroy( object ); } /* Map a value to a slider position. */ static double tslider_value_to_slider( Tslider *tslider, double value ) { /* Map our range to 0-1. */ const double scale = 1.0 / (tslider->to - tslider->from); const double to01 = (value - tslider->from) * scale; /* Pass through user fn. */ const double mapped = tslider->value_to_slider( tslider->from, tslider->to, to01 ); const double nvalue = mapped / scale + tslider->from; #ifdef DEBUG printf( "tslider_value_to_slider: %g, to %g\n", value, nvalue ); #endif /*DEBUG*/ /* Map back to main range. */ return( nvalue ); } /* Map a slider position to a value. */ static double tslider_slider_to_value( Tslider *tslider, double value ) { /* Map our range to 0-1. */ const double scale = 1.0 / (tslider->to - tslider->from); const double to01 = (value - tslider->from) * scale; /* Pass through user fn. */ const double mapped = tslider->slider_to_value( tslider->from, tslider->to, to01 ); const double nvalue = mapped / scale + tslider->from; #ifdef DEBUG printf( "tslider_slider_to_value: %g, to %g\n", value, nvalue ); #endif /*DEBUG*/ /* Map back to main range. */ return( nvalue ); } /* from/to/value have changed ... update the widgets. */ static void tslider_real_changed( Tslider *tslider ) { GtkAdjustment *adj = tslider->adj; GtkWidget *entry = tslider->entry; #ifdef DEBUG printf( "tslider_real_changed: %p, val = %g\n", tslider, tslider->value ); #endif /*DEBUG*/ if( tslider->auto_link ) tslider->svalue = tslider_value_to_slider( tslider, tslider->value ); gtk_signal_handler_block_by_data( GTK_OBJECT( adj ), tslider ); gtk_signal_handler_block_by_data( GTK_OBJECT( entry ), tslider ); /* Some libc's hate out-of-bounds precision, so clip, just in case. */ set_gentry( tslider->entry, "%.*f", IM_CLIP( 0, tslider->digits, 100 ), tslider->value ); gtk_scale_set_digits( GTK_SCALE( tslider->slider ), tslider->digits ); if( !DEQ( tslider->from, tslider->last_from ) || !DEQ( tslider->to, tslider->last_to ) ) { double range = tslider->to - tslider->from; adj->step_increment = range / 100; adj->page_increment = range / 10; adj->page_size = range / 10; adj->lower = tslider->from; adj->upper = tslider->to + adj->page_size; tslider->last_to = tslider->to; tslider->last_from = tslider->from; gtk_adjustment_changed( adj ); } if( !DEQ( tslider->svalue, tslider->last_svalue ) ) { adj->value = tslider->svalue; tslider->last_svalue = tslider->svalue; gtk_adjustment_value_changed( adj ); } gtk_signal_handler_unblock_by_data( GTK_OBJECT( adj ), tslider ); gtk_signal_handler_unblock_by_data( GTK_OBJECT( entry ), tslider ); } static void tslider_class_init( TsliderClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); GtkObjectClass *object_class = (GtkObjectClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = tslider_destroy; class->changed = tslider_real_changed; class->slider_changed = NULL; class->activate = NULL; /* Create signals. */ tslider_signals[CHANGED] = g_signal_new( "changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( TsliderClass, changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); tslider_signals[ACTIVATE] = g_signal_new( "activate", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( TsliderClass, activate ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); tslider_signals[SLIDER_CHANGED] = g_signal_new( "slider_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( TsliderClass, slider_changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); tslider_signals[TEXT_CHANGED] = g_signal_new( "text_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( TsliderClass, text_changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); /* Init methods. */ } /* From/to/value have changed ... tell everyone. */ void tslider_changed( Tslider *tslider ) { #ifdef DEBUG printf( "tslider_changed\n" ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( tslider ), tslider_signals[CHANGED], 0 ); } /* Activated! */ static void tslider_activate( Tslider *tslider ) { #ifdef DEBUG printf( "tslider_activate\n" ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( tslider ), tslider_signals[ACTIVATE], 0 ); } /* Just the slider changed. */ static void tslider_slider_changed( Tslider *tslider ) { #ifdef DEBUG printf( "tslider_slider_changed\n" ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( tslider ), tslider_signals[SLIDER_CHANGED], 0 ); } /* Text has been touched. */ static void tslider_text_changed( Tslider *tslider ) { #ifdef DEBUG printf( "tslider_text_changed\n" ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( tslider ), tslider_signals[TEXT_CHANGED], 0 ); } /* Enter in entry widget */ static void tslider_value_activate_cb( GtkWidget *entry, Tslider *tslider ) { double value; if( !get_geditable_double( entry, &value ) ) { iwindow_alert( entry, GTK_MESSAGE_ERROR ); return; } if( tslider->value != value ) { tslider->value = value; if( tslider->auto_link ) tslider_changed( tslider ); else tslider_activate( tslider ); } } /* Drag on slider. */ static void tslider_value_changed_cb( GtkAdjustment *adj, Tslider *tslider ) { #ifdef DEBUG printf( "tslider_value_changed_cb\n" ); #endif /*DEBUG*/ if( tslider->svalue != adj->value ) { tslider->svalue = adj->value; if( tslider->auto_link ) { tslider->value = tslider_slider_to_value( tslider, adj->value ); tslider_changed( tslider ); } else tslider_slider_changed( tslider ); } } /* Text has changed (and may need to be scanned later). */ static void tslider_text_changed_cb( GtkWidget *widget, Tslider *tslider ) { #ifdef DEBUG printf( "tslider_text_changed_cb\n" ); #endif /*DEBUG*/ tslider_text_changed( tslider ); } /* Default identity conversion. */ static double tslider_conversion_id( double from, double to, double value ) { return( value ); } static gboolean tslider_scroll_cb( GtkWidget *wid, GdkEvent *event, Tslider *tslider ) { gboolean handled; handled = FALSE; /* Stop any other scroll handlers running. We don't want the scroll * wheel to change widgets while we're moving. */ if( tslider->ignore_scroll ) handled = TRUE; return( handled ); } static void tslider_init( Tslider *tslider ) { #ifdef DEBUG printf( "tslider_init: %p\n", tslider ); #endif /*DEBUG*/ /* Any old start values ... overridden later. */ tslider->from = -1; tslider->to = -1; tslider->value = -1; tslider->svalue = -1; tslider->digits = -1; tslider->last_to = -1; tslider->last_from = -1; tslider->last_svalue = -1; tslider->ignore_scroll = TRUE; gtk_box_set_spacing( GTK_BOX( tslider ), 2 ); tslider->entry = build_entry( 5 ); gtk_entry_set_max_length( GTK_ENTRY( tslider->entry ), 10 ); set_tooltip( tslider->entry, _( "Slider value ... edit!" ) ); gtk_box_pack_start( GTK_BOX( tslider ), tslider->entry, FALSE, FALSE, 0 ); gtk_signal_connect( GTK_OBJECT( tslider->entry ), "activate", GTK_SIGNAL_FUNC( tslider_value_activate_cb ), tslider ); gtk_signal_connect( GTK_OBJECT( tslider->entry ), "changed", GTK_SIGNAL_FUNC( tslider_text_changed_cb ), tslider ); gtk_widget_show( tslider->entry ); tslider->slider = gtk_hscale_new( NULL ); tslider->adj = gtk_range_get_adjustment( GTK_RANGE( tslider->slider ) ); gtk_range_set_update_policy( GTK_RANGE( tslider->slider ), GTK_UPDATE_CONTINUOUS ); #ifdef DEBUG gtk_range_set_update_policy( GTK_RANGE( tslider->slider ), GTK_UPDATE_DISCONTINUOUS ); #endif /*DEBUG*/ gtk_scale_set_draw_value( GTK_SCALE( tslider->slider ), FALSE ); gtk_widget_set_size_request( GTK_WIDGET( tslider->slider ), 100, -1 ); gtk_box_pack_start( GTK_BOX( tslider ), tslider->slider, TRUE, TRUE, 0 ); set_tooltip( tslider->slider, _( "Left-drag to set number" ) ); gtk_signal_connect( GTK_OBJECT( tslider->adj ), "value_changed", GTK_SIGNAL_FUNC( tslider_value_changed_cb ), tslider ); g_signal_connect( tslider->slider, "scroll-event", G_CALLBACK( tslider_scroll_cb ), tslider ); gtk_widget_show( tslider->slider ); tslider->auto_link = TRUE; tslider->slider_to_value = tslider_conversion_id; tslider->value_to_slider = tslider_conversion_id; } GtkType tslider_get_type( void ) { static GtkType tslider_type = 0; if( !tslider_type ) { static const GtkTypeInfo sinfo = { "Tslider", sizeof( Tslider ), sizeof( TsliderClass ), (GtkClassInitFunc) tslider_class_init, (GtkObjectInitFunc) tslider_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; tslider_type = gtk_type_unique( GTK_TYPE_HBOX, &sinfo ); } return( tslider_type ); } Tslider * tslider_new() { Tslider *tslider = gtk_type_new( TYPE_TSLIDER ); return( tslider ); } void tslider_set_conversions( Tslider *tslider, tslider_fn value_to_slider, tslider_fn slider_to_value ) { tslider->value_to_slider = value_to_slider; tslider->slider_to_value = slider_to_value; tslider->auto_link = value_to_slider && slider_to_value; } double tslider_log_value_to_slider( double from, double to, double value ) { /* What does 1.0 map to on our [0,1] scale? */ const double mapped1 = (1.0 - from) / (to - from); /* We want an exponent which maps the mid point on the slider to 1. */ const double a = log( mapped1 ) / log( 0.5 ); const double nvalue = pow( value, 1.0 / a ); return( nvalue ); } double tslider_log_slider_to_value( double from, double to, double value ) { /* What does 1.0 map to on our [0,1] scale? */ const double mapped1 = (1.0 - from) / (to - from); /* We want an exponent which maps the mid point on the slider to 1. */ const double a = log( mapped1 ) / log( 0.5 ); const double nvalue = pow( value, a ); return( nvalue ); } void tslider_set_ignore_scroll( Tslider *tslider, gboolean ignore_scroll ) { tslider->ignore_scroll = ignore_scroll; } nip2-8.7.1/src/expressionview.c0000644000175000017500000001404413351443023013346 00000000000000/* a view of a text thingy */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; /* Re-read the text in a tally entry. */ static void * expressionview_scan( View *view ) { Expressionview *expressionview = EXPRESSIONVIEW( view ); Expression *expression = EXPRESSION( VOBJECT( expressionview )->iobject ); iText *itext = expression_get_itext( expression ); #ifdef DEBUG { Row *row = HEAPMODEL( expression )->row; printf( "expressionview_scan: " ); row_name_print( row ); printf( "\n" ); } #endif /*DEBUG*/ if( itext && formula_scan( expressionview->formula ) && itext_set_formula( itext, expressionview->formula->expr ) ) { itext_set_edited( itext, TRUE ); /* ... make sure MEMBER_VALUE gets marked dirty too. */ expr_dirty( HEAPMODEL( itext )->row->expr, link_serial_new() ); } return( VIEW_CLASS( parent_class )->scan( view ) ); } void expressionview_activate_cb( GtkWidget *wid, Expressionview *expressionview ) { Expression *expression = EXPRESSION( VOBJECT( expressionview )->iobject ); Row *row = HEAPMODEL( expression )->row; /* Reset edits on this row and all children. */ (void) icontainer_map_all( ICONTAINER( row ), (icontainer_map_fn) heapmodel_clear_edited, NULL ); /* Make sure we scan this text, even if it's not been edited. */ view_scannable_register( VIEW( expressionview ) ); workspace_set_modified( row->ws, TRUE ); symbol_recalculate_all(); } static void expressionview_refresh( vObject *vobject ) { Expressionview *expressionview = EXPRESSIONVIEW( vobject ); Expression *expression = EXPRESSION( VOBJECT( expressionview )->iobject ); iText *itext = expression_get_itext( expression ); Row *row = HEAPMODEL( expression )->row; #ifdef DEBUG printf( "expressionview_refresh: " ); row_name_print( row ); printf( " (%p)\n", vobject ); #endif /*DEBUG*/ formula_set_edit( expressionview->formula, row->ws->mode == WORKSPACE_MODE_FORMULA ); if( itext ) formula_set_value_expr( expressionview->formula, vips_buf_all( &itext->value ), itext->formula ); if( vobject->iobject->caption ) formula_set_caption( expressionview->formula, vobject->iobject->caption ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void expressionview_set_edit( Expressionview *expressionview, gboolean edit ) { formula_set_edit( expressionview->formula, edit ); if( edit ) view_resettable_register( VIEW( expressionview ) ); } static void expressionview_link( View *view, Model *model, View *parent ) { Expressionview *expressionview = EXPRESSIONVIEW( view ); Expression *expression = EXPRESSION( model ); Row *row = HEAPMODEL( expression )->row; #ifdef DEBUG printf( "expressionview_link: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ VIEW_CLASS( parent_class )->link( view, model, parent ); if( GRAPHICVIEW( view )->sview ) gtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group, expressionview->formula->left_label ); /* Edit mode defaults to edit mode for workspace. */ expressionview_set_edit( expressionview, row->ws->mode == WORKSPACE_MODE_FORMULA ); } /* Reset edit mode ... go back to whatever is set for this ws. */ static void expressionview_reset( View *view ) { Expressionview *expressionview = EXPRESSIONVIEW( view ); Expression *expression = EXPRESSION( VOBJECT( expressionview )->iobject ); Row *row = HEAPMODEL( expression )->row; expressionview_set_edit( expressionview, row->ws->mode == WORKSPACE_MODE_FORMULA ); } static void expressionview_class_init( ExpressionviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = expressionview_refresh; view_class->link = expressionview_link; view_class->reset = expressionview_reset; view_class->scan = expressionview_scan; } static void expressionview_init( Expressionview *expressionview ) { expressionview->formula = formula_new(); gtk_signal_connect_object( GTK_OBJECT( expressionview->formula ), "changed", GTK_SIGNAL_FUNC( view_changed_cb ), GTK_OBJECT( expressionview ) ); gtk_signal_connect( GTK_OBJECT( expressionview->formula ), "activate", GTK_SIGNAL_FUNC( expressionview_activate_cb ), expressionview ); gtk_box_pack_start( GTK_BOX( expressionview ), GTK_WIDGET( expressionview->formula ), TRUE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( expressionview->formula ) ); } GtkType expressionview_get_type( void ) { static GtkType expressionview_type = 0; if( !expressionview_type ) { static const GtkTypeInfo expressionview_info = { "Expressionview", sizeof( Expressionview ), sizeof( ExpressionviewClass ), (GtkClassInitFunc) expressionview_class_init, (GtkObjectInitFunc) expressionview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; expressionview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &expressionview_info ); } return( expressionview_type ); } View * expressionview_new( void ) { Expressionview *expressionview = gtk_type_new( TYPE_EXPRESSIONVIEW ); return( VIEW( expressionview ) ); } nip2-8.7.1/src/iregionview.h0000644000175000017500000000304713351443023012611 00000000000000/* display a region in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IREGIONVIEW (iregionview_get_type()) #define IREGIONVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_IREGIONVIEW, iRegionview )) #define IREGIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_IREGIONVIEW, iRegionviewClass )) #define IS_IREGIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IREGIONVIEW )) #define IS_IREGIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_IREGIONVIEW )) typedef struct _iRegionview { iImageview parent_class; } iRegionview; typedef struct _iRegionviewClass { iImageviewClass parent_class; /* My methods. */ } iRegionviewClass; GtkType iregionview_get_type( void ); View *iregionview_new( void ); nip2-8.7.1/src/idialog.c0000644000175000017500000004213413351443023011665 00000000000000/* make and manage base dialogs ... subclass off this for others */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static iWindowClass *parent_class = NULL; /* An OK button: label (can be a stock) plus a callback. */ typedef struct { char *label; iWindowFn done_cb; } OKButton; static void * okbutton_free( OKButton *ok ) { IM_FREEF( g_free, ok->label ); ok->done_cb = NULL; IM_FREEF( g_free, ok ); return( NULL ); } static OKButton * okbutton_new( char *label, iWindowFn done_cb ) { OKButton *ok; ok = g_new( OKButton, 1 ); ok->label = g_strdup( label ); ok->done_cb = done_cb; return( ok ); } /* Handy destroy callback ... just free client. */ void idialog_free_client( iDialog *idlg, void *client ) { IM_FREE( client ); } /* Notify our parent. */ static void idialog_notify_parent( iDialog *idlg, iWindowResult result ) { if( idlg->nfn ) { iWindowNotifyFn nfn = idlg->nfn; idlg->nfn = NULL; nfn( idlg->sys, result ); } } static void * idialog_set_sensitive( GtkWidget *w, gboolean state ) { gtk_widget_set_sensitive( w, state ); return( NULL ); } /* Set OK sensitivities. */ void idialog_set_ok_button_state( iDialog *idlg, gboolean state ) { slist_map( idlg->ok_but_l, (SListMapFn) idialog_set_sensitive, GINT_TO_POINTER( state ) ); } /* Set all the button sensitivities. */ static void idialog_set_button_state( iDialog *idlg, gboolean state ) { idialog_set_ok_button_state( idlg, state ); if( idlg->but_cancel ) gtk_widget_set_sensitive( idlg->but_cancel, state ); if( idlg->but_help ) gtk_widget_set_sensitive( idlg->but_help, state ); } /* Sub-fn of below. Come back from a popdown notify. */ static void idialog_popdown_notify( void *sys, iWindowResult result ) { iWindowSusp *susp = IWINDOW_SUSP( sys ); iDialog *idlg = IDIALOG( susp->client ); if( result == IWINDOW_YES ) /* If our caller hasn't been notified yet, post off a FALSE. */ idialog_notify_parent( idlg, IWINDOW_NO ); /* Pass result on to our suspension (ie. back to iwindow). */ iwindow_susp_return( susp, result ); /* Housekeeping. */ iwindow_notify_return( IWINDOW( idlg ) ); } /* Our popdown callback ... here from iwindow. */ static void idialog_popdown_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { iDialog *idlg = IDIALOG( client ); iWindowSusp *susp = iwindow_susp_new( NULL, iwnd, idlg, nfn, sys ); #ifdef DEBUG printf( "idialog_popdown_cb: %s\n", IWINDOW( idlg )->title ); #endif /*DEBUG*/ /* Trigger user popdown. */ iwindow_notify_send( IWINDOW( idlg ), idlg->popdown_cb, idlg->client, idialog_popdown_notify, susp ); } /* Sub-fn of below. Come back from a done notify. */ static void idialog_done_notify( void *sys, iWindowResult result ) { iDialog *idlg = IDIALOG( sys ); #ifdef DEBUG printf( "idialog_done_notify: %s\n", IWINDOW( idlg )->title ); #endif /*DEBUG*/ idialog_set_button_state( idlg, TRUE ); /* If all ok, popdown and tell our parent. */ if( result == IWINDOW_YES ) { /* Unless we're pinned up, that is. */ if( !(idlg->tog_pin && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( idlg->tog_pin ) )) ) { idialog_notify_parent( idlg, result ); iwindow_kill( IWINDOW( idlg ) ); } } /* Alert on failure. */ if( result == IWINDOW_ERROR ) iwindow_alert( GTK_WIDGET( idlg ), GTK_MESSAGE_ERROR ); /* Clean up. */ iwindow_notify_return( IWINDOW( idlg ) ); } /* Make a DONE event happen. Used (for example) by the browse window to force * a done in the enclosing FSB on double click on icon. */ void idialog_done_trigger( iDialog *idlg, int pos ) { OKButton *ok = (OKButton *) g_slist_nth_data( idlg->ok_disp_l, pos ); #ifdef DEBUG printf( "idialog_done_trigger: %s, %d\n", IWINDOW( idlg )->title, pos ); #endif /*DEBUG*/ /* Trigger user done callback. */ g_assert( pos >= 0 ); g_assert( ok->done_cb ); idialog_set_button_state( idlg, FALSE ); iwindow_notify_send( IWINDOW( idlg ), ok->done_cb, idlg->client, idialog_done_notify, idlg ); } /* Sub-fn of below. */ static void idialog_cancel_notify( void *sys, iWindowResult result ) { iDialog *idlg = IDIALOG( sys ); #ifdef DEBUG printf( "idialog_cancel_notify: %s\n", IWINDOW( idlg )->title ); #endif /*DEBUG*/ idialog_set_button_state( idlg, TRUE ); /* Send cancel message back to parent if our client cancel was OK. */ if( result == IWINDOW_YES ) { idialog_notify_parent( idlg, IWINDOW_NO ); iwindow_kill( IWINDOW( idlg ) ); } /* Alert on error. */ if( result == IWINDOW_ERROR ) iwindow_alert( GTK_WIDGET( idlg ), GTK_MESSAGE_ERROR ); /* Clean up. */ iwindow_notify_return( IWINDOW( idlg ) ); } static void idialog_cancel_trigger( iDialog *idlg ) { #ifdef DEBUG printf( "idialog_cancel_trigger: %s\n", IWINDOW( idlg )->title ); #endif /*DEBUG*/ /* Trigger user cancel function. */ idialog_set_button_state( idlg, FALSE ); iwindow_notify_send( IWINDOW( idlg ), idlg->cancel_cb, idlg->client, idialog_cancel_notify, idlg ); } /* Button callbacks from gtk. */ static void idialog_done_cb( GtkWidget *w, iDialog *idlg ) { int pos = g_slist_index( idlg->ok_but_l, w ); g_assert( pos != -1 ); idialog_done_trigger( idlg, pos ); } static void idialog_cancel_cb( GtkWidget *w, iDialog *idlg ) { idialog_cancel_trigger( idlg ); } static void idialog_help_cb( GtkWidget *w, iDialog *idlg ) { if( idlg->help_tag ) box_help( GTK_WIDGET( idlg ), idlg->help_tag ); } static void idialog_destroy( GtkObject *object ) { iDialog *idlg; #ifdef DEBUG printf( "idialog_destroy\n" ); #endif /*DEBUG*/ g_return_if_fail( object != NULL ); g_return_if_fail( IS_IDIALOG( object ) ); idlg = IDIALOG( object ); #ifdef DEBUG printf( "... %s\n", IWINDOW( idlg )->title ); #endif /*DEBUG*/ /* My instance destroy stuff. */ if( idlg->destroy_cb ) { idlg->destroy_cb( idlg, idlg->client ); idlg->destroy_cb = NULL; } FREESID( idlg->destroy_sid, idlg->iobject ); slist_map( idlg->ok_l, (SListMapFn) okbutton_free, NULL ); IM_FREEF( g_slist_free, idlg->ok_l ); IM_FREEF( g_slist_free, idlg->ok_disp_l ); IM_FREEF( g_slist_free, idlg->ok_but_l ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void idialog_realize( GtkWidget *widget ) { iDialog *idlg = IDIALOG( widget ); #ifdef DEBUG printf( "idialog_realize: %s\n", IWINDOW( idlg )->title ); #endif /*DEBUG*/ GTK_WIDGET_CLASS( parent_class )->realize( widget ); if( idlg->entry ) gtk_widget_grab_focus( GTK_WIDGET( idlg->entry ) ); } /* The object we represent has been destroyed, kill us too. */ static void idialog_iobject_destroy( iObject *iobject, iDialog *idlg ) { #ifdef DEBUG printf( "idialog_iobject_destroy: %s\n", IWINDOW( idlg )->title ); #endif /*DEBUG*/ /* This object has gone. */ idlg->iobject = NULL; iwindow_kill( IWINDOW( idlg ) ); } static void * idialog_build_ok( OKButton *ok, iDialog *idlg ) { GtkWidget *but; but = build_button( ok->label, GTK_SIGNAL_FUNC( idialog_done_cb ), idlg ); idlg->ok_disp_l = g_slist_prepend( idlg->ok_disp_l, ok ); idlg->ok_but_l = g_slist_prepend( idlg->ok_but_l, but ); gtk_box_pack_start( GTK_BOX( idlg->bb ), but, TRUE, TRUE, 0 ); gtk_widget_show( but ); return( NULL ); } static void * idialog_build_cancel( iDialog *idlg ) { idlg->but_cancel = build_button( idlg->cancel_text, GTK_SIGNAL_FUNC( idialog_cancel_cb ), idlg ); gtk_box_pack_start( GTK_BOX( idlg->bb ), idlg->but_cancel, TRUE, TRUE, 0 ); gtk_widget_show( idlg->but_cancel ); return( NULL ); } /* Set a button to be the dialog default. Turn off button_focus for complex * dialogs like file_chooser which have their on focus systems. */ static void idialog_set_default( iDialog *idlg, GtkWidget *widget ) { if( idlg->button_focus ) gtk_widget_grab_focus( widget ); GTK_WIDGET_SET_FLAGS( widget, GTK_CAN_DEFAULT ); gtk_window_set_default( GTK_WINDOW( idlg ), widget ); } static void idialog_build( GtkWidget *widget ) { iDialog *idlg = IDIALOG( widget ); iWindow *iwnd = IWINDOW( idlg ); #ifdef DEBUG printf( "idialog_build: %s\n", iwnd->title ); #endif /*DEBUG*/ /* Call all builds in superclasses. */ if( IWINDOW_CLASS( parent_class )->build ) (*IWINDOW_CLASS( parent_class )->build)( widget ); /* delete_event and destroy handled by our superclass. */ iwindow_set_popdown( iwnd, idialog_popdown_cb, idlg ); gtk_window_set_modal( GTK_WINDOW( idlg ), idlg->modal ); idlg->work = gtk_vbox_new( FALSE, 6 ); gtk_container_set_border_width( GTK_CONTAINER( idlg->work ), 12 ); gtk_box_pack_start( GTK_BOX( iwnd->work ), idlg->work, TRUE, TRUE, 0 ); if( !idlg->nosep ) { GtkWidget *sep; sep = gtk_hseparator_new(); gtk_box_pack_start( GTK_BOX( iwnd->work ), sep, FALSE, FALSE, 2 ); gtk_widget_show( sep ); } idlg->hb = gtk_hbox_new( FALSE, 6 ); gtk_container_set_border_width( GTK_CONTAINER( idlg->hb ), 12 ); gtk_box_pack_start( GTK_BOX( iwnd->work ), idlg->hb, FALSE, FALSE, 0 ); gtk_widget_show( idlg->hb ); if( idlg->pinup ) { idlg->tog_pin = gtk_check_button_new_with_label( _( "Pin up" ) ); set_tooltip( idlg->tog_pin, _( "Check this to pin the dialog up" ) ); gtk_box_pack_start( GTK_BOX( idlg->hb ), idlg->tog_pin, FALSE, FALSE, 0 ); gtk_widget_show( idlg->tog_pin ); } idlg->bb = gtk_hbutton_box_new(); gtk_button_box_set_layout( GTK_BUTTON_BOX( idlg->bb ), GTK_BUTTONBOX_END ); gtk_box_set_spacing( GTK_BOX( idlg->bb ), 6 ); gtk_box_pack_end( GTK_BOX( idlg->hb ), idlg->bb, FALSE, FALSE, 0 ); gtk_widget_show( idlg->bb ); /* Default button order: * * Help OK3 OK2 Cancel OK1 * * win32 button order: * * OK1 OK2 OK3 Cancel Help */ #ifdef OS_WIN32 /* OK buttons. */ slist_map( idlg->ok_l, (SListMapFn) idialog_build_ok, idlg ); if( idlg->cancel_cb ) { idialog_build_cancel( idlg ); /* Cancel grabs default if it's the only button. Set focus * too; user build can change this later. */ if( !idlg->ok_l ) idialog_set_default( idlg, idlg->but_cancel ); } if( idlg->help_tag ) { idlg->but_help = build_button( GTK_STOCK_HELP, GTK_SIGNAL_FUNC( idialog_help_cb ), idlg ); gtk_widget_show( idlg->but_help ); } #else /*!OS_WIN32*/ if( idlg->help_tag ) { idlg->but_help = build_button( GTK_STOCK_HELP, GTK_SIGNAL_FUNC( idialog_help_cb ), idlg ); gtk_box_pack_end( GTK_BOX( idlg->bb ), idlg->but_help, TRUE, TRUE, 0 ); gtk_button_box_set_child_secondary( GTK_BUTTON_BOX( idlg->bb ), idlg->but_help, TRUE ); gtk_widget_show( idlg->but_help ); } /* Add OK2, 3, etc. */ if( idlg->ok_l && idlg->ok_l->next ) slist_map_rev( idlg->ok_l->next, (SListMapFn) idialog_build_ok, idlg ); if( idlg->cancel_cb ) { idialog_build_cancel( idlg ); /* Cancel grabs default if it's the only button. Set focus * too; user build can change this later. */ if( !idlg->ok_l ) idialog_set_default( idlg, idlg->but_cancel ); } /* Make OK1 */ if( idlg->ok_l ) { OKButton *ok1 = (OKButton *) idlg->ok_l->data; idialog_build_ok( ok1, idlg ); } #endif /*lots*/ /* OK1 grabs the default. */ if( idlg->ok_but_l ) idialog_set_default( idlg, idlg->ok_but_l->data ); /* Escape triggers cancel, if there is a cancel. */ if( idlg->cancel_cb ) gtk_widget_add_accelerator( idlg->but_cancel, "clicked", iwnd->accel_group, GDK_Escape, 0, 0 ); else { /* If there's just 1 OK, that gets Esc too. */ if( idlg->ok_but_l && g_slist_length( idlg->ok_but_l ) == 1 ) gtk_widget_add_accelerator( GTK_WIDGET( idlg->ok_but_l->data ), "clicked", iwnd->accel_group, GDK_Escape, 0, 0 ); } /* F1 triggers help. */ if( idlg->but_help ) gtk_widget_add_accelerator( idlg->but_help, "clicked", iwnd->accel_group, GDK_F1, 0, 0 ); /* Build user dialog contents. */ if( idlg->build ) idlg->build( iwnd, idlg->work, idlg->build_a, idlg->build_b, idlg->build_c ); if( idlg->iobject ) idlg->destroy_sid = g_signal_connect( idlg->iobject, "destroy", G_CALLBACK( idialog_iobject_destroy ), idlg ); gtk_widget_show( idlg->work ); } static void idialog_class_init( iDialogClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; iWindowClass *iwindow_class = (iWindowClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = idialog_destroy; widget_class->realize = idialog_realize; iwindow_class->build = idialog_build; iwindow_class->transient = TRUE; /* Create signals. */ /* Init methods. */ } static void idialog_init( iDialog *idlg ) { #ifdef DEBUG printf( "idialog_init: %s\n", IWINDOW( idlg )->title ); #endif /*DEBUG*/ /* Init our instance fields. */ idlg->iobject = NULL; idlg->destroy_sid = 0; idlg->work = NULL; idlg->ok_l = NULL; idlg->ok_disp_l = NULL; idlg->ok_but_l = NULL; idlg->but_cancel = NULL; idlg->but_help = NULL; idlg->tog_pin = NULL; idlg->entry = NULL; idlg->modal = FALSE; idlg->pinup = FALSE; idlg->nosep = FALSE; idlg->button_focus = TRUE; idlg->help_tag = NULL; idlg->cancel_text = GTK_STOCK_CANCEL; idlg->cancel_cb = NULL; idlg->popdown_cb = NULL; idlg->destroy_cb = NULL; idlg->client = NULL; idlg->arg = NULL; idlg->nfn = iwindow_notify_null; idlg->sys = NULL; gtk_window_set_position( GTK_WINDOW( idlg ), GTK_WIN_POS_CENTER_ON_PARENT ); } GtkType idialog_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "iDialog", sizeof( iDialog ), sizeof( iDialogClass ), (GtkClassInitFunc) idialog_class_init, (GtkObjectInitFunc) idialog_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_IWINDOW, &info ); } return( type ); } GtkWidget * idialog_new() { iDialog *idlg = gtk_type_new( TYPE_IDIALOG ); GtkWindow *gwnd = GTK_WINDOW( idlg ); /* Init gtk base class. */ gwnd->type = GTK_WINDOW_TOPLEVEL; return( GTK_WIDGET( idlg ) ); } void idialog_set_iobject( iDialog *idlg, iObject *iobject ) { idlg->iobject = iobject; } void idialog_set_pinup( iDialog *idlg, gboolean pinup ) { idlg->pinup = pinup; if( idlg->tog_pin ) gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( idlg->tog_pin ), TRUE ); } void idialog_set_modal( iDialog *idlg, gboolean modal ) { idlg->modal = modal; } void idialog_set_nosep( iDialog *idlg, gboolean nosep ) { idlg->nosep = nosep; } void idialog_set_button_focus( iDialog *idlg, gboolean button_focus ) { idlg->button_focus = button_focus; } void idialog_set_help_tag( iDialog *idlg, const char *help_tag ) { IM_SETSTR( idlg->help_tag, help_tag ); } void idialog_set_callbacks( iDialog *idlg, iWindowFn cancel_cb, iWindowFn popdown_cb, iDialogFreeFn destroy_cb, void *client ) { idlg->cancel_cb = cancel_cb; idlg->popdown_cb = popdown_cb; idlg->destroy_cb = destroy_cb; idlg->client = client; } void idialog_add_ok( iDialog *idlg, iWindowFn done_cb, const char *fmt, ... ) { va_list ap; char buf[1024]; va_start( ap, fmt ); (void) im_vsnprintf( buf, 1024, fmt, ap ); va_end( ap ); /* So the last OK button added is the default one (and at the head of * the list). [OK1, OK2, OK3, OK4] */ idlg->ok_l = g_slist_prepend( idlg->ok_l, okbutton_new( buf, done_cb ) ); } void idialog_set_notify( iDialog *idlg, iWindowNotifyFn nfn, void *sys ) { idlg->nfn = nfn; idlg->sys = sys; } void idialog_set_build( iDialog *idlg, iWindowBuildFn build, void *build_a, void *build_b, void *build_c ) { idlg->build = build; idlg->build_a = build_a; idlg->build_b = build_b; idlg->build_c = build_c; } void idialog_set_cancel_text( iDialog *idlg, const char *cancel_text ) { idlg->cancel_text = cancel_text; } void idialog_set_default_entry( iDialog *idlg, GtkEntry *entry ) { gtk_entry_set_activates_default( entry, TRUE ); idlg->entry = entry; } /* Set up an entry inside a dialog ... set tooltip, set start * value, link to OK button in enclosing dialog. */ void idialog_init_entry( iDialog *idlg, GtkWidget *entry, const char *tip, const char *fmt, ... ) { va_list ap; va_start( ap, fmt ); set_gentryv( entry, fmt, ap ); va_end( ap ); set_tooltip( entry, "%s", tip ); idialog_set_default_entry( idlg, GTK_ENTRY( entry ) ); } nip2-8.7.1/src/colour.c0000644000175000017500000002146313351443023011562 00000000000000/* an image class object in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Set of allowed colour_space strings. Do a case-insensitive match. */ static const char *colour_colour_space[] = { "xyz", /* index 0 */ "yxy", /* index 1 */ "lab", /* index 2 */ "lch", /* index 3 */ "ucs", /* index 4 */ "rgb", /* index 5 */ "srgb", /* index 6 */ "rgb16", /* index 7 */ "grey16" /* index 8 */ }; /* For each allowed colourspace, the corresponding VIPS Type value. */ static const int colour_type[] = { IM_TYPE_XYZ, IM_TYPE_YXY, IM_TYPE_LAB, IM_TYPE_LCH, IM_TYPE_UCS, IM_TYPE_RGB, IM_TYPE_sRGB, IM_TYPE_RGB16, IM_TYPE_GREY16 }; static ClassmodelClass *parent_class = NULL; static void colour_finalize( GObject *gobject ) { Colour *colour = COLOUR( gobject ); IM_FREE( colour->colour_space ); vips_buf_destroy( &colour->caption ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Widgets for colour edit. */ typedef struct _ColourEdit { iDialog *idlg; Colour *colour; GtkWidget *colour_widget; } ColourEdit; /* Find the VIPS type for a colour space string. */ static int colour_get_vips_type( Colour *colour ) { int type; int i; /* Default to something harmless. */ type = IM_TYPE_MULTIBAND; if( colour->colour_space ) for( i = 0; i < IM_NUMBER( colour_colour_space ); i++ ) if( strcasecmp( colour->colour_space, colour_colour_space[i] ) == 0 ) { type = colour_type[i]; break; } return( type ); } /* Are two doubles more or less equal. We need this when we check * for update to stop loops. The 0.0001 is a bit of a fudge :-( */ #define DEQ( A, B ) (ABS((A) - (B)) < 0.0001) /* Update non-model stuff in object from the model params. */ static void colour_refresh( Colour *colour ) { vips_buf_rewind( &colour->caption ); vips_buf_appendf( &colour->caption, CLASS_COLOUR " %s [%g, %g, %g]", NN( colour->colour_space ), colour->value[0], colour->value[1], colour->value[2] ); } void colour_set_colour( Colour *colour, const char *colour_space, double value[3] ) { int i; /* No change? */ for( i = 0; i < 3; i++ ) if( !DEQ( value[i], colour->value[i] ) ) break; if( i == 3 && colour_space && strcmp( colour_space, colour->colour_space ) == 0 ) return; for( i = 0; i < 3; i++ ) colour->value[i] = value[i]; IM_SETSTR( colour->colour_space, colour_space ); colour_refresh( colour ); classmodel_update( CLASSMODEL( colour ) ); symbol_recalculate_all(); } /* Code up a colour as an ii. Refcount zero! Will go on next GC. */ Imageinfo * colour_ii_new( Colour *colour ) { Imageinfo *imageinfo; int i; if( !(imageinfo = imageinfo_new_temp( main_imageinfogroup, reduce_context->heap, NULL, "t" )) ) return( NULL ); /* Make a 3 band 32-bit FLOAT memory image. */ im_initdesc( imageinfo->im, 1, 1, 3, IM_BBITS_FLOAT, IM_BANDFMT_FLOAT, IM_CODING_NONE, colour_get_vips_type( colour ), 1.0, 1.0, 0, 0 ); if( im_setupout( imageinfo->im ) ) return( NULL ); for( i = 0; i < 3; i++ ) ((float *) imageinfo->im->data)[i] = colour->value[i]; return( imageinfo ); } /* Convert our colour to rgb. Slow! */ static void colour_get_rgb( Colour *colour, double rgb[4] ) { int i; Imageinfo *imageinfo; for( i = 0; i < 4; i++ ) rgb[i] = 0.0; if( (imageinfo = colour_ii_new( colour )) ) imageinfo_to_rgb( imageinfo, rgb ); } void colour_set_rgb( Colour *colour, double rgb[4] ) { Imageinfo *imageinfo; if( (imageinfo = colour_ii_new( colour )) ) { double old_rgb[4]; double value[3]; int i; /* Setting as RGB can't express small differences since we're * going via 8 bit RGB. So only accept the new value if it's * sufficiently different from * what we have now. */ colour_get_rgb( colour, old_rgb ); if( fabs( rgb[0] - old_rgb[0] ) > (0.5 / 255) || fabs( rgb[1] - old_rgb[1] ) > (0.5 / 255) || fabs( rgb[2] - old_rgb[2] ) > (0.5 / 255) ) { imageinfo_from_rgb( imageinfo, rgb ); for( i = 0; i < 3; i++ ) value[i] = ((float *) imageinfo->im->data)[i]; colour_set_colour( colour, colour->colour_space, value ); } } } /* Done button hit. */ static void colour_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { ColourEdit *eds = (ColourEdit *) client; Colour *colour = eds->colour; double rgb[4]; gtk_color_selection_get_color( GTK_COLOR_SELECTION( eds->colour_widget ), rgb ); colour_set_rgb( colour, rgb ); nfn( sys, IWINDOW_YES ); } /* Build the insides of colour edit. */ static void colour_buildedit( iDialog *idlg, GtkWidget *work, ColourEdit *eds ) { Colour *colour = eds->colour; double rgb[4]; eds->colour_widget = gtk_color_selection_new(); gtk_color_selection_set_has_opacity_control( GTK_COLOR_SELECTION( eds->colour_widget ), FALSE ); colour_get_rgb( colour, rgb ); gtk_color_selection_set_color( GTK_COLOR_SELECTION( eds->colour_widget ), rgb ); gtk_box_pack_start( GTK_BOX( work ), eds->colour_widget, TRUE, TRUE, 2 ); gtk_widget_show_all( work ); } static void colour_edit( GtkWidget *parent, Model *model ) { Colour *colour = COLOUR( model ); ColourEdit *eds = INEW( NULL, ColourEdit ); GtkWidget *idlg; eds->colour = colour; idlg = idialog_new(); iwindow_set_title( IWINDOW( idlg ), _( "Edit %s %s" ), IOBJECT_GET_CLASS_NAME( model ), IOBJECT( HEAPMODEL( model )->row )->name ); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) colour_buildedit, eds, NULL, NULL ); idialog_set_callbacks( IDIALOG( idlg ), iwindow_true_cb, NULL, idialog_free_client, eds ); idialog_add_ok( IDIALOG( idlg ), colour_done_cb, _( "Set %s" ), IOBJECT_GET_CLASS_NAME( model ) ); iwindow_set_parent( IWINDOW( idlg ), parent ); idialog_set_iobject( IDIALOG( idlg ), IOBJECT( model ) ); idialog_set_pinup( IDIALOG( idlg ), TRUE ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); } static View * colour_view_new( Model *model, View *parent ) { return( colourview_new() ); } static void * colour_update_model( Heapmodel *heapmodel ) { Colour *colour = COLOUR( heapmodel ); if( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ) return( heapmodel ); colour_refresh( colour ); return( NULL ); } /* Members of colour we automate. */ static ClassmodelMember colour_members[] = { { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_COLOUR_SPACE, "colour_space", N_( "Color Space" ), G_STRUCT_OFFSET( Colour, colour_space ) }, { CLASSMODEL_MEMBER_REALVEC_FIXED, NULL, 3, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Colour, value ) } }; static void colour_class_init( ColourClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->finalize = colour_finalize; model_class->view_new = colour_view_new; model_class->edit = colour_edit; heapmodel_class->update_model = colour_update_model; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = colour_members; classmodel_class->n_members = IM_NUMBER( colour_members ); } static void colour_init( Colour *colour ) { colour->value[0] = 0.0; colour->value[1] = 0.0; colour->value[2] = 0.0; colour->colour_space = NULL; vips_buf_init_dynamic( &colour->caption, MAX_LINELENGTH ); iobject_set( IOBJECT( colour ), CLASS_COLOUR, NULL ); } GType colour_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ColourClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) colour_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Colour ), 32, /* n_preallocs */ (GInstanceInitFunc) colour_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Colour", &info, 0 ); } return( type ); } nip2-8.7.1/src/plot.c0000644000175000017500000004700213351443023011232 00000000000000/* an input plot */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void plot_free_columns( Plot *plot ) { int i; for( i = 0; i < plot->columns; i++ ) { IM_FREE( plot->xcolumn[i] ); IM_FREE( plot->ycolumn[i] ); } IM_FREE( plot->xcolumn ); IM_FREE( plot->ycolumn ); plot->columns = 0; plot->rows = 0; } static void plot_finalize( GObject *gobject ) { Plot *plot; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_PLOT( gobject ) ); plot = PLOT( gobject ); #ifdef DEBUG printf( "plot_finalize\n" ); #endif /*DEBUG*/ /* My instance finalize stuff. */ image_value_destroy( &plot->value ); plot_free_columns( plot ); vips_buf_destroy( &plot->caption_buffer ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } char * plot_f2c( PlotFormat format ) { switch( format ) { case PLOT_FORMAT_YYYY: return( _( "YYYY" ) ); case PLOT_FORMAT_XYYY: return( _( "XYYY" ) ); case PLOT_FORMAT_XYXY: return( _( "XYXY" ) ); default: g_assert( 0 ); /* Keep gcc happy. */ return( 0 ); } } char * plot_s2c( PlotStyle style ) { switch( style ) { case PLOT_STYLE_POINT: return( _( "Point" ) ); case PLOT_STYLE_LINE: return( _( "Line" ) ); case PLOT_STYLE_SPLINE: return( _( "Spline" ) ); case PLOT_STYLE_BAR: return( _( "Bar" ) ); default: g_assert( 0 ); /* Keep gcc happy. */ return( 0 ); } } static const char * plot_generate_caption( iObject *iobject ) { Plot *plot = PLOT( iobject ); VipsBuf *buf = &plot->caption_buffer; vips_buf_rewind( buf ); image_value_caption( &plot->value, buf ); vips_buf_appendf( buf, ", %d series, %d points", plot->columns, plot->rows ); vips_buf_appendf( buf, ", xrange [%g, %g]", plot->xmin, plot->xmax ); vips_buf_appendf( buf, ", yrange [%g, %g]", plot->ymin, plot->ymax ); return( vips_buf_all( buf ) ); } /* Unpack all data formats to XYXYXY. * * FIXME ... could save mem by reusing columns of Xes in YYYY and XYYY * cases */ static gboolean plot_unpack( Plot *plot, DOUBLEMASK *mask ) { int rows, columns; int r, c; double xmin, xmax; double ymin, ymax; rows = mask->ysize; switch( plot->format ) { case PLOT_FORMAT_YYYY: columns = mask->xsize; break; case PLOT_FORMAT_XYYY: if( mask->xsize < 2 ) { error_top( _( "Bad value." ) ); error_sub( _( "More than one column " "needed or XY plots" ) ); return( FALSE ); } columns = mask->xsize - 1; break; case PLOT_FORMAT_XYXY: if( (mask->xsize & 1) != 0 ) { error_top( _( "Bad value." ) ); error_sub( _( "Even number of columns only for " "XY format plots" ) ); return( FALSE ); } columns = mask->xsize / 2; break; default: columns = 1; g_assert( 0 ); } if( plot->columns != columns || plot->rows != rows ) { plot_free_columns( plot ); plot->xcolumn = IM_ARRAY( NULL, columns, double * ); plot->ycolumn = IM_ARRAY( NULL, columns, double * ); if( !plot->xcolumn || !plot->ycolumn ) { plot_free_columns( plot ); return( FALSE ); } plot->columns = columns; plot->rows = rows; for( c = 0; c < columns; c++ ) { plot->xcolumn[c] = NULL; plot->ycolumn[c] = NULL; } for( c = 0; c < columns; c++ ) { plot->xcolumn[c] = IM_ARRAY( NULL, rows, double ); plot->ycolumn[c] = IM_ARRAY( NULL, rows, double ); if( !plot->xcolumn[c] || !plot->ycolumn[c] ) { plot_free_columns( plot ); return( FALSE ); } } } switch( plot->format ) { case PLOT_FORMAT_YYYY: for( c = 0; c < columns; c++ ) for( r = 0; r < rows; r++ ) { plot->xcolumn[c][r] = r; plot->ycolumn[c][r] = mask->coeff[c + r * mask->xsize]; } break; case PLOT_FORMAT_XYYY: for( c = 0; c < columns; c++ ) for( r = 0; r < rows; r++ ) { plot->xcolumn[c][r] = mask->coeff[r * mask->xsize]; plot->ycolumn[c][r] = mask->coeff[c + 1 + r * mask->xsize]; } break; case PLOT_FORMAT_XYXY: for( c = 0; c < columns; c++ ) for( r = 0; r < rows; r++ ) { plot->xcolumn[c][r] = mask->coeff[c * 2 + r * mask->xsize]; plot->ycolumn[c][r] = mask->coeff[c * 2 + 1 + r * mask->xsize]; } break; default: g_assert( 0 ); } xmin = plot->xcolumn[0][0]; xmax = plot->xcolumn[0][0]; ymin = plot->ycolumn[0][0]; ymax = plot->ycolumn[0][0]; for( c = 0; c < columns; c++ ) for( r = 0; r < rows; r++ ) { if( plot->xcolumn[c][r] > xmax ) xmax = plot->xcolumn[c][r]; if( plot->xcolumn[c][r] < xmin ) xmin = plot->xcolumn[c][r]; if( plot->ycolumn[c][r] > ymax ) ymax = plot->ycolumn[c][r]; if( plot->ycolumn[c][r] < ymin ) ymin = plot->ycolumn[c][r]; } if( plot->xmin == PLOT_RANGE_UNSET ) plot->xmin = xmin; if( plot->xmax == PLOT_RANGE_UNSET ) plot->xmax = xmax; if( plot->ymin == PLOT_RANGE_UNSET ) plot->ymin = ymin; if( plot->ymax == PLOT_RANGE_UNSET ) plot->ymax = ymax; return( TRUE ); } #ifdef HAVE_LIBGOFFICE static View * plot_view_new( Model *model, View *parent ) { return( plotview_new() ); return( NULL ); } #endif /*HAVE_LIBGOFFICE*/ static void plot_edit( GtkWidget *parent, Model *model ) { #ifdef HAVE_LIBGOFFICE Plot *plot = PLOT( model ); Plotwindow *plotwindow; plotwindow = plotwindow_new( plot, parent ); gtk_widget_show( GTK_WIDGET( plotwindow ) ); #endif /*HAVE_LIBGOFFICE*/ } static xmlNode * plot_save( Model *model, xmlNode *xnode ) { Plot *plot = PLOT( model ); xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( !set_iprop( xthis, "plot_left", plot->left ) || !set_iprop( xthis, "plot_top", plot->top ) || !set_iprop( xthis, "plot_mag", plot->mag ) || !set_sprop( xthis, "show_status", bool_to_char( plot->show_status ) ) ) return( NULL ); return( xthis ); } static gboolean plot_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { Plot *plot = PLOT( model ); g_assert( IS_RHS( parent ) ); (void) get_iprop( xnode, "plot_left", &plot->left ); (void) get_iprop( xnode, "plot_top", &plot->top ); (void) get_iprop( xnode, "plot_mag", &plot->mag ); (void) get_bprop( xnode, "show_status", &plot->show_status ); return( MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ); } /* Members of plot we automate. */ static ClassmodelMember plot_options[] = { { CLASSMODEL_MEMBER_ENUM, NULL, PLOT_FORMAT_LAST - 1, "format", "format", N_( "Format" ), G_STRUCT_OFFSET( Plot, format ) }, { CLASSMODEL_MEMBER_ENUM, NULL, PLOT_STYLE_LAST - 1, "style", "style", N_( "Style" ), G_STRUCT_OFFSET( Plot, style ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, "xmin", "xmin", N_( "Xmin" ), G_STRUCT_OFFSET( Plot, xmin ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, "xmax", "xmax", N_( "Xmax" ), G_STRUCT_OFFSET( Plot, xmax ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, "ymin", "ymin", N_( "Ymin" ), G_STRUCT_OFFSET( Plot, ymin ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, "ymax", "ymax", N_( "Ymax" ), G_STRUCT_OFFSET( Plot, ymax ) }, { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_CAPTION, "caption", N_( "Caption" ), G_STRUCT_OFFSET( Plot, caption ) }, { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_XCAPTION, "xcaption", N_( "X Axis Caption" ), G_STRUCT_OFFSET( Plot, xcaption ) }, { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_YCAPTION, "ycaption", N_( "Y Axis Caption" ), G_STRUCT_OFFSET( Plot, ycaption ) }, { CLASSMODEL_MEMBER_STRING_LIST, NULL, 0, MEMBER_SERIES_CAPTIONS, "series_captions", N_( "Series Captions" ), G_STRUCT_OFFSET( Plot, series_captions ) } }; static ClassmodelMember plot_members[] = { { CLASSMODEL_MEMBER_OPTIONS, &plot_options, IM_NUMBER( plot_options ), MEMBER_OPTIONS, NULL, N_( "Options" ), 0 }, { CLASSMODEL_MEMBER_IMAGE, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Plot, value ) } }; /* Come here after we've read in new values from the heap. */ static gboolean plot_class_get( Classmodel *classmodel, PElement *root ) { Plot *plot = PLOT( classmodel ); ImageValue *value = &plot->value; IMAGE *im = imageinfo_get( FALSE, value->ii ); Imageinfo *ii2; IMAGE *t; DOUBLEMASK *mask; int (*fn)(); /* nx1 or 1xm images only ... use Bands for columns. */ if( im->Xsize != 1 && im->Ysize != 1 ) { error_top( _( "Bad value." ) ); error_sub( _( "1xn or nx1 images only for Plot" ) ); return( FALSE ); } /* Don't ref this and it'll be removed on the next GC. */ if( !(ii2 = imageinfo_new_temp( main_imageinfogroup, reduce_context->heap, NULL, "p" )) ) return( FALSE ); t = imageinfo_get( FALSE, ii2 ); /* Rotate so that our mask will be in the correct orientation. */ if( im->Ysize == 1 ) fn = im_rot90; else fn = im_copy; if( fn( im, t ) ) { error_top( _( "Bad value." ) ); error_sub( _( "Unable to prepare image." ) ); error_vips(); return( FALSE ); } /* Unpack the image to a dmask, then unpack the dmask into a set of XY * columns. * * FIXME ... yuk! */ if( !(mask = im_vips2mask( t, "plot_class_get" )) ) { error_top( _( "Bad value." ) ); error_sub( _( "1xn or nx1 images only" ) ); error_vips(); return( FALSE ); } if( !plot_unpack( plot, mask ) ) { im_free_dmask( mask ); return( FALSE ); } im_free_dmask( mask ); return( TRUE ); } static void plot_reset( Classmodel *classmodel ) { Plot *plot = PLOT( classmodel ); image_value_destroy( &plot->value ); plot->format = PLOT_FORMAT_YYYY; plot->style = PLOT_STYLE_LINE; plot->xmin = PLOT_RANGE_UNSET; plot->xmax = PLOT_RANGE_UNSET; plot->ymin = PLOT_RANGE_UNSET; plot->ymax = PLOT_RANGE_UNSET; IM_SETSTR( plot->caption, NULL ); IM_SETSTR( plot->xcaption, NULL ); IM_SETSTR( plot->ycaption, NULL ); IM_FREEF( slist_free_all, plot->series_captions ); } static gboolean plot_graphic_save( Classmodel *classmodel, GtkWidget *parent, const char *filename ) { Plot *plot = PLOT( classmodel ); ImageValue *value = &plot->value; char buf[FILENAME_MAX]; expand_variables( filename, buf ); filesel_add_mode( buf ); if( value->ii ) if( !imageinfo_write( value->ii, buf ) ) return( FALSE ); mainw_recent_add( &mainw_recent_image, filename ); return( TRUE ); } static void plot_class_init( PlotClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->finalize = plot_finalize; iobject_class->generate_caption = plot_generate_caption; #ifdef HAVE_LIBGOFFICE model_class->view_new = plot_view_new; #endif /*HAVE_LIBGOFFICE*/ model_class->edit = plot_edit; model_class->save = plot_save; model_class->load = plot_load; classmodel_class->class_get = plot_class_get; classmodel_class->members = plot_members; classmodel_class->n_members = IM_NUMBER( plot_members ); classmodel_class->reset = plot_reset; classmodel_class->graphic_save = plot_graphic_save; classmodel_class->filetype = filesel_type_image; classmodel_class->filetype_pref = "IMAGE_FILE_TYPE"; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void plot_init( Plot *plot ) { #ifdef DEBUG printf( "plot_init\n" ); #endif /*DEBUG*/ image_value_init( &plot->value, CLASSMODEL( plot ) ); plot->xcolumn = NULL; plot->ycolumn = NULL; plot->rows = 0; plot->columns = 0; plot->show_status = FALSE; plot->mag = 100; plot->left = 0; plot->top = 0; vips_buf_init_dynamic( &plot->caption_buffer, MAX_LINELENGTH ); iobject_set( IOBJECT( plot ), CLASS_PLOT, NULL ); plot_reset( CLASSMODEL( plot ) ); } GtkType plot_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( PlotClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) plot_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Plot ), 32, /* n_preallocs */ (GInstanceInitFunc) plot_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Plot", &info, 0 ); } return( type ); } #ifdef HAVE_LIBGOFFICE /* Make a GOColor from an RGB triple. Different versions of goffice have * different ways of doing this :( */ #ifdef GO_COLOR_FROM_RGB #define RGB( R, G, B ) GO_COLOR_FROM_RGB( R, G, B ) #else #define RGB( R, G, B ) RGB_TO_RGBA( RGB_TO_UINT( R, G, B ), 0xff ) #endif /* Choose line colours with this. RGB first, then mostly random. We can't use * goffice's default colours because we really want the first three to be: red, * green, blue. */ static GOColor default_colour[] = { RGB( 255, 0, 0 ), RGB( 0, 255, 0 ), RGB( 0, 0, 255 ), RGB( 100, 0, 102 ), RGB( 17, 0, 102 ), RGB( 0, 0, 180 ), RGB( 0, 53, 255 ), RGB( 0, 104, 234 ), RGB( 0, 150, 188 ), RGB( 0, 205, 170 ), RGB( 0, 255, 139 ), RGB( 0, 255, 55 ), RGB( 40, 255, 40 ), RGB( 106, 255, 74 ), RGB( 155, 255, 48 ), RGB( 209, 255, 21 ), RGB( 239, 255, 7 ), RGB( 255, 176, 0 ), RGB( 255, 110, 0 ), RGB( 255, 50, 0 ), RGB( 196, 0, 0 ) }; /* Build a GogPlot from a Plot. */ GogPlot * plot_new_gplot( Plot *plot ) { GogPlot *gplot; int i; if( plot->style == PLOT_STYLE_BAR ) gplot = gog_plot_new_by_name( "GogHistogramPlot" ); else gplot = gog_plot_new_by_name( "GogXYPlot" ); switch( plot->style ) { case PLOT_STYLE_POINT: g_object_set( gplot, "default-style-has-lines", FALSE, NULL ); break; case PLOT_STYLE_LINE: g_object_set( gplot, "default-style-has-markers", FALSE, NULL ); break; case PLOT_STYLE_SPLINE: g_object_set( gplot, "default-style-has-markers", FALSE, NULL ); g_object_set( gplot, "use-splines", TRUE, NULL ); break; case PLOT_STYLE_BAR: break; default: g_assert( FALSE ); } for( i = 0; i < plot->columns; i++ ) { GogSeries *series; GOData *data; GError *error; char *caption; series = gog_plot_new_series( gplot ); data = go_data_vector_val_new( plot->xcolumn[i], plot->rows, NULL ); gog_series_set_dim( series, 0, data, &error ); data = go_data_vector_val_new( plot->ycolumn[i], plot->rows, NULL ); gog_series_set_dim( series, 1, data, &error ); if( (caption = (char *) g_slist_nth_data( plot->series_captions, i )) ) caption = g_strdup( caption ); else caption = g_strdup_printf( "Band %d", i ); data = go_data_scalar_str_new( caption, TRUE ); gog_series_set_name( series, (GODataScalar *) data, &error ); if( i < IM_NUMBER( default_colour ) ) { GOStyle *style; style = go_styled_object_get_style( GO_STYLED_OBJECT( series ) ); style->line.color = default_colour[i]; style->line.auto_color = FALSE; go_marker_set_fill_color( style->marker.mark, default_colour[i] ); style->marker.auto_fill_color = FALSE; /* Could match fill, but black everywhere looks nicer. */ go_marker_set_outline_color( style->marker.mark, RGB( 0, 0, 0 ) ); style->marker.auto_outline_color = FALSE; gog_object_request_update( GOG_OBJECT( series ) ); } } return( gplot ); } static void plot_grid_add( GogAxis *axis ) { GogGridLine *ggl; if( !gog_object_get_child_by_name( GOG_OBJECT( axis ), "MajorGrid" ) ) { ggl = g_object_new( GOG_TYPE_GRID_LINE, "is-minor", FALSE, NULL ); gog_object_add_by_name( GOG_OBJECT( axis ), "MajorGrid", GOG_OBJECT( ggl ) ); } if( !gog_object_get_child_by_name( GOG_OBJECT( axis ), "MinorGrid" ) ) { ggl = g_object_new( GOG_TYPE_GRID_LINE, "is-minor", TRUE, NULL ); gog_object_add_by_name( GOG_OBJECT( axis ), "MinorGrid", GOG_OBJECT( ggl ) ); } g_object_set( axis, "pos", GOG_AXIS_CROSS, NULL ); } static void plot_set_title( GogObject *thing, const char *role, const char *text ) { GogObject *title; title = gog_object_get_child_by_name( thing, role ); if( text && !title ) { title = g_object_new( GOG_TYPE_LABEL, NULL ); gog_object_add_by_name( thing, role, title ); } else if( !text && title ) { gog_object_clear_parent( title ); UNREF( title ); } if( text && title ) { GOData *data; data = go_data_scalar_str_new( text, FALSE ); gog_dataset_set_dim( GOG_DATASET( title ), 0, data, NULL ); } } void plot_style_main( Plot *plot, GogChart *gchart ) { GSList *axes; GogAxis *axis; GogObject *legend; axes = gog_chart_get_axes( gchart, GOG_AXIS_X ); axis = GOG_AXIS( axes->data ); g_slist_free( axes ); gog_axis_set_bounds( axis, plot->xmin, plot->xmax ); plot_set_title( GOG_OBJECT( axis ), "Label", plot->xcaption ); plot_grid_add( axis ); axes = gog_chart_get_axes( gchart, GOG_AXIS_Y ); axis = GOG_AXIS( axes->data ); g_slist_free( axes ); gog_axis_set_bounds( axis, plot->ymin, plot->ymax ); plot_set_title( GOG_OBJECT( axis ), "Label", plot->ycaption ); plot_grid_add( axis ); legend = gog_object_get_child_by_name( GOG_OBJECT( gchart ), "Legend" ); if( plot->columns > 1 && !legend ) { legend = g_object_new( GOG_TYPE_LEGEND, NULL ); gog_object_add_by_name( GOG_OBJECT( gchart ), "Legend", GOG_OBJECT( legend ) ); } else if( plot->columns == 1 && legend ) { gog_object_clear_parent( legend ); UNREF( legend ); } plot_set_title( GOG_OBJECT( gchart ), "Title", plot->caption ); } void plot_style_thumbnail( Plot *plot, GogChart *gchart ) { GSList *axes; GogAxis *axis; axes = gog_chart_get_axes( gchart, GOG_AXIS_X ); axis = GOG_AXIS( axes->data ); g_slist_free( axes ); g_object_set( axis, "major-tick-labeled", FALSE, "major-tick-size-pts", 0, "pos", GOG_AXIS_CROSS, NULL ); gog_axis_set_bounds( axis, plot->xmin, plot->xmax ); axes = gog_chart_get_axes( gchart, GOG_AXIS_Y ); axis = GOG_AXIS( axes->data ); g_slist_free( axes ); g_object_set( axis, "major-tick-labeled", FALSE, "major-tick-size-pts", 0, "pos", GOG_AXIS_CROSS, NULL ); gog_axis_set_bounds( axis, plot->ymin, plot->ymax ); } Imageinfo * plot_to_image( Plot *plot, Reduce *rc, double dpi ) { GogGraph *ggraph; GogChart *gchart; GogPlot *gplot; GogRenderer *renderer; GdkPixbuf *pixbuf; double width_in_pts, height_in_pts; Imageinfo *ii; ggraph = g_object_new( GOG_TYPE_GRAPH, NULL ); gchart = g_object_new( GOG_TYPE_CHART, NULL ); gog_object_add_by_name( GOG_OBJECT( ggraph ), "Chart", GOG_OBJECT( gchart ) ); gplot = plot_new_gplot( plot ); gog_object_add_by_name( GOG_OBJECT( gchart ), "Plot", GOG_OBJECT( gplot ) ); plot_style_main( plot, gchart ); renderer = gog_renderer_new( ggraph ); gog_graph_force_update( ggraph ); gog_graph_get_size( ggraph, &width_in_pts, &height_in_pts); gog_renderer_update( renderer, width_in_pts * dpi / 72.0, height_in_pts * dpi / 72.0 ); pixbuf = gog_renderer_get_pixbuf( renderer ); if( !(ii = imageinfo_new_from_pixbuf( main_imageinfogroup, rc->heap, pixbuf )) ) { UNREF( renderer ); UNREF( ggraph ); return( NULL ); } /* Don't unref the pixbuf, we don't own it. */ UNREF( renderer ); UNREF( ggraph ); return( ii ); } #endif /*HAVE_LIBGOFFICE*/ nip2-8.7.1/src/toolkitgroupview.c0000644000175000017500000000611613351443023013712 00000000000000/* a toolkitgroupview button in a toolkitgroup */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; static void * toolkitgroupview_dispose_sub( View *view, void *a, void *b ) { DESTROY_GTK( view ); return( NULL ); } static void toolkitgroupview_dispose( GObject *gobject ) { #ifdef DEBUG printf( "toolkitgroupview_dispose: %p\n", gobject ); #endif /*DEBUG*/ /* Toolkitviews are not child widgets of us, they are menu items pased * into the TK. Destroy them explicitly. */ view_map( VIEW( gobject ), toolkitgroupview_dispose_sub, NULL, NULL ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void toolkitgroupview_refresh( vObject *vobject ) { /* Toolkitgroupview *kitgview = TOOLKITGROUPVIEW( view ); */ /* FIXME ... should update display for reordering of toolkits (to keep * menu sorted) */ #ifdef DEBUG printf( "toolkitgroup changed\n" ); #endif /*DEBUG*/ VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void toolkitgroupview_class_init( ToolkitgroupviewClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = toolkitgroupview_dispose; /* Create signals. */ /* Set methods. */ vobject_class->refresh = toolkitgroupview_refresh; } static void toolkitgroupview_init( Toolkitgroupview *kitgview ) { } GtkType toolkitgroupview_get_type( void ) { static GtkType toolkitgroupview_type = 0; if( !toolkitgroupview_type ) { static const GtkTypeInfo info = { "Toolkitgroupview", sizeof( Toolkitgroupview ), sizeof( ToolkitgroupviewClass ), (GtkClassInitFunc) toolkitgroupview_class_init, (GtkObjectInitFunc) toolkitgroupview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; toolkitgroupview_type = gtk_type_unique( TYPE_VIEW, &info ); } return( toolkitgroupview_type ); } View * toolkitgroupview_new( void ) { Toolkitgroupview *kitgview = gtk_type_new( TYPE_TOOLKITGROUPVIEW ); return( VIEW( kitgview ) ); } void toolkitgroupview_set_mainw( Toolkitgroupview *kitgview, Mainw *mainw ) { kitgview->mainw = mainw; kitgview->menu = mainw->toolkit_menu; } nip2-8.7.1/src/itext.h0000644000175000017500000000444113351443023011416 00000000000000/* a text button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_ITEXT (itext_get_type()) #define ITEXT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_ITEXT, iText )) #define ITEXT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_ITEXT, iTextClass)) #define IS_ITEXT( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_ITEXT )) #define IS_ITEXT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_ITEXT )) #define ITEXT_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_ITEXT, iTextClass )) struct _iText { Heapmodel parent_class; VipsBuf value; /* The value displayed as a [char] */ char *formula; /* The formula we edit */ char *formula_default; /* Formula we inherit */ VipsBuf decompile; /* The value decompiled to a [char] */ /* TRUE if the formula has been entered by the user and should be * saved. * * Can't use classmodel edited, as text must inherit from heapmodel. * Some duplication of code ... see itext_clear_edited() */ gboolean edited; }; typedef struct _iTextClass { HeapmodelClass parent_class; /* My methods. */ } iTextClass; GType itext_get_type( void ); iText *itext_new( Rhs *rhs ); gboolean itext_value( Reduce *rc, VipsBuf *buf, PElement *root ); void itext_value_ev( Reduce *rc, VipsBuf *buf, PElement *root ); gboolean itext_make_value_string( Expr *expr, VipsBuf *buf ); void itext_set_edited( iText *text, gboolean edited ); gboolean itext_set_formula( iText *text, const char *formula ); nip2-8.7.1/src/pane.c0000644000175000017500000002421313351443023011176 00000000000000/* a side panel that can slide in and out of view */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ /* Our signals. */ enum { SIG_CHANGED, /* Change to position or openness */ SIG_LAST }; static GtkHPanedClass *parent_class = NULL; static guint pane_signals[SIG_LAST] = { 0 }; #ifdef DEBUG static char * pane_handedness2char( PaneHandedness handedness ) { switch( handedness ) { case PANE_HIDE_LEFT: return( "PANE_HIDE_LEFT" ); case PANE_HIDE_RIGHT: return( "PANE_HIDE_RIGHT" ); default: g_assert( 0 ); } } #endif /*DEBUG*/ static void pane_changed( Pane *pane ) { g_assert( IS_PANE( pane ) ); #ifdef DEBUG printf( "pane_changed: %p %s\n", pane, pane_handedness2char( pane->handedness ) ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( pane ), pane_signals[SIG_CHANGED], 0 ); } static int pane_closed_position( Pane *pane ) { /* Can't use max/min since we need to be able to work before our * window has been built. */ return( pane->handedness == PANE_HIDE_RIGHT ? 10000 : 0 ); } /* An open position ... used in case we are asked to open, but the position is * already closed. */ static int pane_open_position( Pane *pane ) { int max_position; int min_position; g_object_get( pane, "max_position", &max_position, "min_position", &min_position, NULL ); return( pane->handedness == PANE_HIDE_RIGHT ? max_position - 200: min_position + 200 ); } static void pane_destroy( GtkObject *object ) { Pane *pane; g_return_if_fail( object != NULL ); g_return_if_fail( IS_PANE( object ) ); pane = PANE( object ); #ifdef DEBUG printf( "pane_destroy: %p %s\n", pane, pane_handedness2char( pane->handedness ) ); #endif /*DEBUG*/ /* My instance destroy stuff. */ IM_FREEF( g_source_remove, pane->animate_timeout ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void pane_class_init( PaneClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = pane_destroy; class->changed = NULL; pane_signals[SIG_CHANGED] = g_signal_new( "changed", G_OBJECT_CLASS_TYPE( object_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( PaneClass, changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); } /* Position property has changed. We block the notify signal before we set * position, so this change must have come from a user drag or parent window * resize. */ static void pane_notify_position_cb( Pane *pane ) { int max_position; int min_position; int position; /* Can get here even though we block notify during position set in * animate, because of delays in window setup. */ if( pane->animate_timeout ) return; g_object_get( pane, "max_position", &max_position, "min_position", &min_position, NULL ); /* We can have 10,000 as position (meaning way to the * right), take account of any clipping there may be. */ pane->position = IM_CLIP( min_position, pane->position, max_position ); /* And the new value. */ position = gtk_paned_get_position( GTK_PANED( pane ) ); #ifdef DEBUG printf( "pane_notify_position_cb: %p %s %d\n", pane, pane_handedness2char( pane->handedness ), position ); #endif /*DEBUG*/ pane_set_position( pane, position ); pane_set_user_position( pane, position ); /* Look for dragged close. */ if( pane->open && pane->handedness == PANE_HIDE_LEFT && position == min_position ) pane_set_open( pane, FALSE ); if( pane->open && pane->handedness == PANE_HIDE_RIGHT && position == max_position ) pane_set_open( pane, FALSE ); } static void pane_init( Pane *pane ) { pane->handedness = PANE_HIDE_LEFT; pane->panechild = NULL; pane->open = FALSE; pane->position = 0; pane->user_position = 0; /* overwritten on _link() */ pane->target_position = 0; pane->close_on_end = FALSE; pane->last_set_position = 0; pane->animate_timeout = 0; g_signal_connect( pane, "notify::position", G_CALLBACK( pane_notify_position_cb ), NULL ); } GType pane_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( PaneClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) pane_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Pane ), 32, /* n_preallocs */ (GInstanceInitFunc) pane_init, }; type = g_type_register_static( GTK_TYPE_HPANED, "Pane", &info, 0 ); } return( type ); } /* Operations on the model. */ void pane_set_position( Pane *pane, int position ) { if( pane->position != position ) { #ifdef DEBUG printf( "pane_set_position: %p %s %d\n", pane, pane_handedness2char( pane->handedness ), position ); #endif /*DEBUG*/ g_signal_handlers_block_by_func( pane, pane_notify_position_cb, NULL ); gtk_paned_set_position( GTK_PANED( pane ), position ); g_signal_handlers_unblock_by_func( pane, pane_notify_position_cb, NULL ); pane->position = position; pane_changed( pane ); } } void pane_set_user_position( Pane *pane, int user_position ) { if( pane->user_position != user_position ) { #ifdef DEBUG printf( "pane_set_user_position: %p %s %d\n", pane, pane_handedness2char( pane->handedness ), user_position ); #endif /*DEBUG*/ pane->user_position = user_position; pane_changed( pane ); } } void pane_set_open( Pane *pane, gboolean open ) { if( pane->open != open ) { #ifdef DEBUG printf( "pane_set_open: %p %s %d\n", pane, pane_handedness2char( pane->handedness ), open ); #endif /*DEBUG*/ widget_visible( GTK_WIDGET( pane->panechild ), open ); pane->open = open; pane_changed( pane ); } } /* Set everything all at once on startup. */ void pane_set_state( Pane *pane, gboolean open, int user_position ) { if( pane->open != open || pane->user_position != user_position ) { g_signal_handlers_block_by_func( pane, pane_notify_position_cb, NULL ); gtk_paned_set_position( GTK_PANED( pane ), user_position ); g_signal_handlers_unblock_by_func( pane, pane_notify_position_cb, NULL ); widget_visible( GTK_WIDGET( pane->panechild ), open ); pane->open = open; pane->user_position = user_position; pane->position = user_position; pane_changed( pane ); } } void pane_set_child( Pane *pane, Panechild *panechild ) { g_assert( !pane->panechild ); pane->panechild = panechild; if( pane->handedness == PANE_HIDE_LEFT ) gtk_paned_pack1( GTK_PANED( pane ), GTK_WIDGET( panechild ), TRUE, TRUE ); else gtk_paned_pack2( GTK_PANED( pane ), GTK_WIDGET( panechild ), TRUE, TRUE ); } /* Control. */ static gboolean pane_animate_timeout_cb( Pane *pane ) { int position = pane->position; int target = pane->target_position; int new; gboolean more; #ifdef DEBUG printf( "pane_animate_timeout_cb: %p %s\n", pane, pane_handedness2char( pane->handedness ) ); #endif /*DEBUG*/ more = TRUE; new = position + (target - position) / 2; if( ABS( position - target ) < 5 || new == pane->last_set_position ) { /* At our target! */ new = target; more = FALSE; pane->animate_timeout = 0; } pane_set_position( pane, new ); pane->last_set_position = new; if( !more && pane->close_on_end ) pane_set_open( pane, FALSE ); return( more ); } /* Close the pane with an animation. */ void pane_animate_closed( Pane *pane ) { if( !pane->animate_timeout && pane->open ) { int max_position; int min_position; int target_position; target_position = pane_closed_position( pane ); g_object_get( pane, "max_position", &max_position, "min_position", &min_position, NULL ); /* Can be zero if we're here very early. */ if( max_position > 0 ) target_position = IM_CLIP( min_position, target_position, max_position ); pane->target_position = target_position; pane->close_on_end = TRUE; pane->last_set_position = -1; pane->animate_timeout = g_timeout_add( 50, (GSourceFunc) pane_animate_timeout_cb, pane ); } } /* Open the pane with an animation. */ void pane_animate_open( Pane *pane ) { if( !pane->animate_timeout && !pane->open ) { int max_position; int min_position; int target_position; target_position = pane->user_position; g_object_get( pane, "max_position", &max_position, "min_position", &min_position, NULL ); /* Can be zero if we're here very early. */ if( max_position > 0 ) target_position = IM_CLIP( min_position, target_position, max_position ); /* user_position can be max or min if the pane was dragged * closed. */ if( target_position == max_position || target_position == min_position ) target_position = pane_open_position( pane ); #ifdef DEBUG printf( "pane_animate_open: %p %s %d\n", pane, pane_handedness2char( pane->handedness ), target_position ); #endif /*DEBUG*/ pane->target_position = target_position; pane->close_on_end = FALSE; pane->last_set_position = -1; pane_set_open( pane, TRUE ); pane->animate_timeout = g_timeout_add( 50, (GSourceFunc) pane_animate_timeout_cb, pane ); } } static void pane_link( Pane *pane, PaneHandedness handedness ) { #ifdef DEBUG printf( "pane_link: %p %s\n", pane, pane_handedness2char( handedness ) ); #endif /*DEBUG*/ pane->handedness = handedness; pane_set_open( pane, FALSE ); } Pane * pane_new( PaneHandedness handedness ) { Pane *pane; pane = PANE( g_object_new( TYPE_PANE, NULL ) ); pane_link( pane, handedness ); return( pane ); } nip2-8.7.1/src/matrixview.c0000644000175000017500000006106713351443023012462 00000000000000/* run the display for an input matrixview in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Round N down to P boundary. */ #define ROUND_DOWN(N,P) ((N) - ((N) % P)) /* Round N up to P boundary. */ #define ROUND_UP(N,P) (ROUND_DOWN( (N) + (P) - 1, (P) )) /* The size in cells at which we switch from displaying the whole matrix to * displaying part of it in a scrolled window. */ static const int matrixview_max_width = 7; static const int matrixview_max_height = 10; /* Show a matrix with fixed-width columns. */ static const int matrixview_column_width = 70; /* Limit number of sub-widgets with this ... could be prefs? */ static const int matrixview_max_cells = 100; static GraphicviewClass *parent_class = NULL; static void matrixview_destroy( GtkObject *object ) { Matrixview *matrixview; g_return_if_fail( object != NULL ); g_return_if_fail( IS_MATRIXVIEW( object ) ); #ifdef DEBUG printf( "matrixview_destroy\n" ); #endif /*DEBUG*/ matrixview = MATRIXVIEW( object ); /* My instance destroy stuff. */ IM_FREEF( g_slist_free, matrixview->items ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static gboolean matrixview_scan_text( Matrixview *matrixview, GtkWidget *txt, double *out, gboolean *changed ) { double v; if( !get_geditable_double( txt, &v ) ) return( FALSE ); if( *out != v ) { *out = v; *changed = TRUE; } return( TRUE ); } /* Search and read all text widgets and refill matrix. set_dirty this symbol * if there was a change. Return non-NULL if we found an error. */ static void * matrixview_scan( View *view ) { Matrixview *matrixview = MATRIXVIEW( view ); Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); int width = matrix->value.width; int height = matrix->value.height; Expr *expr = HEAPMODEL( matrix )->row->expr; gboolean changed; int x, y; GSList *p; #ifdef DEBUG printf( "matrixview_scan\n" ); #endif /*DEBUG*/ /* Should be text widgets there ... either text or tslider. */ if( matrixview->display != MATRIX_DISPLAY_TEXT && matrixview->display != MATRIX_DISPLAY_TEXT_SCALE_OFFSET && matrixview->display != MATRIX_DISPLAY_SLIDER ) return( NULL ); expr_error_clear( expr ); changed = FALSE; /* Check for scale and offset, if present. */ if( matrixview->scale && !matrixview_scan_text( matrixview, matrixview->scale, &matrix->scale, &changed ) ) { expr_error_set( expr ); return( view ); } if( matrixview->offset && !matrixview_scan_text( matrixview, matrixview->offset, &matrix->offset, &changed ) ) { expr_error_set( expr ); return( view ); } /* Loop thru' all matrix widgets. tsliders have text fields we must * scan too. */ if( matrixview->items ) for( p = matrixview->items, y = 0; y < height; y++ ) for( x = 0; x < width; x++, p = p->next ) { GtkWidget *item = GTK_WIDGET( p->data ); GtkWidget *entry = TSLIDER( item )->entry; int i = x + y * width; if( !matrixview_scan_text( matrixview, entry, &matrix->value.coeff[i], &changed ) ) { error_top( _( "Bad value." ) ); error_sub( _( "Cell (%d, %d):\n%s" ), x, y, error_get_sub() ); expr_error_set( expr ); return( view ); } } if( matrixview->store ) { GtkTreeModel *tree = GTK_TREE_MODEL( matrixview->store ); GtkTreeIter iter; gtk_tree_model_get_iter_first( tree, &iter ); for( y = 0; y < height; y++ ) { for( x = 0; x < width; x++ ) { double *out = &matrix->value.coeff[x + y * width]; double d; gtk_tree_model_get( tree, &iter, x, &d, -1 ); if( *out != d ) { *out = d; changed = TRUE; } } gtk_tree_model_iter_next( tree, &iter ); } } if( changed ) classmodel_update( CLASSMODEL( matrix ) ) ; return( VIEW_CLASS( parent_class )->scan( view ) ); } /* Change to a toggle widget. */ /*ARGSUSED*/ static void matrixview_toggle_change_cb( GtkWidget *widget, Matrixview *matrixview ) { Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); int pos = g_slist_index( matrixview->items, widget ); int x = pos % matrixview->width; int y = pos / matrixview->width; int i = x + y * matrix->value.width; #ifdef DEBUG printf( "matrixview_toggle_change_cb\n" ); #endif /*DEBUG*/ /* Cycle value. */ switch( (int) matrix->value.coeff[i] ) { case 0: matrix->value.coeff[i] = 128.0; break; case 255: matrix->value.coeff[i] = 0.0; break; default: matrix->value.coeff[i] = 255.0; break; } classmodel_update( CLASSMODEL( matrix ) ); symbol_recalculate_all(); } /* Build a set of toggle items for a matrix. */ static void matrixview_toggle_build( Matrixview *matrixview ) { Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); int x, y; int cx, cy; matrixview->table = gtk_table_new( matrixview->height, matrixview->width, TRUE ); gtk_box_pack_start( GTK_BOX( matrixview->box ), matrixview->table, FALSE, FALSE, 0 ); /* Find the centre position, if there is one. We give this a special * name; it is highlit by our resource file. */ cx = -1; cy = -1; if( matrix->value.height & 0x1 ) cy = matrix->value.height >> 1; if( matrix->value.width & 0x1 ) cx = matrix->value.width >> 1; /* Build contents. */ for( y = 0; y < matrixview->height; y++ ) for( x = 0; x < matrixview->width; x++ ) { GtkWidget *but; but = gtk_button_new_with_label( "0" ); gtk_signal_connect( GTK_OBJECT( but ), "clicked", GTK_SIGNAL_FUNC( matrixview_toggle_change_cb ), matrixview ); if( x == cx && y == cy ) gtk_widget_set_name( but, "centre_widget" ); /* FIXME ... this b0rks thanks to pangolayout confusion set_fixed( GTK_BIN( but )->child, 1 ); */ gtk_table_attach( GTK_TABLE( matrixview->table ), but, x, x + 1, y, y + 1, GTK_FILL, GTK_FILL, 2, 2 ); matrixview->items = g_slist_append( matrixview->items, but ); } } /* Change to a scale in a Tslider. */ /*ARGSUSED*/ static void matrixview_slider_change_cb( Tslider *tslider, Matrixview *matrixview ) { Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); int pos = g_slist_index( matrixview->items, tslider ); int x = pos % matrixview->width; int y = pos / matrixview->width; int i = x + y * matrix->value.width; g_assert( pos >= 0 ); /* Install value. */ if( matrix->value.coeff[i] != tslider->svalue ) { matrix->value.coeff[i] = tslider->svalue; classmodel_update( CLASSMODEL( matrix ) ); symbol_recalculate_all(); } } /* Build a set of slider items for a matrix. */ static void matrixview_slider_build( Matrixview *matrixview ) { int x, y; matrixview->table = gtk_table_new( matrixview->height, matrixview->width, TRUE ); gtk_box_pack_start( GTK_BOX( matrixview->box ), matrixview->table, TRUE, TRUE, 0 ); for( y = 0; y < matrixview->height; y++ ) for( x = 0; x < matrixview->width; x++ ) { Tslider *tslider = tslider_new(); tslider_set_conversions( tslider, NULL, NULL ); tslider->from = -2; tslider->to = 2; tslider->digits = 3; gtk_signal_connect_object( GTK_OBJECT( tslider ), "text_changed", GTK_SIGNAL_FUNC( view_changed_cb ), GTK_OBJECT( matrixview ) ); gtk_signal_connect_object( GTK_OBJECT( tslider ), "activate", GTK_SIGNAL_FUNC( view_activate_cb ), GTK_OBJECT( matrixview ) ); gtk_signal_connect( GTK_OBJECT( tslider ), "slider_changed", GTK_SIGNAL_FUNC( matrixview_slider_change_cb ), matrixview ); gtk_container_set_border_width( GTK_CONTAINER( tslider ), 2 ); gtk_table_attach_defaults( GTK_TABLE( matrixview->table ), GTK_WIDGET( tslider ), x, x + 1, y, y + 1 ); matrixview->items = g_slist_append( matrixview->items, tslider ); } } static gboolean matrixview_text_focus_in( GtkWidget *entry, GdkEvent *event, void *data ) { gtk_editable_select_region( GTK_EDITABLE( entry ), 0, -1 ); return( FALSE ); } static gboolean matrixview_text_focus_out( GtkWidget *entry, GdkEvent *event, void *data ) { gtk_editable_select_region( GTK_EDITABLE( entry ), 0, 0 ); return( FALSE ); } static void matrixview_text_connect( Matrixview *matrixview, GtkWidget *txt ) { gtk_signal_connect_object( GTK_OBJECT( txt ), "changed", GTK_SIGNAL_FUNC( view_changed_cb ), GTK_OBJECT( matrixview ) ); gtk_signal_connect_object( GTK_OBJECT( txt ), "activate", GTK_SIGNAL_FUNC( view_activate_cb ), GTK_OBJECT( matrixview ) ); /* Select text on focus-in, deselect on focus out. */ gtk_signal_connect( GTK_OBJECT( txt ), "focus_in_event", GTK_SIGNAL_FUNC( matrixview_text_focus_in ), NULL ); gtk_signal_connect( GTK_OBJECT( txt ), "focus_out_event", GTK_SIGNAL_FUNC( matrixview_text_focus_out ), NULL ); } static void matrixview_text_build_scale_offset( Matrixview *matrixview ) { GtkSizeGroup *group; matrixview->cbox = gtk_vbox_new( FALSE, 2 ); gtk_box_pack_end( GTK_BOX( matrixview->box ), GTK_WIDGET( matrixview->cbox ), FALSE, FALSE, 0 ); group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL ); matrixview->scale = build_glabeltext4( matrixview->cbox, group, _( "Scale" ) ); gtk_entry_set_width_chars( GTK_ENTRY( matrixview->scale ), 6 ); matrixview_text_connect( matrixview, matrixview->scale ); matrixview->offset = build_glabeltext4( matrixview->cbox, group, _( "Offset" ) ); gtk_entry_set_width_chars( GTK_ENTRY( matrixview->offset ), 6 ); matrixview_text_connect( matrixview, matrixview->offset ); UNREF( group ); } /* Make a GtkListStore from a MatrixValue. */ GtkListStore * matrixview_liststore_new( MatrixValue *matrixvalue ) { int width = matrixvalue->width; int height = matrixvalue->height; GType *types; int i, y; GtkListStore *store; types = g_new( GType, width ); for( i = 0; i < width; i++ ) types[i] = G_TYPE_DOUBLE; store = gtk_list_store_newv( width, types ); g_free( types ); for( y = 0; y < height; y++ ) { GtkTreeIter iter; gtk_list_store_append( store, &iter ); for( i = 0; i < width; i++ ) gtk_list_store_set( store, &iter, i, matrixvalue->coeff[y * width + i], -1 ); } return( store ); } static void matrixview_edited_cb( GtkCellRendererText *renderer, char *path, char *new_text, void *user_data ) { Matrixview *matrixview = MATRIXVIEW( user_data ); GtkTreeModel *tree = GTK_TREE_MODEL( matrixview->store ); GtkTreeIter iter; if( gtk_tree_model_get_iter_from_string( tree, &iter, path ) ) { int col = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( renderer ), "nip2_column_num" ) ); gtk_list_store_set( GTK_LIST_STORE( tree ), &iter, col, atof( new_text ), -1 ); view_scannable_register( VIEW( matrixview ) ); symbol_recalculate_all(); } } static void matrixview_cell_data_cb( GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree, GtkTreeIter *iter, void *data ) { int col = GPOINTER_TO_INT( g_object_get_data( G_OBJECT( cell ), "nip2_column_num" ) ); double d; char buf[256]; gtk_tree_model_get( tree, iter, col, &d, -1 ); vips_snprintf( buf, 256, "%g", d ); g_object_set( cell, "text", buf, NULL ); } /* Build a set of text items for a matrix. */ static void matrixview_text_build( Matrixview *matrixview ) { Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); int i; GtkTreeViewColumn *column; int cell_height; GtkTreeSelection *selection; if( !matrix->value.coeff ) return; matrixview->store = matrixview_liststore_new( &matrix->value ); matrixview->sheet = gtk_tree_view_new_with_model( GTK_TREE_MODEL( matrixview->store ) ); gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( matrixview->sheet ), FALSE ); /* Stops a harmless compiler warning. */ column = NULL; for( i = 0; i < matrix->value.width; i++ ) { GtkCellRenderer *renderer; char buf[256]; renderer = gtk_cell_renderer_text_new(); g_object_set( renderer, "editable", TRUE, NULL ); g_object_set_data( G_OBJECT( renderer ), "nip2_column_num", GINT_TO_POINTER( i ) ); g_signal_connect( G_OBJECT( renderer ), "edited", G_CALLBACK( matrixview_edited_cb ), matrixview ); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_FIXED ); gtk_tree_view_column_set_fixed_width( column, matrixview_column_width ); im_snprintf( buf, 256, "%d", i ); gtk_tree_view_column_set_title( column, buf ); gtk_tree_view_column_pack_start( column, renderer, FALSE ); gtk_tree_view_column_set_attributes( column, renderer, "text", i, NULL ); gtk_tree_view_column_set_cell_data_func( column, renderer, matrixview_cell_data_cb, NULL, NULL ); gtk_tree_view_append_column( GTK_TREE_VIEW( matrixview->sheet ), column ); } gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW( matrixview->sheet ), TRUE ); gtk_tree_view_column_cell_get_size( column, NULL, NULL, NULL, NULL, &cell_height ); selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( matrixview->sheet ) ); gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE ); gtk_tree_view_set_rubber_banding( GTK_TREE_VIEW( matrixview->sheet ), TRUE ); gtk_tree_view_set_grid_lines( GTK_TREE_VIEW( matrixview->sheet ), GTK_TREE_VIEW_GRID_LINES_BOTH ); if( matrix->value.width > matrixview_max_width || matrix->value.height > matrixview_max_height ) { GtkRequisition requisition; gint spacing; int border; int width, height; if( matrix->value.width > matrixview_max_width ) gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( matrixview->sheet ), TRUE ); matrixview->swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( matrixview->swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_container_add( GTK_CONTAINER( matrixview->swin ), matrixview->sheet ); /* Calculate how big we should make the scrolled window. We * need to leave space for the scrollbars. */ gtk_widget_size_request( gtk_scrolled_window_get_hscrollbar( GTK_SCROLLED_WINDOW( matrixview->swin ) ), &requisition ); gtk_widget_style_get( GTK_WIDGET( matrixview->swin ), "scrollbar-spacing", &spacing, NULL ); border = requisition.height + spacing; /* Subarea of matrix we show, in cells. */ width = IM_MIN( matrix->value.width, matrixview_max_width ); height = IM_MIN( matrix->value.height, matrixview_max_height ); /* Convert to pixels. */ width *= matrixview_column_width; height *= cell_height; /* Will we be showing scrollbars? Need to add a bit. */ if( matrixview->width > matrixview_max_width ) height += border; if( matrixview->height > matrixview_max_height ) width += border; gtk_widget_set_size_request( GTK_WIDGET( matrixview->swin ), width + 5, height + 5 ); gtk_box_pack_start( GTK_BOX( matrixview->box ), matrixview->swin, FALSE, FALSE, 0 ); } else { gtk_box_pack_start( GTK_BOX( matrixview->box ), matrixview->sheet, FALSE, FALSE, 0 ); } if( matrixview->display == MATRIX_DISPLAY_TEXT_SCALE_OFFSET ) /* Make the scale/offset widgets too. */ matrixview_text_build_scale_offset( matrixview ); } /* Set the label on a toggle button to reflect its value. */ static void matrixview_toggle_set_label( GtkWidget *button, double v ) { GtkWidget *label = GTK_BIN( button )->child; g_return_if_fail( GTK_IS_LABEL( label ) ); switch( (int) v ) { case 0: set_glabel( label, "0" ); break; case 255: set_glabel( label, "1" ); break; default: set_glabel( label, "*" ); break; } } /* Refresh a set of toggle items for a matrix. */ static void matrixview_toggle_refresh( Matrixview *matrixview ) { Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); int x, y; GSList *p; for( p = matrixview->items, y = 0; y < matrixview->height; y++ ) for( x = 0; x < matrixview->width; x++, p = p->next ) { GtkWidget *wid = GTK_WIDGET( p->data ); int i = x + y * matrix->value.width; matrixview_toggle_set_label( wid, matrix->value.coeff[i] ); } } /* Refresh a set of slider items for a matrix. */ static void matrixview_slider_refresh( Matrixview *matrixview ) { Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); int x, y; GSList *p; for( p = matrixview->items, y = 0; y < matrixview->height; y++ ) for( x = 0; x < matrixview->width; x++, p = p->next ) { Tslider *tslider = TSLIDER( p->data ); int i = x + y * matrix->value.width; tslider->value = matrix->value.coeff[i]; tslider->svalue = matrix->value.coeff[i]; tslider_changed( tslider ); } } static void matrixview_text_set( Matrixview *matrixview, GtkWidget *txt, double val ) { if( txt ) { gtk_signal_handler_block_by_data( GTK_OBJECT( txt ), matrixview ); set_gentry( txt, "%g", val ); gtk_signal_handler_unblock_by_data( GTK_OBJECT( txt ), matrixview ); } } /* Fill the widgets! */ static void matrixview_text_refresh( Matrixview *matrixview ) { Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); MatrixValue *matrixvalue = &matrix->value; int width = matrixvalue->width; int height = matrixvalue->height; GtkTreeModel *tree = GTK_TREE_MODEL( matrixview->store ); int x, y; GtkTreeIter iter; if( !matrixvalue->coeff ) return; matrixview_text_set( matrixview, matrixview->scale, matrix->scale ); matrixview_text_set( matrixview, matrixview->offset, matrix->offset ); gtk_tree_model_get_iter_first( tree, &iter ); for( y = 0; y < height; y++ ) { for( x = 0; x < width; x++ ) gtk_list_store_set( matrixview->store, &iter, x, matrixvalue->coeff[x + y * width], -1 ); gtk_tree_model_iter_next( tree, &iter ); } } static void matrixview_refresh( vObject *vobject ) { Matrixview *matrixview = MATRIXVIEW( vobject ); Matrix *matrix = MATRIX( VOBJECT( matrixview )->iobject ); gboolean built; gboolean hclip; gboolean vclip; int width, height; int i; built = FALSE; hclip = FALSE; vclip = FALSE; /* Find required size ... limit displays which are tables of widgets * to avoid huge slowness. */ width = matrix->value.width; height = matrix->value.height; if( matrix->display == MATRIX_DISPLAY_TOGGLE || matrix->display == MATRIX_DISPLAY_SLIDER ) { if( width * height > matrixview_max_cells ) { if( width > height ) { width = IM_CLIP( 1, matrixview_max_cells / height, matrix->value.width ); hclip = TRUE; } else { height = IM_CLIP( 1, matrixview_max_cells / width, matrix->value.height ); vclip = TRUE; } } /* Clip twice to make sure we clip in both directions if * necessary. */ if( width * height > matrixview_max_cells ) { if( width > height ) { width = IM_CLIP( 1, matrixview_max_cells / height, matrix->value.width ); hclip = TRUE; } else { height = IM_CLIP( 1, matrixview_max_cells / width, matrix->value.height ); vclip = TRUE; } } } #ifdef DEBUG printf( "matrixview_refresh\n" ); #endif /*DEBUG*/ /* Is there a UI already there we can reuse? Has to be same size and * type. */ if( matrixview->display != matrix->display || matrixview->width != width || matrixview->height != height ) { /* Kill old UI stuff. */ IM_FREEF( gtk_widget_destroy, matrixview->sheet ); IM_FREEF( gtk_widget_destroy, matrixview->table ); IM_FREEF( gtk_widget_destroy, matrixview->swin ); IM_FREEF( g_slist_free, matrixview->items ); IM_FREEF( gtk_widget_destroy, matrixview->cbox ); matrixview->scale = NULL; matrixview->offset = NULL; /* So the builders know how many widgets to make. */ matrixview->width = width; matrixview->height = height; matrixview->display = matrix->display; /* Make new contents. */ switch( matrix->display ) { case MATRIX_DISPLAY_TOGGLE: matrixview_toggle_build( matrixview ); break; case MATRIX_DISPLAY_SLIDER: matrixview_slider_build( matrixview ); break; case MATRIX_DISPLAY_TEXT: case MATRIX_DISPLAY_TEXT_SCALE_OFFSET: matrixview_text_build( matrixview ); break; default: g_assert( FALSE ); } if( hclip ) { gtk_table_resize( GTK_TABLE( matrixview->table ), matrixview->height, matrixview->width + 1 ); for( i = 0; i < matrixview->height; i++ ) { GtkWidget *lab; lab = gtk_label_new( "---" ); gtk_table_attach( GTK_TABLE( matrixview->table ), lab, matrixview->width, matrixview->width + 1, i, i + 1, GTK_FILL, GTK_FILL, 2, 2 ); } } if( vclip ) { gtk_table_resize( GTK_TABLE( matrixview->table ), matrixview->height + 1, matrixview->width ); for( i = 0; i < matrixview->width; i++ ) { GtkWidget *lab; lab = gtk_label_new( "|" ); gtk_table_attach( GTK_TABLE( matrixview->table ), lab, i, i + 1, matrixview->height, matrixview->height + 1, GTK_FILL, GTK_FILL, 2, 2 ); } } built = TRUE; } switch( matrixview->display ) { case MATRIX_DISPLAY_TOGGLE: matrixview_toggle_refresh( matrixview ); break; case MATRIX_DISPLAY_SLIDER: matrixview_slider_refresh( matrixview ); break; case MATRIX_DISPLAY_TEXT: case MATRIX_DISPLAY_TEXT_SCALE_OFFSET: matrixview_text_refresh( matrixview ); break; default: g_assert( FALSE ); } /* If we've built a new display, need to show after _refresh. */ if( built ) { gtk_widget_show_all( GTK_WIDGET( matrixview ) ); view_resize( VIEW( matrixview ) ); } VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void matrixview_class_init( MatrixviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = matrixview_destroy; /* Create signals. */ /* Init methods. */ vobject_class->refresh = matrixview_refresh; view_class->scan = matrixview_scan; } static void matrixview_init( Matrixview *matrixview ) { #ifdef DEBUG printf( "matrixview_init\n" ); #endif /*DEBUG*/ matrixview->box = gtk_hbox_new( FALSE, 12 ); gtk_box_pack_start( GTK_BOX( matrixview ), GTK_WIDGET( matrixview->box ), FALSE, FALSE, 0 ); /* Build on 1st refresh. */ matrixview->store = NULL; matrixview->sheet = NULL; matrixview->swin = NULL; matrixview->table = NULL; matrixview->items = NULL; matrixview->width = -1; matrixview->height = -1; matrixview->cbox = NULL; matrixview->scale = NULL; matrixview->offset = NULL; } GtkType matrixview_get_type( void ) { static GtkType matrixview_type = 0; if( !matrixview_type ) { static const GtkTypeInfo info = { "Matrixview", sizeof( Matrixview ), sizeof( MatrixviewClass ), (GtkClassInitFunc) matrixview_class_init, (GtkObjectInitFunc) matrixview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; matrixview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( matrixview_type ); } View * matrixview_new( void ) { Matrixview *matrixview = gtk_type_new( TYPE_MATRIXVIEW ); return( VIEW( matrixview ) ); } nip2-8.7.1/src/value.h0000644000175000017500000000313713351443023011376 00000000000000/* abstract base class for real/group/vector */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_VALUE (value_get_type()) #define VALUE( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_VALUE, Value )) #define VALUE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_VALUE, ValueClass)) #define IS_VALUE( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_VALUE )) #define IS_VALUE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_VALUE )) #define VALUE_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_VALUE, ValueClass )) typedef struct _Value { Classmodel model; /* Build caption buffer here. */ VipsBuf caption_buffer; } Value; typedef struct _ValueClass { ClassmodelClass parent_class; /* My methods. */ } ValueClass; GType value_get_type( void ); nip2-8.7.1/src/prefworkspaceview.h0000644000175000017500000000362013351443023014025 00000000000000/* a view of a workspace for the preferences window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PREFWORKSPACEVIEW (prefworkspaceview_get_type()) #define PREFWORKSPACEVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_PREFWORKSPACEVIEW, Prefworkspaceview )) #define PREFWORKSPACEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_PREFWORKSPACEVIEW, PrefworkspaceviewClass )) #define IS_PREFWORKSPACEVIEW( obj ) \ (GTK_CHECK_TYPE( (obj), TYPE_PREFWORKSPACEVIEW )) #define IS_PREFWORKSPACEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PREFWORKSPACEVIEW )) struct _Prefworkspaceview { View view; /* If set, only display the columns whose caption includes this string * (eg. "JPEG"). Used to display tiny prefs windows for jpeg save etc. */ char *caption_filter; }; typedef struct _PrefworkspaceviewClass { ViewClass parent_class; /* My methods. */ } PrefworkspaceviewClass; GtkType prefworkspaceview_get_type( void ); View *prefworkspaceview_new( void ); void prefworkspaceview_set_caption_filter( Prefworkspaceview *pwview, const char *caption_filter ); nip2-8.7.1/src/managed.h0000644000175000017500000000616613351443023011663 00000000000000/* managed objects ... things like Imageinfo which are lifetime managed by * both the GC and by pointers from C: we need to both mark/sweep and refcount * * abstract class: Managedgvalue, Imageinfo, etc. build off this */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_MANAGED (managed_get_type()) #define MANAGED( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGED, Managed )) #define MANAGED_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_MANAGED, ManagedClass)) #define IS_MANAGED( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGED )) #define IS_MANAGED_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGED )) #define MANAGED_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_MANAGED, ManagedClass )) #define MANAGED_UNREF( X ) { \ if( X ) { \ managed_destroy_nonheap( MANAGED( X ) ); \ X = NULL; \ } \ } #define MANAGED_REF( X ) managed_dup_nonheap( MANAGED( X ) ) struct _Managed { iContainer parent_object; /* Can't just set ->heap = NULL to mean unattached, our subclasses * rely on ->heap being valid even during dispose. */ Heap *heap; /* Heap we are attached to */ gboolean attached; /* If we are attached to the heap */ gboolean marked; /* For mark-sweep */ int count; /* Number of non-heap pointers to us */ gboolean zombie; /* Unreffed, but being kept alive */ double time; /* When we became a zombie */ /* FIXME ... This should go with vips8: it does dependency tracking for us. */ GSList *sub; /* Sub-objects ... mark these if we mark this */ /* Set by subclasses as part of construction. */ guint hash; }; typedef struct _ManagedClass { iContainerClass parent_class; /* How long after zombiefying before we unref. */ double keepalive; } ManagedClass; void managed_check_all_destroyed( void ); void managed_link_heap( Managed *managed, Heap *heap ); void managed_destroy_heap( Managed *managed ); void *managed_destroy_nonheap( Managed *managed ); void managed_dup_nonheap( Managed *managed ); void *managed_sub_remove( Managed *in, Managed *managed ); void managed_sub_add( Managed *managed, Managed *in ); void managed_sub_add_all( Managed *out, int nin, Managed **in ); GType managed_get_type( void ); void managed_clear( Heap *heap ); void managed_mark( Managed *managed ); gboolean managed_free_unused( Heap *heap ); nip2-8.7.1/src/managedfile.h0000644000175000017500000000337713351443023012524 00000000000000/* a managed FILE* ... for lazy file read */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_MANAGEDFILE (managedfile_get_type()) #define MANAGEDFILE( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGEDFILE, Managedfile )) #define MANAGEDFILE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_MANAGEDFILE, ManagedfileClass)) #define IS_MANAGEDFILE( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGEDFILE )) #define IS_MANAGEDFILE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGEDFILE )) #define MANAGEDFILE_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_MANAGEDFILE, ManagedfileClass )) struct _Managedfile { Managed parent_object; iOpenFile *file; }; typedef struct _ManagedfileClass { ManagedClass parent_class; } ManagedfileClass; GType managedfile_get_type( void ); Managedfile *managedfile_new( Heap *heap, const char *filename ); int managedfile_getc( Managedfile *managedfile ); nip2-8.7.1/src/action.c0000644000175000017500000014506313351443023011537 00000000000000/* actions on the graph */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* Index with binop or uop. */ const char *operator_table[] = { "none", /* BI_NONE */ "add", /* BI_ADD */ "subtract", /* BI_SUB */ "remainder", /* BI_REM */ "power", /* BI_POW */ "subscript", /* BI_SELECT */ "left_shift", /* BI_LSHIFT */ "right_shift", /* BI_RSHIFT */ "divide", /* BI_DIV */ "join", /* BI_JOIN */ "dot", /* BI_DOT */ "comma", /* BI_COMMA */ "multiply", /* BI_MUL */ "logical_and", /* BI_LAND */ "logical_or", /* BI_LOR */ "bitwise_and", /* BI_BAND */ "bitwise_or", /* BI_BOR */ "eor", /* BI_EOR */ "equal", /* BI_EQ */ "not_equal", /* BI_NOTEQ */ "pointer_equal", /* BI_PEQ */ "pointer_not_equal", /* BI_PNOTEQ */ "less", /* BI_LESS */ "less_equal", /* BI_LESSEQ */ "none", /* BI_MORE */ "none", /* BI_MOREEQ */ "if_then_else", /* BI_IF */ "cons", /* BI_CONS */ "none", /* UN_NONE */ "cast_signed_char", /* UN_CSCHAR */ "cast_unsigned_char", /* UN_CUCHAR */ "cast_signed_short", /* UN_CSSHORT */ "cast_unsigned_short", /* UN_CUSHORT */ "cast_signed_int", /* UN_CSINT */ "cast_unsigned_int", /* UN_CUINT */ "cast_float", /* UN_CFLOAT */ "cast_double", /* UN_CDOUBLE */ "cast_complex", /* UN_CCOMPLEX */ "cast_double_complex", /* UN_CDCOMPLEX */ "unary_minus", /* UN_MINUS */ "negate", /* UN_NEG */ "complement", /* UN_COMPLEMENT */ "unary_plus" /* UN_PLUS */ }; const int noperator_table = IM_NUMBER( operator_table ); /* Bad bop error. */ static void action_boperror( Reduce *rc, Compile *compile, const char *str, int op, const char *name, PElement *a, PElement *b ) { const char *top_str = str ? str : _( "Bad arguments." ); const char *op_name = op >= 0 ? decode_BinOp( op ) : name; char txt[MAX_ERROR_FRAG]; VipsBuf buf = VIPS_BUF_STATIC( txt ); char txt2[MAX_ERROR_FRAG]; VipsBuf buf2 = VIPS_BUF_STATIC( txt2 ); char txt3[MAX_ERROR_FRAG]; VipsBuf buf3 = VIPS_BUF_STATIC( txt3 ); itext_value_ev( rc, &buf, a ); itext_value_ev( rc, &buf2, b ); if( compile ) { /* Expands to eg. 'bad args to "+", called from "fred"' */ vips_buf_appends( &buf3, _( "Called from" ) ); vips_buf_appends( &buf3, " " ); compile_name( compile, &buf3 ); } error_top( "%s", top_str ); error_sub( _( "Error in binary %s.\n" "left = %s\n" "right = %s\n%s" ), op_name, vips_buf_all( &buf ), vips_buf_all( &buf2 ), vips_buf_all( &buf3 ) ); reduce_throw( rc ); } /* Member not found in class instance error. */ static void action_nomerror( Reduce *rc, Compile *compile, PElement *a, PElement *b ) { char txt[500]; VipsBuf buf = VIPS_BUF_STATIC( txt ); char txt2[MAX_ERROR_FRAG]; VipsBuf buf2 = VIPS_BUF_STATIC( txt2 ); char txt3[MAX_ERROR_FRAG]; VipsBuf buf3 = VIPS_BUF_STATIC( txt3 ); if( PEISCLASS( a ) ) symbol_qualified_name( PEGETCLASSCOMPILE( a )->sym, &buf3 ); else if( PEISSYMREF( a ) ) symbol_qualified_name( PEGETSYMREF( a ), &buf3 ); else if( PEISSYMBOL( a ) ) symbol_qualified_name( PEGETSYMBOL( a ), &buf3 ); else if( PEISCOMPILEREF( a ) ) symbol_qualified_name( PEGETCOMPILE( a )->sym, &buf3 ); else vips_buf_appends( &buf3, "" ); itext_value_ev( rc, &buf2, b ); vips_buf_appendf( &buf, _( "Member \"%s\" not found in class \"%s\"." ), vips_buf_all( &buf2 ), vips_buf_all( &buf3 ) ); vips_buf_appendf( &buf, "\n" ); vips_buf_rewind( &buf3 ); itext_value_ev( rc, &buf3, a ); vips_buf_appendf( &buf, " " ); vips_buf_appendf( &buf, _( "object = %s" ), vips_buf_all( &buf3 ) ); vips_buf_appendf( &buf, "\n" ); vips_buf_appendf( &buf, " " ); vips_buf_appendf( &buf, _( "tag = %s" ), vips_buf_all( &buf2 ) ); vips_buf_appendf( &buf, "\n" ); vips_buf_rewind( &buf3 ); symbol_qualified_name( compile->sym, &buf3 ); vips_buf_appendf( &buf, _( "Reference attempted in \"%s\"." ), vips_buf_all( &buf3 ) ); vips_buf_appendf( &buf, "\n" ); error_top( _( "Member not found." ) ); error_sub( "%s", vips_buf_all( &buf ) ); reduce_throw( rc ); } /* Bad uop error. */ static void action_uoperror( Reduce *rc, Compile *compile, const char *str, int op, const char *name, PElement *a ) { const char *top_str = str ? str : _( "Bad argument." ); const char *op_name = op >= 0 ? decode_UnOp( op ) : name; char txt[MAX_ERROR_FRAG]; VipsBuf buf = VIPS_BUF_STATIC( txt ); char txt2[MAX_ERROR_FRAG]; VipsBuf buf2 = VIPS_BUF_STATIC( txt2 ); itext_value_ev( rc, &buf, a ); if( compile ) { /* Expands to eg. 'bad args to "+", called from "fred"' */ vips_buf_appends( &buf2, _( "Called from" ) ); vips_buf_appends( &buf2, " " ); compile_name( compile, &buf2 ); } error_top( "%s", top_str ); error_sub( _( "Error in unary %s.\n" "argument = %s\n%s" ), op_name, vips_buf_all( &buf ), vips_buf_all( &buf2 ) ); reduce_throw( rc ); } /* Clip real part of number a to a range. */ static void action_set_range( Reduce *rc, double mn, double mx, PElement *a, PElement *out ) { Heap *heap = rc->heap; double d; /* Get real part. */ if( PEISREAL( a ) ) d = PEGETREAL( a ); else d = PEGETREALPART( a ); if( d < mn ) d = mn; else if( d > mx ) d = mx; else d = (int) d; if( !heap_real_new( heap, d, out ) ) reduce_throw( rc ); } /* EOR two things. */ static void action_proc_eor( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISBOOL( a ) && PEISBOOL( b ) ) { PEPUTP( out, ELEMENT_BOOL, PEGETBOOL( a ) ^ PEGETBOOL( b ) ); } else if( PEISREAL( a ) && PEISREAL( b ) ) { int v1 = PEGETREAL( a ); int v2 = PEGETREAL( b ); if( !heap_real_new( heap, v1 ^ v2, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_eorimage", PEGETII( a ), PEGETII( b ) ); else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_eorimageconst", PEGETII( a ), (int) PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_eorimageconst", PEGETII( b ), (int) PEGETREAL( a ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* OR two things. */ static void action_proc_bor( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { int v1 = PEGETREAL( a ); int v2 = PEGETREAL( b ); if( !heap_real_new( heap, v1 | v2, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_orimage", PEGETII( a ), PEGETII( b ) ); else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_orimageconst", PEGETII( a ), (int) PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_orimageconst", PEGETII( b ), (int) PEGETREAL( a ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* AND two things. */ static void action_proc_band( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_andimage", PEGETII( a ), PEGETII( b ) ); else if( PEISREAL( a ) && PEISREAL( b ) ) { int v1 = PEGETREAL( a ); int v2 = PEGETREAL( b ); if( !heap_real_new( heap, v1 & v2, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_andimageconst", PEGETII( a ), (int) PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_andimageconst", PEGETII( b ), (int) PEGETREAL( a ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } static void * action_proc_dot_add_link( Expr *expr, Symbol *child ) { return( link_add( child, expr, TRUE ) ); } static char * action_proc_dot_tag( Reduce *rc, PElement *b, char *tag, int n ) { if( PEISTAG( b ) ) return( PEGETTAG( b ) ); else if( reduce_is_string( rc, b ) ) { (void) reduce_get_string( rc, b, tag, n ); return( tag ); } return( NULL ); } /* Extract field from object. Be careful, a can be equal to out. */ static void action_proc_dot( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { char tag[256]; char *p; if( PEISCLASS( a ) ) { PElement c; if( (p = action_proc_dot_tag( rc, b, tag, 256 )) ) { if( !class_get_member( a, p, NULL, &c ) ) action_nomerror( rc, compile, a, b ); PEPUTPE( out, &c ); } else if( PEISSYMREF( b ) ) { if( !class_get_symbol( a, PEGETSYMREF( b ), &c ) ) action_nomerror( rc, compile, a, b ); PEPUTPE( out, &c ); } else action_boperror( rc, compile, _( "Bad right hand side of '.'." ), op, name, a, b ); } else if( PEISSYMREF( a ) ) { Symbol *sym = PEGETSYMREF( a ); Symbol *child; if( !is_scope( sym ) ) action_boperror( rc, compile, _( "Symbol on left hand side of '.' " "is not scope" ), op, name, a, b ); g_assert( sym->expr ); if( !(p = action_proc_dot_tag( rc, b, tag, 256 )) ) action_boperror( rc, compile, _( "Bad right hand side of '.'." ), op, name, a, b ); if( !(child = compile_lookup( sym->expr->compile, p )) ) action_nomerror( rc, compile, a, b ); /* Add all exprs which use compile to dynamic link graph. */ if( slist_map( compile->exprs, (SListMapFn) action_proc_dot_add_link, child ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); /* Don't check for dirty here ... wait for * link. */ if( child->type == SYM_VALUE ) { PEPUTP( out, ELEMENT_SYMBOL, child ); } else { PEPUTP( out, ELEMENT_SYMREF, child ); } } else if( PEISMANAGEDGOBJECT( a ) ) { GObject *gobject = PEGETMANAGEDGOBJECT( a ); GObjectClass *gclass = G_OBJECT_GET_CLASS( gobject ); GValue value = { 0 }; GParamSpec *pspec; if( !(p = action_proc_dot_tag( rc, b, tag, 256 )) ) action_boperror( rc, compile, _( "Bad right hand side of '.'." ), op, name, a, b ); if( !(pspec = g_object_class_find_property( gclass, p )) ) action_boperror( rc, compile, _( "Property not found." ), op, name, a, b ); g_value_init( &value, G_PARAM_SPEC_VALUE_TYPE( pspec ) ); g_object_get_property( gobject, p, &value); if( !heap_gvalue_to_ip( &value, out ) ) { g_value_unset( &value ); reduce_throw( rc ); } g_value_unset( &value ); } else action_boperror( rc, compile, _( "Bad left hand side of '.'." ), op, name, a, b ); } /* Less than or equal to. */ static void action_proc_lesseq( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { if( PEISREAL( a ) && PEISREAL( b ) ) { PEPUTP( out, ELEMENT_BOOL, PEGETREAL( a ) <= PEGETREAL( b ) ); } else if( PEISCHAR( a ) && PEISCHAR( b ) ) { PEPUTP( out, ELEMENT_BOOL, PEGETCHAR( a ) <= PEGETCHAR( b ) ); } else if( PEISLIST( a ) && PEISLIST( b ) && reduce_is_string( rc, a ) && reduce_is_string( rc, b ) ) { char a_string[MAX_STRSIZE]; char b_string[MAX_STRSIZE]; reduce_get_string( rc, a, a_string, MAX_STRSIZE ); reduce_get_string( rc, b, b_string, MAX_STRSIZE ); PEPUTP( out, ELEMENT_BOOL, strcmp( a_string, b_string ) <= 0 ); } else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_lesseqconst", PEGETII( a ), PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_moreeqconst", PEGETII( b ), PEGETREAL( a ) ); else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_lesseq", PEGETII( a ), PEGETII( b ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Strict less than. */ static void action_proc_less( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { if( PEISREAL( a ) && PEISREAL( b ) ) { PEPUTP( out, ELEMENT_BOOL, PEGETREAL( a ) < PEGETREAL( b ) ); } else if( PEISCHAR( a ) && PEISCHAR( b ) ) { PEPUTP( out, ELEMENT_BOOL, PEGETCHAR( a ) < PEGETCHAR( b ) ); } else if( PEISLIST( a ) && PEISLIST( b ) && reduce_is_string( rc, a ) && reduce_is_string( rc, b ) ) { char a_string[MAX_STRSIZE]; char b_string[MAX_STRSIZE]; reduce_get_string( rc, a, a_string, MAX_STRSIZE ); reduce_get_string( rc, b, b_string, MAX_STRSIZE ); PEPUTP( out, ELEMENT_BOOL, strcmp( a_string, b_string ) < 0 ); } else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_lessconst", PEGETII( a ), PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_moreconst", PEGETII( b ), PEGETREAL( a ) ); else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_less", PEGETII( a ), PEGETII( b ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Forward ref. */ static gboolean action_element_equal( Reduce *rc, PElement *a, PElement *b ); /* Test two nodes for equality. */ static gboolean action_node_equal( Reduce *rc, HeapNode *a, HeapNode *b ) { PElement la, ra; PElement lb, rb; /* Easy! */ if( a->type != b->type ) return( FALSE ); switch( a->type ) { case TAG_APPL: case TAG_CLASS: /* Function compare ... don't allow it. */ return( FALSE ); case TAG_CONS: /* Compare the elements. */ PEPOINTLEFT( a, &la ); PEPOINTLEFT( b, &lb ); PEPOINTRIGHT( a, &ra ); PEPOINTRIGHT( b, &rb ); return( action_element_equal( rc, &la, &lb ) && action_element_equal( rc, &ra, &rb ) ); case TAG_DOUBLE: return( a->body.num == b->body.num ); case TAG_COMPLEX: return( GETLEFT( a )->body.num == GETLEFT( b )->body.num && GETRIGHT( a )->body.num == GETRIGHT( b )->body.num ); case TAG_GEN: case TAG_FILE: case TAG_FREE: case TAG_SHARED: case TAG_REFERENCE: default: g_assert( FALSE ); /* Keep gcc happy. */ return( FALSE ); } } static gboolean action_image_equal( Reduce *rc, Imageinfo *a, Imageinfo *b ) { Imageinfo *ii[2]; IMAGE *t1; IMAGE *ai, *bi; gboolean use_luts; double mn; /* Easy tests first. */ ii[0] = a; ii[1] = b; g_assert( !ii[0] && !ii[1] ); if( ii[0] == ii[1] ) /* Trivial! */ return( TRUE ); /* Extract images ... get LUTs if the underlying image is the * same. */ use_luts = imageinfo_same_underlying( ii, 2 ); if( !(ai = imageinfo_get( use_luts, ii[0] )) || !(bi = imageinfo_get( use_luts, ii[1] )) ) { reduce_throw( rc ); /* Never get here, but keeps gcc happy. */ return( FALSE ); } /* Size and bands must be the same. */ if( ai->Xsize != bi->Xsize || ai->Ysize != bi->Ysize || ai->Bands != bi->Bands || ai->Coding != bi->Coding ) return( FALSE ); /* Exhaustive test. */ if( !(t1 = im_open( "equals:1", "p" )) ) { error_vips_all(); reduce_throw( rc ); } if( im_equal( ai, bi, t1 ) || im_min( t1, &mn ) ) { im_close( t1 ); error_vips_all(); reduce_throw( rc ); } im_close( t1 ); return( mn == 255 ); } /* One of p1/p2 is a managedstring. * * This is pretty dumb. We could have a special loop down the list side which * compared to the managedstring directly, but I doubt if this will ever be a * performance issue. */ static gboolean action_string_equal( Reduce *rc, PElement *p1, PElement *p2 ) { char a_string[MAX_STRSIZE]; char b_string[MAX_STRSIZE]; reduce_get_string( rc, p1, a_string, MAX_STRSIZE ); reduce_get_string( rc, p2, b_string, MAX_STRSIZE ); return( strcmp( a_string, b_string ) == 0 ); } /* Test two elements for equality. Force computation as required. */ static gboolean action_element_equal( Reduce *rc, PElement *p1, PElement *p2 ) { /* Reduce a bit. */ reduce_spine( rc, p1 ); reduce_spine( rc, p2 ); /* We can often test for eg. "fred" == "fred" by just checking * pointers. */ if( PEGETTYPE( p1 ) == PEGETTYPE( p2 ) ) { switch( PEGETTYPE( p1 ) ) { case ELEMENT_CHAR: case ELEMENT_NODE: case ELEMENT_BOOL: case ELEMENT_MANAGED: if( PEGETVAL( p1 ) == PEGETVAL( p2 ) ) return( TRUE ); break; case ELEMENT_ELIST: return( TRUE ); } } /* Special case if either is a managedstring. */ if( PEISMANAGEDSTRING( p1 ) || PEISMANAGEDSTRING( p2 ) ) return( action_string_equal( rc, p1, p2 ) ); /* No other implicit conversions, so types must match. */ if( PEGETTYPE( p1 ) != PEGETTYPE( p2 ) ) return( FALSE ); switch( PEGETTYPE( p1 ) ) { case ELEMENT_TAG: case ELEMENT_BINOP: case ELEMENT_UNOP: case ELEMENT_SYMBOL: case ELEMENT_SYMREF: case ELEMENT_COMPILEREF: case ELEMENT_CONSTRUCTOR: case ELEMENT_COMB: /* Don't allow function compare. */ return( FALSE ); case ELEMENT_NODE: /* Compare the HeapNodes. */ return( action_node_equal( rc, PEGETVAL( p1 ), PEGETVAL( p2 ) ) ); case ELEMENT_CHAR: return( PEGETCHAR( p1 ) == PEGETCHAR( p2 ) ); case ELEMENT_BOOL: return( PEGETBOOL( p1 ) == PEGETBOOL( p2 ) ); case ELEMENT_MANAGED: if( PEISIMAGE( p1 ) && PEISIMAGE( p2 ) ) return( action_image_equal( rc, PEGETII( p1 ), PEGETII( p2 ) ) ); else return( FALSE ); case ELEMENT_ELIST: return( TRUE ); case ELEMENT_NOVAL: default: g_assert( FALSE ); /* Keep gcc happy. */ return( FALSE ); } } /* Top-level == ... special form for image args. */ static void action_proc_equal( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out ) { gboolean res; PElement left, right; PElement *a = &left; PElement *b = &right; PEPOINTRIGHT( arg[1], &left ); PEPOINTRIGHT( arg[0], &right ); if( PEISIMAGE( a ) || PEISIMAGE( b ) ) { /* Special image equals form. Hyperstrict. */ reduce_spine_strict( rc, a ); reduce_spine_strict( rc, b ); if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_equalconst", PEGETII( a ), PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_equalconst", PEGETII( b ), PEGETREAL( a ) ); else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_equal", PEGETII( a ), PEGETII( b ) ); else PEPUTP( out, ELEMENT_BOOL, FALSE ); } else { /* Lazy form. */ res = action_element_equal( rc, a, b ); PEPUTP( out, ELEMENT_BOOL, res ); } } /* Top-level != ... special form for image args. */ static void action_proc_notequal( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out ) { gboolean res; PElement left, right; PElement *a = &left; PElement *b = &right; PEPOINTRIGHT( arg[1], &left ); PEPOINTRIGHT( arg[0], &right ); if( PEISIMAGE( a ) || PEISIMAGE( b ) ) { /* Special image equals form. Hyperstrict. */ reduce_spine_strict( rc, a ); reduce_spine_strict( rc, b ); if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_notequalconst", PEGETII( a ), PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_notequalconst", PEGETII( b ), PEGETREAL( a ) ); else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_notequal", PEGETII( a ), PEGETII( b ) ); else PEPUTP( out, ELEMENT_BOOL, TRUE ); } else { res = action_element_equal( rc, a, b ); PEPUTP( out, ELEMENT_BOOL, !res ); } } static void * action_proc_join_sub( Reduce *rc, PElement *pe, PElement *a, PElement *b, PElement *out ) { if( !heap_list_cat( rc, a, b, pe ) ) return( a ); PEPUTPE( out, pe ); return( NULL ); } static void action_proc_join( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out ) { PElement left, right; PElement *a = &left; PElement *b = &right; PEPOINTRIGHT( arg[1], &left ); PEPOINTRIGHT( arg[0], &right ); if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_bandjoin", PEGETII( a ), PEGETII( b ) ); else if( PEISLIST( a ) && PEISLIST( b ) ) { if( reduce_safe_pointer( rc, (reduce_safe_pointer_fn) action_proc_join_sub, a, b, out, NULL ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISELIST( b ) ) { PEPUTPE( out, a ); } else if( PEISIMAGE( b ) && PEISELIST( a ) ) { PEPUTPE( out, b ); } else action_boperror( rc, compile, NULL, op, name, a, b ); } static void action_proc_index( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out ) { PElement left, right; PElement *a = &left; PElement *b = &right; PEPOINTRIGHT( arg[1], &left ); PEPOINTRIGHT( arg[0], &right ); if( PEISLIST( a ) && PEISREAL( b ) ) { PElement result; reduce_list_index( rc, a, PEGETREAL( b ), &result ); PEPUTPE( out, &result ); } else if( PEISIMAGE( a ) && PEISREAL( b ) ) { callva( rc, out, "im_extract_band", PEGETII( a ), (int) PEGETREAL( b ) ); } else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Raise to power. */ static void action_proc_exp( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { if( !heap_real_new( heap, pow( PEGETREAL( a ), PEGETREAL( b ) ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_powtra", PEGETII( a ), PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_expntra", PEGETII( b ), PEGETREAL( a ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Left shift. */ static void action_proc_lshift( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { int v1 = PEGETREAL( a ); int v2 = PEGETREAL( b ); if( !heap_real_new( heap, v1 << v2, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_shiftleft", PEGETII( a ), (int) PEGETREAL( b ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Right shift. */ static void action_proc_rshift( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { int v1 = PEGETREAL( a ); int v2 = PEGETREAL( b ); if( !heap_real_new( heap, v1 >> v2, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_shiftright", PEGETII( a ), (int) PEGETREAL( b ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Remainder. */ static void action_proc_rem( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { int v1 = PEGETREAL( a ); int v2 = PEGETREAL( b ); if( v2 == 0 ) action_boperror( rc, compile, _( "Division by zero." ), op, name, a, b ); if( !heap_real_new( heap, v1 % v2, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_remainder", PEGETII( a ), PEGETII( b ) ); else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_remainderconst", PEGETII( a ), PEGETREAL( b ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Divide two objects. */ static void action_proc_div( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { if( !heap_real_new( heap, PEGETREAL( a ) / PEGETREAL( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISCOMPLEX( a ) && PEISCOMPLEX( b ) ) { double x1 = PEGETREALPART( a ); double y1 = PEGETIMAGPART( a ); double x2 = PEGETREALPART( b ); double y2 = PEGETIMAGPART( b ); if( !heap_complex_new( heap, (x1 * x2 + y1 * y2) / (x2 * x2 + y2 * y2), (y1 * x2 - x1 * y2) / (x2 * x2 + y2 * y2), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISCOMPLEX( a ) && PEISREAL( b ) ) { double x1 = PEGETREALPART( a ); double y1 = PEGETIMAGPART( a ); double x2 = PEGETREAL( b ); if( !heap_complex_new( heap, (x1 * x2) / (x2 * x2), (y1 * x2) / (x2 * x2), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISREAL( a ) && PEISCOMPLEX( b ) ) { double x1 = PEGETREAL( a ); double x2 = PEGETREALPART( b ); double y2 = PEGETIMAGPART( b ); if( !heap_complex_new( heap, (x1 * x2) / (x2 * x2 + y2 * y2), (-x1 * y2) / (x2 * x2 + y2 * y2), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_divide", PEGETII( a ), PEGETII( b ) ); else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_lintra", 1.0 / PEGETREAL( b ), PEGETII( a ), 0.0 ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) { HeapNode hn; PElement rhs; /* Use this for intermediates. */ PEPOINTRIGHT( &hn, &rhs ); /* Take recip. */ callva( rc, &rhs, "im_powtra", PEGETII( b ), -1.0 ); /* Now multiply by const. */ callva( rc, out, "im_lintra", PEGETREAL( a ), PEGETII( &rhs ), 0.0 ); } else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Multiply two objects. */ static void action_proc_mul( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { if( !heap_real_new( heap, PEGETREAL( a ) * PEGETREAL( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISCOMPLEX( a ) && PEISCOMPLEX( b ) ) { double x1 = PEGETREALPART( a ); double y1 = PEGETIMAGPART( a ); double x2 = PEGETREALPART( b ); double y2 = PEGETIMAGPART( b ); if( !heap_complex_new( heap, x1*x2 - y1*y2, x1*y2 + x2*y1, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISCOMPLEX( a ) && PEISREAL( b ) ) { if( !heap_complex_new( heap, PEGETREALPART( a ) * PEGETREAL( b ), PEGETIMAGPART( a ) * PEGETREAL( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISREAL( a ) && PEISCOMPLEX( b ) ) { if( !heap_complex_new( heap, PEGETREAL( a ) * PEGETREALPART( b ), PEGETREAL( a ) * PEGETIMAGPART( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_multiply", PEGETII( a ), PEGETII( b ) ); else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_lintra", PEGETREAL( b ), PEGETII( a ), 0.0 ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_lintra", PEGETREAL( a ), PEGETII( b ), 0.0 ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Subtract two objects. */ static void action_proc_sub( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { if( !heap_real_new( heap, PEGETREAL( a ) - PEGETREAL( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISCOMPLEX( a ) && PEISCOMPLEX( b ) ) { if( !heap_complex_new( heap, PEGETREALPART( a ) - PEGETREALPART( b ), PEGETIMAGPART( a ) - PEGETIMAGPART( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISCOMPLEX( a ) && PEISREAL( b ) ) { if( !heap_complex_new( heap, PEGETREALPART( a ) - PEGETREAL( b ), PEGETIMAGPART( a ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISREAL( a ) && PEISCOMPLEX( b ) ) { if( !heap_complex_new( heap, PEGETREAL( a ) - PEGETREALPART( b ), PEGETIMAGPART( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_subtract", PEGETII( a ), PEGETII( b ) ); else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_lintra", 1.0, PEGETII( a ), -PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_lintra", -1.0, PEGETII( b ), PEGETREAL( a ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Add two objects. */ static void action_proc_add( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { Heap *heap = rc->heap; if( PEISREAL( a ) && PEISREAL( b ) ) { if( !heap_real_new( heap, PEGETREAL( a ) + PEGETREAL( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISCOMPLEX( a ) && PEISCOMPLEX( b ) ) { if( !heap_complex_new( heap, PEGETREALPART( a ) + PEGETREALPART( b ), PEGETIMAGPART( a ) + PEGETIMAGPART( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISCOMPLEX( a ) && PEISREAL( b ) ) { if( !heap_complex_new( heap, PEGETREALPART( a ) + PEGETREAL( b ), PEGETIMAGPART( a ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISREAL( a ) && PEISCOMPLEX( b ) ) { if( !heap_complex_new( heap, PEGETREAL( a ) + PEGETREALPART( b ), PEGETIMAGPART( b ), out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_add", PEGETII( a ), PEGETII( b ) ); else if( PEISIMAGE( a ) && PEISREAL( b ) ) callva( rc, out, "im_lintra", 1.0, PEGETII( a ), PEGETREAL( b ) ); else if( PEISREAL( a ) && PEISIMAGE( b ) ) callva( rc, out, "im_lintra", 1.0, PEGETII( b ), PEGETREAL( a ) ); else action_boperror( rc, compile, NULL, op, name, a, b ); } /* Evaluate a binary operator on args a and b, write the result to out. a and * b already reduced. * * Call one of the things above. Not all combinations implemented, got bored :/ * Implement simple things in the switch, break to the functions above for * the rest. * * out can be rhs of argv[0], careful. */ static void action_proc_bop_strict( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out ) { Heap *heap = rc->heap; HeapNode *hn; PElement left, right; PElement *a = &left; PElement *b = &right; PEPOINTRIGHT( arg[1], &left ); PEPOINTRIGHT( arg[0], &right ); switch( op ) { case BI_SELECT: action_proc_index( rc, compile, op, name, arg, out ); break; case BI_JOIN: action_proc_join( rc, compile, op, name, arg, out ); break; case BI_EQ: action_proc_equal( rc, compile, op, name, arg, out ); break; case BI_NOTEQ: action_proc_notequal( rc, compile, op, name, arg, out ); break; case BI_PEQ: PEPUTP( out, ELEMENT_BOOL, PEGETTYPE( a ) == PEGETTYPE( b ) && PEGETVAL( a ) == PEGETVAL( b ) ); break; case BI_PNOTEQ: PEPUTP( out, ELEMENT_BOOL, PEGETTYPE( a ) != PEGETTYPE( b ) || PEGETVAL( a ) != PEGETVAL( b ) ); break; case BI_ADD: action_proc_add( rc, compile, op, name, a, b, out ); break; case BI_SUB: action_proc_sub( rc, compile, op, name, a, b, out ); break; case BI_MUL: action_proc_mul( rc, compile, op, name, a, b, out ); break; case BI_DIV: action_proc_div( rc, compile, op, name, a, b, out ); break; case BI_DOT: action_proc_dot( rc, compile, op, name, a, b, out ); break; case BI_POW: action_proc_exp( rc, compile, op, name, a, b, out ); break; case BI_LSHIFT: action_proc_lshift( rc, compile, op, name, a, b, out ); break; case BI_RSHIFT: action_proc_rshift( rc, compile, op, name, a, b, out ); break; case BI_REM: action_proc_rem( rc, compile, op, name, a, b, out ); break; case BI_LESS: action_proc_less( rc, compile, op, name, a, b, out ); break; case BI_LESSEQ: action_proc_lesseq( rc, compile, op, name, a, b, out ); break; case BI_COMMA: if( PEISREAL( a ) && PEISREAL( b ) ) { if( NEWNODE( heap, hn ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); /* Form complex node. */ hn->type = TAG_COMPLEX; PPUT( hn, ELEMENT_NODE, PEGETVAL( a ), ELEMENT_NODE, PEGETVAL( b ) ); PEPUTP( out, ELEMENT_NODE, hn ); } else if( PEISIMAGE( a ) && PEISIMAGE( b ) ) { callva( rc, out, "im_ri2c", PEGETII( a ), PEGETII( b ) ); } else action_boperror( rc, compile, NULL, op, name, a, b ); break; case BI_BAND: action_proc_band( rc, compile, op, name, a, b, out ); break; case BI_BOR: action_proc_bor( rc, compile, op, name, a, b, out ); break; case BI_EOR: action_proc_eor( rc, compile, op, name, a, b, out ); break; case BI_NONE: default: action_boperror( rc, compile, _( "Unimplemented." ), op, name, a, b ); break; } } /* Evaluate a unary operator on arg a, write the result to out. a * already reduced. */ void action_proc_uop( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out ) { Heap *heap = rc->heap; PElement pe, *a = &pe; PElement rhs; PEPOINTRIGHT( arg[0], &pe ); switch( op ) { case UN_NEG: if( PEISREAL( a ) ) { if( !heap_real_new( heap, !PEGETREAL( a ), out ) ) reduce_throw( rc ); } else if( PEISCOMPLEX( a ) ) { if( !heap_complex_new( heap, !PEGETREALPART( a ), !PEGETIMAGPART( a ), out ) ) reduce_throw( rc ); } else if( PEISBOOL( a ) ) { PEPUTP( out, ELEMENT_BOOL, !PEGETBOOL( a ) ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_equalconst", PEGETII( a ), 0.0 ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_MINUS: if( PEISREAL( a ) ) { if( !heap_real_new( heap, -PEGETREAL( a ), out ) ) reduce_throw( rc ); } else if( PEISCOMPLEX( a ) ) { if( !heap_complex_new( heap, -PEGETREALPART( a ), -PEGETIMAGPART( a ), out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_lintra", -1.0, PEGETII( a ), 0.0 ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_COMPLEMENT: if( PEISREAL( a ) ) { int v = PEGETREAL( a ); if( !heap_real_new( heap, ~v, out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_eorimageconst", PEGETII( a ), -1 ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_PLUS: PEPUTPE( out, a ); break; case UN_CSCHAR: /* Convert to signed char. */ if( PEISNUM( a ) ) { action_set_range( rc, SCHAR_MIN, SCHAR_MAX, a, out ); } else if( PEISCHAR( a ) ) { if( !heap_real_new( heap, PEGETCHAR( a ), out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_clip2c", PEGETII( a ) ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_CUCHAR: /* Convert to unsigned char, eg. 65 => 'A'. */ if( PEISREAL( a ) ) { double v = PEGETREAL( a ); v = IM_CLIP( 0, v, UCHAR_MAX ); PEPUTP( out, ELEMENT_CHAR, (int) v ); } else if( PEISCOMPLEX( a ) ) { double v = PEGETREALPART( a ); v = IM_CLIP( 0, v, UCHAR_MAX ); PEPUTP( out, ELEMENT_CHAR, (int) v ); } else if( PEISCHAR( a ) ) { PEPUTPE( out, a ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_clip", PEGETII( a ) ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_CSINT: /* Convert to signed int. */ if( PEISNUM( a ) ) action_set_range( rc, INT_MIN, INT_MAX, a, out ); else if( PEISCHAR( a ) ) { if( !heap_real_new( heap, PEGETCHAR( a ), out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_clip2i", PEGETII( a ) ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_CUINT: /* Convert to unsigned int. */ if( PEISREAL( a ) || PEISCOMPLEX( a ) ) action_set_range( rc, 0, UINT_MAX, a, out ); else if( PEISCHAR( a ) ) { if( !heap_real_new( heap, PEGETCHAR( a ), out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_clip2ui", PEGETII( a ) ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_CSSHORT: /* Convert to signed short. */ if( PEISREAL( a ) || PEISCOMPLEX( a ) ) action_set_range( rc, SHRT_MIN, SHRT_MAX, a, out ); else if( PEISCHAR( a ) ) { if( !heap_real_new( heap, PEGETCHAR( a ), out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_clip2s", PEGETII( a ) ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_CUSHORT: /* Convert to unsigned short. */ if( PEISREAL( a ) || PEISCOMPLEX( a ) ) action_set_range( rc, 0, USHRT_MAX, a, out ); else if( PEISCHAR( a ) ) { if( !heap_real_new( heap, PEGETCHAR( a ), out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_clip2us", PEGETII( a ) ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_CFLOAT: /* Convert to float ... just drop imag part. */ if( PEISCOMPLEX( a ) ) { if( !heap_real_new( heap, PEGETREALPART( a ), out ) ) reduce_throw( rc ); } else if( PEISREAL( a ) ) { PEPUTPE( out, a ); } else if( PEISCHAR( a ) ) { if( !heap_real_new( heap, PEGETCHAR( a ), out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_clip2f", PEGETII( a ) ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_CDOUBLE: /* Convert to double ... just drop imag part. */ if( PEISCOMPLEX( a ) ) { if( !heap_real_new( heap, PEGETREALPART( a ), out ) ) reduce_throw( rc ); } else if( PEISREAL( a ) ) { PEPUTPE( out, a ); } else if( PEISCHAR( a ) ) { if( !heap_real_new( heap, PEGETCHAR( a ), out ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) callva( rc, out, "im_clip2d", PEGETII( a ) ); else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_CDCOMPLEX: case UN_CCOMPLEX: /* Convert to complex ... set imag = 0. */ if( PEISREAL( a ) ) { /* Make base node. */ if( !heap_complex_element_new( heap, a, a, out ) ) reduce_throw( rc ); /* Install new imag part. */ PEPOINTRIGHT( PEGETVAL( out ), &rhs ); if( !heap_real_new( heap, 0, &rhs ) ) reduce_throw( rc ); } else if( PEISCOMPLEX( a ) ) { PEPUTPE( out, a ); } else if( PEISCHAR( a ) ) { /* Make base node. */ if( !heap_complex_element_new( heap, a, a, out ) ) reduce_throw( rc ); /* Install new real and imag parts. */ PEPOINTLEFT( PEGETVAL( out ), &rhs ); if( !heap_real_new( heap, PEGETCHAR( a ), &rhs ) ) reduce_throw( rc ); PEPOINTRIGHT( PEGETVAL( out ), &rhs ); if( !heap_real_new( heap, 0, &rhs ) ) reduce_throw( rc ); } else if( PEISIMAGE( a ) ) { if( op == UN_CCOMPLEX ) callva( rc, out, "im_clip2cm", PEGETII( a ) ); else callva( rc, out, "im_clip2dcm", PEGETII( a ) ); } else action_uoperror( rc, compile, NULL, op, name, a ); break; case UN_NONE: default: action_uoperror( rc, compile, _( "Unimplemented." ), op, name, a ); break; } } static void * action_proc_construct_sub( Reduce *rc, PElement *pe, Compile *compile, HeapNode **arg, PElement *out ) { if( !class_new( rc->heap, compile, arg, pe ) ) reduce_throw( rc ); PEPUTPE( out, pe ); return( NULL ); } /* Eval a constructor. Nasty: out can be RHS of arg[0], so we have to build * instance in a safe spot, then write back to out afterwards. */ void action_proc_construct( Reduce *rc, Compile *compile, HeapNode **arg, PElement *out ) { if( trace_flags & TRACE_CLASS_NEW ) { VipsBuf *buf = trace_push(); vips_buf_appendf( buf, "constructor \"%s\" ", IOBJECT( compile->sym )->name ); trace_args( arg, compile->nparam + compile->nsecret ); } if( reduce_safe_pointer( rc, (reduce_safe_pointer_fn) action_proc_construct_sub, compile, arg, out, NULL ) ) reduce_throw( rc ); /* Is it a class with a typecheck member? Return that instead. */ if( compile_lookup( compile, MEMBER_CHECK ) && class_get_member( out, MEMBER_CHECK, NULL, out ) ) { #ifdef DEBUG printf( "reduce: invoking arg checker\n" ); #endif } if( trace_flags & TRACE_CLASS_NEW ) { trace_result( TRACE_CLASS_NEW, out ); trace_pop(); } } static void * action_proc_class_binary_sub( Reduce *rc, PElement *pe, PElement *fn, const char *name, PElement *b, PElement *out ) { PElement rhs; PElement base; base = *pe; heap_appl_init( &base, fn ); if( !heap_appl_add( rc->heap, &base, &rhs ) || !heap_managedstring_new( rc->heap, name, &rhs ) || !heap_appl_add( rc->heap, &base, &rhs ) ) return( out ); PEPUTPE( &rhs, b ); PEPUTPE( out, pe ); return( NULL ); } /* Something like "class + 12" ... call (class.add 12) */ static void action_proc_class_binary( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { TraceFlags flags = op >= 0 ? TRACE_OPERATOR : TRACE_BUILTIN; PElement fn; if( trace_flags & flags ) { VipsBuf *buf = trace_push(); vips_buf_appendf( buf, "%s\n", _( "invoking method:" ) ); vips_buf_appends( buf, " " ); trace_pelement( a ); vips_buf_appendf( buf, ".%s \"%s\" ", MEMBER_OO_BINARY, name ); trace_pelement( b ); vips_buf_appends( buf, "\n" ); trace_text( flags, "%s", vips_buf_all( buf ) ); trace_pop(); } /* Look up a.oo_binary and build (a.dispatch_binary "add" b) * application. */ if( !class_get_member( a, MEMBER_OO_BINARY, NULL, &fn ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); if( reduce_safe_pointer( rc, (reduce_safe_pointer_fn) action_proc_class_binary_sub, &fn, (void *) name, b, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } /* Something like "12 + class" ... call (class.add' 12) */ static void action_proc_class_binary2( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { TraceFlags flags = op >= 0 ? TRACE_OPERATOR : TRACE_BUILTIN; PElement fn; if( trace_flags & flags ) { VipsBuf *buf = trace_push(); vips_buf_appendf( buf, "%s\n", _( "invoking method:" ) ); vips_buf_appends( buf, " " ); trace_pelement( b ); vips_buf_appendf( buf, ".%s \"%s\" ", MEMBER_OO_BINARY2, name ); trace_pelement( a ); vips_buf_appends( buf, "\n" ); trace_text( flags, "%s", vips_buf_all( buf ) ); trace_pop(); } /* Look up b.dispatch_binary2 and build * (b.dispatch_binary2 "add" a) application. */ if( !class_get_member( b, MEMBER_OO_BINARY2, NULL, &fn ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); if( reduce_safe_pointer( rc, (reduce_safe_pointer_fn) action_proc_class_binary_sub, &fn, (void *) name, a, out ) ) action_boperror( rc, compile, error_get_sub(), op, name, a, b ); } static void action_landlor( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { reduce_spine( rc, a ); if( PEISCOMB( a ) && PEGETCOMB( a ) == COMB_I ) /* The reduce_spine() did us recursively ... bounce back. */ return; if( trace_flags & TRACE_OPERATOR ) trace_push(); /* Examine the LHS and see if we can avoid RHS eval. */ if( PEISCLASS( a ) ) action_proc_class_binary( rc, compile, op, name, a, b, out ); else if( PEISBOOL( a ) ) { if( op == BI_LOR && PEGETBOOL( a ) ) { if( trace_flags & TRACE_OPERATOR ) trace_binop( compile, a, op, b ); PEPUTP( out, ELEMENT_BOOL, TRUE ); if( trace_flags & TRACE_OPERATOR ) trace_result( TRACE_OPERATOR, out ); } else if( op == BI_LAND && !PEGETBOOL( a ) ) { if( trace_flags & TRACE_OPERATOR ) trace_binop( compile, a, op, b ); PEPUTP( out, ELEMENT_BOOL, FALSE ); if( trace_flags & TRACE_OPERATOR ) trace_result( TRACE_OPERATOR, out ); } else { /* Need to look at RHS too. */ reduce_spine( rc, b ); if( PEISCOMB( b ) && PEGETCOMB( b ) != COMB_I ) { if( trace_flags & TRACE_OPERATOR ) trace_pop(); return; } if( PEISCLASS( b ) ) action_proc_class_binary2( rc, compile, op, name, a, b, out ); else if( PEISBOOL( b ) ) { if( trace_flags & TRACE_OPERATOR ) trace_binop( compile, a, op, b ); PEPUTP( out, ELEMENT_BOOL, PEGETBOOL( b ) ); if( trace_flags & TRACE_OPERATOR ) trace_result( TRACE_OPERATOR, out ); } else action_boperror( rc, compile, NULL, op, name, a, b ); } } else action_boperror( rc, compile, NULL, op, name, a, b ); if( trace_flags & TRACE_OPERATOR ) trace_pop(); } static void action_if( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *b, PElement *out ) { reduce_spine( rc, a ); if( PEISCOMB( a ) && PEGETCOMB( a ) == COMB_I ) /* The reduce_spine() did us recursively ... bounce back. */ return; if( PEISCLASS( a ) ) action_proc_class_binary( rc, compile, op, name, a, b, out ); else { PElement t, e; /* a is condition, b should be [then-part, else-part] ... * look down b and find them. Block trace for this, not very * interesting. */ trace_block(); reduce_list_index( rc, b, 0, &t ); reduce_list_index( rc, b, 1, &e ); trace_unblock(); /* Can be BOOL or image. */ if( PEISBOOL( a ) ) { if( trace_flags & TRACE_OPERATOR ) { VipsBuf *buf = trace_push(); vips_buf_appendf( buf, "if " ); trace_pelement( a ); vips_buf_appendf( buf, " then " ); trace_pelement( &t ); vips_buf_appendf( buf, " else " ); trace_pelement( &e ); vips_buf_appendf( buf, " ->\n" ); } if( PEGETBOOL( a ) ) { PEPUTPE( out, &t ); } else { PEPUTPE( out, &e ); } if( trace_flags & TRACE_OPERATOR ) { trace_result( TRACE_OPERATOR, out ); trace_pop(); } } else if( PEISIMAGE( a ) ) { reduce_spine_strict( rc, &t ); reduce_spine_strict( rc, &e ); /* then/else parts must both be image. */ if( !PEISIMAGE( &t ) || !PEISIMAGE( &e ) ) action_boperror( rc, compile, NULL, op, name, a, b ); callva( rc, out, "im_ifthenelse", PEGETII( a ), PEGETII( &t ), PEGETII( &e ) ); } else action_boperror( rc, compile, NULL, op, name, a, b ); } } /* Do a binary operator. Result in arg[0]. */ void action_proc_bop( Reduce *rc, Compile *compile, BinOp bop, HeapNode **arg ) { PElement a, b, out; switch( bop ) { case BI_LAND: case BI_LOR: /* Special ninja magic :-( we need to handle reduce carefully * here. */ PEPOINTRIGHT( arg[0], &b ); PEPOINTRIGHT( arg[1], &a ); PEPOINTRIGHT( arg[0], &out ); action_landlor( rc, compile, bop, OPERATOR_NAME( bop ), &a, &b, &out ); /* Overwrite arg[0] with I node, in case this is a * shared node. */ PPUTLEFT( arg[0], ELEMENT_COMB, COMB_I ); break; case BI_IF: /* If is lazy-ish in it's 2nd argument too. */ PEPOINTRIGHT( arg[0], &b ); PEPOINTRIGHT( arg[1], &a ); PEPOINTRIGHT( arg[0], &out ); action_if( rc, compile, bop, OPERATOR_NAME( bop ), &a, &b, &out ); /* Overwrite arg[0] with I node, in case this is a * shared node. */ PPUTLEFT( arg[0], ELEMENT_COMB, COMB_I ); break; case BI_DOT: case BI_PEQ: case BI_PNOTEQ: /* Strict, not overrideable. */ action_dispatch( rc, compile, reduce_spine, bop, OPERATOR_NAME( bop ), FALSE, (ActionFn) action_proc_bop_strict, 2, arg, NULL ); break; default: /* Strict, overrideable. */ action_dispatch( rc, compile, reduce_spine, bop, OPERATOR_NAME( bop ), TRUE, (ActionFn) action_proc_bop_strict, 2, arg, NULL ); } } static void * action_proc_class_unary_sub( Reduce *rc, PElement *pe, PElement *fn, const char *name, PElement *out ) { PElement rhs; PElement base; base = *pe; heap_appl_init( &base, fn ); if( !heap_appl_add( rc->heap, &base, &rhs ) || !heap_managedstring_new( rc->heap, name, &rhs ) ) return( out ); PEPUTPE( out, pe ); return( NULL ); } static void action_proc_class_unary( Reduce *rc, Compile *compile, int op, const char *name, PElement *a, PElement *out ) { TraceFlags flags = op >= 0 ? TRACE_OPERATOR : TRACE_BUILTIN; PElement fn; if( trace_flags & flags ) { VipsBuf *buf = trace_push(); vips_buf_appendf( buf, "%s\n", _( "invoking method:" ) ); vips_buf_appends( buf, " " ); trace_pelement( a ); vips_buf_appendf( buf, ".%s \"%s\"\n", MEMBER_OO_UNARY, name ); trace_text( flags, "%s", vips_buf_all( buf ) ); trace_pop(); } /* Look up a.dispatch_unary and build * (a.oo_unary "minus") application. */ if( !class_get_member( a, MEMBER_OO_UNARY, NULL, &fn ) ) action_uoperror( rc, compile, error_get_sub(), op, name, a ); if( reduce_safe_pointer( rc, (reduce_safe_pointer_fn) action_proc_class_unary_sub, &fn, (void *) name, out, NULL ) ) action_uoperror( rc, compile, error_get_sub(), op, name, a ); } /* Run a function on the graph ... eval all the args, avoid eval if we reduce * ourselves as a side effect (happens on recursive calls). Result in RHS of * arg[0]. */ void action_dispatch( Reduce *rc, Compile *compile, ReduceFunction rfn, int op, const char *name, gboolean override, ActionFn afn, int nargs, HeapNode **arg, void *user ) { TraceFlags flags = op >= 0 ? TRACE_OPERATOR : TRACE_BUILTIN; PElement a, b; int i; /* Don't allow nargs == 0. We rely on having a bit of graph we can * replace with (I result) for caching. */ g_assert( nargs > 0 ); /* We need to have the */ g_assert( noperator_table == UN_LAST ); /* Reduce all the args. */ for( i = 0; i < nargs; i++ ) { PElement rhs; PEPOINTRIGHT( arg[i], &rhs ); rfn( rc, &rhs ); } /* We may have evaled ourselves already. */ PEPOINTLEFT( arg[0], &b ); if( PEISCOMB( &b ) && PEGETCOMB( &b ) == COMB_I ) return; PEPOINTRIGHT( arg[0], &b ); PEPOINTRIGHT( arg[1], &a ); if( trace_flags & flags ) { VipsBuf *buf = trace_push(); vips_buf_appendf( buf, "\"%s\" ", name ); trace_args( arg, nargs ); } if( override && nargs == 2 && PEISCLASS( &a ) ) action_proc_class_binary( rc, compile, op, name, &a, &b, &b ); else if( override && nargs == 2 && PEISCLASS( &b ) ) action_proc_class_binary2( rc, compile, op, name, &a, &b, &b ); else if( override && nargs == 1 && PEISCLASS( &b ) ) action_proc_class_unary( rc, compile, op, name, &b, &b ); else afn( rc, compile, op, name, arg, &b, user ); PPUTLEFT( arg[0], ELEMENT_COMB, COMB_I ); if( trace_flags & flags ) { trace_result( flags, &b ); trace_pop(); } } nip2-8.7.1/src/column.h0000644000175000017500000000530613351443023011557 00000000000000/* a column in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_COLUMN (column_get_type()) #define COLUMN( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_COLUMN, Column )) #define COLUMN_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_COLUMN, ColumnClass)) #define IS_COLUMN( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_COLUMN )) #define IS_COLUMN_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_COLUMN )) #define COLUMN_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_COLUMN, ColumnClass )) struct _Column { Filemodel parent_object; /* Our context. */ Subcolumn *scol; /* Subcolumn we enclose */ Workspace *ws; /* Enclosing workspace */ /* Appearance state info. */ int x, y; /* Position */ gboolean open; /* Currently popped down */ gboolean selected; /* Other state. */ int next; /* Index of next symbol we make */ Row *last_select; /* Last row clicked ... for x sel */ /* A pending scrollto. */ guint scrollto_timeout; ModelScrollPosition pending_position; }; typedef struct _ColumnClass { FilemodelClass parent_class; /* My methods. */ } ColumnClass; void *column_map( Column *col, row_map_fn fn, void *a, void *b ); void *column_map_symbol( Column *col, symbol_map_fn fn, void *a ); void *column_select_symbols( Column *col ); GtkType column_get_type( void ); Column *column_new( Workspace *ws, const char *name ); Column *column_get_last_new( void ); void column_clear_last_new( void ); Row *column_get_bottom( Column *col ); gboolean column_add_n_names( Column *col, const char *name, VipsBuf *buf, int nparam ); gboolean column_is_empty( Column *col ); void column_set_offset( int x_off, int y_off ); char *column_name_new( Column *col ); void column_set_open( Column *col, gboolean open ); void column_scrollto( Column *col, ModelScrollPosition position ); nip2-8.7.1/src/iregiongroup.h0000644000175000017500000000335013351443023012770 00000000000000/* base model for a client regions on an imageview */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IREGIONGROUP (iregiongroup_get_type()) #define IREGIONGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IREGIONGROUP, iRegiongroup )) #define IREGIONGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_IREGIONGROUP, iRegiongroupClass)) #define IS_IREGIONGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IREGIONGROUP )) #define IS_IREGIONGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IREGIONGROUP )) #define IREGIONGROUP_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_IREGIONGROUP, iRegiongroupClass )) struct _iRegiongroup { Classmodel parent_class; }; typedef struct _iRegiongroupClass { ClassmodelClass parent_class; /* My methods. */ } iRegiongroupClass; GType iregiongroup_get_type( void ); iRegiongroup *iregiongroup_new( Classmodel *classmodel ); nip2-8.7.1/src/toolkitgroupview.h0000644000175000017500000000342313351443023013715 00000000000000/* a view of a toolkitgroup */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TOOLKITGROUPVIEW (toolkitgroupview_get_type()) #define TOOLKITGROUPVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_TOOLKITGROUPVIEW, Toolkitgroupview )) #define TOOLKITGROUPVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_TOOLKITGROUPVIEW, \ ToolkitgroupviewClass )) #define IS_TOOLKITGROUPVIEW( obj ) \ (GTK_CHECK_TYPE( (obj), TYPE_TOOLKITGROUPVIEW )) #define IS_TOOLKITGROUPVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKITGROUPVIEW )) struct _Toolkitgroupview { View parent_class; GtkWidget *menu; /* Display the toolkits in this */ Mainw *mainw; /* Mainw these menu items act on */ }; typedef struct _ToolkitgroupviewClass { ViewClass parent_class; /* My methods. */ } ToolkitgroupviewClass; GtkType toolkitgroupview_get_type( void ); View *toolkitgroupview_new( void ); void toolkitgroupview_set_mainw( Toolkitgroupview *kitgview, Mainw *mainw ); nip2-8.7.1/src/vobject.c0000644000175000017500000001731113351443023011710 00000000000000/* abstract base class for a vobject object ... watch an iobject and call * _refresh in idle if it changes. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Time each refresh #define DEBUG_TIME */ #include "ip.h" static GtkVBoxClass *parent_class = NULL; static Queue *vobject_dirty = NULL; static gint vobject_refresh_timeout = 0; /* Remove from refresh queue. */ static void vobject_refresh_dequeue( vObject *vobject ) { if( vobject->dirty ) { #ifdef DEBUG printf( "vobject_refresh_dequeue: \"%s\"\n", G_OBJECT_TYPE_NAME( vobject ) ); #endif /*DEBUG*/ vobject->dirty = FALSE; queue_remove( vobject_dirty, vobject ); } } #ifdef DEBUG_TIME /* Refresh all vobjects at once and time them. */ static gboolean vobject_refresh_timeout_cb( gpointer user_data ) { static GTimer *refresh_timer = NULL; double last_elapsed; double worst_time = 0.0; int worst_index = -1; void *data; int n; vobject_refresh_timeout = 0; if( !refresh_timer ) refresh_timer = g_timer_new(); g_timer_reset( refresh_timer ); printf( "vobject_idle_refresh: starting ...\n" ); for( n = 0; (data = queue_head( vobject_dirty )); n++ ) { vObject *vobject = VOBJECT( data ); double elapsed; vobject->dirty = FALSE; vobject_refresh( vobject ); elapsed = g_timer_elapsed( refresh_timer, NULL ); if( elapsed - last_elapsed > worst_time ) { worst_time = elapsed - last_elapsed; worst_index = n; } last_elapsed = elapsed; } printf( "vobject_idle_refresh: done after %gs (%d refreshes)\n", g_timer_elapsed( refresh_timer, NULL ), n ); printf( "vobject_idle_refresh: worst %gs (refresh %d)\n", worst_time, worst_index ); return( FALSE ); } #else /*DEBUG_TIME*/ /* Refresh stuff off the dirty list. */ static gboolean vobject_refresh_timeout_cb( gpointer user_data ) { void *data; #ifdef DEBUG printf( "vobject_refresh_timeout_cb:\n" ); #endif /*DEBUG*/ vobject_refresh_timeout = 0; while( (data = queue_head( vobject_dirty ) ) ) { vObject *vobject = VOBJECT( data ); #ifdef DEBUG printf( "vobject_refresh_timeout_cb: starting \"%s\" (%p)\n", G_OBJECT_TYPE_NAME( vobject ), vobject ); #endif /*DEBUG*/ /* We must clear dirty before we _refresh() so that if the * _refresh() indirectly triggers another update, we will * _refresh() again. */ vobject->dirty = FALSE; vobject_refresh( vobject ); } return( FALSE ); } #endif /*DEBUG_TIME*/ /* Mark something for refresh. Seldom call this directly ... just change the * iobject and all vobjects will have a refresh queued. */ void * vobject_refresh_queue( vObject *vobject ) { if( !vobject->dirty ) { #ifdef DEBUG printf( "vobject_refresh_queue: %s (%p)", G_OBJECT_TYPE_NAME( vobject ), vobject ); if( vobject->iobject ) printf( ", iobject %s \"%s\"", G_OBJECT_TYPE_NAME( vobject->iobject ), NN( vobject->iobject->name ) ); printf( "\n" ); #endif /*DEBUG*/ vobject->dirty = TRUE; queue_add( vobject_dirty, vobject ); IM_FREEF( g_source_remove, vobject_refresh_timeout ); vobject_refresh_timeout = g_timeout_add( 20, (GSourceFunc) vobject_refresh_timeout_cb, NULL ); } return( NULL ); } /* Called for iobject changed signal ... queue a refresh. */ static void vobject_iobject_changed( iObject *iobject, vObject *vobject ) { #ifdef DEBUG printf( "vobject_iobject_changed: %s %s \"%s\"\n", G_OBJECT_TYPE_NAME( vobject ), G_OBJECT_TYPE_NAME( iobject ), NN( iobject->name ) ); #endif /*DEBUG*/ vobject_refresh_queue( vobject ); } /* Called for iobject destroy signal ... kill the vobject too. */ static void vobject_iobject_destroy( iObject *iobject, vObject *vobject ) { #ifdef DEBUG printf( "vobject_iobject_destroy: iobject %s \"%s\"\n", G_OBJECT_TYPE_NAME( iobject ), NN( iobject->name ) ); #endif /*DEBUG*/ gtk_widget_destroy( GTK_WIDGET( vobject ) ); } /* Link to iobject. */ void vobject_link( vObject *vobject, iObject *iobject ) { vObjectClass *vobject_class = VOBJECT_GET_CLASS( vobject ); g_assert( !vobject->iobject ); if( vobject_class->link ) vobject_class->link( vobject, iobject ); /* Queue a refresh ... we always need at least one. */ vobject_refresh_queue( vobject ); } static void vobject_destroy( GtkObject *object ) { vObject *vobject; g_return_if_fail( object != NULL ); g_return_if_fail( IS_VOBJECT( object ) ); vobject = VOBJECT( object ); #ifdef DEBUG printf( "vobject_destroy: \"%s\"\n", G_OBJECT_TYPE_NAME( object ) ); #endif /*DEBUG*/ if( vobject->iobject ) { FREESID( vobject->changed_sid, vobject->iobject ); FREESID( vobject->destroy_sid, vobject->iobject ); vobject->iobject = NULL; } vobject_refresh_dequeue( vobject ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void vobject_finalize( GObject *gobject ) { #ifdef DEBUG printf( "vobject_finalize: \"%s\"\n", G_OBJECT_TYPE_NAME( gobject ) ); #endif /*DEBUG*/ G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void vobject_real_refresh( vObject *vobject ) { #ifdef DEBUG printf( "vobject_real_refresh: %p %s\n", vobject, G_OBJECT_TYPE_NAME( vobject ) ); #endif /*DEBUG*/ } static void vobject_real_link( vObject *vobject, iObject *iobject ) { vobject->iobject = iobject; vobject->changed_sid = g_signal_connect( iobject, "changed", G_CALLBACK( vobject_iobject_changed ), vobject ); vobject->destroy_sid = g_signal_connect( iobject, "destroy", G_CALLBACK( vobject_iobject_destroy ), vobject ); } static void vobject_class_init( vObjectClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); GtkObjectClass *object_class = (GtkObjectClass*) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = vobject_finalize; object_class->destroy = vobject_destroy; /* Create signals. */ /* Init default methods. */ class->refresh = vobject_real_refresh; class->link = vobject_real_link; /* Static init. */ vobject_dirty = queue_new(); } static void vobject_init( vObject *vobject ) { /* Init our instance fields. */ vobject->iobject = NULL; vobject->changed_sid = 0; vobject->destroy_sid = 0; vobject->dirty = FALSE; /* All new vobjects will need refreshing. */ vobject_refresh_queue( vobject ); } GtkType vobject_get_type( void ) { static GtkType vobject_type = 0; if( !vobject_type ) { static const GtkTypeInfo vobject_info = { "vObject", sizeof( vObject ), sizeof( vObjectClass ), (GtkClassInitFunc) vobject_class_init, (GtkObjectInitFunc) vobject_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; vobject_type = gtk_type_unique( GTK_TYPE_VBOX, &vobject_info ); } return( vobject_type ); } /* Trigger the refresh method for a vobject immediately ... we usually queue * and wait for idle, but this can be better for interactive stuff. */ void * vobject_refresh( vObject *vobject ) { vObjectClass *vobject_class = VOBJECT_GET_CLASS( vobject ); if( vobject_class->refresh ) vobject_class->refresh( vobject ); return( NULL ); } nip2-8.7.1/src/cache.h0000644000175000017500000000213413351443023011321 00000000000000/* Call vips functions from the graph reducer. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ extern int cache_history_size; void cache_tochar_trace( CallInfo *vi, int i, VipsBuf *buf ); void cache_history_remove( CallInfo *vi ); CallInfo *cache_dispatch( CallInfo *vi, PElement *out ); nip2-8.7.1/src/columnview.c0000644000175000017500000010062313351443023012443 00000000000000/* a view of a column */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; /* The columnview popup menu. */ static GtkWidget *columnview_menu = NULL; /* Edit caption ... right button menu on title bar. */ static void columnview_caption_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview ) { /* Edit caption! */ if( cview->state == COL_EDIT ) return; cview->state = COL_EDIT; vobject_refresh_queue( VOBJECT( cview ) ); } /* Select all objects in menu's column. */ static void columnview_select_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); Workspace *ws = col->ws; workspace_deselect_all( ws ); column_select_symbols( col ); } /* Clone a column. */ static void columnview_clone_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); Workspace *ws = col->ws; char new_name[MAX_STRSIZE]; Column *newcol; workspace_column_name_new( ws, new_name ); newcol = workspace_column_get( ws, new_name ); iobject_set( IOBJECT( newcol ), NULL, IOBJECT( col )->caption ); newcol->x = col->x + 100; newcol->y = col->y; workspace_deselect_all( ws ); column_select_symbols( col ); workspace_column_select( ws, newcol ); if( !workspace_selected_duplicate( ws ) ) iwindow_alert( GTK_WIDGET( cview ), GTK_MESSAGE_ERROR ); workspace_deselect_all( ws ); symbol_recalculate_all(); } static void columnview_merge_sub( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Column *col = COLUMN( client ); Workspace *ws = col->ws; Workspacegroup *wsg = workspace_get_workspacegroup( ws ); char *filename; iWindowResult result; result = IWINDOW_YES; progress_begin(); if( (filename = filesel_get_filename( filesel )) ) { if( !workspacegroup_merge_rows( wsg, filename ) ) result = IWINDOW_ERROR; g_free( filename ); } symbol_recalculate_all(); progress_end(); nfn( sys, result ); } static void columnview_merge_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); iWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( cview ) ) ); GtkWidget *filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Merge Into Column \"%s\"" ), IOBJECT( col )->name ); filesel_set_flags( FILESEL( filesel ), FALSE, FALSE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) ); idialog_set_iobject( IDIALOG( filesel ), IOBJECT( col ) ); filesel_set_done( FILESEL( filesel ), columnview_merge_sub, col ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } /* Callback from save browser. */ static void columnview_save_as_sub( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Column *col = COLUMN( client ); Workspace *ws = col->ws; char *filename; workspace_deselect_all( ws ); column_select_symbols( col ); if( (filename = filesel_get_filename( filesel )) ) { if( workspace_selected_save( ws, filename ) ) { workspace_deselect_all( ws ); nfn( sys, IWINDOW_YES ); } else nfn( sys, IWINDOW_ERROR ); g_free( filename ); } else nfn( sys, IWINDOW_ERROR ); } /* Save a column ... can't just do view_save_as_cb(), since we need to save * the enclosing workspace too. Hence we have to save_selected on the ws, but * only after we have the filename. */ static void columnview_save_as_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); iWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( cview ) ) ); GtkWidget *filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Save Column \"%s\"" ), IOBJECT( col )->name ); filesel_set_flags( FILESEL( filesel ), FALSE, TRUE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) ); idialog_set_iobject( IDIALOG( filesel ), IOBJECT( col ) ); filesel_set_done( FILESEL( filesel ), columnview_save_as_sub, col ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } /* Make a name for a column menu file, based on what we're going to call the * menu item. */ static void columnview_filename( char *file, const char *caption ) { int i; char name[FILENAME_MAX]; im_strncpy( name, caption, 10 ); for( i = 0; i < strlen( name ); i++ ) if( name[i] == ' ' ) name[i] = '_'; for( i = 0; ; i++ ) { im_snprintf( file, FILENAME_MAX, "$SAVEDIR" G_DIR_SEPARATOR_S "data" G_DIR_SEPARATOR_S "%s-%d.ws", name, i ); if( !existsf( "%s", file ) ) break; } } /* Remember the name of the last toolkit the user asked to add to. */ static char *columnview_to_menu_last_toolkit = NULL; /* Done button hit. */ static void columnview_to_menu_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Column *col = COLUMN( client ); Workspace *ws = col->ws; Stringset *ss = STRINGSET( iwnd ); StringsetChild *name = stringset_child_get( ss, _( "Name" ) ); StringsetChild *toolkit = stringset_child_get( ss, _( "Toolkit" ) ); StringsetChild *file = stringset_child_get( ss, _( "Filename" ) ); char name_text[1024]; char toolkit_text[1024]; char file_text[1024]; if( !get_geditable_string( name->entry, name_text, 1024 ) || !get_geditable_name( toolkit->entry, toolkit_text, 1024 ) || !get_geditable_filename( file->entry, file_text, 1024 ) ) { nfn( sys, IWINDOW_ERROR ); return; } /* Save column to file. */ workspace_deselect_all( ws ); column_select_symbols( col ); if( !workspace_selected_save( ws, file_text ) ) { nfn( sys, IWINDOW_ERROR ); return; } workspace_deselect_all( ws ); if( !tool_new_dia( toolkit_by_name( ws->kitg, toolkit_text ), -1, name_text, file_text ) ) { unlinkf( "%s", file_text ); nfn( sys, IWINDOW_ERROR ); return; } IM_SETSTR( columnview_to_menu_last_toolkit, toolkit_text ); nfn( sys, IWINDOW_YES ); } /* Make a column into a menu item. */ static void columnview_to_menu_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); iWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( cview ) ) ); GtkWidget *ss = stringset_new(); char *name; char *kit_name; char filename[FILENAME_MAX]; if( !(name = IOBJECT( col )->caption) ) name = "untitled"; columnview_filename( filename, name ); if( columnview_to_menu_last_toolkit ) kit_name = columnview_to_menu_last_toolkit; else kit_name = "untitled"; stringset_child_new( STRINGSET( ss ), _( "Name" ), name, _( "Set menu item text here" ) ); stringset_child_new( STRINGSET( ss ), _( "Toolkit" ), kit_name, _( "Add to this toolkit" ) ); stringset_child_new( STRINGSET( ss ), _( "Filename" ), filename, _( "Store column in this file" ) ); iwindow_set_title( IWINDOW( ss ), _( "New Menu Item from Column \"%s\"" ), IOBJECT( col )->name ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, col ); idialog_set_help_tag( IDIALOG( ss ), "sec:diaref" ); idialog_add_ok( IDIALOG( ss ), columnview_to_menu_done_cb, _( "Menuize" ) ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( iwnd ) ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); } /* Find the position and size of a columnview. */ void columnview_get_position( Columnview *cview, int *x, int *y, int *w, int *h ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); if( GTK_WIDGET( cview )->allocation.x < 2 || GTK_WIDGET( cview )->allocation.y < 2 ) { /* Nothing there yet, guess. */ *x = col->x; *y = col->y; *w = 200; *h = 50; } else { *x = GTK_WIDGET( cview )->allocation.x; *y = GTK_WIDGET( cview )->allocation.y; *w = GTK_WIDGET( cview )->allocation.width; *h = GTK_WIDGET( cview )->allocation.height; #ifdef DEBUG printf( "columnview_get_position: %s, " "x = %d, y = %d, w = %d, h = %d\n", IOBJECT( col )->name, *x, *y, *w, *h ); #endif /*DEBUG*/ } } /* Transition functions for mouse stuff on columnviews. */ static void columnview_left_press( Columnview *cview, GdkEvent *ev ) { Workspaceview *wview = cview->wview; int ix, iy; int jx, jy; int kx, ky; int wx, wy, ww, wh; #ifdef DEBUG printf( "columnview_left_press\n" ); #endif /*DEBUG*/ /* Find pos of columnview. */ columnview_get_position( cview, &wx, &wy, &ww, &wh ); /* Position in virtual tally window. */ ix = ev->button.x + wx; iy = ev->button.y + wy; /* Position in tally viewport. */ jx = ix - wview->vp.left; jy = iy - wview->vp.top; /* So ... position of top LH corner of tally viewport in root window. */ kx = ev->button.x_root - jx; ky = ev->button.y_root - jy; switch( cview->state ) { case COL_WAIT: cview->state = COL_SELECT; /* Record offset of mouse in columnview title bar. */ cview->rx = ev->button.x; cview->ry = ev->button.y; /* Position of tally window in root window. */ cview->tx = kx; cview->ty = ky; /* Start position of mouse in virtual tally window. */ cview->sx = ix; cview->sy = iy; break; case COL_SELECT: case COL_DRAG: case COL_EDIT: break; default: g_assert( FALSE ); } } static void columnview_add_shadow( Columnview *old_cview ) { Column *col = COLUMN( VOBJECT( old_cview )->iobject ); Workspaceview *wview = old_cview->wview; if( !old_cview->shadow ) { Columnview *new_cview; new_cview = COLUMNVIEW( columnview_new() ); new_cview->wview = wview; VIEW( new_cview )->parent = VIEW( wview ); VOBJECT( new_cview )->iobject = IOBJECT( col ); gtk_fixed_put( GTK_FIXED( wview->fixed ), GTK_WIDGET( new_cview ), col->x, col->y ); gtk_widget_show( GTK_WIDGET( new_cview ) ); old_cview->shadow = new_cview; new_cview->master = old_cview; /* The shadow will be on top of the real column and hide it. * Put the real column to the front. */ model_front( MODEL( col ) ); } } static void columnview_left_motion( Columnview *cview, GdkEvent *ev ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); Workspace *ws = col->ws; Workspaceview *wview = cview->wview; int u, v; /* Posn of pointer in tally viewport. */ int ix = ev->motion.x_root - cview->tx; int iy = ev->motion.y_root - cview->ty; /* Posn in virtual tally cods. */ int jx = ix + wview->vp.left; int jy = iy + wview->vp.top; /* Amount of drag since we started. */ int xoff = jx - cview->sx; int yoff = jy - cview->sy; /* New columnview position. */ int xnew = IM_MAX( 0, jx - cview->rx ); int ynew = IM_MAX( 0, jy - cview->ry ); #ifdef DEBUG printf( "columnview_left_motion\n" ); #endif /*DEBUG*/ switch( cview->state ) { case COL_EDIT: case COL_WAIT: break; case COL_SELECT: /* How much drag? */ if( abs( xoff ) > 5 || abs( yoff ) > 5 ) { cview->state = COL_DRAG; workspaceview_set_cursor( wview, IWINDOW_SHAPE_MOVE ); gtk_grab_add( cview->title ); columnview_add_shadow( cview ); } break; case COL_DRAG: col->x = xnew; col->y = ynew; iobject_changed( IOBJECT( col ) ); #ifdef DEBUG printf( "drag columnview: x=%d, y=%d", col->x, col->y ); #endif /*DEBUG*/ /* Set vars for bg scroll. */ u = 0; if( ix > wview->vp.width ) u = 10; else if( ix < 0 ) u = -10; v = 0; if( iy > wview->vp.height ) v = 10; else if( iy < 0 ) v = -10; workspaceview_scroll_background( wview, u, v ); /* Move other columns about. */ model_layout( MODEL( ws ) ); break; default: g_assert( FALSE ); } } static void columnview_left_release( Columnview *cview, GdkEvent *ev ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); Workspace *ws = col->ws; Workspaceview *wview = cview->wview; #ifdef DEBUG printf( "columnview_left_release\n" ); #endif /*DEBUG*/ /* Back to wait. */ switch( cview->state ) { case COL_SELECT: cview->state = COL_WAIT; workspace_column_select( ws, col ); break; case COL_DRAG: cview->state = COL_WAIT; workspaceview_scroll_background( wview, 0, 0 ); workspaceview_set_cursor( wview, IWINDOW_SHAPE_NONE ); gtk_grab_remove( cview->title ); DESTROY_GTK( cview->shadow ); /* Move columns to their final position. */ model_layout( MODEL( ws ) ); workspace_set_modified( ws, TRUE ); break; case COL_EDIT: case COL_WAIT: break; default: g_assert( FALSE ); } } /* Event in columnview title bar. */ static gboolean columnview_title_event_cb( GtkWidget *widget, GdkEvent *ev, Columnview *cview ) { gboolean handled = FALSE; #ifdef DEBUG { Column *col = COLUMN( VOBJECT( cview )->iobject ); printf( "columnview_title_event_cb: %s %d\n", IOBJECT( col )->name, ev->type ); } #endif /*DEBUG*/ switch( ev->type ) { case GDK_BUTTON_PRESS: if( ev->button.button == 1 ) { columnview_left_press( cview, ev ); handled = TRUE; } break; case GDK_2BUTTON_PRESS: if( ev->button.button == 1 ) { if( cview->state != COL_EDIT ) { cview->state = COL_EDIT; vobject_refresh_queue( VOBJECT( cview ) ); } handled = TRUE; } break; case GDK_MOTION_NOTIFY: if( ev->motion.state & GDK_BUTTON1_MASK ) { columnview_left_motion( cview, ev ); handled = TRUE; } break; case GDK_BUTTON_RELEASE: if( ev->button.button == 1 ) { columnview_left_release( cview, ev ); handled = TRUE; } break; default: break; } return( handled ); } static void columnview_destroy( GtkObject *object ) { Columnview *cview; Column *col; g_return_if_fail( object != NULL ); g_return_if_fail( IS_COLUMNVIEW( object ) ); cview = COLUMNVIEW( object ); col = COLUMN( VOBJECT( cview )->iobject ); #ifdef DEBUG printf( "columnview_destroy:\n" ); #endif /*DEBUG*/ DESTROY_GTK( cview->shadow ); /* The column has gone .. relayout. */ if( col && col->ws ) { workspace_set_needs_layout( col->ws, TRUE ); mainw_layout(); } GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void columnview_size_allocate( GtkWidget *widget, GtkAllocation *allocation ) { Columnview *cview = COLUMNVIEW( widget ); if( cview->old_width != allocation->width || cview->old_height != allocation->height ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); Workspace *ws = col->ws; cview->old_width = allocation->width; cview->old_height = allocation->height; workspace_set_needs_layout( ws, TRUE ); mainw_layout(); } GTK_WIDGET_CLASS( parent_class )->size_allocate( widget, allocation ); } /* Arrow button on title bar. */ static void columnview_updown_cb( GtkWidget *wid, Columnview *cview ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); column_set_open( col, !col->open ); } /* Delete this column from the popup menu. */ static void columnview_destroy_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); model_check_destroy( view_get_toplevel( VIEW( cview ) ), MODEL( col ), NULL ); } /* Delete this column with a click on the 'x' button. */ static void columnview_destroy2_cb( GtkWidget *wid, Columnview *cview ) { Column *col = COLUMN( VOBJECT( cview )->iobject ); model_check_destroy( view_get_toplevel( VIEW( cview ) ), MODEL( col ), NULL ); } /* Callback for enter in caption edit box. */ static void columnview_caption_enter_cb( GtkWidget *wid, Columnview *cview ) { const char *text = gtk_entry_get_text( GTK_ENTRY( cview->capedit ) ); Column *col = COLUMN( VOBJECT( cview )->iobject ); Workspace *ws = col->ws; cview->state = COL_WAIT; iobject_changed( IOBJECT( col ) ); if( strcmp( text, "" ) != 0 ) iobject_set( IOBJECT( col ), NULL, text ); workspace_set_modified( ws, TRUE ); /* The ws view needs to update the jumpto menus. */ iobject_changed( IOBJECT( ws ) ); } /* Detect cancel in a caption field. */ static gboolean columnview_caption_cancel_cb( GtkWidget *widget, GdkEvent *ev, Columnview *cview ) { if( ev->type != GDK_KEY_PRESS || ev->key.keyval != GDK_Escape ) return( FALSE ); /* Turn off edit. */ cview->state = COL_WAIT; vobject_refresh_queue( VOBJECT( cview ) ); return( TRUE ); } /* Add a caption entry to a columnview if not there. */ static void columnview_add_caption( Columnview *cview ) { if( cview->capedit ) return; cview->capedit = gtk_entry_new(); gtk_entry_set_has_frame( GTK_ENTRY( cview->capedit ), FALSE ); gtk_box_pack_start( GTK_BOX( cview->titlehb ), cview->capedit, FALSE, FALSE, 0 ); set_tooltip( cview->capedit, _( "Edit caption, press enter to " "accept changes, press escape to cancel" ) ); gtk_signal_connect( GTK_OBJECT( cview->capedit ), "activate", GTK_SIGNAL_FUNC( columnview_caption_enter_cb ), cview ); gtk_signal_connect( GTK_OBJECT( cview->capedit ), "event", GTK_SIGNAL_FUNC( columnview_caption_cancel_cb ), cview ); } /* Callback for enter in new def widget. */ static void columnview_text_enter_cb( GtkWidget *wid, Columnview *cview ) { const char *text = gtk_entry_get_text( GTK_ENTRY( cview->text ) ); Column *col = COLUMN( VOBJECT( cview )->iobject ); Workspace *ws = col->ws; Symbol *sym; if( !text || strspn( text, WHITESPACE ) == strlen( text ) ) return; if( !(sym = workspace_add_def_recalc( ws, text )) ) { iwindow_alert( wid, GTK_MESSAGE_ERROR ); symbol_recalculate_all(); return; } set_gentry( cview->text, NULL ); } /* Add bottom entry widget. */ static void columnview_add_text( Columnview *cview ) { GtkWidget *inv; if( cview->textfr ) return; cview->textfr = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_end( GTK_BOX( cview->vbox ), cview->textfr, FALSE, FALSE, 0 ); inv = gtk_label_new( "" ); gtk_box_pack_start( GTK_BOX( cview->textfr ), inv, FALSE, FALSE, 25 ); gtk_widget_show( inv ); cview->text = gtk_entry_new(); gtk_box_pack_start( GTK_BOX( cview->textfr ), cview->text, TRUE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT( cview->text ), "activate", GTK_SIGNAL_FUNC( columnview_text_enter_cb ), cview ); gtk_widget_show( cview->text ); set_tooltip( cview->text, _( "Enter expressions here" ) ); } static void columnview_refresh( vObject *vobject ) { Columnview *cview = COLUMNVIEW( vobject ); Columnview *shadow = cview->shadow; Column *col = COLUMN( VOBJECT( cview )->iobject ); gboolean editable = col->ws->mode != WORKSPACE_MODE_NOEDIT; #ifdef DEBUG printf( "columnview_refresh: %s\n", IOBJECT( col )->name ); #endif /*DEBUG*/ /* If this column has a shadow, workspaceview will have put a layout * position into it. See workspaceview_layout_set_pos(). */ if( shadow ) view_child_position( VIEW( shadow ) ); if( shadow ) { gtk_widget_set_size_request( GTK_WIDGET( shadow->frame ), GTK_WIDGET( cview->frame )->allocation.width, GTK_WIDGET( cview->frame )->allocation.height ); gtk_frame_set_shadow_type( GTK_FRAME( shadow->frame ), GTK_SHADOW_IN ); } if( col->x != cview->lx || col->y != cview->ly ) { #ifdef DEBUG printf( "columnview_refresh: move column %s to %d x %d\n", IOBJECT( col )->name, col->x, col->y ); #endif /*DEBUG*/ cview->lx = col->x; cview->ly = col->y; view_child_position( VIEW( cview ) ); /* Update the save offset hints too. */ filemodel_set_offset( FILEMODEL( col ), cview->lx, cview->ly ); } /* Turn titlebar on/off. */ widget_visible( cview->title, editable ); if( editable ) gtk_frame_set_label( GTK_FRAME( cview->frame ), NULL ); else if( IOBJECT( col )->caption ) { GtkWidget *label; char buf[256]; char buf2[256]; gtk_frame_set_label( GTK_FRAME( cview->frame ), "x" ); label = gtk_frame_get_label_widget( GTK_FRAME( cview->frame ) ); escape_markup( IOBJECT( col )->caption, buf2, 256 ); im_snprintf( buf, 256, "%s", buf2 ); gtk_label_set_markup( GTK_LABEL( label ), buf ); gtk_misc_set_padding( GTK_MISC( label ), 2, 6 ); } /* Update names. */ set_glabel( cview->lab, "%s - ", IOBJECT( col )->name ); if( IOBJECT( col )->caption ) set_glabel( cview->head, "%s", IOBJECT( col )->caption ); else { char buf[256]; im_snprintf( buf, 256, "%s", _( "doubleclick to set title" ) ); gtk_label_set_markup( GTK_LABEL( cview->head ), buf ); } /* Set open/closed. */ if( col->open ) { gtk_arrow_set( GTK_ARROW( cview->updown ), GTK_ARROW_DOWN, GTK_SHADOW_OUT ); set_tooltip( cview->updownb, _( "Fold the column away" ) ); } else { gtk_arrow_set( GTK_ARROW( cview->updown ), GTK_ARROW_RIGHT, GTK_SHADOW_OUT ); set_tooltip( cview->updownb, _( "Open the column" ) ); } model_display( MODEL( col->scol ), col->open ); /* Closed columns are hidden in NOEDIT mode. */ widget_visible( GTK_WIDGET( cview ), editable || col->open ); /* Set caption edit. */ if( cview->state == COL_EDIT ) { columnview_add_caption( cview ); gtk_widget_show( cview->capedit ); gtk_widget_hide( cview->headfr ); if( IOBJECT( col )->caption ) { set_gentry( cview->capedit, "%s", IOBJECT( col )->caption ); gtk_editable_select_region( GTK_EDITABLE( cview->capedit ), 0, -1 ); } gtk_widget_grab_focus( cview->capedit ); } else { gtk_widget_show( cview->headfr ); DESTROY_GTK( cview->capedit ); } /* Set bottom entry. */ if( col->selected && col->open && editable && !cview->master ) { columnview_add_text( cview ); gtk_widget_show( cview->textfr ); } else DESTROY_GTK( cview->textfr ); /* Set select state. */ if( cview->master ) gtk_widget_set_name( cview->title, "shadow_widget" ); else if( col->selected && !cview->selected ) { gtk_widget_set_name( cview->title, "selected_widget" ); cview->selected = TRUE; if( cview->textfr ) gtk_widget_grab_focus( cview->text ); } else if( !col->selected ) { /* Always do this, even if cview->selected, so we set on the * first _refresh(). */ gtk_widget_set_name( cview->title, "column_widget" ); cview->selected = FALSE; } VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void columnview_link( View *view, Model *model, View *parent ) { Columnview *cview = COLUMNVIEW( view ); Workspaceview *wview = WORKSPACEVIEW( parent ); VIEW_CLASS( parent_class )->link( view, model, parent ); cview->wview = wview; } static void columnview_child_add( View *parent, View *child ) { Columnview *cview = COLUMNVIEW( parent ); Subcolumnview *sview = SUBCOLUMNVIEW( child ); VIEW_CLASS( parent_class )->child_add( parent, child ); gtk_container_add( GTK_CONTAINER( cview->frame ), GTK_WIDGET( sview ) ); } /* Scroll to keep the text entry at the bottom of the columnview on screen. * We can't use the position/size of the text widget for positioning, since it * may not be properly realized yet ... make the bottom of the column visible * instead. */ static void columnview_scrollto( View *view, ModelScrollPosition position ) { Columnview *cview = COLUMNVIEW( view ); Workspaceview *wview = cview->wview; int x, y, w, h; columnview_get_position( cview, &x, &y, &w, &h ); if( position == MODEL_SCROLL_BOTTOM ) /* 35 is supposed to be enough to ensure the whole of the edit * box gets on the screen. */ workspaceview_scroll( wview, x, y + h, w, 35 ); else workspaceview_scroll( wview, x, y, w, cview->title->allocation.height ); } static void columnview_class_init( ColumnviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; GtkWidget *pane; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ object_class->destroy = columnview_destroy; widget_class->size_allocate = columnview_size_allocate; vobject_class->refresh = columnview_refresh; view_class->link = columnview_link; view_class->child_add = columnview_child_add; view_class->scrollto = columnview_scrollto; pane = columnview_menu = popup_build( _( "Column menu" ) ); popup_add_but( pane, _( "_Edit Caption" ), POPUP_FUNC( columnview_caption_cb ) ); popup_add_but( pane, _( "Select _All" ), POPUP_FUNC( columnview_select_cb ) ); popup_add_but( pane, STOCK_DUPLICATE, POPUP_FUNC( columnview_clone_cb ) ); popup_add_but( pane, _( "Merge Into Column" ), POPUP_FUNC( columnview_merge_cb ) ); popup_add_but( pane, GTK_STOCK_SAVE_AS, POPUP_FUNC( columnview_save_as_cb ) ); menu_add_sep( pane ); popup_add_but( pane, _( "Make Column Into _Menu Item" ), POPUP_FUNC( columnview_to_menu_cb ) ); menu_add_sep( pane ); popup_add_but( pane, GTK_STOCK_DELETE, POPUP_FUNC( columnview_destroy_cb ) ); } static gboolean columnview_event_cb( GtkWidget *wid, GdkEvent *ev, Columnview *cview ) { gboolean handled; handled = FALSE; switch( ev->type ) { case GDK_BUTTON_PRESS: if( ev->button.button == 1 ) /* We want to sop our enclosing notebook seeing * left doubleclicks and creating new tabs. We want to * not block things like scroll events and * middle-drag. */ handled = TRUE; default: break; } return( handled ); } static void columnview_init( Columnview *cview ) { GtkWidget *sb; GtkWidget *frame; GtkWidget *icon; GtkWidget *but; /* No position yet. */ cview->lx = -1; cview->ly = -1; cview->state = COL_WAIT; cview->selected = FALSE; cview->old_width = -1; cview->old_height = -1; /* Make outer vb. */ cview->main = gtk_event_box_new(); gtk_widget_add_events( GTK_WIDGET( cview->main ), GDK_BUTTON_PRESS_MASK ); cview->vbox = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( cview->main ), cview->vbox ); /* Frame for whole title bar. Need an event_box to catch clicks. */ cview->title = gtk_event_box_new(); gtk_widget_add_events( GTK_WIDGET( cview->title ), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK ); gtk_box_pack_start( GTK_BOX( cview->vbox ), cview->title, FALSE, FALSE, 0 ); set_tooltip( cview->title, _( "Left-drag to move, left-double-click to " "set title, right-click for menu" ) ); frame = gtk_frame_new( NULL ); gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_NONE ); gtk_container_add( GTK_CONTAINER( cview->title ), frame ); popup_attach( cview->title, columnview_menu, cview ); gtk_signal_connect( GTK_OBJECT( cview->title ), "event", GTK_SIGNAL_FUNC( columnview_title_event_cb ), cview ); /* Layout contents of title bar. */ cview->titlehb = gtk_hbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( frame ), cview->titlehb ); /* Up/down button. */ cview->updownb = gtk_button_new(); gtk_button_set_relief( GTK_BUTTON( cview->updownb ), GTK_RELIEF_NONE ); gtk_container_set_border_width( GTK_CONTAINER( cview->updownb ), 0 ); gtk_box_pack_start( GTK_BOX( cview->titlehb ), cview->updownb, FALSE, FALSE, 0 ); cview->updown = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT ); gtk_container_add( GTK_CONTAINER( cview->updownb ), cview->updown ); gtk_signal_connect( GTK_OBJECT( cview->updownb ), "clicked", GTK_SIGNAL_FUNC( columnview_updown_cb ), cview ); /* Remove columnview button. */ sb = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_end( GTK_BOX( cview->titlehb ), sb, FALSE, FALSE, 1 ); but = gtk_button_new(); gtk_button_set_relief( GTK_BUTTON( but ), GTK_RELIEF_NONE ); gtk_box_pack_start( GTK_BOX( sb ), but, TRUE, FALSE, 0 ); set_tooltip( but, _( "Delete the column" ) ); icon = gtk_image_new_from_stock( GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU ); gtk_container_add( GTK_CONTAINER( but ), icon ); gtk_signal_connect( GTK_OBJECT( but ), "clicked", GTK_SIGNAL_FUNC( columnview_destroy2_cb ), cview ); /* Columnview name. */ cview->lab = gtk_label_new( "" ); gtk_box_pack_start( GTK_BOX( cview->titlehb ), cview->lab, FALSE, FALSE, 2 ); /* Comment. Wrap a frame around it, to make it the same size as * an entry widget. */ cview->headfr = gtk_frame_new( NULL ); gtk_frame_set_shadow_type( GTK_FRAME( cview->headfr ), GTK_SHADOW_NONE ); gtk_box_pack_start( GTK_BOX( cview->titlehb ), cview->headfr, FALSE, FALSE, 0 ); cview->head = gtk_label_new( "" ); gtk_container_add( GTK_CONTAINER( cview->headfr ), cview->head ); /* Make centre table for tally roll. */ cview->frame = gtk_frame_new( NULL ); gtk_frame_set_shadow_type( GTK_FRAME( cview->frame ), GTK_SHADOW_NONE ); gtk_box_pack_start( GTK_BOX( cview->vbox ), cview->frame, TRUE, TRUE, 0 ); gtk_box_pack_start( GTK_BOX( cview ), cview->main, FALSE, FALSE, 0 ); /* We need to stop our enclosing thing seeing doubeclicks and all * that. */ gtk_signal_connect( GTK_OBJECT( cview ), "event", GTK_SIGNAL_FUNC( columnview_event_cb ), cview ); gtk_widget_show_all( GTK_WIDGET( cview ) ); } GtkType columnview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Columnview", sizeof( Columnview ), sizeof( ColumnviewClass ), (GtkClassInitFunc) columnview_class_init, (GtkObjectInitFunc) columnview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VIEW, &info ); } return( type ); } View * columnview_new( void ) { Columnview *cview = gtk_type_new( TYPE_COLUMNVIEW ); return( VIEW( cview ) ); } nip2-8.7.1/src/managedfile.c0000644000175000017500000000700113351443023012503 00000000000000/* a managed FILE* ... for lazy file read */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static ManagedClass *parent_class = NULL; static void managedfile_dispose( GObject *gobject ) { Managedfile *managedfile = MANAGEDFILE( gobject ); #ifdef DEBUG printf( "managedfile_dispose: " ); iobject_print( IOBJECT( managedfile ) ); #endif /*DEBUG*/ IM_FREEF( ifile_close, managedfile->file ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void managedfile_info( iObject *iobject, VipsBuf *buf ) { Managedfile *managedfile = MANAGEDFILE( iobject ); vips_buf_appendf( buf, "managedfile->fp = %p\n", managedfile->file->fp ); vips_buf_appendf( buf, "managedfile->file->filename = %s\n", managedfile->file->fname ); vips_buf_appendf( buf, "managedfile->file->last_errno = %d\n", managedfile->file->last_errno ); IOBJECT_CLASS( parent_class )->info( iobject, buf ); } static void managedfile_class_init( ManagedfileClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = managedfile_dispose; iobject_class->info = managedfile_info; } static void managedfile_init( Managedfile *managedfile ) { #ifdef DEBUG printf( "managedfile_init: %p\n", managedfile ); #endif /*DEBUG*/ managedfile->file = NULL; } GType managedfile_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ManagedfileClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) managedfile_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Managedfile ), 32, /* n_preallocs */ (GInstanceInitFunc) managedfile_init, }; type = g_type_register_static( TYPE_MANAGED, "Managedfile", &info, 0 ); } return( type ); } Managedfile * managedfile_new( Heap *heap, const char *filename ) { Managedfile *managedfile; iOpenFile *file; #ifdef DEBUG printf( "managedfile_new: %p: %s\n", managedfile, filename ); #endif /*DEBUG*/ if( !(file = ifile_open_read( "%s", filename )) ) return( NULL ); managedfile = g_object_new( TYPE_MANAGEDFILE, NULL ); managed_link_heap( MANAGED( managedfile ), heap ); managedfile->file = file; MANAGED( managedfile )->hash = g_str_hash( filename ); return( managedfile ); } int managedfile_getc( Managedfile *managedfile ) { int ch = ifile_getc( managedfile->file ); #ifdef DEBUG { char in[2]; char out[3]; in[0] = ch; in[1] = '\0'; my_strecpy( out, in, FALSE ); printf( "managedfile_getc: '%s' (%d)\n", out, ch ); } #endif /*DEBUG*/ return( ch ); } nip2-8.7.1/src/plotview.h0000644000175000017500000000311613351443023012130 00000000000000/* a plotview in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PLOTVIEW (plotview_get_type()) #define PLOTVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_PLOTVIEW, Plotview )) #define PLOTVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTVIEW, PlotviewClass )) #define IS_PLOTVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTVIEW )) #define IS_PLOTVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTVIEW )) typedef struct _Plotview { Graphicview parent_object; GtkWidget *box; GtkWidget *label; GtkWidget *canvas; GogChart *gchart; GogPlot *gplot; } Plotview; typedef struct _PlotviewClass { GraphicviewClass parent_class; /* My methods. */ } PlotviewClass; GtkType plotview_get_type( void ); View *plotview_new( void ); nip2-8.7.1/src/iregion.c0000644000175000017500000003313313351443023011710 00000000000000/* an ip region class object in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static iImageClass *parent_class = NULL; void iregion_instance_destroy( iRegionInstance *instance ) { instance->image_class.type = ELEMENT_NOVAL; instance->image_class.ele = (void *) 8; MANAGED_UNREF( instance->ii ); instance->classmodel = NULL; instance->iregiongroup = NULL; heap_unregister_element( reduce_context->heap, &instance->image_class ); } void iregion_instance_init( iRegionInstance *instance, Classmodel *classmodel ) { instance->image_class.type = ELEMENT_NOVAL; instance->image_class.ele = (void *) 9; instance->ii = NULL; instance->area.left = 0; instance->area.top = 0; instance->area.width = 0; instance->area.height = 0; instance->classmodel = classmodel; instance->iregiongroup = NULL; heap_register_element( reduce_context->heap, &instance->image_class ); } gboolean iregion_instance_update( iRegionInstance *instance, PElement *root ) { PElement image; PElement image_class; Imageinfo *value; int left, top, width, height; if( !class_get_member_class( root, MEMBER_IMAGE, "Image", &image ) || !class_get_member_image( &image, MEMBER_VALUE, &value ) || !class_get_member_int( root, MEMBER_LEFT, &left ) || !class_get_member_int( root, MEMBER_TOP, &top ) || !class_get_member_int( root, MEMBER_WIDTH, &width ) || !class_get_member_int( root, MEMBER_HEIGHT, &height ) ) return( FALSE ); instance->area.left = left; instance->area.top = top; instance->area.width = width; instance->area.height = height; MANAGED_UNREF( instance->ii ); instance->ii = value; MANAGED_REF( value ); PEPOINTE( &image_class, &instance->image_class ); PEPUTPE( &image_class, &image ); return( TRUE ); } static void iregion_finalize( GObject *gobject ) { iRegion *iregion; #ifdef DEBUG printf( "iregion_finalize\n" ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_IREGION( gobject ) ); iregion = IREGION( gobject ); /* My instance finalize stuff. */ iregion_instance_destroy( &iregion->instance ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void * iregion_generate_caption_sub( iImage *iimage, iRegion *iregion, gboolean *first ) { iImage *our_iimage = IIMAGE( iregion ); Workspace *ws = HEAPMODEL( iregion )->row->ws; Row *row = HEAPMODEL( iimage )->row; /* Supress this name in the caption if it's a superclass. If this * thing is on a super, it's on the subclass too ... not helpful to * have it twice. */ if( row->sym && !is_super( row->sym ) ) { if( *first ) *first = FALSE; else vips_buf_appends( &our_iimage->caption_buffer, ", " ); row_qualified_name_relative( ws->sym, row, &our_iimage->caption_buffer ); } return( NULL ); } static const char * iregion_generate_caption( iObject *iobject ) { iRegion *iregion = IREGION( iobject ); iImage *iimage = IIMAGE( iregion ); const int nimages = g_slist_length( CLASSMODEL( iregion )->iimages ); VipsBuf *buf = &iimage->caption_buffer; gboolean first; vips_buf_rewind( buf ); heapmodel_name( HEAPMODEL( iregion ), buf ); vips_buf_appendf( buf, " " ); /* Expands to (eg.) "Region on A1 at (10, 10), size (50, 50)" */ vips_buf_appendf( buf, _( "on" ) ); vips_buf_appendf( buf, " " ); if( nimages > 1 ) vips_buf_appendf( buf, "[" ); first = TRUE; slist_map2( CLASSMODEL( iregion )->iimages, (SListMap2Fn) iregion_generate_caption_sub, iregion, &first ); if( nimages > 1 ) vips_buf_appendf( buf, "]" ); vips_buf_appendf( buf, " " ); vips_buf_appendf( buf, _( "at (%d, %d), size (%d, %d)" ), iregion->instance.area.left, iregion->instance.area.top, iregion->instance.area.width, iregion->instance.area.height ); return( vips_buf_all( buf ) ); } static void iregion_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Classmodel *classmodel = CLASSMODEL( client ); iRegionInstance *instance = classmodel_get_instance( classmodel ); Stringset *ss = STRINGSET( iwnd ); Rect area; StringsetChild *left = stringset_child_get( ss, _( "Left" ) ); StringsetChild *top = stringset_child_get( ss, _( "Top" ) ); StringsetChild *width = stringset_child_get( ss, _( "Width" ) ); StringsetChild *height = stringset_child_get( ss, _( "Height" ) ); if( !get_geditable_int( left->entry, &area.left ) || !get_geditable_int( top->entry, &area.top ) || !get_geditable_int( width->entry, &area.width ) || !get_geditable_int( height->entry, &area.height ) ) { nfn( sys, IWINDOW_ERROR ); return; } if( instance ) { instance->area = area; classmodel_update( classmodel ); symbol_recalculate_all(); } nfn( sys, IWINDOW_YES ); } static View * iregion_view_new( Model *model, View *parent ) { return( iregionview_new() ); } /* Pop up a iregion edit box. Shared with iarrow.c. */ void iregion_edit( GtkWidget *parent, Model *model ) { Classmodel *classmodel = CLASSMODEL( model ); iRegionInstance *instance = classmodel_get_instance( classmodel ); GtkWidget *ss = stringset_new(); if( instance ) { char txt[256]; im_snprintf( txt, 256, "%d", instance->area.left ); stringset_child_new( STRINGSET( ss ), _( "Left" ), txt, _( "Left edge of region" ) ); im_snprintf( txt, 256, "%d", instance->area.top ); stringset_child_new( STRINGSET( ss ), _( "Top" ), txt, _( "Top edge of region" ) ); im_snprintf( txt, 256, "%d", instance->area.width ); stringset_child_new( STRINGSET( ss ), _( "Width" ), txt, _( "Width of region" ) ); im_snprintf( txt, 256, "%d", instance->area.height ); stringset_child_new( STRINGSET( ss ), _( "Height" ), txt, _( "Height of region" ) ); } iwindow_set_title( IWINDOW( ss ), _( "Edit %s %s" ), IOBJECT_GET_CLASS_NAME( model ), IOBJECT( HEAPMODEL( model )->row )->name ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, classmodel ); idialog_add_ok( IDIALOG( ss ), iregion_done_cb, _( "Set %s" ), IOBJECT_GET_CLASS_NAME( model ) ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( parent ) ); idialog_set_iobject( IDIALOG( ss ), IOBJECT( model ) ); idialog_set_pinup( IDIALOG( ss ), TRUE ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); } /* Shared with iarrow.c. */ void iregion_parent_add( iContainer *child ) { ICONTAINER_CLASS( parent_class )->parent_add( child ); /* Now we're all linked up, make a child model to handle client * displays on imageviews. */ (void) iregiongroup_new( CLASSMODEL( child ) ); } /* Shared with iarrow.c. */ xmlNode * iregion_save( Model *model, xmlNode *xnode ) { /* Get our parent class. We can't just use the global parent_class, * since due to our lame MI scheme, this method may be called for * iarrow/ipoint etc. as well as iregion ... look up dynamically. */ gpointer parent_class = PARENT_CLASS_DYNAMIC( model ); iRegionInstance *instance = classmodel_get_instance( CLASSMODEL( model ) ); xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( instance && CLASSMODEL( model )->edited ) { Rect *area = &instance->area; if( !set_iprop( xthis, "left", area->left ) || !set_iprop( xthis, "top", area->top ) || !set_iprop( xthis, "width", area->width ) || !set_iprop( xthis, "height", area->height ) ) return( NULL ); } return( xthis ); } /* Shared with iarrow.c. */ gboolean iregion_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { gpointer parent_class = PARENT_CLASS_DYNAMIC( model ); iRegionInstance *instance = classmodel_get_instance( CLASSMODEL( model ) ); g_assert( IS_RHS( parent ) ); if( instance ) { Rect *area = &instance->area; if( get_iprop( xnode, "left", &area->left ) && get_iprop( xnode, "top", &area->top ) && get_iprop( xnode, "width", &area->width ) && get_iprop( xnode, "height", &area->height ) ) classmodel_set_edited( CLASSMODEL( model ), TRUE ); } return( MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ); } /* Need to implement _update_heap(), as not all model fields are directly * editable ... some are set only from expr. See also iimage.c. Shared with * iarrow.c. */ void * iregion_update_heap( Heapmodel *heapmodel ) { gpointer parent_class = PARENT_CLASS_DYNAMIC( heapmodel ); iRegionInstance *instance = classmodel_get_instance( CLASSMODEL( heapmodel ) ); Expr *expr = heapmodel->row->expr; Rect area; PElement pe; if( instance ) { /* Save any model fields that may have been set by _load() and * which might be zapped by _get_instance(). */ area = instance->area; /* Look for the base instance and update from that. */ if( !class_get_exact( &expr->root, IOBJECT( heapmodel )->name, &pe ) ) return( FALSE ); if( !iregion_instance_update( instance, &pe ) ) return( heapmodel ); /* Restore model fields from _load(). */ instance->area = area; } /* Classmodel _update_heap() will do _instance_new() from the fixed up * model. */ return( HEAPMODEL_CLASS( parent_class )->update_heap( heapmodel ) ); } static void * iregion_update_model( Heapmodel *heapmodel ) { iRegion *iregion = IREGION( heapmodel ); if( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ) return( heapmodel ); /* Update who-has-displays-on-what stuff. */ classmodel_iimage_update( CLASSMODEL( iregion ), iregion->instance.ii ); /* Make sure the caption is regenerated. */ iobject_changed( IOBJECT( heapmodel ) ); return( NULL ); } /* Update iRegion from heap. Shared with iarrow.c. */ gboolean iregion_class_get( Classmodel *classmodel, PElement *root ) { gpointer parent_class = PARENT_CLASS_DYNAMIC( classmodel ); iRegionInstance *instance = classmodel_get_instance( classmodel ); #ifdef DEBUG printf( "iregion_class_get: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( "\n" ); #endif /*DEBUG*/ if( instance && !iregion_instance_update( instance, root ) ) return( FALSE ); return( CLASSMODEL_CLASS( parent_class )->class_get( classmodel, root ) ); } /* Make a new "fn value" application. Shared with iarrow.c. */ gboolean iregion_class_new( Classmodel *classmodel, PElement *fn, PElement *out ) { Heap *heap = reduce_context->heap; iRegionInstance *instance = classmodel_get_instance( classmodel ); PElement rhs; #ifdef DEBUG printf( "iregion_class_new\n" ); #endif /*DEBUG*/ /* Make application nodes. */ if( instance ) { heap_appl_init( out, fn ); if( !heap_appl_add( heap, out, &rhs ) || !heap_element_new( heap, &instance->image_class, &rhs ) || !heap_appl_add( heap, out, &rhs ) || !heap_real_new( heap, instance->area.left, &rhs ) || !heap_appl_add( heap, out, &rhs ) || !heap_real_new( heap, instance->area.top, &rhs ) || !heap_appl_add( heap, out, &rhs ) || !heap_real_new( heap, instance->area.width, &rhs ) || !heap_appl_add( heap, out, &rhs ) || !heap_real_new( heap, instance->area.height, &rhs ) ) return( FALSE ); } return( TRUE ); } static void * iregion_get_instance( Classmodel *classmodel ) { iRegion *iregion = IREGION( classmodel ); return( &iregion->instance ); } static void iregion_class_init( iRegionClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->finalize = iregion_finalize; iobject_class->user_name = _( "Region" ); iobject_class->generate_caption = iregion_generate_caption; icontainer_class->parent_add = iregion_parent_add; model_class->view_new = iregion_view_new; model_class->edit = iregion_edit; model_class->save = iregion_save; model_class->load = iregion_load; heapmodel_class->update_heap = iregion_update_heap; heapmodel_class->update_model = iregion_update_model; classmodel_class->class_get = iregion_class_get; classmodel_class->class_new = iregion_class_new; classmodel_class->get_instance = iregion_get_instance; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void iregion_init( iRegion *iregion ) { iregion_instance_init( &iregion->instance, CLASSMODEL( iregion ) ); iobject_set( IOBJECT( iregion ), CLASS_REGION, NULL ); } GType iregion_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( iRegionClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) iregion_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( iRegion ), 32, /* n_preallocs */ (GInstanceInitFunc) iregion_init, }; type = g_type_register_static( TYPE_IIMAGE, "iRegion", &info, 0 ); } return( type ); } nip2-8.7.1/src/group.c0000644000175000017500000001047013351443023011407 00000000000000/* an input group ... put/get methods */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ValueClass *parent_class = NULL; static gboolean group_save_list( PElement *list, char *filename ); /* Exported, since main.c uses this to save 'main' to a file. @filename is * incremented. */ gboolean group_save_item( PElement *item, char *filename ) { gboolean result; Imageinfo *ii; char buf[FILENAME_MAX]; /* We don't want $VAR etc. in the filename we pass down to the file * ops. */ im_strncpy( buf, filename, FILENAME_MAX ); path_expand( buf ); if( !heap_is_instanceof( CLASS_GROUP, item, &result ) ) return( FALSE ); if( result ) { PElement value; if( !class_get_member( item, MEMBER_VALUE, NULL, &value ) || !group_save_list( &value, filename ) ) return( FALSE ); } if( !heap_is_instanceof( CLASS_IMAGE, item, &result ) ) return( FALSE ); if( result ) { PElement value; filesel_add_mode( buf ); if( !class_get_member( item, MEMBER_VALUE, NULL, &value ) || !heap_get_image( &value, &ii ) || !imageinfo_write( ii, buf ) ) return( FALSE ); increment_filename( filename ); } if( !heap_is_instanceof( CLASS_MATRIX, item, &result ) ) return( FALSE ); if( result ) { DOUBLEMASK *dmask; if( !(dmask = matrix_ip_to_dmask( item )) ) return( FALSE ); if( im_write_dmask_name( dmask, buf ) ) { error_vips_all(); IM_FREEF( im_free_dmask, dmask ); return( FALSE ); } IM_FREEF( im_free_dmask, dmask ); increment_filename( filename ); } if( PEISIMAGE( item ) ) { filesel_add_mode( buf ); if( !heap_get_image( item, &ii ) || !imageinfo_write( ii, buf ) ) return( FALSE ); increment_filename( filename ); } if( PEISLIST( item ) ) { if( !group_save_list( item, filename ) ) return( FALSE ); } return( TRUE ); } static gboolean group_save_list( PElement *list, char *filename ) { int i; int length; if( (length = heap_list_length( list )) < 0 ) return( FALSE ); for( i = 0; i < length; i++ ) { PElement item; if( !heap_list_index( list, i, &item ) || !group_save_item( &item, filename ) ) return( FALSE ); } return( TRUE ); } static gboolean group_graphic_save( Classmodel *classmodel, GtkWidget *parent, const char *filename ) { Group *group = GROUP( classmodel ); Row *row = HEAPMODEL( group )->row; PElement *root = &row->expr->root; char buf[FILENAME_MAX]; /* We are going to increment the filename ... make sure there's some * space at the end of the string. */ im_strncpy( buf, filename, FILENAME_MAX - 5 ); if( !group_save_item( root, buf ) ) return( FALSE ); return( TRUE ); } static void group_class_init( GroupClass *class ) { ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ classmodel_class->graphic_save = group_graphic_save; model_register_loadable( MODEL_CLASS( class ) ); } static void group_init( Group *group ) { iobject_set( IOBJECT( group ), CLASS_GROUP, NULL ); } GType group_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( GroupClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) group_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Group ), 32, /* n_preallocs */ (GInstanceInitFunc) group_init, }; type = g_type_register_static( TYPE_VALUE, "Group", &info, 0 ); } return( type ); } nip2-8.7.1/src/stringview.c0000644000175000017500000000646713351443023012467 00000000000000/* a view of a text thingy */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static EditviewClass *parent_class = NULL; /* Re-read the text in a tally entry. */ static void * stringview_scan( View *view ) { Stringview *stringview = STRINGVIEW( view ); String *string = STRING( VOBJECT( stringview )->iobject ); Expr *expr = HEAPMODEL( string )->row->expr; char value[MAX_STRSIZE]; char value2[MAX_STRSIZE]; #ifdef DEBUG Row *row = HEAPMODEL( string )->row; printf( "stringview_scan: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ expr_error_clear( expr ); if( !get_geditable_string( EDITVIEW( stringview )->text, value, MAX_STRSIZE ) ) { expr_error_set( expr ); return( view ); } my_strccpy( value2, value ); if( strcmp( string->value, value2 ) != 0 ) { IM_SETSTR( string->value, value2 ); classmodel_update( CLASSMODEL( string ) ) ; } return( VIEW_CLASS( parent_class )->scan( view ) ); } static void stringview_refresh( vObject *vobject ) { Stringview *stringview = STRINGVIEW( vobject ); String *string = STRING( VOBJECT( stringview )->iobject ); #ifdef DEBUG Row *row = HEAPMODEL( string )->row; printf( "stringview_refresh: " ); row_name_print( row ); printf( " (%p)\n", vobject ); #endif /*DEBUG*/ if( string->value ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_appendsc( &buf, FALSE, string->value ); editview_set_entry( EDITVIEW( stringview ), "%s", vips_buf_all( &buf ) ); } VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void stringview_class_init( StringviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = stringview_refresh; view_class->scan = stringview_scan; } static void stringview_init( Stringview *stringview ) { } GtkType stringview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Stringview", sizeof( Stringview ), sizeof( StringviewClass ), (GtkClassInitFunc) stringview_class_init, (GtkObjectInitFunc) stringview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_EDITVIEW, &info ); } return( type ); } View * stringview_new( void ) { Stringview *stringview = gtk_type_new( TYPE_STRINGVIEW ); return( VIEW( stringview ) ); } nip2-8.7.1/src/mainw.h0000644000175000017500000000777513351443023011411 00000000000000/* A top level window holding some workspaces */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_MAINW (mainw_get_type()) #define MAINW( obj ) (GTK_CHECK_CAST( (obj), TYPE_MAINW, Mainw )) #define MAINW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_MAINW, MainwClass )) #define IS_MAINW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_MAINW )) #define IS_MAINW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_MAINW )) /* Get a widget's enclosing Mainw. */ #define GET_MAINW( W ) \ MAINW( idialog_get_root( GTK_WIDGET( W ) ) ) struct _Mainw { iWindow parent_object; /* Our model. */ Workspacegroup *wsg; guint changed_sid; guint destroy_sid; /* Watch for changed on heap and image, and prefs. Use to update * status bar and space free. */ guint imageinfo_changed_sid; guint heap_changed_sid; guint watch_changed_sid; /* Link to progress system. */ guint begin_sid; guint update_sid; guint end_sid; gboolean cancel; /* Batch refresh with this, it's slow. */ guint refresh_timeout; /* Display MB free in tmp, or cells free in heap. */ gboolean free_type; /* View menu show/hide toggle states. The pane states are in the ws as * we need to save them to the ws file. */ gboolean toolbar_visible; gboolean statusbar_visible; /* The kitg the toolkit menu is currently displaying. Use this to * avoid rebuilding the toolkit menu on every tab switch. */ Toolkitgroup *kitg; /* Component widgets. */ Toolkitgroupview *kitgview; GtkWidget *toolbar; GtkWidget *recent_menu; GtkWidget *jump_to_column_menu; GtkWidget *toolkit_menu; Workspacegroupview *wsgview; GtkWidget *statusbar_main; GtkWidget *statusbar; GtkWidget *space_free; GtkWidget *space_free_eb; GtkWidget *progress_box; GtkWidget *progress; }; typedef struct _MainwClass { iWindowClass parent_class; /* My methods. */ } MainwClass; extern GSList *mainw_recent_workspace; extern GSList *mainw_recent_image; extern GSList *mainw_recent_matrix; extern gboolean mainw_auto_recalc; extern gboolean mainw_cancel; void mainw_startup( void ); void mainw_shutdown( void ); void mainw_recent_freeze( void ); void mainw_recent_thaw( void ); void mainw_recent_add( GSList **recent, const char *filename ); Mainw *mainw_pick_one( void ); GType mainw_get_type( void ); void mainw_find_disc( VipsBuf *buf ); void mainw_find_heap( VipsBuf *buf, Heap *heap ); Workspace *mainw_get_workspace( Mainw *mainw ); void mainw_homepage_action_cb( GtkAction *action, iWindow *iwnd ); void mainw_about_action_cb( GtkAction *action, iWindow *iwnd ); void mainw_guide_action_cb( GtkAction *action, iWindow *iwnd ); void mainw_column_new_action_cb( GtkAction *action, Mainw *mainw ); void mainw_workspace_merge( Mainw *mainw ); void mainw_workspace_merge_action_cb( GtkAction *action, Mainw *mainw ); void mainw_layout_action_cb( GtkAction *action, Mainw *mainw ); void mainw_group_action_cb( GtkAction *action, Mainw *mainw ); void mainw_next_error_action_cb( GtkAction *action, Mainw *mainw ); void mainw_open_action_cb( GtkAction *action, Mainw *mainw ); Workspacegroup *mainw_open_workspace( Workspaceroot *wsr, const char *filename ); Mainw *mainw_new( Workspacegroup *wsg ); void mainw_cull( void ); void mainw_layout( void ); nip2-8.7.1/src/managed.c0000644000175000017500000002307713351443023011656 00000000000000/* managed objects ... things like Imageinfo which are lifetime managed by * both the GC and by pointers from C: we need to both mark/sweep and refcount * * abstract class: Managedgvalue, Imageinfo, etc. build off this */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* get -DDEBUG_LEAK from the gcc command-line #define DEBUG */ static iContainerClass *parent_class = NULL; #ifdef DEBUG_LEAK static GSList *managed_all = NULL; #endif /*DEBUG_LEAK*/ #ifdef DEBUG_LEAK static void * managed_print_info( Managed *managed, VipsBuf *buf ) { iobject_info( IOBJECT( managed ), buf ); vips_buf_appends( buf, "\n" ); return( NULL ); } #endif /*DEBUG_LEAK*/ /* Debugging ... check that all manageds have been closed, dump any which * haven't. */ void managed_check_all_destroyed( void ) { #ifdef DEBUG_LEAK if( managed_all ) { char txt[1000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); printf( "managed_check_all_destroyed:\n" ); slist_map( managed_all, (SListMapFn) managed_print_info, &buf ); printf( "%s", vips_buf_all( &buf ) ); } #endif /*DEBUG_LEAK*/ } void managed_link_heap( Managed *managed, Heap *heap ) { g_assert( !managed->heap ); if( heap == NULL ) heap = reduce_context->heap; managed->heap = heap; g_hash_table_insert( heap->mtable, managed, managed ); managed->attached = TRUE; /* The mtable owns our ref. */ g_object_ref( G_OBJECT( managed ) ); iobject_sink( IOBJECT( managed ) ); } static void managed_unlink_heap( Managed *managed ) { if( managed->attached && managed->heap ) { g_hash_table_remove( managed->heap->mtable, managed ); managed->attached = FALSE; g_object_unref( G_OBJECT( managed ) ); } } /* managed no longer depends upon in. */ void * managed_sub_remove( Managed *in, Managed *managed ) { g_assert( g_slist_find( managed->sub, in ) ); managed->sub = g_slist_remove( managed->sub, in ); managed_destroy_nonheap( in ); return( NULL ); } static void managed_dispose( GObject *gobject ) { Managed *managed = MANAGED( gobject ); #ifdef DEBUG printf( "managed_dispose: " ); iobject_print( IOBJECT( managed ) ); #endif /*DEBUG*/ g_assert( managed->count == 0 ); managed_unlink_heap( managed ); slist_map( managed->sub, (SListMapFn) managed_sub_remove, managed ); g_assert( !managed->sub ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } /* Final death! */ static void managed_finalize( GObject *gobject ) { #ifdef DEBUG Managed *managed = MANAGED( gobject ); printf( "managed_finalize:" ); iobject_print( IOBJECT( managed ) ); #endif /*DEBUG*/ #ifdef DEBUG_LEAK managed_all = g_slist_remove( managed_all, gobject ); #endif /*DEBUG_LEAK*/ G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* _info() is used by itext.c to display managed objects. Don't chain * up, don't print more than one line. */ static void managed_info( iObject *iobject, VipsBuf *buf ) { #ifdef DEBUG Managed *managed = MANAGED( iobject ); vips_buf_appendf( buf, "managed-object %p\n", managed ); vips_buf_appendf( buf, "managed->count = %d\n", managed->count ); vips_buf_appendf( buf, "managed->marked = %d\n", managed->marked ); #endif /*DEBUG*/ vips_buf_appendf( buf, "%s %p", G_OBJECT_TYPE_NAME( iobject ), iobject ); } static void managed_class_init( ManagedClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = managed_dispose; gobject_class->finalize = managed_finalize; iobject_class->info = managed_info; class->keepalive = 0; } static void managed_init( Managed *managed ) { #ifdef DEBUG printf( "managed_init: %p\n", managed ); #endif /*DEBUG*/ managed->heap = NULL; managed->attached = FALSE; /* Init to TRUE, so we won't close until (at least) the next GC. */ managed->marked = TRUE; /* Start with a count of zero (unlike gobject!). We will be deleted * on the next GC unless our caller refs us. */ managed->count = 0; /* When we're unreffed, become a zombie first, then destroy after a * (possibly zero) interval. */ managed->zombie = FALSE; managed->time = 0; managed->sub = NULL; #ifdef DEBUG_LEAK managed_all = g_slist_prepend( managed_all, managed ); #endif /*DEBUG_LEAK*/ } GType managed_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ManagedClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) managed_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Managed ), 32, /* n_preallocs */ (GInstanceInitFunc) managed_init, }; type = g_type_register_static( TYPE_ICONTAINER, "Managed", &info, 0 ); } return( type ); } /* From heap_gc() ... no heap pointers left, delete if there are no * non-heap pointers either. */ void managed_destroy_heap( Managed *managed ) { #ifdef DEBUG printf( "managed_destroy_heap: " ); iobject_print( IOBJECT( managed ) ); #endif /*DEBUG*/ /* All non-heaps gone too? */ if( !managed->count ) IDESTROY( managed ); } /* destroy() for non-heap pointers. */ void * managed_destroy_nonheap( Managed *managed ) { g_assert( managed->count > 0 ); #ifdef DEBUG printf( "managed_destroy_nonheap: count = %d ", managed->count ); iobject_print( IOBJECT( managed ) ); #endif /*DEBUG*/ managed->count--; /* We can't destroy the managed if count == 0 && it's not marked, * since a heap pointer might have been created to it since the last * GC. Queue a GC to clean off stray manageds. */ heap_gc_request( managed->heap ); return( NULL ); } /* Create a new non-heap pointer. */ void managed_dup_nonheap( Managed *managed ) { g_assert( managed->count >= 0 ); managed->count++; #ifdef DEBUG printf( "managed_dup_nonheap: count = %d ", managed->count ); iobject_print( IOBJECT( managed ) ); #endif /*DEBUG*/ } /* managed depends on in ... add a dependency. */ void managed_sub_add( Managed *managed, Managed *in ) { g_assert( managed && in ); managed->sub = g_slist_prepend( managed->sub, in ); managed_dup_nonheap( in ); } /* out needs all of in[], add to sub-mark-list. */ void managed_sub_add_all( Managed *out, int nin, Managed **in ) { int i; if( out ) for( i = 0; i < nin; i++ ) managed_sub_add( out, in[i] ); } static void managed_clear_sub( void *key, Managed *managed ) { managed->marked = FALSE; } void managed_clear( Heap *heap ) { g_hash_table_foreach( heap->mtable, (GHFunc) managed_clear_sub, NULL ); } /* Mark as being used ... also mark all sub-objects. */ void managed_mark( Managed *managed ) { if( !managed->marked ) { managed->marked = TRUE; (void) slist_map( managed->sub, (SListMapFn) managed_mark, NULL ); } } /* Use a timer to remove unreffed keepalive objects after some * interval. */ static GTimer *zombie_timer = NULL; static double zombie_elapsed; static gboolean managed_free_unused_sub( void *key, Managed *managed, gboolean *changed ) { ManagedClass *managed_class = MANAGED_GET_CLASS( managed ); Heap *heap = managed->heap; gboolean remove = FALSE; if( !managed->marked && !managed->count ) { if( !managed->zombie ) { /* Unreffed, but not marked as a zombie. */ #ifdef DEBUG printf( "managed_free: zombiefying: " ); iobject_print( IOBJECT( managed ) ); #endif /*DEBUG*/ managed->zombie = TRUE; managed->time = zombie_elapsed; } } else { if( managed->zombie ) { /* Reffed, but marked as a zombie. Back to life again. */ #ifdef DEBUG printf( "managed_free: resuscitating: " ); iobject_print( IOBJECT( managed ) ); #endif /*DEBUG*/ managed->zombie = FALSE; managed->time = 0; } } /* Is this an old zombie? Or a not-so-old one and we're flushing? * Junk. */ if( managed->zombie && zombie_elapsed - managed->time >= managed_class->keepalive ) remove = TRUE; if( managed->zombie && heap->flush ) remove = TRUE; if( remove ) { #ifdef DEBUG printf( "managed_free: closing unreferenced object: " ); iobject_print( IOBJECT( managed ) ); printf( "managed_free: after %g s as a zombie\n", zombie_elapsed - managed->time ); #endif /*DEBUG*/ /* We will return TRUE to unlink us from the hash table. Stop * managed_dispose unlinking for us, and drop the hash table's * reference. */ managed->attached = FALSE; managed_destroy_heap( managed ); g_object_unref( G_OBJECT( managed ) ); *changed = TRUE; } return( remove ); } /* Make one sweep and destroy all unused managed objects. Return TRUE if we * removed any. */ gboolean managed_free_unused( Heap *heap ) { gboolean changed; if( !zombie_timer ) zombie_timer = g_timer_new(); zombie_elapsed = g_timer_elapsed( zombie_timer, NULL ); changed = FALSE; g_hash_table_foreach_remove( heap->mtable, (GHRFunc) managed_free_unused_sub, &changed ); return( changed ); } nip2-8.7.1/src/colourview.c0000644000175000017500000001153613351443023012455 00000000000000/* run the display for an image in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; static void colourview_link( View *view, Model *model, View *parent ) { Colourview *colourview = COLOURVIEW( view ); Rowview *rview = ROWVIEW( parent->parent ); VIEW_CLASS( parent_class )->link( view, model, parent ); rowview_menu_attach( rview, GTK_WIDGET( colourview->colourdisplay ) ); } static void colourview_refresh( vObject *vobject ) { Colourview *colourview = COLOURVIEW( vobject ); Colour *colour = COLOUR( vobject->iobject ); #ifdef DEBUG printf( "colourview_refresh\n" ); #endif /*DEBUG*/ conversion_set_image( colourview->conv, colour_ii_new( colour ) ); set_gcaption( colourview->label, "%s", vips_buf_all( &colour->caption ) ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void colourview_class_init( ColourviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = colourview_refresh; view_class->link = colourview_link; } static void colourview_area_changed_cb( Imagedisplay *id, Rect *area, Colourview *colourview ) { double rgb[4]; imageinfo_to_rgb( id->conv->ii, rgb ); colour_set_rgb( COLOUR( VOBJECT( colourview )->iobject ), rgb ); } static void colourview_doubleclick_one_cb( GtkWidget *widget, GdkEvent *event, Colourview *colourview ) { Heapmodel *heapmodel = HEAPMODEL( VOBJECT( colourview )->iobject ); Row *row = heapmodel->row; row_select_modifier( row, event->button.state ); } static void colourview_doubleclick_two_cb( GtkWidget *widget, GdkEvent *event, Colourview *colourview ) { model_edit( widget, MODEL( VOBJECT( colourview )->iobject ) ); } static void colourview_init( Colourview *colourview ) { GtkWidget *eb; GtkWidget *vbox; #ifdef DEBUG printf( "colourview_init\n" ); #endif /*DEBUG*/ eb = gtk_event_box_new(); gtk_widget_add_events( GTK_WIDGET( eb ), GDK_POINTER_MOTION_HINT_MASK ); gtk_box_pack_start( GTK_BOX( colourview ), eb, FALSE, FALSE, 0 ); vbox = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( eb ), vbox ); gtk_widget_show( vbox ); colourview->colourdisplay = colourdisplay_new( NULL ); colourview->conv = IMAGEDISPLAY( colourview->colourdisplay )->conv; gtk_widget_set_size_request( GTK_WIDGET( colourview->colourdisplay ), DISPLAY_THUMBNAIL, DISPLAY_THUMBNAIL ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( colourview->colourdisplay ), FALSE, FALSE, 0 ); g_signal_connect( colourview->colourdisplay, "area_changed", G_CALLBACK( colourview_area_changed_cb ), colourview ); gtk_widget_show( GTK_WIDGET( colourview->colourdisplay ) ); colourview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( colourview->label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( colourview->label ), 2, 0 ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( colourview->label ), FALSE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( colourview->label ) ); doubleclick_add( GTK_WIDGET( colourview ), FALSE, DOUBLECLICK_FUNC( colourview_doubleclick_one_cb ), colourview, DOUBLECLICK_FUNC( colourview_doubleclick_two_cb ), colourview ); gtk_widget_set_name( eb, "caption_widget" ); gtk_widget_show( eb ); } GtkType colourview_get_type( void ) { static GtkType colourview_type = 0; if( !colourview_type ) { static const GtkTypeInfo info = { "Colourview", sizeof( Colourview ), sizeof( ColourviewClass ), (GtkClassInitFunc) colourview_class_init, (GtkObjectInitFunc) colourview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; colourview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( colourview_type ); } View * colourview_new( void ) { Colourview *colourview = gtk_type_new( TYPE_COLOURVIEW ); return( VIEW( colourview ) ); } nip2-8.7.1/src/option.h0000644000175000017500000000324513351443023011572 00000000000000/* a option in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_OPTION (option_get_type()) #define OPTION( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_OPTION, Option )) #define OPTION_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_OPTION, OptionClass)) #define IS_OPTION( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_OPTION )) #define IS_OPTION_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_OPTION )) #define OPTION_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_OPTION, OptionClass )) typedef struct _Option { Classmodel parent_class; /* Base class fields. */ GSList *labels; /* [[char]] for option fields */ int value; /* Index of current option */ } Option; typedef struct _OptionClass { ClassmodelClass parent_class; /* My methods. */ } OptionClass; GType option_get_type( void ); nip2-8.7.1/src/iarrow.c0000644000175000017500000001500613351443023011556 00000000000000/* an ip arrow class object in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void iarrow_finalize( GObject *gobject ) { iArrow *iarrow; #ifdef DEBUG printf( "iarrow_finalize\n" ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_IARROW( gobject ) ); iarrow = IARROW( gobject ); /* My instance finalize stuff. */ iregion_instance_destroy( &iarrow->instance ); vips_buf_destroy( &iarrow->caption_buffer ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void * iarrow_generate_caption_sub( iImage *iimage, iArrow *iarrow, gboolean *first ) { Workspace *ws = HEAPMODEL( iarrow )->row->ws; Row *row = HEAPMODEL( iimage )->row; /* Suppress this name in the caption if it's a superclass. If this * thing is on a super, it's on the subclass too ... not helpful to * have it twice. */ if( !is_super( row->sym ) ) { if( *first ) *first = FALSE; else vips_buf_appends( &iarrow->caption_buffer, ", " ); row_qualified_name_relative( ws->sym, row, &iarrow->caption_buffer ); } return( NULL ); } static const char * iarrow_generate_caption( iObject *iobject ) { static const char *names[] = { CLASS_HGUIDE, CLASS_VGUIDE, CLASS_MARK, CLASS_ARROW, NULL }; iArrow *iarrow = IARROW( iobject ); VipsBuf *buf = &iarrow->caption_buffer; const int nimages = g_slist_length( CLASSMODEL( iarrow )->iimages ); Expr *expr; gboolean result; gboolean first; int i; if( !HEAPMODEL( iarrow )->row || !(expr = HEAPMODEL( iarrow )->row->expr) || !heap_is_class( &expr->root, &result ) || !result ) return( _( "No image" ) ); vips_buf_rewind( buf ); heapmodel_name( HEAPMODEL( iarrow ), buf ); vips_buf_appendf( buf, " " ); /* Used in (eg.) "Mark at (10, 10) on [A1, A2]" */ vips_buf_appendf( buf, _( "on" ) ); vips_buf_appendf( buf, " " ); if( nimages > 1 ) vips_buf_appendf( buf, "[" ); first = TRUE; slist_map2( CLASSMODEL( iarrow )->iimages, (SListMap2Fn) iarrow_generate_caption_sub, iarrow, &first ); if( nimages > 1 ) vips_buf_appendf( buf, "]" ); vips_buf_appendf( buf, " " ); for( i = 0; names[i]; i++ ) { if( !heap_is_instanceof( names[i], &expr->root, &result ) ) break; if( result ) { switch( i ) { case 0: vips_buf_appendf( buf, _( "at %d" ), iarrow->instance.area.top ); break; case 1: vips_buf_appendf( buf, _( "at %d" ), iarrow->instance.area.left ); break; case 2: vips_buf_appendf( buf, _( "at (%d, %d)" ), iarrow->instance.area.left, iarrow->instance.area.top ); break; case 3: vips_buf_appendf( buf, _( "at (%d, %d), offset (%d, %d)" ), iarrow->instance.area.left, iarrow->instance.area.top, iarrow->instance.area.width, iarrow->instance.area.height ); break; default: g_assert( 0 ); } break; } } return( vips_buf_all( buf ) ); } static View * iarrow_view_new( Model *model, View *parent ) { return( valueview_new() ); } static void * iarrow_update_model( Heapmodel *heapmodel ) { /* Parent first ... this will update our instance vars. */ if( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ) return( heapmodel ); if( heapmodel->row->expr ) { iArrow *iarrow = IARROW( heapmodel ); /* Update who-has-displays-on-what stuff. */ classmodel_iimage_update( CLASSMODEL( iarrow ), iarrow->instance.ii ); /* Need to make sure the caption is regenerated. */ iobject_changed( IOBJECT( heapmodel ) ); } return( NULL ); } static void * iarrow_get_instance( Classmodel *classmodel ) { iArrow *iarrow = IARROW( classmodel ); return( &iarrow->instance ); } static void iarrow_class_init( iArrowClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; /* We share methods with iregion in a sort of MI way ... iregion needs * to be initialised before we can work. Force it to start up. */ (void) iregion_get_type(); parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->finalize = iarrow_finalize; iobject_class->generate_caption = iarrow_generate_caption; icontainer_class->parent_add = iregion_parent_add; model_class->view_new = iarrow_view_new; model_class->edit = iregion_edit; model_class->save = iregion_save; model_class->load = iregion_load; heapmodel_class->update_model = iarrow_update_model; heapmodel_class->update_heap = iregion_update_heap; classmodel_class->class_get = iregion_class_get; classmodel_class->class_new = iregion_class_new; classmodel_class->get_instance = iarrow_get_instance; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void iarrow_init( iArrow *iarrow ) { iregion_instance_init( &iarrow->instance, CLASSMODEL( iarrow ) ); vips_buf_init_dynamic( &iarrow->caption_buffer, MAX_LINELENGTH ); iobject_set( IOBJECT( iarrow ), CLASS_ARROW, NULL ); } GType iarrow_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( iArrowClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) iarrow_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( iArrow ), 32, /* n_preallocs */ (GInstanceInitFunc) iarrow_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "iArrow", &info, 0 ); } return( type ); } nip2-8.7.1/src/conversionview.c0000644000175000017500000002116513351443023013336 00000000000000/* display an image in a window ... watching an Image model. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GtkEventBoxClass *parent_class = NULL; /* Find max and min of visible area of image. */ static gboolean conversionview_findmaxmin( Imagemodel *imagemodel, double *min, double *max ) { Conversion *conv = imagemodel->conv; Rect a, b; conversion_disp_to_im_rect( conv, &imagemodel->visible, &a ); im_rect_intersectrect( &a, &conv->image, &b ); if( findmaxmin( imageinfo_get( FALSE, conv->ii ), b.left, b.top, b.width, b.height, min, max ) ) { error_top( _( "Unable to find image range." ) ); error_sub( _( "Find image range failed." ) ); error_vips(); return( FALSE ); } return( TRUE ); } static void conversionview_scale_cb( GtkWidget *wid, Conversionview *cv ) { Imagemodel *imagemodel = cv->imagemodel; double min, max; progress_begin(); if( !conversionview_findmaxmin( imagemodel, &min, &max ) ) { progress_end(); iwindow_alert( wid, GTK_MESSAGE_ERROR ); return; } progress_end(); if( max - min < 1e-20 ) { error_top( _( "Unable to scale image." ) ); error_sub( _( "Maximum and minimum pixel values are equal." ) ); iwindow_alert( wid, GTK_MESSAGE_ERROR ); return; } imagemodel->scale = 255.0 / (max - min); imagemodel->offset = -(min * imagemodel->scale); iobject_changed( IOBJECT( imagemodel ) ); } static void conversionview_falsecolour_cb( GtkWidget *wid, Conversionview *cv ) { Imagemodel *imagemodel = cv->imagemodel; GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM( wid ); imagemodel->falsecolour = item->active; iobject_changed( IOBJECT( imagemodel ) ); } static void conversionview_interpret_cb( GtkWidget *wid, Conversionview *cv ) { Imagemodel *imagemodel = cv->imagemodel; GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM( wid ); imagemodel->type = item->active; iobject_changed( IOBJECT( imagemodel ) ); } static void conversionview_reset_cb( GtkWidget *wid, Conversionview *cv ) { Imagemodel *imagemodel = cv->imagemodel; if( imagemodel->iimage ) { Row *row = HEAPMODEL( imagemodel->iimage )->row; imagemodel->scale = row->ws->scale; imagemodel->offset = row->ws->offset; } else { imagemodel->scale = 1.0; imagemodel->offset = 0.0; } imagemodel->falsecolour = FALSE; imagemodel->type = TRUE; iobject_changed( IOBJECT( imagemodel ) ); } static void conversionview_set_default_cb( GtkWidget *wid, Conversionview *cv ) { Imagemodel *imagemodel = cv->imagemodel; if( imagemodel->iimage ) { Row *row = HEAPMODEL( imagemodel->iimage )->row; row->ws->scale = imagemodel->scale; row->ws->offset = imagemodel->offset; } } static void conversionview_hide_cb( GtkWidget *wid, Conversionview *cv ) { Imagemodel *imagemodel = cv->imagemodel; imagemodel_set_convert( imagemodel, FALSE ); } static void conversionview_class_init( ConversionviewClass *class ) { parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ } /* Value changed in scale adjustment. */ static void conversionview_scale_change_cb( Tslider *tslider, Conversionview *cv ) { Imagemodel *imagemodel = cv->imagemodel; if( imagemodel->scale != tslider->value ) { imagemodel->scale = tslider->value; iobject_changed( IOBJECT( imagemodel ) ); } } /* Value changed in offset adjustment. */ static void conversionview_offset_change_cb( Tslider *tslider, Conversionview *cv ) { Imagemodel *imagemodel = cv->imagemodel; if( imagemodel->offset != tslider->value ) { imagemodel->offset = tslider->value; iobject_changed( IOBJECT( imagemodel ) ); } } static void conversionview_init( Conversionview *cv ) { Popupbutton *popupbutton; GtkWidget *hb; GtkWidget *sep; GtkWidget *pane; cv->imagemodel = NULL; gtk_frame_set_shadow_type( GTK_FRAME( cv ), GTK_SHADOW_OUT ); hb = gtk_hbox_new( FALSE, 2 ); gtk_container_set_border_width( GTK_CONTAINER( hb ), 2 ); gtk_container_add( GTK_CONTAINER( cv ), hb ); /* Build menu. One for each window, as we need to track falsecolour * etc. toggles. Could just have one, and modify pre-popup, but this * is easier. */ pane = menu_build( _( "Convert menu" ) ); menu_add_but( pane, _( "_Scale" ), GTK_SIGNAL_FUNC( conversionview_scale_cb ), cv ); cv->falsecolour = menu_add_tog( pane, _( "_False Color" ), GTK_SIGNAL_FUNC( conversionview_falsecolour_cb ), cv ); cv->type = menu_add_tog( pane, _( "_Interpret" ), GTK_SIGNAL_FUNC( conversionview_interpret_cb ), cv ); menu_add_but( pane, _( "_Reset" ), GTK_SIGNAL_FUNC( conversionview_reset_cb ), cv ); menu_add_but( pane, _( "Set As Workspace _Default" ), GTK_SIGNAL_FUNC( conversionview_set_default_cb ), cv ); menu_add_sep( pane ); menu_add_but( pane, GTK_STOCK_CLOSE, GTK_SIGNAL_FUNC( conversionview_hide_cb ), cv ); popupbutton = popupbutton_new(); popupbutton_set_menu( popupbutton, pane ); gtk_box_pack_start( GTK_BOX( hb ), GTK_WIDGET( popupbutton ), FALSE, FALSE, 0 ); cv->scale = tslider_new(); tslider_set_conversions( cv->scale, tslider_log_value_to_slider, tslider_log_slider_to_value ); cv->scale->from = 0.001; cv->scale->to = 255.0; cv->scale->value = 1.0; cv->scale->svalue = 128; cv->scale->digits = 3; tslider_changed( cv->scale ); gtk_box_pack_start( GTK_BOX( hb ), GTK_WIDGET( cv->scale ), TRUE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT( cv->scale ), "changed", GTK_SIGNAL_FUNC( conversionview_scale_change_cb ), cv ); tslider_set_ignore_scroll( cv->scale, FALSE ); sep = gtk_vseparator_new(); gtk_box_pack_start( GTK_BOX( hb ), sep, FALSE, FALSE, 0 ); cv->offset = tslider_new(); cv->offset->from = -128; cv->offset->to = 128; cv->offset->value = 0; cv->offset->svalue = 0; cv->offset->digits = 1; tslider_changed( cv->offset ); gtk_box_pack_start( GTK_BOX( hb ), GTK_WIDGET( cv->offset ), TRUE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT( cv->offset ), "changed", GTK_SIGNAL_FUNC( conversionview_offset_change_cb ), cv ); tslider_set_ignore_scroll( cv->offset, FALSE ); gtk_widget_show_all( hb ); } GtkType conversionview_get_type( void ) { static GtkType conversionview_type = 0; if( !conversionview_type ) { static const GtkTypeInfo sinfo = { "Conversionview", sizeof( Conversionview ), sizeof( ConversionviewClass ), (GtkClassInitFunc) conversionview_class_init, (GtkObjectInitFunc) conversionview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; conversionview_type = gtk_type_unique( GTK_TYPE_FRAME, &sinfo ); } return( conversionview_type ); } /* Our conversion has changed ... update. */ static void conversionview_changed_cb( Imagemodel *imagemodel, Conversionview *cv ) { GtkCheckMenuItem *item; widget_visible( GTK_WIDGET( cv ), imagemodel->show_convert ); if( !imagemodel->show_convert ) return; if( cv->scale->value != imagemodel->scale ) { cv->scale->value = imagemodel->scale; tslider_changed( cv->scale ); } if( cv->offset->value != imagemodel->offset ) { cv->offset->value = imagemodel->offset; tslider_changed( cv->offset ); } item = GTK_CHECK_MENU_ITEM( cv->falsecolour ); if( item->active != imagemodel->falsecolour ) gtk_check_menu_item_set_active( item, imagemodel->falsecolour ); item = GTK_CHECK_MENU_ITEM( cv->type ); if( item->active != imagemodel->type ) gtk_check_menu_item_set_active( item, imagemodel->type ); } static void conversionview_link( Conversionview *cv, Imagemodel *imagemodel ) { g_assert( !cv->imagemodel ); cv->imagemodel = imagemodel; g_signal_connect( G_OBJECT( cv->imagemodel ), "changed", G_CALLBACK( conversionview_changed_cb ), cv ); } Conversionview * conversionview_new( Imagemodel *imagemodel ) { Conversionview *cv = gtk_type_new( TYPE_CONVERSIONVIEW ); conversionview_link( cv, imagemodel ); return( cv ); } nip2-8.7.1/src/defbrowser.h0000644000175000017500000000373613351443023012431 00000000000000/* Def browser */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_DEFBROWSER (defbrowser_get_type()) #define DEFBROWSER( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_DEFBROWSER, Defbrowser )) #define DEFBROWSER_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_DEFBROWSER, DefbrowserClass )) #define IS_DEFBROWSER( obj ) \ (GTK_CHECK_TYPE( (obj), TYPE_DEFBROWSER )) #define IS_DEFBROWSER_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_DEFBROWSER )) typedef struct _Defbrowser { vObject parent_object; Program *program; /* Program whose kits we explore */ GtkListStore *store; /* Model for list view */ GtkTreeModel *filter; /* After filtering with search box */ GtkWidget *tree; /* Displayed tree */ GtkWidget *entry; /* Search widget */ GtkWidget *top; /* hbox for top bar */ } Defbrowser; typedef struct _DefbrowserClass { vObjectClass parent_class; } DefbrowserClass; GtkType defbrowser_get_type( void ); void defbrowser_set_program( Defbrowser *defbrowser, Program *program ); Defbrowser *defbrowser_new( void ); int defbrowser_get_width( Defbrowser *defbrowser ); void defbrowser_set_filter( Defbrowser *defbrowser, const char *filter ); nip2-8.7.1/src/iregiongroupview.h0000644000175000017500000000335013351443023013663 00000000000000/* coordinate the display of regionviews on imageviews */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IREGIONGROUPVIEW (iregiongroupview_get_type()) #define IREGIONGROUPVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_IREGIONGROUPVIEW, iRegiongroupview )) #define IREGIONGROUPVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_IREGIONGROUPVIEW, \ iRegiongroupviewClass )) #define IS_IREGIONGROUPVIEW( obj ) \ (GTK_CHECK_TYPE( (obj), TYPE_IREGIONGROUPVIEW )) #define IS_IREGIONGROUPVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_IREGIONGROUPVIEW )) typedef struct _iRegiongroupview { View parent_class; /* Keep our classmodel here, we need it during destroy. */ Classmodel *classmodel; } iRegiongroupview; typedef struct _iRegiongroupviewClass { ViewClass parent_class; /* My methods. */ } iRegiongroupviewClass; GtkType iregiongroupview_get_type( void ); View *iregiongroupview_new( void ); nip2-8.7.1/src/fontname.c0000644000175000017500000000556513351443023012073 00000000000000/* an input fontname ... put/get methods */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void fontname_finalize( GObject *gobject ) { Fontname *fontname = FONTNAME( gobject ); IM_FREE( fontname->value ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static View * fontname_view_new( Model *model, View *parent ) { return( fontnameview_new() ); } /* Members of fontname we automate. */ static ClassmodelMember fontname_members[] = { { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_CAPTION, "caption", N_( "Caption" ), G_STRUCT_OFFSET( iObject, caption ) }, { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Fontname, value ) } }; static void fontname_class_init( FontnameClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = fontname_finalize; model_class->view_new = fontname_view_new; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = fontname_members; classmodel_class->n_members = IM_NUMBER( fontname_members ); } static void fontname_init( Fontname *fontname ) { /* Overridden later. Just something sensible. */ fontname->value = NULL; IM_SETSTR( fontname->value, "Sans" ); iobject_set( IOBJECT( fontname ), CLASS_FONTNAME, NULL ); } GType fontname_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( FontnameClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) fontname_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Fontname ), 32, /* n_preallocs */ (GInstanceInitFunc) fontname_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Fontname", &info, 0 ); } return( type ); } nip2-8.7.1/src/expression.c0000644000175000017500000001060013351443023012445 00000000000000/* an editable expression */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; /* Sub fn. of below. */ static void * expression_get_itext_sub( Row *row ) { Model *itext; /* FIXME ... yuk, map + strcmp could make subcolumn indexed by symbol name? probably not worth it */ if( row->sym && strcmp( IOBJECT( row->sym )->name, MEMBER_EXPR ) == 0 && row->child_rhs && (itext = row->child_rhs->itext) ) return( itext ); return( NULL ); } /* Look down our RHS and try to grab the itext for our MEMBER_EXPR. * Expressionview presents this as the editable formula. * * We can't call the editable member "value", since this imples (elsewhere in * nip anway) an unboxed value. Our editable member could also be boxed .. so * have a different name of reduce confusion a little. Also means we can * define an Expression which inherits from expr. */ iText * expression_get_itext( Expression *expression ) { Row *row = HEAPMODEL( expression )->row; if( row->child_rhs && row->child_rhs->scol ) return( (iText *) subcolumn_map( SUBCOLUMN( row->child_rhs->scol ), (row_map_fn) expression_get_itext_sub, NULL, NULL ) ); return( NULL ); } static View * expression_view_new( Model *model, View *parent ) { return( expressionview_new() ); } static xmlNode * expression_save( Model *model, xmlNode *xnode ) { xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( !set_sprop( xthis, "caption", IOBJECT( model )->caption ) ) return( NULL ); return( xthis ); } static gboolean expression_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { char caption[MAX_STRSIZE]; g_assert( IS_RHS( parent ) ); if( get_sprop( xnode, "caption", caption, MAX_STRSIZE ) ) iobject_set( IOBJECT( model ), NULL, caption ); return( MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ); } /* Update Expression from heap. */ static gboolean expression_class_get( Classmodel *classmodel, PElement *root ) { char caption[MAX_STRSIZE]; #ifdef DEBUG printf( "expression_class_get: " ); row_name_print( HEAPMODEL( classmodel )->row ); printf( "\n" ); #endif /*DEBUG*/ if( !class_get_member_string( root, MEMBER_CAPTION, caption, MAX_STRSIZE ) ) return( FALSE ); iobject_set( IOBJECT( classmodel ), NULL, caption ); return( TRUE ); } static void expression_class_init( ExpressionClass *class ) { ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ model_class->view_new = expression_view_new; model_class->save = expression_save; model_class->load = expression_load; classmodel_class->class_get = expression_class_get; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void expression_init( Expression *expression ) { iobject_set( IOBJECT( expression ), CLASS_EXPRESSION, NULL ); } GType expression_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ExpressionClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) expression_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Expression ), 32, /* n_pexpressionlocs */ (GInstanceInitFunc) expression_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Expression", &info, 0 ); } return( type ); } nip2-8.7.1/src/workspacedefs.c0000644000175000017500000002121413351443023013111 00000000000000/* Workspace-local defs. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; static void workspacedefs_text_changed( GtkTextBuffer *buffer, Workspacedefs *workspacedefs ) { #ifdef DEBUG printf( "workspacedefs_text_changed\n" ); #endif /*DEBUG*/ if( !workspacedefs->changed ) { workspacedefs->changed = TRUE; #ifdef DEBUG printf( "\t(changed = TRUE)\n" ); #endif /*DEBUG*/ /* The workspace hasn't changed, but this will queue a refresh * on us. */ iobject_changed( IOBJECT( workspacedefs->ws ) ); } } static void workspacedefs_refresh( vObject *vobject ) { Workspacedefs *workspacedefs = WORKSPACEDEFS( vobject ); Workspace *ws = workspacedefs->ws; char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); #ifdef DEBUG printf( "workspacedefs_refresh:\n" ); #endif /*DEBUG*/ if( !workspacedefs->changed ) { guint text_hash = g_str_hash( ws->local_defs ); if( text_hash != workspacedefs->text_hash ) { g_signal_handlers_block_by_func( gtk_text_view_get_buffer( GTK_TEXT_VIEW( workspacedefs->text ) ), workspacedefs_text_changed, workspacedefs ); text_view_set_text( GTK_TEXT_VIEW( workspacedefs->text ), ws->local_defs, TRUE ); g_signal_handlers_unblock_by_func( gtk_text_view_get_buffer( GTK_TEXT_VIEW( workspacedefs->text ) ), workspacedefs_text_changed, workspacedefs ); workspacedefs->text_hash = text_hash; } } if( ws->local_kit ) { int n = icontainer_get_n_children( ICONTAINER( ws->local_kit ) ); vips_buf_appendf( &buf, ngettext( "%d definition", "%d definitions", n ), n ); } if( workspacedefs->errors ) { if( !vips_buf_is_empty( &buf ) ) vips_buf_appendf( &buf, ", " ); vips_buf_appendf( &buf, _( "errors" ) ); } if( workspacedefs->changed ) { if( !vips_buf_is_empty( &buf ) ) vips_buf_appendf( &buf, ", " ); vips_buf_appendf( &buf, _( "modified" ) ); } set_glabel( workspacedefs->status, "%s", vips_buf_all( &buf ) ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void workspacedefs_link( vObject *vobject, iObject *iobject ) { Workspacedefs *workspacedefs = WORKSPACEDEFS( vobject ); Workspace *ws = WORKSPACE( iobject ); g_assert( !workspacedefs->ws ); workspacedefs->ws = ws; VOBJECT_CLASS( parent_class )->link( vobject, iobject ); } static void workspacedefs_class_init( WorkspacedefsClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; parent_class = g_type_class_peek_parent( class ); vobject_class->refresh = workspacedefs_refresh; vobject_class->link = workspacedefs_link; } static gboolean workspacedefs_set_text_from_file( Workspacedefs *workspacedefs, const char *fname ) { Workspace *ws = workspacedefs->ws; workspacedefs->changed = FALSE; workspacedefs->errors = FALSE; if( !workspace_local_set_from_file( ws, fname ) ) { text_view_select_text( GTK_TEXT_VIEW( workspacedefs->text ), input_state.charpos - yyleng, input_state.charpos ); workspacedefs->errors = TRUE; return( FALSE ); } symbol_recalculate_all(); return( TRUE ); } /* Callback from load browser. */ static void workspacedefs_load_file_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Workspacedefs *workspacedefs = WORKSPACEDEFS( client ); char *fname; if( !(fname = filesel_get_filename( filesel )) ) { nfn( sys, IWINDOW_ERROR ); return; } if( !workspacedefs_set_text_from_file( workspacedefs, fname ) ) { g_free( fname ); nfn( sys, IWINDOW_ERROR ); return; } g_free( fname ); nfn( sys, IWINDOW_YES ); } static void workspacedefs_replace_cb( GtkWidget *wid, Workspacedefs *workspacedefs ) { GtkWidget *filesel; filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Replace Definition From File" ) ); filesel_set_flags( FILESEL( filesel ), FALSE, FALSE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_definition, 0 ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( wid ) ); filesel_set_done( FILESEL( filesel ), workspacedefs_load_file_cb, workspacedefs ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } static void workspacedefs_save_as_cb( GtkWidget *wid, Workspacedefs *workspacedefs ) { Workspace *ws = workspacedefs->ws; if( ws->local_kit ) filemodel_inter_saveas( IWINDOW( wid ), FILEMODEL( ws->local_kit ) ); } static gboolean workspacedefs_set_text( Workspacedefs *workspacedefs, const char *txt ) { Workspace *ws = workspacedefs->ws; workspacedefs->changed = FALSE; workspacedefs->errors = FALSE; workspacedefs->text_hash = g_str_hash( txt ); if( !workspace_local_set( ws, txt ) ) { text_view_select_text( GTK_TEXT_VIEW( workspacedefs->text ), input_state.charpos - yyleng, input_state.charpos ); workspacedefs->errors = TRUE; return( FALSE ); } symbol_recalculate_all(); return( TRUE ); } /* "Process" in defs area. */ static void workspacedefs_process_cb( GtkWidget *wid, Workspacedefs *workspacedefs ) { char *txt; #ifdef DEBUG printf( "workspacedefs_process_cb:\n" ); printf( "\tchanged = FALSE\n" ); #endif /*DEBUG*/ txt = text_view_get_text( GTK_TEXT_VIEW( workspacedefs->text ) ); if( !workspacedefs_set_text( workspacedefs, txt ) ) iwindow_alert( wid, GTK_MESSAGE_ERROR ); g_free( txt ); } static void workspacedefs_init( Workspacedefs *workspacedefs ) { GtkWidget *pane; Popupbutton *popupbutton; GtkWidget *swin; GtkWidget *hbox; GtkWidget *but; #ifdef DEBUG printf( "workspacedefs_init:\n" ); #endif /*DEBUG*/ workspacedefs->changed = FALSE; workspacedefs->errors = FALSE; workspacedefs->text_hash = 0; pane = menu_build( _( "Workspace definitions" ) ); menu_add_but( pane, _( "Replace From _File" ), GTK_SIGNAL_FUNC( workspacedefs_replace_cb ), workspacedefs ); menu_add_but( pane, GTK_STOCK_SAVE_AS, GTK_SIGNAL_FUNC( workspacedefs_save_as_cb ), workspacedefs ); hbox = gtk_hbox_new( FALSE, 7 ); gtk_box_pack_start( GTK_BOX( workspacedefs ), hbox, FALSE, FALSE, 0 ); gtk_widget_show( hbox ); popupbutton = popupbutton_new(); popupbutton_set_menu( popupbutton, pane ); gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( popupbutton ), FALSE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( popupbutton ) ); but = gtk_button_new_with_label( _( "Process" ) ); g_signal_connect( G_OBJECT( but ), "clicked", G_CALLBACK( workspacedefs_process_cb ), workspacedefs ); gtk_box_pack_start( GTK_BOX( hbox ), but, FALSE, FALSE, 0 ); gtk_widget_show( but ); workspacedefs->status = gtk_label_new( NULL ); gtk_misc_set_alignment( GTK_MISC( workspacedefs->status ), 0, 0.5 ); gtk_box_pack_start( GTK_BOX( hbox ), workspacedefs->status, TRUE, TRUE, 0 ); gtk_widget_show( workspacedefs->status ); swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_box_pack_end( GTK_BOX( workspacedefs ), swin, TRUE, TRUE, 0 ); gtk_widget_show( swin ); workspacedefs->text = program_text_new(); g_signal_connect( gtk_text_view_get_buffer( GTK_TEXT_VIEW( workspacedefs->text ) ), "changed", G_CALLBACK( workspacedefs_text_changed ), workspacedefs ); gtk_container_add( GTK_CONTAINER( swin ), workspacedefs->text ); gtk_widget_show( workspacedefs->text ); } GtkType workspacedefs_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Workspacedefs", sizeof( Workspacedefs ), sizeof( WorkspacedefsClass ), (GtkClassInitFunc) workspacedefs_class_init, (GtkObjectInitFunc) workspacedefs_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VOBJECT, &info ); } return( type ); } Workspacedefs * workspacedefs_new( void ) { Workspacedefs *workspacedefs = gtk_type_new( TYPE_WORKSPACEDEFS ); return( workspacedefs ); } nip2-8.7.1/src/icontainer.c0000644000175000017500000005220413415063137012414 00000000000000/* abstract base class for containers */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_SANITY #define DEBUG_VERBOSE #define DEBUG */ #include "ip.h" /* Our signals. */ enum { SIG_POS_CHANGED, /* Member has moved */ SIG_CHILD_ADD, /* iContainer is about to gain a child */ SIG_CHILD_REMOVE, /* iContainer is about to loose a child */ SIG_CURRENT, /* Make child current of parent */ SIG_CHILD_DETACH, /* Used as a pair to do reparent */ SIG_CHILD_ATTACH, SIG_LAST }; static iObjectClass *parent_class = NULL; static guint icontainer_signals[SIG_LAST] = { 0 }; int icontainer_get_n_children( iContainer *icontainer ) { return( g_slist_length( icontainer->children ) ); } iContainer * icontainer_get_nth_child( iContainer *icontainer, int n ) { return( ICONTAINER( g_slist_nth_data( icontainer->children, n ) ) ); } GSList * icontainer_get_children( iContainer *icontainer ) { return( g_slist_copy( icontainer->children ) ); } void * icontainer_map( iContainer *icontainer, icontainer_map_fn fn, void *a, void *b ) { return( slist_map2( icontainer->children, (SListMap2Fn) fn, a, b ) ); } void * icontainer_map3( iContainer *icontainer, icontainer_map3_fn fn, void *a, void *b, void *c ) { return( slist_map3( icontainer->children, (SListMap3Fn) fn, a, b, c ) ); } void * icontainer_map4( iContainer *icontainer, icontainer_map4_fn fn, void *a, void *b, void *c, void *d ) { return( slist_map4( icontainer->children, (SListMap4Fn) fn, a, b, c, d ) ); } void * icontainer_map5( iContainer *icontainer, icontainer_map5_fn fn, void *a, void *b, void *c, void *d, void *e ) { return( slist_map5( icontainer->children, (SListMap5Fn) fn, a, b, c, d, e ) ); } /* Map in reverse order. */ void * icontainer_map_rev( iContainer *icontainer, icontainer_map_fn fn, void *a, void *b ) { return( slist_map2_rev( icontainer->children, (SListMap2Fn) fn, a, b ) ); } /* Apply a function to a tree of icontainers, bottom up. */ void * icontainer_map_all( iContainer *icontainer, icontainer_map_fn fn, void *a ) { iContainer *result; if( (result = icontainer_map( icontainer, (icontainer_map_fn) icontainer_map_all, (void *) fn, a )) ) return( result ); return( fn( icontainer, a, NULL ) ); } void * icontainer_map2_all( iContainer *icontainer, icontainer_map_fn fn, void *a, void *b ) { iContainer *result; if( (result = icontainer_map3( icontainer, (icontainer_map3_fn) icontainer_map2_all, (void *) fn, a, b )) ) return( result ); return( fn( icontainer, a, b ) ); } void * icontainer_map3_all( iContainer *icontainer, icontainer_map3_fn fn, void *a, void *b, void *c ) { iContainer *result; if( (result = icontainer_map4( icontainer, (icontainer_map4_fn) icontainer_map3_all, (void *) fn, a, b, c )) ) return( result ); return( fn( icontainer, a, b, c ) ); } void * icontainer_map4_all( iContainer *icontainer, icontainer_map4_fn fn, void *a, void *b, void *c, void *d ) { iContainer *result; if( (result = icontainer_map5( icontainer, (icontainer_map5_fn) icontainer_map4_all, (void *) fn, a, b, c, d )) ) return( result ); return( fn( icontainer, a, b, c, d ) ); } /* Apply a function to the children of a icontainer. */ void * icontainer_map_all_intrans( iContainer *icontainer, icontainer_map_fn fn, void *a ) { return( icontainer_map( icontainer, (icontainer_map_fn) icontainer_map_all, (void *) fn, a ) ); } static void * icontainer_sanity_child( iContainer *child, iContainer *parent ) { g_assert( IS_ICONTAINER( child ) ); g_assert( IS_ICONTAINER( parent ) ); g_assert( child->parent == parent ); g_assert( child->pos >= 0 ); g_assert( g_slist_find( parent->children, child ) ); if( parent->child_hash ) g_assert( g_hash_table_lookup( parent->child_hash, IOBJECT( child )->name ) ); return( NULL ); } void icontainer_sanity( iContainer *icontainer ) { g_assert( IS_ICONTAINER( icontainer ) ); if( icontainer->parent ) icontainer_sanity_child( icontainer, icontainer->parent ); icontainer_map( icontainer, (icontainer_map_fn) icontainer_sanity_child, icontainer, NULL ); } static gint icontainer_pos_compare( iContainer *a, iContainer *b ) { return( a->pos - b->pos ); } void icontainer_pos_sort( iContainer *icontainer ) { icontainer->children = g_slist_sort( icontainer->children, (GCompareFunc) icontainer_pos_compare ); iobject_changed( IOBJECT( icontainer ) ); } static void * icontainer_pos_last_sub( iContainer *icontainer, int *max ) { if( icontainer->pos > *max ) *max = icontainer->pos; return( NULL ); } int icontainer_pos_last( iContainer *icontainer ) { int max = -1; icontainer_map( icontainer, (icontainer_map_fn) icontainer_pos_last_sub, &max, NULL ); return( max ); } static void * icontainer_pos_changed( iContainer *icontainer ) { #ifdef DEBUG printf( "icontainer_pos_changed: " ); iobject_print( IOBJECT( icontainer ) ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( icontainer ), icontainer_signals[SIG_POS_CHANGED], 0 ); return( NULL ); } static void * icontainer_pos_renumber_sub( iContainer *icontainer, int *n, GSList **changed ) { if( icontainer->pos != *n ) { icontainer->pos = *n; *changed = g_slist_prepend( *changed, icontainer ); } *n += 1; return( NULL ); } #ifdef DEBUG_VERBOSE static void * icontainer_print_element( iContainer *element, int *n ) { printf( "\t%3d) pos = %d ", *n, element->pos ); iobject_print( IOBJECT( element ) ); *n += 1; return( NULL ); } #endif /*DEBUG_VERBOSE*/ void icontainer_pos_renumber( iContainer *icontainer ) { int n = 0; GSList *changed; #ifdef DEBUG_VERBOSE { int i; printf( "icontainer_pos_renumber: " ); iobject_print( IOBJECT( icontainer ) ); printf( "\tbefore:\n" ); i = 0; icontainer_map( icontainer, (icontainer_map_fn) icontainer_print_element, &i, NULL ); } #endif /*DEBUG_VERBOSE*/ changed = NULL; icontainer_map( icontainer, (icontainer_map_fn) icontainer_pos_renumber_sub, &n, &changed ); /* Tell all the children that have been renumbered. */ #ifdef DEBUG_VERBOSE if( g_slist_length( changed ) > 1 ) { printf( "icontainer_pos_renumber: renumbering %d children! ", g_slist_length( changed ) ); iobject_print( IOBJECT( icontainer ) ); } #endif /*DEBUG_VERBOSE*/ slist_map( changed, (SListMapFn) icontainer_pos_changed, NULL ); g_slist_free( changed ); iobject_changed( IOBJECT( icontainer ) ); #ifdef DEBUG_VERBOSE { int i; printf( "icontainer_pos_renumber: " ); iobject_print( IOBJECT( icontainer ) ); printf( "\tafter:\n" ); i = 0; icontainer_map( icontainer, (icontainer_map_fn) icontainer_print_element, &i, NULL ); } #endif /*DEBUG_VERBOSE*/ } gint icontainer_name_compare( iContainer *a, iContainer *b ) { return( strcasecmp( IOBJECT( a )->name, IOBJECT( b )->name ) ); } void icontainer_custom_sort( iContainer *icontainer, GCompareFunc fn ) { icontainer->children = g_slist_sort( icontainer->children, fn ); icontainer_pos_renumber( icontainer ); iobject_changed( IOBJECT( icontainer ) ); } /* Add a child. */ void icontainer_child_add( iContainer *parent, iContainer *child, int pos ) { g_assert( IS_ICONTAINER( parent ) ); g_assert( IS_ICONTAINER( child ) ); #ifdef DEBUG_SANITY icontainer_sanity( parent ); icontainer_sanity( child ); #endif /*DEBUG_SANITY*/ g_signal_emit( G_OBJECT( parent ), icontainer_signals[SIG_CHILD_ADD], 0, child, pos ); #ifdef DEBUG_SANITY icontainer_sanity( parent ); icontainer_sanity( child ); #endif /*DEBUG_SANITY*/ } /* Add a child before another child. after == NULL means append. */ void icontainer_child_add_before( iContainer *parent, iContainer *child, iContainer *before ) { int pos; g_assert( !before || IS_ICONTAINER( before ) ); g_assert( !before || before->parent == parent ); pos = g_slist_index( parent->children, before ); icontainer_child_add( parent, child, pos ); } /* pos == 0 ... move to start * pos == -1 ... move to end * pos == n ... move before sibling at position n */ void icontainer_child_move( iContainer *child, int pos ) { iContainer *parent = child->parent; parent->children = g_slist_remove( parent->children, child ); if( pos >= 0 ) parent->children = g_slist_insert( parent->children, child, pos ); else parent->children = g_slist_append( parent->children, child ); icontainer_pos_renumber( parent ); iobject_changed( IOBJECT( child ) ); } void * icontainer_child_remove( iContainer *child ) { iContainer *parent; if( (parent = child->parent) ) { g_assert( ICONTAINER_IS_CHILD( parent, child ) ); #ifdef DEBUG printf( "icontainer_child_remove: (child %p)\n", child ); printf( "\tchild: %s \"%s\"\n", G_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ) ); #endif /*DEBUG*/ #ifdef DEBUG_SANITY icontainer_sanity( parent ); icontainer_sanity( child ); #endif /*DEBUG_SANITY*/ g_signal_emit( G_OBJECT( parent ), icontainer_signals[SIG_CHILD_REMOVE], 0, child ); #ifdef DEBUG_SANITY icontainer_sanity( parent ); #endif /*DEBUG_SANITY*/ } return( NULL ); } void icontainer_current( iContainer *parent, iContainer *child ) { g_assert( parent ); g_assert( !child || ICONTAINER_IS_CHILD( parent, child ) ); if( parent->current == child ) return; #ifdef DEBUG printf( "icontainer_current: (child %p)\n", child ); printf( "\tchild: %s \"%s\"\n", G_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ) ); #endif /*DEBUG*/ #ifdef DEBUG_SANITY icontainer_sanity( parent ); if( child ) icontainer_sanity( child ); #endif /*DEBUG_SANITY*/ g_signal_emit( G_OBJECT( parent ), icontainer_signals[SIG_CURRENT], 0, child ); #ifdef DEBUG_SANITY icontainer_sanity( parent ); if( child ) icontainer_sanity( child ); #endif /*DEBUG_SANITY*/ } iContainer * icontainer_next( iContainer *parent ) { iContainer *child; int i; if( !parent->children ) return( NULL ); if( !parent->current ) i = 0; else i = g_slist_index( parent->children, parent->current ) + 1; if( !(child = g_slist_nth_data( parent->children, i )) ) child = ICONTAINER( parent->children->data ); icontainer_current( parent, child ); return( child ); } void icontainer_reparent( iContainer *parent, iContainer *child, int pos ) { iContainer *old_parent = child->parent; g_assert( parent ); g_assert( child ); #ifdef DEBUG_SANITY icontainer_sanity( old_parent ); icontainer_sanity( parent ); icontainer_sanity( child ); #endif /*DEBUG_SANITY*/ /* These must always happen as a pair. */ g_signal_emit( G_OBJECT( old_parent ), icontainer_signals[SIG_CHILD_DETACH], 0, child ); g_signal_emit( G_OBJECT( parent ), icontainer_signals[SIG_CHILD_ATTACH], 0, child, pos ); icontainer_pos_renumber( parent ); iobject_changed( IOBJECT( parent ) ); iobject_changed( IOBJECT( old_parent ) ); iobject_changed( IOBJECT( child ) ); #ifdef DEBUG_SANITY icontainer_sanity( old_parent ); icontainer_sanity( parent ); icontainer_sanity( child ); #endif /*DEBUG_SANITY*/ } static void icontainer_dispose( GObject *gobject ) { iContainer *icontainer; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_ICONTAINER( gobject ) ); icontainer = ICONTAINER( gobject ); #ifdef DEBUG printf( "icontainer_dispose: (%p) %s \"%s\"\n", icontainer, G_OBJECT_TYPE_NAME( icontainer ), NN( IOBJECT( icontainer )->name ) ); #endif /*DEBUG*/ icontainer_map( icontainer, (icontainer_map_fn) icontainer_child_remove, NULL, NULL ); icontainer_child_remove( icontainer ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void icontainer_finalize( GObject *gobject ) { iContainer *icontainer; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_ICONTAINER( gobject ) ); icontainer = ICONTAINER( gobject ); IM_FREEF( g_hash_table_destroy, icontainer->child_hash ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void icontainer_info( iObject *iobject, VipsBuf *buf ) { iContainer *icontainer = ICONTAINER( iobject ); vips_buf_appendf( buf, "pos = \"%d\"\n", icontainer->pos ); IOBJECT_CLASS( parent_class )->info( iobject, buf ); } static void icontainer_real_pos_changed( iContainer *icontainer ) { } static void icontainer_link( iContainer *parent, iContainer *child, int pos ) { if( pos >= 0 ) parent->children = g_slist_insert( parent->children, child, pos ); else parent->children = g_slist_append( parent->children, child ); child->parent = parent; child->pos = pos; if( parent->child_hash ) { g_assert( !g_hash_table_lookup( parent->child_hash, IOBJECT( child )->name ) ); g_hash_table_insert( parent->child_hash, IOBJECT( child )->name, child ); } } static void icontainer_real_child_add( iContainer *parent, iContainer *child, int pos ) { iContainerClass *icontainer_class = ICONTAINER_GET_CLASS( child ); g_assert( IS_ICONTAINER( parent ) && IS_ICONTAINER( child ) ); g_assert( child->parent == NULL ); #ifdef DEBUG printf( "icontainer_real_child_add:\n\tparent " ); iobject_print( IOBJECT( parent ) ); printf( "\tchild " ); iobject_print( IOBJECT( child ) ); printf( "\tpos = %d\n", pos ); #endif /*DEBUG*/ icontainer_link( parent, child, pos ); g_object_ref( G_OBJECT( child ) ); iobject_sink( IOBJECT( child ) ); /* Renumber to get all the pos set. */ icontainer_pos_renumber( parent ); iobject_changed( IOBJECT( child ) ); /* We've made the link ... trigger the parent_add() on the child. */ icontainer_class->parent_add( child ); #ifdef DEBUG_VERBOSE printf( "icontainer_real_child_add: " ); iobject_print( IOBJECT( parent ) ); #endif /*DEBUG_VERBOSE*/ } static void icontainer_unlink( iContainer *child ) { iContainer *parent = child->parent; parent->children = g_slist_remove( parent->children, child ); child->parent = NULL; if( parent->child_hash ) { g_assert( g_hash_table_lookup( parent->child_hash, IOBJECT( child )->name ) ); g_hash_table_remove( parent->child_hash, IOBJECT( child )->name ); } } static void icontainer_real_child_remove( iContainer *parent, iContainer *child ) { iContainerClass *icontainer_child_class = ICONTAINER_GET_CLASS( child ); g_assert( IS_ICONTAINER( parent ) && IS_ICONTAINER( child ) ); #ifdef DEBUG printf( "icontainer_real_child_remove: parent %s \"%s\"; " "child %s \"%s\"\n", G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ), G_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ) ); #endif /*DEBUG*/ if( parent->current == child ) icontainer_current( parent, NULL ); /* We're about to break the link ... trigger the parent_remove() on * the child. */ icontainer_child_class->parent_remove( child ); icontainer_unlink( child ); UNREF( child ); iobject_changed( IOBJECT( parent ) ); } static void icontainer_real_parent_add( iContainer *child ) { #ifdef DEBUG printf( "icontainer_real_parent_add: child %s \"%s\"; " "parent %s \"%s\"\n", G_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ), G_OBJECT_TYPE_NAME( child->parent ), NN( IOBJECT( child->parent )->name ) ); #endif /*DEBUG*/ } static void icontainer_real_parent_remove( iContainer *child ) { #ifdef DEBUG { iContainer *parent = child->parent; printf( "icontainer_real_parent_remove: child %s \"%s\"; " "parent %s \"%s\"\n", G_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ), G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) ); } #endif /*DEBUG*/ } static void icontainer_real_current( iContainer *parent, iContainer *child ) { iContainer *old_current; g_assert( IS_ICONTAINER( parent ) ); g_assert( !child || IS_ICONTAINER( child ) ); g_assert( !child || ICONTAINER_IS_CHILD( parent, child ) ); #ifdef DEBUG printf( "icontainer_real_current: parent %s \"%s\"; " "child %s \"%s\"\n", G_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ), child ? G_OBJECT_TYPE_NAME( child ) : "NULL", child ? NN( IOBJECT( child )->name ) : "NULL" ); #endif /*DEBUG*/ old_current = parent->current; parent->current = child; if( old_current != child ) { if( old_current ) iobject_changed( IOBJECT( old_current ) ); if( child ) iobject_changed( IOBJECT( child ) ); iobject_changed( IOBJECT( parent ) ); } if( child ) model_front( MODEL( child ) ); } static void icontainer_real_child_detach( iContainer *parent, iContainer *child ) { g_assert( IS_ICONTAINER( parent ) ); g_assert( IS_ICONTAINER( child ) ); g_assert( child->parent != NULL ); g_assert( ICONTAINER_IS_CHILD( parent, child ) ); icontainer_unlink( child ); } static void icontainer_real_child_attach( iContainer *parent, iContainer *child, int pos ) { g_assert( IS_ICONTAINER( parent ) ); g_assert( IS_ICONTAINER( child ) ); g_assert( child->parent == NULL ); icontainer_link( parent, child, pos ); } static void icontainer_class_init( iContainerClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = icontainer_dispose; gobject_class->finalize = icontainer_finalize; iobject_class->info = icontainer_info; class->pos_changed = icontainer_real_pos_changed; class->child_add = icontainer_real_child_add; class->child_remove = icontainer_real_child_remove; class->parent_add = icontainer_real_parent_add; class->parent_remove = icontainer_real_parent_remove; class->current = icontainer_real_current; class->child_detach = icontainer_real_child_detach; class->child_attach = icontainer_real_child_attach; /* Create signals. */ icontainer_signals[SIG_POS_CHANGED] = g_signal_new( "pos_changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( iContainerClass, pos_changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); icontainer_signals[SIG_CHILD_ADD] = g_signal_new( "child_add", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( iContainerClass, child_add ), NULL, NULL, nip_VOID__OBJECT_INT, G_TYPE_NONE, 2, TYPE_ICONTAINER, GTK_TYPE_INT ); icontainer_signals[SIG_CHILD_REMOVE] = g_signal_new( "child_remove", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET( iContainerClass, child_remove ), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, TYPE_ICONTAINER ); icontainer_signals[SIG_CURRENT] = g_signal_new( "current", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET( iContainerClass, current ), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, TYPE_ICONTAINER ); icontainer_signals[SIG_CHILD_DETACH] = g_signal_new( "child_detach", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET( iContainerClass, child_detach ), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, TYPE_ICONTAINER ); icontainer_signals[SIG_CHILD_ATTACH] = g_signal_new( "child_attach", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( iContainerClass, child_attach ), NULL, NULL, nip_VOID__OBJECT_INT, G_TYPE_NONE, 2, TYPE_ICONTAINER, GTK_TYPE_INT ); #ifdef DEBUG_SANITY printf( "*** DEBUG_SANITY is on ... expect slowness\n" ); #endif /*DEBUG_SANITY*/ } static void icontainer_init( iContainer *icontainer ) { /* Init our instance fields. */ icontainer->children = NULL; icontainer->pos = -1; icontainer->parent = NULL; icontainer->child_hash = NULL; } GType icontainer_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( iContainerClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) icontainer_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( iContainer ), 32, /* n_preallocs */ (GInstanceInitFunc) icontainer_init, }; type = g_type_register_static( TYPE_IOBJECT, "iContainer", &info, 0 ); } return( type ); } /* Put the container into lookup-by-child-name mode. */ void icontainer_set_hash( iContainer *icontainer ) { /* Can only do this once just after startup, and before there are any * children. */ g_assert( !icontainer->children ); g_assert( !icontainer->child_hash ); icontainer->child_hash = g_hash_table_new( g_str_hash, g_str_equal ); } iContainer * icontainer_child_lookup( iContainer *parent, const char *name ) { g_assert( parent->child_hash ); return( ICONTAINER( g_hash_table_lookup( parent->child_hash, name ) ) ); } nip2-8.7.1/src/nipmarshal.c0000644000175000017500000001515113351443023012412 00000000000000#include "nipmarshal.h" #include #ifdef G_ENABLE_DEBUG #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) #define g_marshal_value_peek_char(v) g_value_get_char (v) #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) #define g_marshal_value_peek_int(v) g_value_get_int (v) #define g_marshal_value_peek_uint(v) g_value_get_uint (v) #define g_marshal_value_peek_long(v) g_value_get_long (v) #define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) #define g_marshal_value_peek_int64(v) g_value_get_int64 (v) #define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) #define g_marshal_value_peek_enum(v) g_value_get_enum (v) #define g_marshal_value_peek_flags(v) g_value_get_flags (v) #define g_marshal_value_peek_float(v) g_value_get_float (v) #define g_marshal_value_peek_double(v) g_value_get_double (v) #define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) #define g_marshal_value_peek_param(v) g_value_get_param (v) #define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) #define g_marshal_value_peek_object(v) g_value_get_object (v) #else /* !G_ENABLE_DEBUG */ /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. * Do not access GValues directly in your code. Instead, use the * g_value_get_*() functions */ #define g_marshal_value_peek_boolean(v) (v)->data[0].v_int #define g_marshal_value_peek_char(v) (v)->data[0].v_int #define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint #define g_marshal_value_peek_int(v) (v)->data[0].v_int #define g_marshal_value_peek_uint(v) (v)->data[0].v_uint #define g_marshal_value_peek_long(v) (v)->data[0].v_long #define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong #define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 #define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 #define g_marshal_value_peek_enum(v) (v)->data[0].v_long #define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong #define g_marshal_value_peek_float(v) (v)->data[0].v_float #define g_marshal_value_peek_double(v) (v)->data[0].v_double #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer #define g_marshal_value_peek_param(v) (v)->data[0].v_pointer #define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer #define g_marshal_value_peek_object(v) (v)->data[0].v_pointer #endif /* !G_ENABLE_DEBUG */ /* VOID:OBJECT,INT (nipmarshal.list:25) */ void nip_VOID__OBJECT_INT (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__OBJECT_INT) (gpointer data1, gpointer arg_1, gint arg_2, gpointer data2); register GMarshalFunc_VOID__OBJECT_INT callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__OBJECT_INT) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_object (param_values + 1), g_marshal_value_peek_int (param_values + 2), data2); } /* VOID:DOUBLE,DOUBLE (nipmarshal.list:26) */ void nip_VOID__DOUBLE_DOUBLE (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer data1, gdouble arg_1, gdouble arg_2, gpointer data2); register GMarshalFunc_VOID__DOUBLE_DOUBLE callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_double (param_values + 1), g_marshal_value_peek_double (param_values + 2), data2); } /* BOOLEAN:INT,INT (nipmarshal.list:27) */ void nip_BOOLEAN__INT_INT (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef gboolean (*GMarshalFunc_BOOLEAN__INT_INT) (gpointer data1, gint arg_1, gint arg_2, gpointer data2); register GMarshalFunc_BOOLEAN__INT_INT callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; gboolean v_return; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_BOOLEAN__INT_INT) (marshal_data ? marshal_data : cc->callback); v_return = callback (data1, g_marshal_value_peek_int (param_values + 1), g_marshal_value_peek_int (param_values + 2), data2); g_value_set_boolean (return_value, v_return); } nip2-8.7.1/src/rhsview.h0000644000175000017500000000325213351443023011747 00000000000000/* the rhs of a tallyrow ... group together everything to the right of the * button */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_RHSVIEW (rhsview_get_type()) #define RHSVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_RHSVIEW, Rhsview )) #define RHSVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_RHSVIEW, RhsviewClass )) #define IS_RHSVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_RHSVIEW )) #define IS_RHSVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_RHSVIEW )) struct _Rhsview { View item; Rowview *rview; View *graphic; /* Our three elements */ View *scol; View *itext; GtkWidget *table; /* Lay out elements in this */ RhsFlags flags; /* Last vis set we set */ }; typedef struct _RhsviewClass { ViewClass parent_class; /* My methods. */ } RhsviewClass; GtkType rhsview_get_type( void ); View *rhsview_new( void ); nip2-8.7.1/src/colourdisplay.h0000644000175000017500000000341213351443023013147 00000000000000/* subclass imagedisplay ... show a patch of plain colour from a 1x1 pixel * imageinfo */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_COLOURDISPLAY (colourdisplay_get_type()) #define COLOURDISPLAY( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_COLOURDISPLAY, Colourdisplay )) #define COLOURDISPLAY_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_COLOURDISPLAY, ColourdisplayClass )) #define IS_COLOURDISPLAY( obj ) (GTK_CHECK_TYPE( (obj), TYPE_COLOURDISPLAY )) #define IS_COLOURDISPLAY_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_COLOURDISPLAY )) typedef struct _Colourdisplay { Imagedisplay parent_class; /* Set this to indicate that we prefer to drag as text rather than * colour. */ gboolean drag_as_text; } Colourdisplay; typedef struct _ColourdisplayClass { ImagedisplayClass parent_class; /* My methods. */ } ColourdisplayClass; GtkType colourdisplay_get_type( void ); Colourdisplay *colourdisplay_new( Conversion *conv ); nip2-8.7.1/src/slider.c0000644000175000017500000000561113351443023011536 00000000000000/* an input slider ... put/get methods */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static View * slider_view_new( Model *model, View *parent ) { return( sliderview_new() ); } /* Members of slider we automate. */ static ClassmodelMember slider_members[] = { { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_CAPTION, "caption", N_( "Caption" ), G_STRUCT_OFFSET( iObject, caption ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, MEMBER_FROM, "from", N_( "From" ), G_STRUCT_OFFSET( Slider, from ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, MEMBER_TO, "to", N_( "To" ), G_STRUCT_OFFSET( Slider, to ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Slider, value ) } }; static void slider_class_init( SliderClass *class ) { ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ model_class->view_new = slider_view_new; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = slider_members; classmodel_class->n_members = IM_NUMBER( slider_members ); } static void slider_init( Slider *slider ) { /* Overridden later. Just something sensible. */ slider->from = 0; slider->to = 255; slider->value = 128; /* Need to set caption to something too, since it's an automated * member. */ iobject_set( IOBJECT( slider ), CLASS_SLIDER, "" ); } GType slider_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( SliderClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) slider_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Slider ), 32, /* n_preallocs */ (GInstanceInitFunc) slider_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Slider", &info, 0 ); } return( type ); } nip2-8.7.1/src/toolview.c0000644000175000017500000001653113351443023012127 00000000000000/* Manage toolviewkits and their display. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; /* Link menu items to toolview with this. */ static GQuark toolview_quark = 0; static Mainw * toolview_get_mainw( Toolview *tview ) { if( !tview->kview || !tview->kview->kitgview ) return( NULL ); return( tview->kview->kitgview->mainw ); } static Workspace * toolview_get_workspace( Toolview *tview ) { Mainw *mainw; if( !(mainw = toolview_get_mainw( tview )) ) return( NULL ); return( mainw_get_workspace( mainw ) ); } static Workspace * item_get_workspace( GtkWidget *item ) { Toolview *tview; if( !(tview = gtk_object_get_data_by_id( GTK_OBJECT( item ), toolview_quark )) ) return( NULL ); return( toolview_get_workspace( tview ) ); } static void toolview_destroy( GtkObject *object ) { Toolview *tview; g_return_if_fail( object != NULL ); g_return_if_fail( IS_TOOLVIEW( object ) ); tview = TOOLVIEW( object ); #ifdef DEBUG printf( "toolview_destroy: %p\n", object ); #endif /*DEBUG*/ DESTROY_GTK( tview->item ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void toolview_finalize( GObject *gobject ) { #ifdef DEBUG printf( "toolview_finalize: %p\n", gobject ); #endif /*DEBUG*/ G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void toolview_activate_cb( GtkWidget *widget, Toolitem *toolitem ) { Workspace *ws = item_get_workspace( widget ); switch( toolitem->tool->type ) { case TOOL_DIA: if( !workspace_merge_file( ws, FILEMODEL( toolitem->tool )->filename ) ) iwindow_alert( widget, GTK_MESSAGE_ERROR ); symbol_recalculate_all(); break; case TOOL_SYM: if( !workspace_add_action( ws, toolitem->name, toolitem->action, toolitem->action_sym->expr->compile->nparam ) ) iwindow_alert( widget, GTK_MESSAGE_ERROR ); break; default: g_assert( FALSE ); } } /* Flash help for a toolview. */ static void toolview_select_cb( GtkWidget *widget, Toolitem *toolitem ) { Workspace *ws = item_get_workspace( widget ); if( ws && toolitem->help ) workspace_set_status( ws, "%s", toolitem->help ); } /* Sub fn of below ... build a menu item for a TOOL_SYM. */ static GtkWidget * toolview_refresh_sub( Toolview *tview, Toolitem *toolitem, Workspace *ws, GtkWidget *menu ) { Mainw *mainw = toolview_get_mainw( tview ); GtkWidget *item; if( toolitem->is_separator ) item = gtk_menu_item_new(); else { item = gtk_image_menu_item_new_with_mnemonic( toolitem->label ); gtk_object_set_data_by_id( GTK_OBJECT( item ), toolview_quark, tview ); if( toolitem->icon ) gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM( item ), image_new_from_file( toolitem->icon ) ); if( !toolitem->is_pullright ) gtk_signal_connect( GTK_OBJECT( item ), "activate", GTK_SIGNAL_FUNC( toolview_activate_cb ), toolitem ); if( toolitem->help && !toolitem->is_pullright ) set_tooltip( item, "%s", toolitem->help ); gtk_signal_connect( GTK_OBJECT( item ), "select", GTK_SIGNAL_FUNC( toolview_select_cb ), toolitem ); /* Make a pullright and recurse if necessary */ if( toolitem->is_pullright ) { GtkWidget *submenu = gtk_menu_new(); GSList *p; gtk_menu_set_accel_group( GTK_MENU( submenu ), IWINDOW( mainw )->accel_group ); gtk_menu_set_accel_path( GTK_MENU( submenu ), toolitem->path ); for( p = toolitem->children; p; p = p->next ) { Toolitem *child = p->data; toolview_refresh_sub( tview, child, ws, submenu ); } gtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), submenu ); } } /* Is a top-level toolitem? */ if( toolitem == toolitem->tool->toolitem ) gtk_menu_shell_insert( GTK_MENU_SHELL( menu ), item, ICONTAINER( toolitem->tool )->pos + 1 ); else /* Submenus are always completely rebuilt, so we can just * append. */ gtk_menu_shell_append( GTK_MENU_SHELL( menu ), item ); gtk_widget_show( item ); return( item ); } /* Our widget has been destroyed. NULL out or pointer to it, to stop us * destroying it again later. */ void toolview_destroy_cb( GtkWidget *widget, Toolview *tview ) { g_assert( tview->item == widget ); tview->item = NULL; } /* Update toolview display. */ static void toolview_refresh( vObject *vobject ) { Toolview *tview = TOOLVIEW( vobject ); Workspace *ws = toolview_get_workspace( tview ); Tool *tool = TOOL( VOBJECT( tview )->iobject ); Toolkitview *kview = tview->kview; #ifdef DEBUG printf( "toolview_refresh: " ); iobject_print( VOBJECT( tview )->iobject ); #endif /*DEBUG*/ if( !toolview_quark ) toolview_quark = g_quark_from_static_string( "toolview_quark" ); DESTROY_GTK( tview->item ); if( tool->toolitem ) tview->item = toolview_refresh_sub( tview, tool->toolitem, ws, kview->menu ); if( tview->item ) gtk_signal_connect( GTK_OBJECT( tview->item ), "destroy", GTK_SIGNAL_FUNC( toolview_destroy_cb ), tview ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void toolview_link( View *view, Model *model, View *parent ) { Toolview *tview = TOOLVIEW( view ); Toolkitview *kview = TOOLKITVIEW( parent ); VIEW_CLASS( parent_class )->link( view, model, parent ); #ifdef DEBUG printf( "toolview_link: " ); iobject_print( VOBJECT( tview )->iobject ); #endif /*DEBUG*/ tview->kview = kview; } static void toolview_class_init( ToolviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass*) class; GObjectClass *gobject_class = (GObjectClass*) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = toolview_destroy; gobject_class->finalize = toolview_finalize; /* Create signals. */ /* Init methods. */ vobject_class->refresh = toolview_refresh; view_class->link = toolview_link; } static void toolview_init( Toolview *toolview ) { toolview->item = NULL; } GtkType toolview_get_type( void ) { static GtkType toolview_type = 0; if( !toolview_type ) { static const GtkTypeInfo toolview_info = { "Toolview", sizeof( Toolview ), sizeof( ToolviewClass ), (GtkClassInitFunc) toolview_class_init, (GtkObjectInitFunc) toolview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; toolview_type = gtk_type_unique( TYPE_VIEW, &toolview_info ); } return( toolview_type ); } View * toolview_new( void ) { Toolview *tview = gtk_type_new( TYPE_TOOLVIEW ); #ifdef DEBUG printf( "toolview_new: %p\n", tview ); #endif /*DEBUG*/ return( VIEW( tview ) ); } nip2-8.7.1/src/matrix.c0000644000175000017500000003735513351443023011572 00000000000000/* an input matrix */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void matrix_finalize( GObject *gobject ) { Matrix *matrix; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_MATRIX( gobject ) ); matrix = MATRIX( gobject ); #ifdef DEBUG printf( "matrix_finalize\n" ); #endif /*DEBUG*/ /* My instance finalize stuff. */ IM_FREE( matrix->value.coeff ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } /* Rearrange our model for a new width/height. */ gboolean matrix_value_resize( MatrixValue *value, int width, int height ) { double *coeff; int x, y, i; if( width == value->width && height == value->height ) return( TRUE ); if( !(coeff = IARRAY( NULL, width * height, double )) ) return( FALSE ); /* Set what we can with values from the old matrix. */ for( i = 0, y = 0; y < height; y++ ) for( x = 0; x < width; x++, i++ ) if( y < value->height && x < value->width ) coeff[i] = value->coeff[x + y * value->width]; else coeff[i] = 0.0; /* Install new values. */ IM_FREE( value->coeff ); value->coeff = coeff; value->width = width; value->height = height; return( TRUE ); } /* Widgets for matrix edit. */ typedef struct _MatrixEdit { iDialog *idlg; Matrix *matrix; GtkWidget *width; GtkWidget *height; GtkWidget *display; } MatrixEdit; /* Done button hit. */ /*ARGSUSED*/ static void matrix_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { MatrixEdit *eds = (MatrixEdit *) client; int width, height; /* Parse values. We have to scan before we resize in case we are * sizing smaller and we have unscanned changes at the edges. */ view_scan_all(); eds->matrix->display = (MatrixDisplayType) gtk_combo_box_get_active( GTK_COMBO_BOX( eds->display ) ); if( !get_geditable_pint( eds->width, &width ) || !get_geditable_pint( eds->height, &height ) || !matrix_value_resize( &eds->matrix->value, width, height ) ) { nfn( sys, IWINDOW_ERROR ); return; } /* Rebuild object. */ classmodel_update( CLASSMODEL( eds->matrix ) ); symbol_recalculate_all(); nfn( sys, IWINDOW_YES ); } /* Build the insides of matrix edit. */ static void matrix_buildedit( iDialog *idlg, GtkWidget *work, MatrixEdit *eds ) { Matrix *matrix = eds->matrix; GtkSizeGroup *group; /* Index with MatrixType. */ static const char *display_names[] = { N_( "Text" ), N_( "Sliders" ), N_( "Toggle buttons" ), N_( "Text, plus scale and offset" ) }; group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL ); eds->width = build_glabeltext4( work, group, "Width" ); idialog_init_entry( idlg, eds->width, "Width of matrix", "%d", matrix->value.width ); eds->height = build_glabeltext4( work, group, "Height" ); idialog_init_entry( idlg, eds->height, "Height of matrix", "%d", matrix->value.height ); eds->display = build_goption( work, group, _( "Display as" ), display_names, IM_NUMBER( display_names ), NULL, NULL ); gtk_combo_box_set_active( GTK_COMBO_BOX( eds->display ), matrix->display ); UNREF( group ); gtk_widget_show_all( work ); } static View * matrix_view_new( Model *model, View *parent ) { return( matrixview_new() ); } /* Pop up a matrix edit box. */ static void matrix_edit( GtkWidget *parent, Model *model ) { Matrix *matrix = MATRIX( model ); MatrixEdit *eds = INEW( NULL, MatrixEdit ); GtkWidget *idlg; eds->matrix = matrix; idlg = idialog_new(); iwindow_set_title( IWINDOW( idlg ), _( "Edit %s %s" ), IOBJECT_GET_CLASS_NAME( model ), IOBJECT( HEAPMODEL( model )->row )->name ); idialog_set_build( IDIALOG( idlg ), (iWindowBuildFn) matrix_buildedit, eds, NULL, NULL ); idialog_set_callbacks( IDIALOG( idlg ), iwindow_true_cb, NULL, idialog_free_client, eds ); idialog_add_ok( IDIALOG( idlg ), matrix_done_cb, _( "Set %s" ), IOBJECT_GET_CLASS_NAME( model ) ); iwindow_set_parent( IWINDOW( idlg ), parent ); idialog_set_iobject( IDIALOG( idlg ), IOBJECT( model ) ); iwindow_build( IWINDOW( idlg ) ); gtk_widget_show( GTK_WIDGET( idlg ) ); } static gboolean matrix_graphic_save( Classmodel *classmodel, GtkWidget *parent, const char *filename ) { Matrix *matrix = MATRIX( classmodel ); DOUBLEMASK *dmask; char buf[FILENAME_MAX]; if( !(dmask = matrix_model_to_dmask( matrix )) ) return( FALSE ); /* We don't want $VAR etc. in the filename we pass down to the file * ops. */ im_strncpy( buf, filename, FILENAME_MAX ); path_expand( buf ); if( im_write_dmask_name( dmask, buf ) ) { error_vips_all(); IM_FREEF( im_free_dmask, dmask ); return( FALSE ); } IM_FREEF( im_free_dmask, dmask ); mainw_recent_add( &mainw_recent_matrix, filename ); return( TRUE ); } static gboolean matrix_graphic_replace( Classmodel *classmodel, GtkWidget *parent, const char *filename ) { Matrix *matrix = MATRIX( classmodel ); Row *row = HEAPMODEL( matrix )->row; iText *itext = ITEXT( HEAPMODEL( matrix )->rhs->itext ); DOUBLEMASK *dmask; char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); /* We don't want $VAR etc. in the filename we pass down to the file * ops. */ im_strncpy( txt, filename, FILENAME_MAX ); path_expand( txt ); if( !(dmask = im_read_dmask( txt )) ) { error_vips_all(); return( FALSE ); } matrix_dmask_to_ip( dmask, &buf ); im_free_dmask( dmask ); if( itext_set_formula( itext, vips_buf_all( &buf ) ) ) { itext_set_edited( itext, TRUE ); (void) expr_dirty( row->expr, link_serial_new() ); } mainw_recent_add( &mainw_recent_matrix, filename ); return( TRUE ); } /* Members of matrix we automate. */ static ClassmodelMember matrix_members[] = { { CLASSMODEL_MEMBER_MATRIX, NULL, 0, MEMBER_VALUE, NULL, N_( "Value" ), G_STRUCT_OFFSET( Matrix, value ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, MEMBER_SCALE, "scale", N_( "Scale" ), G_STRUCT_OFFSET( Matrix, scale ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, MEMBER_OFFSET, "offset", N_( "Offset" ), G_STRUCT_OFFSET( Matrix, offset ) }, { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_FILENAME, "filename", N_( "Filename" ), G_STRUCT_OFFSET( Classmodel, filename ) }, { CLASSMODEL_MEMBER_ENUM, NULL, MATRIX_DISPLAY_LAST - 1, MEMBER_DISPLAY, "display", N_( "Display" ), G_STRUCT_OFFSET( Matrix, display ) } }; static void matrix_class_init( MatrixClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->finalize = matrix_finalize; iobject_class->user_name = _( "Matrix" ); model_class->view_new = matrix_view_new; model_class->edit = matrix_edit; classmodel_class->graphic_save = matrix_graphic_save; classmodel_class->graphic_replace = matrix_graphic_replace; classmodel_class->filetype = filesel_type_matrix; classmodel_class->filetype_pref = "MATRIX_FILE_TYPE"; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = matrix_members; classmodel_class->n_members = IM_NUMBER( matrix_members ); } static void matrix_init( Matrix *matrix ) { #ifdef DEBUG printf( "matrix_init\n" ); #endif /*DEBUG*/ matrix->value.coeff = NULL; matrix->value.width = 0; matrix->value.height = 0; matrix->display = MATRIX_DISPLAY_TEXT; matrix->scale = 1.0; matrix->offset = 0.0; matrix->selected = FALSE; iobject_set( IOBJECT( matrix ), CLASS_MATRIX, NULL ); } GtkType matrix_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( MatrixClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) matrix_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Matrix ), 32, /* n_preallocs */ (GInstanceInitFunc) matrix_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Matrix", &info, 0 ); } return( type ); } void matrix_select( Matrix *matrix, int left, int top, int width, int height ) { if( !matrix->selected || matrix->range.left != left || matrix->range.top != top || matrix->range.width != width || matrix->range.height != height ) { Row *row = HEAPMODEL( matrix )->row; #ifdef DEBUG printf( "matrix_select: " "left=%d, top = %d, width = %d, height = %d\n", left, top, width, height ); #endif /*DEBUG*/ matrix->selected = TRUE; matrix->range.left = left; matrix->range.top = top; matrix->range.width = width; matrix->range.height = height; iobject_changed( IOBJECT( matrix ) ); /* Also make sure this row is selected. */ row_select_ensure( row ); /* The range of cells selected has changed, so the workspace * must update the status line too. row_select_ensure() only * spots row on/off selects. Yuk! */ iobject_changed( IOBJECT( row->ws ) ); } } void matrix_deselect( Matrix *matrix ) { if( matrix->selected ) { Row *row = HEAPMODEL( matrix )->row; #ifdef DEBUG printf( "matrix_deselect\n" ); #endif /*DEBUG*/ matrix->selected = FALSE; iobject_changed( IOBJECT( matrix ) ); /* Also make sure this row is not selected. */ row_deselect( row ); } } /* Guess a display type from a filename. */ static int matrix_guess_display( const char *fname ) { /* Choose display type based on filename suffix ... rec * displays as 1, mor displays as 2, .con displays as 3, all others * display as 0. Keep in sync with MatrixDisplayType. */ static const FileselFileType *types[] = { &filesel_xfile_type, // matrix &filesel_rfile_type, // recombination &filesel_mfile_type, // morphology &filesel_cfile_type // convolution }; int i; if( !fname ) return( 0 ); for( i = 0; i < IM_NUMBER( types ); i++ ) if( is_file_type( types[i], fname ) ) return( i ); return( 0 ); } /* Make an ip definition out of a DOUBLEMASK. */ void matrix_dmask_to_ip( DOUBLEMASK *dmask, VipsBuf *buf ) { int x, y; /* Build matrix expression. */ vips_buf_appends( buf, CLASS_MATRIX " " ); vips_buf_appends( buf, "[" ); for( y = 0; y < dmask->ysize; y++ ) { vips_buf_appends( buf, "[" ); for( x = 0; x < dmask->xsize; x++ ) { vips_buf_appendf( buf, "%g", dmask->coeff[x + y*dmask->xsize] ); if( x != dmask->xsize - 1 ) vips_buf_appends( buf, "," ); } vips_buf_appends( buf, "]" ); if( y != dmask->ysize - 1 ) vips_buf_appends( buf, "," ); } vips_buf_appends( buf, "]" ); vips_buf_appendf( buf, "(%g) (%g) \"%s\" %d", dmask->scale, dmask->offset, dmask->filename, matrix_guess_display( dmask->filename ) ); } /* Make a heap object out of a DOUBLEMASK. */ gboolean matrix_dmask_to_heap( Heap *heap, DOUBLEMASK *dmask, PElement *out ) { Symbol *sym = compile_lookup( symbol_root->expr->compile, CLASS_MATRIX ); PElement rhs; if( !sym || !sym->expr || !sym->expr->compile || !heap_copy( heap, sym->expr->compile, out ) ) return( FALSE ); if( !heap_appl_add( heap, out, &rhs ) || !heap_matrix_new( heap, dmask->xsize, dmask->ysize, dmask->coeff, &rhs ) || !heap_appl_add( heap, out, &rhs ) || !heap_real_new( heap, dmask->scale, &rhs ) || !heap_appl_add( heap, out, &rhs ) || !heap_real_new( heap, dmask->offset, &rhs ) || !heap_appl_add( heap, out, &rhs ) || !heap_managedstring_new( heap, dmask->filename, &rhs ) || !heap_appl_add( heap, out, &rhs ) || !heap_real_new( heap, matrix_guess_display( dmask->filename ), &rhs ) ) return( FALSE ); return( TRUE ); } /* Cast an IMASK to a DMASK. */ DOUBLEMASK * matrix_imask_to_dmask( INTMASK *imask ) { DOUBLEMASK *dmask; int i; if( !(dmask = im_create_dmask( imask->filename, imask->xsize, imask->ysize )) ) { error_vips_all(); return( NULL ); } dmask->scale = imask->scale; dmask->offset = imask->offset; for( i = 0; i < imask->xsize * imask->ysize; i++ ) dmask->coeff[i] = imask->coeff[i]; return( dmask ); } /* Cast a DMASK to an IMASK. */ INTMASK * matrix_dmask_to_imask( DOUBLEMASK *dmask ) { INTMASK *imask; int i; if( !(imask = im_create_imask( dmask->filename, dmask->xsize, dmask->ysize )) ) { error_vips_all(); return( NULL ); } imask->scale = dmask->scale; imask->offset = dmask->offset; for( i = 0; i < dmask->xsize * dmask->ysize; i++ ) imask->coeff[i] = dmask->coeff[i]; return( imask ); } /* Make a heap object out of an INTMASK. */ gboolean matrix_imask_to_heap( Heap *heap, INTMASK *imask, PElement *out ) { DOUBLEMASK *dmask; if( !(dmask = matrix_imask_to_dmask( imask )) ) return( FALSE ); if( !matrix_dmask_to_heap( heap, dmask, out ) ) { im_free_dmask( dmask ); return( FALSE ); } im_free_dmask( dmask ); return( TRUE ); } /* Make a DOUBLEMASK out of an ip value. */ DOUBLEMASK * matrix_ip_to_dmask( PElement *root ) { char buf[MAX_STRSIZE]; char name[FILENAME_MAX]; DOUBLEMASK *dmask; double scale, offset; char *filename; int width, height; if( !class_get_member_matrix_size( root, MEMBER_VALUE, &width, &height ) ) return( NULL ); if( class_get_member_string( root, MEMBER_FILENAME, buf, MAX_STRSIZE ) ) filename = buf; else { if( !temp_name( name, "mat" ) ) return( NULL ); filename = name; } if( !(dmask = im_create_dmask( filename, width, height )) ) { error_vips_all(); return( NULL ); } if( !class_get_member_matrix( root, MEMBER_VALUE, dmask->coeff, width * height, &width, &height ) ) { IM_FREEF( im_free_dmask, dmask ); return( FALSE ); } if( !class_get_member_real( root, MEMBER_SCALE, &scale ) ) scale = 1.0; if( !class_get_member_real( root, MEMBER_OFFSET, &offset ) ) offset = 0.0; dmask->scale = scale; dmask->offset = offset; return( dmask ); } /* Make an INTMASK out of an ip value. */ INTMASK * matrix_ip_to_imask( PElement *root ) { DOUBLEMASK *dmask; INTMASK *imask; if( !(dmask = matrix_ip_to_dmask( root )) ) return( NULL ); if( !(imask = matrix_dmask_to_imask( dmask )) ) { IM_FREEF( im_free_dmask, dmask ); return( NULL ); } return( imask ); } DOUBLEMASK * matrix_model_to_dmask( Matrix *matrix ) { DOUBLEMASK *dmask; int i; if( !(dmask = im_create_dmask( CLASSMODEL( matrix )->filename, matrix->value.width, matrix->value.height )) ) { error_vips_all(); return( NULL ); } dmask->scale = matrix->scale; dmask->offset = matrix->offset; for( i = 0; i < matrix->value.width * matrix->value.height; i++ ) dmask->coeff[i] = matrix->value.coeff[i]; return( dmask ); } gboolean matrix_dmask_to_model( Matrix *matrix, DOUBLEMASK *dmask ) { int i; if( !matrix_value_resize( &matrix->value, dmask->xsize, dmask->ysize ) ) return( FALSE ); matrix->scale = dmask->scale; matrix->offset = dmask->offset; for( i = 0; i < matrix->value.width * matrix->value.height; i++ ) matrix->value.coeff[i] = dmask->coeff[i]; matrix->display = (MatrixDisplayType) matrix_guess_display( dmask->filename ); IM_SETSTR( CLASSMODEL( matrix )->filename, dmask->filename ); return( TRUE ); } nip2-8.7.1/src/call.c0000644000175000017500000007757313351443023011207 00000000000000/* Call vips functions from the graph reducer. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with CALL - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG_TIME #define DEBUG */ /* This is usually turned on from a -D in cflags. #define DEBUG_LEAK */ /* Often want it off ... we get spurious complaints about leaks if an * operation has no images in or out (eg. im_version) because it'll never * get GCed. #undef DEBUG_LEAK */ /* CALL argument types we support. Keep order in sync with CallArgumentType. */ static im_arg_type call_supported[] = { IM_TYPE_DOUBLE, IM_TYPE_INT, IM_TYPE_COMPLEX, IM_TYPE_STRING, IM_TYPE_IMAGE, IM_TYPE_DOUBLEVEC, IM_TYPE_DMASK, IM_TYPE_IMASK, IM_TYPE_IMAGEVEC, IM_TYPE_INTVEC, IM_TYPE_GVALUE, IM_TYPE_INTERPOLATE }; static iObjectClass *parent_class = NULL; /* All the CallInfo we make ... for leak and sanity testing. Build this file * with DEBUG_LEAK to enable add/remove to this list. */ GSList *call_info_all = NULL; void call_check_all_destroyed( void ) { #ifdef DEBUG_LEAK int n_leaks; GSList *p; n_leaks = 0; for( p = call_info_all; p; p = p->next ) { CallInfo *vi = (CallInfo *) p->data; /* Operations which don't take an image as either an input or * output will stay in the cache. Don't report them. */ if( vi->ninii || vi->noutii ) { n_leaks += 1; printf( "\t%s\n", vi->name ); } } if( n_leaks ) printf( "** %d CallInfo leaked!\n", n_leaks ); #endif /*DEBUG_LEAK*/ } /* Does a vips argument type require an argument from nip2? */ gboolean call_type_needs_input( im_type_desc *ty ) { /* We supply these. */ if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) return( FALSE ); if( !(ty->flags & IM_TYPE_OUTPUT) ) return( TRUE ); if( ty->flags & IM_TYPE_RW ) return( TRUE ); return( FALSE ); } /* Will a vips argument type generate a result for nip2? */ gboolean call_type_makes_output( im_type_desc *ty ) { /* We ignore these. */ if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) return( FALSE ); if( ty->flags & (IM_TYPE_OUTPUT | IM_TYPE_RW) ) return( TRUE ); return( FALSE ); } /* Error early on .. we can't print args yet. */ void call_error( CallInfo *vi ) { error_top( _( "CALL library error." ) ); error_sub( _( "Error calling library function \"%s\" (%s)." ), vi->name, vi->fn->desc ); } /* Get the args from the heap. */ static void call_args_heap( CallInfo *vi, HeapNode **arg, VipsBuf *buf ) { int i; vips_buf_appendf( buf, _( "You passed:" ) ); vips_buf_appendf( buf, "\n" ); for( i = 0; i < vi->nargs; i++ ) { im_arg_desc *varg = &vi->fn->argv[vi->inpos[i]]; PElement rhs; PEPOINTRIGHT( arg[vi->nargs - i - 1], &rhs ); vips_buf_appendf( buf, " %s - ", varg->name ); itext_value_ev( vi->rc, buf, &rhs ); vips_buf_appendf( buf, "\n" ); } } /* Make a usage error for a CALL function. */ void call_usage( VipsBuf *buf, im_function *fn ) { im_package *pack = im_package_of_function( fn->name ); char input[MAX_STRSIZE]; char output[MAX_STRSIZE]; int nout, nin; int i; strcpy( input, "" ); strcpy( output, "" ); nin = 0; nout = 0; for( i = 0; i < fn->argc; i++ ) { im_arg_desc *arg = &fn->argv[i]; char line[256]; /* Format name, type message. */ im_snprintf( line, 256, " %s - %s\n", arg->name, arg->desc->type ); if( call_type_makes_output( arg->desc ) ) { strcat( output, line ); nout++; } if( call_type_needs_input( arg->desc ) ) { strcat( input, line ); nin++; } } vips_buf_appendf( buf, _( "Usage:" ) ); vips_buf_appends( buf, "\n" ); vips_buf_appendf( buf, _( "CALL operator \"%s\"" ), fn->name ); vips_buf_appends( buf, "\n" ); vips_buf_appendf( buf, _( "%s, from package \"%s\"" ), fn->desc, pack->name ); vips_buf_appends( buf, "\n" ); vips_buf_appendf( buf, ngettext( "\"%s\" takes %d argument:", "\"%s\" takes %d arguments:", nin ), fn->name, nin ); vips_buf_appendf( buf, "\n%s", input ); vips_buf_appendf( buf, ngettext( "And produces %d result:", "And produces %d results:", nout ), nout ); vips_buf_appendf( buf, "\n%s", output ); /* Print any flags this function has. */ vips_buf_appendf( buf, _( "Flags:" ) ); vips_buf_appends( buf, "\n" ); vips_buf_appendf( buf, " (" ); if( fn->flags & IM_FN_PIO ) vips_buf_appendf( buf, _( "PIO function" ) ); else vips_buf_appendf( buf, _( "WIO function" ) ); vips_buf_appendf( buf, ") (" ); if( fn->flags & IM_FN_TRANSFORM ) vips_buf_appendf( buf, _( "coordinate transformer" ) ); else vips_buf_appendf( buf, _( "no coordinate transformation" ) ); vips_buf_appendf( buf, ") (" ); if( fn->flags & IM_FN_PTOP ) vips_buf_appendf( buf, _( "point-to-point operation" ) ); else vips_buf_appendf( buf, _( "area operation" ) ); vips_buf_appendf( buf, ") (" ); if( fn->flags & IM_FN_NOCACHE ) vips_buf_appendf( buf, _( "uncacheable operation" ) ); else vips_buf_appendf( buf, _( "operation can be cached" ) ); vips_buf_appendf( buf, ")\n" ); } /* We know there's a problem exporting a particular arg to CALL. */ static void call_error_arg( CallInfo *vi, HeapNode **arg, int argi ) { char txt[10000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); error_top( _( "Bad argument." ) ); vips_buf_appendf( &buf, _( "Argument %d (%s) to \"%s\" is the wrong type." ), argi + 1, vi->fn->argv[vi->inpos[argi]].name, vi->name ); vips_buf_appendf( &buf, "\n" ); call_args_heap( vi, arg, &buf ); vips_buf_appendf( &buf, "\n" ); call_usage( &buf, vi->fn ); error_sub( "%s", vips_buf_all( &buf ) ); } /* Too many args. */ void call_error_toomany( CallInfo *vi ) { char txt[1000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); error_top( _( "Too many arguments." ) ); vips_buf_appendf( &buf, _( "Too many arguments to \"%s\"." ), vi->name ); vips_buf_appendf( &buf, "\n" ); call_usage( &buf, vi->fn ); error_sub( "%s", vips_buf_all( &buf ) ); } /* Look up a CALL type. */ CallArgumentType call_lookup_type( im_arg_type type ) { int i; for( i = 0; i < IM_NUMBER( call_supported ); i++ ) if( strcmp( type, call_supported[i] ) == 0 ) return( (CallArgumentType) i ); error_top( _( "Unknown type." ) ); error_sub( _( "CALL type \"%s\" not supported" ), type ); return( CALL_NONE ); } /* Is this the sort of CALL function we can call? */ gboolean call_is_callable( im_function *fn ) { int i; int nout; int nin; if( fn->argc >= MAX_CALL_ARGS ) return( FALSE ); /* Check all argument types are supported. As well as the arg types * spotted by call_lookup_type, we also allow IM_TYPE_DISPLAY. */ for( i = 0; i < fn->argc; i++ ) { im_arg_desc *arg = &fn->argv[i]; im_arg_type vt = arg->desc->type; if( call_lookup_type( vt ) == CALL_NONE ) { /* Unknown type .. if DISPLAY it's OK. */ if( strcmp( vt, IM_TYPE_DISPLAY ) != 0 ) return( FALSE ); } } nin = nout = 0; for( i = 0; i < fn->argc; i++ ) { im_type_desc *ty = fn->argv[i].desc; if( call_type_makes_output( ty ) ) nout += 1; if( call_type_needs_input( ty ) ) nin += 1; } /* Must be at least one output argument. */ /* Must be at least one output argument. */ if( nout == 0 ) return( FALSE ); /* Need at least 1 input argument: we reply on having an application * node to overwrite with (I result). */ if( nin == 0 ) return( FALSE ); return( TRUE ); } /* Count the number of args a CALL function needs. */ int call_n_args( im_function *fn ) { int i; int nin; for( nin = 0, i = 0; i < fn->argc; i++ ) { im_type_desc *ty = fn->argv[i].desc; if( call_type_needs_input( ty ) ) nin += 1; } return( nin ); } /* Make an im_doublevec_object. */ static int call_make_doublevec( im_doublevec_object *dv, int n, double *vec ) { int i; dv->n = n; dv->vec = NULL; if( n > 0 ) { if( !(dv->vec = IARRAY( NULL, n, double )) ) return( -1 ); for( i = 0; i < n; i++ ) dv->vec[i] = vec[i]; } return( 0 ); } /* Make an im_intvec_object. Make from a vec of doubles, because that's what * we get from nip. */ static int call_make_intvec( im_intvec_object *dv, int n, double *vec ) { int i; dv->n = n; dv->vec = NULL; if( n > 0 ) { if( !(dv->vec = IARRAY( NULL, n, int )) ) return( -1 ); for( i = 0; i < n; i++ ) dv->vec[i] = vec[i]; } return( 0 ); } /* Make an im_imagevec_object. */ static int call_make_imagevec( im_imagevec_object *iv, int n ) { int i; iv->n = n; iv->vec = NULL; if( n > 0 ) { if( !(iv->vec = IARRAY( NULL, n, IMAGE * )) ) return( -1 ); for( i = 0; i < n; i++ ) iv->vec[i] = NULL; } return( 0 ); } /* Add another ii to inii. */ static gboolean call_add_input_ii( CallInfo *vi, Imageinfo *ii ) { if( vi->ninii > MAX_CALL_ARGS ) { call_error_toomany( vi ); return( FALSE ); } vi->inii[vi->ninii] = ii; vi->ninii += 1; /* We hold a ref to the ii until the call is done and the result * written back to nip2. If we cache the result, we make a new * weakref. */ managed_dup_nonheap( MANAGED( ii ) ); vi->must_drop = TRUE; return( TRUE ); } /* ip types -> CALL types. Write to obj. FALSE for no conversion possible. */ static gboolean call_fromip( CallInfo *vi, int i, PElement *arg ) { im_type_desc *ty = vi->fn->argv[i].desc; CallArgumentType vt = call_lookup_type( ty->type ); im_object *obj = &vi->vargv[i]; /* If call_lookup_type failed, is it the special DISPLAY type? */ if( vt == CALL_NONE && strcmp( ty->type, IM_TYPE_DISPLAY ) != 0 ) /* Unknown type, and it's not DISPLAY. Flag an error. */ return( FALSE ); switch( vt ) { case CALL_NONE: /* IM_TYPE_DISPLAY */ /* Just use IM_TYPE_sRGB. */ *obj = im_col_displays( 7 ); break; case CALL_DOUBLE: { double *a = *obj; if( !PEISREAL( arg ) ) return( FALSE ); *a = PEGETREAL( arg ); break; } case CALL_INT: { int *i = *obj; if( PEISREAL( arg ) ) { double t = PEGETREAL( arg ); *i = (int) t; } else if( PEISBOOL( arg ) ) *i = PEGETBOOL( arg ); else return( FALSE ); break; } case CALL_COMPLEX: { double *c = *obj; if( !PEISCOMPLEX( arg ) ) return( FALSE ); c[0] = PEGETREALPART( arg ); c[1] = PEGETIMAGPART( arg ); break; } case CALL_STRING: { char **c = (char **) obj; char buf[MAX_STRSIZE]; if( !heap_get_string( arg, buf, MAX_STRSIZE ) ) return( FALSE ); *c = im_strdup( NULL, buf ); break; } case CALL_IMAGE: /* Just note the Imageinfo for now ... a later pass sets vargv * once we've checked all the LUTs. */ if( !PEISIMAGE( arg ) || !call_add_input_ii( vi, IMAGEINFO( PEGETII( arg ) ) ) ) return( FALSE ); break; case CALL_DOUBLEVEC: { double buf[MAX_VEC]; int n; if( (n = heap_get_realvec( arg, buf, MAX_VEC )) < 0 || call_make_doublevec( *obj, n, buf ) ) return( FALSE ); break; } case CALL_INTVEC: { double buf[MAX_VEC]; int n; if( (n = heap_get_realvec( arg, buf, MAX_VEC )) < 0 || call_make_intvec( *obj, n, buf ) ) return( FALSE ); break; } case CALL_IMAGEVEC: { Imageinfo *buf[MAX_VEC]; int n; int i; /* Put Imageinfo in for now ... a later pass changes this to * IMAGE* once we've checked all the LUTs. */ if( (n = heap_get_imagevec( arg, buf, MAX_VEC )) < 0 || call_make_imagevec( *obj, n ) ) return( FALSE ); for( i = 0; i < n; i++ ) if( !call_add_input_ii( vi, buf[i] ) ) return( FALSE ); break; } case CALL_DMASK: case CALL_IMASK: { im_mask_object **mo = (im_mask_object **) obj; if( vt == 6 ) { DOUBLEMASK *mask; if( !(mask = matrix_ip_to_dmask( arg )) ) return( FALSE ); (*mo)->mask = mask; (*mo)->name = im_strdupn( mask->filename ); } else { INTMASK *mask; if( !(mask = matrix_ip_to_imask( arg )) ) return( FALSE ); (*mo)->mask = mask; (*mo)->name = im_strdupn( mask->filename ); } break; } case CALL_GVALUE: { GValue *value = *obj; memset( value, 0, sizeof( GValue ) ); if( !heap_ip_to_gvalue( arg, value ) ) return( FALSE ); break; } case CALL_INTERPOLATE: if( !PEISMANAGEDGOBJECT( arg ) ) return( FALSE ); *obj = PEGETMANAGEDGOBJECT( arg ); break; default: g_assert( FALSE ); } return( TRUE ); } /* CALL types -> ip types. Write to arg. Use outiiindex to iterate through * outii[] as we find output imageinfo. */ static gboolean call_toip( CallInfo *vi, int i, int *outiiindex, PElement *arg ) { im_object obj = vi->vargv[i]; im_type_desc *ty = vi->fn->argv[i].desc; #ifdef DEBUG printf( "call_toip: arg[%d] (%s) = ", i, ty->type ); #endif /*DEBUG*/ switch( call_lookup_type( ty->type ) ) { case CALL_DOUBLE: if( !heap_real_new( vi->rc->heap, *((double*)obj), arg ) ) return( FALSE ); break; case CALL_INT: if( !heap_real_new( vi->rc->heap, *((int*)obj), arg ) ) return( FALSE ); break; case CALL_DOUBLEVEC: { im_doublevec_object *dv = obj; if( !heap_realvec_new( vi->rc->heap, dv->n, dv->vec, arg ) ) return( FALSE ); break; } case CALL_INTVEC: { im_intvec_object *iv = obj; if( !heap_intvec_new( vi->rc->heap, iv->n, iv->vec, arg ) ) return( FALSE ); break; } case CALL_COMPLEX: if( !heap_complex_new( vi->rc->heap, ((double*)obj)[0], ((double*)obj)[1], arg ) ) return( FALSE ); break; case CALL_STRING: if( !heap_managedstring_new( vi->rc->heap, (char *) obj, arg ) ) return( FALSE ); break; case CALL_IMAGE: { Imageinfo *outii; outii = vi->outii[*outiiindex]; *outiiindex += 1; PEPUTP( arg, ELEMENT_MANAGED, outii ); break; } case CALL_DMASK: { im_mask_object *mo = obj; DOUBLEMASK *mask = mo->mask; if( !matrix_dmask_to_heap( vi->rc->heap, mask, arg ) ) return( FALSE ); break; } case CALL_IMASK: { im_mask_object *mo = obj; INTMASK *mask = mo->mask; if( !matrix_imask_to_heap( vi->rc->heap, mask, arg ) ) return( FALSE ); break; } case CALL_GVALUE: if( !heap_gvalue_to_ip( (GValue *) obj, arg ) ) return( FALSE ); break; case CALL_IMAGEVEC: case CALL_INTERPOLATE: default: g_assert( FALSE ); } #ifdef DEBUG pgraph( arg ); #endif /*DEBUG*/ return( TRUE ); } static void * call_write_result_sub( Reduce *rc, PElement *safe, CallInfo *vi, PElement *out ) { int outiiindex; /* call_toip() uses this to iterate through outii[]. */ outiiindex = 0; /* Write result. */ if( vi->nres == 1 ) { /* Single result. */ if( !call_toip( vi, vi->outpos[0], &outiiindex, safe ) ) return( out ); } else { /* Have to build a list of results. */ PElement list; PElement t; int i; list = *safe; heap_list_init( &list ); for( i = 0; i < vi->nres; i++ ) { if( !heap_list_add( vi->rc->heap, &list, &t ) || !call_toip( vi, vi->outpos[i], &outiiindex, &t ) ) return( out ); (void) heap_list_next( &list ); } } /* Now overwrite out with safe. */ PEPUTPE( out, safe ); return( NULL ); } /* Write the results back to the heap. We have to so this in two stages: * build the output object linked off a new managed Element, then once it's * built, overwrite our output */ static gboolean call_write_result( CallInfo *vi, PElement *out ) { if( reduce_safe_pointer( vi->rc, (reduce_safe_pointer_fn) call_write_result_sub, vi, out, NULL, NULL ) ) return( FALSE ); return( TRUE ); } /* Junk all the refs we were holding during the call. See call_add_input_ii() * and call_add_output_ii(). * * This gets called explicitly after we have handed the ii refs back to nip2 * during normal processing, or from _dispose() if we bomb out early and * unref. */ static void call_drop_refs( CallInfo *vi ) { if( vi->must_drop ) { int i; #ifdef DEBUG printf( "call_drop_refs: dropping %d in refs\n", vi->ninii ); printf( "call_drop_refs: dropping %d out refs\n", vi->noutii ); #endif /*DEBUG*/ for( i = 0; i < vi->ninii; i++ ) managed_destroy_nonheap( MANAGED( vi->inii[i] ) ); for( i = 0; i < vi->noutii; i++ ) managed_destroy_nonheap( MANAGED( vi->outii[i] ) ); vi->must_drop = FALSE; } } static void call_info_dispose( GObject *gobject ) { CallInfo *vi; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_CALL_INFO( gobject ) ); vi = CALL_INFO( gobject ); #ifdef DEBUG printf( "call_info_dispose: (%p) %s \"%s\"\n", vi, G_OBJECT_TYPE_NAME( vi ), vi->name ); #endif /*DEBUG*/ /* Are we in the history? Remove us. */ cache_history_remove( vi ); /* Drop any refs we may have left dangling. */ call_drop_refs( vi ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } /* Junk stuff we may have attached to vargv. */ static void call_vargv_free( im_function *fn, im_object *vargv ) { int i; /* Free any CALL args we built and haven't used. */ for( i = 0; i < fn->argc; i++ ) { im_type_desc *ty = fn->argv[i].desc; im_object *obj = vargv[i]; CallArgumentType vt; /* Make sure we don't damage any error message we might * have. */ error_block(); vt = call_lookup_type( ty->type ); error_unblock(); switch( vt ) { case CALL_NONE: /* IM_TYPE_DISPLAY */ case CALL_DOUBLE: case CALL_INT: case CALL_COMPLEX: case CALL_GVALUE: case CALL_INTERPOLATE: case CALL_IMAGE: /* Do nothing. */ break; case CALL_STRING: IM_FREE( obj ); break; case CALL_IMAGEVEC: IM_FREE( ((im_imagevec_object *) obj)->vec ); break; case CALL_DOUBLEVEC: IM_FREE( ((im_doublevec_object *) obj)->vec ); break; case CALL_INTVEC: IM_FREE( ((im_intvec_object *) obj)->vec ); break; case CALL_DMASK: IM_FREE( ((im_mask_object *) obj)->name ); IM_FREEF( im_free_dmask, ((im_mask_object *) obj)->mask ); break; case CALL_IMASK: IM_FREE( ((im_mask_object *) obj)->name ); IM_FREEF( im_free_imask, ((im_mask_object *) obj)->mask ); break; default: g_assert( FALSE ); } } } static void call_info_finalize( GObject *gobject ) { CallInfo *vi; g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_CALL_INFO( gobject ) ); vi = CALL_INFO( gobject ); #ifdef DEBUG_LEAK call_info_all = g_slist_remove( call_info_all, vi ); #endif /*DEBUG_LEAK*/ if( vi->vargv ) { call_vargv_free( vi->fn, vi->vargv ); im_free_vargv( vi->fn, vi->vargv ); IM_FREE( vi->vargv ); } G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void call_info_info( iObject *iobject, VipsBuf *buf ) { CallInfo *vi = CALL_INFO( iobject ); vips_buf_appendf( buf, "call_info_info: (%p) %s \"%s\"\n", vi, G_OBJECT_TYPE_NAME( vi ), NN( IOBJECT( vi )->name ) ); } static void call_info_class_init( CallInfoClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = call_info_dispose; gobject_class->finalize = call_info_finalize; iobject_class->info = call_info_info; } static void call_info_init( CallInfo *vi ) { int i; vi->name = NULL; vi->fn = NULL; vi->rc = NULL; vi->vargv = NULL; vi->nargs = 0; vi->nres = 0; vi->nires = 0; vi->ninii = 0; vi->noutii = 0; vi->use_lut = FALSE; /* Set this properly later */ vi->found_hash = FALSE; vi->in_cache = FALSE; vi->must_drop = FALSE; #ifdef DEBUG_LEAK call_info_all = g_slist_prepend( call_info_all, vi ); #endif /*DEBUG_LEAK*/ for( i = 0; i < MAX_CALL_ARGS; i++ ) { vi->outii_destroy_sid[i] = 0; vi->inii_destroy_sid[i] = 0; vi->inii_invalidate_sid[i] = 0; } } GType call_info_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( CallInfoClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) call_info_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( CallInfo ), 32, /* n_preallocs */ (GInstanceInitFunc) call_info_init, }; type = g_type_register_static( TYPE_IOBJECT, "CallInfo", &info, 0 ); } return( type ); } static CallInfo * call_new( Reduce *rc, im_function *fn ) { CallInfo *vi; int i; g_assert( fn->argc < MAX_CALL_ARGS - 1 ); if( !fn || !(vi = CALL_INFO( g_object_new( TYPE_CALL_INFO, NULL ) )) ) return( NULL ); vi->name = fn->name; vi->fn = fn; vi->rc = rc; /* Look over the args ... count the number of inputs we need, and * the number of outputs we generate. Note the position of each. */ for( i = 0; i < vi->fn->argc; i++ ) { im_type_desc *ty = vi->fn->argv[i].desc; if( call_type_makes_output( ty ) ) { vi->outpos[vi->nres] = i; vi->nres += 1; /* Image output. */ if( strcmp( ty->type, IM_TYPE_IMAGE ) == 0 ) vi->nires += 1; } if( call_type_needs_input( ty ) ) { vi->inpos[vi->nargs] = i; vi->nargs += 1; } } /* Make the call spine, alloc memory. */ if( !(vi->vargv = IM_ARRAY( NULL, vi->fn->argc + 1, im_object )) || im_allocate_vargv( vi->fn, vi->vargv ) ) { call_error( vi ); g_object_unref( vi ); return( NULL ); } return( vi ); } /* Add another ii to outii. */ static gboolean call_add_output_ii( CallInfo *vi, Imageinfo *ii ) { if( vi->noutii > MAX_CALL_ARGS ) { call_error_toomany( vi ); return( FALSE ); } vi->outii[vi->noutii] = ii; vi->noutii += 1; /* We hold a ref to the ii until the call is done and the result * written back to nip2. If we cache the result, we make a new * weakref. */ managed_dup_nonheap( MANAGED( ii ) ); vi->must_drop = TRUE; return( TRUE ); } /* Init an output slot in vargv. */ static gboolean call_build_output( CallInfo *vi, int i ) { im_type_desc *ty = vi->fn->argv[i].desc; /* Provide output objects for the function to write to. */ switch( call_lookup_type( ty->type ) ) { case CALL_DOUBLE: case CALL_INT: case CALL_COMPLEX: case CALL_STRING: break; case CALL_IMAGE: { Imageinfo *ii; if( !(ii = imageinfo_new_temp( main_imageinfogroup, vi->rc->heap, NULL, "p" )) || !call_add_output_ii( vi, ii ) || !(vi->vargv[i] = imageinfo_get( FALSE, ii )) ) return( FALSE ); break; } case CALL_DMASK: case CALL_IMASK: { im_mask_object *mo = vi->vargv[i]; mo->mask = NULL; mo->name = im_strdup( NULL, "" ); break; } case CALL_GVALUE: { GValue *value = vi->vargv[i]; memset( value, 0, sizeof( GValue ) ); break; } case CALL_DOUBLEVEC: case CALL_INTVEC: { /* intvec is also int + pointer. */ im_doublevec_object *dv = vi->vargv[i]; dv->n = 0; dv->vec = NULL; break; } default: g_assert( FALSE ); } return( TRUE ); } static gboolean call_build_inputva( CallInfo *vi, int i, va_list *ap ) { im_type_desc *ty = vi->fn->argv[i].desc; switch( call_lookup_type( ty->type ) ) { case CALL_DOUBLE: { double v = va_arg( *ap, double ); #ifdef DEBUG printf( "%g\n", v ); #endif /*DEBUG*/ *((double*)vi->vargv[i]) = v; if( trace_flags & TRACE_VIPS ) vips_buf_appendf( trace_current(), "%g ", v ); break; } case CALL_INT: { int v = va_arg( *ap, int ); #ifdef DEBUG printf( "%d\n", v ); #endif /*DEBUG*/ *((int*)vi->vargv[i]) = v; if( trace_flags & TRACE_VIPS ) vips_buf_appendf( trace_current(), "%d ", v ); break; } case CALL_GVALUE: { GValue *value = va_arg( *ap, GValue * ); #ifdef DEBUG printf( "gvalue %p\n", value ); #endif /*DEBUG*/ vi->vargv[i] = value; if( trace_flags & TRACE_VIPS ) { vips_buf_appendgv( trace_current(), value ); vips_buf_appends( trace_current(), " " ); } break; } case CALL_INTERPOLATE: { VipsInterpolate *value = va_arg( *ap, VipsInterpolate * ); #ifdef DEBUG printf( "interpolate %p\n", value ); #endif /*DEBUG*/ vi->vargv[i] = value; if( trace_flags & TRACE_VIPS ) { vips_object_to_string( VIPS_OBJECT( value ), trace_current() ); vips_buf_appends( trace_current(), " " ); } break; } case CALL_IMAGE: { Imageinfo *ii = va_arg( *ap, Imageinfo * ); #ifdef DEBUG printf( "imageinfo %p\n", ii ); #endif /*DEBUG*/ if( !call_add_input_ii( vi, ii ) ) return( FALSE ); /* Filled in later. */ vi->vargv[i] = NULL; if( trace_flags & TRACE_VIPS ) { VipsBuf *buf = trace_current(); if( ii && ii->im ) { vips_buf_appends( buf, "<" ); vips_buf_appendf( buf, _( "image \"%s\"" ), ii->im->filename ); vips_buf_appends( buf, "> " ); } else { vips_buf_appends( buf, "<" ); vips_buf_appends( buf, _( "no image" ) ); vips_buf_appends( buf, "> " ); } } break; } case CALL_DOUBLEVEC: { int n = va_arg( *ap, int ); double *vec = va_arg( *ap, double * ); #ifdef DEBUG { int i; for( i = 0; i < n; i++ ) printf( "%g, ", vec[i] ); printf( "\n" ); } #endif /*DEBUG*/ if( call_make_doublevec( vi->vargv[i], n, vec ) ) return( FALSE ); if( trace_flags & TRACE_VIPS ) { VipsBuf *buf = trace_current(); int i; vips_buf_appendf( buf, "<" ); vips_buf_appendf( buf, _( "doublevec" ) ); for( i = 0; i < n; i++ ) vips_buf_appendf( buf, " %g", vec[i] ); vips_buf_appends( buf, "> " ); } break; } /* FIXME ... add intvec perhaps */ case CALL_IMAGEVEC: { int n = va_arg( *ap, int ); Imageinfo **vec = va_arg( *ap, Imageinfo ** ); #ifdef DEBUG { int i; for( i = 0; i < n; i++ ) printf( "%p, ", vec[i] ); printf( "\n" ); } #endif /*DEBUG*/ if( call_make_imagevec( vi->vargv[i], n ) ) return( FALSE ); for( i = 0; i < n; i++ ) if( !call_add_input_ii( vi, vec[i] ) ) return( FALSE ); if( trace_flags & TRACE_VIPS ) { VipsBuf *buf = trace_current(); int i; vips_buf_appendf( buf, "<" ); vips_buf_appendf( buf, _( "imagevec" ) ); for( i = 0; i < n; i++ ) { vips_buf_appendf( buf, " <" ); vips_buf_appendf( buf, _( "image \"%s\"" ), vec[i]->im->filename ); vips_buf_appendf( buf, ">" ); } vips_buf_appends( buf, "> " ); } break; } default: g_assert( FALSE ); } return( TRUE ); } /* Fill an argument vector from the C stack. */ static gboolean call_fillva( CallInfo *vi, va_list *ap ) { int i; g_assert( vi->ninii == 0 ); g_assert( vi->noutii == 0 ); for( i = 0; i < vi->fn->argc; i++ ) { im_type_desc *ty = vi->fn->argv[i].desc; #ifdef DEBUG printf( "call_fillva: arg[%d] (%s) = ", i, ty->type ); #endif /*DEBUG*/ if( call_type_makes_output( ty ) ) { if( !call_build_output( vi, i ) ) return( FALSE ); #ifdef DEBUG printf( " output\n" ); #endif /*DEBUG*/ } if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) { /* DISPLAY argument ... just IM_TYPE_sRGB. */ vi->vargv[i] = im_col_displays( 7 ); #ifdef DEBUG printf( " display\n" ); #endif /*DEBUG*/ } if( call_type_needs_input( ty ) ) { if( !call_build_inputva( vi, i, ap ) ) return( FALSE ); } } /* Every output ii depends upon all of the input ii. */ for( i = 0; i < vi->noutii; i++ ) managed_sub_add_all( MANAGED( vi->outii[i] ), vi->ninii, (Managed **) vi->inii ); #ifdef DEBUG printf( "call_fill_spine: reffed %d in\n", vi->ninii ); printf( "call_fill_spine: created %d out\n", vi->noutii ); #endif /*DEBUG*/ return( TRUE ); } static gboolean callva_sub( Reduce *rc, const char *name, PElement *out, va_list *ap ) { CallInfo *vi; gboolean result; if( trace_flags & TRACE_VIPS ) trace_push(); if( !(vi = call_new( rc, im_find_function( name ) )) ) return( FALSE ); if( trace_flags & TRACE_VIPS ) vips_buf_appendf( trace_current(), "\"%s\" ", vi->name ); result = TRUE; if( !call_fillva( vi, ap ) ) result = FALSE; if( trace_flags & TRACE_VIPS ) vips_buf_appends( trace_current(), " ->\n" ); if( result && ( !(vi = cache_dispatch( vi, out )) || !call_write_result( vi, out ) ) ) result = FALSE; if( trace_flags & TRACE_VIPS ) { trace_result( TRACE_VIPS, out ); trace_pop(); } if( vi ) { /* We must drop refs explicitly, since this unref might not * dispose the vi. */ call_drop_refs( vi ); g_object_unref( vi ); } return( result ); } /* Call a CALL function picking up args from the function call. */ void callva( Reduce *rc, PElement *out, const char *name, ... ) { va_list ap; gboolean result; #ifdef DEBUG printf( "** callva: starting for %s\n", name ); #endif /*DEBUG*/ va_start( ap, name ); result = callva_sub( rc, name, out, &ap ); va_end( ap ); #ifdef DEBUG printf( "callva: done\n" ); #endif /*DEBUG*/ if( !result ) reduce_throw( rc ); } /* Fill an argument vector from our stack frame. Number of args already * checked. */ static gboolean call_fill_spine( CallInfo *vi, HeapNode **arg ) { int i, j; g_assert( vi->ninii == 0 ); g_assert( vi->noutii == 0 ); /* Fully reduce all arguments. Once we've done this, we can be sure * there will not be a GC while we gather, and therefore that no * pointers will become invalid during this call. */ for( i = 0; i < vi->nargs; i++ ) { PElement rhs; PEPOINTRIGHT( arg[i], &rhs ); if( !heap_reduce_strict( &rhs ) ) return( FALSE ); } for( j = 0, i = 0; i < vi->fn->argc; i++ ) { im_type_desc *ty = vi->fn->argv[i].desc; if( call_type_makes_output( ty ) ) if( !call_build_output( vi, i ) ) return( FALSE ); if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) { /* Special DISPLAY argument - don't fetch another ip * argument for it. */ (void) call_fromip( vi, i, NULL ); } if( call_type_needs_input( ty ) ) { PElement rhs; /* Convert ip type to CALL type. */ PEPOINTRIGHT( arg[vi->nargs - j - 1], &rhs ); if( !call_fromip( vi, i, &rhs ) ) { call_error_arg( vi, arg, j ); return( FALSE ); } j += 1; } } /* Every output ii depends upon all of the input ii. */ for( i = 0; i < vi->noutii; i++ ) managed_sub_add_all( MANAGED( vi->outii[i] ), vi->ninii, (Managed **) vi->inii ); #ifdef DEBUG printf( "call_fill_spine: reffed %d inii\n", vi->ninii ); printf( "call_fill_spine: created %d outii\n", vi->noutii ); #endif /*DEBUG*/ return( TRUE ); } static gboolean call_spine_sub( Reduce *rc, const char *name, im_function *fn, PElement *out, HeapNode **arg ) { CallInfo *vi; gboolean result; #ifdef DEBUG printf( "** call_spine: starting for %s\n", name ); #endif /*DEBUG*/ if( !(vi = call_new( rc, fn )) ) return( FALSE ); if( trace_flags & TRACE_VIPS ) { VipsBuf *buf = trace_push(); vips_buf_appendf( buf, "\"%s\" ", name ); trace_args( arg, vi->nargs ); } result = TRUE; if( !call_fill_spine( vi, arg ) || !(vi = cache_dispatch( vi, out )) || !call_write_result( vi, out ) ) result = FALSE; if( trace_flags & TRACE_VIPS ) { trace_result( TRACE_VIPS, out ); trace_pop(); } if( vi ) { /* We must drop refs explicitly, since this unref might not * dispose the vi. */ call_drop_refs( vi ); g_object_unref( vi ); } #ifdef DEBUG printf( "call_spine: done\n" ); #endif /*DEBUG*/ return( result ); } /* Call a CALL function, pick up args from the graph. */ void call_spine( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { if( !call_spine_sub( rc, name, im_find_function( name ), out, arg ) ) reduce_throw( rc ); } /* As an ActionFn. */ void call_run( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out, im_function *function ) { if( !call_spine_sub( rc, name, function, out, arg ) ) reduce_throw( rc ); } nip2-8.7.1/src/heap.h0000644000175000017500000003751613351443023011207 00000000000000/* Heap management. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Node type. Generally represent data objects. * * Don't use enum, as we want this to fit in 1 byte. */ typedef unsigned char NodeType; #define TAG_APPL (0) /* Application */ #define TAG_CONS (1) /* List cons */ #define TAG_FREE (2) /* On free list */ #define TAG_DOUBLE (3) /* Constant double */ #define TAG_COMPLEX (4) /* Constant complex */ #define TAG_GEN (5) /* List generator */ #define TAG_CLASS (8) /* Class object */ #define TAG_SHARED (9) /* Root of a common sub-expression */ #define TAG_REFERENCE (10) /* Reference to a common sub-expression */ #define TAG_FILE (12) /* Generate list from file */ /* Element types. Generally represent operators. */ typedef unsigned char EType; #define ELEMENT_NOVAL (0) /* No value */ #define ELEMENT_NODE (1) /* Pointer to another node */ #define ELEMENT_SYMBOL (2) /* Pointer to Symbol, reduces to value */ #define ELEMENT_SYMREF (3) /* Pointer to Symbol, does not reduce */ #define ELEMENT_COMPILEREF (4) /* Pointer to Compile, does not reduce */ #define ELEMENT_CHAR (5) /* Boxed char type */ #define ELEMENT_BOOL (6) /* Boxed bool type */ #define ELEMENT_BINOP (7) /* Binary operator */ #define ELEMENT_UNOP (8) /* Unary operator */ #define ELEMENT_COMB (9) /* Combinator */ #define ELEMENT_TAG (10) /* RHS of '.' operator */ #define ELEMENT_MANAGED (11) /* A managed object */ #define ELEMENT_CONSTRUCTOR (12)/* Class constructor */ #define ELEMENT_ELIST (13) /* Empty list */ /* Flags we attach to a node. */ typedef unsigned char NodeFlags; #define FLAG_SERIAL (31) /* Serial number mask .. must be 1st */ #define FLAG_PRINT (32) /* Marked (for decompile print) */ #define FLAG_DEBUG (64) /* Marked (for debug traverse) */ #define FLAG_MARK (128) /* Marked (for mark-sweep) */ #define FLAG_ALL (255) /* All flags mask */ /* Set the serial number without disturbing other stuff. */ #define SETSERIAL( FLAGS, SERIAL ) { \ (FLAGS) = ((FLAGS) & (FLAG_SERIAL ^ FLAG_ALL)) | \ ((SERIAL) & FLAG_SERIAL); \ } /* Combinators. Don't change the order of these! See reduce.c for an array * indexed with a CombinatorType. */ typedef enum combinator_type { COMB_S = 0, /* S combinator */ COMB_SL, /* S-left combinator */ COMB_SR, /* S-right combinator */ COMB_I, /* Identity combinator */ COMB_K, /* K combinator */ COMB_GEN /* List generator combinator */ } CombinatorType; /* An element ... a tag plus a pointer. Use one of these to hold a pointer * into a heap. */ typedef struct _Element { EType type; void *ele; } Element; /* A node on the heap. Should fit in 12 bytes on most machines. */ typedef struct _HeapNode { /* Elements: either a pair of pointers, or a double. Sensible on most * 32-bit systems, not so great on 64 bitters. */ union { struct { void *left; void *right; } ptrs; double num; } body; /* Flags ... should fit in 4 bytes. */ NodeType type; /* What this is */ NodeFlags flgs; /* GC flags etc */ EType ltype; /* Type of left element */ EType rtype; /* Type of right element */ } HeapNode; /* Put type/value pairs into nodes. Make sure we completely read before we * write. */ #define PPUTLEFT(N,T,V) {\ EType t99 = (T);\ void *v99 = (void*)(V);\ \ (N)->ltype = t99;\ (N)->body.ptrs.left = v99;\ } #define PPUTRIGHT(N,T,V) {\ EType t99 = (T);\ void *v99 = (void*)(V);\ \ (N)->rtype = t99;\ (N)->body.ptrs.right = v99;\ } #define PPUT(N,Tl,Vl,Tr,Vr) {PPUTLEFT( N, Tl, Vl ); PPUTRIGHT( N, Tr, Vr );} /* Get value as a HeapNode pointer (most common case). */ #define GETLEFT(N) ((HeapNode*)((N)->body.ptrs.left)) #define GETRIGHT(N) ((HeapNode*)((N)->body.ptrs.right)) #define GETLT(N) ((N)->ltype) #define GETRT(N) ((N)->rtype) /* A pointer to an element inside a HeapNode, or to an Element. */ typedef struct pelement { EType *type; void **ele; } PElement; /* Make a PElement point to a node. */ #define PEPOINTLEFT(N,P) \ {(P)->type=&((N)->ltype);(P)->ele=&((N)->body.ptrs.left);} #define PEPOINTRIGHT(N,P) \ {(P)->type=&((N)->rtype);(P)->ele=&((N)->body.ptrs.right);} /* Make a PElement point to an element. */ #define PEPOINTE(PE,E) \ {(PE)->type=&((E)->type);(PE)->ele=&((E)->ele);} /* Get from a PE. */ #define PEGETTYPE(P) (*((P)->type)) #define PEGETVAL(P) ((HeapNode*)(*((P)->ele))) #define PEGETE(P,E) ((E)->type = PEGETTYPE(P),(E)->ele = PEGETVAL(P)) #define PEGETP(PE,T,V) ((T)=*((PE)->type),(V)=*((PE)->ele)) /* Write to a PE. We are careful to eval all args before writing, in case we * are writing to one of the inputs. */ #define PEPUTE(PE,E) {*((PE)->type)=(E)->type;*((PE)->ele)=(E)->ele;} #define PEPUTPE(PEto,PEfrom) {\ EType t99 = PEGETTYPE(PEfrom);\ void *v99 = PEGETVAL(PEfrom);\ \ *((PEto)->type) = t99;\ *((PEto)->ele) = v99;\ } #define PEPUTP(PE,T,V) {\ EType t99 = (T);\ void *v99 = GUINT_TO_POINTER(V);\ \ *((PE)->type) = t99;\ *((PE)->ele) = v99;\ } /* Write a PE to a node. Again, make sure we read both before we write, in * case we are writing an expression to ourselves. */ #define PEPUTLEFT(N,PE) {\ EType t99 = PEGETTYPE(PE);\ void *v99 = PEGETVAL(PE);\ \ (N)->ltype = t99;\ (N)->body.ptrs.left = v99;\ } #define PEPUTRIGHT(N,PE) {\ EType t99 = PEGETTYPE(PE);\ void *v99 = PEGETVAL(PE);\ \ (N)->rtype = t99;\ (N)->body.ptrs.right = v99;\ } /* Predicates. */ #define PEISBINOP(P) (PEGETTYPE(P) == ELEMENT_BINOP) #define PEISBOOL(P) (PEGETTYPE(P) == ELEMENT_BOOL) #define PEISCHAR(P) (PEGETTYPE(P) == ELEMENT_CHAR) #define PEISCLASS(P) (PEISNODE(P) && PEGETVAL(P)->type == TAG_CLASS) #define PEISCONSTRUCTOR(P) (PEGETTYPE(P) == ELEMENT_CONSTRUCTOR) #define PEISCOMB(P) (PEGETTYPE(P) == ELEMENT_COMB) #define PEISCOMPLEX(P) (PEISNODE(P) && PEGETVAL(P)->type == TAG_COMPLEX) #define PEISTAG(P) (PEGETTYPE(P) == ELEMENT_TAG) #define PEISMANAGED(P) (PEGETTYPE(P) == ELEMENT_MANAGED) #define PEISMANAGEDGOBJECT(P) (PEISMANAGED(P) && \ IS_MANAGEDGOBJECT( PEGETVAL(P) )) #define PEISMANAGEDSTRING(P) (PEISMANAGED(P) && \ IS_MANAGEDSTRING(PEGETVAL(P))) #define PEISIMAGE(P) (PEISMANAGED(P) && IS_IMAGEINFO( PEGETVAL(P) )) #define PEISVIPSOBJECT(P) \ (PEISMANAGEDGOBJECT(P) && VIPS_IS_OBJECT( PEGETMANAGEDGOBJECT(P) )) #define PEISFILE(P) (PEISMANAGED(P) && IS_MANAGEDFILE(PEGETVAL(P))) #define PEISELIST(P) (PEGETTYPE(P) == ELEMENT_ELIST) #define PEISFLIST(P) ((PEISNODE(P) && PEGETVAL(P)->type == TAG_CONS) || \ PEISMANAGEDSTRING(P)) #define PEISLIST(P) (PEISELIST(P) || PEISFLIST(P)) #define PEISNOVAL(P) (PEGETTYPE(P) == ELEMENT_NOVAL) #define PEISNUM(P) (PEISREAL(P) || PEISCOMPLEX(P)) #define PEISNODE(P) (PEGETTYPE(P) == ELEMENT_NODE) #define PEISREAL(P) (PEISNODE(P) && PEGETVAL(P)->type == TAG_DOUBLE) #define PEISSYMBOL(P) (PEGETTYPE(P) == ELEMENT_SYMBOL) #define PEISSYMREF(P) (PEGETTYPE(P) == ELEMENT_SYMREF) #define PEISCOMPILEREF(P) (PEGETTYPE(P) == ELEMENT_COMPILEREF) #define PEISUNOP(P) (PEGETTYPE(P) == ELEMENT_UNOP) /* Extract bits of primitive compound types. */ #define PEGETSYMBOL(P) ((Symbol*)PEGETVAL(P)) #define PEGETSYMREF(P) ((Symbol*)PEGETVAL(P)) #define PEGETCOMPILE(P) ((Compile*)(PEGETVAL(P))) #define PEGETBINOP(P) ((BinOp)PEGETVAL(P)) #define PEGETUNOP(P) ((UnOp)PEGETVAL(P)) #define PEGETCOMB(P) ((CombinatorType)PEGETVAL(P)) #define PEGETTAG(P) ((char*)PEGETVAL(P)) #define PEGETREAL(P) (PEGETVAL(P)->body.num) #define PEGETBOOL(P) ((gboolean)GPOINTER_TO_UINT(PEGETVAL(P))) #define PEGETCHAR(P) ((unsigned char)(GPOINTER_TO_UINT(PEGETVAL(P)))) #define PEGETIMAGE(P) (((Imageinfo*)PEGETVAL(P))->im) #define PEGETII(P) ((Imageinfo*)PEGETVAL(P)) #define PEGETFILE(P) ((Managedfile*)PEGETVAL(P)) #define PEGETMANAGED(P) ((Managed*)PEGETVAL(P)) #define PEGETMANAGEDSTRING(P) ((Managedstring*)PEGETVAL(P)) #define PEGETMANAGEDGOBJECT(P) (((Managedgobject*)PEGETVAL(P))->object) #define PEGETVIPSOBJECT(P) \ ((VipsObject*)(((Managedgobject*)PEGETVAL(P))->object)) #define PEGETHD(P1,P2) PEPOINTLEFT(PEGETVAL(P2), P1) #define PEGETTL(P1,P2) PEPOINTRIGHT(PEGETVAL(P2), P1) #define PEGETREALPART(P) (GETLEFT(PEGETVAL(P))->body.num) #define PEGETIMAGPART(P) (GETRIGHT(PEGETVAL(P))->body.num) #define PEGETCLASSCOMPILE(P) (COMPILE(GETLEFT(PEGETVAL(P)))) #define PEGETCLASSSECRET(P1,P2) PEPOINTLEFT(GETRIGHT(PEGETVAL(P2)),P1) #define PEGETCLASSMEMBER(P1,P2) PEPOINTRIGHT(GETRIGHT(PEGETVAL(P2)),P1) /* A block on the heap. */ struct _HeapBlock { Heap *heap; /* Heap we are part of */ HeapBlock *next; /* Next block in chain */ HeapNode *node; /* Nodes on this block */ int sz; /* Number of nodes in this block */ }; /* Function to get max heap size. */ typedef int (*heap_max_fn)( Heap * ); #define TYPE_HEAP (heap_get_type()) #define HEAP( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_HEAP, Heap )) #define HEAP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_HEAP, HeapClass)) #define IS_HEAP( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_HEAP )) #define IS_HEAP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_HEAP )) #define HEAP_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_HEAP, HeapClass )) struct _Heap { iObject parent_object; Compile *compile; /* If non-null, assoc. compile */ heap_max_fn max_fn; /* Max nodes in this heap */ int mxb; /* Max blocks until next check */ int rsz; /* Nodes to allocate in each extra block */ int nb; /* Number of blocks attached */ HeapBlock *hb; /* List of current blocks */ HeapNode *free; /* Start of free-node chain (sweep to here) */ int ncells; /* Cells allocated */ int nfree; /* Cells free */ int serial; /* Last serial number we used */ gboolean filled; /* Set on heap full */ GHashTable *emark; /* Set of elements to mark on GC */ GHashTable *rmark; /* Set of Reduce to mark on GC */ GHashTable *mtable; /* Managed associated with this heap */ guint gc_tid; /* id of gc delay timer */ /* Set this to force unreffed objects out immediately. Handy for leak * testing. */ gboolean flush; }; typedef struct _HeapClass { iObjectClass parent_class; /* My methods. */ } HeapClass; /* Get a node from the free-list. No check for free-list exhausted! Set sym * pointer in node to heap sym pointer. */ #ifdef DEBUG_HEAP #define EXTRACTNODE( H, A ) \ (heap_sanity( H ), (A) = (H)->free, (H)->free = GETLEFT( A ), 0) #else /*!DEBUG_HEAP*/ #define EXTRACTNODE( H, A ) \ ((A) = (H)->free, (H)->free = GETLEFT( A ), 0) #endif /*DEBUG_HEAP*/ /* Allocate a new node from heap H, pop the pointer into A, return non-zero if * alloc failed. Node is uninitialised! */ #define NEWNODE( H, A ) ( \ (H)->free ? \ EXTRACTNODE( H, A ): \ (((A) = heap_getmem( H )) ? 0 : -1) \ ) typedef void *(*heap_safe_pointer_fn)( Heap *heap, PElement *, void *, void *, void *, void * ); void *heap_safe_pointer( Heap *heap, heap_safe_pointer_fn fn, void *a, void *b, void *c, void *d ); typedef void *(*heap_map_fn)( HeapNode *, void *, void *); void *heap_map( HeapNode *hn, heap_map_fn fn, void *a, void *b ); int heap_sanity( Heap *heap ); void heap_check_all_destroyed( void ); void heap_destroy( Heap *heap ); GType heap_get_type( void ); Heap *heap_new( Compile *compile, heap_max_fn max_fn, int stsz, int rsz ); HeapNode *heap_getmem( Heap *heap ); gboolean heap_gc( Heap *heap ); void heap_gc_request( Heap *heap ); void heap_register_element( Heap *heap, Element *root ); void heap_unregister_element( Heap *heap, Element *root ); void heap_register_reduce( Heap *heap, Reduce *rc ); void heap_unregister_reduce( Heap *heap, Reduce *rc ); void heap_set( Heap *heap, NodeFlags setmask ); void heap_clear( Heap *heap, NodeFlags clearmask ); int heap_serial_new( Heap *heap ); gboolean heap_bool_new( Heap *heap, gboolean val, PElement *out ); gboolean heap_real_new( Heap *heap, double in, PElement *out ); gboolean heap_element_new( Heap *heap, Element *e, PElement *out ); gboolean heap_complex_element_new( Heap *heap, PElement *rp, PElement *ip, PElement *out ); gboolean heap_complex_new( Heap *heap, double rp, double ip, PElement *out ); gboolean heap_realvec_new( Heap *heap, int n, double *vec, PElement *out ); gboolean heap_intvec_new( Heap *heap, int n, int *vec, PElement *out ); void heap_list_init( PElement *list ); gboolean heap_list_add( Heap *heap, PElement *list, PElement *data ); gboolean heap_list_next( PElement *list ); gboolean heap_list_cat( Reduce *rc, PElement *a, PElement *b, PElement *out ); void heap_appl_init( PElement *base, PElement *func ); gboolean heap_appl_add( Heap *heap, PElement *base, PElement *parm ); gboolean heap_matrix_new( Heap *heap, int xsize, int ysize, double *vec, PElement *out ); gboolean heap_string_new( Heap *heap, const char *str, PElement *out ); gboolean heap_managedstring_new( Heap *heap, const char *str, PElement *out ); gboolean heap_lstring_new( Heap *heap, GSList *labels, PElement *out ); gboolean heap_file_new( Heap *heap, const char *filename, PElement *out ); gboolean heap_error_typecheck( PElement *e, const char *name, const char *type ); typedef void *(*heap_map_list_fn)( PElement *, void *, void * ); void *heap_map_list( PElement *base, heap_map_list_fn fn, void *a, void *b ); typedef void *(*heap_map_dict_fn)( const char *, PElement *, void *a, void *b ); void *heap_map_dict( PElement *base, heap_map_dict_fn fn, void *a, void *b ); gboolean heap_get_list( PElement *list ); gboolean heap_get_list_next( PElement *list, PElement *data ); gboolean heap_get_string( PElement *base, char *buf, int n ); gboolean heap_get_lstring( PElement *base, GSList **labels ); gboolean heap_get_bool( PElement *base, gboolean *out ); gboolean heap_get_real( PElement *base, double *out ); gboolean heap_get_class( PElement *base, PElement *out ); gboolean heap_get_image( PElement *base, Imageinfo **out ); int heap_get_realvec( PElement *base, double *buf, int n ); int heap_get_imagevec( PElement *base, Imageinfo **buf, int n ); gboolean heap_get_matrix_size( PElement *base, int *xsize, int *ysize ); gboolean heap_get_matrix( PElement *base, double *buf, int n, int *xsize, int *ysize ); gboolean heap_is_elist( PElement *base, gboolean *out ); gboolean heap_is_list( PElement *base, gboolean *out ); gboolean heap_is_string( PElement *base, gboolean *out ); gboolean heap_is_realvec( PElement *base, gboolean *out ); gboolean heap_is_imagevec( PElement *base, gboolean *out ); gboolean heap_is_matrix( PElement *base, gboolean *out ); gboolean heap_is_class( PElement *base, gboolean *out ); gboolean heap_is_instanceof_exact( const char *name, PElement *klass, gboolean *out); gboolean heap_is_instanceof( const char *name, PElement *klass, gboolean *out ); int heap_list_length( PElement *base ); int heap_list_length_max( PElement *base, int max_length ); gboolean heap_list_index( PElement *base, int n, PElement *out ); gboolean heap_reduce_strict( PElement *base ); gboolean heap_copy( Heap *heap, Compile *compile, PElement *out ); gboolean heap_ip_to_gvalue( PElement *in, GValue *out ); gboolean heap_gvalue_to_ip( GValue *in, PElement *out ); void graph_node( Heap *heap, VipsBuf *buf, HeapNode *root, gboolean fn ); void graph_pelement( Heap *heap, VipsBuf *buf, PElement *root, gboolean fn ); void graph_element( Heap *heap, VipsBuf *buf, Element *root, gboolean fn ); void graph_pointer( PElement *root ); /* Reduce and print, csh-style output. */ void graph_value( PElement *root ); nip2-8.7.1/src/toggleview.h0000644000175000017500000000310613351443023012432 00000000000000/* a toggleview button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TOGGLEVIEW (toggleview_get_type()) #define TOGGLEVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_TOGGLEVIEW, Toggleview )) #define TOGGLEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_TOGGLEVIEW, ToggleviewClass )) #define IS_TOGGLEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TOGGLEVIEW )) #define IS_TOGGLEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOGGLEVIEW )) typedef struct _Toggleview { Graphicview parent_object; /* My instance vars. */ GtkWidget *toggle; } Toggleview; typedef struct _ToggleviewClass { GraphicviewClass parent_class; /* My methods. */ } ToggleviewClass; GtkType toggleview_get_type( void ); View *toggleview_new( void ); nip2-8.7.1/src/spin.c0000644000175000017500000001376413351443023011235 00000000000000/* a pair of spin buttons, with no entry ... don't actually use buttons, * since we may have lots and lots of these, and we don't want to make an X * window for each one * * we do the event handling ourselves ... our enclosing view passes the ev * to spin_event(), this triggers signals as required */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; /* Our signals. Up and down click. */ enum { UP_CLICK, DOWN_CLICK, LAST_SIGNAL }; static guint spin_signals[LAST_SIGNAL] = { 0 }; /* Default up and down signal handlers. */ static void spin_real_up_click( Spin *spin ) { #ifdef DEBUG printf( "spin_real_up_click\n" ); #endif /*DEBUG*/ } static void spin_real_down_click( Spin *spin ) { #ifdef DEBUG printf( "spin_real_down_click\n" ); #endif /*DEBUG*/ } static void spin_class_init( SpinClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ spin_signals[UP_CLICK] = g_signal_new( "up_click", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( SpinClass, up_click ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); spin_signals[DOWN_CLICK] = g_signal_new( "down_click", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( SpinClass, down_click ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); class->up_click = spin_real_up_click; class->down_click = spin_real_down_click; } typedef struct { Spin *spin; int x, y; /* Click position */ gboolean handled; } SpinEvent; static void allocation2rect( GtkAllocation *from, Rect *to ) { to->left = from->x; to->top = from->y; to->width = from->width; to->height = from->height; } static void spin_button_press_event_test( GtkWidget *widget, gpointer data ) { SpinEvent *sev = (SpinEvent *) data; Rect pos; if( sev->handled ) return; allocation2rect( &widget->allocation, &pos ); if( im_rect_includespoint( &pos, sev->x, sev->y ) ) { if( GTK_IS_ARROW( widget ) ) { sev->handled = TRUE; if( GTK_ARROW( widget )->arrow_type == GTK_ARROW_UP ) g_signal_emit( GTK_OBJECT( sev->spin ), spin_signals[UP_CLICK], 0 ); else g_signal_emit( GTK_OBJECT( sev->spin ), spin_signals[DOWN_CLICK], 0 ); } } } /* Event in us somewhere. */ static gboolean spin_button_press_event_cb( GtkWidget *widget, GdkEventButton *event, Spin *spin ) { gboolean handled = FALSE; if( event->type == GDK_BUTTON_PRESS ) { SpinEvent sev; if( event->button == 1 ) { sev.spin = spin; /* Find button x/y relative to top LH corner of spin. */ sev.x = event->x + GTK_WIDGET( spin )->allocation.x; sev.y = event->y + GTK_WIDGET( spin )->allocation.y; sev.handled = FALSE; spin_button_press_event_test( spin->up, &sev ); spin_button_press_event_test( spin->down, &sev ); handled = sev.handled; } } return( handled ); } static gboolean spin_button_enter_notify_event_cb( GtkWidget *widget, GdkEventCrossing *event, Spin *spin ) { gboolean handled = FALSE; if( event->detail != GDK_NOTIFY_INFERIOR ) gtk_widget_set_state( widget, GTK_STATE_PRELIGHT ); return( handled ); } static gboolean spin_button_leave_notify_event_cb( GtkWidget *widget, GdkEventCrossing *event, Spin *spin ) { gboolean handled = FALSE; if( event->detail != GDK_NOTIFY_INFERIOR ) gtk_widget_set_state( widget, GTK_STATE_NORMAL ); return( handled ); } static void spin_init( Spin *spin ) { GtkWidget *ebox; GtkWidget *vbox; ebox = gtk_event_box_new(); set_tooltip( ebox, _( "Expand or collapse row" ) ); gtk_event_box_set_visible_window( GTK_EVENT_BOX( ebox ), FALSE ); gtk_signal_connect( GTK_OBJECT( ebox ), "button_press_event", GTK_SIGNAL_FUNC( spin_button_press_event_cb ), spin ); gtk_signal_connect( GTK_OBJECT( ebox ), "enter_notify_event", GTK_SIGNAL_FUNC( spin_button_enter_notify_event_cb ), spin ); gtk_signal_connect( GTK_OBJECT( ebox ), "leave_notify_event", GTK_SIGNAL_FUNC( spin_button_leave_notify_event_cb ), spin ); gtk_box_pack_start( GTK_BOX( spin ), ebox, FALSE, FALSE, 0 ); gtk_widget_show( ebox ); vbox = gtk_vbox_new( 0, FALSE ); gtk_container_add( GTK_CONTAINER( ebox ), vbox ); gtk_widget_show( vbox ); spin->up = gtk_arrow_new( GTK_ARROW_UP, GTK_SHADOW_OUT ); spin->down = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT ); gtk_box_pack_start( GTK_BOX( vbox ), spin->up, FALSE, FALSE, 0 ); gtk_box_pack_end( GTK_BOX( vbox ), spin->down, FALSE, FALSE, 0 ); gtk_widget_show( spin->up ); gtk_widget_show( spin->down ); } GtkType spin_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Spin", sizeof( Spin ), sizeof( SpinClass ), (GtkClassInitFunc) spin_class_init, (GtkObjectInitFunc) spin_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VIEW, &info ); } return( type ); } GtkWidget * spin_new( void ) { Spin *spin = (Spin *) gtk_type_new( TYPE_SPIN ); return( GTK_WIDGET( spin ) ); } nip2-8.7.1/src/heapmodel.h0000644000175000017500000000563413351443023012224 00000000000000/* like a model, but something that represents a part of the heap (eg. * toggle/slider/text etc.) */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_HEAPMODEL (heapmodel_get_type()) #define HEAPMODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_HEAPMODEL, Heapmodel )) #define HEAPMODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_HEAPMODEL, HeapmodelClass)) #define IS_HEAPMODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_HEAPMODEL )) #define IS_HEAPMODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_HEAPMODEL )) #define HEAPMODEL_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_HEAPMODEL, HeapmodelClass )) struct _Heapmodel { Model parent_class; /* Context. */ Row *row; /* Enclosing row */ Rhs *rhs; /* Enclosing rhs */ /* Set if model has changes which have not yet been applied to the * heap ... update_model() blocks, update_heap() clears. */ gboolean modified; }; typedef struct _HeapmodelClass { ModelClass parent_class; /* Building heaps from models, building models from heaps. new_heap the heap has changed ... recurse down adding, updating (with a recursive new_heap()) and removing children update_model read the heap into the model ... eg. update text representation update_heap if the heapmodel has any unapplied user edits, use them to update the heap ... update the heap area pointed to by the last update_model clear_edited set back to default values */ void *(*new_heap)( Heapmodel *, PElement * ); void *(*update_model)( Heapmodel * ); void *(*update_heap)( Heapmodel * ); void *(*clear_edited)( Heapmodel * ); } HeapmodelClass; void *heapmodel_new_heap( Heapmodel *heapmodel, PElement *root ); void *heapmodel_update_model( Heapmodel *heapmodel ); void *heapmodel_update_heap( Heapmodel *heapmodel ); void *heapmodel_clear_edited( Heapmodel *heapmodel ); GType heapmodel_get_type( void ); void heapmodel_set_modified( Heapmodel *heapmodel, gboolean modified ); gboolean heapmodel_name( Heapmodel *heapmodel, VipsBuf *buf ); gboolean heapmodel_value( Heapmodel *heapmodel, VipsBuf *buf ); nip2-8.7.1/src/pathnameview.c0000644000175000017500000001170613351443023012746 00000000000000/* run the display for an arrow in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; static void pathnameview_link( View *view, Model *model, View *parent ) { Pathnameview *pathnameview = PATHNAMEVIEW( view ); VIEW_CLASS( parent_class )->link( view, model, parent ); if( GRAPHICVIEW( view )->sview ) gtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group, pathnameview->label ); } static void pathnameview_refresh( vObject *vobject ) { Pathnameview *pathnameview = PATHNAMEVIEW( vobject ); Pathname *pathname = PATHNAME( VOBJECT( vobject )->iobject ); #ifdef DEBUG printf( "pathnameview_refresh: " ); row_name_print( HEAPMODEL( pathname )->row ); printf( "\n" ); #endif /*DEBUG*/ if( vobject->iobject->caption ) set_glabel( pathnameview->label, _( "%s:" ), vobject->iobject->caption ); if( pathname->value ) gtk_button_set_label( GTK_BUTTON( pathnameview->button ), im_skip_dir( pathname->value ) ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void pathnameview_class_init( PathnameviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = pathnameview_refresh; view_class->link = pathnameview_link; } static void pathnameview_edit_ok( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Pathname *pathname = PATHNAME( client ); char *fname; if( (fname = filesel_get_filename( filesel )) ) { IM_SETSTR( pathname->value, fname ); classmodel_update( CLASSMODEL( pathname ) ); symbol_recalculate_all(); g_free( fname ); nfn( sys, IWINDOW_YES ); } else nfn( sys, IWINDOW_ERROR ); } static void pathnameview_clicked_cb( GtkWidget *widget, Pathnameview *pathnameview ) { Pathname *pathname = PATHNAME( VOBJECT( pathnameview )->iobject ); GtkWidget *filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), "%s", IOBJECT( pathname )->caption ); filesel_set_flags( FILESEL( filesel ), TRUE, FALSE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_any, 0 ); iwindow_set_parent( IWINDOW( filesel ), widget ); idialog_set_iobject( IDIALOG( filesel ), IOBJECT( pathname ) ); filesel_set_done( FILESEL( filesel ), pathnameview_edit_ok, pathname ); iwindow_build( IWINDOW( filesel ) ); filesel_set_filename( FILESEL( filesel ), pathname->value ); gtk_widget_show( GTK_WIDGET( filesel ) ); } static void pathnameview_init( Pathnameview *pathnameview ) { GtkWidget *hbox; #ifdef DEBUG printf( "pathnameview_init\n" ); #endif /*DEBUG*/ hbox = gtk_hbox_new( FALSE, 12 ); gtk_box_pack_start( GTK_BOX( pathnameview ), hbox, TRUE, FALSE, 0 ); pathnameview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( pathnameview->label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( pathnameview->label ), 2, 7 ); gtk_box_pack_start( GTK_BOX( hbox ), pathnameview->label, FALSE, FALSE, 2 ); pathnameview->button = gtk_button_new_with_label( "" ); gtk_box_pack_start( GTK_BOX( hbox ), pathnameview->button, TRUE, TRUE, 0 ); gtk_signal_connect( GTK_OBJECT( pathnameview->button ), "clicked", GTK_SIGNAL_FUNC( pathnameview_clicked_cb ), pathnameview ); set_tooltip( pathnameview->button, _( "Select a new file name" ) ); gtk_widget_show_all( GTK_WIDGET( hbox ) ); } GtkType pathnameview_get_type( void ) { static GtkType pathnameview_type = 0; if( !pathnameview_type ) { static const GtkTypeInfo info = { "Pathnameview", sizeof( Pathnameview ), sizeof( PathnameviewClass ), (GtkClassInitFunc) pathnameview_class_init, (GtkObjectInitFunc) pathnameview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; pathnameview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( pathnameview_type ); } View * pathnameview_new( void ) { Pathnameview *pathnameview = gtk_type_new( TYPE_PATHNAMEVIEW ); return( VIEW( pathnameview ) ); } nip2-8.7.1/src/pathname.c0000644000175000017500000000651413351443023012054 00000000000000/* an input pathname ... put/get methods */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static void pathname_dispose( GObject *gobject ) { Pathname *pathname = PATHNAME( gobject ); #ifdef DEBUG printf( "pathname_dispose\n" ); #endif /*DEBUG*/ IM_FREE( pathname->value ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static View * pathname_view_new( Model *model, View *parent ) { return( pathnameview_new() ); } static void * pathname_update_model( Heapmodel *heapmodel ) { #ifdef DEBUG printf( "pathname_update_model\n" ); #endif /*DEBUG*/ if( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ) return( heapmodel ); return( NULL ); } /* Members of pathname we automate. */ static ClassmodelMember pathname_members[] = { { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_CAPTION, "caption", N_( "Caption" ), G_STRUCT_OFFSET( iObject, caption ) }, { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Pathname, value ) } }; static void pathname_class_init( PathnameClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->dispose = pathname_dispose; model_class->view_new = pathname_view_new; heapmodel_class->update_model = pathname_update_model; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = pathname_members; classmodel_class->n_members = IM_NUMBER( pathname_members ); } static void pathname_init( Pathname *pathname ) { /* Overridden later. Just something sensible. */ pathname->value = NULL; IM_SETSTR( pathname->value, "no-file" ); iobject_set( IOBJECT( pathname ), CLASS_PATHNAME, NULL ); } GType pathname_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( PathnameClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) pathname_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Pathname ), 32, /* n_preallocs */ (GInstanceInitFunc) pathname_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Pathname", &info, 0 ); } return( type ); } nip2-8.7.1/src/trace.c0000644000175000017500000002160013351443023011346 00000000000000/* trace window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* OR of the flags in all the trace windows. */ TraceFlags trace_flags = (TraceFlags) 0; static LogClass *parent_class = NULL; /* All trace windows. */ static GSList *trace_all = NULL; /* Trace buffer stack. */ static VipsBuf trace_buffer_stack[SPINE_SIZE]; static int trace_buffer_stack_p = 0; /* Number of active trace blocks. */ static int trace_block_count = 0; /* All the trace menus we have. */ typedef struct _TraceTypeMenu { const char *name; TraceFlags flag; } TraceTypeMenu; /* Map action names to trace flags for the radio menu. */ static const TraceTypeMenu trace_types[] = { { "Operator", TRACE_OPERATOR }, { "Builtin", TRACE_BUILTIN }, { "Class", TRACE_CLASS_NEW }, { "VIPS", TRACE_VIPS } }; static TraceFlags trace_get_trace_flag( GtkAction *action ) { const char *name = gtk_action_get_name( action ); int i; for( i = 0; i < IM_NUMBER( trace_types ); i++ ) if( strcmp( name, trace_types[i].name ) == 0 ) return( trace_types[i].flag ); g_assert( FALSE ); /* Keep gcc happy. */ return( FALSE ); } void trace_block( void ) { trace_block_count += 1; } void trace_unblock( void ) { trace_block_count -= 1; g_assert( trace_block_count >= 0 ); } void trace_reset( void ) { int i; for( i = 0; i < trace_buffer_stack_p; i++ ) vips_buf_destroy( &trace_buffer_stack[i] ); trace_buffer_stack_p = 0; } void trace_check( void ) { g_assert( trace_buffer_stack_p == 0 ); } VipsBuf * trace_push( void ) { int i; #ifdef DEBUG printf( "trace_push: %d\n", trace_buffer_stack_p ); #endif if( trace_buffer_stack_p >= SPINE_SIZE ) { error_top( _( "Overflow error." ) ); error_sub( _( "Trace buffer stack overflow." ) ); reduce_throw( reduce_context ); } i = trace_buffer_stack_p++; vips_buf_init_dynamic( &trace_buffer_stack[i], MAX_TRACE ); return( &trace_buffer_stack[i] ); } void trace_pop( void ) { int i; #ifdef DEBUG printf( "trace_pop: %d\n", trace_buffer_stack_p ); #endif g_assert( trace_buffer_stack_p > 0 ); i = --trace_buffer_stack_p; vips_buf_destroy( &trace_buffer_stack[i] ); } VipsBuf * trace_current( void ) { g_assert( trace_buffer_stack_p > 0 ); return( &trace_buffer_stack[trace_buffer_stack_p - 1] ); } int trace_get_mark( void ) { return( trace_buffer_stack_p ); } void trace_pop_to( int n ) { g_assert( n >= 0 && n <= trace_buffer_stack_p ); while( trace_buffer_stack_p > n ) trace_pop(); } static void * trace_global_rethink_sub( Trace *trace ) { trace_flags |= trace->flags; return( NULL ); } /* Rethink the global trace_flags. */ static void trace_global_rethink( void ) { trace_flags = 0; slist_map( trace_all, (SListMapFn) trace_global_rethink_sub, NULL ); } static void trace_destroy( GtkObject *object ) { Trace *trace; g_return_if_fail( object != NULL ); g_return_if_fail( IS_TRACE( object ) ); trace = TRACE( object ); /* My instance destroy stuff. */ trace_all = g_slist_remove( trace_all, trace ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); trace_global_rethink(); } static void trace_view_action_cb( GtkToggleAction *action, Trace *trace ) { TraceFlags flag = trace_get_trace_flag( GTK_ACTION( action ) ); if( gtk_toggle_action_get_active( action ) ) trace->flags |= flag; else trace->flags &= flag ^ ((TraceFlags) -1); trace_global_rethink(); } /* Our actions. */ static GtkActionEntry trace_actions[] = { { "Clear", NULL, N_( "_Clear" ), NULL, N_( "Clear trace window" ), G_CALLBACK( log_clear_action_cb ) } }; static GtkToggleActionEntry trace_toggle_actions[] = { { "Operator", NULL, N_( "_Operators" ), NULL, N_( "trace operators" ), G_CALLBACK( trace_view_action_cb ), FALSE }, { "Builtin", NULL, N_( "_Builtin Functions" ), NULL, N_( "trace calls to built in functions" ), G_CALLBACK( trace_view_action_cb ), FALSE }, { "Class", NULL, N_( "_Class Construction" ), NULL, N_( "trace class constructors" ), G_CALLBACK( trace_view_action_cb ), FALSE }, { "VIPS", NULL, N_( "_VIPS Operations" ), NULL, N_( "trace calls to VIPS" ), G_CALLBACK( trace_view_action_cb ), FALSE } }; static const char *trace_menubar_ui_description = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static void trace_class_init( TraceClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; LogClass *log_class = (LogClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = trace_destroy; log_class->actions = trace_actions; log_class->n_actions = IM_NUMBER( trace_actions ); log_class->toggle_actions = trace_toggle_actions; log_class->n_toggle_actions = IM_NUMBER( trace_toggle_actions ); log_class->action_name = "TraceActions"; log_class->ui_description = trace_menubar_ui_description; log_class->menu_bar_name = "/TraceMenubar"; } static void trace_init( Trace *trace ) { trace->flags = 0; } GtkType trace_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Trace", sizeof( Trace ), sizeof( TraceClass ), (GtkClassInitFunc) trace_class_init, (GtkObjectInitFunc) trace_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_LOG, &info ); } return( type ); } static void trace_link( Trace *trace ) { iwindow_set_title( IWINDOW( trace ), _( "Trace" ) ); gtk_window_set_default_size( GTK_WINDOW( trace ), 640, 480 ); iwindow_set_size_prefs( IWINDOW( trace ), "TRACE_WIDTH", "TRACE_HEIGHT" ); iwindow_build( IWINDOW( trace ) ); trace_all = g_slist_prepend( trace_all, trace ); gtk_widget_show( GTK_WIDGET( trace ) ); } Trace * trace_new( void ) { Trace *trace = gtk_type_new( TYPE_TRACE ); trace_link( trace ); return( trace ); } static void * trace_text_sub( Trace *trace, const char *buf, TraceFlags flags ) { if( !trace_block_count && trace->flags & flags ) log_text( LOG( trace ), buf ); return( NULL ); } void trace_text( TraceFlags flags, const char *fmt, ... ) { va_list ap; char buf[MAX_STRSIZE]; if( !(trace_flags & flags) ) return; va_start( ap, fmt ); (void) im_vsnprintf( buf, MAX_STRSIZE, fmt, ap ); va_end( ap ); slist_map2( trace_all, (SListMap2Fn) trace_text_sub, buf, (void *) flags ); } void trace_pelement( PElement *pe ) { VipsBuf *buf = trace_current(); Heap *heap = reduce_context->heap; graph_pelement( heap, buf, pe, TRACE_FUNCTIONS ); } void trace_node( HeapNode *node ) { Element e; PElement pe; PEPOINTE( &pe, &e ); PEPUTP( &pe, ELEMENT_NODE, node ); trace_pelement( &pe ); } void trace_args( HeapNode **arg, int n ) { VipsBuf *buf = trace_current(); int i; for( i = n - 1; i >= 0; i-- ) { PElement rhs; PEPOINTRIGHT( arg[i], &rhs ); trace_pelement( &rhs ); vips_buf_appends( buf, " " ); } vips_buf_appendf( buf, "->\n" ); } void trace_binop( Compile *compile, PElement *left, BinOp bop, PElement *right ) { VipsBuf *buf = trace_current(); vips_buf_appendf( buf, "\"%s\" ", decode_BinOp( bop ) ); trace_pelement( left ); vips_buf_appends( buf, " " ); trace_pelement( right ); vips_buf_appends( buf, " -> (" ); compile_name( compile, buf ); vips_buf_appends( buf, ")\n" ); } void trace_uop( UnOp uop, PElement *arg ) { VipsBuf *buf = trace_current(); vips_buf_appendf( buf, "\"%s\" ", decode_UnOp( uop ) ); trace_pelement( arg ); vips_buf_appends( buf, " ->\n" ); } void trace_result( TraceFlags flags, PElement *out ) { VipsBuf *buf = trace_current(); vips_buf_appendf( buf, " " ); trace_pelement( out ); vips_buf_appends( buf, "\n" ); trace_text( flags, "%s", vips_buf_all( buf ) ); } nip2-8.7.1/src/defbrowser.c0000644000175000017500000002022013351443023012407 00000000000000/* Defbrowser dialog. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; /* Our columns. */ enum { NAME_COLUMN, /* Kit or tool name */ TOOLTIP_COLUMN, TOOL_POINTER_COLUMN, /* Pointer to tool */ KIT_POINTER_COLUMN, /* Pointer to kit (if no tool) */ N_COLUMNS }; static void defbrowser_destroy( GtkObject *object ) { Defbrowser *defbrowser = DEFBROWSER( object ); UNREF( defbrowser->store ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void defbrowser_rebuild_item3( Defbrowser *defbrowser, const char *name, const char *tip, Tool *tool, Toolkit *kit ) { GtkTreeIter iter; gtk_list_store_append( defbrowser->store, &iter ); gtk_list_store_set( defbrowser->store, &iter, NAME_COLUMN, name, TOOLTIP_COLUMN, tip, TOOL_POINTER_COLUMN, tool, KIT_POINTER_COLUMN, kit, -1 ); } static void * defbrowser_rebuild_item2( Tool *tool, Defbrowser *defbrowser ) { if( tool->toolitem && tool->toolitem->tooltip ) defbrowser_rebuild_item3( defbrowser, IOBJECT( tool )->name, tool->toolitem->tooltip, tool, tool->kit ); else defbrowser_rebuild_item3( defbrowser, IOBJECT( tool )->name, tool->help, tool, tool->kit ); return( NULL ); } static void * defbrowser_rebuild_item( Toolkit *kit, Defbrowser *defbrowser ) { toolkit_map( kit, (tool_map_fn) defbrowser_rebuild_item2, defbrowser, NULL ); return( NULL ); } static void defbrowser_refresh( vObject *vobject ) { Defbrowser *defbrowser = DEFBROWSER( vobject ); #ifdef DEBUG printf( "defbrowser_refresh:\n" ); #endif /*DEBUG*/ gtk_list_store_clear( defbrowser->store ); toolkitgroup_map( defbrowser->program->kitg, (toolkit_map_fn) defbrowser_rebuild_item, defbrowser, NULL ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void defbrowser_class_init( DefbrowserClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = defbrowser_destroy; vobject_class->refresh = defbrowser_refresh; } static void defbrowser_entry_changed_cb( GtkEditable *editable, Defbrowser *defbrowser ) { gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER( defbrowser->filter ) ); } static gboolean defbrowser_rebuild_test( Tool *tool, const char *text ) { if( tool->toolitem && tool->toolitem->tooltip ) { if( my_strcasestr( tool->toolitem->tooltip, text ) ) return( TRUE ); } if( my_strcasestr( IOBJECT( tool )->name, text ) ) return( TRUE ); return( FALSE ); } static gboolean defbrowser_visible_func( GtkTreeModel *model, GtkTreeIter *iter, gpointer data ) { Defbrowser *defbrowser = DEFBROWSER( data ); const char *text = gtk_entry_get_text( GTK_ENTRY( defbrowser->entry ) ); Tool *tool; gtk_tree_model_get( model, iter, TOOL_POINTER_COLUMN, &tool, -1 ); if( !tool ) return( FALSE ); return( defbrowser_rebuild_test( tool, text ) ); } static Tool * defbrowser_get_selected( Defbrowser *defbrowser ) { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( defbrowser->tree ) ); GtkTreeIter iter; GtkTreeModel *model; Tool *tool; if( gtk_tree_selection_get_selected( selection, &model, &iter ) ) { gtk_tree_model_get( model, &iter, TOOL_POINTER_COLUMN, &tool, -1 ); return( tool ); } return( NULL ); } static gboolean defbrowser_activate_selected( Defbrowser *defbrowser ) { Tool *tool; if( (tool = defbrowser_get_selected( defbrowser )) ) if( !program_select( defbrowser->program, MODEL( tool ) ) ) return( FALSE ); return( TRUE ); } static void defbrowser_selection_changed_cb( GtkTreeSelection *select, Defbrowser *defbrowser ) { if( !defbrowser_activate_selected( defbrowser ) ) iwindow_alert( GTK_WIDGET( defbrowser ), GTK_MESSAGE_ERROR ); } static void defbrowser_init( Defbrowser *defbrowser ) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *label; GtkWidget *swin; GtkTreeSelection *select; defbrowser->top = gtk_hbox_new( FALSE, 12 ); defbrowser->entry = gtk_entry_new(); gtk_signal_connect( GTK_OBJECT( defbrowser->entry ), "changed", GTK_SIGNAL_FUNC( defbrowser_entry_changed_cb ), defbrowser ); gtk_box_pack_end( GTK_BOX( defbrowser->top ), defbrowser->entry, FALSE, FALSE, 2 ); label = gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_MENU ); gtk_box_pack_end( GTK_BOX( defbrowser->top ), label, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( defbrowser ), defbrowser->top, FALSE, FALSE, 2 ); gtk_widget_show_all( defbrowser->top ); defbrowser->store = gtk_list_store_new( N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER ); defbrowser->filter = gtk_tree_model_filter_new( GTK_TREE_MODEL( defbrowser->store ), NULL ); gtk_tree_model_filter_set_visible_func( GTK_TREE_MODEL_FILTER( defbrowser->filter ), defbrowser_visible_func, defbrowser, NULL ); defbrowser->tree = gtk_tree_view_new_with_model( GTK_TREE_MODEL( defbrowser->filter ) ); gtk_tree_view_set_rules_hint( GTK_TREE_VIEW( defbrowser->tree ), TRUE ); gtk_tree_view_set_headers_visible( GTK_TREE_VIEW( defbrowser->tree ), FALSE ); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( _( "Name" ), renderer, "text", NAME_COLUMN, NULL ); gtk_tree_view_append_column( GTK_TREE_VIEW( defbrowser->tree ), column ); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( _( "Tooltip" ), renderer, "text", TOOLTIP_COLUMN, NULL ); gtk_tree_view_append_column( GTK_TREE_VIEW( defbrowser->tree ), column ); select = gtk_tree_view_get_selection( GTK_TREE_VIEW( defbrowser->tree ) ); gtk_tree_selection_set_mode( select, GTK_SELECTION_SINGLE ); g_signal_connect( G_OBJECT( select ), "changed", G_CALLBACK( defbrowser_selection_changed_cb ), defbrowser ); swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_container_add( GTK_CONTAINER( swin ), defbrowser->tree ); gtk_box_pack_start( GTK_BOX( defbrowser ), swin, TRUE, TRUE, 2 ); gtk_widget_show_all( swin ); } GtkType defbrowser_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Defbrowser", sizeof( Defbrowser ), sizeof( DefbrowserClass ), (GtkClassInitFunc) defbrowser_class_init, (GtkObjectInitFunc) defbrowser_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VOBJECT, &info ); } return( type ); } void defbrowser_set_program( Defbrowser *defbrowser, Program *program ) { g_assert( !defbrowser->program ); #ifdef DEBUG printf( "defbrowser_set_program:\n" ); #endif /*DEBUG*/ defbrowser->program = program; } Defbrowser * defbrowser_new( void ) { Defbrowser *defbrowser = gtk_type_new( TYPE_DEFBROWSER ); return( defbrowser ); } /* Find the 'natural' width of the browser. */ int defbrowser_get_width( Defbrowser *defbrowser ) { if( defbrowser->top ) return( defbrowser->top->requisition.width ); else return( 200 ); } /* Set the filter string. */ void defbrowser_set_filter( Defbrowser *defbrowser, const char *filter ) { gtk_entry_set_text( GTK_ENTRY( defbrowser->entry ), filter ); } nip2-8.7.1/src/workspace.h0000644000175000017500000001513113351443023012255 00000000000000/* Declarations for workspace.c. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_WORKSPACE (workspace_get_type()) #define WORKSPACE( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WORKSPACE, Workspace )) #define WORKSPACE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WORKSPACE, WorkspaceClass)) #define IS_WORKSPACE( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WORKSPACE )) #define IS_WORKSPACE_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACE )) #define WORKSPACE_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WORKSPACE, WorkspaceClass )) /* Three sorts of workspace file load. */ typedef enum { WORKSPACE_MODE_REGULAR, /* Vanilla! */ WORKSPACE_MODE_FORMULA, /* Show formula, not values */ WORKSPACE_MODE_NOEDIT /* Shut down all edits */ } WorkspaceMode; /* A workspace. */ struct _Workspace { Model parent_object; /* Our rows are part of this symbol. */ Symbol *sym; /* We are using this set of toolkits. */ Toolkitgroup *kitg; /* State. */ int next; /* Index for next column name */ GSList *selected; /* Rows selected in this workspace */ GSList *errors; /* Rows with errors */ WorkspaceMode mode; /* Display mode */ gboolean locked; /* WS has been locked */ /* The nip2 version that made this workspace. */ int major; int minor; /* We may load some compat definitions to support this workspace, if it * was written by an older version. * * The version number of the compat stuff we loaded. Zero for no compat * stuff loaded. */ int compat_major; int compat_minor; /* The last row we scrolled to on next-error. */ Row *last_error; Rect area; /* Rect enclosing the set of columns */ Rect vp; /* Viewport hint ... set by views */ gboolean lpane_open; /* Pane model */ int lpane_position; gboolean rpane_open; int rpane_position; char *status; /* Status message */ /* Visualisation defaults for this ws. */ double scale; double offset; /* Workspace-local defs, displayed in the left pane. All in a private * kitg and kit. */ char *local_defs; Toolkitgroup *local_kitg; Toolkit *local_kit; /* Some view inside this ws has changed and this ws needs a relayout. * Use in_dispose to stop relayout during ws shutdown. */ gboolean needs_layout; gboolean in_dispose; }; typedef struct _WorkspaceClass { ModelClass parent_class; /* Methods. */ } WorkspaceClass; void workspace_set_needs_layout( Workspace *ws, gboolean needs_layout ); GSList *workspace_get_needs_layout(); Workspacegroup *workspace_get_workspacegroup( Workspace *ws ); Workspaceroot *workspace_get_workspaceroot( Workspace *ws ); void workspace_set_modified( Workspace *ws, gboolean modified ); void *workspace_map( workspace_map_fn fn, void *a, void *b ); void *workspace_map_column( Workspace *ws, column_map_fn fn, void *a ); void *workspace_map_symbol( Workspace *ws, symbol_map_fn fn, void *a ); void *workspace_map_view( Workspace *ws, view_map_fn fn, void *a ); gboolean workspace_is_empty( Workspace *ws ); void *workspace_selected_map( Workspace *ws, row_map_fn fn, void *a, void *b ); void *workspace_selected_map_sym( Workspace *ws, symbol_map_fn fn, void *a, void *b ); gboolean workspace_selected_any( Workspace *ws ); int workspace_selected_num( Workspace *ws ); gboolean workspace_selected_sym( Workspace *ws, Symbol *sym ); Row *workspace_selected_one( Workspace *ws ); void workspace_deselect_all( Workspace *ws ); void workspace_selected_names( Workspace *ws, VipsBuf *buf, const char *separator ); void workspace_column_names( Column *col, VipsBuf *buf, const char *separator ); void workspace_select_all( Workspace *ws ); Column *workspace_is_one_empty( Workspace *ws ); Column *workspace_column_find( Workspace *ws, const char *name ); Column *workspace_column_get( Workspace *ws, const char *name ); void workspace_column_name_new( Workspace *ws, char *name ); Column *workspace_column_pick( Workspace *ws ); void workspace_column_select( Workspace *ws, Column *col ); Column *workspace_column_new( Workspace *ws ); Symbol *workspace_add_def( Workspace *ws, const char *str ); Symbol *workspace_add_def_recalc( Workspace *ws, const char *str ); gboolean workspace_load_file_buf( VipsBuf *buf, const char *filename ); Symbol *workspace_load_file( Workspace *ws, const char *filename ); void workspace_get_version( Workspace *ws, int *major, int *minor ); int workspace_have_compat( int major, int minor, int *best_major, int *best_minor ); gboolean workspace_load_compat( Workspace *ws, int major, int minor ); GType workspace_get_type( void ); Workspace *workspace_new( Workspacegroup *wsg, const char *name ); Workspace *workspace_new_blank( Workspacegroup *wsg ); gboolean workspace_add_action( Workspace *ws, const char *name, const char *action, int nparam ); int workspace_number( void ); gboolean workspace_selected_recalc( Workspace *ws ); void workspace_selected_remove_yesno( Workspace *ws, GtkWidget *parent ); gboolean workspace_selected_ungroup( Workspace *ws ); gboolean workspace_selected_group( Workspace *ws ); gboolean workspace_next_error( Workspace *ws ); void workspace_set_status( Workspace *ws, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); void workspace_set_mode( Workspace *ws, WorkspaceMode mode ); gboolean workspace_local_set( Workspace *ws, const char *txt ); gboolean workspace_local_set_from_file( Workspace *ws, const char *fname ); void workspace_jump_update( Workspace *ws, GtkWidget *menu ); gboolean workspace_merge_file( Workspace *ws, const char *filename ); gboolean workspace_selected_duplicate( Workspace *ws ); gboolean workspace_selected_save( Workspace *ws, const char *filename ); gboolean workspace_rename( Workspace *ws, const char *name, const char *caption ); void workspace_set_locked( Workspace *ws, gboolean locked ); gboolean workspace_duplicate( Workspace *ws ); nip2-8.7.1/src/cache.c0000644000175000017500000005716213351443023011327 00000000000000/* Call vips functions, cache recent results */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG_TIME #define DEBUG_HISTORY_SANITY #define DEBUG_HISTORY_MISS #define DEBUG_HISTORY #define DEBUG */ /* This is usually turned on from a -D in cflags. #define DEBUG_LEAK */ /* Often want it off ... we get spurious complaints about leaks if an * operation has no images in or out (eg. im_version) because it'll never * get GCed. #undef DEBUG_LEAK */ /* The previous function calls we are caching, plus an LRU queue for flushing. */ static GHashTable *cache_history_table = NULL; static Queue *cache_history_lru = NULL; int cache_history_size = 0; /* Hash from a vargv ... just look at input args and the function name. */ static unsigned int cache_hash( CallInfo *vi ) { int i; unsigned int hash; if( vi->found_hash ) return( vi->hash ); hash = 0; /* add ints, floats, pointers and strings to the hash. FIXME ... could do better on double? could or top and bottom 32 bits but would this be stupid on a 64 bit machine? */ #define HASH_I( I ) hash = (hash << 1) | ((unsigned int) (I)); #define HASH_D( D ) hash = (hash << 1) | ((unsigned int) (D)); #define HASH_P( P ) hash = (hash << 1) | (GPOINTER_TO_UINT( P )); #define HASH_S( S ) hash = (hash << 1) | g_str_hash( S ); /* Add the function to the hash. We often call many functions on * the same args, we'd like these calls to hash to different numbers. */ HASH_P( vi->fn ); for( i = 0; i < vi->fn->argc; i++ ) { im_type_desc *ty = vi->fn->argv[i].desc; if( call_type_needs_input( ty ) ) { switch( call_lookup_type( ty->type ) ) { case CALL_DOUBLE: HASH_D( *((double *) vi->vargv[i]) ); break; case CALL_INT: HASH_I( *((int *) vi->vargv[i]) ); break; case CALL_COMPLEX: HASH_D( ((double *) vi->vargv[i])[0] ); HASH_D( ((double *) vi->vargv[i])[1] ); break; case CALL_STRING: HASH_S( (char *) vi->vargv[i] ); break; case CALL_GVALUE: case CALL_INTERPOLATE: break; case CALL_DOUBLEVEC: { im_doublevec_object *v = (im_doublevec_object *) vi->vargv[i]; int j; for( j = 0; j < v->n; j++ ) HASH_D( v->vec[j] ); break; } case CALL_INTVEC: { im_intvec_object *v = (im_intvec_object *) vi->vargv[i]; int j; for( j = 0; j < v->n; j++ ) HASH_I( v->vec[j] ); break; } case CALL_DMASK: { im_mask_object *mo = vi->vargv[i]; DOUBLEMASK *mask = mo->mask; /* mask can be NULL if we are called after * call_new() but before we've built the arg * list. */ if( mask ) { int ne = mask->xsize * mask->ysize; int j; for( j = 0; j < ne; j++ ) HASH_D( mask->coeff[j] ); HASH_D( mask->scale ); HASH_D( mask->offset ); } break; } case CALL_IMASK: { im_mask_object *mo = vi->vargv[i]; INTMASK *mask = mo->mask; /* mask can be NULL if we are called after * call_new() but before we've built the arg * list. */ if( mask ) { int ne = mask->xsize * mask->ysize; int j; for( j = 0; j < ne; j++ ) HASH_I( mask->coeff[j] ); HASH_I( mask->scale ); HASH_I( mask->offset ); } break; } default: case CALL_NONE: break; } } } /* And the input images. */ for( i = 0; i < vi->ninii; i++ ) HASH_P( vi->inii[i] ); vi->found_hash = TRUE; vi->hash = hash; return( hash ); } /* Are two function calls equal. Check the func and the input args. */ static gboolean cache_equal( CallInfo *vi1, CallInfo *vi2 ) { int i; im_function *fn = vi1->fn; if( vi1 == vi2 ) return( TRUE ); if( vi1->fn != vi2->fn ) return( FALSE ); for( i = 0; i < fn->argc; i++ ) { im_type_desc *ty = fn->argv[i].desc; if( call_type_needs_input( ty ) ) { switch( call_lookup_type( ty->type ) ) { case CALL_DOUBLE: if( *((double *) vi1->vargv[i]) != *((double *) vi2->vargv[i]) ) return( FALSE ); break; case CALL_INT: if( *((int *) vi1->vargv[i]) != *((int *) vi2->vargv[i]) ) return( FALSE ); break; case CALL_COMPLEX: if( ((double *) vi1->vargv[i])[0] != ((double *) vi2->vargv[i])[0] ) return( FALSE ); if( ((double *) vi1->vargv[i])[1] != ((double *) vi2->vargv[i])[1] ) return( FALSE ); break; case CALL_STRING: if( strcmp( (char *) vi1->vargv[i], (char *) vi2->vargv[i] ) != 0 ) return( FALSE ); break; case CALL_DOUBLEVEC: { im_doublevec_object *v1 = (im_doublevec_object *) vi1->vargv[i]; im_doublevec_object *v2 = (im_doublevec_object *) vi2->vargv[i]; int j; for( j = 0; j < v1->n; j++ ) if( v1->vec[j] != v2->vec[j] ) return( FALSE ); break; } case CALL_INTVEC: { im_intvec_object *v1 = (im_intvec_object *) vi1->vargv[i]; im_intvec_object *v2 = (im_intvec_object *) vi2->vargv[i]; int j; for( j = 0; j < v1->n; j++ ) if( v1->vec[j] != v2->vec[j] ) return( FALSE ); break; } case CALL_DMASK: { im_mask_object *mo1 = (im_mask_object *) vi1->vargv[i]; im_mask_object *mo2 = (im_mask_object *) vi2->vargv[i]; DOUBLEMASK *mask1 = mo1->mask; DOUBLEMASK *mask2 = mo2->mask; int ne = mask1->xsize * mask2->ysize; int j; if( mask1->xsize != mask2->xsize || mask1->ysize != mask2->ysize ) return( FALSE ); for( j = 0; j < ne; j++ ) if( mask1->coeff[j] != mask2->coeff[j] ) return( FALSE ); if( mask1->scale != mask2->scale ) return( FALSE ); if( mask1->offset != mask2->offset ) return( FALSE ); break; } case CALL_IMASK: { im_mask_object *mo1 = (im_mask_object *) vi1->vargv[i]; im_mask_object *mo2 = (im_mask_object *) vi2->vargv[i]; INTMASK *mask1 = mo1->mask; INTMASK *mask2 = mo2->mask; int ne = mask1->xsize * mask2->ysize; int j; if( mask1->xsize != mask2->xsize || mask1->ysize != mask2->ysize ) return( FALSE ); for( j = 0; j < ne; j++ ) if( mask1->coeff[j] != mask2->coeff[j] ) return( FALSE ); if( mask1->scale != mask2->scale ) return( FALSE ); if( mask1->offset != mask2->offset ) return( FALSE ); break; } case CALL_IMAGEVEC: { im_imagevec_object *v1 = (im_imagevec_object *) vi1->vargv[i]; im_imagevec_object *v2 = (im_imagevec_object *) vi2->vargv[i]; if( v1->n != v2->n ) return( FALSE ); break; } /* Very strict. Could be more generous here: we'd need * to have a pspec for each argument type and then use * g_param_values_cmp() to test equality. */ case CALL_GVALUE: if( vi1->vargv[i] != vi2->vargv[i] ) return( FALSE ); break; case CALL_INTERPOLATE: if( vi1->vargv[i] != vi2->vargv[i] ) return( FALSE ); break; default: case CALL_NONE: break; } } } /* And the input images. */ if( vi1->ninii != vi2->ninii ) return( FALSE ); for( i = 0; i < vi1->ninii; i++ ) if( vi1->inii[i] != vi2->inii[i] ) return( FALSE ); return( TRUE ); } #ifdef DEBUG_HISTORY_SANITY static void cache_history_sanity_sub( CallInfo *vi ) { g_assert( g_slist_find( cache_history_lru->list, vi ) ); } static void cache_history_sanity( void ) { GSList *p; if( !cache_history_lru || !cache_history_table ) return; /* Everything that's on the LRU should be in the history table. */ for( p = cache_history_lru->list; p; p = p->next ) { CallInfo *vi = (CallInfo *) p->data; g_assert( g_hash_table_lookup( cache_history_table, vi ) ); g_assert( vi->fn ); g_assert( vi->fn->argc > 0 && vi->fn->argc < MAX_CALL_ARGS ); g_assert( vi->in_cache ); } /* Everything that's on the history table should be in the LRU. */ g_hash_table_foreach( cache_history_table, (GHFunc) cache_history_sanity_sub, NULL ); } #endif /*DEBUG_HISTORY_SANITY */ /* Is a function call in our history? Return the old one. */ static CallInfo * cache_history_lookup( CallInfo *vi ) { CallInfo *old_vi; if( !cache_history_table ) { cache_history_table = g_hash_table_new( (GHashFunc) cache_hash, (GEqualFunc) cache_equal ); cache_history_lru = queue_new(); } old_vi = (CallInfo *) g_hash_table_lookup( cache_history_table, vi ); #ifdef DEBUG_HISTORY if( old_vi ) printf( "cache_history_lookup: found \"%s\"\n", old_vi->name ); #endif /*DEBUG_HISTORY*/ #ifdef DEBUG_HISTORY_SANITY cache_history_sanity(); #endif /*DEBUG_HISTORY_SANITY*/ return( old_vi ); } /* Bump to end of LRU. */ static void cache_history_touch( CallInfo *vi ) { g_assert( vi->in_cache ); queue_remove( cache_history_lru, vi ); queue_add( cache_history_lru, vi ); #ifdef DEBUG_HISTORY_SANITY cache_history_sanity(); #endif /*DEBUG_HISTORY_SANITY*/ #ifdef DEBUG_HISTORY printf( "cache_history_touch: bumping \"%s\"\n", vi->name ); #endif /*DEBUG_HISTORY*/ } /* Are we in the history? Remove us. Called from cache_info_dispose() on unref, * don't call this directly. */ void cache_history_remove( CallInfo *vi ) { int i; if( vi->in_cache ) { queue_remove( cache_history_lru, vi ); g_hash_table_remove( cache_history_table, vi ); cache_history_size -= 1; vi->in_cache = FALSE; #ifdef DEBUG_HISTORY printf( "cache_history_remove: removing \"%s\"\n", vi->name ); #endif /*DEBUG_HISTORY*/ } /* Disconnect signals. */ for( i = 0; i < vi->noutii; i++ ) FREESID( vi->outii_destroy_sid[i], vi->outii[i] ); for( i = 0; i < vi->ninii; i++ ) { FREESID( vi->inii_destroy_sid[i], vi->inii[i] ); FREESID( vi->inii_invalidate_sid[i], vi->inii[i] ); } #ifdef DEBUG_HISTORY_SANITY cache_history_sanity(); #endif /*DEBUG_HISTORY_SANITY*/ } static void cache_history_remove_lru( void ) { CallInfo *vi; vi = (CallInfo *) queue_head( cache_history_lru ); #ifdef DEBUG_HISTORY printf( "cache_history_remove_lru: flushing \"%s\"\n", vi->name ); #endif /*DEBUG_HISTORY*/ g_object_unref( vi ); #ifdef DEBUG_HISTORY_SANITY cache_history_sanity(); #endif /*DEBUG_HISTORY_SANITY*/ } static void cache_history_destroy_cb( Imageinfo *ii, CallInfo *vi ) { #ifdef DEBUG_HISTORY printf( "cache_history_destroy_cb: on death of ii, uncaching \"%s\"\n", vi->name ); #endif /*DEBUG_HISTORY*/ g_object_unref( vi ); } static void cache_history_invalidate_cb( Imageinfo *ii, CallInfo *vi ) { #ifdef DEBUG_HISTORY printf( "cache_history_invalidate_cb: " "on invalidate of ii, uncaching \"%s\"\n", vi->name ); #endif /*DEBUG_HISTORY*/ g_object_unref( vi ); } /* Add a function call to the history. */ static void cache_history_add( CallInfo *vi ) { int i; #ifdef DEBUG_HISTORY_SANITY cache_history_sanity(); #endif /*DEBUG_HISTORY_SANITY*/ #ifdef DEBUG_HISTORY printf( "cache_history_add: adding \"%s\" (%p), hash = %u\n", vi->name, vi, vi->hash ); #endif /*DEBUG_HISTORY*/ g_assert( !g_hash_table_lookup( cache_history_table, vi ) ); g_assert( !vi->in_cache ); g_hash_table_insert( cache_history_table, vi, vi ); cache_history_size += 1; g_assert( g_hash_table_lookup( cache_history_table, vi ) ); queue_add( cache_history_lru, vi ); vi->in_cache = TRUE; g_object_ref( vi ); /* If any of our ii are destroyed, we must go too. */ for( i = 0; i < vi->noutii; i++ ) vi->outii_destroy_sid[i] = g_signal_connect( vi->outii[i], "destroy", G_CALLBACK( cache_history_destroy_cb ), vi ); /* If any of our input ii are destroyed or painted on, we must also * uncache. */ for( i = 0; i < vi->ninii; i++ ) { vi->inii_destroy_sid[i] = g_signal_connect( vi->inii[i], "destroy", G_CALLBACK( cache_history_destroy_cb ), vi ); vi->inii_invalidate_sid[i] = g_signal_connect( vi->inii[i], "invalidate", G_CALLBACK( cache_history_invalidate_cb ), vi ); } /* History too big? Flush! */ if( queue_length( cache_history_lru ) > CALL_HISTORY_MAX ) cache_history_remove_lru(); #ifdef DEBUG_HISTORY_SANITY cache_history_sanity(); #endif /*DEBUG_HISTORY_SANITY*/ } /* Sort out the input images. */ static gboolean cache_gather( CallInfo *vi ) { int i, j; int ni; /* No input images. */ if( vi->ninii == 0 ) return( TRUE ); /* Can we LUT? Function needs to be LUTable, all input images * have to be the same underlying image, and image must be uncoded * IM_BANDFMT_UCHAR. */ vi->use_lut = (vi->fn->flags & IM_FN_PTOP) && imageinfo_same_underlying( vi->inii, vi->ninii ) && imageinfo_get_underlying( vi->inii[0] )->Coding == IM_CODING_NONE && imageinfo_get_underlying( vi->inii[0] )->BandFmt == IM_BANDFMT_UCHAR; if( vi->use_lut ) for( i = 0; i < vi->noutii; i++ ) imageinfo_set_underlying( vi->outii[i], vi->inii[0] ); /* Now fill the vargv vector with the IMAGE pointers. */ ni = 0; for( i = 0; i < vi->fn->argc; i++ ) { im_type_desc *ty = vi->fn->argv[i].desc; if( !call_type_needs_input( ty ) ) continue; if( strcmp( ty->type, IM_TYPE_IMAGE ) == 0 ) { Imageinfo *inii = vi->inii[ni++]; IMAGE *im; if( !(im = imageinfo_get( vi->use_lut, inii )) ) return( FALSE ); /* RW operations need an extra copy. Tyhe vargv will * already have been created by cache_build_output(). */ if( ty->flags & IM_TYPE_RW ) { if( im_copy( im, vi->vargv[i] ) ) return( FALSE ); } else vi->vargv[i] = im; } if( strcmp( ty->type, IM_TYPE_IMAGEVEC ) == 0 ) { im_imagevec_object *iv = (im_imagevec_object *) vi->vargv[i]; /* Found an input image vector. Add all the imageinfo * in the vector. */ for( j = 0; j < iv->n; j++ ) { Imageinfo *inii = vi->inii[ni++]; IMAGE *im; if( !(im = imageinfo_get( vi->use_lut, inii )) ) return( FALSE ); iv->vec[j] = im; } } } /* We should have used up all the images exactly. */ g_assert( ni == vi->ninii ); return( TRUE ); } /* VIPS types -> a string buffer. Yuk! Should be a method on object type. This * is used to generate vips history, so it has to be in sh format. */ void cache_tochar_shell( CallInfo *vi, int i, VipsBuf *buf ) { im_object obj = vi->vargv[i]; im_type_desc *ty = vi->fn->argv[i].desc; switch( call_lookup_type( ty->type ) ) { case CALL_DOUBLE: vips_buf_appendf( buf, "%g", *((double*)obj) ); break; case CALL_INT: vips_buf_appendf( buf, "%d", *((int*)obj) ); break; case CALL_COMPLEX: vips_buf_appendf( buf, "(%g, %g)", ((double*)obj)[0], ((double*)obj)[1] ); break; case CALL_STRING: vips_buf_appendf( buf, "\"%s\"", (char*)obj ); break; case CALL_IMAGE: { IMAGE *im = (IMAGE *) obj; /* In quotes, in case there are spaces in the * filename. We also need to test im, as we might be called * before the im has been generated. */ vips_buf_appendf( buf, "\"%s\"", im ? im->filename : "null" ); break; } case CALL_DMASK: case CALL_IMASK: { im_mask_object *mo = obj; vips_buf_appendf( buf, "%s", NN( mo->name ) ); break; } case CALL_DOUBLEVEC: { im_doublevec_object *v = (im_doublevec_object *) obj; int j; vips_buf_appendf( buf, "\"" ); for( j = 0; j < v->n; j++ ) vips_buf_appendf( buf, "%g ", v->vec[j] ); vips_buf_appendf( buf, "\"" ); break; } case CALL_INTVEC: { im_intvec_object *v = (im_intvec_object *) obj; int j; vips_buf_appendf( buf, "\"" ); for( j = 0; j < v->n; j++ ) vips_buf_appendf( buf, "%d ", v->vec[j] ); vips_buf_appendf( buf, "\"" ); break; } case CALL_IMAGEVEC: { im_imagevec_object *v = (im_imagevec_object *) obj; int j; vips_buf_appendf( buf, "\"" ); for( j = 0; j < v->n; j++ ) vips_buf_appendf( buf, "%s ", v->vec[j]->filename ); vips_buf_appendf( buf, "\"" ); break; } case CALL_GVALUE: { GValue *value = (GValue *) obj; vips_buf_appendgv( buf, value ); break; } case CALL_INTERPOLATE: vips_object_to_string( VIPS_OBJECT( obj ), buf ); break; case CALL_NONE: if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) /* Just assume sRGB. */ vips_buf_appendf( buf, "sRGB" ); break; default: g_assert( FALSE ); } } /* VIPS types -> a buffer. For tracing calls and debug. */ void cache_tochar_trace( CallInfo *vi, int i, VipsBuf *buf ) { im_object obj = vi->vargv[i]; im_type_desc *vips = vi->fn->argv[i].desc; switch( call_lookup_type( vips->type ) ) { case CALL_DOUBLE: vips_buf_appendf( buf, "%g", *((double*)obj) ); break; case CALL_INT: vips_buf_appendf( buf, "%d", *((int*)obj) ); break; case CALL_COMPLEX: vips_buf_appendf( buf, "(%g, %g)", ((double*)obj)[0], ((double*)obj)[1] ); break; case CALL_STRING: vips_buf_appendf( buf, "\"%s\"", (char*) obj ); break; case CALL_IMAGE: vips_buf_appendi( buf, (IMAGE *) obj ); break; case CALL_DMASK: vips_buf_appendf( buf, "dmask" ); break; case CALL_IMASK: vips_buf_appendf( buf, "imask" ); break; case CALL_DOUBLEVEC: vips_buf_appendf( buf, "doublevec" ); break; case CALL_INTVEC: vips_buf_appendf( buf, "intvec" ); break; case CALL_IMAGEVEC: vips_buf_appendf( buf, "imagevec" ); break; case CALL_GVALUE: { GValue *value = (GValue *) obj; vips_buf_appends( buf, "(gvalue" ); vips_buf_appendgv( buf, value ); vips_buf_appendf( buf, ")" ); break; } case CALL_INTERPOLATE: vips_object_to_string( VIPS_OBJECT( obj ), buf ); break; default: g_assert( FALSE ); } } /* Get the args from the VIPS call buffer. */ static void cache_args_vips( CallInfo *vi, VipsBuf *buf ) { int i; vips_buf_appendf( buf, _( "You passed:" ) ); vips_buf_appendf( buf, "\n" ); for( i = 0; i < vi->fn->argc; i++ ) { im_type_desc *ty = vi->fn->argv[i].desc; char *name = vi->fn->argv[i].name; if( call_type_needs_input( ty ) ) { vips_buf_appendf( buf, " %s - ", name ); cache_tochar_trace( vi, i, buf ); vips_buf_appendf( buf, "\n" ); } } } /* There's a problem calling the function. Show args from the vips call * struct. */ static void cache_error_fn_vips( CallInfo *vi ) { char txt[1000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); error_top( _( "VIPS library error." ) ); vips_buf_appendf( &buf, _( "Error calling library function \"%s\" (%s)." ), vi->name, vi->fn->desc ); vips_buf_appendf( &buf, "\n" ); vips_buf_appendf( &buf, _( "VIPS library: %s" ), im_error_buffer() ); im_error_clear(); vips_buf_appendf( &buf, "\n" ); cache_args_vips( vi, &buf ); vips_buf_appendf( &buf, "\n" ); call_usage( &buf, vi->fn ); error_sub( "%s", vips_buf_all( &buf ) ); } static gboolean cache_build_argv( CallInfo *vi, char **argv ) { int i; for( i = 0; i < vi->fn->argc; i++ ) { char txt[512]; VipsBuf buf = VIPS_BUF_STATIC( txt ); cache_tochar_shell( vi, i, &buf ); if( !(argv[i] = im_strdup( NULL, vips_buf_all( &buf ) )) ) return( FALSE ); } #ifdef DEBUG printf( "cache_build_argv: argv for %s is:\n ", vi->fn->name ); for( i = 0; i < vi->fn->argc; i++ ) printf( "%s ", NN( argv[i] ) ); printf( "\n" ); #endif /*DEBUG*/ return( TRUE ); } static void cache_free_argv( int argc, char **argv ) { int i; for( i = 0; i < argc; i++ ) { IM_FREE( argv[i] ); } IM_FREE( argv ); } /* Update the VIPS hist for all output images. */ static void cache_update_hist( CallInfo *vi ) { int argc = vi->fn->argc; char **argv; int i; #ifdef DEBUG printf( "cache_update_hist: %s\n", vi->name ); #endif /*DEBUG*/ /* No output images? Nothing to do. */ if( vi->nires == 0 ) return; /* Build an argv for this call. +1 for NULL termination. */ if( !(argv = IM_ARRAY( NULL, argc + 1, char * )) ) return; for( i = 0; i < argc + 1; i++ ) argv[i] = NULL; if( !cache_build_argv( vi, argv ) ) { cache_free_argv( argc, argv ); return; } for( i = 0; i < vi->nres; i++ ) { int j = vi->outpos[i]; im_type_desc *ty = vi->fn->argv[j].desc; /* Image output. */ if( call_lookup_type( ty->type ) == CALL_IMAGE ) { #ifdef DEBUG printf( "cache_update_hist: adding to arg %d\n", j ); #endif /*DEBUG*/ im_updatehist( vi->vargv[j], vi->fn->name, argc, argv ); } } cache_free_argv( argc, argv ); } /* Call a vips operation. * * The cache takes ownership of the CallInfo passed in, and returns a ref to a * CallInfo (might be a different one) that contains the result. Should be * unreffed when you're done with it. * * On error, return NULL. */ CallInfo * cache_dispatch( CallInfo *vi, PElement *out ) { CallInfo *old_vi; #ifdef DEBUG_HISTORY_SANITY cache_history_sanity(); #endif /*DEBUG_HISTORY_SANITY*/ /* Calculate the hash for this vi after building it, but before we do * cache_gather(); * * We want the hash to reflect the args as supplied by nip2, not the * args as transformed by cache_gather() for this specific call. */ (void) cache_hash( vi ); /* Look over the images we have and turn input Imageinfos to IMAGEs. * If we can do this with a lut, set all that up. */ if( !cache_gather( vi ) ) { g_object_unref( vi ); return( NULL ); } /* We have to show args after gather, since the tracer wants IMAGE not * Imageinfo. */ #ifdef DEBUG { int i; for( i = 0; i < vi->fn->argc; i++ ) { im_type_desc *ty = vi->fn->argv[i].desc; char txt[512]; VipsBuf buf = VIPS_BUF_STATIC( txt ); printf( "cache_fill_spine: arg[%d] (%s) = ", i, ty->type ); cache_tochar_trace( vi, i, &buf ); printf( "%s\n", vips_buf_all( &buf ) ); } } #endif /*DEBUG*/ /* Is this function call in the history? */ if( (old_vi = cache_history_lookup( vi )) ) { /* Yes: reuse! unref our arg to junk it, adda ref to the * cached call for our caller. */ g_object_unref( vi ); vi = old_vi; g_object_ref( vi ); if( trace_flags & TRACE_VIPS ) vips_buf_appendf( trace_current(), "(from cache) " ); #ifdef DEBUG_HISTORY printf( "cache_dispatch: found %s in history\n", vi->name ); #endif /*DEBUG_HISTORY*/ } else { /* No: call function. */ int result; #ifdef DEBUG_TIME static GTimer *timer = NULL; if( !timer ) timer = g_timer_new(); g_timer_reset( timer ); #endif /*DEBUG_TIME*/ #ifdef DEBUG_HISTORY_MISS printf( "cache_dispatch: calling %s\n", vi->name ); #endif /*DEBUG_HISTORY_MISS*/ /* Be careful. Eval callbacks from this may do anything, * including call cache_dispatch(). */ result = vi->fn->disp( vi->vargv ); #ifdef DEBUG_TIME printf( "cache_dispatch: %s - %g seconds\n", vi->name, g_timer_elapsed( timer, NULL ) ); #endif /*DEBUG_TIME*/ if( result ) { cache_error_fn_vips( vi ); g_object_unref( vi ); return( NULL ); } cache_update_hist( vi ); } /* Add to our operation cache, if necessary. */ if( !(vi->fn->flags & IM_FN_NOCACHE) ) { if( vi->in_cache ) /* Already in the history. Just touch the time. */ cache_history_touch( vi ); else if( (old_vi = cache_history_lookup( vi )) ) { /* We have an equal but older item there? This can * happen with nested calls. Touch the old one. */ cache_history_touch( old_vi ); vi = old_vi; } else cache_history_add( vi ); } #ifdef DEBUG_HISTORY_SANITY cache_history_sanity(); #endif /*DEBUG_HISTORY_SANITY*/ return( vi ); } nip2-8.7.1/src/vector.h0000644000175000017500000000263513351443023011566 00000000000000/* a vector in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_VECTOR (vector_get_type()) #define VECTOR( obj ) (GTK_CHECK_CAST( (obj), TYPE_VECTOR, Vector )) #define VECTOR_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_VECTOR, VectorClass )) #define IS_VECTOR( obj ) (GTK_CHECK_TYPE( (obj), TYPE_VECTOR )) #define IS_VECTOR_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_VECTOR )) typedef struct _Vector { Value parent_object; } Vector; typedef struct _VectorClass { ValueClass parent_class; /* My methods. */ } VectorClass; GType vector_get_type( void ); nip2-8.7.1/src/main.h0000644000175000017500000000370113351443023011203 00000000000000/* Declarations supporting main.c. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ extern Workspaceroot *main_workspaceroot; /* All the workspaces */ extern Toolkitgroup *main_toolkitgroup; /* All the toolkits */ extern Symbol *main_symbol_root; /* Root of symtable */ extern Watchgroup *main_watchgroup; /* All of the watches */ extern Imageinfogroup *main_imageinfogroup; /* All of the images */ extern void *main_c_stack_base; /* Base of C stack */ extern gboolean main_starting; /* In startup */ extern gboolean main_option_time_save; /* Time save image ops */ extern gboolean main_option_profile; /* Profile calcualtion */ extern gboolean main_option_i18n; /* Output i18n strings */ extern gboolean main_option_batch; /* Running in batch mode */ extern gboolean main_option_verbose; /* Verbose output */ /* Styles for buttons etc. */ extern GtkStyle *default_style; extern GtkStyle *selected_style; extern GtkStyle *error_style; extern GtkStyle *ok_style; extern GtkStyle *tooltip_style; extern GtkStyle *leaf_style; extern GtkStyle *dirty_style; void main_quit_test( void ); void main_reload( void ); const char *get_prefix( void ); nip2-8.7.1/src/iimageview.h0000644000175000017500000000327313351443023012411 00000000000000/* a iimageview in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IIMAGEVIEW (iimageview_get_type()) #define IIMAGEVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_IIMAGEVIEW, iImageview )) #define IIMAGEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_IIMAGEVIEW, iImageviewClass )) #define IS_IIMAGEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IIMAGEVIEW )) #define IS_IIMAGEVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_IIMAGEVIEW )) typedef struct _iImageview { Graphicview parent_object; guint popup_sid; /* id for popup menu */ Imagedisplay *id; Conversion *conv; GtkWidget *label; } iImageview; typedef struct _iImageviewClass { GraphicviewClass parent_class; /* My methods. */ } iImageviewClass; GtkWidget *iimageview_drag_window_new( int width, int height ); GtkType iimageview_get_type( void ); View *iimageview_new( void ); nip2-8.7.1/src/graphwindow.h0000644000175000017500000000373213351443023012614 00000000000000/* display workspaces with graphviz */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_GRAPHWINDOW (graphwindow_get_type()) #define GRAPHWINDOW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_GRAPHWINDOW, Graphwindow )) #define GRAPHWINDOW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_GRAPHWINDOW, GraphwindowClass )) #define IS_GRAPHWINDOW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_GRAPHWINDOW )) #define IS_GRAPHWINDOW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_GRAPHWINDOW )) struct _Graphwindow { Floatwindow parent_class; /* The last dot graph we generated. */ char *dot; /* Regenerate the graph on a timeout to avoid regen on many small * changes. */ guint layout_timeout; /* The imagedisplay we make. */ Imagemodel *imagemodel; Imagepresent *ip; /* Watch the ws with this. */ guint workspace_changed_sid; #ifdef HAVE_LIBGVC GVC_t *gvc; graph_t *graph; #endif /*HAVE_LIBGVC*/ }; typedef struct _GraphwindowClass { FloatwindowClass parent_class; /* My methods. */ } GraphwindowClass; void graph_write( Workspace *ws ); GtkType graphwindow_get_type( void ); Graphwindow *graphwindow_new( Workspace *ws, GtkWidget *parent ); nip2-8.7.1/src/error.c0000644000175000017500000001165113351443023011406 00000000000000/* ierror window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static LogClass *parent_class = NULL; static void * ierror_print( Expr *expr, iError *ierror, gboolean *found ) { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); expr_error_print( expr, &buf ); log_text( LOG( ierror ), vips_buf_all( &buf ) ); *found = TRUE; return( NULL ); } static void ierror_show_all( iError *ierror ) { gboolean found; found = FALSE; slist_map2( expr_error_all, (SListMap2Fn) ierror_print, ierror, &found ); if( !found ) { log_text( LOG( ierror ), _( "No ierrors found." ) ); log_text( LOG( ierror ), "\n" ); } } static void ierror_show_all_action_cb( GtkAction *action, iError *ierror ) { ierror_show_all( ierror ); } static void * unresolved_print_tool( Tool *tool, iError *ierror, gboolean *found ) { char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); tool_linkreport_tool( tool, &buf, found ); log_text( LOG( ierror ), vips_buf_all( &buf ) ); return( NULL ); } static void * unresolved_print( Toolkit *kit, iError *ierror, gboolean *found ) { toolkit_map( kit, (tool_map_fn) unresolved_print_tool, ierror, found ); return( NULL ); } static void unresolved_show_all( iError *ierror ) { gboolean found; found = FALSE; (void) toolkitgroup_map( ierror->kitg, (toolkit_map_fn) unresolved_print, ierror, &found ); if( !found ) { log_text( LOG( ierror ), _( "No unresolved symbols found." ) ); log_text( LOG( ierror ), "\n" ); } } static void unresolved_show_all_action_cb( GtkAction *action, iError *ierror ) { unresolved_show_all( ierror ); } /* Our actions. */ static GtkActionEntry ierror_actions[] = { { "Clear", NULL, N_( "_Clear" ), NULL, N_( "Clear ierror window" ), G_CALLBACK( log_clear_action_cb ) }, { "iErrors", NULL, N_( "List _iErrors" ), NULL, N_( "Search for all ierrors" ), G_CALLBACK( ierror_show_all_action_cb ) }, { "Unresolved", NULL, N_( "List _Unresolved" ), NULL, N_( "Search for all unresolved references" ), G_CALLBACK( unresolved_show_all_action_cb ) } }; static const char *ierror_menubar_ui_description = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static void ierror_class_init( iErrorClass *class ) { LogClass *log_class = (LogClass *) class; parent_class = g_type_class_peek_parent( class ); log_class->actions = ierror_actions; log_class->n_actions = IM_NUMBER( ierror_actions ); log_class->action_name = "iErrorActions"; log_class->ui_description = ierror_menubar_ui_description; log_class->menu_bar_name = "/iErrorMenubar"; } static void ierror_init( iError *ierror ) { } GtkType ierror_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "iError", sizeof( iError ), sizeof( iErrorClass ), (GtkClassInitFunc) ierror_class_init, (GtkObjectInitFunc) ierror_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_LOG, &info ); } return( type ); } static void ierror_link( iError *ierror, Toolkitgroup *kitg ) { ierror->kitg = kitg; destroy_if_destroyed( G_OBJECT( ierror ), G_OBJECT( kitg ), (DestroyFn) gtk_widget_destroy ); iwindow_set_title( IWINDOW( ierror ), _( "iError - %s" ), IOBJECT( kitg )->name ); gtk_window_set_default_size( GTK_WINDOW( ierror ), 640, 480 ); iwindow_set_size_prefs( IWINDOW( ierror ), "IERROR_WIDTH", "IERROR_HEIGHT" ); iwindow_build( IWINDOW( ierror ) ); } iError * ierror_new( Toolkitgroup *kitg ) { iError *ierror = gtk_type_new( TYPE_IERROR ); ierror_link( ierror, kitg ); ierror_show_all( ierror ); unresolved_show_all( ierror ); return( ierror ); } nip2-8.7.1/src/util.c0000644000175000017500000015260713351443023011241 00000000000000/* Some basic util functions. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Handy for tracing errors. #define DEBUG_ERROR */ /* Prettyprint xml save files. FIXME ... slight mem leak, and save files are much larger ... but leave it on for convenience */ #define DEBUG_SAVEFILE #include "ip.h" /* Track errors messages in this thing. We keep two messages: a principal * error, and extra informative text. For example "Unable to load file.", * "Read failed for file blah, permission denied.". */ static char error_top_text[MAX_STRSIZE]; static char error_sub_text[MAX_STRSIZE]; VipsBuf error_top_buf = VIPS_BUF_STATIC( error_top_text ); VipsBuf error_sub_buf = VIPS_BUF_STATIC( error_sub_text ); /* Useful: Error message and quit. Emergencies only ... we don't tidy up * properly. */ void error( const char *fmt, ... ) { va_list args; fprintf( stderr, IP_NAME ": " ); va_start( args, fmt ); (void) vfprintf( stderr, fmt, args ); va_end( args ); fprintf( stderr, "\n" ); #ifdef DEBUG /* Make a coredump. */ abort(); #endif /*DEBUG*/ exit( 1 ); } /* Set this to block error messages. Useful if we've found an error, we want * to clean up, but we don't want any of the clean-up code to touch the error * buffer. */ static int error_level = 0; void error_block( void ) { error_level++; } void error_unblock( void ) { g_assert( error_level ); error_level--; } /* Set an error buffer. */ static void error_set( VipsBuf *buf, const char *fmt, va_list ap ) { if( !error_level ) { char txt[MAX_STRSIZE]; VipsBuf tmp = VIPS_BUF_STATIC( txt ); /* The string we write may contain itself ... write to an * intermediate, then copy to main. */ vips_buf_vappendf( &tmp, fmt, ap ); vips_buf_rewind( buf ); (void) vips_buf_appends( buf, vips_buf_all( &tmp ) ); #ifdef DEBUG_ERROR printf( "error: %p %s\n", buf, vips_buf_all( buf ) ); #endif /*DEBUG_ERROR*/ } } void error_clear_nip( void ) { if( !error_level ) { vips_buf_rewind( &error_top_buf ); vips_buf_rewind( &error_sub_buf ); #ifdef DEBUG_ERROR printf( "error_clear_nip\n" ); #endif /*DEBUG_ERROR*/ } } void error_clear( void ) { if( !error_level ) { error_clear_nip(); im_error_clear(); } } void error_top( const char *fmt, ... ) { va_list ap; va_start( ap, fmt ); error_set( &error_top_buf, fmt, ap ); va_end( ap ); /* We could use error_clear_nip() before calling error_set(), but that * fails if the arg to us uses the contents of either error buffer. */ if( !error_level ) vips_buf_rewind( &error_sub_buf ); } void error_sub( const char *fmt, ... ) { va_list ap; va_start( ap, fmt ); error_set( &error_sub_buf, fmt, ap ); va_end( ap ); } /* Append any VIPS errors to sub buffer. */ void error_vips( void ) { if( !error_level && strlen( im_error_buffer() ) > 0 ) { if( !vips_buf_is_empty( &error_sub_buf ) ) (void) vips_buf_appendf( &error_sub_buf, "\n" ); (void) vips_buf_appendf( &error_sub_buf, "%s", im_error_buffer() ); im_error_clear(); } } void error_vips_all( void ) { error_top( _( "VIPS library error." ) ); error_vips(); } const char *error_get_top( void ) { return( vips_buf_all( &error_top_buf ) ); } const char *error_get_sub( void ) { return( vips_buf_all( &error_sub_buf ) ); } /* Set an xml property printf() style. */ gboolean set_prop( xmlNode *xnode, const char *name, const char *fmt, ... ) { va_list ap; char value[MAX_STRSIZE]; va_start( ap, fmt ); (void) im_vsnprintf( value, MAX_STRSIZE, fmt, ap ); va_end( ap ); if( !xmlSetProp( xnode, (xmlChar *) name, (xmlChar *) value ) ) { error_top( _( "Unable to set XML property." ) ); error_sub( _( "Unable to set property \"%s\" " "to value \"%s\"." ), name, value ); return( FALSE ); } return( TRUE ); } /* Set an xml property from an optionally NULL string. */ gboolean set_sprop( xmlNode *xnode, const char *name, const char *value ) { if( value && !set_prop( xnode, name, "%s", value ) ) return( FALSE ); return( TRUE ); } /* Set an xml property from an optionally NULL string. */ gboolean set_iprop( xmlNode *xnode, const char *name, int value ) { return( set_prop( xnode, name, "%d", value ) ); } /* Save a list of strings. For name=="fred" and n strings in list, save as * "fredn" == n, "fred0" == list[0], etc. */ gboolean set_slprop( xmlNode *xnode, const char *name, GSList *labels ) { if( labels ) { char buf[256]; int i; (void) im_snprintf( buf, 256, "%sn", name ); if( !set_prop( xnode, buf, "%d", g_slist_length( labels ) ) ) return( FALSE ); for( i = 0; labels; i++, labels = labels->next ) { const char *label = (const char *) labels->data; (void) im_snprintf( buf, 256, "%s%d", name, i ); if( !set_sprop( xnode, buf, label ) ) return( FALSE ); } } return( TRUE ); } /* Set a double ... use non-localisable conversion, rather than %g. */ gboolean set_dprop( xmlNode *xnode, const char *name, double value ) { char buf[G_ASCII_DTOSTR_BUF_SIZE]; g_ascii_dtostr( buf, sizeof( buf ), value ); return( set_sprop( xnode, name, buf ) ); } /* Save an array of double. For name=="fred" and n doubles in array, save as * "fredn" == n, "fred0" == array[0], etc. */ gboolean set_dlprop( xmlNode *xnode, const char *name, double *values, int n ) { char buf[256]; int i; (void) im_snprintf( buf, 256, "%sn", name ); if( !set_prop( xnode, buf, "%d", n ) ) return( FALSE ); for( i = 0; i < n; i++ ) { (void) im_snprintf( buf, 256, "%s%d", name, i ); if( !set_dprop( xnode, buf, values[i] ) ) return( FALSE ); } return( TRUE ); } gboolean get_sprop( xmlNode *xnode, const char *name, char *buf, int sz ) { char *value = (char *) xmlGetProp( xnode, (xmlChar *) name ); if( !value ) return( FALSE ); im_strncpy( buf, value, sz ); IM_FREEF( xmlFree, value ); return( TRUE ); } gboolean get_spropb( xmlNode *xnode, const char *name, VipsBuf *buf ) { char *value = (char *) xmlGetProp( xnode, (xmlChar *) name ); if( !value ) return( FALSE ); vips_buf_appends( buf, value ); IM_FREEF( xmlFree, value ); return( TRUE ); } gboolean get_iprop( xmlNode *xnode, const char *name, int *out ) { char buf[256]; if( !get_sprop( xnode, name, buf, 256 ) ) return( FALSE ); *out = atoi( buf ); return( TRUE ); } gboolean get_dprop( xmlNode *xnode, const char *name, double *out ) { char buf[256]; if( !get_sprop( xnode, name, buf, 256 ) ) return( FALSE ); *out = g_ascii_strtod( buf, NULL ); return( TRUE ); } gboolean get_bprop( xmlNode *xnode, const char *name, gboolean *out ) { char buf[256]; if( !get_sprop( xnode, name, buf, 256 ) ) return( FALSE ); *out = strcasecmp( buf, "true" ) == 0; return( TRUE ); } /* Load a list of strings. For name=="fred", look for "fredn" == number of * strings to load, "fred0" == list[0], etc. */ gboolean get_slprop( xmlNode *xnode, const char *name, GSList **out ) { char buf[256]; int n, i; (void) im_snprintf( buf, 256, "%sn", name ); if( !get_iprop( xnode, buf, &n ) ) return( FALSE ); *out = NULL; for( i = n - 1; i >= 0; i-- ) { (void) im_snprintf( buf, 256, "%s%d", name, i ); if( !get_sprop( xnode, buf, buf, 256 ) ) return( FALSE ); *out = g_slist_prepend( *out, g_strdup( buf ) ); } return( TRUE ); } /* Load an array of double. For name=="fred", look for "fredn" == length of * array, "fred0" == array[0], etc. */ gboolean get_dlprop( xmlNode *xnode, const char *name, double **out ) { char buf[256]; int n, i; (void) im_snprintf( buf, 256, "%sn", name ); if( !get_iprop( xnode, buf, &n ) ) return( FALSE ); if( !(*out = IARRAY( NULL, n, double )) ) return( FALSE ); for( i = 0; i < n; i++ ) { (void) im_snprintf( buf, 256, "%s%d", name, i ); if( !get_dprop( xnode, buf, *out + i ) ) return( FALSE ); } return( TRUE ); } /* Find the first child node with a name. */ xmlNode * get_node( xmlNode *base, const char *name ) { xmlNode *i; for( i = base->children; i; i = i->next ) if( strcmp( (char *) i->name, name ) == 0 ) return( i ); return( NULL ); } static int rect_n_rects = 0; /* Allocate and free rects. */ Rect * rect_dup( Rect *init ) { Rect *new_rect; if( !(new_rect = INEW( NULL, Rect )) ) return( NULL ); *new_rect = *init; rect_n_rects += 1; return( new_rect ); } void * rect_free( Rect *rect ) { im_free( rect ); rect_n_rects -= 1; return( NULL ); } /* Test two lists for eqality. */ gboolean slist_equal( GSList *l1, GSList *l2 ) { while( l1 && l2 ) { if( l1->data != l2->data ) return( FALSE ); l1 = l1->next; l2 = l2->next; } if( l1 || l2 ) return( FALSE ); return( TRUE ); } /* Map over an slist. */ void * slist_map( GSList *list, SListMapFn fn, gpointer a ) { GSList *copy; GSList *i; void *result; copy = g_slist_copy( list ); result = NULL; for( i = copy; i && !(result = fn( i->data, a )); i = i->next ) ; g_slist_free( copy ); return( result ); } void * slist_map2( GSList *list, SListMap2Fn fn, gpointer a, gpointer b ) { GSList *copy; GSList *i; void *result; copy = g_slist_copy( list ); result = NULL; for( i = copy; i && !(result = fn( i->data, a, b )); i = i->next ) ; g_slist_free( copy ); return( result ); } void * slist_map3( GSList *list, SListMap3Fn fn, gpointer a, gpointer b, gpointer c ) { GSList *copy; GSList *i; void *result; copy = g_slist_copy( list ); result = NULL; for( i = copy; i && !(result = fn( i->data, a, b, c )); i = i->next ) ; g_slist_free( copy ); return( result ); } void * slist_map4( GSList *list, SListMap4Fn fn, gpointer a, gpointer b, gpointer c, gpointer d ) { GSList *copy; GSList *i; void *result; copy = g_slist_copy( list ); result = NULL; for( i = copy; i && !(result = fn( i->data, a, b, c, d )); i = i->next ) ; g_slist_free( copy ); return( result ); } void * slist_map5( GSList *list, SListMap5Fn fn, gpointer a, gpointer b, gpointer c, gpointer d, gpointer e ) { GSList *copy; GSList *i; void *result; copy = g_slist_copy( list ); result = NULL; for( i = copy; i && !(result = fn( i->data, a, b, c, d, e )); i = i->next ) ; g_slist_free( copy ); return( result ); } /* Map backwards. */ void * slist_map_rev( GSList *list, SListMapFn fn, gpointer a ) { GSList *copy; GSList *i; void *result; copy = g_slist_copy( list ); copy = g_slist_reverse( copy ); result = NULL; for( i = copy; i && !(result = fn( i->data, a )); i = i->next ) ; g_slist_free( copy ); return( result ); } void * slist_map2_rev( GSList *list, SListMap2Fn fn, gpointer a, gpointer b ) { GSList *copy; GSList *i; void *result; copy = g_slist_copy( list ); copy = g_slist_reverse( copy ); result = NULL; for( i = copy; i && !(result = fn( i->data, a, b )); i = i->next ) ; g_slist_free( copy ); return( result ); } void * slist_map3_rev( GSList *list, SListMap3Fn fn, void *a, void *b, void *c ) { GSList *copy; GSList *i; void *result; copy = g_slist_copy( list ); copy = g_slist_reverse( copy ); result = NULL; for( i = copy; i && !(result = fn( i->data, a, b, c )); i = i->next ) ; g_slist_free( copy ); return( result ); } void * map_equal( void *a, void *b ) { if( a == b ) return( a ); return( NULL ); } void * slist_fold( GSList *list, void *start, SListFoldFn fn, void *a ) { void *c; GSList *ths, *next; for( c = start, ths = list; ths; ths = next ) { next = ths->next; if( !(c = fn( ths->data, c, a )) ) return( NULL ); } return( c ); } void * slist_fold2( GSList *list, void *start, SListFold2Fn fn, void *a, void *b ) { void *c; GSList *ths, *next; for( c = start, ths = list; ths; ths = next ) { next = ths->next; if( !(c = fn( ths->data, c, a, b )) ) return( NULL ); } return( c ); } static void slist_free_all_cb( gpointer thing, gpointer dummy ) { g_free( thing ); } /* Free a g_slist of things which need g_free()ing. */ void slist_free_all( GSList *list ) { g_slist_foreach( list, slist_free_all_cb, NULL ); g_slist_free( list ); } /* Remove all occurences of an item from a list. */ GSList * slist_remove_all( GSList *list, gpointer data ) { GSList *tmp; GSList *prev; prev = NULL; tmp = list; while( tmp ) { if( tmp->data == data ) { GSList *next = tmp->next; if( prev ) prev->next = next; if( list == tmp ) list = next; tmp->next = NULL; g_slist_free( tmp ); tmp = next; } else { prev = tmp; tmp = tmp->next; } } return( list ); } Queue * queue_new( void ) { Queue *q = INEW( NULL, Queue ); q->list = NULL; q->tail = NULL; q->length = 0; return( q ); } void * queue_head( Queue *q ) { void *data; g_assert( q ); if( !q->list ) return( NULL ); data = q->list->data; q->list = g_slist_remove( q->list, data ); if( !q->list ) q->tail = NULL; q->length -= 1; return( data ); } void queue_add( Queue *q, void *data ) { if( !q->tail ) { g_assert( !q->list ); q->list = q->tail = g_slist_append( q->list, data ); } else { g_assert( q->list ); q->tail = g_slist_append( q->tail, data ); q->tail = q->tail->next; } q->length += 1; } /* Not very fast! But used infrequently. TRUE if the data was in the queue and * has now been removed. */ gboolean queue_remove( Queue *q, void *data ) { GSList *ele; if( !(ele = g_slist_find( q->list, data )) ) return( FALSE ); q->list = g_slist_remove( q->list, data ); if( ele == q->tail ) q->tail = g_slist_last( q->list ); q->length -= 1; return( TRUE ); } int queue_length( Queue *q ) { return( q->length ); } /* Make an info string about an image. */ void vips_buf_appendi( VipsBuf *buf, IMAGE *im ) { if( !im ) { vips_buf_appends( buf, _( "(no image)" ) ); return; } /* Coded? Special warning. */ if( im->Coding != IM_CODING_NONE ) vips_buf_appendf( buf, "%s, ", NN( im_Coding2char( im->Coding ) ) ); /* Format string expands to (eg.) * "2000x3000 128-bit complex, 3 bands, Lab" */ vips_buf_appendf( buf, ngettext( "%dx%d %s, %d band, %s", "%dx%d %s, %d bands, %s", im->Bands ), im->Xsize, im->Ysize, decode_bandfmt( im->BandFmt ), im->Bands, decode_type( im->Type ) ); } /* Append a string, escaping C stuff. Escape double quotes if quote is set. */ gboolean vips_buf_appendsc( VipsBuf *buf, gboolean quote, const char *str ) { char buffer[FILENAME_MAX]; char buffer2[FILENAME_MAX]; /* /2 to leave a bit of space. */ im_strncpy( buffer, str, FILENAME_MAX / 2 ); /* FIXME ... possible buffer overflow :-( */ my_strecpy( buffer2, buffer, quote ); return( vips_buf_appends( buf, buffer2 ) ); } /* Test for string a ends string b. */ gboolean is_postfix( const char *a, const char *b ) { int n = strlen( a ); int m = strlen( b ); if( m < n ) return( FALSE ); return( !strcmp( a, b + m - n ) ); } /* Test for string a ends string b, case independent. */ gboolean is_casepostfix( const char *a, const char *b ) { int n = strlen( a ); int m = strlen( b ); if( m < n ) return( FALSE ); return( !strcasecmp( a, b + m - n ) ); } /* Test for string a starts string b. */ gboolean is_prefix( const char *a, const char *b ) { int n = strlen( a ); int m = strlen( b ); int i; if( m < n ) return( FALSE ); for( i = 0; i < n; i++ ) if( a[i] != b[i] ) return( FALSE ); return( TRUE ); } /* Test for string a starts string b ... case insensitive. */ gboolean is_caseprefix( const char *a, const char *b ) { int n = strlen( a ); int m = strlen( b ); int i; if( m < n ) return( FALSE ); for( i = 0; i < n; i++ ) if( toupper( a[i] ) != toupper( b[i] ) ) return( FALSE ); return( TRUE ); } /* Like strstr(), but case-insensitive. */ char * my_strcasestr( const char *haystack, const char *needle ) { int i; int hlen = strlen( haystack ); int nlen = strlen( needle ); for( i = 0; i <= hlen - nlen; i++ ) if( is_caseprefix( needle, haystack + i ) ) return( (char *) (haystack + i) ); return( NULL ); } /* Copy a string, interpreting (a few) C-language escape codes. FIXME ... yuk! dangerous and not that useful, needs a proper function to do this */ char * my_strccpy( char *output, const char *input ) { const char *p; char *q; for( p = input, q = output; *p; p++, q++ ) if( p[0] == '\\' ) { switch( p[1] ) { case 'n': q[0] = '\n'; break; case 't': q[0] = '\t'; break; case 'r': q[0] = '\r'; break; case '"': q[0] = '\"'; break; case '\'': q[0] = '\''; break; case '\\': q[0] = '\\'; break; default: /* Leave uninterpreted. */ q[0] = p[0]; q[1] = p[1]; q++; break; } p++; } else q[0] = p[0]; q[0] = '\0'; return( output ); } /* Copy a string, expanding escape characters into C-language escape codes. * Escape double quotes if quote is set. */ char * my_strecpy( char *output, const char *input, gboolean quote ) { const char *p; char *q; for( p = input, q = output; *p; p++, q++ ) switch( p[0] ) { case '\n': q[0] = '\\'; q[1] = 'n'; q++; break; case '\t': q[0] = '\\'; q[1] = 't'; q++; break; case '\r': q[0] = '\\'; q[1] = 'r'; q++; break; case '\"': if( quote ) { q[0] = '\\'; q[1] = '\"'; q++; } else q[0] = p[0]; break; case '\'': q[0] = '\\'; q[1] = '\''; q++; break; case '\\': q[0] = '\\'; q[1] = '\\'; q++; break; default: q[0] = p[0]; break; } q[0] = '\0'; return( output ); } /* Is a character in a string? */ static int instr( char c, const char *spn ) { const char *p; for( p = spn; *p; p++ ) if( *p == c ) return( 1 ); return( 0 ); } /* Doh ... not everyone has strrspn(), define one. Return a pointer to the * start of the trailing segment of p which contains only chars in spn. */ const char * my_strrspn( const char *p, const char *spn ) { const char *p1; for( p1 = p + strlen( p ) - 1; p1 >= p && instr( *p1, spn ); p1-- ) ; p1++; return( p1 ); } /* Find a pointer to the start of the trailing segment of p which contains * only chars not in spn. */ const char * my_strrcspn( const char *p, const char *spn ) { const char *p1; for( p1 = p + strlen( p ) - 1; p1 >= p && !instr( *p1, spn ); p1-- ) ; p1++; return( p1 ); } /* Find the rightmost occurence of string a in string b. */ const char * findrightmost( const char *a, const char *b ) { int la = strlen( a ); int lb = strlen( b ); int i; if( lb < la ) return( NULL ); for( i = lb - la; i > 0; i-- ) if( strncmp( a, &b[i], la ) == 0 ) return( &b[i] ); return( NULL ); } /* Useful transformation: strip off a set of suffixes (eg. ".v", ".icon", * ".hr"), add a single new suffix (eg. ".hr.v"). */ void change_suffix( const char *name, char *out, const char *new, const char **olds, int nolds ) { char *p; int i; /* Copy start string. */ strcpy( out, name ); /* Drop all matching suffixes. */ while( (p = strrchr( out, '.' )) ) { /* Found suffix - test against list of alternatives. Ignore * case. */ for( i = 0; i < nolds; i++ ) if( strcasecmp( p, olds[i] ) == 0 ) { *p = '\0'; break; } /* Found match? If not, break from loop. */ if( *p ) break; } /* Add new suffix. */ strcat( out, new ); } /* Drop leading and trim trailing non-alphanum characters. NULL if nothing * left. The result can be a variable name. */ char * trim_nonalpha( char *text ) { char *p, *q; /* Skip any initial non-alpha characters. */ for( q = text; *q && !isalpha( (int)(*q) ); q++ ) ; /* Find next non-alphanumeric character. */ for( p = q; *p && isalnum( (int)(*p) ); p++ ) ; *p = '\0'; if( strlen( q ) == 0 ) return( NULL ); else return( q ); } /* Drop leading and trim trailing whitespace characters. NULL if nothing * left. */ char * trim_white( char *text ) { char *p, *q; /* Skip any initial whitespace characters. */ for( q = text; *q && isspace( (int)(*q) ); q++ ) ; /* Find rightmost non-space char. */ for( p = q + strlen( q ) - 1; p > q && isspace( (int)(*p) ); p-- ) ; p[1] = '\0'; if( strlen( q ) == 0 ) return( NULL ); else return( q ); } /* Get a pointer to a band element in a region. */ void * get_element( REGION *ireg, int x, int y, int b ) { IMAGE *im = ireg->im; /* Return a pointer to this on error. */ static PEL empty[50] = { 0 }; PEL *data; int es = IM_IMAGE_SIZEOF_ELEMENT( im ); Rect iarea; /* Make sure we can read from this descriptor. */ if( im_pincheck( im ) ) /* Help! */ return( empty ); /* Ask for the area we need. */ iarea.left = x; iarea.top = y; iarea.width = 1; iarea.height = 1; if( im_prepare( ireg, &iarea ) ) return( empty ); /* Find a pointer to the start of the data. */ data = (PEL *) IM_REGION_ADDR( ireg, x, y ) + b * es; return( (void *) data ); } /* Decode band formats in a friendly way. */ static const char *bandfmt_names[] = { N_( "8-bit unsigned integer" ), /* IM_BANDFMT_UCHAR */ N_( "8-bit signed integer" ), /* IM_BANDFMT_CHAR */ N_( "16-bit unsigned integer" ),/* IM_BANDFMT_USHORT */ N_( "16-bit signed integer" ), /* IM_BANDFMT_SHORT */ N_( "32-bit unsigned integer" ),/* IM_BANDFMT_UINT */ N_( "32-bit signed integer" ), /* IM_BANDFMT_INT */ N_( "32-bit float" ), /* IM_BANDFMT_FLOAT */ N_( "64-bit complex" ), /* IM_BANDFMT_COMPLEX */ N_( "64-bit float" ), /* IM_BANDFMT_DOUBLE */ N_( "128-bit complex" ) /* IM_BANDFMT_DPCOMPLEX */ }; static const int nbandfmt_names = IM_NUMBER( bandfmt_names ); const char * decode_bandfmt( int f ) { if( f > nbandfmt_names - 1 || f < 0 ) return( _( "" ) ); else return( _( bandfmt_names[f] ) ); } /* Decode type names in a way consistent with the menus. */ static const char *type_names[] = { "multiband", /* IM_TYPE_MULTIBAND 0 */ "mono", /* IM_TYPE_B_W 1 */ "luminance", /* LUMINACE 2 */ "xray", /* XRAY 3 */ "infrared", /* IR 4 */ "Yuv", /* YUV 5 */ "red_only", /* RED_ONLY 6 */ "green_only", /* GREEN_ONLY 7 */ "blue_only", /* BLUE_ONLY 8 */ "power_spectrum", /* POWER_SPECTRUM 9 */ "histogram", /* IM_TYPE_HISTOGRAM 10 */ "lookup_table", /* LUT 11 */ "XYZ", /* IM_TYPE_XYZ 12 */ "Lab", /* IM_TYPE_LAB 13 */ "CMC", /* CMC 14 */ "CMYK", /* IM_TYPE_CMYK 15 */ "LabQ", /* IM_TYPE_LABQ 16 */ "RGB", /* IM_TYPE_RGB 17 */ "UCS", /* IM_TYPE_UCS 18 */ "LCh", /* IM_TYPE_LCH 19 */ "", /* ?? 20 */ "LabS", /* IM_TYPE_LABS 21 */ "sRGB", /* IM_TYPE_sRGB 22 */ "Yxy", /* IM_TYPE_YXY 23 */ "Fourier", /* IM_TYPE_FOURIER 24 */ "RGB16", /* IM_TYPE_RGB16 25 */ "GREY16", /* IM_TYPE_GREY16 26 */ "Array", /* VIPS_INTERPRETATION_ARRAY = 27 */ "scRGB" /* VIPS_INTERPRETATION_scRGB = 28 */ }; static const int ntype_names = IM_NUMBER( type_names ); const char * decode_type( int t ) { if( t > ntype_names - 1 || t < 0 ) return( _( "" ) ); else return( type_names[t] ); } /* Make an info string about a file. */ void get_image_info( VipsBuf *buf, const char *name ) { char name2[FILENAME_MAX]; struct stat st; expand_variables( name, name2 ); vips_buf_appendf( buf, "%s, ", im_skip_dir( name ) ); /* Read size and file/dir. */ if( stat( name2, &st ) == -1 ) { vips_buf_appendf( buf, "%s", g_strerror( errno ) ); return; } if( S_ISDIR( st.st_mode ) ) vips_buf_appends( buf, _( "directory" ) ); else if( S_ISREG( st.st_mode ) ) { IMAGE *im; /* Spot workspace files from the filename. These are XML files * and if imagemagick sees them it'll try to load them as SVG * or somethiing awful like that. */ if( is_file_type( &filesel_wfile_type, name2 ) ) { vips_buf_appends( buf, _( "workspace" ) ); } else if( (im = im_open( name2, "r" )) ) { vips_buf_appendi( buf, im ); im_close( im ); } else /* No idea wtf this is, just put the size in. */ vips_buf_append_size( buf, st.st_size ); } } /* A char that can be part of an environment variable name? A-Za-z0-9_ */ static gboolean isvariable( int ch ) { return( isalnum( ch ) || ch == '_' ); } /* Expand environment variables from in to out. Return true if we performed an * expansion, false for no variables there. */ static gboolean expand_once( char *in, char *out ) { char *p, *q; gboolean have_substituted = FALSE; /* Scan and copy. */ for( p = in, q = out; (*q = *p) && (q - out) < FILENAME_MAX; p++, q++ ) /* Did we just copy a '$'? */ if( *p == '$' ) { char vname[FILENAME_MAX]; char *r; const char *subst; const char *s; /* Extract the variable name. */ p++; for( r = vname; isvariable( (int)(*r = *p) ) && (r - vname) < FILENAME_MAX; p++, r++ ) ; *r = '\0'; p--; /* Look up variable. */ subst = g_getenv( vname ); /* Copy variable contents. */ if( subst ) { for( s = subst; (*q = *s) && (q - out) < FILENAME_MAX; s++, q++ ) ; } q--; /* Remember we have performed a substitution. */ have_substituted = TRUE; } /* Or a '~' at the start of the string? */ else if( *p == '~' && p == in ) { const char *subst = g_getenv( "HOME" ); const char *r; /* Copy variable contents. */ if( subst ) { for( r = subst; (*q = *r) && (q - out) < FILENAME_MAX; r++, q++ ) ; } q--; /* Remember we have performed a substitution. */ have_substituted = TRUE; } return( have_substituted ); } /* Expand all variables! Don't touch in, assume out[] is at least * FILENAME_MAX bytes. in and out must not point to the same place! */ void expand_variables( const char *in, char *out ) { char buf[FILENAME_MAX]; char *p1 = (char *) in; /* Discard const, but safe */ char *p2 = out; g_assert( in != out ); /* Expand any environment variables in component. */ while( expand_once( p1, p2 ) ) /* We have expanded --- swap the buffers and try * again. */ if( p2 == out ) { p1 = out; p2 = buf; } else { p1 = buf; p2 = out; } } static void swap_chars( char *buf, char from, char to ) { int i; for( i = 0; buf[i]; i++ ) if( buf[i] == from ) buf[i] = to; } /* If we use '/' seps, swap all '\' for '/' ... likewise vice versa. Only in * the filename part, though. We don't want to junk '\,', for example. */ void nativeize_path( char *buf ) { char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; im_filename_split( buf, filename, mode ); if( G_DIR_SEPARATOR == '/' ) swap_chars( filename, '\\', '/' ); else swap_chars( filename, '/', '\\' ); if( strcmp( mode, "" ) != 0 ) im_snprintf( buf, FILENAME_MAX, "%s:%s", filename, mode ); else im_snprintf( buf, FILENAME_MAX, "%s", filename ); } /* Change all occurences of "from" into "to". This will loop if "to" contains * "from", beware. */ static void swap_string( char *buffer, const char *from, const char *to ) { char *p; while( (p = strstr( buffer, from )) ) { int off = p - buffer; char buf2[FILENAME_MAX]; im_strncpy( buf2, buffer, FILENAME_MAX ); buf2[off] = '\0'; im_snprintf( buffer, FILENAME_MAX, "%s%s%s", buf2, to, buf2 + off + strlen( from ) ); } } /* Remove "." and ".." from an absolute path (if we can). */ void canonicalize_path( char *path ) { gboolean found; g_assert( is_absolute( path ) ); /* Any "/./" can go. */ swap_string( path, G_DIR_SEPARATOR_S "." G_DIR_SEPARATOR_S, G_DIR_SEPARATOR_S ); /* Any "//" can go. */ swap_string( path, G_DIR_SEPARATOR_S G_DIR_SEPARATOR_S, G_DIR_SEPARATOR_S ); /* Repeatedly search for "/[^/]+/../" and remove it. FIXME ... yuk, should search backwards from the end of the string */ do { char *p; found = FALSE; for( p = path; (p = strchr( p, G_DIR_SEPARATOR )); p++ ) { char *q; q = strchr( p + 1, G_DIR_SEPARATOR ); if( q && is_prefix( G_DIR_SEPARATOR_S "..", q ) ) { memmove( p, q + 3, strlen( q + 3 ) + 1 ); found = TRUE; break; } } } while( found ); /* We may have the empty string ... that's just '/'. */ if( strcmp( path, "" ) == 0 ) strcpy( path, G_DIR_SEPARATOR_S ); } /* Absoluteize a path. Must be FILENAME_MAX chars available. */ void absoluteize_path( char *path ) { if( !is_absolute( path ) ) { char buf[FILENAME_MAX]; char *cwd; im_strncpy( buf, path, FILENAME_MAX ); cwd = g_get_current_dir(); im_snprintf( path, FILENAME_MAX, "%s%s%s", cwd, G_DIR_SEPARATOR_S, buf ); g_free( cwd ); canonicalize_path( path ); } } /* Call a void*-valued function, building a string arg. We expand env. * variables, but that's all. */ void * callv_string( callv_string_fn fn, const char *arg, void *a, void *b, void *c ) { char buf[FILENAME_MAX]; expand_variables( arg, buf ); return( fn( buf, a, b, c ) ); } void * callv_stringva( callv_string_fn fn, const char *fmt, va_list ap, void *a, void *b, void *c ) { char buf[FILENAME_MAX]; (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap ); return( callv_string( fn, buf, a, b, c ) ); } void * callv_stringf( callv_string_fn fn, const char *fmt, ... ) { va_list ap; void *res; va_start( ap, fmt ); res = callv_stringva( fn, fmt, ap, NULL, NULL, NULL ); va_end( ap ); return( res ); } /* Call a function, building a filename arg. Nativize and absoluteize too. */ void * callv_string_filename( callv_string_fn fn, const char *filename, void *a, void *b, void *c ) { char buf[FILENAME_MAX]; expand_variables( filename, buf ); nativeize_path( buf ); absoluteize_path( buf ); return( fn( buf, a, b, c ) ); } void * callv_string_filenameva( callv_string_fn fn, const char *fmt, va_list ap, void *a, void *b, void *c ) { char buf[FILENAME_MAX]; (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap ); return( callv_string_filename( fn, buf, a, b, c ) ); } void * callv_string_filenamef( callv_string_fn fn, const char *fmt, ... ) { va_list ap; void *res; va_start( ap, fmt ); res = callv_string_filenameva( fn, fmt, ap, NULL, NULL, NULL ); va_end( ap ); return( res ); } /* Call an int-valued function, building a string arg. We expand env. * variables, but that's all. */ int calli_string( calli_string_fn fn, const char *arg, void *a, void *b, void *c ) { char buf[FILENAME_MAX]; expand_variables( arg, buf ); return( fn( buf, a, b, c ) ); } int calli_stringva( calli_string_fn fn, const char *fmt, va_list ap, void *a, void *b, void *c ) { char buf[FILENAME_MAX]; (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap ); return( calli_string( fn, buf, a, b, c ) ); } int calli_stringf( calli_string_fn fn, const char *fmt, ... ) { va_list ap; int res; va_start( ap, fmt ); res = calli_stringva( fn, fmt, ap, NULL, NULL, NULL ); va_end( ap ); return( res ); } /* Call a function, building a filename arg. Nativize and absoluteize too. */ int calli_string_filename( calli_string_fn fn, const char *filename, void *a, void *b, void *c ) { char buf[FILENAME_MAX]; expand_variables( filename, buf ); nativeize_path( buf ); absoluteize_path( buf ); return( fn( buf, a, b, c ) ); } int calli_string_filenameva( calli_string_fn fn, const char *fmt, va_list ap, void *a, void *b, void *c ) { char buf[FILENAME_MAX]; (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap ); return( calli_string_filename( fn, buf, a, b, c ) ); } int calli_string_filenamef( calli_string_fn fn, const char *fmt, ... ) { va_list ap; int res; va_start( ap, fmt ); res = calli_string_filenameva( fn, fmt, ap, NULL, NULL, NULL ); va_end( ap ); return( res ); } /* Convert a filename to utf8 ... g_free the result. */ char * f2utf8( const char *filename ) { char *utf8; if( !(utf8 = g_filename_to_utf8( filename, -1, NULL, NULL, NULL )) ) utf8 = g_strdup( _( "" ) ); return( utf8 ); } void setenvf( const char *name, const char *fmt, ... ) { va_list ap; char buf[FILENAME_MAX]; va_start( ap, fmt ); (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap ); va_end( ap ); g_setenv( name, buf, TRUE ); } int check( const char *filename ) { /* Need to work on filenames containing %. */ return( im_existsf( "%s", filename ) ); } /* File exists? */ gboolean existsf( const char *name, ... ) { va_list ap; gboolean res; va_start( ap, name ); res = calli_string_filenameva( (calli_string_fn) check, name, ap, NULL, NULL, NULL ); va_end( ap ); return( res ); } int isdir_sub( const char *filename ) { struct stat st; /* Read size and file/dir. */ if( stat( filename, &st ) == -1 ) return( FALSE ); if( !S_ISDIR( st.st_mode ) ) return( FALSE ); return( TRUE ); } gboolean isdir( const char *filename, ... ) { va_list ap; gboolean res; va_start( ap, filename ); res = calli_string_filenameva( (calli_string_fn) isdir_sub, filename, ap, NULL, NULL, NULL ); va_end( ap ); return( res ); } static void * mtime_sub( const char *filename, time_t *time ) { struct stat st; if( stat( filename, &st ) == -1 ) return( NULL ); #ifdef HAVE_GETEUID if( st.st_uid != geteuid() ) return( NULL ); #endif /*HAVE_GETEUID*/ *time = st.st_mtime; return( NULL ); } time_t mtime( const char *filename, ... ) { va_list ap; time_t time; time = 0; va_start( ap, filename ); (void) callv_string_filenameva( (callv_string_fn) mtime_sub, filename, ap, &time, NULL, NULL ); va_end( ap ); return( time ); } gboolean mkdirf( const char *name, ... ) { va_list ap; gboolean res; va_start( ap, name ); res = calli_string_filenameva( (calli_string_fn) g_mkdir, name, ap, GINT_TO_POINTER( 0755 ), NULL, NULL ) == 0; va_end( ap ); return( res ); } /* system(), with printf() args and $xxx expansion. */ int systemf( const char *fmt, ... ) { va_list ap; int res; va_start( ap, fmt ); res = calli_stringva( (calli_string_fn) system, fmt, ap, NULL, NULL, NULL ); va_end( ap ); return( res ); } gboolean touchf( const char *fmt, ... ) { va_list ap; int fd; va_start( ap, fmt ); fd = calli_string_filenameva( (calli_string_fn) creat, fmt, ap, GINT_TO_POINTER( S_IRUSR | S_IWUSR ), NULL, NULL ); va_end( ap ); (void) close( fd ); return( fd != -1 ); } int unlinkf( const char *fmt, ... ) { va_list ap; int res; va_start( ap, fmt ); res = calli_string_filenameva( (calli_string_fn) unlink, fmt, ap, NULL, NULL, NULL ); va_end( ap ); return( res ); } /* Relative or absolute dir path? Have to expand env vars to see. */ gboolean is_absolute( const char *fname ) { char buf[FILENAME_MAX]; expand_variables( fname, buf ); nativeize_path( buf ); /* We can't use g_path_is_absolute(), we might be given a Windows path * including a drive specifier, and g_path_is_absolute() on unix does * not know about Windows paths. * * We should probably look out for whitespace. */ if( buf[0] == '/' || (buf[0] != '\0' && buf[1] == ':') ) return( TRUE ); else return( FALSE ); } /* OK filename? Ban ':' characters, they may confuse im_open(). Except on * winders :-( */ gboolean is_valid_filename( const char *name ) { const char *p; if( strlen( name ) > FILENAME_MAX ) { error_top( _( "Bad filename." ) ); error_sub( _( "Filename is too long." ) ); return( FALSE ); } if( (p = im_skip_dir( name )) && strspn( p, WHITESPACE ) == strlen( p ) ) { error_top( _( "Bad filename." ) ); error_sub( _( "Filename contains only blank characters." ) ); return( FALSE ); } return( TRUE ); } /* im_strdup(), with NULL supplied. */ char *im_strdupn( const char *txt ) { return( im_strdup( NULL, txt ) ); } /* Free an iOpenFile. */ void ifile_close( iOpenFile *of ) { IM_FREEF( fclose, of->fp ); IM_FREE( of->fname ); IM_FREE( of->fname_real ); IM_FREE( of ); } /* Make an iOpenFile*. */ static iOpenFile * ifile_build( const char *fname ) { iOpenFile *of; if( !(of = INEW( NULL, iOpenFile )) ) return( NULL ); of->fp = NULL; of->fname = NULL; of->fname_real = NULL; of->last_errno = 0; IM_SETSTR( of->fname, fname ); if( !of->fname ) { ifile_close( of ); return( NULL ); } return( of ); } /* Find and open for read. */ iOpenFile * ifile_open_read( const char *name, ... ) { va_list ap; char buf[FILENAME_MAX]; iOpenFile *of; va_start( ap, name ); (void) im_vsnprintf( buf, FILENAME_MAX, name, ap ); va_end( ap ); of = ifile_build( buf ); if( !of ) return( NULL ); if( !(of->fname_real = path_find_file( of->fname )) ) { error_top( _( "Unable to open." ) ); error_sub( _( "Unable to open file \"%s\" for reading.\n%s." ), of->fname, g_strerror( errno ) ); ifile_close( of ); return( NULL ); } if( !(of->fp = (FILE *) callv_string_filename( (callv_string_fn) fopen, of->fname_real, "r", NULL, NULL )) ) { error_top( _( "Unable to open." ) ); error_sub( _( "Unable to open file \"%s\" for reading.\n%s." ), of->fname_real, g_strerror( errno ) ); ifile_close( of ); return( NULL ); } of->read = TRUE; return( of ); } /* Open stdin for read. */ iOpenFile * ifile_open_read_stdin() { iOpenFile *of; if( !(of = ifile_build( "stdin" )) ) return( NULL ); IM_SETSTR( of->fname_real, of->fname ); if( !of->fname_real ) { ifile_close( of ); return( NULL ); } of->fp = stdin; of->read = TRUE; return( of ); } /* Find and open for write. */ iOpenFile * ifile_open_write( const char *name, ... ) { va_list ap; char buf[FILENAME_MAX]; iOpenFile *of; va_start( ap, name ); (void) im_vsnprintf( buf, FILENAME_MAX, name, ap ); va_end( ap ); of = ifile_build( buf ); if( !of ) return( NULL ); IM_SETSTR( of->fname_real, of->fname ); if( !of->fname_real ) { ifile_close( of ); return( NULL ); } if( !(of->fp = (FILE *) callv_string_filename( (callv_string_fn) fopen, of->fname_real, "w", NULL, NULL )) ) { error_top( _( "Unable to open." ) ); error_sub( _( "Unable to open file \"%s\" for writing.\n%s." ), of->fname_real, g_strerror( errno ) ); ifile_close( of ); return( NULL ); } of->read = FALSE; return( of ); } /* fprintf() to a file, checking result. */ gboolean ifile_write( iOpenFile *of, const char *fmt, ... ) { va_list ap; va_start( ap, fmt ); if( vfprintf( of->fp, fmt, ap ) == EOF ) { of->last_errno = errno; error_top( _( "Unable to write." ) ); error_sub( _( "Unable to write to file \"%s\".\n%s." ), of->fname_real, g_strerror( of->last_errno ) ); return( FALSE ); } va_end( ap ); return( TRUE ); } /* Save a string ... if non-NULL. Eg. * fred="boink!" */ gboolean ifile_write_var( iOpenFile *of, const char *name, const char *value ) { if( value ) return( ifile_write( of, " %s=\"%s\"", name, value ) ); return( TRUE ); } /* Load up a file as a string. */ char * ifile_read( iOpenFile *of ) { long len; size_t len2; char *str; /* Find length. */ fseek( of->fp, 0L, 2 ); len = ftell( of->fp ); rewind( of->fp ); if( len < 0 || len > 1024 * 1024 ) { error_top( _( "Unable to read." ) ); error_sub( _( "File \"%s\" too large." ), of->fname_real ); return( NULL ); } /* Allocate memory and fill. */ if( !(str = imalloc( NULL, len + 1 )) ) return( NULL ); /* We can't check len2 against len, since we may be reading a text * file on Windows, in which case this fread will change CRLF to LF * and len2 will be less than len. */ len2 = fread( str, sizeof( char ), (size_t) len, of->fp ); str[len2] = '\0'; return( str ); } /* Load a file into a buffer. Useful for OpenFiles we can't seek in, like * stdin. */ char * ifile_read_buffer( iOpenFile *of, char *buffer, size_t max ) { size_t len; /* -1 off max to leave space for the '\0'. */ len = fread( buffer, sizeof( char ), max - 1, of->fp ); if( !feof( of->fp ) ) { /* File too large for buffer. */ of->last_errno = errno; error_top( _( "Unable to read." ) ); error_sub( _( "Unable to read from file \"%s\".\n%s." ), of->fname_real, g_strerror( of->last_errno ) ); return( NULL ); } buffer[len] = '\0'; return( buffer ); } /* Return '\0' for EOF, -1 for error. */ int ifile_getc( iOpenFile *of ) { int ch; ch = fgetc( of->fp ); if( ch == EOF && feof( of->fp ) ) return( 0 ); else if( ch == EOF ) return( -1 ); else return( ch ); } off_t statf( const char *fmt, ... ) { va_list ap; struct stat st; int result; va_start( ap, fmt ); result = calli_string_filenameva( (calli_string_fn) stat, fmt, ap, &st, NULL, NULL ); va_end( ap ); if( result == -1 || S_ISDIR( st.st_mode ) ) return( 0 ); else return( st.st_size ); } static void * directory_size_sub( const char *filename, double *total ) { *total += statf( "%s", filename ); return( NULL ); } /* Find the amount of 'stuff' in a directory. Result in bytes. Don't look in * sub-dirs. */ double directory_size( const char *dirname ) { double total; total = 0; path_map_dir( dirname, "*", (path_map_fn) directory_size_sub, &total ); return( total ); } /* Escape "%" characters in a string. */ char * escape_percent( const char *in, char *out, int len ) { const char *p; char *q; for( p = in, q = out; *p && q - out < len - 3; p++, q++ ) if( *p == '%' ) { q[0] = '%'; q[1] = '%'; q++; } else *q = *p; *q = '\0'; return( out ); } char * escape_markup( const char *in, char *out, int len ) { const char *p; char *q; for( p = in, q = out; *p && q - out < len - 5; p++, q++ ) if( *p == '<' ) { strcpy( q, "<" ); q += 3; } else if( *p == '>' ) { strcpy( q, ">" ); q += 3; } else if( *p == '&' ) { strcpy( q, "&" ); q += 4; } else *q = *p; *q = '\0'; return( out ); } /* VIPS filenames can have embedded modes. Mode strings are punctuated with * ',' and ':' chars. So strings in modes must have these chars escaped. */ char * escape_mode( const char *in, char *out, int len ) { const char *p; char *q; for( p = in, q = out; *p && q - out < len - 5; p++, q++ ) { if( *p == ':' || *p == ',' ) *q++ = '\\'; *q = *p; } *q = '\0'; return( out ); } /* Return a string of n characters. Buffer is zapped each time! */ const char * rpt( char ch, int n ) { int i; static char buf[200]; n = IM_MIN( 190, n ); for( i = 0; i < n; i++ ) buf[i] = ch; buf[i] = '\0'; return( buf ); } /* Return a string of n spaces. Buffer is zapped each time! */ const char * spc( int n ) { return( rpt( ' ', n ) ); } /* Like strtok(), but better. Give a string and a list of break characters; * write a '\0' into the string over the first break character and return a * pointer to the next non-break character. If there are no break characters, * then return a pointer to the end of the string. If passed a pointer to an * empty string or NULL, then return NULL. */ char * break_token( char *str, const char *brk ) { char *p; /* Is the string empty? If yes, return NULL immediately. */ if( !str || !*str ) return( NULL ); /* Skip initial break characters. */ p = str + strspn( str, brk ); /* Search for the first break character after the token. */ p += strcspn( p, brk ); /* Is there string left? */ if( *p ) { /* Write in an end-of-string mark and return the start of the * next token. */ *p++ = '\0'; p += strspn( p, brk ); } return( p ); } /* Turn a number to a string. 0 is "A", 1 is "B", 25 is "Z", 26 is "AA", 27 is * "AB", etc. */ void number_to_string( int n, char *buf ) { do { int rem = n % 26; *buf++ = (char) (rem + (int) 'A'); n /= 26; } while( n > 0 ); *buf ='\0'; } /* Find the space remaining in a directory, in bytes. A double for >32bit * problem avoidance. <0 for error. */ #ifdef HAVE_SYS_STATVFS_H double find_space( const char *name ) { struct statvfs st; double sz; if( calli_string_filename( (calli_string_fn) statvfs, (gpointer) name, &st, NULL, NULL ) ) /* Set to error value. */ sz = -1; else sz = IM_MAX( 0, (double) st.f_frsize * st.f_bavail ); return( sz ); } #elif (HAVE_SYS_VFS_H || HAVE_SYS_MOUNT_H) double find_space( const char *name ) { struct statfs st; double sz; if( calli_string_filename( (calli_string_fn) statfs, (gpointer) name, &st, NULL, NULL ) ) sz = -1; else sz = IM_MAX( 0, (double) st.f_bsize * st.f_bavail ); return( sz ); } #elif defined OS_WIN32 double find_space( const char *name ) { ULARGE_INTEGER avail; ULARGE_INTEGER total; ULARGE_INTEGER free; double sz; char name2[FILENAME_MAX]; expand_variables( name, name2 ); /* Truncate to just the drive letter. */ if( name2[1] == ':' ) name2[3] = 0; if( !GetDiskFreeSpaceEx( name2, &avail, &total, &free ) ) sz = -1; else sz = IM_MAX( 0, (double) free.QuadPart ); return( sz ); } #else double find_space( const char *name ) { return( -1 ); } #endif /*HAVE_SYS_STATVFS_H*/ /* Make a name for a temp file. Add the specified extension. */ gboolean temp_name( char *name, const char *type ) { /* Some mkstemp() require files to actually exist before they don't * reuse the filename :-( add an extra field. */ static int n = 0; const char *dir; int fd; char buf[FILENAME_MAX]; dir = PATH_TMP; if( !existsf( "%s", dir ) ) dir = G_DIR_SEPARATOR_S; im_snprintf( name, FILENAME_MAX, "%s" G_DIR_SEPARATOR_S "untitled-" PACKAGE "-%d-XXXXXXX", dir, n++ ); expand_variables( name, buf ); fd = g_mkstemp( buf ); if( fd == -1 ) { error_top( _( "Unable to create temporary file." ) ); error_sub( _( "Unable to make file \"%s\"\n%s" ), buf, g_strerror( errno ) ); return( FALSE ); } close( fd ); unlinkf( "%s", buf ); im_snprintf( name, FILENAME_MAX, "%s.%s", buf, type ); return( TRUE ); } /* Max/min of an area. */ int findmaxmin( IMAGE *in, int left, int top, int width, int height, double *min, double *max ) { DOUBLEMASK *msk; IMAGE *t1; if( !(t1 = im_open( "temp", "p" )) ) return( -1 ); if( im_extract_area( in, t1, left, top, width, height ) || !(msk = im_stats( t1 )) ) return( -1 ); im_close( t1 ); *min = msk->coeff[0]; *max = msk->coeff[1]; im_free_dmask( msk ); #ifdef DEBUG printf( "findmaxmin: left = %d, top = %d, width = %d, height = %d\n", left, top, width, height ); printf( "findmaxmin: max = %g, min = %g\n", *max, *min ); #endif /*DEBUG*/ return( 0 ); } gboolean char_to_bool( char *str, void *out ) { gboolean *t = (gboolean *) out; if( strcasecmp( "TRUE", str ) == 0 ) *t = TRUE; else *t = FALSE; return( TRUE ); } char * bool_to_char( gboolean b ) { if( b ) return( "true" ); else return( "false" ); } /* Increment a name ... strip any trailing numbers, add one, put numbers back. * Start at 1 if no number there. buf should be at least namelen chars. Keep * leading zeros, if any. */ void increment_name( char *buf ) { char *p; int n; char fmt[256]; /* If there's no number, p will point at the '\0'. */ p = (char *) my_strrspn( buf, NUMERIC ); if( *p ) { n = atoi( p ); im_snprintf( fmt, 256, "%%0%dd", (int) strlen( p ) ); } else { strcpy( fmt, "%d" ); n = 0; } im_snprintf( p, MAX_STRSIZE - (p - buf), fmt, n + 1 ); } /* Increment filename. Eg. "/home/jim/fred_00_tn.tif" becomes * "/home/jim/fred_01_tn.tif" */ void increment_filename( char *filename ) { char buf[FILENAME_MAX]; char suf[FILENAME_MAX]; char tail[FILENAME_MAX]; char *file, *p; im_strncpy( buf, filename, FILENAME_MAX ); /* Save and replace the suffix around an increment_name. */ file = (char *) im_skip_dir( buf ); if( !(p = strrchr( file, '.' )) ) p = file + strlen( file ); im_strncpy( suf, p, FILENAME_MAX ); *p = '\0'; /* Also save any chars to the right of the number component (if any) of * the filename. */ p = (char *) my_strrcspn( file, NUMERIC ); /* No numbers there? Take nothing as the tail and put the number at * the end. */ if( p == file ) p = file + strlen( file ); im_strncpy( tail, p, FILENAME_MAX ); *p = '\0'; increment_name( buf ); strcpy( filename, buf ); strcat( filename, tail ); strcat( filename, suf ); } /* Extract the first line of a string in to buf, extract no more than len * chars. */ int extract_first_line( char *buf, char *str, int len ) { char *p; int n; /* Find next '\n' or '\0'. */ if( (p = strchr( str, '\n' )) ) n = p - str; else n = strlen( str ); n = IM_MIN( len - 1, n ); /* Copy those characters and make sure we have a '\0'. */ strncpy( buf, str, n ); buf[n] = '\0'; return( n ); } /* Make a valid ip name from a filename. */ void name_from_filename( const char *in, char *out ) { const char *p; /* Skip leading path prefix, and any non-alpha. * Don't use isalnum(), since we don't want leading digits. */ p = im_skip_dir( in ); while( *p && !(isalpha( *p ) || *p == '_') ) p += 1; if( !*p ) strcpy( out, "untitled" ); else { char *q; /* Filter non-identifier chars. Stop at the first '.' * character, so we don't get the suffix in there too. */ for( q = out; *p && *p != '.'; p++ ) if( isalnum( *p ) || *p == '_' || *p == '\'' ) *q++ = *p; *q = '\0'; } } /* Do any leak checking we can. */ void util_check_all_destroyed( void ) { if( rect_n_rects ) printf( "rect_n_rects == %d\n", rect_n_rects ); } /* Like im_malloc(), but set our error stuff. */ void * imalloc( IMAGE *im, size_t len ) { void *mem; if( !(mem = im_malloc( im, len )) ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); vips_buf_append_size( &buf, len ); error_top( _( "Out of memory." ) ); error_sub( _( "Request for %s of RAM triggered memory " "allocation failure." ), vips_buf_all( &buf ) ); error_vips(); return( NULL ); } return( mem ); } /* Add a filename to a recent list. If there are more than MAX_RECENT items, * drop the last one off. If this is a dupe, move it to the head of the list. */ GSList * recent_add( GSList *recent, const char *filename ) { char absolute[FILENAME_MAX]; int n; GSList *p; im_strncpy( absolute, filename, FILENAME_MAX ); absoluteize_path( absolute ); for( p = recent; p; p = p->next ) { const char *stored = p->data; if( strcmp( absolute, stored ) == 0 ) { recent = g_slist_remove( recent, stored ); recent = g_slist_prepend( recent, (void *) stored ); return( recent ); } } recent = g_slist_prepend( recent, g_strdup( absolute ) ); if( (n = g_slist_length( recent )) > MAX_RECENT ) { const char *item; item = g_slist_nth_data( recent, n - 1 ); recent = g_slist_remove( recent, item ); g_free( (char *) item ); } return( recent ); } GSList * recent_load( const char *filename ) { iOpenFile *of; GSList *recent; recent = NULL; if( (of = ifile_open_read( "%s" G_DIR_SEPARATOR_S "%s", get_savedir(), filename )) ) { char buf[256]; while( fgets( buf, 256, of->fp ) ) { int n; if( (n = strlen( buf )) > 0 ) { if( buf[n - 1] == '\n' ) buf[n - 1] = '\0'; recent = recent_add( recent, buf ); } } ifile_close( of ); } return( recent ); } void recent_free( GSList *recent ) { GSList *p; for( p = recent; p; p = p->next ) { const char *item = (const char *) p->data; g_free( (char *) item ); } g_slist_free( recent ); } static void * recent_save_sub( const char *filename, GSList **old_recent ) { *old_recent = recent_add( *old_recent, filename ); return( NULL ); } static void * recent_save_sub2( const char *filename, iOpenFile *of ) { fprintf( of->fp, "%s\n", filename ); return( NULL ); } void recent_save( GSList *recent, const char *filename ) { iOpenFile *of; GSList *old_recent; /* If there are several nips running, we could be saving over a file * that's been modified since we loaded it. Try to make this less * awful by merging our recent list over the one in the file. */ old_recent = recent_load( filename ); slist_map_rev( recent, (SListMapFn) recent_save_sub, &old_recent ); if( (of = ifile_open_write( "%s" G_DIR_SEPARATOR_S "%s", get_savedir(), filename )) ) { slist_map_rev( old_recent, (SListMapFn) recent_save_sub2, of ); ifile_close( of ); } recent_free( old_recent ); } /* Return the name of the save dir we use ... eg. "$HOME/.nip2-7.10.8", * or maybe "C:\Documents and Settings\john\Application Data" */ const char * get_savedir( void ) { #ifdef OS_WIN32 /* If APPDATA is not defined, default to HOME, we know that will * exist (since we make it if necessary in main()). */ if( g_getenv( "APPDATA" ) && existsf( "%s", g_getenv( "APPDATA" ) ) ) return( "$APPDATA" G_DIR_SEPARATOR_S IP_NAME ); else return( "$HOME" G_DIR_SEPARATOR_S "." IP_NAME ); #elif OS_DARWIN /* Darwin ... in ~/Library */ return( "$HOME" G_DIR_SEPARATOR_S "Library" G_DIR_SEPARATOR_S IP_NAME ); #else /* *nix-style system .. .dot file in home area. */ return( "$HOME" G_DIR_SEPARATOR_S "." IP_NAME ); #endif /*OS_WIN32*/ } /* Turn an slist into a null-terminated array. */ void ** slist_to_array( GSList *list ) { void **array; int i; array = g_new( void *, g_slist_length( list ) + 1 ); for( i = 0; list ; list = list->next, i++ ) array[i] = list->data; array[i] = NULL; return( array ); } /* Length of a NULL-terminated array. */ int array_len( void **array ) { int i; for( i = 0; array[i]; i++ ) ; return( i ); } nip2-8.7.1/src/rowview.c0000644000175000017500000004645313351443023011767 00000000000000/* A rowview in a workspace ... not a widget, part of column */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ModelClass *parent_class = NULL; enum { ROWVIEW_TARGET_STRING, }; static GtkTargetEntry rowview_target_table[] = { { "STRING", 0, ROWVIEW_TARGET_STRING }, { "text/plain", 0, ROWVIEW_TARGET_STRING } }; /* Just one popup for all tally buttons. */ static GtkWidget *rowview_popup_menu = NULL; static void rowview_destroy( GtkObject *object ) { Rowview *rview; g_return_if_fail( object != NULL ); g_return_if_fail( IS_ROWVIEW( object ) ); rview = ROWVIEW( object ); #ifdef DEBUG printf( "rowview_destroy: " ); row_name_print( ROW( VOBJECT( rview )->iobject ) ); printf( "\n" ); #endif /*DEBUG*/ IM_FREE( rview->last_tooltip ); /* Kill children ... must do this ourselves, since we are not a * self-contained widget. */ DESTROY_GTK( rview->but ); DESTROY_GTK( rview->spin ); DESTROY_GTK( rview->led ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void rowview_attach( Rowview *rview, GtkWidget *child, int x, GtkAttachOptions xoptions, GtkAttachOptions yoptions ) { Subcolumnview *sview = rview->sview; gtk_widget_ref( child ); if( child->parent ) gtk_container_remove( GTK_CONTAINER( sview->table ), child ); gtk_table_attach( GTK_TABLE( sview->table ), child, x, x + 1, rview->rnum, rview->rnum + 1, xoptions, yoptions, 0, 0 ); gtk_widget_unref( child ); } static void rowview_update_widgets( Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); int pos = ICONTAINER( row )->pos; gboolean editable = row->ws->mode != WORKSPACE_MODE_NOEDIT; #ifdef DEBUG printf( "rowview_refresh: " ); row_name_print( row ); printf( "\n" ); printf( "\teditable == %d\n", editable ); #endif /*DEBUG*/ /* Attach widgets to parent in new place. */ if( rview->rnum != pos ) { #ifdef DEBUG printf( "rowview_refresh: move from row %d to row %d\n", rview->rnum, pos ); #endif /*DEBUG*/ rview->rnum = pos; rowview_attach( rview, rview->spin, 0, GTK_FILL, GTK_FILL ); rowview_attach( rview, rview->but, 1, GTK_FILL, GTK_EXPAND | GTK_FILL ); rowview_attach( rview, rview->led, 2, GTK_FILL, GTK_EXPAND | GTK_FILL ); if( rview->rhsview ) rowview_attach( rview, GTK_WIDGET( rview->rhsview ), 3, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL ); } /* Set colours. */ if( CALC_DISPLAY_LED ) { char *stock_id; stock_id = STOCK_LED_OFF; if( row->selected ) stock_id = STOCK_LED_GREEN; else if( row->show == ROW_SHOW_PARENT ) stock_id = STOCK_LED_CYAN; else if( row->show == ROW_SHOW_CHILD ) stock_id = STOCK_LED_BLUE; else if( row->err ) stock_id = STOCK_LED_RED; else if( row->dirty ) stock_id = STOCK_LED_YELLOW; gtk_image_set_from_stock( GTK_IMAGE( rview->led ), stock_id, GTK_ICON_SIZE_MENU ); } else { gchar *name = ""; if( row->selected ) name = "selected_widget"; else if( row->show == ROW_SHOW_PARENT ) name = "parent_widget"; else if( row->show == ROW_SHOW_CHILD ) name = "child_widget"; else if( row->err ) name = "error_widget"; else if( row->dirty ) name = "dirty_widget"; gtk_widget_set_name( rview->but, name ); } widget_visible( rview->led, rview->visible && CALC_DISPLAY_LED && editable ); /* Update button. */ set_glabel( rview->label, "%s", row_name( row ) ); widget_visible( rview->but, rview->visible && editable ); /* Spin visible only if this is a class. */ widget_visible( rview->spin, rview->visible && row->is_class && editable ); if( rview->rhsview ) widget_visible( GTK_WIDGET( rview->rhsview ), rview->visible ); } static void rowview_reset( View *view ) { Rowview *rview = ROWVIEW( view ); rowview_update_widgets( rview ); VIEW_CLASS( parent_class )->reset( view ); } static void rowview_refresh( vObject *vobject ) { Rowview *rview = ROWVIEW( vobject ); rowview_update_widgets( rview ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } /* Single click on button callback. */ static void rowview_single_cb( GtkWidget *wid, GdkEvent *event, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); row_select_modifier( row, event->button.state ); } /* Edit our object. */ static gboolean rowview_edit( Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); Model *graphic = row->child_rhs->graphic; if( graphic ) model_edit( GTK_WIDGET( rview->sview ), graphic ); return( TRUE ); } /* Double click on button callback. */ static void rowview_double_cb( GtkWidget *button, GdkEvent *event, Rowview *rview ) { if( !rowview_edit( rview ) ) iwindow_alert( button, GTK_MESSAGE_ERROR ); } /* Edit in menu. */ static void rowview_edit_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { if( !rowview_edit( rview ) ) iwindow_alert( button, GTK_MESSAGE_ERROR ); } /* Show info. */ static gboolean rowview_header( Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); Model *graphic = row->child_rhs->graphic; if( graphic ) model_header( GTK_WIDGET( rview->sview ), graphic ); return( TRUE ); } /* Info in menu. */ static void rowview_header_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { if( !rowview_header( rview ) ) iwindow_alert( button, GTK_MESSAGE_ERROR ); } /* Clone the current item. */ static void rowview_clone_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); Workspace *ws = row->top_col->ws; /* Only allow clone of top level rows. */ if( row->top_row != row ) { error_top( _( "Can't duplicate." ) ); error_sub( "%s", _( "You can only duplicate top level rows." ) ); iwindow_alert( button, GTK_MESSAGE_INFO ); return; } workspace_deselect_all( ws ); row_select( row ); if( !workspace_selected_duplicate( ws ) ) iwindow_alert( button, GTK_MESSAGE_ERROR ); workspace_deselect_all( ws ); symbol_recalculate_all(); } /* Ungroup the current item. */ static void rowview_ungroup_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); workspace_deselect_all( row->ws ); row_select( row ); if( !workspace_selected_ungroup( row->ws ) ) iwindow_alert( button, GTK_MESSAGE_ERROR ); symbol_recalculate_all(); } /* Save the current item. */ static void rowview_save_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { iWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( rview ) ) ); Row *row = ROW( VOBJECT( rview )->iobject ); Model *graphic = row->child_rhs->graphic; if( graphic ) classmodel_graphic_save( CLASSMODEL( graphic ), GTK_WIDGET( iwnd ) ); } /* Replace the current item. */ static void rowview_replace_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { iWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( rview ) ) ); Row *row = ROW( VOBJECT( rview )->iobject ); Model *graphic = row->child_rhs->graphic; if( graphic ) classmodel_graphic_replace( CLASSMODEL( graphic ), GTK_WIDGET( iwnd ) ); } /* Recalculate the current item. */ static void rowview_recalc_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); Workspace *ws = row->top_col->ws; /* Mark dirty from this sym on, and force a recalc even if recalc is * off. */ workspace_deselect_all( ws ); row_select( row ); if( !workspace_selected_recalc( ws ) ) iwindow_alert( button, GTK_MESSAGE_ERROR ); workspace_deselect_all( ws ); /* Now ... pick up any errors. */ if( row->sym && !symbol_recalculate_check( row->sym ) ) iwindow_alert( button, GTK_MESSAGE_ERROR ); } /* Reset the current item. */ static void rowview_clear_edited_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); (void) icontainer_map_all( ICONTAINER( row ), (icontainer_map_fn) model_clear_edited, NULL ); symbol_recalculate_all(); } /* Remove the current item. */ static void rowview_remove_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); Workspace *ws = row->top_col->ws; workspace_deselect_all( ws ); row_select( row ); workspace_selected_remove_yesno( ws, button ); } /* Callback for up/down spin button. */ static void rowview_spin_up_cb( GtkWidget *widget, gpointer client ) { Rowview *rview = ROWVIEW( client ); Row *row = ROW( VOBJECT( rview )->iobject ); Rhs *rhs = row->child_rhs; rhs_vislevel_down( rhs ); workspace_set_modified( row->ws, TRUE ); } static void rowview_spin_down_cb( GtkWidget *widget, gpointer client ) { Rowview *rview = ROWVIEW( client ); Row *row = ROW( VOBJECT( rview )->iobject ); Rhs *rhs = row->child_rhs; rhs_vislevel_up( rhs ); workspace_set_modified( row->ws, TRUE ); } /* Scroll to make tally entry visible. */ static void rowview_scrollto( View *view, ModelScrollPosition position ) { Rowview *rview = ROWVIEW( view ); Columnview *cview = view_get_columnview( VIEW( rview ) ); Workspaceview *wview = cview->wview; int x, y, w, h; /* Extract position of tally row in RC widget. */ rowview_get_position( rview, &x, &y, &w, &h ); workspaceview_scroll( wview, x, y, w, h ); } static void rowview_drag( Rowview *rview_from, Rowview *rview_to ) { Row *row_from = ROW( VOBJECT( rview_from )->iobject ); Row *row_to = ROW( VOBJECT( rview_to )->iobject ); if( row_from->top_col != row_to->top_col ) { error_top( _( "Not implemented." ) ); error_sub( _( "Drag between columns not yet implemented." ) ); iwindow_alert( GTK_WIDGET( rview_from ), GTK_MESSAGE_ERROR ); return; } icontainer_child_move( ICONTAINER( row_from ), ICONTAINER( row_to )->pos ); /* Refresh all the rows, to make sure we move all rows to their new * slots. */ icontainer_map( ICONTAINER( row_from->scol ), (icontainer_map_fn) iobject_changed, NULL, NULL ); workspace_deselect_all( row_from->ws ); } static void rowview_drag_data_get( GtkWidget *but, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, Rowview *rview ) { if( info == ROWVIEW_TARGET_STRING ) { /* Send a pointer to us. */ gtk_selection_data_set( selection_data, selection_data->target, 8, (const guchar *) &rview, sizeof( Rowview * ) ); } } static void rowview_drag_data_received( GtkWidget *but, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, Rowview *rview_to ) { if( data->length == sizeof( Rowview * ) && data->format == 8 && info == ROWVIEW_TARGET_STRING ) { Rowview *rview_from = *((Rowview **) data->data); if( IS_ROWVIEW( rview_from ) ) { rowview_drag( rview_from, rview_to ); gtk_drag_finish( context, TRUE, FALSE, time ); return; } } gtk_drag_finish( context, FALSE, FALSE, time ); } /* Attach the rowview menu to a widget ... also used by iimageview */ guint rowview_menu_attach( Rowview *rview, GtkWidget *widget ) { return( popup_attach( widget, rowview_popup_menu, rview ) ); } static void rowview_link( View *view, Model *model, View *parent ) { Row *row = ROW( model ); Rowview *rview = ROWVIEW( view ); Subcolumnview *sview = SUBCOLUMNVIEW( parent ); VIEW_CLASS( parent_class )->link( view, model, parent ); rview->sview = sview; /* Only drag n drop top level rows. */ if( row->top_row == row ) { gtk_drag_source_set( rview->but, GDK_BUTTON1_MASK, rowview_target_table, IM_NUMBER( rowview_target_table ), GDK_ACTION_COPY ); gtk_signal_connect( GTK_OBJECT( rview->but ), "drag_data_get", GTK_SIGNAL_FUNC( rowview_drag_data_get ), rview ); gtk_drag_dest_set( rview->but, GTK_DEST_DEFAULT_ALL, rowview_target_table, IM_NUMBER( rowview_target_table ), GDK_ACTION_COPY ); gtk_signal_connect( GTK_OBJECT( rview->but ), "drag_data_received", GTK_SIGNAL_FUNC( rowview_drag_data_received ), rview ); } rowview_menu_attach( rview, rview->but ); } static void rowview_child_add( View *parent, View *child ) { Rowview *rowview = ROWVIEW( parent ); g_assert( IS_RHSVIEW( child ) ); g_assert( !rowview->rhsview ); rowview->rhsview = RHSVIEW( child ); VIEW_CLASS( parent_class )->child_add( parent, child ); } static void rowview_child_remove( View *parent, View *child ) { Rowview *rowview = ROWVIEW( parent ); g_assert( IS_RHSVIEW( child ) ); g_assert( rowview->rhsview ); rowview->rhsview = NULL; VIEW_CLASS( parent_class )->child_remove( parent, child ); } static void rowview_class_init( RowviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; GtkWidget *pane; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ object_class->destroy = rowview_destroy; vobject_class->refresh = rowview_refresh; view_class->link = rowview_link; view_class->child_add = rowview_child_add; view_class->child_remove = rowview_child_remove; view_class->reset = rowview_reset; view_class->scrollto = rowview_scrollto; /* Other init. */ pane = rowview_popup_menu = popup_build( _( "Row menu" ) ); popup_add_but( pane, _( "_Edit" ), POPUP_FUNC( rowview_edit_cb ) ); popup_add_but( pane, _( "_Header" ), POPUP_FUNC( rowview_header_cb ) ); popup_add_but( pane, STOCK_DUPLICATE, POPUP_FUNC( rowview_clone_cb ) ); popup_add_but( pane, _( "U_ngroup" ), POPUP_FUNC( rowview_ungroup_cb ) ); popup_add_but( pane, GTK_STOCK_SAVE_AS, POPUP_FUNC( rowview_save_cb ) ); popup_add_but( pane, _( "Replace From _File" ), POPUP_FUNC( rowview_replace_cb ) ); popup_add_but( pane, _( "_Recalculate" ), POPUP_FUNC( rowview_recalc_cb ) ); popup_add_but( pane, _( "Re_set" ), POPUP_FUNC( rowview_clear_edited_cb ) ); menu_add_sep( pane ); popup_add_but( pane, GTK_STOCK_DELETE, POPUP_FUNC( rowview_remove_cb ) ); } static void rowview_enter_cb( GtkWidget *widget, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); row_set_status( row ); row_show_dependents( row ); } static void rowview_leave_cb( GtkWidget *widget, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); row_hide_dependents( row ); } static gboolean rowview_focus_cb( GtkWidget *widget, GtkDirectionType dir, Rowview *rview ) { view_scrollto( VIEW( rview ), MODEL_SCROLL_TOP ); return( FALSE ); } static void rowview_tooltip_generate( GtkWidget *widget, VipsBuf *buf, Rowview *rview ) { Row *row = ROW( VOBJECT( rview )->iobject ); iobject_info( IOBJECT( row ), buf ); vips_buf_removec( buf, '\n' ); } static void rowview_init( Rowview *rview ) { rview->visible = TRUE; rview->rnum = -1; rview->last_tooltip = NULL; /* Make leds. */ rview->led = gtk_image_new_from_stock( STOCK_LED_OFF, GTK_ICON_SIZE_MENU ); gtk_misc_set_alignment( GTK_MISC( rview->led ), 0.5, 0.0 ); gtk_misc_set_padding( GTK_MISC( rview->led ), 2, 2 ); /* Make fold/unfold button. */ rview->spin = spin_new(); gtk_signal_connect( GTK_OBJECT( rview->spin ), "up_click", GTK_SIGNAL_FUNC( rowview_spin_up_cb ), rview ); gtk_signal_connect( GTK_OBJECT( rview->spin ), "down_click", GTK_SIGNAL_FUNC( rowview_spin_down_cb ), rview ); gtk_widget_show( rview->spin ); set_tooltip( rview->spin, _( "Click to open or close class" ) ); /* Make name button. */ rview->but = gtk_button_new(); gtk_widget_show( rview->but ); doubleclick_add( rview->but, FALSE, DOUBLECLICK_FUNC( rowview_single_cb ), rview, DOUBLECLICK_FUNC( rowview_double_cb ), rview ); rview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( rview->label ), 1, 0 ); gtk_misc_set_padding( GTK_MISC( rview->label ), 2, 0 ); gtk_container_add( GTK_CONTAINER( rview->but ), rview->label ); gtk_widget_show( rview->label ); gtk_signal_connect( GTK_OBJECT( rview->but ), "enter", GTK_SIGNAL_FUNC( rowview_enter_cb ), rview ); gtk_signal_connect( GTK_OBJECT( rview->but ), "leave", GTK_SIGNAL_FUNC( rowview_leave_cb ), rview ); gtk_signal_connect( GTK_OBJECT( rview->but ), "focus", GTK_SIGNAL_FUNC( rowview_focus_cb ), rview ); set_tooltip_generate( rview->but, (TooltipGenerateFn) rowview_tooltip_generate, rview, NULL ); } GtkType rowview_get_type( void ) { static GtkType rowview_type = 0; if( !rowview_type ) { static const GtkTypeInfo rview_info = { "Rowview", sizeof( Rowview ), sizeof( RowviewClass ), (GtkClassInitFunc) rowview_class_init, (GtkObjectInitFunc) rowview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; rowview_type = gtk_type_unique( TYPE_VIEW, &rview_info ); } return( rowview_type ); } View * rowview_new( void ) { Rowview *rview = gtk_type_new( TYPE_ROWVIEW ); return( VIEW( rview ) ); } /* Find the position and size of a row in the enclosing GtkFixed. */ void rowview_get_position( Rowview *rview, int *x, int *y, int *w, int *h ) { Columnview *cview = view_get_columnview( VIEW( rview ) ); if( GTK_WIDGET_VISIBLE( rview->spin ) ) { *x = rview->spin->allocation.x; *y = rview->spin->allocation.y; *w = rview->spin->allocation.width; *h = rview->spin->allocation.height; } else { *x = rview->but->allocation.x; *y = rview->but->allocation.y; *w = 0; *h = 0; } *w += rview->but->allocation.width; *h = IM_MAX( rview->but->allocation.height, *h ); if( GTK_WIDGET_VISIBLE( rview->led ) ) { *w += rview->led->allocation.width; *h = IM_MAX( rview->led->allocation.height, *h ); } *w += GTK_WIDGET( rview->rhsview )->allocation.width; *h = IM_MAX( GTK_WIDGET( rview->rhsview )->allocation.height, *h ); /* Title bar, plus separator. */ *y += cview->title->allocation.height + 2; *x += cview->main->allocation.x; *y += cview->main->allocation.y; #ifdef DEBUG printf( "rowview_get_position: " ); row_name_print( ROW( VOBJECT( rview )->iobject ) ); printf( ": x = %d, y = %d, w = %d, h = %d\n", *x, *y, *w, *h ); #endif /*DEBUG*/ } /* Hide/show a row. */ void rowview_set_visible( Rowview *rview, gboolean visible ) { if( rview->visible != visible ) { rview->visible = visible; rowview_update_widgets( rview ); } } gboolean rowview_get_visible( Rowview *rview ) { return( rview->visible ); } nip2-8.7.1/src/statusview.h0000644000175000017500000000423413351443023012477 00000000000000/* Decls for statusview.c ... display image info and mouse posn */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_STATUSVIEW (statusview_get_type()) #define STATUSVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_STATUSVIEW, Statusview )) #define STATUSVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_STATUSVIEW, StatusviewClass )) #define IS_STATUSVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_STATUSVIEW )) #define IS_STATUSVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_STATUSVIEW )) /* A band element display in the status bar. */ typedef struct _StatusviewBand { Statusview *sv; /* Bar we're in */ int bandno; /* Band we extract */ GtkWidget *val; /* Label we write to */ } StatusviewBand; struct _Statusview { GtkFrame parent_class; Imagemodel *imagemodel; guint changed_sid; GtkWidget *top; /* Top label */ GtkWidget *pos; /* Position */ GtkWidget *hb; /* Band element hbox */ GtkWidget *mag; /* Magnification display */ GSList *bands; /* List of StatusviewBand */ int nb; /* Last number of bands we saw */ int fmt; /* The last bandfmt we set ... for spacing */ }; typedef struct _StatusviewClass { GtkFrameClass parent_class; /* My methods. */ } StatusviewClass; GtkType statusview_get_type( void ); Statusview *statusview_new( Imagemodel *imagemodel ); void statusview_mouse( Statusview *sv, int x, int y ); nip2-8.7.1/src/istring.h0000644000175000017500000000270613351443023011742 00000000000000/* an editable string in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_STRING (string_get_type()) #define STRING( obj ) (GTK_CHECK_CAST( (obj), TYPE_STRING, String )) #define STRING_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_STRING, StringClass )) #define IS_STRING( obj ) (GTK_CHECK_TYPE( (obj), TYPE_STRING )) #define IS_STRING_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_STRING )) struct _String { Classmodel parent_class; /* Class fields. */ char *value; }; typedef struct _StringClass { ClassmodelClass parent_class; /* My methods. */ } StringClass; GType string_get_type( void ); nip2-8.7.1/src/columnview.h0000644000175000017500000000675413351443023012462 00000000000000/* view of a column */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_COLUMNVIEW (columnview_get_type()) #define COLUMNVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_COLUMNVIEW, Columnview )) #define COLUMNVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_COLUMNVIEW, ColumnviewClass )) #define IS_COLUMNVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_COLUMNVIEW )) #define IS_COLUMNVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_COLUMNVIEW )) /* State ... for mouse titlebar interactions. */ typedef enum { COL_WAIT, /* Rest state */ COL_SELECT, /* Select start, but no drag yet */ COL_DRAG, /* Drag state */ COL_EDIT /* Editing caption */ } ColumnviewState; struct _Columnview { View view; /* Our enclosing workspaceview. */ Workspaceview *wview; /* Display parts. */ GtkWidget *main; /* Enclosing window for whole cview */ GtkWidget *lab; /* Columnview name label */ GtkWidget *vbox; /* Outermost vbox for cview */ GtkWidget *frame; /* Enclosing frame for tally stuff */ GtkWidget *title; /* Eventbox wrapper for title bar */ GtkWidget *titlehb; /* Title bar hbox */ GtkWidget *updown; /* Fold up/down arrow */ GtkWidget *updownb; /* Fold up/down button */ GtkWidget *head; /* Label on columnview */ GtkWidget *headfr; /* Frame wrapper around label */ GtkWidget *text; /* Text entry at bottom */ GtkWidget *textfr; /* Enclosing stuff for text entry */ GtkWidget *capedit; /* Shadow text for editing caption */ /* A shadow for this cview, used during drag to show where this column * will end up. * * And if we are a shadow, the master cview we are the shadow for. */ Columnview *shadow; Columnview *master; /* Appearance state info. */ int lx, ly; /* last pos we set */ ColumnviewState state; /* Waiting or dragging */ int sx, sy; /* Drag start point */ int rx, ry; /* Drag offset */ int tx, ty; /* Tally window pos in root cods */ gboolean selected; /* Last drawn in selected state? */ /* We watch resize events and trigger a workspace relayout with these. */ int old_width; int old_height; }; typedef struct _ColumnviewClass { ViewClass parent_class; /* My methods. */ } ColumnviewClass; void columnview_get_position( Columnview *cview, int *x, int *y, int *w, int *h ); GtkType columnview_get_type( void ); View *columnview_new( void ); nip2-8.7.1/src/log.h0000644000175000017500000000372013351443023011041 00000000000000/* Abstract base class for a log window: errors, link report, log, etc. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_LOG (log_get_type()) #define LOG( obj ) (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_LOG, Log )) #define LOG_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_LOG, LogClass)) #define IS_LOG( obj ) (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_LOG )) #define IS_LOG_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_LOG )) #define LOG_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_LOG, LogClass )) struct _Log { iWindow parent_class; GtkWidget *view; /* The textview we use to show the log */ }; typedef struct _LogClass { iWindowClass parent_class; /* How we want the menu bar built. */ GtkActionEntry *actions; int n_actions; GtkToggleActionEntry *toggle_actions; int n_toggle_actions; const char *action_name; const char *ui_description; const char *menu_bar_name; } LogClass; GtkType log_get_type( void ); void log_clear_action_cb( GtkAction *action, Log *log ); void log_text( Log *log, const char *buf ); void log_textf( Log *log, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); nip2-8.7.1/src/matrixview.h0000644000175000017500000000405013351443023012454 00000000000000/* a matrixview in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_MATRIXVIEW (matrixview_get_type()) #define MATRIXVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_MATRIXVIEW, Matrixview )) #define MATRIXVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_MATRIXVIEW, MatrixviewClass )) #define IS_MATRIXVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_MATRIXVIEW )) #define IS_MATRIXVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_MATRIXVIEW )) typedef struct _Matrixview { Graphicview parent_object; GtkWidget *box; /* Top level hbox we lay out in */ /* If we're displaying a matrix with a gtktreeview. */ GtkListStore *store; GtkWidget *sheet; GtkWidget *swin; /* Displaying a table of widgets: sliders or toggles. */ GtkWidget *table; /* Matrix table */ GSList *items; /* Widgets for elems */ MatrixDisplayType display; /* What's in items at the mo */ int width; /* Size of mat panel we have */ int height; GtkWidget *cbox; /* Convolution only: scale & offset */ GtkWidget *scale; GtkWidget *offset; } Matrixview; typedef struct _MatrixviewClass { GraphicviewClass parent_class; /* My methods. */ } MatrixviewClass; GtkType matrixview_get_type( void ); View *matrixview_new( void ); nip2-8.7.1/src/workspacegroupview.h0000644000175000017500000000336613351443023014234 00000000000000/* A view for a Workspacegroup (a set of workspaces) ... display as a notebook. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_WORKSPACEGROUPVIEW (workspacegroupview_get_type()) #define WORKSPACEGROUPVIEW( obj ) (GTK_CHECK_CAST( (obj), \ TYPE_WORKSPACEGROUPVIEW, Workspacegroupview )) #define WORKSPACEGROUPVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_WORKSPACEGROUPVIEW, WorkspacegroupviewClass )) #define IS_WORKSPACEGROUPVIEW( obj ) (GTK_CHECK_TYPE( (obj), \ TYPE_WORKSPACEGROUPVIEW )) #define IS_WORKSPACEGROUPVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEGROUPVIEW )) struct _Workspacegroupview { View parent_object; GtkWidget *tab_menu; GtkWidget *gutter_menu; GtkWidget *notebook; }; typedef struct _WorkspacegroupviewClass { ViewClass parent_class; /* My methods. */ } WorkspacegroupviewClass; GType workspacegroupview_get_type( void ); View *workspacegroupview_new( void ); nip2-8.7.1/src/stringview.h0000644000175000017500000000277413351443023012471 00000000000000/* edit a string */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_STRINGVIEW (stringview_get_type()) #define STRINGVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_STRINGVIEW, Stringview )) #define STRINGVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_STRINGVIEW, StringviewClass )) #define IS_STRINGVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_STRINGVIEW )) #define IS_STRINGVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_STRINGVIEW )) typedef struct _Stringview { Editview parent_object; } Stringview; typedef struct _StringviewClass { EditviewClass parent_class; /* My methods. */ } StringviewClass; GtkType stringview_get_type( void ); View *stringview_new( void ); nip2-8.7.1/src/toolkitbrowser.c0000644000175000017500000002306313351443023013346 00000000000000/* Toolkitbrowser dialog. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; /* Our columns. */ enum { TOOLTIP_COLUMN, /* Visible columns */ MENU_COLUMN, NPARAM_COLUMN, TOOLITEM_COLUMN, /* Secret column */ N_COLUMNS }; static void toolkitbrowser_destroy( GtkObject *object ) { Toolkitbrowser *toolkitbrowser = TOOLKITBROWSER( object ); UNREF( toolkitbrowser->filter ); UNREF( toolkitbrowser->store ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void * toolkitbrowser_rebuild_item_sub( Symbol *param, VipsBuf *buf ) { vips_buf_appends( buf, " " ); vips_buf_appends( buf, IOBJECT( param )->name ); return( NULL ); } static void * toolkitbrowser_rebuild_item3( Toolitem *toolitem, Toolkitbrowser *toolkitbrowser ) { if( !toolitem->is_pullright && !toolitem->is_separator && toolitem->compile ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); GtkTreeIter iter; if( toolitem->action_sym && toolitem->action_sym->expr && toolitem->action_sym->expr->compile->param ) slist_map( toolitem->action_sym->expr->compile->param, (SListMapFn) toolkitbrowser_rebuild_item_sub, &buf ); gtk_list_store_append( toolkitbrowser->store, &iter ); gtk_list_store_set( toolkitbrowser->store, &iter, TOOLTIP_COLUMN, toolitem->tooltip, MENU_COLUMN, toolitem->user_path, NPARAM_COLUMN, vips_buf_all( &buf ), TOOLITEM_COLUMN, toolitem, -1 ); } slist_map( toolitem->children, (SListMapFn) toolkitbrowser_rebuild_item3, toolkitbrowser ); return( NULL ); } static void * toolkitbrowser_rebuild_item2( Tool *tool, Toolkitbrowser *toolkitbrowser ) { if( tool->toolitem ) toolkitbrowser_rebuild_item3( tool->toolitem, toolkitbrowser ); return( NULL ); } static void * toolkitbrowser_rebuild_item( Toolkit *kit, Toolkitbrowser *toolkitbrowser ) { toolkit_map( kit, (tool_map_fn) toolkitbrowser_rebuild_item2, toolkitbrowser, NULL ); return( NULL ); } static void toolkitbrowser_refresh( vObject *vobject ) { Toolkitbrowser *toolkitbrowser = TOOLKITBROWSER( vobject ); #ifdef DEBUG printf( "toolkitbrowser_refresh:\n" ); #endif /*DEBUG*/ gtk_list_store_clear( toolkitbrowser->store ); toolkitgroup_map( toolkitbrowser->kitg, (toolkit_map_fn) toolkitbrowser_rebuild_item, toolkitbrowser, NULL ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void toolkitbrowser_link( vObject *vobject, iObject *iobject ) { Toolkitbrowser *toolkitbrowser = TOOLKITBROWSER( vobject ); Toolkitgroup *kitg = TOOLKITGROUP( iobject ); g_assert( !toolkitbrowser->kitg ); toolkitbrowser->kitg = kitg; VOBJECT_CLASS( parent_class )->link( vobject, iobject ); } static void toolkitbrowser_class_init( ToolkitbrowserClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = toolkitbrowser_destroy; vobject_class->refresh = toolkitbrowser_refresh; vobject_class->link = toolkitbrowser_link; } static void toolkitbrowser_entry_changed_cb( GtkEditable *editable, Toolkitbrowser *toolkitbrowser ) { gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER( toolkitbrowser->filter ) ); } static gboolean toolkitbrowser_rebuild_test( Toolitem *toolitem, const char *text ) { if( my_strcasestr( toolitem->user_path, text ) || my_strcasestr( toolitem->tooltip, text ) ) return( TRUE ); return( FALSE ); } static gboolean toolkitbrowser_visible_func( GtkTreeModel *model, GtkTreeIter *iter, gpointer data ) { Toolkitbrowser *toolkitbrowser = TOOLKITBROWSER( data ); const char *text = gtk_entry_get_text( GTK_ENTRY( toolkitbrowser->entry ) ); Toolitem *toolitem; gtk_tree_model_get( model, iter, TOOLITEM_COLUMN, &toolitem, -1 ); if( !toolitem ) return( FALSE ); return( toolkitbrowser_rebuild_test( toolitem, text ) ); } static Toolitem * toolkitbrowser_get_selected( Toolkitbrowser *toolkitbrowser ) { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW( toolkitbrowser->tree ) ); GtkTreeIter iter; GtkTreeModel *model; Toolitem *toolitem; if( gtk_tree_selection_get_selected( selection, &model, &iter ) ) { gtk_tree_model_get( model, &iter, TOOLITEM_COLUMN, &toolitem, -1 ); return( toolitem ); } return( NULL ); } static gboolean toolkitbrowser_activate_selected( Toolkitbrowser *toolkitbrowser ) { Toolitem *toolitem; if( (toolitem = toolkitbrowser_get_selected( toolkitbrowser )) ) { if( !workspace_add_action( toolkitbrowser->ws, toolitem->name, toolitem->action, toolitem->action_sym->expr->compile->nparam ) ) return( FALSE ); } return( TRUE ); } static void toolkitbrowser_row_activated_cb( GtkTreeView *treeview, GtkTreePath *arg1, GtkTreeViewColumn *arg2, Toolkitbrowser *toolkitbrowser ) { if( !toolkitbrowser_activate_selected( toolkitbrowser ) ) iwindow_alert( GTK_WIDGET( toolkitbrowser ), GTK_MESSAGE_ERROR ); } static void toolkitbrowser_init( Toolkitbrowser *toolkitbrowser ) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *label; GtkWidget *swin; toolkitbrowser->top = gtk_hbox_new( FALSE, 12 ); toolkitbrowser->entry = gtk_entry_new(); gtk_signal_connect( GTK_OBJECT( toolkitbrowser->entry ), "changed", GTK_SIGNAL_FUNC( toolkitbrowser_entry_changed_cb ), toolkitbrowser ); gtk_box_pack_end( GTK_BOX( toolkitbrowser->top ), toolkitbrowser->entry, FALSE, FALSE, 2 ); label = gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_MENU ); gtk_box_pack_end( GTK_BOX( toolkitbrowser->top ), label, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( toolkitbrowser ), toolkitbrowser->top, FALSE, FALSE, 2 ); gtk_widget_show_all( toolkitbrowser->top ); toolkitbrowser->store = gtk_list_store_new( N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER ); toolkitbrowser->filter = gtk_tree_model_filter_new( GTK_TREE_MODEL( toolkitbrowser->store ), NULL ); gtk_tree_model_filter_set_visible_func( GTK_TREE_MODEL_FILTER( toolkitbrowser->filter ), toolkitbrowser_visible_func, toolkitbrowser, NULL ); toolkitbrowser->tree = gtk_tree_view_new_with_model( GTK_TREE_MODEL( toolkitbrowser->filter ) ); gtk_tree_view_set_rules_hint( GTK_TREE_VIEW( toolkitbrowser->tree ), TRUE ); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( _( "Action" ), renderer, "text", TOOLTIP_COLUMN, NULL ); gtk_tree_view_column_set_resizable( column, TRUE ); gtk_tree_view_column_set_reorderable( column, TRUE ); gtk_tree_view_append_column( GTK_TREE_VIEW( toolkitbrowser->tree ), column ); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( _( "Parameters" ), renderer, "text", NPARAM_COLUMN, NULL ); gtk_tree_view_column_set_resizable( column, TRUE ); gtk_tree_view_column_set_reorderable( column, TRUE ); gtk_tree_view_append_column( GTK_TREE_VIEW( toolkitbrowser->tree ), column ); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( _( "Menu Item" ), renderer, "text", MENU_COLUMN, NULL ); gtk_tree_view_column_set_resizable( column, TRUE ); gtk_tree_view_column_set_reorderable( column, TRUE ); gtk_tree_view_append_column( GTK_TREE_VIEW( toolkitbrowser->tree ), column ); g_signal_connect( G_OBJECT( toolkitbrowser->tree ), "row-activated", G_CALLBACK( toolkitbrowser_row_activated_cb ), toolkitbrowser ); swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_container_add( GTK_CONTAINER( swin ), toolkitbrowser->tree ); gtk_box_pack_start( GTK_BOX( toolkitbrowser ), swin, TRUE, TRUE, 2 ); gtk_widget_show_all( swin ); } GtkType toolkitbrowser_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Toolkitbrowser", sizeof( Toolkitbrowser ), sizeof( ToolkitbrowserClass ), (GtkClassInitFunc) toolkitbrowser_class_init, (GtkObjectInitFunc) toolkitbrowser_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VOBJECT, &info ); } return( type ); } Toolkitbrowser * toolkitbrowser_new( void ) { Toolkitbrowser *toolkitbrowser = gtk_type_new( TYPE_TOOLKITBROWSER ); return( toolkitbrowser ); } /* Find the 'natural' width of the browser. */ int toolkitbrowser_get_width( Toolkitbrowser *toolkitbrowser ) { if( toolkitbrowser->top ) return( toolkitbrowser->top->requisition.width ); else return( 200 ); } void toolkitbrowser_set_workspace( Toolkitbrowser *toolkitbrowser, Workspace *ws ) { g_assert( !toolkitbrowser->ws ); toolkitbrowser->ws = ws; } nip2-8.7.1/src/expressionview.h0000644000175000017500000000317613351443023013357 00000000000000/* a textview button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_EXPRESSIONVIEW (expressionview_get_type()) #define EXPRESSIONVIEW( obj ) (GTK_CHECK_CAST( (obj), \ TYPE_EXPRESSIONVIEW, Expressionview )) #define EXPRESSIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_EXPRESSIONVIEW, ExpressionviewClass )) #define IS_EXPRESSIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_EXPRESSIONVIEW )) #define IS_EXPRESSIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_EXPRESSIONVIEW )) typedef struct _Expressionview { Graphicview parent_object; Formula *formula; } Expressionview; typedef struct _ExpressionviewClass { GraphicviewClass parent_class; /* My methods. */ } ExpressionviewClass; GtkType expressionview_get_type( void ); View *expressionview_new( void ); nip2-8.7.1/src/prefworkspaceview.c0000644000175000017500000000673513351443023014032 00000000000000/* a prefworkspaceview button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Define to trace button press events. #define EVENT */ #include "ip.h" static ViewClass *parent_class = NULL; static void prefworkspaceview_destroy( GtkObject *object ) { Prefworkspaceview *pwview; #ifdef DEBUG printf( "prefworkspaceview_destroy\n" ); #endif /*DEBUG*/ g_return_if_fail( object != NULL ); g_return_if_fail( IS_PREFWORKSPACEVIEW( object ) ); pwview = PREFWORKSPACEVIEW( object ); /* Instance destroy. */ IM_FREE( pwview->caption_filter ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void prefworkspaceview_child_add( View *parent, View *child ) { Prefworkspaceview *pwview = PREFWORKSPACEVIEW( parent ); VIEW_CLASS( parent_class )->child_add( parent, child ); gtk_box_pack_end( GTK_BOX( pwview ), GTK_WIDGET( child ), FALSE, FALSE, 0 ); } /* Should a child model have a display? */ static gboolean prefworkspaceview_display( View *parent, Model *child ) { Prefworkspaceview *pwview = PREFWORKSPACEVIEW( parent ); Column *column = COLUMN( child ); if( pwview->caption_filter ) return( strstr( IOBJECT( column )->caption, pwview->caption_filter ) != NULL ); else return( TRUE ); } static void prefworkspaceview_class_init( PrefworkspaceviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = prefworkspaceview_destroy; view_class->child_add = prefworkspaceview_child_add; view_class->display = prefworkspaceview_display; } static void prefworkspaceview_init( Prefworkspaceview *pwview ) { pwview->caption_filter = NULL; } GtkType prefworkspaceview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Prefworkspaceview", sizeof( Prefworkspaceview ), sizeof( PrefworkspaceviewClass ), (GtkClassInitFunc) prefworkspaceview_class_init, (GtkObjectInitFunc) prefworkspaceview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VIEW, &info ); } return( type ); } View * prefworkspaceview_new( void ) { Prefworkspaceview *pwview = gtk_type_new( TYPE_PREFWORKSPACEVIEW ); return( VIEW( pwview ) ); } void prefworkspaceview_set_caption_filter( Prefworkspaceview *pwview, const char *caption_filter ) { IM_SETSTR( pwview->caption_filter, caption_filter ); /* caption_filter is a property of the view, not the model, so we have * to queue a refresh rather than just signalling change. */ vobject_refresh_queue( VOBJECT( pwview ) ); } nip2-8.7.1/src/colour.h0000644000175000017500000000337113351443023011565 00000000000000/* a colour colour in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_COLOUR (colour_get_type()) #define COLOUR( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_COLOUR, Colour )) #define COLOUR_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_COLOUR, ColourClass)) #define IS_COLOUR( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_COLOUR )) #define IS_COLOUR_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_COLOUR )) #define COLOUR_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_COLOUR, ColourClass )) struct _Colour { Classmodel parent_class; /* Class fields. */ double value[3]; char *colour_space; /* Build view caption here. */ VipsBuf caption; }; typedef struct _ColourClass { ClassmodelClass parent_class; /* My methods. */ } ColourClass; Imageinfo *colour_ii_new( Colour *colour ); void colour_set_rgb( Colour *colour, double rgb[3] ); GType colour_get_type( void ); nip2-8.7.1/src/progress.h0000644000175000017500000000536213351443023012130 00000000000000/* Handle feedback about eval progress. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your watch) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* The max size of the feedback message. */ #define PROGRESS_FEEDBACK_SIZE (100) #define TYPE_PROGRESS (progress_get_type()) #define PROGRESS( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_PROGRESS, Progress )) #define PROGRESS_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_PROGRESS, ProgressClass)) #define IS_PROGRESS( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_PROGRESS )) #define IS_PROGRESS_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_PROGRESS )) #define PROGRESS_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_PROGRESS, ProgressClass )) typedef struct _Progress { iObject parent_object; /* Nest progress_begin() calls with this. */ int count; /* How long we've been busy, time since last update. */ GTimer *busy_timer; GTimer *update_timer; /* Trying to cancel. */ gboolean cancel; /* In the "busy" state, ie. we've emitted "begin" and so we need to * emit "end" on progress_end(). */ gboolean busy; /* The feedback message we suggest, percent for progress bar. */ VipsBuf feedback; char buf[PROGRESS_FEEDBACK_SIZE]; int percent; } Progress; typedef struct _ProgressClass { iObjectClass parent_class; /* Entering busy state: display progress bar, change cursor, etc. */ void (*begin)( Progress * ); /* Progress update. Set cancel to cancel computation. */ void (*update)( Progress *, gboolean *cancel ); /* End busy state. Restore screen. */ void (*end)( Progress * ); } ProgressClass; /* Called from all over nip2 as computation proceeds. */ void progress_begin( void ); gboolean progress_update_percent( int percent, int eta ); gboolean progress_update_expr( Expr *expr ); gboolean progress_update_loading( int percent, const char *filename ); gboolean progress_update_tick( void ); void progress_end( void ); GType progress_get_type( void ); Progress *progress_get( void ); nip2-8.7.1/src/path.c0000644000175000017500000003506213351443023011213 00000000000000/* Search paths for files. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* just load .defs/.wses from "." #define DEBUG_LOCAL */ /* show path searches #define DEBUG_SEARCH */ /* show path rewrites #define DEBUG_REWRITE */ #include "ip.h" /* Default search paths if prefs fail. */ GSList *path_start_default = NULL; GSList *path_search_default = NULL; const char *path_tmp_default = NULL; /* We rewrite paths to try to handle files referenced in workspaces in * directories that move. * * For example, suppose we have workspace.ws in /some/directory which loads * image.v in that directory. The workspace will include a line like * (Image_file "/some/directory/image"). Now if directory is moved to * /other/directory and workspace.ws reloaded, we want to rewrite the string * "/some/directory/image.v" to "/other/directory/image.v". * * Also consider picking ICC profiles in export/import: we want to avoid * putting the path into the ws file, we need to go back to "$VIPSHOME" again. * * Rewrite rules can be "locked". For example, we don't want the rewrite from * "/home/john" to "$HOME" to ever be removed. */ typedef struct _Rewrite { char *old; char *new; gboolean lock; } Rewrite; static GSList *rewrite_list = NULL; static void path_rewrite_free( Rewrite *rewrite ) { rewrite_list = g_slist_remove( rewrite_list, rewrite ); IM_FREE( rewrite->old ); IM_FREE( rewrite->new ); IM_FREE( rewrite ); } void path_rewrite_free_all( void ) { while( rewrite_list ) { Rewrite *rewrite = (Rewrite *) rewrite_list->data; IM_FREEF( path_rewrite_free, rewrite ); } } static Rewrite * path_rewrite_new( const char *old, const char *new, gboolean lock ) { Rewrite *rewrite; rewrite = g_new( Rewrite, 1 ); rewrite->old = g_strdup( old ); rewrite->new = g_strdup( new ); rewrite->lock = lock; rewrite_list = g_slist_prepend( rewrite_list, rewrite ); return( rewrite ); } static gint path_rewrite_sort_fn( Rewrite *a, Rewrite *b ) { return( strlen( b->old ) - strlen( a->old ) ); } static Rewrite * path_rewrite_lookup( const char *old ) { GSList *p; Rewrite *rewrite; for( p = rewrite_list; p; p = p->next ) { rewrite = (Rewrite *) p->data; if( strcmp( old, rewrite->old ) == 0 ) return( rewrite ); } return( NULL ); } /* Add a new rewrite pair to the rewrite list. @new can be NULL, meaning * remove a rewrite rule. */ void path_rewrite_add( const char *old, const char *new, gboolean lock ) { char old_buf[FILENAME_MAX + 1]; char new_buf[FILENAME_MAX + 1]; Rewrite *rewrite; #ifdef DEBUG_REWRITE printf( "path_rewrite_add: old = %s, new = %s, lock = %d\n", old, new, lock ); #endif /*DEBUG_REWRITE*/ g_return_if_fail( old ); /* We want the old path in long form, with a trailing '/'. The * trailing '/' will stop us rewriting filenames. * * If we keep all @old paths in long form we can avoid rewrite loops. */ im_strncpy( old_buf, old, FILENAME_MAX ); strcat( old_buf, G_DIR_SEPARATOR_S ); path_expand( old_buf ); old = old_buf; if( new ) { /* We must keep the new path in short (unexpanded) form, * obviously. */ im_strncpy( new_buf, new, FILENAME_MAX ); strcat( new_buf, G_DIR_SEPARATOR_S ); new = new_buf; } /* If old is a prefix of new we will get endless expansion. */ if( new && is_prefix( old, new ) ) return; if( (rewrite = path_rewrite_lookup( old )) ) { if( !rewrite->lock && (!new || strcmp( old, new ) == 0) ) { #ifdef DEBUG_REWRITE printf( "path_rewrite_add: removing\n" ); #endif /*DEBUG_REWRITE*/ IM_FREEF( path_rewrite_free, rewrite ); } else if( !rewrite->lock && new ) { #ifdef DEBUG_REWRITE printf( "path_rewrite_add: updating\n" ); #endif /*DEBUG_REWRITE*/ IM_SETSTR( rewrite->new, new ); } else { #ifdef DEBUG_REWRITE printf( "path_rewrite_add: rewrite rule locked\n" ); #endif /*DEBUG_REWRITE*/ } } else if( new && strcmp( old, new ) != 0 ) { #ifdef DEBUG_REWRITE printf( "path_rewrite_add: adding\n" ); #endif /*DEBUG_REWRITE*/ (void) path_rewrite_new( old, new, lock ); } /* Keep longest old first, in case one old is a prefix of * another. */ rewrite_list = g_slist_sort( rewrite_list, (GCompareFunc) path_rewrite_sort_fn ); #ifdef DEBUG_REWRITE { GSList *p; printf( "path_rewrite_add: state:\n" ); for( p = rewrite_list; p; p = p->next ) { rewrite = (Rewrite *) p->data; printf( "\told = %s, new = %s\n", rewrite->old, rewrite->new ); } } #endif /*DEBUG_REWRITE*/ } /* Rewrite a string using the rewrite list. buf must be FILENAME_MAX * characters. */ void path_rewrite( char *buf ) { GSList *p; gboolean changed; #ifdef DEBUG_REWRITE printf( "path_rewrite: %s\n", buf ); #endif /*DEBUG_REWRITE*/ do { changed = FALSE; for( p = rewrite_list; p; p = p->next ) { Rewrite *rewrite = (Rewrite *) p->data; if( is_prefix( rewrite->old, buf ) ) { int olen = strlen( rewrite->old ); int nlen = strlen( rewrite->new ); int blen = strlen( buf ); if( blen - olen + nlen > FILENAME_MAX - 3 ) break; memmove( buf + nlen, buf + olen, blen - olen + 1 ); memcpy( buf, rewrite->new, nlen ); changed = TRUE; break; } } } while( changed ); #ifdef DEBUG_REWRITE printf( "\t-> %s\n", buf ); #endif /*DEBUG_REWRITE*/ } /* The inverse: rewrite in long form ready for file ops. */ void path_expand( char *path ) { char buf[FILENAME_MAX]; expand_variables( path, buf ); nativeize_path( buf ); absoluteize_path( buf ); canonicalize_path( buf ); im_strncpy( path, buf, FILENAME_MAX ); } /* Rewite a path to compact form. @path must be FILENAME_MAX characters. * * Examples: * * /home/john/../somefile -> $HOME/../somefile * /home/./john/../somefile -> $HOME/../somefile * fred -> ./fred */ void path_compact( char *path ) { path_expand( path ); path_rewrite( path ); } /* Turn a search path (eg. "/pics/lr:/pics/hr") into a list of directory names. */ GSList * path_parse( const char *path ) { GSList *op = NULL; const char *p; const char *e; int len; char name[FILENAME_MAX + 1]; for( p = path; *p; p = e ) { /* Find the start of the next component, or the NULL * character. */ if( !(e = strchr( p, G_SEARCHPATH_SEPARATOR )) ) e = p + strlen( p ); len = e - p + 1; /* Copy to our buffer, turn to string. */ im_strncpy( name, p, IM_MIN( len, FILENAME_MAX ) ); /* Add to path list. */ op = g_slist_append( op, im_strdupn( name ) ); /* Skip G_SEARCHPATH_SEPARATOR. */ if( *e == G_SEARCHPATH_SEPARATOR ) e++; } return( op ); } /* Free a path. path_free() is reserved n OS X :( */ void path_free2( GSList *path ) { slist_map( path, (SListMapFn) im_free, NULL ); g_slist_free( path ); } /* Sub-fn of below. Add length of this string + 1 (for ':'). */ static int path_add_component( const char *str, int c ) { return( c + strlen( str ) + 1 ); } /* Sub-fn of below. Copy string to buffer, append ':', return new end. */ static char * path_add_string( const char *str, char *buf ) { strcpy( buf, str ); strcat( buf, G_SEARCHPATH_SEPARATOR_S ); return( buf + strlen( buf ) ); } /* Turn a list of directory names into a search path. */ char * path_unparse( GSList *path ) { int len = GPOINTER_TO_INT( slist_fold( path, 0, (SListFoldFn) path_add_component, NULL ) ); char *buf = imalloc( NULL, len + 1 ); /* Build new string. */ slist_fold( path, buf, (SListFoldFn) path_add_string, NULL ); /* Fix '\0' to remove trailing G_SEARCHPATH_SEPARATOR. */ if( len > 0 ) buf[len - 1] = '\0'; return( buf ); } /* Track this stuff during a file search. */ typedef struct _Search { /* Pattern we search for, and it's compiled form. This does not * include any directory components. */ char *basename; GPatternSpec *wild; /* Directory offset. If the original pattern is a relative path, eg. * "poop/x*.v", we search every directory on path for a subdirectory * called "poop" and then search all files within that. */ char *dirname; /* User function to call for every matching file. */ path_map_fn fn; void *a; /* Files we've previously offered to the user function: we remove * duplicates. So "path1/wombat.def" hides "path2/wombat.def". */ GSList *previous; } Search; static void path_search_free( Search *search ) { IM_FREEF( g_free, search->basename ); IM_FREEF( g_free, search->dirname ); IM_FREEF( slist_free_all, search->previous ); IM_FREEF( g_pattern_spec_free, search->wild ); } static gboolean path_search_init( Search *search, const char *patt, path_map_fn fn, void *a ) { search->basename = g_path_get_basename( patt ); search->dirname = g_path_get_dirname( patt ); search->wild = NULL; search->fn = fn; search->a = a; search->previous = NULL; if( !(search->wild = g_pattern_spec_new( search->basename )) ) { path_search_free( search ); return( FALSE ); } return( TRUE ); } static void * path_str_eq( const char *s1, const char *s2 ) { if( strcmp( s1, s2 ) == 0 ) return( (void *) s1 ); else return( NULL ); } /* Test for string matches pattern. If the match is successful, call a user * function. */ static void * path_search_match( Search *search, const char *dir_name, const char *name ) { if( g_pattern_match_string( search->wild, name ) && !slist_map( search->previous, (SListMapFn) path_str_eq, (gpointer) name ) ) { char buf[FILENAME_MAX + 10]; void *result; /* Add to exclusion list. */ search->previous = g_slist_prepend( search->previous, g_strdup( name ) ); im_snprintf( buf, FILENAME_MAX, "%s" G_DIR_SEPARATOR_S "%s", dir_name, name ); path_compact( buf ); #ifdef DEBUG_SEARCH printf( "path_search_match: matched \"%s\"\n", buf ); #endif /*DEBUG_SEARCH*/ if( (result = search->fn( buf, search->a, NULL, NULL )) ) return( result ); } return( NULL ); } /* Scan a directory, calling a function for every entry. Abort scan if * function returns non-NULL. */ static void * path_scan_dir( const char *dir_name, Search *search ) { char buf[FILENAME_MAX]; GDir *dir; const char *name; void *result; /* Add the pattern offset, if any. It's '.' for no offset. */ im_snprintf( buf, FILENAME_MAX, "%s" G_DIR_SEPARATOR_S "%s", dir_name, search->dirname ); if( !(dir = (GDir *) callv_string_filename( (callv_string_fn) g_dir_open, buf, NULL, NULL, NULL )) ) return( NULL ); while( (name = g_dir_read_name( dir )) ) if( (result = path_search_match( search, buf, name )) ) { g_dir_close( dir ); return( result ); } g_dir_close( dir ); return( NULL ); } /* Scan a search path, applying a function to every file name which matches a * pattern. If the user function returns NULL, keep looking, otherwise return * its result. We return NULL on error, or if the user function returns NULL * for all filenames which match. * * Remove duplicates: if fred.wombat is in the first and second dirs on the * path, only apply to the first occurence. FIXME ... speed up with a hash and a (date based) cache at some point */ void * path_map( GSList *path, const char *patt, path_map_fn fn, void *a ) { Search search; void *result; #ifdef DEBUG_SEARCH printf( "path_map: searching for \"%s\"\n", patt ); #endif /*DEBUG_SEARCH*/ if( !path_search_init( &search, patt, fn, a ) ) return( NULL ); result = slist_map( path, (SListMapFn) path_scan_dir, &search ); path_search_free( &search ); return( result ); } /* As above, but scan a single directory. */ void * path_map_dir( const char *dir, const char *patt, path_map_fn fn, void *a ) { Search search; void *result; #ifdef DEBUG_SEARCH printf( "path_map_dir: searching for \"%s\"\n", patt ); #endif /*DEBUG_SEARCH*/ if( !path_search_init( &search, patt, fn, a ) ) return( NULL ); if( !(result = path_scan_dir( dir, &search )) ) { /* Not found? Maybe - error message anyway. */ error_top( _( "Not found." ) ); error_sub( _( "File \"%s\" not found." ), patt ); } path_search_free( &search ); return( result ); } /* Search for a file on the search path. */ char * path_find_file( const char *filename ) { char *fname; #ifdef DEBUG_SEARCH printf( "path_find_file: \"%s\"\n", filename ); #endif /*DEBUG_SEARCH*/ /* Try file name exactly. */ if( existsf( "%s", filename ) ) return( im_strdupn( filename ) ); /* Search everywhere. */ if( (fname = path_map( PATH_SEARCH, filename, (path_map_fn) im_strdupn, NULL )) ) return( fname ); error_top( _( "Not found." ) ); error_sub( _( "File \"%s\" not found on path" ), filename ); return( NULL ); } void path_init( void ) { char buf[FILENAME_MAX]; path_rewrite_add( get_prefix(), "$VIPSHOME", TRUE ); path_rewrite_add( g_get_home_dir(), "$HOME", TRUE ); path_rewrite_add( get_savedir(), "$SAVEDIR", TRUE ); /* You might think we could add a rule to swap '.' for * g_get_current_dir(), but that would then make workspaces depend on * a certain value of cwd before they could work. */ /* And the expanded form too. */ expand_variables( get_savedir(), buf ); path_rewrite_add( buf, "$SAVEDIR", TRUE ); #ifdef DEBUG_LOCAL printf( "path_init: loading start from \".\" only\n" ); path_start_default = path_parse( "." ); path_search_default = path_parse( "." ); path_tmp_default = im_strdup( NULL, "." ); #else /*!DEBUG_LOCAL*/ im_snprintf( buf, FILENAME_MAX, "%s" G_DIR_SEPARATOR_S "start" G_SEARCHPATH_SEPARATOR_S "$VIPSHOME" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S "$PACKAGE" G_DIR_SEPARATOR_S "start", get_savedir() ); path_start_default = path_parse( buf ); im_snprintf( buf, FILENAME_MAX, "%s" G_DIR_SEPARATOR_S "data" G_SEARCHPATH_SEPARATOR_S "$VIPSHOME" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S "$PACKAGE" G_DIR_SEPARATOR_S "data" G_SEARCHPATH_SEPARATOR_S ".", get_savedir() ); path_search_default = path_parse( buf ); im_snprintf( buf, FILENAME_MAX, "%s" G_DIR_SEPARATOR_S "tmp", get_savedir() ); path_tmp_default = im_strdup( NULL, buf ); #endif /*DEBUG_LOCAL*/ } nip2-8.7.1/src/boxes.h0000644000175000017500000001457513351443023011412 00000000000000/* decls for boxes. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ void box_alert( GtkWidget *par ); void box_vinfo( GtkWidget *par, const char *top, const char *sub, va_list ap ); void box_info( GtkWidget *par, const char *top, const char *sub, ... ) __attribute__((format(printf, 3, 4))); iDialog *box_yesno( GtkWidget *par, iWindowFn okcb, iWindowFn cancelcb, void *client, /* Call client */ iWindowNotifyFn nfn, void *sys, /* Call parent */ const char *yes_label, const char *top, const char *sub, ... ) __attribute__((format(printf, 9, 10))); void box_savenosave( GtkWidget *par, iWindowFn save, iWindowFn nosave, void *client, /* Call client */ iWindowNotifyFn nfn, void *sys, /* Call parent */ const char *top, const char *sub, ... ) __attribute__((format(printf, 8, 9))); void box_about( GtkWidget *par ); void box_help( GtkWidget *par, const char *name ); /* A dialog showing a bunch of editable strings ... eg. name and caption for * new toolkit etc. etc. */ #define TYPE_STRINGSET (stringset_get_type()) #define STRINGSET( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_STRINGSET, Stringset )) #define STRINGSET_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_STRINGSET, StringsetClass )) #define IS_STRINGSET( obj ) (GTK_CHECK_TYPE( (obj), TYPE_STRINGSET )) #define IS_STRINGSET_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_STRINGSET )) /* A Stringset is a bunch of these. */ typedef struct { struct _Stringset *ss; GtkWidget *entry; char *label; char *text; /* Current text value */ char *tooltip; } StringsetChild; typedef struct _Stringset { iDialog parent; GSList *children; GtkSizeGroup *group; /* Align labels with this */ } Stringset; typedef struct _StringsetClass { iDialogClass parent_class; /* My methods. */ } StringsetClass; void *stringset_child_destroy( StringsetChild *ssc ); StringsetChild *stringset_child_new( Stringset *ss, const char *label, const char *text, const char *tooltip ); GtkType stringset_get_type( void ); GtkWidget *stringset_new( void ); StringsetChild *stringset_child_get( Stringset *, const char *label ); /* Find dialog. */ #define TYPE_FIND (find_get_type()) #define FIND( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_FIND, Find )) #define FIND_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_FIND, FindClass )) #define IS_FIND( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FIND )) #define IS_FIND_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_FIND )) typedef struct _Find { iDialog parent; /* My instance vars. */ GtkWidget *search; #ifdef HAVE_GREGEX GtkWidget *regexp; #endif /*HAVE_GREGEX*/ GtkWidget *csens; GtkWidget *fromtop; } Find; typedef struct _FindClass { iDialogClass parent_class; /* My methods. */ } FindClass; GtkType find_get_type( void ); GtkWidget *find_new( void ); void box_url( GtkWidget *par, const char *url ); /* Font chooser window. */ #define TYPE_FONTCHOOSER (fontchooser_get_type()) #define FONTCHOOSER( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_FONTCHOOSER, Fontchooser )) #define FONTCHOOSER_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_FONTCHOOSER, FontchooserClass )) #define IS_FONTCHOOSER( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FONTCHOOSER )) #define IS_FONTCHOOSER_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_FONTCHOOSER )) typedef struct _Fontchooser { iDialog parent_object; GtkWidget *fontchooser; /* gtk font select widget */ } Fontchooser; typedef struct _FontchooserClass { iDialogClass parent_class; /* My methods. */ } FontchooserClass; GtkType fontchooser_get_type( void ); Fontchooser *fontchooser_new( void ); gboolean fontchooser_set_font_name( Fontchooser *fontchooser, const char *font_name ); char *fontchooser_get_font_name( Fontchooser * ); /* Font button. */ #define TYPE_FONTBUTTON (fontbutton_get_type()) #define FONTBUTTON( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_FONTBUTTON, Fontbutton )) #define FONTBUTTON_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_FONTBUTTON, FontbuttonClass )) #define IS_FONTBUTTON( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FONTBUTTON )) #define IS_FONTBUTTON_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_FONTBUTTON )) typedef struct _Fontbutton { GtkButton parent_object; char *font_name; /* Current name */ Fontchooser *fontchooser; /* Pop up dialog */ } Fontbutton; typedef struct _FontbuttonClass { GtkButtonClass parent_class; void (*changed)( Fontbutton * ); } FontbuttonClass; GtkType fontbutton_get_type( void ); Fontbutton *fontbutton_new( void ); void fontbutton_set_font_name( Fontbutton *fontbutton, const char *font_name ); const char *fontbutton_get_font_name( Fontbutton * ); /* Infobar subclass, with a close animation and a label. */ #define TYPE_INFOBAR (infobar_get_type()) #define INFOBAR( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_INFOBAR, Infobar )) #define INFOBAR_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_INFOBAR, InfobarClass )) #define IS_INFOBAR( obj ) (GTK_CHECK_TYPE( (obj), TYPE_INFOBAR )) #define IS_INFOBAR_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_INFOBAR )) struct _Infobar { #ifdef USE_INFOBAR GtkInfoBar parent_object; #endif /*USE_INFOBAR*/ GtkWidget *top; GtkWidget *sub; GtkWidget *info; guint close_timeout; guint close_animation_timeout; int height; }; typedef struct _InfobarClass { #ifdef USE_INFOBAR GtkInfoBarClass parent_class; #endif /*USE_INFOBAR*/ } InfobarClass; GtkType infobar_get_type( void ); Infobar *infobar_new( void ); void infobar_vset( Infobar *infobar, GtkMessageType type, const char *top, const char *sub, va_list ap ); void infobar_set( Infobar *infobar, GtkMessageType type, const char *top, const char *sub, ... ); nip2-8.7.1/src/number.c0000644000175000017500000000507113351443023011544 00000000000000/* an editable number */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ClassmodelClass *parent_class = NULL; static View * number_view_new( Model *model, View *parent ) { return( numberview_new() ); } /* Members of number we automate. */ static ClassmodelMember number_members[] = { { CLASSMODEL_MEMBER_STRING, NULL, 0, MEMBER_CAPTION, "caption", N_( "Caption" ), G_STRUCT_OFFSET( iObject, caption ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Number, value ) } }; static void number_class_init( NumberClass *class ) { iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Init methods. */ iobject_class->user_name = _( "Number" ); model_class->view_new = number_view_new; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = number_members; classmodel_class->n_members = IM_NUMBER( number_members ); } static void number_init( Number *number ) { number->value = 0.0; iobject_set( IOBJECT( number ), CLASS_NUMBER, NULL ); } GType number_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( NumberClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) number_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Number ), 32, /* n_pnumberlocs */ (GInstanceInitFunc) number_init, }; type = g_type_register_static( TYPE_CLASSMODEL, "Number", &info, 0 ); } return( type ); } nip2-8.7.1/src/dump.c0000644000175000017500000004430013351443023011217 00000000000000/* Prettyprint various things for debugging. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* A lot of this file is just for debugging. Uncomment to enable all the * debugging code. #define DEBUG */ /* Dump a binary operator. */ char * decode_BinOp( BinOp op ) { switch( op ) { case BI_NONE: return( "(none)" ); case BI_ADD: return( "+" ); case BI_SUB: return( "-" ); case BI_POW: return( "**" ); case BI_REM: return( "%" ); case BI_LSHIFT: return( "<<" ); case BI_RSHIFT: return( ">>" ); case BI_SELECT: return( "?" ); case BI_DIV: return( "/" ); case BI_JOIN: return( "++" ); case BI_COMMA: return( "," ); case BI_DOT: return( "." ); case BI_MUL: return( "*" ); case BI_LAND: return( "&&" ); case BI_LOR: return( "||" ); case BI_BAND: return( "&" ); case BI_BOR: return( "|" ); case BI_EOR: return( "^" ); case BI_EQ: return( "==" ); case BI_NOTEQ: return( "!=" ); case BI_PEQ: return( "===" ); case BI_PNOTEQ: return( "!==" ); case BI_LESS: return( "<" ); case BI_LESSEQ: return( "<=" ); case BI_MORE: return( ">" ); case BI_MOREEQ: return( ">=" ); case BI_IF: return( "if_then_else" ); case BI_CONS: return( ":" ); default: g_assert( FALSE ); /* Keep gcc happy. */ return( NULL ); } } /* Dump a unary operator. */ char * decode_UnOp( UnOp op ) { switch( op ) { case UN_NONE: return( "(none)" ); case UN_CSCHAR: return( "(signed char)" ); case UN_CUCHAR: return( "(unsigned char)" ); case UN_CSSHORT: return( "(signed short)" ); case UN_CUSHORT: return( "(unsigned short)" ); case UN_CSINT: return( "(signed int)" ); case UN_CUINT: return( "(unsigned int)" ); case UN_CFLOAT: return( "(float)" ); case UN_CDOUBLE: return( "(double)" ); case UN_CCOMPLEX: return( "(complex)" ); case UN_CDCOMPLEX: return( "(double complex)" ); case UN_MINUS: return( "-" ); case UN_NEG: return( "!" ); case UN_COMPLEMENT: return( "~" ); case UN_PLUS: return( "+" ); default: g_assert( FALSE ); /* Keep gcc happy. */ return( NULL ); } } /* Decode a node tag. */ char * decode_NodeType( NodeType tag ) { switch( tag ) { case TAG_APPL: return( "TAG_APPL" ); case TAG_CONS: return( "TAG_CONS" ); case TAG_FREE: return( "TAG_FREE" ); case TAG_DOUBLE: return( "TAG_DOUBLE" ); case TAG_COMPLEX: return( "TAG_COMPLEX" ); case TAG_CLASS: return( "TAG_CLASS" ); case TAG_GEN: return( "TAG_GEN" ); case TAG_FILE: return( "TAG_FILE" ); case TAG_SHARED: return( "TAG_SHARED" ); case TAG_REFERENCE: return( "TAG_REFERENCE" ); default: g_assert( FALSE ); /* Keep gcc happy. */ return( NULL ); } } /* Decode a CombinatorType. */ char * decode_CombinatorType( CombinatorType comb ) { switch( comb ) { case COMB_S: return( "S" ); case COMB_SL: return( "Sl" ); case COMB_SR: return( "Sr" ); case COMB_I: return( "I" ); case COMB_K: return( "K" ); case COMB_GEN: return( "G" ); default: g_assert( FALSE ); /* Keep gcc happy. */ return( NULL ); } } /* Decode a symbol type. */ char * decode_SymbolType( SymbolType t ) { switch( t ) { case SYM_VALUE: return( "SYM_VALUE" ); case SYM_PARAM: return( "SYM_PARAM" ); case SYM_ZOMBIE: return( "SYM_ZOMBIE" ); case SYM_WORKSPACE: return( "SYM_WORKSPACE" ); case SYM_WORKSPACEROOT: return( "SYM_WORKSPACEROOT" ); case SYM_ROOT: return( "SYM_ROOT" ); case SYM_EXTERNAL: return( "SYM_EXTERNAL" ); case SYM_BUILTIN: return( "SYM_BUILTIN" ); default: g_assert( FALSE ); return( NULL ); } } /* Decode a symbol type into something users might like to see. */ char * decode_SymbolType_user( SymbolType t ) { switch( t ) { case SYM_VALUE: return( _( "value" ) ); case SYM_PARAM: return( _( "parameter" ) ); case SYM_ZOMBIE: return( _( "zombie" ) ); case SYM_WORKSPACE: return( _( "workspace" ) ); case SYM_WORKSPACEROOT: return( _( "workspace root" ) ); case SYM_ROOT: return( _( "root symbol" ) ); case SYM_EXTERNAL: return( _( "external symbol" ) ); case SYM_BUILTIN: return( _( "built-in symbol" ) ); default: g_assert( FALSE ); return( NULL ); } } /* From here on, just used for debugging. */ #ifdef DEBUG #warning "DEBUG on in dump.c" /* Do a tiny dump of a symbol. Just a few characters. */ void * dump_tiny( Symbol *sym ) { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); printf( "(%p) ", sym ); symbol_qualified_name( sym, &buf ); if( sym->dirty ) printf( "*" ); printf( "%s %s; ", decode_SymbolType( sym->type ), vips_buf_all( &buf ) ); return( NULL ); } /* Dump a expr, tiny. */ static void * dump_expr_tiny( Expr *expr ) { printf( "(expr->sym->name = " ); symbol_name_print( expr->sym ); printf( ") " ); return( NULL ); } /* Dump a expr info. */ void dump_expr( Expr *expr ) { Symbol *sym = expr->sym; printf( "expr (%p)->sym->name = \"%s\"\n", expr, IOBJECT( sym )->name ); if( expr->row ) printf( "%s->row = (set)\n", IOBJECT( sym )->name ); if( expr->compile ) { printf( "%s->compile:\n", IOBJECT( sym )->name ); dump_compile( expr->compile ); } if( sym->dirty ) printf( "\n" ); else if( !PEISNOVAL( &expr->root ) ) { printf( "%s->expr->root = ", IOBJECT( sym )->name ); pgraph( &expr->root ); } if( expr->err ) printf( "%s->expr->err = %s\n", IOBJECT( sym )->name, bool_to_char( expr->err ) ); if( expr->error_top ) printf( "%s->expr->error_top = \"%s\"\n", IOBJECT( sym )->name, NN( expr->error_top ) ); if( expr->error_sub ) printf( "%s->expr->error_sub = \"%s\"\n", IOBJECT( sym )->name, NN( expr->error_sub ) ); } /* Dump a compile, tiny. */ static void * dump_compile_tiny( Compile *compile ) { printf( "(compile->sym->name = " ); symbol_name_print( compile->sym ); printf( ") " ); return( NULL ); } /* Dump a compile. */ void dump_compile( Compile *compile ) { Symbol *sym = compile->sym; printf( "compile (%p)->sym->name = \"%s\"\n", compile, IOBJECT( sym )->name ); #ifdef VERBOSE printf( "%s->class = %s\n", IOBJECT( sym )->name, bool_to_char( compile->is_klass ) ); printf( "%s->super = %s\n", IOBJECT( sym )->name, bool_to_char( compile->has_super ) ); printf( "%s->compile->text = \"%s\"\n", IOBJECT( sym )->name, NN( compile->text ) ); printf( "%s->compile->prhstext = \"%s\"\n", IOBJECT( sym )->name, NN( compile->prhstext ) ); printf( "%s->compile->rhstext = \"%s\"\n", IOBJECT( sym )->name, NN( compile->rhstext ) ); #endif /*VERBOSE*/ if( compile->tree ) { printf( "%s->compile->tree = \n", IOBJECT( sym )->name ); (void) dump_tree( compile->tree ); } #ifdef VERBOSE printf( "%s->compile->treefrag = %d pointers\n", IOBJECT( sym )->name, g_slist_length( compile->treefrag ) ); #endif /*VERBOSE*/ if( icontainer_get_n_children( ICONTAINER( compile ) ) > 0 ) { printf( "%s->compile->children =\n", IOBJECT( sym )->name ); (void) icontainer_map( ICONTAINER( compile ), (icontainer_map_fn) dump_symbol, NULL, NULL ); } #ifdef VERBOSE { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); printf( "%s->compile->nparam = %d\n", IOBJECT( sym )->name, compile->nparam ); printf( "%s->compile->param = ", IOBJECT( sym )->name ); (void) slist_map( compile->param, (SListMapFn) dump_tiny, NULL ); printf( "\n" ); printf( "%s->compile->nsecret = %d\n", IOBJECT( sym )->name, compile->nsecret ); printf( "%s->compile->secret = ", IOBJECT( sym )->name ); (void) slist_map( compile->secret, (SListMapFn) dump_tiny, NULL ); printf( "\n" ); printf( "%s->compile->this = ", IOBJECT( sym )->name ); if( compile->this ) dump_tiny( compile->this ); else printf( "(null)" ); printf( "\n" ); printf( "%s->compile->super = ", IOBJECT( sym )->name ); if( compile->super ) dump_tiny( compile->super ); else printf( "(null)" ); printf( "\n" ); printf( "%s->compile->children = ", IOBJECT( sym )->name ); (void) slist_map( compile->children, (SListMapFn) dump_tiny, NULL ); printf( "\n" ); graph_element( compile->heap, &buf, &compile->base, FALSE ); printf( "%s->compile->base = %s\n", IOBJECT( sym )->name, vips_buf_all( &buf ) ); if( compile->heap ) iobject_dump( IOBJECT( compile->heap ) ); } #endif /*VERBOSE*/ } /* Print a full symbol and all it's children. */ void * dump_symbol( Symbol *sym ) { printf( "\n\nsym->name = " ); (void) dump_tiny( sym ); printf( "\n" ); #ifdef VERBOSE printf( "%s->patch = %d pointers\n", IOBJECT( sym )->name, g_slist_length( sym->patch ) ); #endif /*VERBOSE*/ if( sym->expr ) dump_expr( sym->expr ); #ifdef VERBOSE printf( "%s->base = ", IOBJECT( sym )->name ); if( !sym->dirty ) { PElement root; PEPOINTE( &root, &sym->base ); pgraph( &root ); } else printf( "" ); printf( "\n" ); printf( "%s->dirty = %s\n", IOBJECT( sym )->name, bool_to_char( sym->dirty ) ); printf( "%s->parents = ", IOBJECT( sym )->name ); (void) slist_map( sym->parents, (SListMapFn) dump_compile_tiny, NULL ); printf( "\n" ); /* Prints topchildren and topparents. */ dump_links( sym ); printf( "%s->ndirtychildren = %d\n", IOBJECT( sym )->name, sym->ndirtychildren ); printf( "%s->leaf = %s\n", IOBJECT( sym )->name, bool_to_char( sym->leaf ) ); printf( "%s->tool = kit ", IOBJECT( sym )->name ); if( sym->tool ) dump_kit( sym->tool->kit ); else printf( "\n" ); #endif /*VERBOSE*/ return( NULL ); } /* Pretty print the whole of the symbol table. */ void dump_symbol_table( void ) { (void) icontainer_map( ICONTAINER( symbol_root->expr->compile ), (icontainer_map_fn) dump_symbol, NULL, NULL ); } /* Tiny dump a tool. */ static void * dump_tiny_tool( Tool *tool ) { switch( tool->type ) { case TOOL_SEP: printf( " " ); break; case TOOL_DIA: printf( " ", FILEMODEL( tool )->filename ); break; case TOOL_SYM: dump_tiny( tool->sym ); break; default: g_assert( FALSE ); } return( NULL ); } /* Print out the syms in a kit. */ void * dump_kit( Toolkit *kit ) { printf( "kit->name = %s; ", IOBJECT( kit )->name ); printf( "%s->tools = ", IOBJECT( kit )->name ); icontainer_map( ICONTAINER( kit ), (icontainer_map_fn) dump_tiny_tool, NULL, NULL ); printf( "\n" ); return( NULL ); } /* Easy find-a-symbol for gdb. */ Symbol * sym( char *name ) { return( compile_lookup( symbol_root->expr->compile, name ) ); } /* Print from a name. */ void psym( char *name ) { Symbol *s; if( (s = sym( name )) ) (void) dump_symbol( s ); else printf( "Symbol \"%s\" not found\n", name ); } /* Print scrap of graph. */ void pgraph( PElement *graph ) { char txt[10240]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( reduce_context->heap, &buf, graph, TRUE ); printf( "%s\n", vips_buf_all( &buf ) ); } /* Print symbol value from name. */ void psymv( char *name ) { Symbol *s; if( (s = sym( name )) ) { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_pelement( reduce_context->heap, &buf, &s->expr->root, TRUE ); printf( "%s = %s\n", name, vips_buf_all( &buf ) ); } } /* Pretty-print an element. */ static void print_element( int nsp, EType type, void *arg ) { switch( type ) { case ELEMENT_NOVAL: printf( "no value (%d)\n", GPOINTER_TO_INT( arg ) ); break; case ELEMENT_NODE: printf( "node ->\n" ); graph_heap( nsp + 1, arg ); break; case ELEMENT_SYMBOL: printf( "symbol \"%s\"", IOBJECT( arg )->name ); break; case ELEMENT_SYMREF: printf( "symref \"%s\"", IOBJECT( arg )->name ); break; case ELEMENT_COMPILEREF: printf( "compileref " ); compile_name_print( COMPILE( arg ) ); break; case ELEMENT_CONSTRUCTOR: printf( "constructor \"%s\"", IOBJECT( arg )->name ); break; case ELEMENT_CHAR: printf( "char \"%c\"", GPOINTER_TO_UINT( arg ) ); break; case ELEMENT_BOOL: printf( "bool \"%s\"", bool_to_char( (gboolean) GPOINTER_TO_UINT( arg ) ) ); break; case ELEMENT_BINOP: printf( "binop \"%s\"", decode_BinOp( (BinOp)arg ) ); break; case ELEMENT_UNOP: printf( "unop \"%s\"", decode_UnOp( (UnOp)arg ) ); break; case ELEMENT_COMB: printf( "combinator \"%s\"", decode_CombinatorType( (CombinatorType)arg ) ); break; case ELEMENT_TAG: printf( "tag \"%s\"", (char*)arg ); break; case ELEMENT_MANAGED: printf( "Managed* %p", arg ); break; case ELEMENT_ELIST: printf( "empty-list []" ); break; default: g_assert( FALSE ); } } /* Pretty-print a heap graph. */ void graph_heap( int nsp, HeapNode *hn ) { if( !hn ) return; printf( "%s", spc( nsp ) ); printf( "Node: " ); printf( "serial = %d, ", hn->flgs & FLAG_SERIAL ); if( hn->flgs & FLAG_PRINT ) printf( "print, " ); else printf( "noprint, " ); if( hn->flgs & FLAG_DEBUG ) printf( "debug, " ); else printf( "nodebug, " ); if( hn->flgs & FLAG_MARK ) printf( "marked, " ); else printf( "notmarked, " ); printf( "%s ", decode_NodeType( hn->type ) ); switch( hn->type ) { case TAG_APPL: case TAG_CONS: printf( "\n" ); printf( "%s", spc( nsp ) ); printf( "left: " ); print_element( nsp, hn->ltype, hn->body.ptrs.left ); printf( "\n" ); printf( "%s", spc( nsp ) ); printf( "right: " ); print_element( nsp, hn->rtype, hn->body.ptrs.right ); printf( "\n" ); break; case TAG_DOUBLE: printf( "real \"%g\"\n", hn->body.num ); break; case TAG_CLASS: printf( "instance-of-class \"%s\"\n", IOBJECT( hn->body.ptrs.left )->name ); printf( " secrets=(" ); print_element( nsp, GETRIGHT( hn )->ltype, GETRIGHT( hn )->body.ptrs.left ); printf( ") members=(" ); print_element( nsp, GETRIGHT( hn )->rtype, GETRIGHT( hn )->body.ptrs.right ); printf( ")\n" ); break; case TAG_COMPLEX: printf( "complex \"(%g,%g)\"\n", GETLEFT( hn )->body.num, GETRIGHT( hn )->body.num ); break; case TAG_GEN: printf( "list generator start=%g next=%g final=%g\n", GETLEFT( hn )->body.num, GETLEFT( GETRIGHT( hn ) )->body.num, GETRIGHT( GETRIGHT( hn ) )->body.num ); break; case TAG_FILE: printf( "list generator file=%s\n", MANAGEDFILE( GETLEFT( hn ) )->file->fname ); break; case TAG_FREE: default: g_assert( FALSE ); } } /* Pretty-print a const. */ static void dump_parseconst( ParseConst *pc ) { switch( pc->type ) { case PARSE_CONST_NUM: printf( "%G", pc->val.num ); break; case PARSE_CONST_COMPLEX: printf( "%Gj", pc->val.num ); case PARSE_CONST_STR: printf( "\"%s\"", pc->val.str ); break; case PARSE_CONST_BOOL: printf( "%s", bool_to_char( pc->val.bool ) ); break; case PARSE_CONST_CHAR: printf( "'%c'", pc->val.ch ); break; case PARSE_CONST_ELIST: printf( "[]" ); break; default: g_assert( FALSE ); } } /* Dump a parse tree. */ void * dump_tree( ParseNode *n ) { switch( n->type ) { case NODE_NONE: printf( "node->type == NODE_NONE\n" ); break; case NODE_APPLY: printf( "Function application\n" ); printf( "LHS = " ); (void) dump_tree( n->arg1 ); printf( "RHS = " ); (void) dump_tree( n->arg2 ); break; case NODE_CLASS: printf( "Class: " ); (void) dump_compile_tiny( n->klass ); printf( "\n" ); break; case NODE_LEAF: printf( "Leaf symbol (%p): ", n->leaf ); (void) dump_tiny( n->leaf ); printf( "\n" ); break; case NODE_TAG: printf( "Tag: %s\n", n->tag ); break; case NODE_BINOP: printf( "Binary operator %s\n", decode_BinOp( n->biop ) ); printf( "Left expression:\n" ); (void) dump_tree( n->arg1 ); printf( "Right expression:\n" ); (void) dump_tree( n->arg2 ); break; case NODE_UOP: printf( "Unary operator %s\n", decode_UnOp( n->uop ) ); printf( "Arg expression:\n" ); (void) dump_tree( n->arg1 ); break; case NODE_CONST: printf( "Constant " ); dump_parseconst( &n->con ); printf( "\n" ); break; case NODE_GENERATOR: printf( "List generator\n" ); printf( "Start:\n" ); (void) dump_tree( n->arg1 ); if( n->arg2 ) { printf( "Next:\n" ); (void) dump_tree( n->arg2 ); } if( n->arg3 ) { printf( "End:\n" ); (void) dump_tree( n->arg3 ); } break; case NODE_COMPOSE: printf( "Function compose\n" ); printf( "Left:\n" ); (void) dump_tree( n->arg1 ); printf( "Right:\n" ); (void) dump_tree( n->arg2 ); break; case NODE_LISTCONST: case NODE_SUPER: if( n->type == NODE_LISTCONST ) printf( "List constant\n" ); else printf( "Superclass construct\n" ); printf( "***[\n" ); slist_map_rev( n->elist, (SListMapFn) dump_tree, NULL ); printf( "***]\n" ); break; default: g_assert( FALSE ); } return( NULL ); } static void * dump_link_expr( LinkExpr *le ) { dump_expr_tiny( le->expr ); printf( " count = %d ; ", le->count ); return( NULL ); } void * dump_link( Link *link ) { printf( "link->parent = " ); symbol_name_print( link->parent ); if( link->parent->dirty ) printf( "(dirty)" ); printf( "\n" ); printf( "link->child = " ); symbol_name_print( link->child ); if( link->child->dirty ) printf( "(dirty)" ); printf( "\n" ); printf( "link->serial = %d\n", link->serial ); printf( "link->static_links = " ); slist_map( link->static_links, (SListMapFn) dump_link_expr, NULL ); printf( "\n" ); printf( "link->dynamic_links = " ); slist_map( link->dynamic_links, (SListMapFn) dump_link_expr, NULL ); printf( "\n" ); return( NULL ); } void dump_links( Symbol *sym ) { symbol_name_print( sym ); printf( "->topchildren = \n" ); slist_map( sym->topchildren, (SListMapFn) dump_link, NULL ); symbol_name_print( sym ); printf( "->topparents = \n" ); slist_map( sym->topparents, (SListMapFn) dump_link, NULL ); } void dump_symbol_heap( Symbol *sym ) { printf( "symbol " ); symbol_name_print( sym ); printf( "has graph:\n" ); if( sym->expr ) pgraph( &sym->expr->root ); printf( "\n" ); } #endif /*DEBUG*/ nip2-8.7.1/src/secret.h0000644000175000017500000000165213351443023011547 00000000000000/* Decls for secret.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ void secret_build( Compile *compile ); nip2-8.7.1/src/iobject.c0000644000175000017500000001516013351443023011673 00000000000000/* abstract base class for all nip objects */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Our signals. */ enum { SIG_DESTROY, /* End lifetime */ SIG_CHANGED, /* iObject has changed somehow */ SIG_LAST }; static GObjectClass *parent_class = NULL; static guint iobject_signals[SIG_LAST] = { 0 }; /* Don't emit "destroy" immediately, do it from the _dispose handler. */ void * iobject_destroy( iObject *iobject ) { #ifdef DEBUG printf( "iobject_destroy: " ); iobject_print( iobject ); #endif /*DEBUG*/ if( !iobject->in_destruction ) g_object_run_dispose( G_OBJECT( iobject ) ); return( NULL ); } void * iobject_changed( iObject *iobject ) { g_return_val_if_fail( iobject != NULL, NULL ); g_return_val_if_fail( IS_IOBJECT( iobject ), NULL ); #ifdef DEBUG printf( "iobject_changed: " ); iobject_print( iobject ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( iobject ), iobject_signals[SIG_CHANGED], 0 ); return( NULL ); } void * iobject_info( iObject *iobject, VipsBuf *buf ) { iObjectClass *iobject_class = IOBJECT_GET_CLASS( iobject ); g_return_val_if_fail( iobject != NULL, NULL ); g_return_val_if_fail( IS_IOBJECT( iobject ), NULL ); if( iobject_class->info ) iobject_class->info( iobject, buf ); return( NULL ); } static void iobject_dispose( GObject *gobject ) { iObject *iobject = IOBJECT( gobject ); #ifdef DEBUG printf( "iobject_dispose: " ); iobject_print( iobject ); #endif /*DEBUG*/ if( !iobject->in_destruction ) { iobject->in_destruction = TRUE; g_signal_emit( G_OBJECT( iobject ), iobject_signals[SIG_DESTROY], 0 ); iobject->in_destruction = FALSE; } G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void iobject_finalize( GObject *gobject ) { iObject *iobject = IOBJECT( gobject ); #ifdef DEBUG printf( "iobject_finalize: " ); iobject_print( iobject ); #endif /*DEBUG*/ /* Unlike GTK, we allow floating objects to be finalized. Handy if a * _new() fails. So don't assert( !iobject->floating ); */ IM_FREE( iobject->name ); IM_FREE( iobject->caption ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void iobject_real_destroy( iObject *iobject ) { } static void iobject_real_changed( iObject *iobject ) { iObjectClass *iobject_class = IOBJECT_GET_CLASS( iobject ); if( iobject_class->generate_caption ) IM_SETSTR( iobject->caption, iobject_class->generate_caption( iobject ) ); } static void iobject_real_info( iObject *iobject, VipsBuf *buf ) { if( iobject->name ) vips_buf_appendf( buf, "name = \"%s\"\n", iobject->name ); if( iobject->caption ) vips_buf_appendf( buf, "caption = \"%s\"\n", iobject->caption ); vips_buf_appendf( buf, "iObject :: \"%s\"\n", G_OBJECT_TYPE_NAME( iobject ) ); } static void iobject_class_init( iObjectClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = iobject_dispose; gobject_class->finalize = iobject_finalize; class->destroy = iobject_real_destroy; class->changed = iobject_real_changed; class->info = iobject_real_info; class->generate_caption = NULL; class->user_name = _( "Object" ); /* Create signals. */ iobject_signals[SIG_DESTROY] = g_signal_new( "destroy", G_TYPE_FROM_CLASS( gobject_class ), G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, G_STRUCT_OFFSET( iObjectClass, destroy ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); iobject_signals[SIG_CHANGED] = g_signal_new( "changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( iObjectClass, changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); } static void iobject_init( iObject *iobject ) { #ifdef DEBUG printf( "iobject_init: " ); iobject_print( iobject ); #endif /*DEBUG*/ /* Init our instance fields. */ iobject->name = NULL; iobject->caption = NULL; iobject->floating = TRUE; iobject->in_destruction = FALSE; } GType iobject_get_type( void ) { static GType iobject_type = 0; if( !iobject_type ) { static const GTypeInfo info = { sizeof( iObjectClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) iobject_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( iObject ), 32, /* n_preallocs */ (GInstanceInitFunc) iobject_init, }; iobject_type = g_type_register_static( G_TYPE_OBJECT, "iObject", &info, 0 ); } return( iobject_type ); } /* Test the name field ... handy with map. */ void * iobject_test_name( iObject *iobject, const char *name ) { g_return_val_if_fail( iobject != NULL, NULL ); g_return_val_if_fail( IS_IOBJECT( iobject ), NULL ); if( iobject->name && strcmp( iobject->name, name ) == 0 ) return( iobject ); return( NULL ); } void * iobject_print( iObject *iobject ) { g_print( "%s \"%s\" (%p)\n", G_OBJECT_TYPE_NAME( iobject ), NN( iobject->name ), iobject ); return( NULL ); } void iobject_set( iObject *iobject, const char *name, const char *caption ) { gboolean changed = FALSE; g_return_if_fail( iobject != NULL ); g_return_if_fail( IS_IOBJECT( iobject ) ); if( name && name != iobject->name ) { IM_SETSTR( iobject->name, name ); changed = TRUE; } if( caption && caption != iobject->caption ) { IM_SETSTR( iobject->caption, caption ); changed = TRUE; } if( changed ) iobject_changed( iobject ); #ifdef DEBUG printf( "iobject_set: " ); iobject_print( iobject ); #endif /*DEBUG*/ } void iobject_sink( iObject *iobject ) { g_assert( IS_IOBJECT( iobject ) ); if( iobject->floating ) { iobject->floating = FALSE; g_object_unref( G_OBJECT( iobject ) ); } } void iobject_dump( iObject *iobject ) { char txt[1000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); iobject_info( iobject, &buf ); printf( "%s", vips_buf_all( &buf ) ); } nip2-8.7.1/src/slider.h0000644000175000017500000000310513351443023011537 00000000000000/* a slider in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_SLIDER (slider_get_type()) #define SLIDER( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_SLIDER, Slider )) #define SLIDER_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_SLIDER, SliderClass)) #define IS_SLIDER( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_SLIDER )) #define IS_SLIDER_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_SLIDER )) #define SLIDER_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_SLIDER, SliderClass )) typedef struct _Slider { Classmodel parent_object; double from, to, value; } Slider; typedef struct _SliderClass { ClassmodelClass parent_class; /* My methods. */ } SliderClass; GType slider_get_type( void ); nip2-8.7.1/src/pathname.h0000644000175000017500000000272113351443023012055 00000000000000/* a pathname in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PATHNAME (pathname_get_type()) #define PATHNAME( obj ) (GTK_CHECK_CAST( (obj), TYPE_PATHNAME, Pathname )) #define PATHNAME_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PATHNAME, PathnameClass )) #define IS_PATHNAME( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PATHNAME )) #define IS_PATHNAME_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PATHNAME )) typedef struct _Pathname { Classmodel model; char *value; } Pathname; typedef struct _PathnameClass { ClassmodelClass parent_class; /* My methods. */ } PathnameClass; GType pathname_get_type( void ); nip2-8.7.1/src/rhs.c0000644000175000017500000002350313351443023011050 00000000000000/* the rhs of a tallyrow ... group together everything to the right of the * button */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static HeapmodelClass *parent_class = NULL; /* child is about to be added ... update our graphic/scol/text shortcuts. */ static void rhs_child_add( iContainer *parent, iContainer *child, int pos ) { Rhs *rhs = RHS( parent ); if( IS_SUBCOLUMN( child ) ) { IDESTROY( rhs->scol ); rhs->scol = MODEL( child ); } else if( IS_ITEXT( child ) ) { IDESTROY( rhs->itext ); rhs->itext = MODEL( child ); } else { IDESTROY( rhs->graphic ); rhs->graphic = MODEL( child ); } ICONTAINER_CLASS( parent_class )->child_add( parent, child, pos ); } static void rhs_child_remove( iContainer *parent, iContainer *child ) { Rhs *rhs = RHS( parent ); if( (void *) child == (void *) rhs->graphic ) rhs->graphic = NULL; else if( (void *) child == (void *) rhs->scol ) rhs->scol = NULL; else if( (void *) child == (void *) rhs->itext ) rhs->itext = NULL; ICONTAINER_CLASS( parent_class )->child_remove( parent, child ); } static void rhs_parent_add( iContainer *child ) { g_assert( IS_ROW( child->parent ) ); ICONTAINER_CLASS( parent_class )->parent_add( child ); } static View * rhs_view_new( Model *model, View *parent ) { return( rhsview_new() ); } static gboolean rhs_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ) { Rhs *rhs = RHS( model ); g_assert( IS_ROW( parent ) ); /* Hmm. Is this guaranteed? */ g_assert( sizeof( RhsFlags ) == sizeof( int ) ); if( !get_iprop( xnode, "vislevel", &rhs->vislevel ) || !get_iprop( xnode, "flags", (int *) &rhs->flags ) ) return( FALSE ); if( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) ) return( FALSE ); return( TRUE ); } static xmlNode * rhs_save( Model *model, xmlNode *xnode ) { Rhs *rhs = RHS( model ); xmlNode *xthis; if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) ) return( NULL ); if( !set_iprop( xthis, "vislevel", rhs->vislevel ) || !set_iprop( xthis, "flags", rhs->flags ) ) return( NULL ); return( xthis ); } /* How to spot and make a graphic display. */ typedef struct { const char *name; GType (*type)( void ); } RhsGraphic; /* All our graphicdisplay widgets. Order is important! Most-derived classes * first. */ static RhsGraphic rhs_graphic[] = { { CLASS_CLOCK, clock_get_type }, { CLASS_EXPRESSION, expression_get_type }, { CLASS_GROUP, group_get_type }, { CLASS_LIST, group_get_type }, { CLASS_PATHNAME, pathname_get_type }, { CLASS_FONTNAME, fontname_get_type }, { CLASS_TOGGLE, toggle_get_type }, { CLASS_SLIDER, slider_get_type }, { CLASS_COLOUR, colour_get_type }, { CLASS_OPTION, option_get_type }, { CLASS_MATRIX, matrix_get_type }, { CLASS_ARROW, iarrow_get_type }, { CLASS_REGION, iregion_get_type }, { CLASS_PLOT, plot_get_type }, { CLASS_IMAGE, iimage_get_type }, { CLASS_NUMBER, number_get_type }, { CLASS_REAL, real_get_type }, { CLASS_VECTOR, vector_get_type }, { CLASS_STRING, string_get_type } }; /* Create/destroy the graphic display. */ static gboolean rhs_refresh_graphic( Rhs *rhs, PElement *root ) { gboolean result; Row *row = HEAPMODEL( rhs )->row; int i; if( !heap_is_class( root, &result ) ) return( FALSE ); /* Only for non-parameter class objects. */ if( result && row->sym && row->sym->type != SYM_PARAM ) { for( i = 0; i < IM_NUMBER( rhs_graphic ); i++ ) { const char *name = rhs_graphic[i].name; if( !heap_is_instanceof( name, root, &result ) ) return( FALSE ); if( result ) break; } if( i != IM_NUMBER( rhs_graphic ) ) { GType type = rhs_graphic[i].type(); if( !rhs->graphic || !TYPE_EXACT( rhs->graphic, type ) ) classmodel_new_classmodel( type, rhs ); } else /* Not a class we know about. */ IDESTROY( rhs->graphic ); } else /* Should be no graphic display. */ IDESTROY( rhs->graphic ); return( TRUE ); } static void * rhs_new_heap( Heapmodel *heapmodel, PElement *root ) { gboolean result; Rhs *rhs = RHS( heapmodel ); Row *row = HEAPMODEL( rhs )->row; #ifdef DEBUG printf( "rhs_new_heap: " ); row_name_print( HEAPMODEL( rhs )->row ); printf( "\n" ); #endif /*DEBUG*/ /* Create/reuse/destroy the graphic display. */ if( !rhs_refresh_graphic( rhs, root ) ) return( rhs ); /* Create/reuse/destroy class display. Only for non-param symbols. */ if( !heap_is_class( root, &result ) ) return( rhs ); if( result && row->sym && row->sym->type != SYM_PARAM ) { if( !rhs->scol || !IS_SUBCOLUMN( rhs->scol ) ) subcolumn_new( rhs, NULL ); } else /* Should be no klass display. */ IDESTROY( rhs->scol ); /* Create/reuse/destroy text display. */ if( !rhs->itext ) itext_new( rhs ); /* Recurse for children. */ if( rhs->graphic ) if( heapmodel_new_heap( HEAPMODEL( rhs->graphic ), root ) ) return( rhs ); if( rhs->scol ) if( heapmodel_new_heap( HEAPMODEL( rhs->scol ), root ) ) return( rhs ); if( rhs->itext ) if( heapmodel_new_heap( HEAPMODEL( rhs->itext ), root ) ) return( rhs ); return( HEAPMODEL_CLASS( parent_class )->new_heap( heapmodel, root ) ); } /* Rethink child visibility. */ void rhs_set_vislevel( Rhs *rhs, int vislevel ) { vislevel = IM_MAX( 0, vislevel ); #ifdef DEBUG printf( "rhs_set_vislevel: %d ...\n", vislevel ); #endif /*DEBUG*/ if( rhs->scol ) { Subcolumn *scol = SUBCOLUMN( rhs->scol ); if( rhs->graphic ) { switch( vislevel ) { case 0: rhs->flags = RHS_ITEXT; break; case 1: rhs->flags = RHS_GRAPHIC; break; case 2: rhs->flags = RHS_ITEXT | RHS_GRAPHIC; break; default: rhs->flags = RHS_ITEXT | RHS_GRAPHIC | RHS_SCOL; } subcolumn_set_vislevel( scol, vislevel - 2 ); if( vislevel < 3 ) rhs->vislevel = vislevel; else rhs->vislevel = scol->vislevel + 2; } else { vislevel = IM_MAX( 1, vislevel ); if( vislevel == 1 ) rhs->flags = RHS_ITEXT; else rhs->flags = RHS_ITEXT | RHS_SCOL; subcolumn_set_vislevel( scol, vislevel - 1 ); rhs->vislevel = scol->vislevel + 1; } } else { rhs->flags = RHS_ITEXT; rhs->vislevel = vislevel; } #ifdef DEBUG printf( "... set to: %d\n", rhs->vislevel ); #endif /*DEBUG*/ iobject_changed( IOBJECT( rhs ) ); } void rhs_vislevel_up( Rhs *rhs ) { rhs_set_vislevel( rhs, rhs->vislevel + 1 ); } void rhs_vislevel_down( Rhs *rhs ) { rhs_set_vislevel( rhs, rhs->vislevel - 1 ); } static void * rhs_update_model( Heapmodel *heapmodel ) { Rhs *rhs = RHS( heapmodel ); /* Update visibility. */ rhs_set_vislevel( rhs, rhs->vislevel ); return( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ); } static void rhs_class_init( RhsClass *class ) { iContainerClass *icontainer_class = (iContainerClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ icontainer_class->child_add = rhs_child_add; icontainer_class->child_remove = rhs_child_remove; icontainer_class->parent_add = rhs_parent_add; model_class->view_new = rhs_view_new; model_class->load = rhs_load; model_class->save = rhs_save; heapmodel_class->new_heap = rhs_new_heap; heapmodel_class->update_model = rhs_update_model; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); } static void rhs_init( Rhs *rhs ) { #ifdef DEBUG printf( "rhs_init\n" ); #endif /*DEBUG*/ /* -1 means not set yet ... default vislevel set by row_new_heap() * when the class members become available. */ rhs->vislevel = -1; rhs->graphic = NULL; rhs->scol = NULL; rhs->itext = NULL; } GType rhs_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( RhsClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) rhs_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Rhs ), 32, /* n_preallocs */ (GInstanceInitFunc) rhs_init, }; type = g_type_register_static( TYPE_HEAPMODEL, "Rhs", &info, 0 ); } return( type ); } Rhs * rhs_new( Row *row ) { Rhs *rhs = RHS( g_object_new( TYPE_RHS, NULL ) ); icontainer_child_add( ICONTAINER( row ), ICONTAINER( rhs ), -1 ); #ifdef DEBUG printf( "rhs_new: " ); row_name_print( HEAPMODEL( rhs )->row ); printf( " (%p)\n", rhs ); #endif /*DEBUG*/ return( rhs ); } static void * rhs_child_edited_sub( Model *model ) { Row *row = ROW( model ); if( row->child_rhs && rhs_child_edited( row->child_rhs ) ) return( row ); return( NULL ); } /* Does this RHS have any edited children? text, graphic, or recursive. */ gboolean rhs_child_edited( Rhs *rhs ) { if( rhs->itext && ITEXT( rhs->itext )->edited ) return( TRUE ); else if( rhs->graphic && CLASSMODEL( rhs->graphic )->edited ) return( TRUE ); else if( rhs->scol ) return( icontainer_map( ICONTAINER( rhs->scol ), (icontainer_map_fn) rhs_child_edited_sub, NULL, NULL ) != NULL ); else return( FALSE ); } nip2-8.7.1/src/builtin.c0000644000175000017500000006720613351443023011732 00000000000000/* Run builtin functions ... sin/error etc. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" #ifdef HAVE_GSL #include #include #endif /*HAVE_GSL*/ /* Trace builtin calls. #define DEBUG */ /* Spot something that might be an arg to sin/cos/tan etc. */ static gboolean ismatharg( Reduce *rc, PElement *base ) { return( PEISIMAGE( base ) || PEISREAL( base ) || PEISCOMPLEX( base ) ); } /* Spot something that might be an arg to re/im etc. */ static gboolean iscomplexarg( Reduce *rc, PElement *base ) { return( PEISIMAGE( base ) || PEISCOMPLEX( base ) ); } /* Spot anything. */ static gboolean isany( Reduce *rc, PElement *base ) { return( TRUE ); } /* Other PEIS as functions. */ static gboolean pe_is_image( Reduce *rc, PElement *base ) { return( PEISIMAGE( base ) ); } static gboolean pe_is_real( Reduce *rc, PElement *base ) { return( PEISREAL( base ) ); } static gboolean pe_is_complex( Reduce *rc, PElement *base ) { return( PEISCOMPLEX( base ) ); } static gboolean pe_is_bool( Reduce *rc, PElement *base ) { return( PEISBOOL( base ) ); } static gboolean pe_is_char( Reduce *rc, PElement *base ) { return( PEISCHAR( base ) ); } static gboolean pe_is_list( Reduce *rc, PElement *base ) { return( PEISLIST( base ) ); } static gboolean pe_is_flist( Reduce *rc, PElement *base ) { return( PEISFLIST( base ) ); } static gboolean pe_is_class( Reduce *rc, PElement *base ) { return( PEISCLASS( base ) ); } /* The types we might want to spot for builtins. * * Others, eg.: * static BuiltinTypeSpot vimage_spot = { "vips_image", pe_is_image }; static BuiltinTypeSpot bool_spot = { "bool", pe_is_bool }; static BuiltinTypeSpot realvec_spot = { "[real]", reduce_is_realvec }; static BuiltinTypeSpot matrix_spot = { "[[real]]", reduce_is_matrix }; static BuiltinTypeSpot instance_spot = { "class instance", pe_is_class }; static gboolean pe_is_gobject( Reduce *rc, PElement *base ) { return( PEISMANAGEDGOBJECT( base ) ); } static BuiltinTypeSpot gobject_spot = { "GObject", pe_is_gobject }; * */ static BuiltinTypeSpot real_spot = { "real", pe_is_real }; static BuiltinTypeSpot complex_spot = { "complex|image", iscomplexarg }; static BuiltinTypeSpot flist_spot = { "non-empty list", pe_is_flist }; static BuiltinTypeSpot string_spot = { "[char]", reduce_is_finitestring }; static BuiltinTypeSpot list_spot = { "[*]", reduce_is_list }; static BuiltinTypeSpot math_spot = { "image|real|complex", ismatharg }; static BuiltinTypeSpot any_spot = { "any", isany }; /* Args for "_". */ static BuiltinTypeSpot *underscore_args[] = { &string_spot }; /* Do a _ call. Args already spotted. */ static void apply_underscore_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char text[MAX_STRSIZE]; PEPOINTRIGHT( arg[0], &rhs ); (void) reduce_get_string( rc, &rhs, text, MAX_STRSIZE ); /* Pump though gettext. */ if( !heap_managedstring_new( rc->heap, _( text ), out ) ) reduce_throw( rc ); } /* Args for "has_member". */ static BuiltinTypeSpot *has_member_args[] = { &string_spot, &any_spot }; /* Do a has_member call. Args already spotted. */ static void apply_has_member_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char mname[MAX_STRSIZE]; PElement member; PEPOINTRIGHT( arg[1], &rhs ); (void) reduce_get_string( rc, &rhs, mname, MAX_STRSIZE ); PEPOINTRIGHT( arg[0], &rhs ); PEPUTP( out, ELEMENT_BOOL, class_get_member( &rhs, mname, NULL, &member ) ); } /* Args for "is_instanceof". */ static BuiltinTypeSpot *is_instanceof_args[] = { &string_spot, &any_spot }; /* Do an is_instance call. Args already spotted. */ static void apply_is_instanceof_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char kname[MAX_STRSIZE]; PEPOINTRIGHT( arg[1], &rhs ); (void) reduce_get_string( rc, &rhs, kname, MAX_STRSIZE ); PEPOINTRIGHT( arg[0], &rhs ); PEPUTP( out, ELEMENT_BOOL, reduce_is_instanceof( rc, kname, &rhs ) ); } /* Args for builtin on complex. */ static BuiltinTypeSpot *complex_args[] = { &complex_spot }; /* Do a complex op. Args already spotted. */ static void apply_complex_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; PEPOINTRIGHT( arg[0], &rhs ); if( PEISIMAGE( &rhs ) ) { if( strcmp( name, "re" ) == 0 ) call_spine( rc, "im_c2real", arg, out ); else if( strcmp( name, "im" ) == 0 ) call_spine( rc, "im_c2imag", arg, out ); } else if( PEISCOMPLEX( &rhs ) ) { if( strcmp( name, "re" ) == 0 ) { PEPUTP( out, ELEMENT_NODE, GETLEFT( PEGETVAL( &rhs ) ) ); } else if( strcmp( name, "im" ) == 0 ) { PEPUTP( out, ELEMENT_NODE, GETRIGHT( PEGETVAL( &rhs ) ) ); } } else error( "internal error #98743698437639487" ); } /* Args for builtin on list. */ static BuiltinTypeSpot *flist_args[] = { &flist_spot }; /* Do a list op. Args already spotted. */ static void apply_list_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; PElement a; PEPOINTRIGHT( arg[0], &rhs ); g_assert( PEISFLIST( &rhs ) ); reduce_get_list( rc, &rhs ); if( strcmp( name, "hd" ) == 0 ) { PEGETHD( &a, &rhs ); PEPUTPE( out, &a ); } else if( strcmp( name, "tl" ) == 0 ) { PEGETTL( &a, &rhs ); PEPUTPE( out, &a ); } else error( "internal error #098734953" ); } /* "gammq" */ static BuiltinTypeSpot *gammq_args[] = { &real_spot, &real_spot }; static void apply_gammq_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; double a, x, Q; PEPOINTRIGHT( arg[1], &rhs ); a = PEGETREAL( &rhs ); PEPOINTRIGHT( arg[0], &rhs ); x = PEGETREAL( &rhs ); if( a <= 0 || x < 0 ) { error_top( _( "Out of range." ) ); error_sub( _( "gammq arguments must be a > 0, x >= 0." ) ); reduce_throw( rc ); } #ifdef HAVE_GSL Q = gsl_sf_gamma_inc_Q( a, x ); #else /*!HAVE_GSL*/ error_top( _( "Not available." ) ); error_sub( _( "No GSL library available for gammq." ) ); reduce_throw( rc ); #endif /*HAVE_GSL*/ if( !heap_real_new( rc->heap, Q, out ) ) reduce_throw( rc ); } /* Args for "vips_image". */ static BuiltinTypeSpot *image_args[] = { &string_spot }; /* Do a image call. */ static void apply_image_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { Heap *heap = rc->heap; PElement rhs; char buf[FILENAME_MAX]; char filename[FILENAME_MAX]; char mode[FILENAME_MAX]; char *fn; Imageinfo *ii; /* Get string. */ PEPOINTRIGHT( arg[0], &rhs ); (void) reduce_get_string( rc, &rhs, buf, FILENAME_MAX ); /* The buf might be something like n3862.pyr.tif:1, ie. contain some * load options. Split and search just for the filename component. */ im_filename_split( buf, filename, mode ); /* Try to load image from given string. */ if( !(fn = path_find_file( filename )) ) reduce_throw( rc ); /* Reattach the mode and load. */ im_snprintf( buf, FILENAME_MAX, "%s:%s", fn, mode ); if( !(ii = imageinfo_new_input( main_imageinfogroup, NULL, heap, buf )) ) { IM_FREE( fn ); reduce_throw( rc ); } IM_FREE( fn ); PEPUTP( out, ELEMENT_MANAGED, ii ); MANAGED_UNREF( ii ); } /* Args for "read". */ static BuiltinTypeSpot *read_args[] = { &string_spot }; /* Do a read call. */ static void apply_read_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char buf[FILENAME_MAX]; /* Get string. */ PEPOINTRIGHT( arg[0], &rhs ); (void) reduce_get_string( rc, &rhs, buf, FILENAME_MAX ); if( !heap_file_new( rc->heap, buf, out ) ) reduce_throw( rc ); } /* Args for "graph_export_image". */ static BuiltinTypeSpot *graph_export_image_args[] = { &real_spot, &any_spot }; /* Do a graph_export_image call. */ static void apply_graph_export_image_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { #ifdef HAVE_LIBGOFFICE PElement rhs; double dpi; Plot *plot; Imageinfo *ii; PEPOINTRIGHT( arg[1], &rhs ); dpi = PEGETREAL( &rhs ); PEPOINTRIGHT( arg[0], &rhs ); if( !reduce_is_instanceof( rc, CLASS_PLOT, &rhs ) ) { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); itext_value_ev( rc, &buf, &rhs ); error_top( _( "Bad argument." ) ); error_sub( _( "Argument 2 to \"%s\" should " "be instance of \"%s\", you passed:\n %s" ), name, CLASS_PLOT, vips_buf_all( &buf ) ); reduce_throw( rc ); } plot = g_object_new( TYPE_PLOT, NULL ); if( !classmodel_update_members( CLASSMODEL( plot ), &rhs ) ) { UNREF( plot ); reduce_throw( rc ); } if( !(ii = plot_to_image( plot, rc, dpi )) ) { UNREF( plot ); reduce_throw( rc ); } UNREF( plot ); PEPUTP( out, ELEMENT_MANAGED, ii ); #else /*!HAVE_LIBGOFFICE*/ PEPUTP( out, ELEMENT_BOOL, TRUE ); #endif /*HAVE_LIBGOFFICE*/ } /* Args for "math". */ static BuiltinTypeSpot *math_args[] = { &math_spot }; /* A math function ... name, number implementation, image implementation. */ typedef struct { const char *name; /* ip name */ double (*rfn)( double ); /* Number implementation */ const char *ifn; /* VIPS name */ } MathFn; static double ip_sin( double a ) { return( sin( IM_RAD( a ) ) ); } static double ip_cos( double a ) { return( cos( IM_RAD( a ) ) ); } static double ip_tan( double a ) { return( tan( IM_RAD( a ) ) ); } static double ip_asin( double a ) { return( IM_DEG( asin( a ) ) ); } static double ip_acos( double a ) { return( IM_DEG( acos( a ) ) ); } static double ip_atan( double a ) { return( IM_DEG( atan( a ) ) ); } static double ip_exp10( double a ) { return( pow( 10.0, a ) ); } static double ip_ceil( double a ) { return( ceil( a ) ); } static double ip_floor( double a ) { return( floor( a ) ); } /* Table of math functions ... number implementations, image implementations. */ static MathFn math_fn[] = { { "sin", &ip_sin, "im_sintra" }, { "cos", &ip_cos, "im_costra" }, { "tan", &ip_tan, "im_tantra" }, { "asin", &ip_asin, "im_asintra" }, { "acos", &ip_acos, "im_acostra" }, { "atan", &ip_atan, "im_atantra" }, { "log", &log, "im_logtra" }, { "log10", &log10, "im_log10tra" }, { "exp", &exp, "im_exptra" }, { "exp10", &ip_exp10, "im_exp10tra" }, { "ceil", &ip_ceil, "im_ceil" }, { "floor", &ip_floor, "im_floor" } }; /* Do a math function (eg. sin, cos, tan). */ static void apply_math_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; int i; /* Find implementation. */ for( i = 0; i < IM_NUMBER( math_fn ); i++ ) if( strcmp( name, math_fn[i].name ) == 0 ) break; if( i == IM_NUMBER( math_fn ) ) error( "internal error #928456936" ); /* Get arg type ... real/complex/image */ PEPOINTRIGHT( arg[0], &rhs ); if( PEISIMAGE( &rhs ) ) { /* Easy ... pass to VIPS. */ call_spine( rc, math_fn[i].ifn, arg, out ); } else if( PEISREAL( &rhs ) ) { double a = PEGETREAL( &rhs ); double b = math_fn[i].rfn( a ); if( !heap_real_new( rc->heap, b, out ) ) reduce_throw( rc ); } else if( PEISCOMPLEX( &rhs ) ) { error_top( _( "Not implemented." ) ); error_sub( _( "Complex math ops not implemented." ) ); reduce_throw( rc ); } else error( "internal error #92870653" ); } /* Args for "predicate". */ static BuiltinTypeSpot *pred_args[] = { &any_spot }; /* A predicate function ... name, implementation. */ typedef struct { const char *name; /* ip name */ gboolean (*fn)( Reduce *, PElement * ); /* Implementation */ } PredicateFn; /* Table of predicate functions ... name and implementation. */ static PredicateFn predicate_fn[] = { { "is_image", &pe_is_image }, { "is_bool", &pe_is_bool }, { "is_real", &pe_is_real }, { "is_char", &pe_is_char }, { "is_class", &pe_is_class }, { "is_list", &pe_is_list }, { "is_complex", &pe_is_complex } }; /* Do a predicate function (eg. is_bool) */ static void apply_pred_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; gboolean res; int i; /* Find implementation. */ for( i = 0; i < IM_NUMBER( predicate_fn ); i++ ) if( strcmp( name, predicate_fn[i].name ) == 0 ) break; if( i == IM_NUMBER( predicate_fn ) ) error( "internal error #928456936" ); /* Call! */ PEPOINTRIGHT( arg[0], &rhs ); res = predicate_fn[i].fn( rc, &rhs ); PEPUTP( out, ELEMENT_BOOL, res ); } /* Args for "error". */ static BuiltinTypeSpot *error_args[] = { &string_spot }; /* Do "error". */ static void apply_error_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { char buf[MAX_STRSIZE]; PElement rhs; /* Get string. */ PEPOINTRIGHT( arg[0], &rhs ); (void) reduce_get_string( rc, &rhs, buf, MAX_STRSIZE ); error_top( _( "Macro error." ) ); error_sub( "%s", buf ); reduce_throw( rc ); } /* Args for "search". */ static BuiltinTypeSpot *search_args[] = { &string_spot }; /* Do "search". */ static void apply_search_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { char buf[MAX_STRSIZE]; PElement rhs; char *fn; /* Get string. */ PEPOINTRIGHT( arg[0], &rhs ); (void) reduce_get_string( rc, &rhs, buf, MAX_STRSIZE ); if( !(fn = path_find_file( buf )) ) /* If not found, return []. */ fn = im_strdup( NULL, "" ); if( !heap_managedstring_new( rc->heap, fn, out ) ) { IM_FREE( fn ); reduce_throw( rc ); } IM_FREE( fn ); } /* Args for "print". */ static BuiltinTypeSpot *print_args[] = { &any_spot }; /* Do "print". */ static void apply_print_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); PEPOINTRIGHT( arg[0], &rhs ); itext_value_ev( rc, &buf, &rhs ); if( !heap_managedstring_new( rc->heap, vips_buf_all( &buf ), out ) ) reduce_throw( rc ); } /* Args for "dir". */ static BuiltinTypeSpot *dir_args[] = { &any_spot }; static void * dir_object_member( Symbol *sym, PElement *value, Reduce *rc, PElement *list ) { PElement t; if( !heap_list_add( rc->heap, list, &t ) || !heap_managedstring_new( rc->heap, IOBJECT( sym )->name, &t ) ) reduce_throw( rc ); (void) heap_list_next( list ); return( NULL ); } static void * dir_object( Reduce *rc, PElement *list, PElement *instance, PElement *out ) { PElement p; /* p walks down the list as we build it, list stays pointing at the * head ready to be written to out. */ p = *list; heap_list_init( &p ); class_map( instance, (class_map_fn) dir_object_member, rc, &p ); PEPUTPE( out, list ); return( NULL ); } static void * dir_scope( Symbol *sym, Reduce *rc, PElement *list ) { PElement t; if( !heap_list_add( rc->heap, list, &t ) || !heap_managedstring_new( rc->heap, IOBJECT( sym )->name, &t ) ) reduce_throw( rc ); (void) heap_list_next( list ); return( NULL ); } static void * dir_gtype( GType type, void *a, void *b ) { Reduce *rc = (Reduce *) a; PElement *list = (PElement *) b; PElement t; if( !heap_list_add( rc->heap, list, &t ) || !heap_real_new( rc->heap, type, &t ) ) return( rc ); (void) heap_list_next( list ); return( NULL ); } static void dir_gobject( Reduce *rc, GParamSpec **properties, guint n_properties, PElement *out ) { int i; PElement list; list = *out; heap_list_init( &list ); for( i = 0; i < n_properties; i++ ) { PElement t; if( !heap_list_add( rc->heap, &list, &t ) || !heap_managedstring_new( rc->heap, properties[i]->name, &t ) ) reduce_throw( rc ); (void) heap_list_next( &list ); } } /* Do "dir". */ static void apply_dir_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; PEPOINTRIGHT( arg[0], &rhs ); if( PEISCLASS( &rhs ) ) /* This is more complex than it looks. We have to walk a class * instance generating a list of member names, while not * destroying the instance as we go, in the case that out will * overwrite (rhs) arg[0]. */ reduce_safe_pointer( rc, (reduce_safe_pointer_fn) dir_object, &rhs, out, NULL, NULL ); else if( PEISSYMREF( &rhs ) ) { Symbol *sym = PEGETSYMREF( &rhs ); if( is_scope( sym ) && sym->expr && sym->expr->compile ) { PElement list; list = *out; heap_list_init( &list ); icontainer_map( ICONTAINER( sym->expr->compile ), (icontainer_map_fn) dir_scope, rc, &list ); } } else if( PEISREAL( &rhs ) ) { /* Assume this is a gtype and try to get the children of that * type. */ GType type = PEGETREAL( &rhs ); PElement list; list = *out; heap_list_init( &list ); if( !g_type_name( type ) ) { error_top( _( "No such type" ) ); error_sub( _( "GType %u not found." ), (unsigned int) type ); reduce_throw( rc ); } if( vips_type_map( type, dir_gtype, rc, &list ) ) reduce_throw( rc ); } else if( PEISMANAGEDGOBJECT( &rhs ) ) { guint n_properties; ManagedgobjectClass *class = MANAGEDGOBJECT_GET_CLASS( PEGETMANAGEDGOBJECT( &rhs ) ); GParamSpec **properties; properties = g_object_class_list_properties( G_OBJECT_CLASS( class ), &n_properties ); dir_gobject( rc, properties, n_properties, out ); g_free( properties); } else /* Just [], ie. no names possible. */ heap_list_init( out ); } /* Args for "expand". */ static BuiltinTypeSpot *expand_args[] = { &string_spot }; /* Do "expand". */ static void apply_expand_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char txt[FILENAME_MAX]; char txt2[FILENAME_MAX]; PEPOINTRIGHT( arg[0], &rhs ); (void) reduce_get_string( rc, &rhs, txt, FILENAME_MAX ); expand_variables( txt, txt2 ); if( !heap_managedstring_new( rc->heap, txt2, out ) ) reduce_throw( rc ); } /* Args for "name2gtype". */ static BuiltinTypeSpot *name2gtype_args[] = { &string_spot }; /* Do "name2gtype". */ static void apply_name2gtype_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char txt[FILENAME_MAX]; int gtype; PEPOINTRIGHT( arg[0], &rhs ); (void) reduce_get_string( rc, &rhs, txt, FILENAME_MAX ); gtype = g_type_from_name( txt ); if( !heap_real_new( rc->heap, gtype, out ) ) reduce_throw( rc ); } /* Args for "gtype2name". */ static BuiltinTypeSpot *gtype2name_args[] = { &real_spot }; /* Do "gtype2name". */ static void apply_gtype2name_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; int gtype; PEPOINTRIGHT( arg[0], &rhs ); gtype = PEGETREAL( &rhs ); if( !heap_managedstring_new( rc->heap, g_type_name( gtype ), out ) ) reduce_throw( rc ); } /* Args for "vips_object_new". */ static BuiltinTypeSpot *vo_new_args[] = { &string_spot, &list_spot, &list_spot }; /* Do a vips_object_new call. */ static void apply_vo_new_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char buf[256]; PElement required; PElement optional; PEPOINTRIGHT( arg[2], &rhs ); reduce_get_string( rc, &rhs, buf, 256 ); PEPOINTRIGHT( arg[1], &required ); PEPOINTRIGHT( arg[0], &optional ); vo_object_new( rc, buf, &required, &optional, out ); } /* Args for "vips_call". */ static BuiltinTypeSpot *vo_call_args[] = { &string_spot, &list_spot, &list_spot }; /* Do a vips_call call. */ static void apply_vo_call_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out ) { PElement rhs; char buf[256]; PElement required; PElement optional; PEPOINTRIGHT( arg[2], &rhs ); reduce_get_string( rc, &rhs, buf, 256 ); PEPOINTRIGHT( arg[1], &required ); PEPOINTRIGHT( arg[0], &optional ); vo_call( rc, buf, &required, &optional, out ); } /* All ip's builtin functions. */ static BuiltinInfo builtin_table[] = { /* Other. */ { "dir", N_( "return list of names of members" ), FALSE, IM_NUMBER( dir_args ), &dir_args[0], &apply_dir_call }, { "search", N_( "search for file" ), FALSE, IM_NUMBER( search_args ), &search_args[0], &apply_search_call }, { "error", N_( "raise error" ), FALSE, IM_NUMBER( error_args ), &error_args[0], &apply_error_call }, { "print", N_( "convert to [char]" ), FALSE, IM_NUMBER( print_args ), &print_args[0], &apply_print_call }, { "expand", N_( "expand environment variables" ), FALSE, IM_NUMBER( expand_args ), &expand_args[0], &apply_expand_call }, { "name2gtype", N_( "convert [char] to GType" ), FALSE, IM_NUMBER( name2gtype_args ), &name2gtype_args[0], &apply_name2gtype_call }, { "gtype2name", N_( "convert GType to [char]" ), FALSE, IM_NUMBER( gtype2name_args ), >ype2name_args[0], &apply_gtype2name_call }, { "_", N_( "look up localised string" ), FALSE, IM_NUMBER( underscore_args ), &underscore_args[0], &apply_underscore_call }, /* vips8 wrapper. */ { "vips_object_new", N_( "create new vips8 object" ), FALSE, IM_NUMBER( vo_new_args ), &vo_new_args[0], apply_vo_new_call }, { "vips_call", N_( "call vips8 operator" ), FALSE, IM_NUMBER( vo_call_args ), &vo_call_args[0], apply_vo_call_call }, /* Predicates. */ { "is_image", N_( "true if argument is primitive image" ), FALSE, IM_NUMBER( pred_args ), &pred_args[0], apply_pred_call }, { "is_bool", N_( "true if argument is primitive bool" ), FALSE, IM_NUMBER( pred_args ), &pred_args[0], apply_pred_call }, { "is_real", N_( "true if argument is primitive real number" ), FALSE, IM_NUMBER( pred_args ), &pred_args[0], apply_pred_call }, { "is_class", N_( "true if argument is class" ), FALSE, IM_NUMBER( pred_args ), &pred_args[0], apply_pred_call }, { "is_char", N_( "true if argument is primitive char" ), FALSE, IM_NUMBER( pred_args ), &pred_args[0], apply_pred_call }, { "is_list", N_( "true if argument is primitive list" ), FALSE, IM_NUMBER( pred_args ), &pred_args[0], apply_pred_call }, { "is_complex", N_( "true if argument is primitive complex" ), FALSE, IM_NUMBER( pred_args ), &pred_args[0], apply_pred_call }, { "is_instanceof", N_( "true if argument class instance of type" ), FALSE, IM_NUMBER( is_instanceof_args ), &is_instanceof_args[0], apply_is_instanceof_call }, { "has_member", N_( "true if class has named member" ), FALSE, IM_NUMBER( has_member_args ), &has_member_args[0], apply_has_member_call }, /* List and complex projections. */ { "re", N_( "real part of complex" ), TRUE, IM_NUMBER( complex_args ), &complex_args[0], apply_complex_call }, { "im", N_( "imaginary part of complex" ), TRUE, IM_NUMBER( complex_args ), &complex_args[0], apply_complex_call }, { "hd", N_( "head of list" ), TRUE, IM_NUMBER( flist_args ), &flist_args[0], apply_list_call }, { "tl", N_( "tail of list" ), TRUE, IM_NUMBER( flist_args ), &flist_args[0], apply_list_call }, /* Math. */ { "sin", N_( "sine of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "cos", N_( "cosine of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "tan", N_( "tangent of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "asin", N_( "arc sine of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "acos", N_( "arc cosine of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "atan", N_( "arc tangent of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "log", N_( "log base e of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "log10", N_( "log base 10 of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "exp", N_( "e to the power of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "exp10", N_( "10 to the power of real number" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "ceil", N_( "real to int, rounding up" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, { "floor", N_( "real to int, rounding down" ), TRUE, IM_NUMBER( math_args ), &math_args[0], apply_math_call }, /* Optional GSL funcs. */ { "gammq", N_( "gamma function" ), TRUE, IM_NUMBER( gammq_args ), &gammq_args[0], apply_gammq_call }, /* Constructors. */ { "vips_image", N_( "load vips image" ), FALSE, IM_NUMBER( image_args ), &image_args[0], apply_image_call }, { "read", N_( "load text file" ), FALSE, IM_NUMBER( read_args ), &read_args[0], apply_read_call }, { "graph_export_image", N_( "generate image from Plot object" ), FALSE, IM_NUMBER( graph_export_image_args ), &graph_export_image_args[0], apply_graph_export_image_call }, }; #ifdef HAVE_GSL static void builtin_gsl_error( const char *reason, const char *file, int line, int gsl_errno ) { error_top( _( "GSL library error." ) ); error_sub( "%s - (%s:%d) - %s", reason, file, line, gsl_strerror( gsl_errno ) ); reduce_throw( reduce_context ); } #endif /*HAVE_GSL*/ void builtin_init( void ) { Toolkit *kit; int i; /* Make the _builtin toolkit and populate. */ kit = toolkit_new( main_toolkitgroup, "_builtin" ); for( i = 0; i < IM_NUMBER( builtin_table ); i++ ) { Symbol *sym; sym = symbol_new( symbol_root->expr->compile, builtin_table[i].name ); g_assert( sym->type == SYM_ZOMBIE ); sym->type = SYM_BUILTIN; sym->builtin = &builtin_table[i]; (void) tool_new_sym( kit, -1, sym ); symbol_made( sym ); } filemodel_set_auto_load( FILEMODEL( kit ) ); filemodel_set_modified( FILEMODEL( kit ), FALSE ); kit->pseudo = TRUE; /* Start up GSL, if we have it. */ #ifdef HAVE_GSL gsl_set_error_handler( builtin_gsl_error ); #endif /*HAVE_GSL*/ } /* Make a usage error. */ void builtin_usage( VipsBuf *buf, BuiltinInfo *builtin ) { int i; vips_buf_appendf( buf, ngettext( "Builtin \"%s\" takes %d argument.", "Builtin \"%s\" takes %d arguments.", builtin->nargs ), builtin->name, builtin->nargs ); vips_buf_appends( buf, "\n" ); for( i = 0; i < builtin->nargs; i++ ) vips_buf_appendf( buf, " %d - %s\n", i + 1, builtin->args[i]->name ); } #ifdef DEBUG static void builtin_trace_args( Heap *heap, const char *name, int n, HeapNode **arg ) { int i; char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); for( i = 0; i < n; i++ ) { PElement t; PEPOINTRIGHT( arg[n - i - 1], &t ); vips_buf_appends( &buf, "(" ); graph_pelement( heap, &buf, &t, FALSE ); vips_buf_appends( &buf, ") " ); } printf( "builtin: %s %s\n", name, vips_buf_all( &buf ) ); } #endif /*DEBUG*/ /* Execute the internal implementation of a builtin function. */ void builtin_run( Reduce *rc, Compile *compile, int op, const char *name, HeapNode **arg, PElement *out, BuiltinInfo *builtin ) { int i; /* Typecheck args. */ for( i = 0; i < builtin->nargs; i++ ) { BuiltinTypeSpot *ts = builtin->args[i]; PElement base; PEPOINTRIGHT( arg[builtin->nargs - i - 1], &base ); if( !ts->pred( rc, &base ) ) { char txt[100]; VipsBuf buf = VIPS_BUF_STATIC( txt ); itext_value_ev( rc, &buf, &base ); error_top( _( "Bad argument." ) ); error_sub( _( "Argument %d to builtin \"%s\" should " "be \"%s\", you passed:\n %s" ), i + 1, name, ts->name, vips_buf_all( &buf ) ); reduce_throw( rc ); } } #ifdef DEBUG builtin_trace_args( rc->heap, name, builtin->nargs, arg ); #endif /*DEBUG*/ builtin->fn( rc, name, arg, out ); } nip2-8.7.1/src/toolkitview.h0000644000175000017500000000321013351443023012632 00000000000000/* View for toolkit. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TOOLKITVIEW (toolkitview_get_type()) #define TOOLKITVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_TOOLKITVIEW, Toolkitview )) #define TOOLKITVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_TOOLKITVIEW, ToolkitviewClass )) #define IS_TOOLKITVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TOOLKITVIEW )) #define IS_TOOLKITVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKITVIEW )) struct _Toolkitview { View parent_class; Toolkitgroupview *kitgview; GtkWidget *menu; /* Menu for this kit */ GtkWidget *item; /* Menu item in enclosing menu */ guint destroy_sid; }; typedef struct _ToolkitviewClass { ViewClass parent_class; /* My methods. */ } ToolkitviewClass; GtkType toolkitview_get_type( void ); View *toolkitview_new( void ); nip2-8.7.1/src/toolkitgroup.h0000644000175000017500000000410313351443023013016 00000000000000/* Declarations for toolkitgroup.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TOOLKITGROUP (toolkitgroup_get_type()) #define TOOLKITGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_TOOLKITGROUP, Toolkitgroup )) #define TOOLKITGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_TOOLKITGROUP, \ ToolkitgroupClass)) #define IS_TOOLKITGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_TOOLKITGROUP )) #define IS_TOOLKITGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKITGROUP )) #define TOOLKITGROUP_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_TOOLKITGROUP, \ ToolkitgroupClass )) /* A toolkitgroup. */ struct _Toolkitgroup { Model parent_class; /* Defs in toolkits in this group are created as locals of this * symbol. This is symbol_root for the main toolkitgroup, but can be * local to a workspace if we are loading a set of compatibility defs. */ Symbol *root; }; typedef struct _ToolkitgroupClass { ModelClass parent_class; /* Methods. */ } ToolkitgroupClass; Toolkit *toolkitgroup_map( Toolkitgroup *kitg, toolkit_map_fn fn, void *a, void *b ); GType toolkitgroup_get_type( void ); Toolkitgroup *toolkitgroup_new( Symbol *root ); void toolkitgroup_sort( Toolkitgroup *kitg ); nip2-8.7.1/src/preview.h0000644000175000017500000000316613351443023011745 00000000000000/* thumbnail widget */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_PREVIEW (preview_get_type()) #define PREVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_PREVIEW, Preview )) #define PREVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_PREVIEW, PreviewClass )) #define IS_PREVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PREVIEW )) #define IS_PREVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_PREVIEW )) struct _Preview { Imagedisplay parent; char *filename; /* The file we are trying to display */ Conversion *conv; /* Hold a ref to the convert object */ }; typedef struct _PreviewClass { ImagedisplayClass parent_class; /* My methods. */ } PreviewClass; GtkType preview_get_type( void ); Preview *preview_new( void ); void preview_set_filename( Preview *preview, char *filename ); nip2-8.7.1/src/model.h0000644000175000017500000001501013351443023011353 00000000000000/* abstract base class for things which form the model of a model/view pair */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* When scrolling, do we want the top or the bottom of the object visible. * Important for Columns, since we sometimes want to see the title bar and * sometimes the edit box at the bottom. */ typedef enum { MODEL_SCROLL_TOP, MODEL_SCROLL_BOTTOM } ModelScrollPosition; /* How to rename symbols. */ typedef struct _ModelRename { char *old_name; char *new_name; } ModelRename; /* What we track during a load operation. */ typedef struct _ModelLoadState { char *filename; /* Name we loaded from */ char *filename_user; /* The filename to record in the model */ xmlDoc *xdoc; /* Document we load from */ /* FIXME ... a linked list? try a hash sometime see model_loadstate_rewrite_name() would probably only see a speedup for merging very large workspaces, not something we do often */ GSList *renames; /* Rename table for this load context */ /* The column renames we have planned. Don't rewrite exprs with these. */ GSList *column_renames; /* Version info we read from this XML file. */ int major; int minor; int micro; /* Log error messages here. */ char error_log_buffer[MAX_STRSIZE]; VipsBuf error_log; /* Set this bool to rewrite string constants using the filename * rewrite system. */ gboolean rewrite_path; /* The old_dir we added with path_rewrite_add() ... if non, NULL, * unset this rewrite rule on close. */ char *old_dir; } ModelLoadState; #define TYPE_MODEL (model_get_type()) #define MODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MODEL, Model )) #define MODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_MODEL, ModelClass)) #define IS_MODEL( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MODEL )) #define IS_MODEL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MODEL )) #define MODEL_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_MODEL, ModelClass )) struct _Model { iContainer parent_object; /* My instance vars. */ gboolean display; /* This model should have a view */ /* For things that have a pop-up window (eg. iimage, plot), the * position and size of the window. */ int window_x, window_y; int window_width, window_height; }; typedef struct _ModelClass { iContainerClass parent_class; /* Build display methods. view_new make a view for this model ... make the top view yourself, thereafter view will watch child_add etc. and manage subviews automatically ... use model->display to create and destroy views */ View *(*view_new)( Model *model, View *parent ); /* Change methods edit open an editor on the model header view model header scrollto try to make views visible reset signals views to reset ... eg. textview pops back to whatever the ws says it should be displaying (value or formula) layout try to lay child view out front trigger view_child_front() for all views display create and destroy views */ void (*edit)( GtkWidget *, Model * ); void (*header)( GtkWidget *, Model * ); void (*scrollto)( Model *, ModelScrollPosition ); void (*reset)( Model * ); void (*layout)( Model * ); void (*front)( Model * ); void (*display)( Model *, gboolean display ); /* Load and save methods. save write model as child of node save_test predicate ... save model if save_test is defined and true save_text plain text save ... eg. for toolkits load _init() model from xmlNode load_text _init() from plain text ... eg. toolkit empty remove contents of model */ xmlNode *(*save)( Model *, xmlNode * ); gboolean (*save_test)( Model * ); gboolean (*save_text)( Model *, iOpenFile * ); gboolean (*load)( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ); gboolean (*load_text)( Model *model, Model *parent, iOpenFile * ); void (*empty)( Model * ); } ModelClass; extern ModelLoadState *model_loadstate; gboolean model_loadstate_rename_new( ModelLoadState *state, const char *old_name, const char *new_name ); gboolean model_loadstate_taken( ModelLoadState *state, const char *name ); gboolean model_loadstate_column_rename_new( ModelLoadState *state, const char *old_name, const char *new_name ); gboolean model_loadstate_column_taken( ModelLoadState *state, const char *name ); ModelLoadState *model_loadstate_new( const char *filename, const char *filename_user ); ModelLoadState *model_loadstate_new_openfile( iOpenFile *of ); void model_loadstate_destroy( ModelLoadState *state ); char *model_loadstate_rewrite_name( char *name ); void model_loadstate_rewrite( ModelLoadState *state, char *old_rhs, char *new_rhs ); void model_register_loadable( ModelClass *model_class ); View *model_view_new( Model *model, View *parent ); void model_scrollto( Model *model, ModelScrollPosition position ); void model_layout( Model *model ); void *model_reset( Model *model ); void *model_edit( GtkWidget *parent, Model *model ); void *model_header( GtkWidget *parent, Model *model ); void model_front( Model *model ); void model_display( Model *model, gboolean display ); void *model_save( Model *model, xmlNode * ); gboolean model_save_test( Model *model ); void *model_save_text( Model *model, iOpenFile * ); void *model_load( Model *model, ModelLoadState *state, Model *parent, xmlNode *xnode ); void *model_load_text( Model *model, Model *parent, iOpenFile * ); void *model_empty( Model *model ); gboolean model_new_xml( ModelLoadState *state, Model *parent, xmlNode *xnode ); GType model_get_type( void ); void model_base_init( void ); View *model_build_display_all( Model *model, View *parent ); void model_check_destroy( GtkWidget *parent, Model *model, iWindowFn done_cb ); void *model_clear_edited( Model *model ); nip2-8.7.1/src/predicate.c0000644000175000017500000001113113351443023012206 00000000000000/* Symbol classifiers. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* Is it one of the system members? Hidden in menus and class display. We * can't safely use is_super()/is_this() (they are fast), because we can get * called during build (before they are working). Use strcmp() instead. */ gboolean is_system( Symbol *sym ) { Symbol *parent = symbol_get_parent( sym ); /* Something like $$lambda1 and friends. */ if( sym->generated ) return( TRUE ); if( strcmp( IOBJECT( sym )->name, MEMBER_CHECK ) == 0 || strcmp( IOBJECT( sym )->name, MEMBER_NAME ) == 0 || strcmp( IOBJECT( sym )->name, MEMBER_THIS ) == 0 || IOBJECT( sym )->name[0] == '_' ) return( TRUE ); if( parent && !is_scope( parent ) && strcmp( IOBJECT( sym )->name, IOBJECT( parent )->name ) == 0 ) return( TRUE ); return( FALSE ); } /* Something like "a = Separator;" */ gboolean is_separator( Symbol *sym ) { if( sym->expr && sym->expr->compile && sym->expr->compile->tree && sym->expr->compile->tree->type == NODE_LEAF ) { Symbol *leaf = sym->expr->compile->tree->leaf; return( strcmp( IOBJECT( leaf )->name, CLASS_SEPARATOR ) == 0 ); } return( FALSE ); } /* Is a symbol a class. */ gboolean is_class( Compile *compile ) { return( compile->is_klass ); } /* Is a sym the super member of some class. */ gboolean is_super( Symbol *sym ) { Symbol *parent = symbol_get_parent( sym ); Compile *parent_compile = parent->expr->compile; return( parent_compile && is_class( parent_compile ) && sym == parent_compile->super ); } /* Is a sym the this member of some class. */ gboolean is_this( Symbol *sym ) { Symbol *parent = symbol_get_parent( sym ); Compile *parent_compile = parent->expr->compile; return( is_class( parent_compile ) && sym == parent_compile->this ); } /* Is sym a member of an enclosing class of compile. */ gboolean is_member_enclosing( Compile *compile, Symbol *sym ) { for( compile = compile_get_parent( compile ); compile; compile = compile_get_parent( compile ) ) if( is_class( compile ) && compile->sym != sym && ICONTAINER( sym )->parent == ICONTAINER( compile ) ) return( TRUE ); return( FALSE ); } /* Is a symbol a compile-time scope (eg. workspace) */ gboolean is_scope( Symbol *sym ) { return( sym->type == SYM_ROOT || sym->type == SYM_WORKSPACE || sym->type == SYM_WORKSPACEROOT || !symbol_get_parent( sym ) ); } /* Is a symbol a top-level definition. Tops are symbols whose parents are * SYM_ROOT, SYM_WORKSPACE and friends. */ gboolean is_top( Symbol *sym ) { if( is_scope( sym ) || is_scope( symbol_get_parent( sym ) ) ) return( TRUE ); return( FALSE ); } /* Is a symbol a member of a class? Params don't count. */ gboolean is_member( Symbol *sym ) { return( is_value( sym ) && is_class( COMPILE( ICONTAINER( sym )->parent ) ) ); } /* Is a compile a member function (not a sub-class)? */ gboolean is_memberfunc( Compile *compile ) { return( is_class( compile_get_parent( compile ) ) && !is_class( compile ) ); } /* Something that ought to have a value. */ gboolean is_value( Symbol *sym ) { return( sym->type == SYM_VALUE && sym->expr ); } /* Is sym an ancestor of context? */ gboolean is_ancestor( Symbol *context, Symbol *sym ) { if( context == sym ) return( TRUE ); if( context == symbol_root ) return( FALSE ); return( is_ancestor( symbol_get_parent( context ), sym ) ); } gboolean is_menuable( Symbol *sym ) { /* In a hidden kit? */ if( sym->tool && IOBJECT( sym->tool->kit )->name[0] == '_' ) return( FALSE ); /* A hidden item? */ if( IOBJECT( sym )->name[0] == '_' ) return( FALSE ); /* We also hide all supers, system things */ if( !is_value( sym ) || !sym->expr->compile || is_system( sym ) || strcmp( IOBJECT( sym )->name, MEMBER_SUPER ) == 0 ) return( FALSE ); return( TRUE ); } nip2-8.7.1/src/progress.c0000644000175000017500000001626713351443023012131 00000000000000/* Handle feedback about eval progress. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your watch) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_MEMUSE #define DEBUG */ #include "ip.h" static iContainerClass *progress_parent_class = NULL; /* Our signals. */ enum { SIG_BEGIN, /* Switch to busy state */ SIG_UPDATE, /* Busy progress update */ SIG_END, /* End busy state */ SIG_LAST }; static guint progress_signals[SIG_LAST] = { 0 }; /* Delay before we start showing busy feedback. */ static const double progress_busy_delay = 1.0; /* Delay between busy updates. */ static const double progress_update_interval = 0.1; void progress_begin( void ) { Progress *progress = progress_get(); g_assert( progress->count >= 0 ); #ifdef DEBUG printf( "progress_begin: %d\n", progress->count ); #endif /*DEBUG*/ progress->count += 1; if( progress->count == 1 ) { g_timer_start( progress->busy_timer ); g_timer_start( progress->update_timer ); #ifdef DEBUG_MEMUSE printf( "progress_begin:\n" ); im__print_all(); #endif /*DEBUG_MEMUSE*/ } } static void progress_update( Progress *progress ) { /* Don't show the process and cancel button for a bit. */ if( progress->count ) { double elapsed = g_timer_elapsed( progress->busy_timer, NULL ); if( !progress->busy && elapsed > progress_busy_delay ) { #ifdef DEBUG printf( "progress_update: displaying progress bar\n" ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( progress ), progress_signals[SIG_BEGIN], 0 ); progress->busy = TRUE; } } /* Update regularly, even if we're not inside a begin/end * block. */ if( g_timer_elapsed( progress->update_timer, NULL ) > progress_update_interval ) { gboolean cancel; #ifdef DEBUG printf( "progress_update:\n" ); #endif /*DEBUG*/ g_timer_start( progress->update_timer ); /* Overwrite the message if we're cancelling. */ if( progress->cancel ) { vips_buf_rewind( &progress->feedback ); vips_buf_appends( &progress->feedback, _( "Cancelling" ) ); vips_buf_appends( &progress->feedback, " ..." ); } cancel = FALSE; g_signal_emit( progress, progress_signals[SIG_UPDATE], 0, &cancel ); if( cancel ) progress->cancel = TRUE; /* Rather dangerous, but we need this to give nice updates * for the feedback thing. */ process_events(); #ifdef DEBUG_MEMUSE printf( "progress_update:\n" ); im__print_all(); #endif /*DEBUG_MEMUSE*/ } } gboolean progress_update_percent( int percent, int eta ) { Progress *progress = progress_get(); vips_buf_rewind( &progress->feedback ); if( eta > 30 ) { int minutes = (eta + 30) / 60; vips_buf_appendf( &progress->feedback, ngettext( "%d minute left", "%d minutes left", minutes ), minutes ); } else if( eta > 5 ) vips_buf_appendf( &progress->feedback, ngettext( "%d second left", "%d seconds left", eta ), eta ); else /* The empty string changes the height of the progress bar * argh. */ vips_buf_appendf( &progress->feedback, " " ); progress->percent = percent; progress_update( progress ); return( progress->cancel ); } gboolean progress_update_expr( Expr *expr ) { Progress *progress = progress_get(); vips_buf_rewind( &progress->feedback ); vips_buf_appends( &progress->feedback, _( "Calculating" ) ); vips_buf_appends( &progress->feedback, " " ); if( expr ) expr_name( expr, &progress->feedback ); else vips_buf_appends( &progress->feedback, symbol_get_last_calc() ); vips_buf_appends( &progress->feedback, " ..." ); progress->percent = 0; progress_update( progress ); return( progress->cancel ); } gboolean progress_update_loading( int percent, const char *filename ) { Progress *progress = progress_get(); vips_buf_rewind( &progress->feedback ); vips_buf_appends( &progress->feedback, _( "Loading" ) ); vips_buf_appendf( &progress->feedback, " \"%s\"", filename ); progress->percent = percent; progress_update( progress ); return( progress->cancel ); } gboolean progress_update_tick( void ) { Progress *progress = progress_get(); progress_update( progress ); return( progress->cancel ); } void progress_end( void ) { Progress *progress = progress_get(); progress->count -= 1; #ifdef DEBUG printf( "progress_end: %d\n", progress->count ); #endif /*DEBUG*/ g_assert( progress->count >= 0 ); if( !progress->count ) { if( progress->busy ) g_signal_emit( G_OBJECT( progress ), progress_signals[SIG_END], 0 ); progress->cancel = FALSE; progress->busy = FALSE; #ifdef DEBUG_MEMUSE printf( "progress_end:\n" ); im__print_all(); #endif /*DEBUG_MEMUSE*/ } } static void progress_class_init( ProgressClass *class ) { progress_parent_class = g_type_class_peek_parent( class ); progress_signals[SIG_BEGIN] = g_signal_new( "begin", G_OBJECT_CLASS_TYPE( class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ProgressClass, begin ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); progress_signals[SIG_UPDATE] = g_signal_new( "update", G_OBJECT_CLASS_TYPE( class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ProgressClass, update ), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER ); progress_signals[SIG_END] = g_signal_new( "end", G_OBJECT_CLASS_TYPE( class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ProgressClass, end ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); } static void progress_init( Progress *progress ) { #ifdef DEBUG printf( "progress_init\n" ); #endif /*DEBUG*/ progress->count = 0; progress->busy_timer = g_timer_new(); progress->update_timer = g_timer_new(); progress->cancel = FALSE; progress->busy = FALSE; vips_buf_init_static( &progress->feedback, progress->buf, PROGRESS_FEEDBACK_SIZE ); } GType progress_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ProgressClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) progress_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Progress ), 32, /* n_preallocs */ (GInstanceInitFunc) progress_init, }; type = g_type_register_static( TYPE_IOBJECT, "Progress", &info, 0 ); } return( type ); } static Progress * progress_new( void ) { Progress *progress = PROGRESS( g_object_new( TYPE_PROGRESS, NULL ) ); return( progress ); } Progress * progress_get( void ) { static Progress *progress = NULL; if( !progress ) progress = progress_new(); return( progress ); } nip2-8.7.1/src/imageheader.c0000644000175000017500000002157013351443023012511 00000000000000/* display an image header */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static iDialogClass *imageheader_parent_class = NULL; /* Our columns. */ enum { NAME_COLUMN, VALUE_COLUMN, N_COLUMNS }; static void imageheader_destroy( GtkObject *object ) { Imageheader *imageheader; g_return_if_fail( object != NULL ); g_return_if_fail( IS_IMAGEHEADER( object ) ); imageheader = IMAGEHEADER( object ); /* My instance destroy stuff. */ UNREF( imageheader->store ); if( GTK_OBJECT_CLASS( imageheader_parent_class )->destroy ) GTK_OBJECT_CLASS( imageheader_parent_class )->destroy( object ); } static void * imageheader_add_item( IMAGE *im, const char *field, GValue *value, Imageheader *imageheader ) { char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); GtkTreeIter iter; /* Show the nicks for enums. */ if( G_VALUE_HOLDS_ENUM( value ) ) vips_buf_appendf( &buf, "%s", vips_enum_nick( G_VALUE_TYPE( value ), g_value_get_enum( value ) ) ); else { char *value_str; value_str = g_strdup_value_contents( value ); vips_buf_appendf( &buf, "%s", value_str ); g_free( value_str ); } gtk_list_store_append( imageheader->store, &iter ); gtk_list_store_set( imageheader->store, &iter, NAME_COLUMN, field, VALUE_COLUMN, vips_buf_all( &buf ), -1 ); return( NULL ); } static void imageheader_refresh( Imageheader *imageheader ) { gtk_list_store_clear( imageheader->store ); if( imageheader->iimage && imageheader->iimage->value.ii ) { Imageinfo *ii = imageheader->iimage->value.ii; IMAGE *im = imageinfo_get( FALSE, ii ); im_header_map( im, (im_header_map_fn) imageheader_add_item, imageheader ); gtk_text_buffer_set_text( gtk_text_view_get_buffer( GTK_TEXT_VIEW( imageheader->history ) ), im_history_get( im ), -1 ); } else { gtk_editable_delete_text( GTK_EDITABLE( imageheader->history ), 0, -1 ); } } static void imageheader_entry_changed_cb( GtkEditable *editable, Imageheader *imageheader ) { gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER( imageheader->filter ) ); } static gboolean imageheader_visible_func( GtkTreeModel *model, GtkTreeIter *iter, gpointer data ) { Imageheader *imageheader = IMAGEHEADER( data ); const char *text = gtk_entry_get_text( GTK_ENTRY( imageheader->entry ) ); char *name; char *value; gboolean found; found = FALSE; gtk_tree_model_get( model, iter, NAME_COLUMN, &name, -1 ); if( name ) { found = my_strcasestr( name, text ) != NULL; g_free( name ); } if( found ) return( TRUE ); gtk_tree_model_get( model, iter, VALUE_COLUMN, &value, -1 ); if( value ) { found = my_strcasestr( value, text ) != NULL; g_free( value ); } return( found ); } static void imageheader_build( GtkWidget *widget ) { Imageheader *imageheader = IMAGEHEADER( widget ); iDialog *idlg = IDIALOG( widget ); GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkWidget *top; GtkWidget *label; GtkWidget *swin; GtkWidget *pane; GtkWidget *vbox; PangoFontDescription *font_desc; #ifdef DEBUG printf( "imageheader_build: %s\n", IWINDOW( imageheader )->title ); #endif /*DEBUG*/ /* Call all builds in superclasses. */ if( IWINDOW_CLASS( imageheader_parent_class )->build ) (*IWINDOW_CLASS( imageheader_parent_class )->build)( widget ); pane = gtk_vpaned_new(); gtk_box_pack_start( GTK_BOX( idlg->work ), pane, TRUE, TRUE, 2 ); vbox = gtk_vbox_new( FALSE, 2 ); gtk_paned_pack1( GTK_PANED( pane ), vbox, TRUE, FALSE ); top = gtk_hbox_new( FALSE, 12 ); gtk_box_pack_start( GTK_BOX( vbox ), top, FALSE, FALSE, 2 ); imageheader->entry = gtk_entry_new(); gtk_signal_connect( GTK_OBJECT( imageheader->entry ), "changed", GTK_SIGNAL_FUNC( imageheader_entry_changed_cb ), imageheader ); gtk_box_pack_end( GTK_BOX( top ), imageheader->entry, FALSE, FALSE, 2 ); label = gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_MENU ); gtk_box_pack_end( GTK_BOX( top ), label, FALSE, FALSE, 0 ); swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_box_pack_start( GTK_BOX( vbox ), swin, TRUE, TRUE, 2 ); imageheader->store = gtk_list_store_new( N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING ); imageheader->filter = gtk_tree_model_filter_new( GTK_TREE_MODEL( imageheader->store ), NULL ); gtk_tree_model_filter_set_visible_func( GTK_TREE_MODEL_FILTER( imageheader->filter ), imageheader_visible_func, imageheader, NULL ); imageheader->tree = gtk_tree_view_new_with_model( GTK_TREE_MODEL( imageheader->filter ) ); gtk_tree_view_set_rules_hint( GTK_TREE_VIEW( imageheader->tree ), TRUE ); gtk_container_add( GTK_CONTAINER( swin ), imageheader->tree ); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( _( "Field" ), renderer, "text", NAME_COLUMN, NULL ); gtk_tree_view_column_set_resizable( column, TRUE ); gtk_tree_view_append_column( GTK_TREE_VIEW( imageheader->tree ), column ); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes( _( "Value" ), renderer, "text", VALUE_COLUMN, NULL ); gtk_tree_view_column_set_resizable( column, TRUE ); gtk_tree_view_append_column( GTK_TREE_VIEW( imageheader->tree ), column ); vbox = gtk_vbox_new( FALSE, 2 ); gtk_paned_pack2( GTK_PANED( pane ), vbox, TRUE, FALSE ); label = gtk_label_new( _( "Image history" ) ); gtk_misc_set_alignment( GTK_MISC( label ), 0.0, 0.5 ); gtk_box_pack_start( GTK_BOX( vbox ), label, FALSE, FALSE, 2 ); swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_box_pack_end( GTK_BOX( vbox ), swin, TRUE, TRUE, 2 ); imageheader->history = gtk_text_view_new(); gtk_text_view_set_editable( GTK_TEXT_VIEW( imageheader->history ), FALSE ); gtk_text_view_set_cursor_visible( GTK_TEXT_VIEW( imageheader->history ), FALSE ); font_desc = pango_font_description_from_string( "Monospace" ); gtk_widget_modify_font( imageheader->history, font_desc ); pango_font_description_free( font_desc ); gtk_container_add( GTK_CONTAINER( swin ), imageheader->history ); imageheader_refresh( imageheader ); gtk_window_set_default_size( GTK_WINDOW( imageheader ), 550, 550 ); gtk_paned_set_position( GTK_PANED( pane ), 350 ); gtk_widget_show_all( idlg->work ); } static void imageheader_class_init( ImageheaderClass *class ) { GtkObjectClass *object_class; iWindowClass *iwindow_class; object_class = (GtkObjectClass *) class; iwindow_class = (iWindowClass *) class; object_class->destroy = imageheader_destroy; iwindow_class->build = imageheader_build; imageheader_parent_class = g_type_class_peek_parent( class ); } static void imageheader_init( Imageheader *imageheader ) { #ifdef DEBUG printf( "imageheader_init: %s\n", IWINDOW( imageheader )->title ); #endif /*DEBUG*/ imageheader->iimage = NULL; } GtkType imageheader_get_type( void ) { static GtkType imageheader_type = 0; if( !imageheader_type ) { static const GtkTypeInfo info = { "Imageheader", sizeof( Imageheader ), sizeof( ImageheaderClass ), (GtkClassInitFunc) imageheader_class_init, (GtkObjectInitFunc) imageheader_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; imageheader_type = gtk_type_unique( TYPE_IDIALOG, &info ); } return( imageheader_type ); } /* Conversion has changed signal. */ static void imageheader_ii_changed( Model *model, Imageheader *imageheader ) { g_assert( IS_MODEL( model ) ); g_assert( IS_IMAGEHEADER( imageheader ) ); imageheader_refresh( imageheader ); } static void imageheader_link( Imageheader *imageheader, iImage *iimage ) { imageheader->iimage = iimage; listen_add( G_OBJECT( imageheader ), (GObject **) &imageheader->iimage, "changed", G_CALLBACK( imageheader_ii_changed ) ); } GtkWidget * imageheader_new( iImage *iimage ) { Imageheader *imageheader = gtk_type_new( TYPE_IMAGEHEADER ); imageheader_link( imageheader, iimage ); return( GTK_WIDGET( imageheader ) ); } nip2-8.7.1/src/clock.c0000644000175000017500000001573113351443023011353 00000000000000/* a clock ... triggers a recomp every whenever */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ValueClass *parent_class = NULL; static void clock_dispose( GObject *gobject ) { Clock *clock = CLOCK( gobject ); #ifdef DEBUG printf( "clock_dispose\n" ); #endif /*DEBUG*/ IM_FREEF( g_source_remove, clock->recalc_timeout ); IM_FREEF( g_timer_destroy, clock->elapsed_timer ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void clock_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Clock *clock = CLOCK( client ); Stringset *ss = STRINGSET( iwnd ); StringsetChild *interval = stringset_child_get( ss, _( "Interval" ) ); StringsetChild *value = stringset_child_get( ss, _( "Elapsed time" ) ); if( !get_geditable_double( interval->entry, &clock->interval ) || !get_geditable_double( value->entry, &clock->value ) ) { nfn( sys, IWINDOW_ERROR ); return; } if( clock->interval < 0.1 ) clock->interval = 0.1; if( clock->value < 0.0 ) clock->value = 0.0; /* Magic: ask for the clock timer to be reset. */ clock->time_offset = -1; classmodel_update( CLASSMODEL( clock ) ); symbol_recalculate_all(); nfn( sys, IWINDOW_YES ); } static void clock_edit( GtkWidget *parent, Model *model ) { Clock *clock = CLOCK( model ); GtkWidget *ss = stringset_new(); char txt[256]; im_snprintf( txt, 256, "%g", clock->interval ); stringset_child_new( STRINGSET( ss ), _( "Interval" ), txt, _( "Interval between ticks (seconds)" ) ); im_snprintf( txt, 256, "%g", clock->value ); stringset_child_new( STRINGSET( ss ), _( "Elapsed time" ), txt, _( "Elapsed time (seconds)" ) ); /* Expands to eg. "Edit Toggle A1". */ iwindow_set_title( IWINDOW( ss ), _( "Edit %s %s" ), IOBJECT_GET_CLASS_NAME( model ), IOBJECT( HEAPMODEL( model )->row )->name ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, clock ); idialog_add_ok( IDIALOG( ss ), clock_done_cb, _( "Set %s" ), IOBJECT_GET_CLASS_NAME( model ) ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( parent ) ); idialog_set_iobject( IDIALOG( ss ), IOBJECT( model ) ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); } static gboolean clock_timeout_cb( Clock *clock ) { #ifdef DEBUG printf( "clock_timeout_cb: " ); row_name_print( HEAPMODEL( clock )->row ); printf( " interval=%g, value=%g\n", clock->interval, clock->value ); #endif /*DEBUG*/ /* Test autocalc ... if it's off, make sure we don't update the * interface. */ if( mainw_auto_recalc ) { clock->value = g_timer_elapsed( clock->elapsed_timer, NULL ) + clock->time_offset; classmodel_update( CLASSMODEL( clock ) ); symbol_recalculate_all(); } return( TRUE ); } static void * clock_update_model( Heapmodel *heapmodel ) { Clock *clock = CLOCK( heapmodel ); #ifdef DEBUG printf( "clock_update_model: " ); row_name_print( HEAPMODEL( clock )->row ); printf( " interval=%g, value=%g\n", clock->interval, clock->value ); #endif /*DEBUG*/ if( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) ) return( heapmodel ); /* Milliseconds for the update timeout ... don't let it go under 100, * there's a danger the interface will lock up. */ int ms = IM_MAX( 100, clock->interval * 1000 ); IM_FREEF( g_source_remove, clock->recalc_timeout ); clock->recalc_timeout = g_timeout_add( ms, (GSourceFunc) clock_timeout_cb, clock ); /* Should we reset the timer from the value? */ if( clock->time_offset == -1 ) { g_timer_start( clock->elapsed_timer ); clock->time_offset = clock->value; } return( NULL ); } /* Override value_generate_caption(): pick from the model. */ static const char * clock_generate_caption( iObject *iobject ) { Value *value = VALUE( iobject ); ValueClass *value_class = VALUE_GET_CLASS( value ); Clock *clock = CLOCK( iobject ); VipsBuf *buf = &value->caption_buffer; vips_buf_rewind( buf ); if( !heapmodel_name( HEAPMODEL( value ), buf ) ) vips_buf_appends( buf, G_OBJECT_CLASS_NAME( value_class ) ); vips_buf_appendf( buf, " %g %g", clock->interval, clock->value ); return( vips_buf_all( buf ) ); } /* Members of clock we automate. */ static ClassmodelMember clock_members[] = { { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, MEMBER_INTERVAL, "interval", N_( "Interval" ), G_STRUCT_OFFSET( Clock, interval ) }, { CLASSMODEL_MEMBER_DOUBLE, NULL, 0, MEMBER_VALUE, "value", N_( "Value" ), G_STRUCT_OFFSET( Clock, value ) } }; static void clock_class_init( ClockClass *class ) { GObjectClass *gobject_class = (GObjectClass *) class; iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; HeapmodelClass *heapmodel_class = (HeapmodelClass *) class; ClassmodelClass *classmodel_class = (ClassmodelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ gobject_class->dispose = clock_dispose; iobject_class->user_name = _( "Clock" ); iobject_class->generate_caption = clock_generate_caption; model_class->edit = clock_edit; heapmodel_class->update_model = clock_update_model; /* Static init. */ model_register_loadable( MODEL_CLASS( class ) ); classmodel_class->members = clock_members; classmodel_class->n_members = IM_NUMBER( clock_members ); } static void clock_init( Clock *clock ) { #ifdef DEBUG printf( "clock_init\n" ); #endif /*DEBUG*/ /* Overridden later. Just something sensible. */ clock->interval = 1; clock->value = 0; /* time_offset: set to -1 means we should set the offset from value on * the next rebuild. */ clock->elapsed_timer = g_timer_new(); clock->time_offset = -1; clock->recalc_timeout = 0; iobject_set( IOBJECT( clock ), CLASS_CLOCK, NULL ); } GType clock_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ClockClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) clock_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Clock ), 32, /* n_preallocs */ (GInstanceInitFunc) clock_init, }; type = g_type_register_static( TYPE_VALUE, "Clock", &info, 0 ); } return( type ); } nip2-8.7.1/src/toggleview.c0000644000175000017500000000571713351443023012437 00000000000000/* the display part of a toggle button */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static GraphicviewClass *parent_class = NULL; /* Toggleview callback. */ static void toggleview_change_cb( GtkWidget *widget, Toggleview *togview ) { Toggle *tog = TOGGLE( VOBJECT( togview )->iobject ); Classmodel *classmodel = CLASSMODEL( tog ); if( tog->value != GTK_TOGGLE_BUTTON( widget )->active ) { tog->value = GTK_TOGGLE_BUTTON( widget )->active; classmodel_update( classmodel ); symbol_recalculate_all(); } } static void toggleview_refresh( vObject *vobject ) { Toggleview *togview = TOGGLEVIEW( vobject ); Toggle *tog = TOGGLE( VOBJECT( togview )->iobject ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( togview->toggle ), tog->value ); set_glabel( GTK_BIN( togview->toggle )->child, "%s", IOBJECT( tog )->caption ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void toggleview_class_init( ToggleviewClass *class ) { vObjectClass *vobject_class = (vObjectClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = toggleview_refresh; } static void toggleview_init( Toggleview *togview ) { togview->toggle = build_gtoggle( GTK_WIDGET( togview ), "" ); set_tooltip( togview->toggle, _( "Left-click to change value" ) ); gtk_signal_connect( GTK_OBJECT( togview->toggle ), "clicked", GTK_SIGNAL_FUNC( toggleview_change_cb ), togview ); gtk_widget_show_all( GTK_WIDGET( togview ) ); } GtkType toggleview_get_type( void ) { static GtkType toggleview_type = 0; if( !toggleview_type ) { static const GtkTypeInfo info = { "Toggleview", sizeof( Toggleview ), sizeof( ToggleviewClass ), (GtkClassInitFunc) toggleview_class_init, (GtkObjectInitFunc) toggleview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; toggleview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( toggleview_type ); } View * toggleview_new( void ) { Toggleview *togview = gtk_type_new( TYPE_TOGGLEVIEW ); return( VIEW( togview ) ); } nip2-8.7.1/src/imageheader.h0000644000175000017500000000340713351443023012515 00000000000000/* display an image header */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IMAGEHEADER (imageheader_get_type()) #define IMAGEHEADER( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_IMAGEHEADER, Imageheader )) #define IMAGEHEADER_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_IMAGEHEADER, ImageheaderClass )) #define IS_IMAGEHEADER( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IMAGEHEADER )) #define IS_IMAGEHEADER_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEHEADER )) typedef struct _Imageheader { iDialog parent; iImage *iimage; GtkListStore *store; /* Model for list view */ GtkTreeModel *filter; /* After filtering with search box */ GtkWidget *tree; /* Displayed tree */ GtkWidget *entry; /* Search widget */ GtkWidget *history; } Imageheader; typedef struct _ImageheaderClass { iDialogClass parent_class; /* My methods. */ } ImageheaderClass; GtkType imageheader_get_type( void ); GtkWidget *imageheader_new( iImage *iimage ); nip2-8.7.1/src/Makefile.am0000644000175000017500000001223213351443023012141 00000000000000SUBDIRS = BITMAPS # need this to keep autoconf quiet, but we don't actually use it ... see the # bison rule below YACC = bison # windows resource files ... see .rc.o rule later SUFFIXES = .rc # only build the cli wrapper on win32 if OS_WIN32 bin_PROGRAMS = nip2 nip2-cli nip2_cli_SOURCES = nip2-cli.c nip2_CFLAGS="-mwindows" CLI_DIST = else bin_PROGRAMS = nip2 CLI_DIST = nip2-cli.c endif nip2_SOURCES = \ vipsobject.c \ vipsobject.h \ plotmodel.c \ plotmodel.h \ progress.c \ progress.h \ panechild.c \ panechild.h \ plotpresent.c \ plotpresent.h \ plotstatus.c \ plotstatus.h \ floatwindow.c \ floatwindow.h \ vobject.c \ vobject.h \ action.c \ action.h \ boxes.c \ boxes.h \ popupbutton.c \ popupbutton.h \ imageheader.c \ imageheader.h \ preview.c \ preview.h \ builtin.c \ builtin.h \ icontainer.c \ icontainer.h \ iobject.c \ iobject.h \ class.c \ class.h \ classmodel.c \ classmodel.h \ colour.c \ colour.h \ colourdisplay.c \ colourdisplay.h \ colourview.c \ colourview.h \ column.c \ column.h \ columnview.c \ columnview.h \ compile.c \ compile.h \ conversion.c \ conversion.h \ conversionview.c \ conversionview.h \ doubleclick.c \ doubleclick.h \ dump.c \ dump.h \ expr.c \ expr.h \ filemodel.c \ filemodel.h \ pane.c \ pane.h \ pathname.c \ pathname.h \ fontname.c \ fontname.h \ group.c \ group.h \ pathnameview.c \ pathnameview.h \ fontnameview.c \ fontnameview.h \ filesel.c \ filesel.h \ graphwindow.c \ graphwindow.h \ graphicview.c \ graphicview.h \ gtkutil.c \ gtkutil.h \ heap.c \ heap.h \ heapmodel.c \ heapmodel.h \ helpindex.h \ nipmarshal.h \ nipmarshal.c \ iarrow.c \ iarrow.h \ value.c \ value.h \ valueview.c \ valueview.h \ idialog.c \ idialog.h \ iimage.c \ iimage.h \ iimageview.c \ iimageview.h \ imagedisplay.c \ imagedisplay.h \ log.c \ log.h \ error.c \ error.h \ managed.c \ managed.h \ managedfile.c \ managedfile.h \ managedgvalue.c \ managedgvalue.h \ managedgobject.c \ managedgobject.h \ managedstring.c \ managedstring.h \ imageinfo.c \ imageinfo.h \ imagemodel.c \ imagemodel.h \ imagepresent.c \ imagepresent.h \ imageview.c \ imageview.h \ ip.h \ iregion.c \ iregion.h \ iregiongroup.c \ iregiongroup.h \ iregiongroupview.c \ iregiongroupview.h \ iregionview.c \ iregionview.h \ itext.c \ itext.h \ itextview.c \ itextview.h \ iwindow.c \ iwindow.h \ parse.y \ parser.h \ prefs.c \ prefs.h \ prefworkspaceview.c \ prefworkspaceview.h \ prefcolumnview.c \ prefcolumnview.h \ lex.l \ link.c \ link.h \ main.c \ main.h \ mainw.c \ mainw.h \ matrix.c \ matrix.h \ matrixview.c \ matrixview.h \ plot.c \ plot.h \ plotview.c \ plotview.h \ plotwindow.c \ plotwindow.h \ model.c \ model.h \ option.c \ option.h \ optionview.c \ optionview.h \ formula.c \ formula.h \ paintboxview.c \ paintboxview.h \ path.c \ path.h \ predicate.c \ predicate.h \ program.c \ program.h \ string.c \ istring.h \ number.c \ number.h \ expression.c \ expression.h \ expressionview.c \ expressionview.h \ stringview.c \ stringview.h \ editview.c \ editview.h \ numberview.c \ numberview.h \ real.c \ real.h \ vector.c \ vector.h \ reduce.c \ reduce.h \ regionview.c \ regionview.h \ rhs.c \ rhs.h \ rhsview.c \ rhsview.h \ row.c \ row.h \ rowview.c \ rowview.h \ secret.c \ secret.h \ slider.c \ slider.h \ sliderview.c \ sliderview.h \ clock.c \ clock.h \ spin.c \ spin.h \ statusview.c \ statusview.h \ subcolumn.c \ subcolumn.h \ subcolumnview.c \ subcolumnview.h \ symbol.c \ symbol.h \ toggle.c \ toggle.h \ toggleview.c \ toggleview.h \ tool.c \ tool.h \ toolkit.c \ toolkit.h \ toolkitgroup.c \ toolkitgroup.h \ toolkitgroupview.c \ toolkitgroupview.h \ toolkitview.c \ toolkitview.h \ defbrowser.c \ defbrowser.h \ toolkitbrowser.c \ toolkitbrowser.h \ toolview.c \ toolview.h \ trace.c \ trace.h \ tree.c \ tree.h \ tslider.c \ tslider.h \ util.c \ util.h \ view.c \ view.h \ call.c \ call.h \ cache.c \ cache.h \ watch.c \ watch.h \ workspace.c \ workspace.h \ workspacegroup.c \ workspacegroup.h \ workspacegroupview.c \ workspacegroupview.h \ workspacedefs.c \ workspacedefs.h \ workspaceroot.c \ workspaceroot.h \ workspaceview.c \ workspaceview.h if OS_WIN32 nip2_SOURCES += \ nip2-icon.rc endif helpindex.h: ./makehelpindex.pl $(prefix) > helpindex.h nipmarshal.h: glib-genmarshal --prefix=nip --header nipmarshal.list > nipmarshal.h nipmarshal.c: echo "#include \"nipmarshal.h\"" > nipmarshal.c glib-genmarshal --prefix=nip --body nipmarshal.list >> nipmarshal.c .rc.o: cp ${top_srcdir}/share/nip2/data/nip2-icon.ico . ${WINDRES} $< -o $@ # we have to replace the standard .y.c rule: we are a bison-only GLR parser, # so we can't use autoconf's preferred -y yacc-compatibility stuff .y.c: $(BISON) --defines=$*.h -o $*.c $< nip2-model.o model.o: model.c parse.c AM_CPPFLAGS = @IP_CFLAGS@ LDADD = @IP_CFLAGS@ @IP_LIBS@ AM_LDFLAGS = @LDFLAGS@ dist-hook: ${RM} ${distdir}/parse.c ${distdir}/lex.c CLEANFILES = parse.c parse.h lex.c tags EXTRA_DIST = makehelpindex.pl helpindex.h \ nipmarshal.h nipmarshal.c nipmarshal.list \ $(CLI_DIST) nip2-8.7.1/src/managedgvalue.c0000644000175000017500000000644613351443023013063 00000000000000/* a managedgvalue gvalue */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ static ManagedClass *parent_class = NULL; static void managedgvalue_dispose( GObject *gobject ) { Managedgvalue *managedgvalue = MANAGEDGVALUE( gobject ); #ifdef DEBUG printf( "managedgvalue_dispose: " ); iobject_print( IOBJECT( managedgvalue ) ); #endif /*DEBUG*/ g_value_unset( &managedgvalue->value ); G_OBJECT_CLASS( parent_class )->dispose( gobject ); } static void managedgvalue_info( iObject *iobject, VipsBuf *buf ) { Managedgvalue *managedgvalue = MANAGEDGVALUE( iobject ); char *value_str; value_str = g_strdup_value_contents( &managedgvalue->value ); vips_buf_appendf( buf, "managedgvalue->value = %s\n", value_str ); g_free( value_str ); IOBJECT_CLASS( parent_class )->info( iobject, buf ); } static void managedgvalue_class_init( ManagedgvalueClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); iObjectClass *iobject_class = IOBJECT_CLASS( class ); parent_class = g_type_class_peek_parent( class ); gobject_class->dispose = managedgvalue_dispose; iobject_class->info = managedgvalue_info; } static void managedgvalue_init( Managedgvalue *managedgvalue ) { #ifdef DEBUG printf( "managedgvalue_init: %p\n", managedgvalue ); #endif /*DEBUG*/ memset( &managedgvalue->value, 0, sizeof( GValue ) ); } GType managedgvalue_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ManagedgvalueClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) managedgvalue_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Managedgvalue ), 32, /* n_preallocs */ (GInstanceInitFunc) managedgvalue_init, }; type = g_type_register_static( TYPE_MANAGED, "Managedgvalue", &info, 0 ); } return( type ); } void managedgvalue_set_value( Managedgvalue *managedgvalue, GValue *value ) { g_value_unset( &managedgvalue->value ); g_value_init( &managedgvalue->value, G_VALUE_TYPE( value ) ); g_value_copy( &managedgvalue->value, value ); } Managedgvalue * managedgvalue_new( Heap *heap, GValue *value ) { Managedgvalue *managedgvalue = g_object_new( TYPE_MANAGEDGVALUE, NULL ); managed_link_heap( MANAGED( managedgvalue ), heap ); managedgvalue_set_value( managedgvalue, value ); /* Not a very good hash. */ MANAGED( managedgvalue )->hash = (guint) G_VALUE_TYPE( value ); return( managedgvalue ); } nip2-8.7.1/src/graphicview.h0000644000175000017500000000321613351443023012570 00000000000000/* abstract base class for graphic views, ie. things we can display as part of * the graphic component of a rhsview */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_GRAPHICVIEW (graphicview_get_type()) #define GRAPHICVIEW( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_GRAPHICVIEW, Graphicview )) #define GRAPHICVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_GRAPHICVIEW, GraphicviewClass )) #define IS_GRAPHICVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_GRAPHICVIEW )) #define IS_GRAPHICVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_GRAPHICVIEW )) typedef struct _Graphicview { View view; /* My instance vars. */ Subcolumnview *sview; /* Enclosing subc. */ } Graphicview; typedef struct _GraphicviewClass { ViewClass parent_class; /* My methods. */ } GraphicviewClass; GtkType graphicview_get_type( void ); nip2-8.7.1/src/trace.h0000644000175000017500000000452613351443023011363 00000000000000/* Decls for trace.c ... a trace window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_TRACE (trace_get_type()) #define TRACE( obj ) (GTK_CHECK_CAST( (obj), TYPE_TRACE, Trace )) #define TRACE_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_TRACE, TraceClass )) #define IS_TRACE( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TRACE )) #define IS_TRACE_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_TRACE )) /* The various things we can trace. */ typedef enum { TRACE_BUILTIN = 1, /* Calls to built in functions */ TRACE_OPERATOR = 2, /* +, -, etc. */ TRACE_CLASS_NEW = 4, /* Class construction */ TRACE_VIPS = 8 /* VIPS operations */ } TraceFlags; struct _Trace { Log parent_class; TraceFlags flags; }; typedef struct _TraceClass { LogClass parent_class; /* My methods. */ } TraceClass; extern TraceFlags trace_flags; void trace_block( void ); void trace_unblock( void ); void trace_reset( void ); void trace_check( void ); VipsBuf *trace_push( void ); void trace_pop( void ); VipsBuf *trace_current( void ); void trace_pop_to( int n ); int trace_get_mark( void ); GtkType trace_get_type( void ); Trace *trace_new( void ); void trace_text( TraceFlags flags, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); void trace_pelement( PElement *pe ); void trace_node( HeapNode *node ); void trace_args( HeapNode **arg, int n ); void trace_binop( Compile *compile, PElement *left, BinOp bop, PElement *right ); void trace_uop( UnOp uop, PElement *arg ); void trace_result( TraceFlags flags, PElement *out ); nip2-8.7.1/src/tool.h0000644000175000017500000000760513351443023011243 00000000000000/* Tools ... mostly a menu item. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Build a tree of these for each tool we make. */ struct _Toolitem { /* The thing for which we are making an item. Eg. if the .def file * has 'fred = class Menuitem "poop" "lots of poop" {}', this is the * Compile for fred. * * compile is not always valid .. eg. for #dialog or #separator */ Compile *compile; /* The top-level tool we come from. */ Tool *tool; /* The symbol we perform the action with (eg. get nparam from this). */ Symbol *action_sym; /* Set for a separator. */ gboolean is_separator; /* Set if we decide during build that this item should be a pullright. */ gboolean is_pullright; /* If this is a pullright, the children of this item. If we are a * child, the parent. */ GSList *children; Toolitem *parent; /* Set if we decide this should have an action. */ gboolean is_action; char *label; /* eg. "W_hite Balance" */ char *name; /* eg. "White Balance" */ char *icon; /* eg. "$VIPSHOME/icons/wb.png" */ char *tooltip; /* eg. "move whitepoint to region neutral" */ char *help; /* eg. "White Balance r: move ..." */ char *action; /* eg. "White_balance_widget._action" */ char *path; /* eg. "/Toolkits/Image" */ char *user_path; /* eg. "Image / White Balance" */ }; #define TYPE_TOOL (tool_get_type()) #define TOOL( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_TOOL, Tool )) #define TOOL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_TOOL, ToolClass)) #define IS_TOOL( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_TOOL )) #define IS_TOOL_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_TOOL )) #define TOOL_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_TOOL, ToolClass )) /* Tool types: a def (sym points to symbol for this def), a dialog (keep * filename and prompt name), or a separator. */ typedef enum { TOOL_SYM, TOOL_DIA, TOOL_SEP } Tooltype; /* What we hold for each tool. */ struct _Tool { Filemodel parent_class; Tooltype type; Symbol *sym; /* For SYM tools: symbol this tool represents */ guint new_value_sid; /* Watch for new_value with this */ Symbol *link_sym; /* the sym we are watching (in case ->sym is NULLed before we try to disconnect */ Toolkit *kit; /* Link back to toolkit */ int lineno; /* -1 for not known, or lineno in kit */ Toolitem *toolitem; /* Items made by this tool */ /* The first line of the comment prior to the definition. Toolitem help * and tooltip can be generated from the Menuitem members. */ char *help; /* eg. "concat l: join a list of .." */ }; typedef struct _ToolClass { FilemodelClass parent_class; /* My methods. */ } ToolClass; void tool_error( Tool *tool, VipsBuf *buf ); void *tool_linkreport_tool( Tool *tool, VipsBuf *buf, gboolean *found ); GType tool_get_type( void ); Tool *tool_new_sym( Toolkit *kit, int pos, Symbol *sym ); Tool *tool_new_sep( Toolkit *kit, int pos ); Tool *tool_new_dia( Toolkit *kit, int pos, const char *filename, const char *name ); Toolitem *toolitem_lookup( Toolkitgroup *kitg, Symbol *action ); nip2-8.7.1/src/numberview.h0000644000175000017500000000277413351443023012453 00000000000000/* edit a number */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_NUMBERVIEW (numberview_get_type()) #define NUMBERVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_NUMBERVIEW, Numberview )) #define NUMBERVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_NUMBERVIEW, NumberviewClass )) #define IS_NUMBERVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_NUMBERVIEW )) #define IS_NUMBERVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_NUMBERVIEW )) typedef struct _Numberview { Editview parent_object; } Numberview; typedef struct _NumberviewClass { EditviewClass parent_class; /* My methods. */ } NumberviewClass; GtkType numberview_get_type( void ); View *numberview_new( void ); nip2-8.7.1/src/conversion.h0000644000175000017500000001002413351443023012440 00000000000000/* Manage display conversion parameters. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_CONVERSION (conversion_get_type()) #define CONVERSION( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_CONVERSION, Conversion )) #define CONVERSION_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_CONVERSION, ConversionClass)) #define IS_CONVERSION( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_CONVERSION )) #define IS_CONVERSION_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_CONVERSION )) #define CONVERSION_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_CONVERSION, ConversionClass )) struct _Conversion { Model parent_class; /* Image. */ Imageinfo *ii; /* Underlying image */ guint changed_sid; /* Watch ii with these two */ guint area_changed_sid; REGION *reg; /* Region for input from underlying image */ gboolean synchronous; /* TRUE to disable BG stuff */ int priority; /* render priority */ Imageinfo *visual_ii; /* Visualisation image ... eg. histplot */ Imageinfo *display_ii; /* Sized and cached */ int display_mag; /* What mag the display_ii is built for */ IMAGE *mask; /* Read display mask from here */ Imageinfo *repaint_ii; /* Colour converted for screen */ REGION *ireg; /* Region for input from repaint image */ REGION *mreg; /* Region for input from repaint mask */ int tile_size; /* Set smaller for thumbnails */ /* Basic geometry. */ Rect underlay; /* Size of underlying image (at 0,0) */ Rect image; /* Size of visualisation image (at 0,0) */ Rect canvas; /* Size of image we display (always at 0,0) */ Rect visible; /* hint ... visible region of display image */ int mag; /* -ve for shrink, +ve for expand */ /* Visualisation controls. If enabled is set, we built the pipeline * using these params. */ gboolean enabled; gboolean changed; /* Trigger a rebuild with these */ double scale; /* Contrast/brightness */ double offset; gboolean falsecolour; /* False colour display on */ gboolean type; /* Interpret type field */ }; typedef struct _ConversionClass { ModelClass parent_class; /* My methods. area_changed we forward the "area" changed signal off the ii we are holding ... in repaint coordinates */ void (*area_changed)( Conversion *, Rect * ); /* The imageinfo has been swapped for a new one. */ void (*imageinfo_changed)( Conversion * ); } ConversionClass; GType conversion_get_type( void ); Conversion *conversion_new( Imageinfo *ii ); void conversion_set_image( Conversion *conv, Imageinfo *ii ); gboolean conversion_refresh_text( Conversion *conv ); double conversion_dmag( int mag ); int conversion_double( int mag ); int conversion_halve( int mag ); void conversion_disp_to_im( Conversion *conv, int dx, int dy, int *ix, int *iy ); void conversion_im_to_disp( Conversion *conv, int ix, int iy, int *dx, int *dy ); void conversion_disp_to_im_rect( Conversion *conv, Rect *dr, Rect *ir ); void conversion_im_to_disp_rect( Conversion *conv, Rect *ir, Rect *dr ); void conversion_set_mag( Conversion *conv, int mag ); void conversion_set_synchronous( Conversion *conv, gboolean synchronous ); void conversion_set_params( Conversion *conv, gboolean enabled, double scale, double offset, gboolean falsecolour, gboolean type ); nip2-8.7.1/src/formula.c0000644000175000017500000003466213351443023011731 00000000000000/* display a caption/value label pair, on a click display the formula in an * entry widget */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" /* Our signals. */ enum { EDIT, CHANGED, ACTIVATE, ENTER, LEAVE, LAST_SIGNAL }; static GtkEventBoxClass *parent_class = NULL; static guint formula_signals[LAST_SIGNAL] = { 0 }; /* Formula needing a refresh. */ static GSList *formula_refresh_all = NULL; /* The idle we add if there are any formula needing a refresh. */ static gint formula_refresh_idle = 0; /* Unqueue a refresh. */ static void formula_refresh_unqueue( Formula *formula ) { if( formula->refresh_queued ) { formula_refresh_all = g_slist_remove( formula_refresh_all, formula ); formula->refresh_queued = FALSE; if( !formula_refresh_all ) IM_FREEF( g_source_remove, formula_refresh_idle ); } } /* Detect cancel in a text field. */ static gboolean formula_key_press_event_cb( GtkWidget *widget, GdkEventKey *ev, Formula *formula ) { gboolean handled; handled = FALSE; if( ev->keyval == GDK_Escape ) { set_gentry( formula->entry, "%s", formula->expr ); /* FIXME ... really we want to go back to the edit mode set by our environment (eg. if we're in a show_formula workspace, should stay in show formula). */ formula_set_edit( formula, FALSE ); handled = TRUE; } return( handled ); } /* Activated! */ static void formula_activate( Formula *formula ) { g_signal_emit( G_OBJECT( formula ), formula_signals[ACTIVATE], 0 ); } static void formula_activate_cb( GtkWidget *wid, Formula *formula ) { formula_activate( formula ); } /* A char has changed in the entry (we will need scanning on activate). */ static void formula_changed( Formula *formula ) { g_signal_emit( G_OBJECT( formula ), formula_signals[CHANGED], 0 ); } /* Add an edit box. */ static void formula_add_edit( Formula *formula ) { if( formula->entry_frame ) return; /* We need to use an alignment since if the left label is hidden we'll * have nothing to hold us to the right height. */ formula->entry_frame = gtk_alignment_new( 0.5, 0.5, 1, 1 ); gtk_alignment_set_padding( GTK_ALIGNMENT( formula->entry_frame ), 3, 3, 2, 2 ); gtk_box_pack_start( GTK_BOX( formula->hbox ), formula->entry_frame, TRUE, TRUE, 0 ); formula->entry = gtk_entry_new(); set_tooltip( formula->entry, _( "Press Escape to cancel edit, " "press Return to accept edit and recalculate" ) ); gtk_signal_connect( GTK_OBJECT( formula->entry ), "key_press_event", GTK_SIGNAL_FUNC( formula_key_press_event_cb ), GTK_OBJECT( formula ) ); gtk_signal_connect_object( GTK_OBJECT( formula->entry ), "changed", GTK_SIGNAL_FUNC( formula_changed ), GTK_OBJECT( formula ) ); gtk_signal_connect( GTK_OBJECT( formula->entry ), "activate", GTK_SIGNAL_FUNC( formula_activate_cb ), formula ); gtk_container_add( GTK_CONTAINER( formula->entry_frame ), formula->entry ); gtk_widget_show( formula->entry ); /* Tell everyone we are in edit mode ... used to add to resettable, * for example. */ g_signal_emit( G_OBJECT( formula ), formula_signals[EDIT], 0 ); } static void formula_refresh( Formula *formula ) { #ifdef DEBUG printf( "formula_refresh\n" ); #endif /*DEBUG*/ /* Set edit mode. */ if( formula->edit ) { formula_add_edit( formula ); gtk_widget_show( formula->entry_frame ); gtk_widget_hide( formula->right_label ); formula->changed = FALSE; } else { gtk_widget_show( formula->right_label ); IM_FREEF( gtk_widget_destroy, formula->entry ); IM_FREEF( gtk_widget_destroy, formula->entry_frame ); } /* Don't update the formula display if the user has edited the text ... * we shouldn't destroy their work. */ if( formula->entry && formula->expr && !formula->changed ) { /* Make sure we don't trigger "changed" when we zap in new * text. */ gtk_signal_handler_block_by_data( GTK_OBJECT( formula->entry ), formula ); set_gentry( formula->entry, "%s", formula->expr ); gtk_signal_handler_unblock_by_data( GTK_OBJECT( formula->entry ), formula ); } if( formula->caption ) { set_glabel( formula->left_label, _( "%s:" ), formula->caption ); gtk_widget_show( formula->left_label ); } else gtk_widget_hide( formula->left_label ); if( formula->value ) /* Just display the first line of the formula ... it can be * mutiline for class members, for example. */ set_glabel1( formula->right_label, "%s", formula->value ); if( formula->edit && formula->needs_focus ) { if( formula->expr ) gtk_editable_select_region( GTK_EDITABLE( formula->entry ), 0, -1 ); gtk_widget_grab_focus( formula->entry ); formula->needs_focus = FALSE; } } static gboolean formula_refresh_idle_cb( void ) { formula_refresh_idle = 0; while( formula_refresh_all ) { Formula *formula = FORMULA( formula_refresh_all->data ); formula_refresh_unqueue( formula ); formula_refresh( formula ); } return( FALSE ); } static void formula_refresh_queue( Formula *formula ) { if( !formula->refresh_queued ) { formula_refresh_all = g_slist_prepend( formula_refresh_all, formula ); formula->refresh_queued = TRUE; if( !formula_refresh_idle ) formula_refresh_idle = g_idle_add( (GSourceFunc) formula_refresh_idle_cb, NULL ); } } static void formula_destroy( GtkObject *object ) { Formula *formula; #ifdef DEBUG printf( "formula_destroy\n" ); #endif /*DEBUG*/ g_return_if_fail( object != NULL ); g_return_if_fail( IS_FORMULA( object ) ); /* My instance destroy stuff. */ formula = FORMULA( object ); formula_refresh_unqueue( formula ); IM_FREE( formula->caption ); IM_FREE( formula->value ); IM_FREE( formula->expr ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } /* Change edit mode. */ void formula_set_edit( Formula *formula, gboolean edit ) { #ifdef DEBUG printf( "formula_set_edit: %d\n", edit ); #endif /*DEBUG*/ if( formula->edit != edit ) { formula->edit = edit; formula_refresh_queue( formula ); } /* Can't have been edited yet, whichever way we're turning edit. */ formula->changed = FALSE; } /* Grab focus on next refresh. */ void formula_set_needs_focus( Formula *formula, gboolean needs_focus ) { #ifdef DEBUG printf( "formula_set_needs_focus: %d\n", needs_focus ); #endif /*DEBUG*/ if( formula->needs_focus != needs_focus ) { formula->needs_focus = needs_focus; formula_refresh_queue( formula ); } } /* Change sensitive mode. */ void formula_set_sensitive( Formula *formula, gboolean sensitive ) { #ifdef DEBUG printf( "formula_set_sensitive: %d\n", sensitive ); #endif /*DEBUG*/ if( formula->sensitive != sensitive ) { formula->sensitive = sensitive; if( !formula->sensitive ) formula_set_edit( formula, FALSE ); formula_refresh_queue( formula ); } } /* Re-read the text. TRUE if we saw a change. */ gboolean formula_scan( Formula *formula ) { gboolean changed; #ifdef DEBUG printf( "formula_scan\n" ); #endif /*DEBUG*/ changed = FALSE; /* Should be in edit mode. */ if( formula->edit && formula->entry && GTK_WIDGET_VISIBLE( formula->entry ) ) { const char *expr; /* There should be some edited text. */ expr = gtk_entry_get_text( GTK_ENTRY( formula->entry ) ); if( expr && strspn( expr, WHITESPACE ) != strlen( expr ) ) { IM_SETSTR( formula->expr, expr ); changed = TRUE; } formula_set_edit( formula, FALSE ); } return( changed ); } static gboolean formula_enter_notify_event( GtkWidget *widget, GdkEventCrossing *event ) { GtkWidget *event_widget; event_widget = gtk_get_event_widget( (GdkEvent *) event ); if( event_widget == widget && event->detail != GDK_NOTIFY_INFERIOR ) { gtk_widget_set_state( widget, GTK_STATE_PRELIGHT ); /* Tell people about our highlight change ... used to (eg.) set * flash help. */ g_signal_emit( G_OBJECT( widget ), formula_signals[ENTER], 0 ); } return( FALSE ); } static gboolean formula_leave_notify_event( GtkWidget *widget, GdkEventCrossing *event ) { GtkWidget *event_widget; event_widget = gtk_get_event_widget( (GdkEvent *) event ); if( event_widget == widget && event->detail != GDK_NOTIFY_INFERIOR ) { gtk_widget_set_state( widget, GTK_STATE_NORMAL ); /* Tell people about our highlight change ... used to (eg.) set * flash help. */ g_signal_emit( G_OBJECT( widget ), formula_signals[LEAVE], 0 ); } return( FALSE ); } /* Event in us somewhere. */ static gboolean formula_button_press_event( GtkWidget *widget, GdkEventButton *event ) { gboolean handled = FALSE; if( event->type == GDK_BUTTON_PRESS ) { Formula *formula = FORMULA( widget ); if( event->button == 1 && formula->sensitive ) { if( !formula->edit ) { formula_set_edit( formula, TRUE ); formula_set_needs_focus( formula, TRUE ); } handled = TRUE; } } return( handled ); } static void formula_real_changed( Formula *formula ) { #ifdef DEBUG printf( "formula_real_changed\n" ); #endif /*DEBUG*/ formula->changed = TRUE; } static void formula_class_init( FormulaClass *class ) { GtkObjectClass *gobject_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->destroy = formula_destroy; widget_class->enter_notify_event = formula_enter_notify_event; widget_class->leave_notify_event = formula_leave_notify_event; widget_class->button_press_event = formula_button_press_event; /* Create signals. */ formula_signals[EDIT] = g_signal_new( "edit", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( FormulaClass, changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); formula_signals[CHANGED] = g_signal_new( "changed", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( FormulaClass, changed ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); formula_signals[ACTIVATE] = g_signal_new( "activate", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( FormulaClass, activate ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); formula_signals[ENTER] = g_signal_new( "enter", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( FormulaClass, enter ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); formula_signals[LEAVE] = g_signal_new( "leave", G_OBJECT_CLASS_TYPE( gobject_class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( FormulaClass, leave ), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); /* Init methods. */ class->changed = formula_real_changed; } static void formula_init( Formula *formula ) { /* How annoying! To avoid vertical resizes on edit/view toggles we * need to add differing amounts of padding to the label depending on * the theme. FIXME ... get this from the style somehow */ #ifdef OS_WIN32 /* with either wimp theme or gtk default. */ const int vpadding = 7; #else /*!OS_WIN32*/ /* clearlooks */ const int vpadding = 8; #endif /*OS_WIN32*/ formula->caption = NULL; formula->value = NULL; formula->expr = NULL; formula->edit = FALSE; formula->sensitive = TRUE; formula->changed = FALSE; formula->refresh_queued = FALSE; formula->needs_focus = FALSE; formula->entry_frame = NULL; gtk_widget_add_events( GTK_WIDGET( formula ), GDK_POINTER_MOTION_HINT_MASK ); formula->hbox = gtk_hbox_new( FALSE, 12 ); gtk_container_add( GTK_CONTAINER( formula ), formula->hbox ); gtk_widget_show( formula->hbox ); formula->left_label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( formula->left_label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( formula->left_label ), 2, vpadding ); gtk_box_pack_start( GTK_BOX( formula->hbox ), formula->left_label, FALSE, FALSE, 2 ); gtk_widget_show( formula->left_label ); formula->right_label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( formula->right_label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( formula->right_label ), 7, vpadding ); gtk_box_pack_start( GTK_BOX( formula->hbox ), formula->right_label, TRUE, TRUE, 0 ); gtk_widget_show( formula->right_label ); } GtkType formula_get_type( void ) { static GtkType formula_type = 0; if( !formula_type ) { static const GtkTypeInfo formula_info = { "Formula", sizeof( Formula ), sizeof( FormulaClass ), (GtkClassInitFunc) formula_class_init, (GtkObjectInitFunc) formula_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; formula_type = gtk_type_unique( GTK_TYPE_EVENT_BOX, &formula_info ); } return( formula_type ); } Formula * formula_new( void ) { Formula *formula = gtk_type_new( TYPE_FORMULA ); return( formula ); } void formula_set_caption( Formula *formula, const char *caption ) { if( !caption && formula->caption ) { IM_FREE( formula->caption ); formula_refresh_queue( formula ); } else if( caption && (!formula->caption || strcmp( caption, formula->caption ) != 0) ) { IM_SETSTR( formula->caption, caption ); formula_refresh_queue( formula ); } } void formula_set_value_expr( Formula *formula, const char *value, const char *expr ) { #ifdef DEBUG printf( "formula_set_value_expr: value=\"%s\", expr=\"%s\"\n", value, expr ); #endif /*DEBUG*/ if( value && (!formula->value || strcmp( value, formula->value ) != 0) ) { IM_SETSTR( formula->value, value ); formula_refresh_queue( formula ); } if( expr && (!formula->expr || strcmp( expr, formula->expr ) != 0) ) { IM_SETSTR( formula->expr, expr ); formula_refresh_queue( formula ); } } nip2-8.7.1/src/Makefile.in0000644000175000017500000112635513417043242012171 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ @OS_WIN32_FALSE@bin_PROGRAMS = nip2$(EXEEXT) @OS_WIN32_TRUE@bin_PROGRAMS = nip2$(EXEEXT) nip2-cli$(EXEEXT) @OS_WIN32_TRUE@am__append_1 = \ @OS_WIN32_TRUE@ nip2-icon.rc subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am__nip2_SOURCES_DIST = vipsobject.c vipsobject.h plotmodel.c \ plotmodel.h progress.c progress.h panechild.c panechild.h \ plotpresent.c plotpresent.h plotstatus.c plotstatus.h \ floatwindow.c floatwindow.h vobject.c vobject.h action.c \ action.h boxes.c boxes.h popupbutton.c popupbutton.h \ imageheader.c imageheader.h preview.c preview.h builtin.c \ builtin.h icontainer.c icontainer.h iobject.c iobject.h \ class.c class.h classmodel.c classmodel.h colour.c colour.h \ colourdisplay.c colourdisplay.h colourview.c colourview.h \ column.c column.h columnview.c columnview.h compile.c \ compile.h conversion.c conversion.h conversionview.c \ conversionview.h doubleclick.c doubleclick.h dump.c dump.h \ expr.c expr.h filemodel.c filemodel.h pane.c pane.h pathname.c \ pathname.h fontname.c fontname.h group.c group.h \ pathnameview.c pathnameview.h fontnameview.c fontnameview.h \ filesel.c filesel.h graphwindow.c graphwindow.h graphicview.c \ graphicview.h gtkutil.c gtkutil.h heap.c heap.h heapmodel.c \ heapmodel.h helpindex.h nipmarshal.h nipmarshal.c iarrow.c \ iarrow.h value.c value.h valueview.c valueview.h idialog.c \ idialog.h iimage.c iimage.h iimageview.c iimageview.h \ imagedisplay.c imagedisplay.h log.c log.h error.c error.h \ managed.c managed.h managedfile.c managedfile.h \ managedgvalue.c managedgvalue.h managedgobject.c \ managedgobject.h managedstring.c managedstring.h imageinfo.c \ imageinfo.h imagemodel.c imagemodel.h imagepresent.c \ imagepresent.h imageview.c imageview.h ip.h iregion.c \ iregion.h iregiongroup.c iregiongroup.h iregiongroupview.c \ iregiongroupview.h iregionview.c iregionview.h itext.c itext.h \ itextview.c itextview.h iwindow.c iwindow.h parse.y parser.h \ prefs.c prefs.h prefworkspaceview.c prefworkspaceview.h \ prefcolumnview.c prefcolumnview.h lex.l link.c link.h main.c \ main.h mainw.c mainw.h matrix.c matrix.h matrixview.c \ matrixview.h plot.c plot.h plotview.c plotview.h plotwindow.c \ plotwindow.h model.c model.h option.c option.h optionview.c \ optionview.h formula.c formula.h paintboxview.c paintboxview.h \ path.c path.h predicate.c predicate.h program.c program.h \ string.c istring.h number.c number.h expression.c expression.h \ expressionview.c expressionview.h stringview.c stringview.h \ editview.c editview.h numberview.c numberview.h real.c real.h \ vector.c vector.h reduce.c reduce.h regionview.c regionview.h \ rhs.c rhs.h rhsview.c rhsview.h row.c row.h rowview.c \ rowview.h secret.c secret.h slider.c slider.h sliderview.c \ sliderview.h clock.c clock.h spin.c spin.h statusview.c \ statusview.h subcolumn.c subcolumn.h subcolumnview.c \ subcolumnview.h symbol.c symbol.h toggle.c toggle.h \ toggleview.c toggleview.h tool.c tool.h toolkit.c toolkit.h \ toolkitgroup.c toolkitgroup.h toolkitgroupview.c \ toolkitgroupview.h toolkitview.c toolkitview.h defbrowser.c \ defbrowser.h toolkitbrowser.c toolkitbrowser.h toolview.c \ toolview.h trace.c trace.h tree.c tree.h tslider.c tslider.h \ util.c util.h view.c view.h call.c call.h cache.c cache.h \ watch.c watch.h workspace.c workspace.h workspacegroup.c \ workspacegroup.h workspacegroupview.c workspacegroupview.h \ workspacedefs.c workspacedefs.h workspaceroot.c \ workspaceroot.h workspaceview.c workspaceview.h nip2-icon.rc @OS_WIN32_TRUE@am__objects_1 = nip2-icon.$(OBJEXT) am_nip2_OBJECTS = nip2-vipsobject.$(OBJEXT) nip2-plotmodel.$(OBJEXT) \ nip2-progress.$(OBJEXT) nip2-panechild.$(OBJEXT) \ nip2-plotpresent.$(OBJEXT) nip2-plotstatus.$(OBJEXT) \ nip2-floatwindow.$(OBJEXT) nip2-vobject.$(OBJEXT) \ nip2-action.$(OBJEXT) nip2-boxes.$(OBJEXT) \ nip2-popupbutton.$(OBJEXT) nip2-imageheader.$(OBJEXT) \ nip2-preview.$(OBJEXT) nip2-builtin.$(OBJEXT) \ nip2-icontainer.$(OBJEXT) nip2-iobject.$(OBJEXT) \ nip2-class.$(OBJEXT) nip2-classmodel.$(OBJEXT) \ nip2-colour.$(OBJEXT) nip2-colourdisplay.$(OBJEXT) \ nip2-colourview.$(OBJEXT) nip2-column.$(OBJEXT) \ nip2-columnview.$(OBJEXT) nip2-compile.$(OBJEXT) \ nip2-conversion.$(OBJEXT) nip2-conversionview.$(OBJEXT) \ nip2-doubleclick.$(OBJEXT) nip2-dump.$(OBJEXT) \ nip2-expr.$(OBJEXT) nip2-filemodel.$(OBJEXT) \ nip2-pane.$(OBJEXT) nip2-pathname.$(OBJEXT) \ nip2-fontname.$(OBJEXT) nip2-group.$(OBJEXT) \ nip2-pathnameview.$(OBJEXT) nip2-fontnameview.$(OBJEXT) \ nip2-filesel.$(OBJEXT) nip2-graphwindow.$(OBJEXT) \ nip2-graphicview.$(OBJEXT) nip2-gtkutil.$(OBJEXT) \ nip2-heap.$(OBJEXT) nip2-heapmodel.$(OBJEXT) \ nip2-nipmarshal.$(OBJEXT) nip2-iarrow.$(OBJEXT) \ nip2-value.$(OBJEXT) nip2-valueview.$(OBJEXT) \ nip2-idialog.$(OBJEXT) nip2-iimage.$(OBJEXT) \ nip2-iimageview.$(OBJEXT) nip2-imagedisplay.$(OBJEXT) \ nip2-log.$(OBJEXT) nip2-error.$(OBJEXT) nip2-managed.$(OBJEXT) \ nip2-managedfile.$(OBJEXT) nip2-managedgvalue.$(OBJEXT) \ nip2-managedgobject.$(OBJEXT) nip2-managedstring.$(OBJEXT) \ nip2-imageinfo.$(OBJEXT) nip2-imagemodel.$(OBJEXT) \ nip2-imagepresent.$(OBJEXT) nip2-imageview.$(OBJEXT) \ nip2-iregion.$(OBJEXT) nip2-iregiongroup.$(OBJEXT) \ nip2-iregiongroupview.$(OBJEXT) nip2-iregionview.$(OBJEXT) \ nip2-itext.$(OBJEXT) nip2-itextview.$(OBJEXT) \ nip2-iwindow.$(OBJEXT) nip2-parse.$(OBJEXT) \ nip2-prefs.$(OBJEXT) nip2-prefworkspaceview.$(OBJEXT) \ nip2-prefcolumnview.$(OBJEXT) nip2-lex.$(OBJEXT) \ nip2-link.$(OBJEXT) nip2-main.$(OBJEXT) nip2-mainw.$(OBJEXT) \ nip2-matrix.$(OBJEXT) nip2-matrixview.$(OBJEXT) \ nip2-plot.$(OBJEXT) nip2-plotview.$(OBJEXT) \ nip2-plotwindow.$(OBJEXT) nip2-model.$(OBJEXT) \ nip2-option.$(OBJEXT) nip2-optionview.$(OBJEXT) \ nip2-formula.$(OBJEXT) nip2-paintboxview.$(OBJEXT) \ nip2-path.$(OBJEXT) nip2-predicate.$(OBJEXT) \ nip2-program.$(OBJEXT) nip2-string.$(OBJEXT) \ nip2-number.$(OBJEXT) nip2-expression.$(OBJEXT) \ nip2-expressionview.$(OBJEXT) nip2-stringview.$(OBJEXT) \ nip2-editview.$(OBJEXT) nip2-numberview.$(OBJEXT) \ nip2-real.$(OBJEXT) nip2-vector.$(OBJEXT) \ nip2-reduce.$(OBJEXT) nip2-regionview.$(OBJEXT) \ nip2-rhs.$(OBJEXT) nip2-rhsview.$(OBJEXT) nip2-row.$(OBJEXT) \ nip2-rowview.$(OBJEXT) nip2-secret.$(OBJEXT) \ nip2-slider.$(OBJEXT) nip2-sliderview.$(OBJEXT) \ nip2-clock.$(OBJEXT) nip2-spin.$(OBJEXT) \ nip2-statusview.$(OBJEXT) nip2-subcolumn.$(OBJEXT) \ nip2-subcolumnview.$(OBJEXT) nip2-symbol.$(OBJEXT) \ nip2-toggle.$(OBJEXT) nip2-toggleview.$(OBJEXT) \ nip2-tool.$(OBJEXT) nip2-toolkit.$(OBJEXT) \ nip2-toolkitgroup.$(OBJEXT) nip2-toolkitgroupview.$(OBJEXT) \ nip2-toolkitview.$(OBJEXT) nip2-defbrowser.$(OBJEXT) \ nip2-toolkitbrowser.$(OBJEXT) nip2-toolview.$(OBJEXT) \ nip2-trace.$(OBJEXT) nip2-tree.$(OBJEXT) \ nip2-tslider.$(OBJEXT) nip2-util.$(OBJEXT) nip2-view.$(OBJEXT) \ nip2-call.$(OBJEXT) nip2-cache.$(OBJEXT) nip2-watch.$(OBJEXT) \ nip2-workspace.$(OBJEXT) nip2-workspacegroup.$(OBJEXT) \ nip2-workspacegroupview.$(OBJEXT) nip2-workspacedefs.$(OBJEXT) \ nip2-workspaceroot.$(OBJEXT) nip2-workspaceview.$(OBJEXT) \ $(am__objects_1) nip2_OBJECTS = $(am_nip2_OBJECTS) nip2_LDADD = $(LDADD) nip2_DEPENDENCIES = AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = nip2_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(nip2_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__nip2_cli_SOURCES_DIST = nip2-cli.c @OS_WIN32_TRUE@am_nip2_cli_OBJECTS = nip2-cli.$(OBJEXT) nip2_cli_OBJECTS = $(am_nip2_cli_OBJECTS) nip2_cli_LDADD = $(LDADD) nip2_cli_DEPENDENCIES = 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 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/nip2-action.Po \ ./$(DEPDIR)/nip2-boxes.Po ./$(DEPDIR)/nip2-builtin.Po \ ./$(DEPDIR)/nip2-cache.Po ./$(DEPDIR)/nip2-call.Po \ ./$(DEPDIR)/nip2-class.Po ./$(DEPDIR)/nip2-classmodel.Po \ ./$(DEPDIR)/nip2-cli.Po ./$(DEPDIR)/nip2-clock.Po \ ./$(DEPDIR)/nip2-colour.Po ./$(DEPDIR)/nip2-colourdisplay.Po \ ./$(DEPDIR)/nip2-colourview.Po ./$(DEPDIR)/nip2-column.Po \ ./$(DEPDIR)/nip2-columnview.Po ./$(DEPDIR)/nip2-compile.Po \ ./$(DEPDIR)/nip2-conversion.Po \ ./$(DEPDIR)/nip2-conversionview.Po \ ./$(DEPDIR)/nip2-defbrowser.Po ./$(DEPDIR)/nip2-doubleclick.Po \ ./$(DEPDIR)/nip2-dump.Po ./$(DEPDIR)/nip2-editview.Po \ ./$(DEPDIR)/nip2-error.Po ./$(DEPDIR)/nip2-expr.Po \ ./$(DEPDIR)/nip2-expression.Po \ ./$(DEPDIR)/nip2-expressionview.Po \ ./$(DEPDIR)/nip2-filemodel.Po ./$(DEPDIR)/nip2-filesel.Po \ ./$(DEPDIR)/nip2-floatwindow.Po ./$(DEPDIR)/nip2-fontname.Po \ ./$(DEPDIR)/nip2-fontnameview.Po ./$(DEPDIR)/nip2-formula.Po \ ./$(DEPDIR)/nip2-graphicview.Po \ ./$(DEPDIR)/nip2-graphwindow.Po ./$(DEPDIR)/nip2-group.Po \ ./$(DEPDIR)/nip2-gtkutil.Po ./$(DEPDIR)/nip2-heap.Po \ ./$(DEPDIR)/nip2-heapmodel.Po ./$(DEPDIR)/nip2-iarrow.Po \ ./$(DEPDIR)/nip2-icontainer.Po ./$(DEPDIR)/nip2-idialog.Po \ ./$(DEPDIR)/nip2-iimage.Po ./$(DEPDIR)/nip2-iimageview.Po \ ./$(DEPDIR)/nip2-imagedisplay.Po \ ./$(DEPDIR)/nip2-imageheader.Po ./$(DEPDIR)/nip2-imageinfo.Po \ ./$(DEPDIR)/nip2-imagemodel.Po \ ./$(DEPDIR)/nip2-imagepresent.Po ./$(DEPDIR)/nip2-imageview.Po \ ./$(DEPDIR)/nip2-iobject.Po ./$(DEPDIR)/nip2-iregion.Po \ ./$(DEPDIR)/nip2-iregiongroup.Po \ ./$(DEPDIR)/nip2-iregiongroupview.Po \ ./$(DEPDIR)/nip2-iregionview.Po ./$(DEPDIR)/nip2-itext.Po \ ./$(DEPDIR)/nip2-itextview.Po ./$(DEPDIR)/nip2-iwindow.Po \ ./$(DEPDIR)/nip2-lex.Po ./$(DEPDIR)/nip2-link.Po \ ./$(DEPDIR)/nip2-log.Po ./$(DEPDIR)/nip2-main.Po \ ./$(DEPDIR)/nip2-mainw.Po ./$(DEPDIR)/nip2-managed.Po \ ./$(DEPDIR)/nip2-managedfile.Po \ ./$(DEPDIR)/nip2-managedgobject.Po \ ./$(DEPDIR)/nip2-managedgvalue.Po \ ./$(DEPDIR)/nip2-managedstring.Po ./$(DEPDIR)/nip2-matrix.Po \ ./$(DEPDIR)/nip2-matrixview.Po ./$(DEPDIR)/nip2-model.Po \ ./$(DEPDIR)/nip2-nipmarshal.Po ./$(DEPDIR)/nip2-number.Po \ ./$(DEPDIR)/nip2-numberview.Po ./$(DEPDIR)/nip2-option.Po \ ./$(DEPDIR)/nip2-optionview.Po \ ./$(DEPDIR)/nip2-paintboxview.Po ./$(DEPDIR)/nip2-pane.Po \ ./$(DEPDIR)/nip2-panechild.Po ./$(DEPDIR)/nip2-parse.Po \ ./$(DEPDIR)/nip2-path.Po ./$(DEPDIR)/nip2-pathname.Po \ ./$(DEPDIR)/nip2-pathnameview.Po ./$(DEPDIR)/nip2-plot.Po \ ./$(DEPDIR)/nip2-plotmodel.Po ./$(DEPDIR)/nip2-plotpresent.Po \ ./$(DEPDIR)/nip2-plotstatus.Po ./$(DEPDIR)/nip2-plotview.Po \ ./$(DEPDIR)/nip2-plotwindow.Po ./$(DEPDIR)/nip2-popupbutton.Po \ ./$(DEPDIR)/nip2-predicate.Po \ ./$(DEPDIR)/nip2-prefcolumnview.Po ./$(DEPDIR)/nip2-prefs.Po \ ./$(DEPDIR)/nip2-prefworkspaceview.Po \ ./$(DEPDIR)/nip2-preview.Po ./$(DEPDIR)/nip2-program.Po \ ./$(DEPDIR)/nip2-progress.Po ./$(DEPDIR)/nip2-real.Po \ ./$(DEPDIR)/nip2-reduce.Po ./$(DEPDIR)/nip2-regionview.Po \ ./$(DEPDIR)/nip2-rhs.Po ./$(DEPDIR)/nip2-rhsview.Po \ ./$(DEPDIR)/nip2-row.Po ./$(DEPDIR)/nip2-rowview.Po \ ./$(DEPDIR)/nip2-secret.Po ./$(DEPDIR)/nip2-slider.Po \ ./$(DEPDIR)/nip2-sliderview.Po ./$(DEPDIR)/nip2-spin.Po \ ./$(DEPDIR)/nip2-statusview.Po ./$(DEPDIR)/nip2-string.Po \ ./$(DEPDIR)/nip2-stringview.Po ./$(DEPDIR)/nip2-subcolumn.Po \ ./$(DEPDIR)/nip2-subcolumnview.Po ./$(DEPDIR)/nip2-symbol.Po \ ./$(DEPDIR)/nip2-toggle.Po ./$(DEPDIR)/nip2-toggleview.Po \ ./$(DEPDIR)/nip2-tool.Po ./$(DEPDIR)/nip2-toolkit.Po \ ./$(DEPDIR)/nip2-toolkitbrowser.Po \ ./$(DEPDIR)/nip2-toolkitgroup.Po \ ./$(DEPDIR)/nip2-toolkitgroupview.Po \ ./$(DEPDIR)/nip2-toolkitview.Po ./$(DEPDIR)/nip2-toolview.Po \ ./$(DEPDIR)/nip2-trace.Po ./$(DEPDIR)/nip2-tree.Po \ ./$(DEPDIR)/nip2-tslider.Po ./$(DEPDIR)/nip2-util.Po \ ./$(DEPDIR)/nip2-value.Po ./$(DEPDIR)/nip2-valueview.Po \ ./$(DEPDIR)/nip2-vector.Po ./$(DEPDIR)/nip2-view.Po \ ./$(DEPDIR)/nip2-vipsobject.Po ./$(DEPDIR)/nip2-vobject.Po \ ./$(DEPDIR)/nip2-watch.Po ./$(DEPDIR)/nip2-workspace.Po \ ./$(DEPDIR)/nip2-workspacedefs.Po \ ./$(DEPDIR)/nip2-workspacegroup.Po \ ./$(DEPDIR)/nip2-workspacegroupview.Po \ ./$(DEPDIR)/nip2-workspaceroot.Po \ ./$(DEPDIR)/nip2-workspaceview.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS) LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS) AM_V_LEX = $(am__v_LEX_@AM_V@) am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@) am__v_LEX_0 = @echo " LEX " $@; am__v_LEX_1 = YLWRAP = $(top_srcdir)/ylwrap am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = SOURCES = $(nip2_SOURCES) $(nip2_cli_SOURCES) DIST_SOURCES = $(am__nip2_SOURCES_DIST) $(am__nip2_cli_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir distdir-am am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \ $(top_srcdir)/ylwrap lex.c parse.c DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ SUBDIRS = BITMAPS # need this to keep autoconf quiet, but we don't actually use it ... see the # bison rule below YACC = bison # windows resource files ... see .rc.o rule later SUFFIXES = .rc @OS_WIN32_TRUE@nip2_cli_SOURCES = nip2-cli.c @OS_WIN32_TRUE@nip2_CFLAGS = "-mwindows" @OS_WIN32_FALSE@CLI_DIST = nip2-cli.c @OS_WIN32_TRUE@CLI_DIST = nip2_SOURCES = vipsobject.c vipsobject.h plotmodel.c plotmodel.h \ progress.c progress.h panechild.c panechild.h plotpresent.c \ plotpresent.h plotstatus.c plotstatus.h floatwindow.c \ floatwindow.h vobject.c vobject.h action.c action.h boxes.c \ boxes.h popupbutton.c popupbutton.h imageheader.c \ imageheader.h preview.c preview.h builtin.c builtin.h \ icontainer.c icontainer.h iobject.c iobject.h class.c class.h \ classmodel.c classmodel.h colour.c colour.h colourdisplay.c \ colourdisplay.h colourview.c colourview.h column.c column.h \ columnview.c columnview.h compile.c compile.h conversion.c \ conversion.h conversionview.c conversionview.h doubleclick.c \ doubleclick.h dump.c dump.h expr.c expr.h filemodel.c \ filemodel.h pane.c pane.h pathname.c pathname.h fontname.c \ fontname.h group.c group.h pathnameview.c pathnameview.h \ fontnameview.c fontnameview.h filesel.c filesel.h \ graphwindow.c graphwindow.h graphicview.c graphicview.h \ gtkutil.c gtkutil.h heap.c heap.h heapmodel.c heapmodel.h \ helpindex.h nipmarshal.h nipmarshal.c iarrow.c iarrow.h \ value.c value.h valueview.c valueview.h idialog.c idialog.h \ iimage.c iimage.h iimageview.c iimageview.h imagedisplay.c \ imagedisplay.h log.c log.h error.c error.h managed.c managed.h \ managedfile.c managedfile.h managedgvalue.c managedgvalue.h \ managedgobject.c managedgobject.h managedstring.c \ managedstring.h imageinfo.c imageinfo.h imagemodel.c \ imagemodel.h imagepresent.c imagepresent.h imageview.c \ imageview.h ip.h iregion.c iregion.h iregiongroup.c \ iregiongroup.h iregiongroupview.c iregiongroupview.h \ iregionview.c iregionview.h itext.c itext.h itextview.c \ itextview.h iwindow.c iwindow.h parse.y parser.h prefs.c \ prefs.h prefworkspaceview.c prefworkspaceview.h \ prefcolumnview.c prefcolumnview.h lex.l link.c link.h main.c \ main.h mainw.c mainw.h matrix.c matrix.h matrixview.c \ matrixview.h plot.c plot.h plotview.c plotview.h plotwindow.c \ plotwindow.h model.c model.h option.c option.h optionview.c \ optionview.h formula.c formula.h paintboxview.c paintboxview.h \ path.c path.h predicate.c predicate.h program.c program.h \ string.c istring.h number.c number.h expression.c expression.h \ expressionview.c expressionview.h stringview.c stringview.h \ editview.c editview.h numberview.c numberview.h real.c real.h \ vector.c vector.h reduce.c reduce.h regionview.c regionview.h \ rhs.c rhs.h rhsview.c rhsview.h row.c row.h rowview.c \ rowview.h secret.c secret.h slider.c slider.h sliderview.c \ sliderview.h clock.c clock.h spin.c spin.h statusview.c \ statusview.h subcolumn.c subcolumn.h subcolumnview.c \ subcolumnview.h symbol.c symbol.h toggle.c toggle.h \ toggleview.c toggleview.h tool.c tool.h toolkit.c toolkit.h \ toolkitgroup.c toolkitgroup.h toolkitgroupview.c \ toolkitgroupview.h toolkitview.c toolkitview.h defbrowser.c \ defbrowser.h toolkitbrowser.c toolkitbrowser.h toolview.c \ toolview.h trace.c trace.h tree.c tree.h tslider.c tslider.h \ util.c util.h view.c view.h call.c call.h cache.c cache.h \ watch.c watch.h workspace.c workspace.h workspacegroup.c \ workspacegroup.h workspacegroupview.c workspacegroupview.h \ workspacedefs.c workspacedefs.h workspaceroot.c \ workspaceroot.h workspaceview.c workspaceview.h \ $(am__append_1) AM_CPPFLAGS = @IP_CFLAGS@ LDADD = @IP_CFLAGS@ @IP_LIBS@ AM_LDFLAGS = @LDFLAGS@ CLEANFILES = parse.c parse.h lex.c tags EXTRA_DIST = makehelpindex.pl helpindex.h \ nipmarshal.h nipmarshal.c nipmarshal.list \ $(CLI_DIST) all: all-recursive .SUFFIXES: .SUFFIXES: .rc .c .l .lo .o .obj .y $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; 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 echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ 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; \ else { print "f", $$3 "/" $$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_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list nip2$(EXEEXT): $(nip2_OBJECTS) $(nip2_DEPENDENCIES) $(EXTRA_nip2_DEPENDENCIES) @rm -f nip2$(EXEEXT) $(AM_V_CCLD)$(nip2_LINK) $(nip2_OBJECTS) $(nip2_LDADD) $(LIBS) nip2-cli$(EXEEXT): $(nip2_cli_OBJECTS) $(nip2_cli_DEPENDENCIES) $(EXTRA_nip2_cli_DEPENDENCIES) @rm -f nip2-cli$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nip2_cli_OBJECTS) $(nip2_cli_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-action.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-boxes.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-builtin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-cache.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-call.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-class.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-classmodel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-cli.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-clock.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-colour.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-colourdisplay.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-colourview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-column.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-columnview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-compile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-conversion.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-conversionview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-defbrowser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-doubleclick.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-dump.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-editview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-expr.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-expression.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-expressionview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-filemodel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-filesel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-floatwindow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-fontname.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-fontnameview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-formula.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-graphicview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-graphwindow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-group.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-gtkutil.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-heap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-heapmodel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iarrow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-icontainer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-idialog.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iimage.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iimageview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-imagedisplay.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-imageheader.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-imageinfo.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-imagemodel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-imagepresent.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-imageview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iobject.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iregion.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iregiongroup.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iregiongroupview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iregionview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-itext.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-itextview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-iwindow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-lex.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-link.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-log.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-mainw.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-managed.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-managedfile.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-managedgobject.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-managedgvalue.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-managedstring.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-matrix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-matrixview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-model.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-nipmarshal.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-number.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-numberview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-option.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-optionview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-paintboxview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-pane.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-panechild.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-parse.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-path.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-pathname.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-pathnameview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-plot.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-plotmodel.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-plotpresent.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-plotstatus.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-plotview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-plotwindow.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-popupbutton.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-predicate.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-prefcolumnview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-prefs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-prefworkspaceview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-preview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-program.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-progress.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-real.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-reduce.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-regionview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-rhs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-rhsview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-row.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-rowview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-secret.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-slider.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-sliderview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-spin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-statusview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-string.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-stringview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-subcolumn.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-subcolumnview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-symbol.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-toggle.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-toggleview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-tool.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-toolkit.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-toolkitbrowser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-toolkitgroup.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-toolkitgroupview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-toolkitview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-toolview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-trace.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-tree.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-tslider.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-util.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-value.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-valueview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-vector.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-view.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-vipsobject.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-vobject.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-watch.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-workspace.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-workspacedefs.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-workspacegroup.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-workspacegroupview.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-workspaceroot.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nip2-workspaceview.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< nip2-vipsobject.o: vipsobject.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-vipsobject.o -MD -MP -MF $(DEPDIR)/nip2-vipsobject.Tpo -c -o nip2-vipsobject.o `test -f 'vipsobject.c' || echo '$(srcdir)/'`vipsobject.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-vipsobject.Tpo $(DEPDIR)/nip2-vipsobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vipsobject.c' object='nip2-vipsobject.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-vipsobject.o `test -f 'vipsobject.c' || echo '$(srcdir)/'`vipsobject.c nip2-vipsobject.obj: vipsobject.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-vipsobject.obj -MD -MP -MF $(DEPDIR)/nip2-vipsobject.Tpo -c -o nip2-vipsobject.obj `if test -f 'vipsobject.c'; then $(CYGPATH_W) 'vipsobject.c'; else $(CYGPATH_W) '$(srcdir)/vipsobject.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-vipsobject.Tpo $(DEPDIR)/nip2-vipsobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vipsobject.c' object='nip2-vipsobject.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-vipsobject.obj `if test -f 'vipsobject.c'; then $(CYGPATH_W) 'vipsobject.c'; else $(CYGPATH_W) '$(srcdir)/vipsobject.c'; fi` nip2-plotmodel.o: plotmodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotmodel.o -MD -MP -MF $(DEPDIR)/nip2-plotmodel.Tpo -c -o nip2-plotmodel.o `test -f 'plotmodel.c' || echo '$(srcdir)/'`plotmodel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotmodel.Tpo $(DEPDIR)/nip2-plotmodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotmodel.c' object='nip2-plotmodel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotmodel.o `test -f 'plotmodel.c' || echo '$(srcdir)/'`plotmodel.c nip2-plotmodel.obj: plotmodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotmodel.obj -MD -MP -MF $(DEPDIR)/nip2-plotmodel.Tpo -c -o nip2-plotmodel.obj `if test -f 'plotmodel.c'; then $(CYGPATH_W) 'plotmodel.c'; else $(CYGPATH_W) '$(srcdir)/plotmodel.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotmodel.Tpo $(DEPDIR)/nip2-plotmodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotmodel.c' object='nip2-plotmodel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotmodel.obj `if test -f 'plotmodel.c'; then $(CYGPATH_W) 'plotmodel.c'; else $(CYGPATH_W) '$(srcdir)/plotmodel.c'; fi` nip2-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-progress.o -MD -MP -MF $(DEPDIR)/nip2-progress.Tpo -c -o nip2-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-progress.Tpo $(DEPDIR)/nip2-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='nip2-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c nip2-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-progress.obj -MD -MP -MF $(DEPDIR)/nip2-progress.Tpo -c -o nip2-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-progress.Tpo $(DEPDIR)/nip2-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='nip2-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` nip2-panechild.o: panechild.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-panechild.o -MD -MP -MF $(DEPDIR)/nip2-panechild.Tpo -c -o nip2-panechild.o `test -f 'panechild.c' || echo '$(srcdir)/'`panechild.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-panechild.Tpo $(DEPDIR)/nip2-panechild.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='panechild.c' object='nip2-panechild.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-panechild.o `test -f 'panechild.c' || echo '$(srcdir)/'`panechild.c nip2-panechild.obj: panechild.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-panechild.obj -MD -MP -MF $(DEPDIR)/nip2-panechild.Tpo -c -o nip2-panechild.obj `if test -f 'panechild.c'; then $(CYGPATH_W) 'panechild.c'; else $(CYGPATH_W) '$(srcdir)/panechild.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-panechild.Tpo $(DEPDIR)/nip2-panechild.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='panechild.c' object='nip2-panechild.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-panechild.obj `if test -f 'panechild.c'; then $(CYGPATH_W) 'panechild.c'; else $(CYGPATH_W) '$(srcdir)/panechild.c'; fi` nip2-plotpresent.o: plotpresent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotpresent.o -MD -MP -MF $(DEPDIR)/nip2-plotpresent.Tpo -c -o nip2-plotpresent.o `test -f 'plotpresent.c' || echo '$(srcdir)/'`plotpresent.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotpresent.Tpo $(DEPDIR)/nip2-plotpresent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotpresent.c' object='nip2-plotpresent.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotpresent.o `test -f 'plotpresent.c' || echo '$(srcdir)/'`plotpresent.c nip2-plotpresent.obj: plotpresent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotpresent.obj -MD -MP -MF $(DEPDIR)/nip2-plotpresent.Tpo -c -o nip2-plotpresent.obj `if test -f 'plotpresent.c'; then $(CYGPATH_W) 'plotpresent.c'; else $(CYGPATH_W) '$(srcdir)/plotpresent.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotpresent.Tpo $(DEPDIR)/nip2-plotpresent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotpresent.c' object='nip2-plotpresent.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotpresent.obj `if test -f 'plotpresent.c'; then $(CYGPATH_W) 'plotpresent.c'; else $(CYGPATH_W) '$(srcdir)/plotpresent.c'; fi` nip2-plotstatus.o: plotstatus.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotstatus.o -MD -MP -MF $(DEPDIR)/nip2-plotstatus.Tpo -c -o nip2-plotstatus.o `test -f 'plotstatus.c' || echo '$(srcdir)/'`plotstatus.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotstatus.Tpo $(DEPDIR)/nip2-plotstatus.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotstatus.c' object='nip2-plotstatus.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotstatus.o `test -f 'plotstatus.c' || echo '$(srcdir)/'`plotstatus.c nip2-plotstatus.obj: plotstatus.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotstatus.obj -MD -MP -MF $(DEPDIR)/nip2-plotstatus.Tpo -c -o nip2-plotstatus.obj `if test -f 'plotstatus.c'; then $(CYGPATH_W) 'plotstatus.c'; else $(CYGPATH_W) '$(srcdir)/plotstatus.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotstatus.Tpo $(DEPDIR)/nip2-plotstatus.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotstatus.c' object='nip2-plotstatus.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotstatus.obj `if test -f 'plotstatus.c'; then $(CYGPATH_W) 'plotstatus.c'; else $(CYGPATH_W) '$(srcdir)/plotstatus.c'; fi` nip2-floatwindow.o: floatwindow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-floatwindow.o -MD -MP -MF $(DEPDIR)/nip2-floatwindow.Tpo -c -o nip2-floatwindow.o `test -f 'floatwindow.c' || echo '$(srcdir)/'`floatwindow.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-floatwindow.Tpo $(DEPDIR)/nip2-floatwindow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='floatwindow.c' object='nip2-floatwindow.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-floatwindow.o `test -f 'floatwindow.c' || echo '$(srcdir)/'`floatwindow.c nip2-floatwindow.obj: floatwindow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-floatwindow.obj -MD -MP -MF $(DEPDIR)/nip2-floatwindow.Tpo -c -o nip2-floatwindow.obj `if test -f 'floatwindow.c'; then $(CYGPATH_W) 'floatwindow.c'; else $(CYGPATH_W) '$(srcdir)/floatwindow.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-floatwindow.Tpo $(DEPDIR)/nip2-floatwindow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='floatwindow.c' object='nip2-floatwindow.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-floatwindow.obj `if test -f 'floatwindow.c'; then $(CYGPATH_W) 'floatwindow.c'; else $(CYGPATH_W) '$(srcdir)/floatwindow.c'; fi` nip2-vobject.o: vobject.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-vobject.o -MD -MP -MF $(DEPDIR)/nip2-vobject.Tpo -c -o nip2-vobject.o `test -f 'vobject.c' || echo '$(srcdir)/'`vobject.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-vobject.Tpo $(DEPDIR)/nip2-vobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vobject.c' object='nip2-vobject.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-vobject.o `test -f 'vobject.c' || echo '$(srcdir)/'`vobject.c nip2-vobject.obj: vobject.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-vobject.obj -MD -MP -MF $(DEPDIR)/nip2-vobject.Tpo -c -o nip2-vobject.obj `if test -f 'vobject.c'; then $(CYGPATH_W) 'vobject.c'; else $(CYGPATH_W) '$(srcdir)/vobject.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-vobject.Tpo $(DEPDIR)/nip2-vobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vobject.c' object='nip2-vobject.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-vobject.obj `if test -f 'vobject.c'; then $(CYGPATH_W) 'vobject.c'; else $(CYGPATH_W) '$(srcdir)/vobject.c'; fi` nip2-action.o: action.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-action.o -MD -MP -MF $(DEPDIR)/nip2-action.Tpo -c -o nip2-action.o `test -f 'action.c' || echo '$(srcdir)/'`action.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-action.Tpo $(DEPDIR)/nip2-action.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='action.c' object='nip2-action.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-action.o `test -f 'action.c' || echo '$(srcdir)/'`action.c nip2-action.obj: action.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-action.obj -MD -MP -MF $(DEPDIR)/nip2-action.Tpo -c -o nip2-action.obj `if test -f 'action.c'; then $(CYGPATH_W) 'action.c'; else $(CYGPATH_W) '$(srcdir)/action.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-action.Tpo $(DEPDIR)/nip2-action.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='action.c' object='nip2-action.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-action.obj `if test -f 'action.c'; then $(CYGPATH_W) 'action.c'; else $(CYGPATH_W) '$(srcdir)/action.c'; fi` nip2-boxes.o: boxes.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-boxes.o -MD -MP -MF $(DEPDIR)/nip2-boxes.Tpo -c -o nip2-boxes.o `test -f 'boxes.c' || echo '$(srcdir)/'`boxes.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-boxes.Tpo $(DEPDIR)/nip2-boxes.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='boxes.c' object='nip2-boxes.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-boxes.o `test -f 'boxes.c' || echo '$(srcdir)/'`boxes.c nip2-boxes.obj: boxes.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-boxes.obj -MD -MP -MF $(DEPDIR)/nip2-boxes.Tpo -c -o nip2-boxes.obj `if test -f 'boxes.c'; then $(CYGPATH_W) 'boxes.c'; else $(CYGPATH_W) '$(srcdir)/boxes.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-boxes.Tpo $(DEPDIR)/nip2-boxes.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='boxes.c' object='nip2-boxes.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-boxes.obj `if test -f 'boxes.c'; then $(CYGPATH_W) 'boxes.c'; else $(CYGPATH_W) '$(srcdir)/boxes.c'; fi` nip2-popupbutton.o: popupbutton.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-popupbutton.o -MD -MP -MF $(DEPDIR)/nip2-popupbutton.Tpo -c -o nip2-popupbutton.o `test -f 'popupbutton.c' || echo '$(srcdir)/'`popupbutton.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-popupbutton.Tpo $(DEPDIR)/nip2-popupbutton.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='popupbutton.c' object='nip2-popupbutton.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-popupbutton.o `test -f 'popupbutton.c' || echo '$(srcdir)/'`popupbutton.c nip2-popupbutton.obj: popupbutton.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-popupbutton.obj -MD -MP -MF $(DEPDIR)/nip2-popupbutton.Tpo -c -o nip2-popupbutton.obj `if test -f 'popupbutton.c'; then $(CYGPATH_W) 'popupbutton.c'; else $(CYGPATH_W) '$(srcdir)/popupbutton.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-popupbutton.Tpo $(DEPDIR)/nip2-popupbutton.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='popupbutton.c' object='nip2-popupbutton.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-popupbutton.obj `if test -f 'popupbutton.c'; then $(CYGPATH_W) 'popupbutton.c'; else $(CYGPATH_W) '$(srcdir)/popupbutton.c'; fi` nip2-imageheader.o: imageheader.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imageheader.o -MD -MP -MF $(DEPDIR)/nip2-imageheader.Tpo -c -o nip2-imageheader.o `test -f 'imageheader.c' || echo '$(srcdir)/'`imageheader.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imageheader.Tpo $(DEPDIR)/nip2-imageheader.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imageheader.c' object='nip2-imageheader.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imageheader.o `test -f 'imageheader.c' || echo '$(srcdir)/'`imageheader.c nip2-imageheader.obj: imageheader.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imageheader.obj -MD -MP -MF $(DEPDIR)/nip2-imageheader.Tpo -c -o nip2-imageheader.obj `if test -f 'imageheader.c'; then $(CYGPATH_W) 'imageheader.c'; else $(CYGPATH_W) '$(srcdir)/imageheader.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imageheader.Tpo $(DEPDIR)/nip2-imageheader.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imageheader.c' object='nip2-imageheader.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imageheader.obj `if test -f 'imageheader.c'; then $(CYGPATH_W) 'imageheader.c'; else $(CYGPATH_W) '$(srcdir)/imageheader.c'; fi` nip2-preview.o: preview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-preview.o -MD -MP -MF $(DEPDIR)/nip2-preview.Tpo -c -o nip2-preview.o `test -f 'preview.c' || echo '$(srcdir)/'`preview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-preview.Tpo $(DEPDIR)/nip2-preview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='preview.c' object='nip2-preview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-preview.o `test -f 'preview.c' || echo '$(srcdir)/'`preview.c nip2-preview.obj: preview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-preview.obj -MD -MP -MF $(DEPDIR)/nip2-preview.Tpo -c -o nip2-preview.obj `if test -f 'preview.c'; then $(CYGPATH_W) 'preview.c'; else $(CYGPATH_W) '$(srcdir)/preview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-preview.Tpo $(DEPDIR)/nip2-preview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='preview.c' object='nip2-preview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-preview.obj `if test -f 'preview.c'; then $(CYGPATH_W) 'preview.c'; else $(CYGPATH_W) '$(srcdir)/preview.c'; fi` nip2-builtin.o: builtin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-builtin.o -MD -MP -MF $(DEPDIR)/nip2-builtin.Tpo -c -o nip2-builtin.o `test -f 'builtin.c' || echo '$(srcdir)/'`builtin.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-builtin.Tpo $(DEPDIR)/nip2-builtin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='builtin.c' object='nip2-builtin.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-builtin.o `test -f 'builtin.c' || echo '$(srcdir)/'`builtin.c nip2-builtin.obj: builtin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-builtin.obj -MD -MP -MF $(DEPDIR)/nip2-builtin.Tpo -c -o nip2-builtin.obj `if test -f 'builtin.c'; then $(CYGPATH_W) 'builtin.c'; else $(CYGPATH_W) '$(srcdir)/builtin.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-builtin.Tpo $(DEPDIR)/nip2-builtin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='builtin.c' object='nip2-builtin.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-builtin.obj `if test -f 'builtin.c'; then $(CYGPATH_W) 'builtin.c'; else $(CYGPATH_W) '$(srcdir)/builtin.c'; fi` nip2-icontainer.o: icontainer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-icontainer.o -MD -MP -MF $(DEPDIR)/nip2-icontainer.Tpo -c -o nip2-icontainer.o `test -f 'icontainer.c' || echo '$(srcdir)/'`icontainer.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-icontainer.Tpo $(DEPDIR)/nip2-icontainer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='icontainer.c' object='nip2-icontainer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-icontainer.o `test -f 'icontainer.c' || echo '$(srcdir)/'`icontainer.c nip2-icontainer.obj: icontainer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-icontainer.obj -MD -MP -MF $(DEPDIR)/nip2-icontainer.Tpo -c -o nip2-icontainer.obj `if test -f 'icontainer.c'; then $(CYGPATH_W) 'icontainer.c'; else $(CYGPATH_W) '$(srcdir)/icontainer.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-icontainer.Tpo $(DEPDIR)/nip2-icontainer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='icontainer.c' object='nip2-icontainer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-icontainer.obj `if test -f 'icontainer.c'; then $(CYGPATH_W) 'icontainer.c'; else $(CYGPATH_W) '$(srcdir)/icontainer.c'; fi` nip2-iobject.o: iobject.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iobject.o -MD -MP -MF $(DEPDIR)/nip2-iobject.Tpo -c -o nip2-iobject.o `test -f 'iobject.c' || echo '$(srcdir)/'`iobject.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iobject.Tpo $(DEPDIR)/nip2-iobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iobject.c' object='nip2-iobject.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iobject.o `test -f 'iobject.c' || echo '$(srcdir)/'`iobject.c nip2-iobject.obj: iobject.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iobject.obj -MD -MP -MF $(DEPDIR)/nip2-iobject.Tpo -c -o nip2-iobject.obj `if test -f 'iobject.c'; then $(CYGPATH_W) 'iobject.c'; else $(CYGPATH_W) '$(srcdir)/iobject.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iobject.Tpo $(DEPDIR)/nip2-iobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iobject.c' object='nip2-iobject.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iobject.obj `if test -f 'iobject.c'; then $(CYGPATH_W) 'iobject.c'; else $(CYGPATH_W) '$(srcdir)/iobject.c'; fi` nip2-class.o: class.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-class.o -MD -MP -MF $(DEPDIR)/nip2-class.Tpo -c -o nip2-class.o `test -f 'class.c' || echo '$(srcdir)/'`class.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-class.Tpo $(DEPDIR)/nip2-class.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='class.c' object='nip2-class.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-class.o `test -f 'class.c' || echo '$(srcdir)/'`class.c nip2-class.obj: class.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-class.obj -MD -MP -MF $(DEPDIR)/nip2-class.Tpo -c -o nip2-class.obj `if test -f 'class.c'; then $(CYGPATH_W) 'class.c'; else $(CYGPATH_W) '$(srcdir)/class.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-class.Tpo $(DEPDIR)/nip2-class.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='class.c' object='nip2-class.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-class.obj `if test -f 'class.c'; then $(CYGPATH_W) 'class.c'; else $(CYGPATH_W) '$(srcdir)/class.c'; fi` nip2-classmodel.o: classmodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-classmodel.o -MD -MP -MF $(DEPDIR)/nip2-classmodel.Tpo -c -o nip2-classmodel.o `test -f 'classmodel.c' || echo '$(srcdir)/'`classmodel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-classmodel.Tpo $(DEPDIR)/nip2-classmodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='classmodel.c' object='nip2-classmodel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-classmodel.o `test -f 'classmodel.c' || echo '$(srcdir)/'`classmodel.c nip2-classmodel.obj: classmodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-classmodel.obj -MD -MP -MF $(DEPDIR)/nip2-classmodel.Tpo -c -o nip2-classmodel.obj `if test -f 'classmodel.c'; then $(CYGPATH_W) 'classmodel.c'; else $(CYGPATH_W) '$(srcdir)/classmodel.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-classmodel.Tpo $(DEPDIR)/nip2-classmodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='classmodel.c' object='nip2-classmodel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-classmodel.obj `if test -f 'classmodel.c'; then $(CYGPATH_W) 'classmodel.c'; else $(CYGPATH_W) '$(srcdir)/classmodel.c'; fi` nip2-colour.o: colour.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-colour.o -MD -MP -MF $(DEPDIR)/nip2-colour.Tpo -c -o nip2-colour.o `test -f 'colour.c' || echo '$(srcdir)/'`colour.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-colour.Tpo $(DEPDIR)/nip2-colour.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='colour.c' object='nip2-colour.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-colour.o `test -f 'colour.c' || echo '$(srcdir)/'`colour.c nip2-colour.obj: colour.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-colour.obj -MD -MP -MF $(DEPDIR)/nip2-colour.Tpo -c -o nip2-colour.obj `if test -f 'colour.c'; then $(CYGPATH_W) 'colour.c'; else $(CYGPATH_W) '$(srcdir)/colour.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-colour.Tpo $(DEPDIR)/nip2-colour.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='colour.c' object='nip2-colour.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-colour.obj `if test -f 'colour.c'; then $(CYGPATH_W) 'colour.c'; else $(CYGPATH_W) '$(srcdir)/colour.c'; fi` nip2-colourdisplay.o: colourdisplay.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-colourdisplay.o -MD -MP -MF $(DEPDIR)/nip2-colourdisplay.Tpo -c -o nip2-colourdisplay.o `test -f 'colourdisplay.c' || echo '$(srcdir)/'`colourdisplay.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-colourdisplay.Tpo $(DEPDIR)/nip2-colourdisplay.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='colourdisplay.c' object='nip2-colourdisplay.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-colourdisplay.o `test -f 'colourdisplay.c' || echo '$(srcdir)/'`colourdisplay.c nip2-colourdisplay.obj: colourdisplay.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-colourdisplay.obj -MD -MP -MF $(DEPDIR)/nip2-colourdisplay.Tpo -c -o nip2-colourdisplay.obj `if test -f 'colourdisplay.c'; then $(CYGPATH_W) 'colourdisplay.c'; else $(CYGPATH_W) '$(srcdir)/colourdisplay.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-colourdisplay.Tpo $(DEPDIR)/nip2-colourdisplay.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='colourdisplay.c' object='nip2-colourdisplay.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-colourdisplay.obj `if test -f 'colourdisplay.c'; then $(CYGPATH_W) 'colourdisplay.c'; else $(CYGPATH_W) '$(srcdir)/colourdisplay.c'; fi` nip2-colourview.o: colourview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-colourview.o -MD -MP -MF $(DEPDIR)/nip2-colourview.Tpo -c -o nip2-colourview.o `test -f 'colourview.c' || echo '$(srcdir)/'`colourview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-colourview.Tpo $(DEPDIR)/nip2-colourview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='colourview.c' object='nip2-colourview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-colourview.o `test -f 'colourview.c' || echo '$(srcdir)/'`colourview.c nip2-colourview.obj: colourview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-colourview.obj -MD -MP -MF $(DEPDIR)/nip2-colourview.Tpo -c -o nip2-colourview.obj `if test -f 'colourview.c'; then $(CYGPATH_W) 'colourview.c'; else $(CYGPATH_W) '$(srcdir)/colourview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-colourview.Tpo $(DEPDIR)/nip2-colourview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='colourview.c' object='nip2-colourview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-colourview.obj `if test -f 'colourview.c'; then $(CYGPATH_W) 'colourview.c'; else $(CYGPATH_W) '$(srcdir)/colourview.c'; fi` nip2-column.o: column.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-column.o -MD -MP -MF $(DEPDIR)/nip2-column.Tpo -c -o nip2-column.o `test -f 'column.c' || echo '$(srcdir)/'`column.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-column.Tpo $(DEPDIR)/nip2-column.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='column.c' object='nip2-column.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-column.o `test -f 'column.c' || echo '$(srcdir)/'`column.c nip2-column.obj: column.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-column.obj -MD -MP -MF $(DEPDIR)/nip2-column.Tpo -c -o nip2-column.obj `if test -f 'column.c'; then $(CYGPATH_W) 'column.c'; else $(CYGPATH_W) '$(srcdir)/column.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-column.Tpo $(DEPDIR)/nip2-column.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='column.c' object='nip2-column.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-column.obj `if test -f 'column.c'; then $(CYGPATH_W) 'column.c'; else $(CYGPATH_W) '$(srcdir)/column.c'; fi` nip2-columnview.o: columnview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-columnview.o -MD -MP -MF $(DEPDIR)/nip2-columnview.Tpo -c -o nip2-columnview.o `test -f 'columnview.c' || echo '$(srcdir)/'`columnview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-columnview.Tpo $(DEPDIR)/nip2-columnview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='columnview.c' object='nip2-columnview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-columnview.o `test -f 'columnview.c' || echo '$(srcdir)/'`columnview.c nip2-columnview.obj: columnview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-columnview.obj -MD -MP -MF $(DEPDIR)/nip2-columnview.Tpo -c -o nip2-columnview.obj `if test -f 'columnview.c'; then $(CYGPATH_W) 'columnview.c'; else $(CYGPATH_W) '$(srcdir)/columnview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-columnview.Tpo $(DEPDIR)/nip2-columnview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='columnview.c' object='nip2-columnview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-columnview.obj `if test -f 'columnview.c'; then $(CYGPATH_W) 'columnview.c'; else $(CYGPATH_W) '$(srcdir)/columnview.c'; fi` nip2-compile.o: compile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-compile.o -MD -MP -MF $(DEPDIR)/nip2-compile.Tpo -c -o nip2-compile.o `test -f 'compile.c' || echo '$(srcdir)/'`compile.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-compile.Tpo $(DEPDIR)/nip2-compile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compile.c' object='nip2-compile.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-compile.o `test -f 'compile.c' || echo '$(srcdir)/'`compile.c nip2-compile.obj: compile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-compile.obj -MD -MP -MF $(DEPDIR)/nip2-compile.Tpo -c -o nip2-compile.obj `if test -f 'compile.c'; then $(CYGPATH_W) 'compile.c'; else $(CYGPATH_W) '$(srcdir)/compile.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-compile.Tpo $(DEPDIR)/nip2-compile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='compile.c' object='nip2-compile.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-compile.obj `if test -f 'compile.c'; then $(CYGPATH_W) 'compile.c'; else $(CYGPATH_W) '$(srcdir)/compile.c'; fi` nip2-conversion.o: conversion.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-conversion.o -MD -MP -MF $(DEPDIR)/nip2-conversion.Tpo -c -o nip2-conversion.o `test -f 'conversion.c' || echo '$(srcdir)/'`conversion.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-conversion.Tpo $(DEPDIR)/nip2-conversion.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='conversion.c' object='nip2-conversion.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-conversion.o `test -f 'conversion.c' || echo '$(srcdir)/'`conversion.c nip2-conversion.obj: conversion.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-conversion.obj -MD -MP -MF $(DEPDIR)/nip2-conversion.Tpo -c -o nip2-conversion.obj `if test -f 'conversion.c'; then $(CYGPATH_W) 'conversion.c'; else $(CYGPATH_W) '$(srcdir)/conversion.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-conversion.Tpo $(DEPDIR)/nip2-conversion.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='conversion.c' object='nip2-conversion.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-conversion.obj `if test -f 'conversion.c'; then $(CYGPATH_W) 'conversion.c'; else $(CYGPATH_W) '$(srcdir)/conversion.c'; fi` nip2-conversionview.o: conversionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-conversionview.o -MD -MP -MF $(DEPDIR)/nip2-conversionview.Tpo -c -o nip2-conversionview.o `test -f 'conversionview.c' || echo '$(srcdir)/'`conversionview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-conversionview.Tpo $(DEPDIR)/nip2-conversionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='conversionview.c' object='nip2-conversionview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-conversionview.o `test -f 'conversionview.c' || echo '$(srcdir)/'`conversionview.c nip2-conversionview.obj: conversionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-conversionview.obj -MD -MP -MF $(DEPDIR)/nip2-conversionview.Tpo -c -o nip2-conversionview.obj `if test -f 'conversionview.c'; then $(CYGPATH_W) 'conversionview.c'; else $(CYGPATH_W) '$(srcdir)/conversionview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-conversionview.Tpo $(DEPDIR)/nip2-conversionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='conversionview.c' object='nip2-conversionview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-conversionview.obj `if test -f 'conversionview.c'; then $(CYGPATH_W) 'conversionview.c'; else $(CYGPATH_W) '$(srcdir)/conversionview.c'; fi` nip2-doubleclick.o: doubleclick.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-doubleclick.o -MD -MP -MF $(DEPDIR)/nip2-doubleclick.Tpo -c -o nip2-doubleclick.o `test -f 'doubleclick.c' || echo '$(srcdir)/'`doubleclick.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-doubleclick.Tpo $(DEPDIR)/nip2-doubleclick.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='doubleclick.c' object='nip2-doubleclick.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-doubleclick.o `test -f 'doubleclick.c' || echo '$(srcdir)/'`doubleclick.c nip2-doubleclick.obj: doubleclick.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-doubleclick.obj -MD -MP -MF $(DEPDIR)/nip2-doubleclick.Tpo -c -o nip2-doubleclick.obj `if test -f 'doubleclick.c'; then $(CYGPATH_W) 'doubleclick.c'; else $(CYGPATH_W) '$(srcdir)/doubleclick.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-doubleclick.Tpo $(DEPDIR)/nip2-doubleclick.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='doubleclick.c' object='nip2-doubleclick.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-doubleclick.obj `if test -f 'doubleclick.c'; then $(CYGPATH_W) 'doubleclick.c'; else $(CYGPATH_W) '$(srcdir)/doubleclick.c'; fi` nip2-dump.o: dump.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-dump.o -MD -MP -MF $(DEPDIR)/nip2-dump.Tpo -c -o nip2-dump.o `test -f 'dump.c' || echo '$(srcdir)/'`dump.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-dump.Tpo $(DEPDIR)/nip2-dump.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dump.c' object='nip2-dump.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-dump.o `test -f 'dump.c' || echo '$(srcdir)/'`dump.c nip2-dump.obj: dump.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-dump.obj -MD -MP -MF $(DEPDIR)/nip2-dump.Tpo -c -o nip2-dump.obj `if test -f 'dump.c'; then $(CYGPATH_W) 'dump.c'; else $(CYGPATH_W) '$(srcdir)/dump.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-dump.Tpo $(DEPDIR)/nip2-dump.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dump.c' object='nip2-dump.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-dump.obj `if test -f 'dump.c'; then $(CYGPATH_W) 'dump.c'; else $(CYGPATH_W) '$(srcdir)/dump.c'; fi` nip2-expr.o: expr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-expr.o -MD -MP -MF $(DEPDIR)/nip2-expr.Tpo -c -o nip2-expr.o `test -f 'expr.c' || echo '$(srcdir)/'`expr.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-expr.Tpo $(DEPDIR)/nip2-expr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='expr.c' object='nip2-expr.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-expr.o `test -f 'expr.c' || echo '$(srcdir)/'`expr.c nip2-expr.obj: expr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-expr.obj -MD -MP -MF $(DEPDIR)/nip2-expr.Tpo -c -o nip2-expr.obj `if test -f 'expr.c'; then $(CYGPATH_W) 'expr.c'; else $(CYGPATH_W) '$(srcdir)/expr.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-expr.Tpo $(DEPDIR)/nip2-expr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='expr.c' object='nip2-expr.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-expr.obj `if test -f 'expr.c'; then $(CYGPATH_W) 'expr.c'; else $(CYGPATH_W) '$(srcdir)/expr.c'; fi` nip2-filemodel.o: filemodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-filemodel.o -MD -MP -MF $(DEPDIR)/nip2-filemodel.Tpo -c -o nip2-filemodel.o `test -f 'filemodel.c' || echo '$(srcdir)/'`filemodel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-filemodel.Tpo $(DEPDIR)/nip2-filemodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='filemodel.c' object='nip2-filemodel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-filemodel.o `test -f 'filemodel.c' || echo '$(srcdir)/'`filemodel.c nip2-filemodel.obj: filemodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-filemodel.obj -MD -MP -MF $(DEPDIR)/nip2-filemodel.Tpo -c -o nip2-filemodel.obj `if test -f 'filemodel.c'; then $(CYGPATH_W) 'filemodel.c'; else $(CYGPATH_W) '$(srcdir)/filemodel.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-filemodel.Tpo $(DEPDIR)/nip2-filemodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='filemodel.c' object='nip2-filemodel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-filemodel.obj `if test -f 'filemodel.c'; then $(CYGPATH_W) 'filemodel.c'; else $(CYGPATH_W) '$(srcdir)/filemodel.c'; fi` nip2-pane.o: pane.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-pane.o -MD -MP -MF $(DEPDIR)/nip2-pane.Tpo -c -o nip2-pane.o `test -f 'pane.c' || echo '$(srcdir)/'`pane.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-pane.Tpo $(DEPDIR)/nip2-pane.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pane.c' object='nip2-pane.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-pane.o `test -f 'pane.c' || echo '$(srcdir)/'`pane.c nip2-pane.obj: pane.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-pane.obj -MD -MP -MF $(DEPDIR)/nip2-pane.Tpo -c -o nip2-pane.obj `if test -f 'pane.c'; then $(CYGPATH_W) 'pane.c'; else $(CYGPATH_W) '$(srcdir)/pane.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-pane.Tpo $(DEPDIR)/nip2-pane.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pane.c' object='nip2-pane.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-pane.obj `if test -f 'pane.c'; then $(CYGPATH_W) 'pane.c'; else $(CYGPATH_W) '$(srcdir)/pane.c'; fi` nip2-pathname.o: pathname.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-pathname.o -MD -MP -MF $(DEPDIR)/nip2-pathname.Tpo -c -o nip2-pathname.o `test -f 'pathname.c' || echo '$(srcdir)/'`pathname.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-pathname.Tpo $(DEPDIR)/nip2-pathname.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pathname.c' object='nip2-pathname.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-pathname.o `test -f 'pathname.c' || echo '$(srcdir)/'`pathname.c nip2-pathname.obj: pathname.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-pathname.obj -MD -MP -MF $(DEPDIR)/nip2-pathname.Tpo -c -o nip2-pathname.obj `if test -f 'pathname.c'; then $(CYGPATH_W) 'pathname.c'; else $(CYGPATH_W) '$(srcdir)/pathname.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-pathname.Tpo $(DEPDIR)/nip2-pathname.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pathname.c' object='nip2-pathname.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-pathname.obj `if test -f 'pathname.c'; then $(CYGPATH_W) 'pathname.c'; else $(CYGPATH_W) '$(srcdir)/pathname.c'; fi` nip2-fontname.o: fontname.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-fontname.o -MD -MP -MF $(DEPDIR)/nip2-fontname.Tpo -c -o nip2-fontname.o `test -f 'fontname.c' || echo '$(srcdir)/'`fontname.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-fontname.Tpo $(DEPDIR)/nip2-fontname.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fontname.c' object='nip2-fontname.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-fontname.o `test -f 'fontname.c' || echo '$(srcdir)/'`fontname.c nip2-fontname.obj: fontname.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-fontname.obj -MD -MP -MF $(DEPDIR)/nip2-fontname.Tpo -c -o nip2-fontname.obj `if test -f 'fontname.c'; then $(CYGPATH_W) 'fontname.c'; else $(CYGPATH_W) '$(srcdir)/fontname.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-fontname.Tpo $(DEPDIR)/nip2-fontname.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fontname.c' object='nip2-fontname.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-fontname.obj `if test -f 'fontname.c'; then $(CYGPATH_W) 'fontname.c'; else $(CYGPATH_W) '$(srcdir)/fontname.c'; fi` nip2-group.o: group.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-group.o -MD -MP -MF $(DEPDIR)/nip2-group.Tpo -c -o nip2-group.o `test -f 'group.c' || echo '$(srcdir)/'`group.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-group.Tpo $(DEPDIR)/nip2-group.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='group.c' object='nip2-group.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-group.o `test -f 'group.c' || echo '$(srcdir)/'`group.c nip2-group.obj: group.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-group.obj -MD -MP -MF $(DEPDIR)/nip2-group.Tpo -c -o nip2-group.obj `if test -f 'group.c'; then $(CYGPATH_W) 'group.c'; else $(CYGPATH_W) '$(srcdir)/group.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-group.Tpo $(DEPDIR)/nip2-group.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='group.c' object='nip2-group.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-group.obj `if test -f 'group.c'; then $(CYGPATH_W) 'group.c'; else $(CYGPATH_W) '$(srcdir)/group.c'; fi` nip2-pathnameview.o: pathnameview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-pathnameview.o -MD -MP -MF $(DEPDIR)/nip2-pathnameview.Tpo -c -o nip2-pathnameview.o `test -f 'pathnameview.c' || echo '$(srcdir)/'`pathnameview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-pathnameview.Tpo $(DEPDIR)/nip2-pathnameview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pathnameview.c' object='nip2-pathnameview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-pathnameview.o `test -f 'pathnameview.c' || echo '$(srcdir)/'`pathnameview.c nip2-pathnameview.obj: pathnameview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-pathnameview.obj -MD -MP -MF $(DEPDIR)/nip2-pathnameview.Tpo -c -o nip2-pathnameview.obj `if test -f 'pathnameview.c'; then $(CYGPATH_W) 'pathnameview.c'; else $(CYGPATH_W) '$(srcdir)/pathnameview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-pathnameview.Tpo $(DEPDIR)/nip2-pathnameview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pathnameview.c' object='nip2-pathnameview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-pathnameview.obj `if test -f 'pathnameview.c'; then $(CYGPATH_W) 'pathnameview.c'; else $(CYGPATH_W) '$(srcdir)/pathnameview.c'; fi` nip2-fontnameview.o: fontnameview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-fontnameview.o -MD -MP -MF $(DEPDIR)/nip2-fontnameview.Tpo -c -o nip2-fontnameview.o `test -f 'fontnameview.c' || echo '$(srcdir)/'`fontnameview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-fontnameview.Tpo $(DEPDIR)/nip2-fontnameview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fontnameview.c' object='nip2-fontnameview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-fontnameview.o `test -f 'fontnameview.c' || echo '$(srcdir)/'`fontnameview.c nip2-fontnameview.obj: fontnameview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-fontnameview.obj -MD -MP -MF $(DEPDIR)/nip2-fontnameview.Tpo -c -o nip2-fontnameview.obj `if test -f 'fontnameview.c'; then $(CYGPATH_W) 'fontnameview.c'; else $(CYGPATH_W) '$(srcdir)/fontnameview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-fontnameview.Tpo $(DEPDIR)/nip2-fontnameview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fontnameview.c' object='nip2-fontnameview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-fontnameview.obj `if test -f 'fontnameview.c'; then $(CYGPATH_W) 'fontnameview.c'; else $(CYGPATH_W) '$(srcdir)/fontnameview.c'; fi` nip2-filesel.o: filesel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-filesel.o -MD -MP -MF $(DEPDIR)/nip2-filesel.Tpo -c -o nip2-filesel.o `test -f 'filesel.c' || echo '$(srcdir)/'`filesel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-filesel.Tpo $(DEPDIR)/nip2-filesel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='filesel.c' object='nip2-filesel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-filesel.o `test -f 'filesel.c' || echo '$(srcdir)/'`filesel.c nip2-filesel.obj: filesel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-filesel.obj -MD -MP -MF $(DEPDIR)/nip2-filesel.Tpo -c -o nip2-filesel.obj `if test -f 'filesel.c'; then $(CYGPATH_W) 'filesel.c'; else $(CYGPATH_W) '$(srcdir)/filesel.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-filesel.Tpo $(DEPDIR)/nip2-filesel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='filesel.c' object='nip2-filesel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-filesel.obj `if test -f 'filesel.c'; then $(CYGPATH_W) 'filesel.c'; else $(CYGPATH_W) '$(srcdir)/filesel.c'; fi` nip2-graphwindow.o: graphwindow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-graphwindow.o -MD -MP -MF $(DEPDIR)/nip2-graphwindow.Tpo -c -o nip2-graphwindow.o `test -f 'graphwindow.c' || echo '$(srcdir)/'`graphwindow.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-graphwindow.Tpo $(DEPDIR)/nip2-graphwindow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='graphwindow.c' object='nip2-graphwindow.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-graphwindow.o `test -f 'graphwindow.c' || echo '$(srcdir)/'`graphwindow.c nip2-graphwindow.obj: graphwindow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-graphwindow.obj -MD -MP -MF $(DEPDIR)/nip2-graphwindow.Tpo -c -o nip2-graphwindow.obj `if test -f 'graphwindow.c'; then $(CYGPATH_W) 'graphwindow.c'; else $(CYGPATH_W) '$(srcdir)/graphwindow.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-graphwindow.Tpo $(DEPDIR)/nip2-graphwindow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='graphwindow.c' object='nip2-graphwindow.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-graphwindow.obj `if test -f 'graphwindow.c'; then $(CYGPATH_W) 'graphwindow.c'; else $(CYGPATH_W) '$(srcdir)/graphwindow.c'; fi` nip2-graphicview.o: graphicview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-graphicview.o -MD -MP -MF $(DEPDIR)/nip2-graphicview.Tpo -c -o nip2-graphicview.o `test -f 'graphicview.c' || echo '$(srcdir)/'`graphicview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-graphicview.Tpo $(DEPDIR)/nip2-graphicview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='graphicview.c' object='nip2-graphicview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-graphicview.o `test -f 'graphicview.c' || echo '$(srcdir)/'`graphicview.c nip2-graphicview.obj: graphicview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-graphicview.obj -MD -MP -MF $(DEPDIR)/nip2-graphicview.Tpo -c -o nip2-graphicview.obj `if test -f 'graphicview.c'; then $(CYGPATH_W) 'graphicview.c'; else $(CYGPATH_W) '$(srcdir)/graphicview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-graphicview.Tpo $(DEPDIR)/nip2-graphicview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='graphicview.c' object='nip2-graphicview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-graphicview.obj `if test -f 'graphicview.c'; then $(CYGPATH_W) 'graphicview.c'; else $(CYGPATH_W) '$(srcdir)/graphicview.c'; fi` nip2-gtkutil.o: gtkutil.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-gtkutil.o -MD -MP -MF $(DEPDIR)/nip2-gtkutil.Tpo -c -o nip2-gtkutil.o `test -f 'gtkutil.c' || echo '$(srcdir)/'`gtkutil.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-gtkutil.Tpo $(DEPDIR)/nip2-gtkutil.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gtkutil.c' object='nip2-gtkutil.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-gtkutil.o `test -f 'gtkutil.c' || echo '$(srcdir)/'`gtkutil.c nip2-gtkutil.obj: gtkutil.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-gtkutil.obj -MD -MP -MF $(DEPDIR)/nip2-gtkutil.Tpo -c -o nip2-gtkutil.obj `if test -f 'gtkutil.c'; then $(CYGPATH_W) 'gtkutil.c'; else $(CYGPATH_W) '$(srcdir)/gtkutil.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-gtkutil.Tpo $(DEPDIR)/nip2-gtkutil.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gtkutil.c' object='nip2-gtkutil.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-gtkutil.obj `if test -f 'gtkutil.c'; then $(CYGPATH_W) 'gtkutil.c'; else $(CYGPATH_W) '$(srcdir)/gtkutil.c'; fi` nip2-heap.o: heap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-heap.o -MD -MP -MF $(DEPDIR)/nip2-heap.Tpo -c -o nip2-heap.o `test -f 'heap.c' || echo '$(srcdir)/'`heap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-heap.Tpo $(DEPDIR)/nip2-heap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='heap.c' object='nip2-heap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-heap.o `test -f 'heap.c' || echo '$(srcdir)/'`heap.c nip2-heap.obj: heap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-heap.obj -MD -MP -MF $(DEPDIR)/nip2-heap.Tpo -c -o nip2-heap.obj `if test -f 'heap.c'; then $(CYGPATH_W) 'heap.c'; else $(CYGPATH_W) '$(srcdir)/heap.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-heap.Tpo $(DEPDIR)/nip2-heap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='heap.c' object='nip2-heap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-heap.obj `if test -f 'heap.c'; then $(CYGPATH_W) 'heap.c'; else $(CYGPATH_W) '$(srcdir)/heap.c'; fi` nip2-heapmodel.o: heapmodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-heapmodel.o -MD -MP -MF $(DEPDIR)/nip2-heapmodel.Tpo -c -o nip2-heapmodel.o `test -f 'heapmodel.c' || echo '$(srcdir)/'`heapmodel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-heapmodel.Tpo $(DEPDIR)/nip2-heapmodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='heapmodel.c' object='nip2-heapmodel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-heapmodel.o `test -f 'heapmodel.c' || echo '$(srcdir)/'`heapmodel.c nip2-heapmodel.obj: heapmodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-heapmodel.obj -MD -MP -MF $(DEPDIR)/nip2-heapmodel.Tpo -c -o nip2-heapmodel.obj `if test -f 'heapmodel.c'; then $(CYGPATH_W) 'heapmodel.c'; else $(CYGPATH_W) '$(srcdir)/heapmodel.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-heapmodel.Tpo $(DEPDIR)/nip2-heapmodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='heapmodel.c' object='nip2-heapmodel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-heapmodel.obj `if test -f 'heapmodel.c'; then $(CYGPATH_W) 'heapmodel.c'; else $(CYGPATH_W) '$(srcdir)/heapmodel.c'; fi` nip2-nipmarshal.o: nipmarshal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-nipmarshal.o -MD -MP -MF $(DEPDIR)/nip2-nipmarshal.Tpo -c -o nip2-nipmarshal.o `test -f 'nipmarshal.c' || echo '$(srcdir)/'`nipmarshal.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-nipmarshal.Tpo $(DEPDIR)/nip2-nipmarshal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nipmarshal.c' object='nip2-nipmarshal.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-nipmarshal.o `test -f 'nipmarshal.c' || echo '$(srcdir)/'`nipmarshal.c nip2-nipmarshal.obj: nipmarshal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-nipmarshal.obj -MD -MP -MF $(DEPDIR)/nip2-nipmarshal.Tpo -c -o nip2-nipmarshal.obj `if test -f 'nipmarshal.c'; then $(CYGPATH_W) 'nipmarshal.c'; else $(CYGPATH_W) '$(srcdir)/nipmarshal.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-nipmarshal.Tpo $(DEPDIR)/nip2-nipmarshal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nipmarshal.c' object='nip2-nipmarshal.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-nipmarshal.obj `if test -f 'nipmarshal.c'; then $(CYGPATH_W) 'nipmarshal.c'; else $(CYGPATH_W) '$(srcdir)/nipmarshal.c'; fi` nip2-iarrow.o: iarrow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iarrow.o -MD -MP -MF $(DEPDIR)/nip2-iarrow.Tpo -c -o nip2-iarrow.o `test -f 'iarrow.c' || echo '$(srcdir)/'`iarrow.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iarrow.Tpo $(DEPDIR)/nip2-iarrow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iarrow.c' object='nip2-iarrow.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iarrow.o `test -f 'iarrow.c' || echo '$(srcdir)/'`iarrow.c nip2-iarrow.obj: iarrow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iarrow.obj -MD -MP -MF $(DEPDIR)/nip2-iarrow.Tpo -c -o nip2-iarrow.obj `if test -f 'iarrow.c'; then $(CYGPATH_W) 'iarrow.c'; else $(CYGPATH_W) '$(srcdir)/iarrow.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iarrow.Tpo $(DEPDIR)/nip2-iarrow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iarrow.c' object='nip2-iarrow.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iarrow.obj `if test -f 'iarrow.c'; then $(CYGPATH_W) 'iarrow.c'; else $(CYGPATH_W) '$(srcdir)/iarrow.c'; fi` nip2-value.o: value.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-value.o -MD -MP -MF $(DEPDIR)/nip2-value.Tpo -c -o nip2-value.o `test -f 'value.c' || echo '$(srcdir)/'`value.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-value.Tpo $(DEPDIR)/nip2-value.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='value.c' object='nip2-value.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-value.o `test -f 'value.c' || echo '$(srcdir)/'`value.c nip2-value.obj: value.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-value.obj -MD -MP -MF $(DEPDIR)/nip2-value.Tpo -c -o nip2-value.obj `if test -f 'value.c'; then $(CYGPATH_W) 'value.c'; else $(CYGPATH_W) '$(srcdir)/value.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-value.Tpo $(DEPDIR)/nip2-value.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='value.c' object='nip2-value.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-value.obj `if test -f 'value.c'; then $(CYGPATH_W) 'value.c'; else $(CYGPATH_W) '$(srcdir)/value.c'; fi` nip2-valueview.o: valueview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-valueview.o -MD -MP -MF $(DEPDIR)/nip2-valueview.Tpo -c -o nip2-valueview.o `test -f 'valueview.c' || echo '$(srcdir)/'`valueview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-valueview.Tpo $(DEPDIR)/nip2-valueview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='valueview.c' object='nip2-valueview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-valueview.o `test -f 'valueview.c' || echo '$(srcdir)/'`valueview.c nip2-valueview.obj: valueview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-valueview.obj -MD -MP -MF $(DEPDIR)/nip2-valueview.Tpo -c -o nip2-valueview.obj `if test -f 'valueview.c'; then $(CYGPATH_W) 'valueview.c'; else $(CYGPATH_W) '$(srcdir)/valueview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-valueview.Tpo $(DEPDIR)/nip2-valueview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='valueview.c' object='nip2-valueview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-valueview.obj `if test -f 'valueview.c'; then $(CYGPATH_W) 'valueview.c'; else $(CYGPATH_W) '$(srcdir)/valueview.c'; fi` nip2-idialog.o: idialog.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-idialog.o -MD -MP -MF $(DEPDIR)/nip2-idialog.Tpo -c -o nip2-idialog.o `test -f 'idialog.c' || echo '$(srcdir)/'`idialog.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-idialog.Tpo $(DEPDIR)/nip2-idialog.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='idialog.c' object='nip2-idialog.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-idialog.o `test -f 'idialog.c' || echo '$(srcdir)/'`idialog.c nip2-idialog.obj: idialog.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-idialog.obj -MD -MP -MF $(DEPDIR)/nip2-idialog.Tpo -c -o nip2-idialog.obj `if test -f 'idialog.c'; then $(CYGPATH_W) 'idialog.c'; else $(CYGPATH_W) '$(srcdir)/idialog.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-idialog.Tpo $(DEPDIR)/nip2-idialog.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='idialog.c' object='nip2-idialog.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-idialog.obj `if test -f 'idialog.c'; then $(CYGPATH_W) 'idialog.c'; else $(CYGPATH_W) '$(srcdir)/idialog.c'; fi` nip2-iimage.o: iimage.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iimage.o -MD -MP -MF $(DEPDIR)/nip2-iimage.Tpo -c -o nip2-iimage.o `test -f 'iimage.c' || echo '$(srcdir)/'`iimage.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iimage.Tpo $(DEPDIR)/nip2-iimage.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iimage.c' object='nip2-iimage.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iimage.o `test -f 'iimage.c' || echo '$(srcdir)/'`iimage.c nip2-iimage.obj: iimage.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iimage.obj -MD -MP -MF $(DEPDIR)/nip2-iimage.Tpo -c -o nip2-iimage.obj `if test -f 'iimage.c'; then $(CYGPATH_W) 'iimage.c'; else $(CYGPATH_W) '$(srcdir)/iimage.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iimage.Tpo $(DEPDIR)/nip2-iimage.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iimage.c' object='nip2-iimage.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iimage.obj `if test -f 'iimage.c'; then $(CYGPATH_W) 'iimage.c'; else $(CYGPATH_W) '$(srcdir)/iimage.c'; fi` nip2-iimageview.o: iimageview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iimageview.o -MD -MP -MF $(DEPDIR)/nip2-iimageview.Tpo -c -o nip2-iimageview.o `test -f 'iimageview.c' || echo '$(srcdir)/'`iimageview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iimageview.Tpo $(DEPDIR)/nip2-iimageview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iimageview.c' object='nip2-iimageview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iimageview.o `test -f 'iimageview.c' || echo '$(srcdir)/'`iimageview.c nip2-iimageview.obj: iimageview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iimageview.obj -MD -MP -MF $(DEPDIR)/nip2-iimageview.Tpo -c -o nip2-iimageview.obj `if test -f 'iimageview.c'; then $(CYGPATH_W) 'iimageview.c'; else $(CYGPATH_W) '$(srcdir)/iimageview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iimageview.Tpo $(DEPDIR)/nip2-iimageview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iimageview.c' object='nip2-iimageview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iimageview.obj `if test -f 'iimageview.c'; then $(CYGPATH_W) 'iimageview.c'; else $(CYGPATH_W) '$(srcdir)/iimageview.c'; fi` nip2-imagedisplay.o: imagedisplay.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imagedisplay.o -MD -MP -MF $(DEPDIR)/nip2-imagedisplay.Tpo -c -o nip2-imagedisplay.o `test -f 'imagedisplay.c' || echo '$(srcdir)/'`imagedisplay.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imagedisplay.Tpo $(DEPDIR)/nip2-imagedisplay.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imagedisplay.c' object='nip2-imagedisplay.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imagedisplay.o `test -f 'imagedisplay.c' || echo '$(srcdir)/'`imagedisplay.c nip2-imagedisplay.obj: imagedisplay.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imagedisplay.obj -MD -MP -MF $(DEPDIR)/nip2-imagedisplay.Tpo -c -o nip2-imagedisplay.obj `if test -f 'imagedisplay.c'; then $(CYGPATH_W) 'imagedisplay.c'; else $(CYGPATH_W) '$(srcdir)/imagedisplay.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imagedisplay.Tpo $(DEPDIR)/nip2-imagedisplay.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imagedisplay.c' object='nip2-imagedisplay.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imagedisplay.obj `if test -f 'imagedisplay.c'; then $(CYGPATH_W) 'imagedisplay.c'; else $(CYGPATH_W) '$(srcdir)/imagedisplay.c'; fi` nip2-log.o: log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-log.o -MD -MP -MF $(DEPDIR)/nip2-log.Tpo -c -o nip2-log.o `test -f 'log.c' || echo '$(srcdir)/'`log.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-log.Tpo $(DEPDIR)/nip2-log.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='nip2-log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-log.o `test -f 'log.c' || echo '$(srcdir)/'`log.c nip2-log.obj: log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-log.obj -MD -MP -MF $(DEPDIR)/nip2-log.Tpo -c -o nip2-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-log.Tpo $(DEPDIR)/nip2-log.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='nip2-log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-log.obj `if test -f 'log.c'; then $(CYGPATH_W) 'log.c'; else $(CYGPATH_W) '$(srcdir)/log.c'; fi` nip2-error.o: error.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-error.o -MD -MP -MF $(DEPDIR)/nip2-error.Tpo -c -o nip2-error.o `test -f 'error.c' || echo '$(srcdir)/'`error.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-error.Tpo $(DEPDIR)/nip2-error.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='error.c' object='nip2-error.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-error.o `test -f 'error.c' || echo '$(srcdir)/'`error.c nip2-error.obj: error.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-error.obj -MD -MP -MF $(DEPDIR)/nip2-error.Tpo -c -o nip2-error.obj `if test -f 'error.c'; then $(CYGPATH_W) 'error.c'; else $(CYGPATH_W) '$(srcdir)/error.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-error.Tpo $(DEPDIR)/nip2-error.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='error.c' object='nip2-error.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-error.obj `if test -f 'error.c'; then $(CYGPATH_W) 'error.c'; else $(CYGPATH_W) '$(srcdir)/error.c'; fi` nip2-managed.o: managed.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managed.o -MD -MP -MF $(DEPDIR)/nip2-managed.Tpo -c -o nip2-managed.o `test -f 'managed.c' || echo '$(srcdir)/'`managed.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managed.Tpo $(DEPDIR)/nip2-managed.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managed.c' object='nip2-managed.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managed.o `test -f 'managed.c' || echo '$(srcdir)/'`managed.c nip2-managed.obj: managed.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managed.obj -MD -MP -MF $(DEPDIR)/nip2-managed.Tpo -c -o nip2-managed.obj `if test -f 'managed.c'; then $(CYGPATH_W) 'managed.c'; else $(CYGPATH_W) '$(srcdir)/managed.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managed.Tpo $(DEPDIR)/nip2-managed.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managed.c' object='nip2-managed.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managed.obj `if test -f 'managed.c'; then $(CYGPATH_W) 'managed.c'; else $(CYGPATH_W) '$(srcdir)/managed.c'; fi` nip2-managedfile.o: managedfile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managedfile.o -MD -MP -MF $(DEPDIR)/nip2-managedfile.Tpo -c -o nip2-managedfile.o `test -f 'managedfile.c' || echo '$(srcdir)/'`managedfile.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managedfile.Tpo $(DEPDIR)/nip2-managedfile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managedfile.c' object='nip2-managedfile.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managedfile.o `test -f 'managedfile.c' || echo '$(srcdir)/'`managedfile.c nip2-managedfile.obj: managedfile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managedfile.obj -MD -MP -MF $(DEPDIR)/nip2-managedfile.Tpo -c -o nip2-managedfile.obj `if test -f 'managedfile.c'; then $(CYGPATH_W) 'managedfile.c'; else $(CYGPATH_W) '$(srcdir)/managedfile.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managedfile.Tpo $(DEPDIR)/nip2-managedfile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managedfile.c' object='nip2-managedfile.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managedfile.obj `if test -f 'managedfile.c'; then $(CYGPATH_W) 'managedfile.c'; else $(CYGPATH_W) '$(srcdir)/managedfile.c'; fi` nip2-managedgvalue.o: managedgvalue.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managedgvalue.o -MD -MP -MF $(DEPDIR)/nip2-managedgvalue.Tpo -c -o nip2-managedgvalue.o `test -f 'managedgvalue.c' || echo '$(srcdir)/'`managedgvalue.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managedgvalue.Tpo $(DEPDIR)/nip2-managedgvalue.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managedgvalue.c' object='nip2-managedgvalue.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managedgvalue.o `test -f 'managedgvalue.c' || echo '$(srcdir)/'`managedgvalue.c nip2-managedgvalue.obj: managedgvalue.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managedgvalue.obj -MD -MP -MF $(DEPDIR)/nip2-managedgvalue.Tpo -c -o nip2-managedgvalue.obj `if test -f 'managedgvalue.c'; then $(CYGPATH_W) 'managedgvalue.c'; else $(CYGPATH_W) '$(srcdir)/managedgvalue.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managedgvalue.Tpo $(DEPDIR)/nip2-managedgvalue.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managedgvalue.c' object='nip2-managedgvalue.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managedgvalue.obj `if test -f 'managedgvalue.c'; then $(CYGPATH_W) 'managedgvalue.c'; else $(CYGPATH_W) '$(srcdir)/managedgvalue.c'; fi` nip2-managedgobject.o: managedgobject.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managedgobject.o -MD -MP -MF $(DEPDIR)/nip2-managedgobject.Tpo -c -o nip2-managedgobject.o `test -f 'managedgobject.c' || echo '$(srcdir)/'`managedgobject.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managedgobject.Tpo $(DEPDIR)/nip2-managedgobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managedgobject.c' object='nip2-managedgobject.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managedgobject.o `test -f 'managedgobject.c' || echo '$(srcdir)/'`managedgobject.c nip2-managedgobject.obj: managedgobject.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managedgobject.obj -MD -MP -MF $(DEPDIR)/nip2-managedgobject.Tpo -c -o nip2-managedgobject.obj `if test -f 'managedgobject.c'; then $(CYGPATH_W) 'managedgobject.c'; else $(CYGPATH_W) '$(srcdir)/managedgobject.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managedgobject.Tpo $(DEPDIR)/nip2-managedgobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managedgobject.c' object='nip2-managedgobject.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managedgobject.obj `if test -f 'managedgobject.c'; then $(CYGPATH_W) 'managedgobject.c'; else $(CYGPATH_W) '$(srcdir)/managedgobject.c'; fi` nip2-managedstring.o: managedstring.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managedstring.o -MD -MP -MF $(DEPDIR)/nip2-managedstring.Tpo -c -o nip2-managedstring.o `test -f 'managedstring.c' || echo '$(srcdir)/'`managedstring.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managedstring.Tpo $(DEPDIR)/nip2-managedstring.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managedstring.c' object='nip2-managedstring.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managedstring.o `test -f 'managedstring.c' || echo '$(srcdir)/'`managedstring.c nip2-managedstring.obj: managedstring.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-managedstring.obj -MD -MP -MF $(DEPDIR)/nip2-managedstring.Tpo -c -o nip2-managedstring.obj `if test -f 'managedstring.c'; then $(CYGPATH_W) 'managedstring.c'; else $(CYGPATH_W) '$(srcdir)/managedstring.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-managedstring.Tpo $(DEPDIR)/nip2-managedstring.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='managedstring.c' object='nip2-managedstring.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-managedstring.obj `if test -f 'managedstring.c'; then $(CYGPATH_W) 'managedstring.c'; else $(CYGPATH_W) '$(srcdir)/managedstring.c'; fi` nip2-imageinfo.o: imageinfo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imageinfo.o -MD -MP -MF $(DEPDIR)/nip2-imageinfo.Tpo -c -o nip2-imageinfo.o `test -f 'imageinfo.c' || echo '$(srcdir)/'`imageinfo.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imageinfo.Tpo $(DEPDIR)/nip2-imageinfo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imageinfo.c' object='nip2-imageinfo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imageinfo.o `test -f 'imageinfo.c' || echo '$(srcdir)/'`imageinfo.c nip2-imageinfo.obj: imageinfo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imageinfo.obj -MD -MP -MF $(DEPDIR)/nip2-imageinfo.Tpo -c -o nip2-imageinfo.obj `if test -f 'imageinfo.c'; then $(CYGPATH_W) 'imageinfo.c'; else $(CYGPATH_W) '$(srcdir)/imageinfo.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imageinfo.Tpo $(DEPDIR)/nip2-imageinfo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imageinfo.c' object='nip2-imageinfo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imageinfo.obj `if test -f 'imageinfo.c'; then $(CYGPATH_W) 'imageinfo.c'; else $(CYGPATH_W) '$(srcdir)/imageinfo.c'; fi` nip2-imagemodel.o: imagemodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imagemodel.o -MD -MP -MF $(DEPDIR)/nip2-imagemodel.Tpo -c -o nip2-imagemodel.o `test -f 'imagemodel.c' || echo '$(srcdir)/'`imagemodel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imagemodel.Tpo $(DEPDIR)/nip2-imagemodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imagemodel.c' object='nip2-imagemodel.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imagemodel.o `test -f 'imagemodel.c' || echo '$(srcdir)/'`imagemodel.c nip2-imagemodel.obj: imagemodel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imagemodel.obj -MD -MP -MF $(DEPDIR)/nip2-imagemodel.Tpo -c -o nip2-imagemodel.obj `if test -f 'imagemodel.c'; then $(CYGPATH_W) 'imagemodel.c'; else $(CYGPATH_W) '$(srcdir)/imagemodel.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imagemodel.Tpo $(DEPDIR)/nip2-imagemodel.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imagemodel.c' object='nip2-imagemodel.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imagemodel.obj `if test -f 'imagemodel.c'; then $(CYGPATH_W) 'imagemodel.c'; else $(CYGPATH_W) '$(srcdir)/imagemodel.c'; fi` nip2-imagepresent.o: imagepresent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imagepresent.o -MD -MP -MF $(DEPDIR)/nip2-imagepresent.Tpo -c -o nip2-imagepresent.o `test -f 'imagepresent.c' || echo '$(srcdir)/'`imagepresent.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imagepresent.Tpo $(DEPDIR)/nip2-imagepresent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imagepresent.c' object='nip2-imagepresent.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imagepresent.o `test -f 'imagepresent.c' || echo '$(srcdir)/'`imagepresent.c nip2-imagepresent.obj: imagepresent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imagepresent.obj -MD -MP -MF $(DEPDIR)/nip2-imagepresent.Tpo -c -o nip2-imagepresent.obj `if test -f 'imagepresent.c'; then $(CYGPATH_W) 'imagepresent.c'; else $(CYGPATH_W) '$(srcdir)/imagepresent.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imagepresent.Tpo $(DEPDIR)/nip2-imagepresent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imagepresent.c' object='nip2-imagepresent.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imagepresent.obj `if test -f 'imagepresent.c'; then $(CYGPATH_W) 'imagepresent.c'; else $(CYGPATH_W) '$(srcdir)/imagepresent.c'; fi` nip2-imageview.o: imageview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imageview.o -MD -MP -MF $(DEPDIR)/nip2-imageview.Tpo -c -o nip2-imageview.o `test -f 'imageview.c' || echo '$(srcdir)/'`imageview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imageview.Tpo $(DEPDIR)/nip2-imageview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imageview.c' object='nip2-imageview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imageview.o `test -f 'imageview.c' || echo '$(srcdir)/'`imageview.c nip2-imageview.obj: imageview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-imageview.obj -MD -MP -MF $(DEPDIR)/nip2-imageview.Tpo -c -o nip2-imageview.obj `if test -f 'imageview.c'; then $(CYGPATH_W) 'imageview.c'; else $(CYGPATH_W) '$(srcdir)/imageview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-imageview.Tpo $(DEPDIR)/nip2-imageview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='imageview.c' object='nip2-imageview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-imageview.obj `if test -f 'imageview.c'; then $(CYGPATH_W) 'imageview.c'; else $(CYGPATH_W) '$(srcdir)/imageview.c'; fi` nip2-iregion.o: iregion.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iregion.o -MD -MP -MF $(DEPDIR)/nip2-iregion.Tpo -c -o nip2-iregion.o `test -f 'iregion.c' || echo '$(srcdir)/'`iregion.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iregion.Tpo $(DEPDIR)/nip2-iregion.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iregion.c' object='nip2-iregion.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iregion.o `test -f 'iregion.c' || echo '$(srcdir)/'`iregion.c nip2-iregion.obj: iregion.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iregion.obj -MD -MP -MF $(DEPDIR)/nip2-iregion.Tpo -c -o nip2-iregion.obj `if test -f 'iregion.c'; then $(CYGPATH_W) 'iregion.c'; else $(CYGPATH_W) '$(srcdir)/iregion.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iregion.Tpo $(DEPDIR)/nip2-iregion.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iregion.c' object='nip2-iregion.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iregion.obj `if test -f 'iregion.c'; then $(CYGPATH_W) 'iregion.c'; else $(CYGPATH_W) '$(srcdir)/iregion.c'; fi` nip2-iregiongroup.o: iregiongroup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iregiongroup.o -MD -MP -MF $(DEPDIR)/nip2-iregiongroup.Tpo -c -o nip2-iregiongroup.o `test -f 'iregiongroup.c' || echo '$(srcdir)/'`iregiongroup.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iregiongroup.Tpo $(DEPDIR)/nip2-iregiongroup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iregiongroup.c' object='nip2-iregiongroup.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iregiongroup.o `test -f 'iregiongroup.c' || echo '$(srcdir)/'`iregiongroup.c nip2-iregiongroup.obj: iregiongroup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iregiongroup.obj -MD -MP -MF $(DEPDIR)/nip2-iregiongroup.Tpo -c -o nip2-iregiongroup.obj `if test -f 'iregiongroup.c'; then $(CYGPATH_W) 'iregiongroup.c'; else $(CYGPATH_W) '$(srcdir)/iregiongroup.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iregiongroup.Tpo $(DEPDIR)/nip2-iregiongroup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iregiongroup.c' object='nip2-iregiongroup.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iregiongroup.obj `if test -f 'iregiongroup.c'; then $(CYGPATH_W) 'iregiongroup.c'; else $(CYGPATH_W) '$(srcdir)/iregiongroup.c'; fi` nip2-iregiongroupview.o: iregiongroupview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iregiongroupview.o -MD -MP -MF $(DEPDIR)/nip2-iregiongroupview.Tpo -c -o nip2-iregiongroupview.o `test -f 'iregiongroupview.c' || echo '$(srcdir)/'`iregiongroupview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iregiongroupview.Tpo $(DEPDIR)/nip2-iregiongroupview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iregiongroupview.c' object='nip2-iregiongroupview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iregiongroupview.o `test -f 'iregiongroupview.c' || echo '$(srcdir)/'`iregiongroupview.c nip2-iregiongroupview.obj: iregiongroupview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iregiongroupview.obj -MD -MP -MF $(DEPDIR)/nip2-iregiongroupview.Tpo -c -o nip2-iregiongroupview.obj `if test -f 'iregiongroupview.c'; then $(CYGPATH_W) 'iregiongroupview.c'; else $(CYGPATH_W) '$(srcdir)/iregiongroupview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iregiongroupview.Tpo $(DEPDIR)/nip2-iregiongroupview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iregiongroupview.c' object='nip2-iregiongroupview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iregiongroupview.obj `if test -f 'iregiongroupview.c'; then $(CYGPATH_W) 'iregiongroupview.c'; else $(CYGPATH_W) '$(srcdir)/iregiongroupview.c'; fi` nip2-iregionview.o: iregionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iregionview.o -MD -MP -MF $(DEPDIR)/nip2-iregionview.Tpo -c -o nip2-iregionview.o `test -f 'iregionview.c' || echo '$(srcdir)/'`iregionview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iregionview.Tpo $(DEPDIR)/nip2-iregionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iregionview.c' object='nip2-iregionview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iregionview.o `test -f 'iregionview.c' || echo '$(srcdir)/'`iregionview.c nip2-iregionview.obj: iregionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iregionview.obj -MD -MP -MF $(DEPDIR)/nip2-iregionview.Tpo -c -o nip2-iregionview.obj `if test -f 'iregionview.c'; then $(CYGPATH_W) 'iregionview.c'; else $(CYGPATH_W) '$(srcdir)/iregionview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iregionview.Tpo $(DEPDIR)/nip2-iregionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iregionview.c' object='nip2-iregionview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iregionview.obj `if test -f 'iregionview.c'; then $(CYGPATH_W) 'iregionview.c'; else $(CYGPATH_W) '$(srcdir)/iregionview.c'; fi` nip2-itext.o: itext.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-itext.o -MD -MP -MF $(DEPDIR)/nip2-itext.Tpo -c -o nip2-itext.o `test -f 'itext.c' || echo '$(srcdir)/'`itext.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-itext.Tpo $(DEPDIR)/nip2-itext.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='itext.c' object='nip2-itext.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-itext.o `test -f 'itext.c' || echo '$(srcdir)/'`itext.c nip2-itext.obj: itext.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-itext.obj -MD -MP -MF $(DEPDIR)/nip2-itext.Tpo -c -o nip2-itext.obj `if test -f 'itext.c'; then $(CYGPATH_W) 'itext.c'; else $(CYGPATH_W) '$(srcdir)/itext.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-itext.Tpo $(DEPDIR)/nip2-itext.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='itext.c' object='nip2-itext.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-itext.obj `if test -f 'itext.c'; then $(CYGPATH_W) 'itext.c'; else $(CYGPATH_W) '$(srcdir)/itext.c'; fi` nip2-itextview.o: itextview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-itextview.o -MD -MP -MF $(DEPDIR)/nip2-itextview.Tpo -c -o nip2-itextview.o `test -f 'itextview.c' || echo '$(srcdir)/'`itextview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-itextview.Tpo $(DEPDIR)/nip2-itextview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='itextview.c' object='nip2-itextview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-itextview.o `test -f 'itextview.c' || echo '$(srcdir)/'`itextview.c nip2-itextview.obj: itextview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-itextview.obj -MD -MP -MF $(DEPDIR)/nip2-itextview.Tpo -c -o nip2-itextview.obj `if test -f 'itextview.c'; then $(CYGPATH_W) 'itextview.c'; else $(CYGPATH_W) '$(srcdir)/itextview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-itextview.Tpo $(DEPDIR)/nip2-itextview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='itextview.c' object='nip2-itextview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-itextview.obj `if test -f 'itextview.c'; then $(CYGPATH_W) 'itextview.c'; else $(CYGPATH_W) '$(srcdir)/itextview.c'; fi` nip2-iwindow.o: iwindow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iwindow.o -MD -MP -MF $(DEPDIR)/nip2-iwindow.Tpo -c -o nip2-iwindow.o `test -f 'iwindow.c' || echo '$(srcdir)/'`iwindow.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iwindow.Tpo $(DEPDIR)/nip2-iwindow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iwindow.c' object='nip2-iwindow.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iwindow.o `test -f 'iwindow.c' || echo '$(srcdir)/'`iwindow.c nip2-iwindow.obj: iwindow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-iwindow.obj -MD -MP -MF $(DEPDIR)/nip2-iwindow.Tpo -c -o nip2-iwindow.obj `if test -f 'iwindow.c'; then $(CYGPATH_W) 'iwindow.c'; else $(CYGPATH_W) '$(srcdir)/iwindow.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-iwindow.Tpo $(DEPDIR)/nip2-iwindow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iwindow.c' object='nip2-iwindow.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-iwindow.obj `if test -f 'iwindow.c'; then $(CYGPATH_W) 'iwindow.c'; else $(CYGPATH_W) '$(srcdir)/iwindow.c'; fi` nip2-parse.o: parse.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-parse.o -MD -MP -MF $(DEPDIR)/nip2-parse.Tpo -c -o nip2-parse.o `test -f 'parse.c' || echo '$(srcdir)/'`parse.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-parse.Tpo $(DEPDIR)/nip2-parse.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='parse.c' object='nip2-parse.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-parse.o `test -f 'parse.c' || echo '$(srcdir)/'`parse.c nip2-parse.obj: parse.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-parse.obj -MD -MP -MF $(DEPDIR)/nip2-parse.Tpo -c -o nip2-parse.obj `if test -f 'parse.c'; then $(CYGPATH_W) 'parse.c'; else $(CYGPATH_W) '$(srcdir)/parse.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-parse.Tpo $(DEPDIR)/nip2-parse.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='parse.c' object='nip2-parse.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-parse.obj `if test -f 'parse.c'; then $(CYGPATH_W) 'parse.c'; else $(CYGPATH_W) '$(srcdir)/parse.c'; fi` nip2-prefs.o: prefs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-prefs.o -MD -MP -MF $(DEPDIR)/nip2-prefs.Tpo -c -o nip2-prefs.o `test -f 'prefs.c' || echo '$(srcdir)/'`prefs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-prefs.Tpo $(DEPDIR)/nip2-prefs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='prefs.c' object='nip2-prefs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-prefs.o `test -f 'prefs.c' || echo '$(srcdir)/'`prefs.c nip2-prefs.obj: prefs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-prefs.obj -MD -MP -MF $(DEPDIR)/nip2-prefs.Tpo -c -o nip2-prefs.obj `if test -f 'prefs.c'; then $(CYGPATH_W) 'prefs.c'; else $(CYGPATH_W) '$(srcdir)/prefs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-prefs.Tpo $(DEPDIR)/nip2-prefs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='prefs.c' object='nip2-prefs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-prefs.obj `if test -f 'prefs.c'; then $(CYGPATH_W) 'prefs.c'; else $(CYGPATH_W) '$(srcdir)/prefs.c'; fi` nip2-prefworkspaceview.o: prefworkspaceview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-prefworkspaceview.o -MD -MP -MF $(DEPDIR)/nip2-prefworkspaceview.Tpo -c -o nip2-prefworkspaceview.o `test -f 'prefworkspaceview.c' || echo '$(srcdir)/'`prefworkspaceview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-prefworkspaceview.Tpo $(DEPDIR)/nip2-prefworkspaceview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='prefworkspaceview.c' object='nip2-prefworkspaceview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-prefworkspaceview.o `test -f 'prefworkspaceview.c' || echo '$(srcdir)/'`prefworkspaceview.c nip2-prefworkspaceview.obj: prefworkspaceview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-prefworkspaceview.obj -MD -MP -MF $(DEPDIR)/nip2-prefworkspaceview.Tpo -c -o nip2-prefworkspaceview.obj `if test -f 'prefworkspaceview.c'; then $(CYGPATH_W) 'prefworkspaceview.c'; else $(CYGPATH_W) '$(srcdir)/prefworkspaceview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-prefworkspaceview.Tpo $(DEPDIR)/nip2-prefworkspaceview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='prefworkspaceview.c' object='nip2-prefworkspaceview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-prefworkspaceview.obj `if test -f 'prefworkspaceview.c'; then $(CYGPATH_W) 'prefworkspaceview.c'; else $(CYGPATH_W) '$(srcdir)/prefworkspaceview.c'; fi` nip2-prefcolumnview.o: prefcolumnview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-prefcolumnview.o -MD -MP -MF $(DEPDIR)/nip2-prefcolumnview.Tpo -c -o nip2-prefcolumnview.o `test -f 'prefcolumnview.c' || echo '$(srcdir)/'`prefcolumnview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-prefcolumnview.Tpo $(DEPDIR)/nip2-prefcolumnview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='prefcolumnview.c' object='nip2-prefcolumnview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-prefcolumnview.o `test -f 'prefcolumnview.c' || echo '$(srcdir)/'`prefcolumnview.c nip2-prefcolumnview.obj: prefcolumnview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-prefcolumnview.obj -MD -MP -MF $(DEPDIR)/nip2-prefcolumnview.Tpo -c -o nip2-prefcolumnview.obj `if test -f 'prefcolumnview.c'; then $(CYGPATH_W) 'prefcolumnview.c'; else $(CYGPATH_W) '$(srcdir)/prefcolumnview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-prefcolumnview.Tpo $(DEPDIR)/nip2-prefcolumnview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='prefcolumnview.c' object='nip2-prefcolumnview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-prefcolumnview.obj `if test -f 'prefcolumnview.c'; then $(CYGPATH_W) 'prefcolumnview.c'; else $(CYGPATH_W) '$(srcdir)/prefcolumnview.c'; fi` nip2-lex.o: lex.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-lex.o -MD -MP -MF $(DEPDIR)/nip2-lex.Tpo -c -o nip2-lex.o `test -f 'lex.c' || echo '$(srcdir)/'`lex.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-lex.Tpo $(DEPDIR)/nip2-lex.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lex.c' object='nip2-lex.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-lex.o `test -f 'lex.c' || echo '$(srcdir)/'`lex.c nip2-lex.obj: lex.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-lex.obj -MD -MP -MF $(DEPDIR)/nip2-lex.Tpo -c -o nip2-lex.obj `if test -f 'lex.c'; then $(CYGPATH_W) 'lex.c'; else $(CYGPATH_W) '$(srcdir)/lex.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-lex.Tpo $(DEPDIR)/nip2-lex.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lex.c' object='nip2-lex.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-lex.obj `if test -f 'lex.c'; then $(CYGPATH_W) 'lex.c'; else $(CYGPATH_W) '$(srcdir)/lex.c'; fi` nip2-link.o: link.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-link.o -MD -MP -MF $(DEPDIR)/nip2-link.Tpo -c -o nip2-link.o `test -f 'link.c' || echo '$(srcdir)/'`link.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-link.Tpo $(DEPDIR)/nip2-link.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='link.c' object='nip2-link.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-link.o `test -f 'link.c' || echo '$(srcdir)/'`link.c nip2-link.obj: link.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-link.obj -MD -MP -MF $(DEPDIR)/nip2-link.Tpo -c -o nip2-link.obj `if test -f 'link.c'; then $(CYGPATH_W) 'link.c'; else $(CYGPATH_W) '$(srcdir)/link.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-link.Tpo $(DEPDIR)/nip2-link.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='link.c' object='nip2-link.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-link.obj `if test -f 'link.c'; then $(CYGPATH_W) 'link.c'; else $(CYGPATH_W) '$(srcdir)/link.c'; fi` nip2-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-main.o -MD -MP -MF $(DEPDIR)/nip2-main.Tpo -c -o nip2-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-main.Tpo $(DEPDIR)/nip2-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='nip2-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c nip2-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-main.obj -MD -MP -MF $(DEPDIR)/nip2-main.Tpo -c -o nip2-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-main.Tpo $(DEPDIR)/nip2-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='nip2-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` nip2-mainw.o: mainw.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-mainw.o -MD -MP -MF $(DEPDIR)/nip2-mainw.Tpo -c -o nip2-mainw.o `test -f 'mainw.c' || echo '$(srcdir)/'`mainw.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-mainw.Tpo $(DEPDIR)/nip2-mainw.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mainw.c' object='nip2-mainw.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-mainw.o `test -f 'mainw.c' || echo '$(srcdir)/'`mainw.c nip2-mainw.obj: mainw.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-mainw.obj -MD -MP -MF $(DEPDIR)/nip2-mainw.Tpo -c -o nip2-mainw.obj `if test -f 'mainw.c'; then $(CYGPATH_W) 'mainw.c'; else $(CYGPATH_W) '$(srcdir)/mainw.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-mainw.Tpo $(DEPDIR)/nip2-mainw.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mainw.c' object='nip2-mainw.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-mainw.obj `if test -f 'mainw.c'; then $(CYGPATH_W) 'mainw.c'; else $(CYGPATH_W) '$(srcdir)/mainw.c'; fi` nip2-matrix.o: matrix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-matrix.o -MD -MP -MF $(DEPDIR)/nip2-matrix.Tpo -c -o nip2-matrix.o `test -f 'matrix.c' || echo '$(srcdir)/'`matrix.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-matrix.Tpo $(DEPDIR)/nip2-matrix.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='matrix.c' object='nip2-matrix.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-matrix.o `test -f 'matrix.c' || echo '$(srcdir)/'`matrix.c nip2-matrix.obj: matrix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-matrix.obj -MD -MP -MF $(DEPDIR)/nip2-matrix.Tpo -c -o nip2-matrix.obj `if test -f 'matrix.c'; then $(CYGPATH_W) 'matrix.c'; else $(CYGPATH_W) '$(srcdir)/matrix.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-matrix.Tpo $(DEPDIR)/nip2-matrix.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='matrix.c' object='nip2-matrix.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-matrix.obj `if test -f 'matrix.c'; then $(CYGPATH_W) 'matrix.c'; else $(CYGPATH_W) '$(srcdir)/matrix.c'; fi` nip2-matrixview.o: matrixview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-matrixview.o -MD -MP -MF $(DEPDIR)/nip2-matrixview.Tpo -c -o nip2-matrixview.o `test -f 'matrixview.c' || echo '$(srcdir)/'`matrixview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-matrixview.Tpo $(DEPDIR)/nip2-matrixview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='matrixview.c' object='nip2-matrixview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-matrixview.o `test -f 'matrixview.c' || echo '$(srcdir)/'`matrixview.c nip2-matrixview.obj: matrixview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-matrixview.obj -MD -MP -MF $(DEPDIR)/nip2-matrixview.Tpo -c -o nip2-matrixview.obj `if test -f 'matrixview.c'; then $(CYGPATH_W) 'matrixview.c'; else $(CYGPATH_W) '$(srcdir)/matrixview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-matrixview.Tpo $(DEPDIR)/nip2-matrixview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='matrixview.c' object='nip2-matrixview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-matrixview.obj `if test -f 'matrixview.c'; then $(CYGPATH_W) 'matrixview.c'; else $(CYGPATH_W) '$(srcdir)/matrixview.c'; fi` nip2-plot.o: plot.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plot.o -MD -MP -MF $(DEPDIR)/nip2-plot.Tpo -c -o nip2-plot.o `test -f 'plot.c' || echo '$(srcdir)/'`plot.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plot.Tpo $(DEPDIR)/nip2-plot.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plot.c' object='nip2-plot.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plot.o `test -f 'plot.c' || echo '$(srcdir)/'`plot.c nip2-plot.obj: plot.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plot.obj -MD -MP -MF $(DEPDIR)/nip2-plot.Tpo -c -o nip2-plot.obj `if test -f 'plot.c'; then $(CYGPATH_W) 'plot.c'; else $(CYGPATH_W) '$(srcdir)/plot.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plot.Tpo $(DEPDIR)/nip2-plot.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plot.c' object='nip2-plot.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plot.obj `if test -f 'plot.c'; then $(CYGPATH_W) 'plot.c'; else $(CYGPATH_W) '$(srcdir)/plot.c'; fi` nip2-plotview.o: plotview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotview.o -MD -MP -MF $(DEPDIR)/nip2-plotview.Tpo -c -o nip2-plotview.o `test -f 'plotview.c' || echo '$(srcdir)/'`plotview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotview.Tpo $(DEPDIR)/nip2-plotview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotview.c' object='nip2-plotview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotview.o `test -f 'plotview.c' || echo '$(srcdir)/'`plotview.c nip2-plotview.obj: plotview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotview.obj -MD -MP -MF $(DEPDIR)/nip2-plotview.Tpo -c -o nip2-plotview.obj `if test -f 'plotview.c'; then $(CYGPATH_W) 'plotview.c'; else $(CYGPATH_W) '$(srcdir)/plotview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotview.Tpo $(DEPDIR)/nip2-plotview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotview.c' object='nip2-plotview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotview.obj `if test -f 'plotview.c'; then $(CYGPATH_W) 'plotview.c'; else $(CYGPATH_W) '$(srcdir)/plotview.c'; fi` nip2-plotwindow.o: plotwindow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotwindow.o -MD -MP -MF $(DEPDIR)/nip2-plotwindow.Tpo -c -o nip2-plotwindow.o `test -f 'plotwindow.c' || echo '$(srcdir)/'`plotwindow.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotwindow.Tpo $(DEPDIR)/nip2-plotwindow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotwindow.c' object='nip2-plotwindow.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotwindow.o `test -f 'plotwindow.c' || echo '$(srcdir)/'`plotwindow.c nip2-plotwindow.obj: plotwindow.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-plotwindow.obj -MD -MP -MF $(DEPDIR)/nip2-plotwindow.Tpo -c -o nip2-plotwindow.obj `if test -f 'plotwindow.c'; then $(CYGPATH_W) 'plotwindow.c'; else $(CYGPATH_W) '$(srcdir)/plotwindow.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-plotwindow.Tpo $(DEPDIR)/nip2-plotwindow.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plotwindow.c' object='nip2-plotwindow.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-plotwindow.obj `if test -f 'plotwindow.c'; then $(CYGPATH_W) 'plotwindow.c'; else $(CYGPATH_W) '$(srcdir)/plotwindow.c'; fi` nip2-model.o: model.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-model.o -MD -MP -MF $(DEPDIR)/nip2-model.Tpo -c -o nip2-model.o `test -f 'model.c' || echo '$(srcdir)/'`model.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-model.Tpo $(DEPDIR)/nip2-model.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='model.c' object='nip2-model.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-model.o `test -f 'model.c' || echo '$(srcdir)/'`model.c nip2-model.obj: model.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-model.obj -MD -MP -MF $(DEPDIR)/nip2-model.Tpo -c -o nip2-model.obj `if test -f 'model.c'; then $(CYGPATH_W) 'model.c'; else $(CYGPATH_W) '$(srcdir)/model.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-model.Tpo $(DEPDIR)/nip2-model.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='model.c' object='nip2-model.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-model.obj `if test -f 'model.c'; then $(CYGPATH_W) 'model.c'; else $(CYGPATH_W) '$(srcdir)/model.c'; fi` nip2-option.o: option.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-option.o -MD -MP -MF $(DEPDIR)/nip2-option.Tpo -c -o nip2-option.o `test -f 'option.c' || echo '$(srcdir)/'`option.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-option.Tpo $(DEPDIR)/nip2-option.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='option.c' object='nip2-option.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-option.o `test -f 'option.c' || echo '$(srcdir)/'`option.c nip2-option.obj: option.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-option.obj -MD -MP -MF $(DEPDIR)/nip2-option.Tpo -c -o nip2-option.obj `if test -f 'option.c'; then $(CYGPATH_W) 'option.c'; else $(CYGPATH_W) '$(srcdir)/option.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-option.Tpo $(DEPDIR)/nip2-option.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='option.c' object='nip2-option.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-option.obj `if test -f 'option.c'; then $(CYGPATH_W) 'option.c'; else $(CYGPATH_W) '$(srcdir)/option.c'; fi` nip2-optionview.o: optionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-optionview.o -MD -MP -MF $(DEPDIR)/nip2-optionview.Tpo -c -o nip2-optionview.o `test -f 'optionview.c' || echo '$(srcdir)/'`optionview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-optionview.Tpo $(DEPDIR)/nip2-optionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='optionview.c' object='nip2-optionview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-optionview.o `test -f 'optionview.c' || echo '$(srcdir)/'`optionview.c nip2-optionview.obj: optionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-optionview.obj -MD -MP -MF $(DEPDIR)/nip2-optionview.Tpo -c -o nip2-optionview.obj `if test -f 'optionview.c'; then $(CYGPATH_W) 'optionview.c'; else $(CYGPATH_W) '$(srcdir)/optionview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-optionview.Tpo $(DEPDIR)/nip2-optionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='optionview.c' object='nip2-optionview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-optionview.obj `if test -f 'optionview.c'; then $(CYGPATH_W) 'optionview.c'; else $(CYGPATH_W) '$(srcdir)/optionview.c'; fi` nip2-formula.o: formula.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-formula.o -MD -MP -MF $(DEPDIR)/nip2-formula.Tpo -c -o nip2-formula.o `test -f 'formula.c' || echo '$(srcdir)/'`formula.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-formula.Tpo $(DEPDIR)/nip2-formula.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='formula.c' object='nip2-formula.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-formula.o `test -f 'formula.c' || echo '$(srcdir)/'`formula.c nip2-formula.obj: formula.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-formula.obj -MD -MP -MF $(DEPDIR)/nip2-formula.Tpo -c -o nip2-formula.obj `if test -f 'formula.c'; then $(CYGPATH_W) 'formula.c'; else $(CYGPATH_W) '$(srcdir)/formula.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-formula.Tpo $(DEPDIR)/nip2-formula.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='formula.c' object='nip2-formula.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-formula.obj `if test -f 'formula.c'; then $(CYGPATH_W) 'formula.c'; else $(CYGPATH_W) '$(srcdir)/formula.c'; fi` nip2-paintboxview.o: paintboxview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-paintboxview.o -MD -MP -MF $(DEPDIR)/nip2-paintboxview.Tpo -c -o nip2-paintboxview.o `test -f 'paintboxview.c' || echo '$(srcdir)/'`paintboxview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-paintboxview.Tpo $(DEPDIR)/nip2-paintboxview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='paintboxview.c' object='nip2-paintboxview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-paintboxview.o `test -f 'paintboxview.c' || echo '$(srcdir)/'`paintboxview.c nip2-paintboxview.obj: paintboxview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-paintboxview.obj -MD -MP -MF $(DEPDIR)/nip2-paintboxview.Tpo -c -o nip2-paintboxview.obj `if test -f 'paintboxview.c'; then $(CYGPATH_W) 'paintboxview.c'; else $(CYGPATH_W) '$(srcdir)/paintboxview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-paintboxview.Tpo $(DEPDIR)/nip2-paintboxview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='paintboxview.c' object='nip2-paintboxview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-paintboxview.obj `if test -f 'paintboxview.c'; then $(CYGPATH_W) 'paintboxview.c'; else $(CYGPATH_W) '$(srcdir)/paintboxview.c'; fi` nip2-path.o: path.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-path.o -MD -MP -MF $(DEPDIR)/nip2-path.Tpo -c -o nip2-path.o `test -f 'path.c' || echo '$(srcdir)/'`path.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-path.Tpo $(DEPDIR)/nip2-path.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='path.c' object='nip2-path.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-path.o `test -f 'path.c' || echo '$(srcdir)/'`path.c nip2-path.obj: path.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-path.obj -MD -MP -MF $(DEPDIR)/nip2-path.Tpo -c -o nip2-path.obj `if test -f 'path.c'; then $(CYGPATH_W) 'path.c'; else $(CYGPATH_W) '$(srcdir)/path.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-path.Tpo $(DEPDIR)/nip2-path.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='path.c' object='nip2-path.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-path.obj `if test -f 'path.c'; then $(CYGPATH_W) 'path.c'; else $(CYGPATH_W) '$(srcdir)/path.c'; fi` nip2-predicate.o: predicate.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-predicate.o -MD -MP -MF $(DEPDIR)/nip2-predicate.Tpo -c -o nip2-predicate.o `test -f 'predicate.c' || echo '$(srcdir)/'`predicate.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-predicate.Tpo $(DEPDIR)/nip2-predicate.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='predicate.c' object='nip2-predicate.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-predicate.o `test -f 'predicate.c' || echo '$(srcdir)/'`predicate.c nip2-predicate.obj: predicate.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-predicate.obj -MD -MP -MF $(DEPDIR)/nip2-predicate.Tpo -c -o nip2-predicate.obj `if test -f 'predicate.c'; then $(CYGPATH_W) 'predicate.c'; else $(CYGPATH_W) '$(srcdir)/predicate.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-predicate.Tpo $(DEPDIR)/nip2-predicate.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='predicate.c' object='nip2-predicate.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-predicate.obj `if test -f 'predicate.c'; then $(CYGPATH_W) 'predicate.c'; else $(CYGPATH_W) '$(srcdir)/predicate.c'; fi` nip2-program.o: program.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-program.o -MD -MP -MF $(DEPDIR)/nip2-program.Tpo -c -o nip2-program.o `test -f 'program.c' || echo '$(srcdir)/'`program.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-program.Tpo $(DEPDIR)/nip2-program.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='program.c' object='nip2-program.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-program.o `test -f 'program.c' || echo '$(srcdir)/'`program.c nip2-program.obj: program.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-program.obj -MD -MP -MF $(DEPDIR)/nip2-program.Tpo -c -o nip2-program.obj `if test -f 'program.c'; then $(CYGPATH_W) 'program.c'; else $(CYGPATH_W) '$(srcdir)/program.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-program.Tpo $(DEPDIR)/nip2-program.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='program.c' object='nip2-program.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-program.obj `if test -f 'program.c'; then $(CYGPATH_W) 'program.c'; else $(CYGPATH_W) '$(srcdir)/program.c'; fi` nip2-string.o: string.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-string.o -MD -MP -MF $(DEPDIR)/nip2-string.Tpo -c -o nip2-string.o `test -f 'string.c' || echo '$(srcdir)/'`string.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-string.Tpo $(DEPDIR)/nip2-string.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='string.c' object='nip2-string.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-string.o `test -f 'string.c' || echo '$(srcdir)/'`string.c nip2-string.obj: string.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-string.obj -MD -MP -MF $(DEPDIR)/nip2-string.Tpo -c -o nip2-string.obj `if test -f 'string.c'; then $(CYGPATH_W) 'string.c'; else $(CYGPATH_W) '$(srcdir)/string.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-string.Tpo $(DEPDIR)/nip2-string.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='string.c' object='nip2-string.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-string.obj `if test -f 'string.c'; then $(CYGPATH_W) 'string.c'; else $(CYGPATH_W) '$(srcdir)/string.c'; fi` nip2-number.o: number.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-number.o -MD -MP -MF $(DEPDIR)/nip2-number.Tpo -c -o nip2-number.o `test -f 'number.c' || echo '$(srcdir)/'`number.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-number.Tpo $(DEPDIR)/nip2-number.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='number.c' object='nip2-number.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-number.o `test -f 'number.c' || echo '$(srcdir)/'`number.c nip2-number.obj: number.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-number.obj -MD -MP -MF $(DEPDIR)/nip2-number.Tpo -c -o nip2-number.obj `if test -f 'number.c'; then $(CYGPATH_W) 'number.c'; else $(CYGPATH_W) '$(srcdir)/number.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-number.Tpo $(DEPDIR)/nip2-number.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='number.c' object='nip2-number.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-number.obj `if test -f 'number.c'; then $(CYGPATH_W) 'number.c'; else $(CYGPATH_W) '$(srcdir)/number.c'; fi` nip2-expression.o: expression.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-expression.o -MD -MP -MF $(DEPDIR)/nip2-expression.Tpo -c -o nip2-expression.o `test -f 'expression.c' || echo '$(srcdir)/'`expression.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-expression.Tpo $(DEPDIR)/nip2-expression.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='expression.c' object='nip2-expression.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-expression.o `test -f 'expression.c' || echo '$(srcdir)/'`expression.c nip2-expression.obj: expression.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-expression.obj -MD -MP -MF $(DEPDIR)/nip2-expression.Tpo -c -o nip2-expression.obj `if test -f 'expression.c'; then $(CYGPATH_W) 'expression.c'; else $(CYGPATH_W) '$(srcdir)/expression.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-expression.Tpo $(DEPDIR)/nip2-expression.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='expression.c' object='nip2-expression.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-expression.obj `if test -f 'expression.c'; then $(CYGPATH_W) 'expression.c'; else $(CYGPATH_W) '$(srcdir)/expression.c'; fi` nip2-expressionview.o: expressionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-expressionview.o -MD -MP -MF $(DEPDIR)/nip2-expressionview.Tpo -c -o nip2-expressionview.o `test -f 'expressionview.c' || echo '$(srcdir)/'`expressionview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-expressionview.Tpo $(DEPDIR)/nip2-expressionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='expressionview.c' object='nip2-expressionview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-expressionview.o `test -f 'expressionview.c' || echo '$(srcdir)/'`expressionview.c nip2-expressionview.obj: expressionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-expressionview.obj -MD -MP -MF $(DEPDIR)/nip2-expressionview.Tpo -c -o nip2-expressionview.obj `if test -f 'expressionview.c'; then $(CYGPATH_W) 'expressionview.c'; else $(CYGPATH_W) '$(srcdir)/expressionview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-expressionview.Tpo $(DEPDIR)/nip2-expressionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='expressionview.c' object='nip2-expressionview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-expressionview.obj `if test -f 'expressionview.c'; then $(CYGPATH_W) 'expressionview.c'; else $(CYGPATH_W) '$(srcdir)/expressionview.c'; fi` nip2-stringview.o: stringview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-stringview.o -MD -MP -MF $(DEPDIR)/nip2-stringview.Tpo -c -o nip2-stringview.o `test -f 'stringview.c' || echo '$(srcdir)/'`stringview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-stringview.Tpo $(DEPDIR)/nip2-stringview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stringview.c' object='nip2-stringview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-stringview.o `test -f 'stringview.c' || echo '$(srcdir)/'`stringview.c nip2-stringview.obj: stringview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-stringview.obj -MD -MP -MF $(DEPDIR)/nip2-stringview.Tpo -c -o nip2-stringview.obj `if test -f 'stringview.c'; then $(CYGPATH_W) 'stringview.c'; else $(CYGPATH_W) '$(srcdir)/stringview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-stringview.Tpo $(DEPDIR)/nip2-stringview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stringview.c' object='nip2-stringview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-stringview.obj `if test -f 'stringview.c'; then $(CYGPATH_W) 'stringview.c'; else $(CYGPATH_W) '$(srcdir)/stringview.c'; fi` nip2-editview.o: editview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-editview.o -MD -MP -MF $(DEPDIR)/nip2-editview.Tpo -c -o nip2-editview.o `test -f 'editview.c' || echo '$(srcdir)/'`editview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-editview.Tpo $(DEPDIR)/nip2-editview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='editview.c' object='nip2-editview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-editview.o `test -f 'editview.c' || echo '$(srcdir)/'`editview.c nip2-editview.obj: editview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-editview.obj -MD -MP -MF $(DEPDIR)/nip2-editview.Tpo -c -o nip2-editview.obj `if test -f 'editview.c'; then $(CYGPATH_W) 'editview.c'; else $(CYGPATH_W) '$(srcdir)/editview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-editview.Tpo $(DEPDIR)/nip2-editview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='editview.c' object='nip2-editview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-editview.obj `if test -f 'editview.c'; then $(CYGPATH_W) 'editview.c'; else $(CYGPATH_W) '$(srcdir)/editview.c'; fi` nip2-numberview.o: numberview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-numberview.o -MD -MP -MF $(DEPDIR)/nip2-numberview.Tpo -c -o nip2-numberview.o `test -f 'numberview.c' || echo '$(srcdir)/'`numberview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-numberview.Tpo $(DEPDIR)/nip2-numberview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='numberview.c' object='nip2-numberview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-numberview.o `test -f 'numberview.c' || echo '$(srcdir)/'`numberview.c nip2-numberview.obj: numberview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-numberview.obj -MD -MP -MF $(DEPDIR)/nip2-numberview.Tpo -c -o nip2-numberview.obj `if test -f 'numberview.c'; then $(CYGPATH_W) 'numberview.c'; else $(CYGPATH_W) '$(srcdir)/numberview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-numberview.Tpo $(DEPDIR)/nip2-numberview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='numberview.c' object='nip2-numberview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-numberview.obj `if test -f 'numberview.c'; then $(CYGPATH_W) 'numberview.c'; else $(CYGPATH_W) '$(srcdir)/numberview.c'; fi` nip2-real.o: real.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-real.o -MD -MP -MF $(DEPDIR)/nip2-real.Tpo -c -o nip2-real.o `test -f 'real.c' || echo '$(srcdir)/'`real.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-real.Tpo $(DEPDIR)/nip2-real.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='real.c' object='nip2-real.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-real.o `test -f 'real.c' || echo '$(srcdir)/'`real.c nip2-real.obj: real.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-real.obj -MD -MP -MF $(DEPDIR)/nip2-real.Tpo -c -o nip2-real.obj `if test -f 'real.c'; then $(CYGPATH_W) 'real.c'; else $(CYGPATH_W) '$(srcdir)/real.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-real.Tpo $(DEPDIR)/nip2-real.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='real.c' object='nip2-real.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-real.obj `if test -f 'real.c'; then $(CYGPATH_W) 'real.c'; else $(CYGPATH_W) '$(srcdir)/real.c'; fi` nip2-vector.o: vector.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-vector.o -MD -MP -MF $(DEPDIR)/nip2-vector.Tpo -c -o nip2-vector.o `test -f 'vector.c' || echo '$(srcdir)/'`vector.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-vector.Tpo $(DEPDIR)/nip2-vector.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vector.c' object='nip2-vector.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-vector.o `test -f 'vector.c' || echo '$(srcdir)/'`vector.c nip2-vector.obj: vector.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-vector.obj -MD -MP -MF $(DEPDIR)/nip2-vector.Tpo -c -o nip2-vector.obj `if test -f 'vector.c'; then $(CYGPATH_W) 'vector.c'; else $(CYGPATH_W) '$(srcdir)/vector.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-vector.Tpo $(DEPDIR)/nip2-vector.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vector.c' object='nip2-vector.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-vector.obj `if test -f 'vector.c'; then $(CYGPATH_W) 'vector.c'; else $(CYGPATH_W) '$(srcdir)/vector.c'; fi` nip2-reduce.o: reduce.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-reduce.o -MD -MP -MF $(DEPDIR)/nip2-reduce.Tpo -c -o nip2-reduce.o `test -f 'reduce.c' || echo '$(srcdir)/'`reduce.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-reduce.Tpo $(DEPDIR)/nip2-reduce.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='reduce.c' object='nip2-reduce.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-reduce.o `test -f 'reduce.c' || echo '$(srcdir)/'`reduce.c nip2-reduce.obj: reduce.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-reduce.obj -MD -MP -MF $(DEPDIR)/nip2-reduce.Tpo -c -o nip2-reduce.obj `if test -f 'reduce.c'; then $(CYGPATH_W) 'reduce.c'; else $(CYGPATH_W) '$(srcdir)/reduce.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-reduce.Tpo $(DEPDIR)/nip2-reduce.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='reduce.c' object='nip2-reduce.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-reduce.obj `if test -f 'reduce.c'; then $(CYGPATH_W) 'reduce.c'; else $(CYGPATH_W) '$(srcdir)/reduce.c'; fi` nip2-regionview.o: regionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-regionview.o -MD -MP -MF $(DEPDIR)/nip2-regionview.Tpo -c -o nip2-regionview.o `test -f 'regionview.c' || echo '$(srcdir)/'`regionview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-regionview.Tpo $(DEPDIR)/nip2-regionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regionview.c' object='nip2-regionview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-regionview.o `test -f 'regionview.c' || echo '$(srcdir)/'`regionview.c nip2-regionview.obj: regionview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-regionview.obj -MD -MP -MF $(DEPDIR)/nip2-regionview.Tpo -c -o nip2-regionview.obj `if test -f 'regionview.c'; then $(CYGPATH_W) 'regionview.c'; else $(CYGPATH_W) '$(srcdir)/regionview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-regionview.Tpo $(DEPDIR)/nip2-regionview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='regionview.c' object='nip2-regionview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-regionview.obj `if test -f 'regionview.c'; then $(CYGPATH_W) 'regionview.c'; else $(CYGPATH_W) '$(srcdir)/regionview.c'; fi` nip2-rhs.o: rhs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-rhs.o -MD -MP -MF $(DEPDIR)/nip2-rhs.Tpo -c -o nip2-rhs.o `test -f 'rhs.c' || echo '$(srcdir)/'`rhs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-rhs.Tpo $(DEPDIR)/nip2-rhs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rhs.c' object='nip2-rhs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-rhs.o `test -f 'rhs.c' || echo '$(srcdir)/'`rhs.c nip2-rhs.obj: rhs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-rhs.obj -MD -MP -MF $(DEPDIR)/nip2-rhs.Tpo -c -o nip2-rhs.obj `if test -f 'rhs.c'; then $(CYGPATH_W) 'rhs.c'; else $(CYGPATH_W) '$(srcdir)/rhs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-rhs.Tpo $(DEPDIR)/nip2-rhs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rhs.c' object='nip2-rhs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-rhs.obj `if test -f 'rhs.c'; then $(CYGPATH_W) 'rhs.c'; else $(CYGPATH_W) '$(srcdir)/rhs.c'; fi` nip2-rhsview.o: rhsview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-rhsview.o -MD -MP -MF $(DEPDIR)/nip2-rhsview.Tpo -c -o nip2-rhsview.o `test -f 'rhsview.c' || echo '$(srcdir)/'`rhsview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-rhsview.Tpo $(DEPDIR)/nip2-rhsview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rhsview.c' object='nip2-rhsview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-rhsview.o `test -f 'rhsview.c' || echo '$(srcdir)/'`rhsview.c nip2-rhsview.obj: rhsview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-rhsview.obj -MD -MP -MF $(DEPDIR)/nip2-rhsview.Tpo -c -o nip2-rhsview.obj `if test -f 'rhsview.c'; then $(CYGPATH_W) 'rhsview.c'; else $(CYGPATH_W) '$(srcdir)/rhsview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-rhsview.Tpo $(DEPDIR)/nip2-rhsview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rhsview.c' object='nip2-rhsview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-rhsview.obj `if test -f 'rhsview.c'; then $(CYGPATH_W) 'rhsview.c'; else $(CYGPATH_W) '$(srcdir)/rhsview.c'; fi` nip2-row.o: row.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-row.o -MD -MP -MF $(DEPDIR)/nip2-row.Tpo -c -o nip2-row.o `test -f 'row.c' || echo '$(srcdir)/'`row.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-row.Tpo $(DEPDIR)/nip2-row.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='row.c' object='nip2-row.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-row.o `test -f 'row.c' || echo '$(srcdir)/'`row.c nip2-row.obj: row.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-row.obj -MD -MP -MF $(DEPDIR)/nip2-row.Tpo -c -o nip2-row.obj `if test -f 'row.c'; then $(CYGPATH_W) 'row.c'; else $(CYGPATH_W) '$(srcdir)/row.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-row.Tpo $(DEPDIR)/nip2-row.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='row.c' object='nip2-row.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-row.obj `if test -f 'row.c'; then $(CYGPATH_W) 'row.c'; else $(CYGPATH_W) '$(srcdir)/row.c'; fi` nip2-rowview.o: rowview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-rowview.o -MD -MP -MF $(DEPDIR)/nip2-rowview.Tpo -c -o nip2-rowview.o `test -f 'rowview.c' || echo '$(srcdir)/'`rowview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-rowview.Tpo $(DEPDIR)/nip2-rowview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rowview.c' object='nip2-rowview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-rowview.o `test -f 'rowview.c' || echo '$(srcdir)/'`rowview.c nip2-rowview.obj: rowview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-rowview.obj -MD -MP -MF $(DEPDIR)/nip2-rowview.Tpo -c -o nip2-rowview.obj `if test -f 'rowview.c'; then $(CYGPATH_W) 'rowview.c'; else $(CYGPATH_W) '$(srcdir)/rowview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-rowview.Tpo $(DEPDIR)/nip2-rowview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rowview.c' object='nip2-rowview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-rowview.obj `if test -f 'rowview.c'; then $(CYGPATH_W) 'rowview.c'; else $(CYGPATH_W) '$(srcdir)/rowview.c'; fi` nip2-secret.o: secret.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-secret.o -MD -MP -MF $(DEPDIR)/nip2-secret.Tpo -c -o nip2-secret.o `test -f 'secret.c' || echo '$(srcdir)/'`secret.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-secret.Tpo $(DEPDIR)/nip2-secret.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='secret.c' object='nip2-secret.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-secret.o `test -f 'secret.c' || echo '$(srcdir)/'`secret.c nip2-secret.obj: secret.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-secret.obj -MD -MP -MF $(DEPDIR)/nip2-secret.Tpo -c -o nip2-secret.obj `if test -f 'secret.c'; then $(CYGPATH_W) 'secret.c'; else $(CYGPATH_W) '$(srcdir)/secret.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-secret.Tpo $(DEPDIR)/nip2-secret.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='secret.c' object='nip2-secret.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-secret.obj `if test -f 'secret.c'; then $(CYGPATH_W) 'secret.c'; else $(CYGPATH_W) '$(srcdir)/secret.c'; fi` nip2-slider.o: slider.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-slider.o -MD -MP -MF $(DEPDIR)/nip2-slider.Tpo -c -o nip2-slider.o `test -f 'slider.c' || echo '$(srcdir)/'`slider.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-slider.Tpo $(DEPDIR)/nip2-slider.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slider.c' object='nip2-slider.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-slider.o `test -f 'slider.c' || echo '$(srcdir)/'`slider.c nip2-slider.obj: slider.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-slider.obj -MD -MP -MF $(DEPDIR)/nip2-slider.Tpo -c -o nip2-slider.obj `if test -f 'slider.c'; then $(CYGPATH_W) 'slider.c'; else $(CYGPATH_W) '$(srcdir)/slider.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-slider.Tpo $(DEPDIR)/nip2-slider.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slider.c' object='nip2-slider.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-slider.obj `if test -f 'slider.c'; then $(CYGPATH_W) 'slider.c'; else $(CYGPATH_W) '$(srcdir)/slider.c'; fi` nip2-sliderview.o: sliderview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-sliderview.o -MD -MP -MF $(DEPDIR)/nip2-sliderview.Tpo -c -o nip2-sliderview.o `test -f 'sliderview.c' || echo '$(srcdir)/'`sliderview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-sliderview.Tpo $(DEPDIR)/nip2-sliderview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sliderview.c' object='nip2-sliderview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-sliderview.o `test -f 'sliderview.c' || echo '$(srcdir)/'`sliderview.c nip2-sliderview.obj: sliderview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-sliderview.obj -MD -MP -MF $(DEPDIR)/nip2-sliderview.Tpo -c -o nip2-sliderview.obj `if test -f 'sliderview.c'; then $(CYGPATH_W) 'sliderview.c'; else $(CYGPATH_W) '$(srcdir)/sliderview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-sliderview.Tpo $(DEPDIR)/nip2-sliderview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sliderview.c' object='nip2-sliderview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-sliderview.obj `if test -f 'sliderview.c'; then $(CYGPATH_W) 'sliderview.c'; else $(CYGPATH_W) '$(srcdir)/sliderview.c'; fi` nip2-clock.o: clock.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-clock.o -MD -MP -MF $(DEPDIR)/nip2-clock.Tpo -c -o nip2-clock.o `test -f 'clock.c' || echo '$(srcdir)/'`clock.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-clock.Tpo $(DEPDIR)/nip2-clock.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clock.c' object='nip2-clock.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-clock.o `test -f 'clock.c' || echo '$(srcdir)/'`clock.c nip2-clock.obj: clock.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-clock.obj -MD -MP -MF $(DEPDIR)/nip2-clock.Tpo -c -o nip2-clock.obj `if test -f 'clock.c'; then $(CYGPATH_W) 'clock.c'; else $(CYGPATH_W) '$(srcdir)/clock.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-clock.Tpo $(DEPDIR)/nip2-clock.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='clock.c' object='nip2-clock.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-clock.obj `if test -f 'clock.c'; then $(CYGPATH_W) 'clock.c'; else $(CYGPATH_W) '$(srcdir)/clock.c'; fi` nip2-spin.o: spin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-spin.o -MD -MP -MF $(DEPDIR)/nip2-spin.Tpo -c -o nip2-spin.o `test -f 'spin.c' || echo '$(srcdir)/'`spin.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-spin.Tpo $(DEPDIR)/nip2-spin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='spin.c' object='nip2-spin.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-spin.o `test -f 'spin.c' || echo '$(srcdir)/'`spin.c nip2-spin.obj: spin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-spin.obj -MD -MP -MF $(DEPDIR)/nip2-spin.Tpo -c -o nip2-spin.obj `if test -f 'spin.c'; then $(CYGPATH_W) 'spin.c'; else $(CYGPATH_W) '$(srcdir)/spin.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-spin.Tpo $(DEPDIR)/nip2-spin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='spin.c' object='nip2-spin.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-spin.obj `if test -f 'spin.c'; then $(CYGPATH_W) 'spin.c'; else $(CYGPATH_W) '$(srcdir)/spin.c'; fi` nip2-statusview.o: statusview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-statusview.o -MD -MP -MF $(DEPDIR)/nip2-statusview.Tpo -c -o nip2-statusview.o `test -f 'statusview.c' || echo '$(srcdir)/'`statusview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-statusview.Tpo $(DEPDIR)/nip2-statusview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='statusview.c' object='nip2-statusview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-statusview.o `test -f 'statusview.c' || echo '$(srcdir)/'`statusview.c nip2-statusview.obj: statusview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-statusview.obj -MD -MP -MF $(DEPDIR)/nip2-statusview.Tpo -c -o nip2-statusview.obj `if test -f 'statusview.c'; then $(CYGPATH_W) 'statusview.c'; else $(CYGPATH_W) '$(srcdir)/statusview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-statusview.Tpo $(DEPDIR)/nip2-statusview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='statusview.c' object='nip2-statusview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-statusview.obj `if test -f 'statusview.c'; then $(CYGPATH_W) 'statusview.c'; else $(CYGPATH_W) '$(srcdir)/statusview.c'; fi` nip2-subcolumn.o: subcolumn.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-subcolumn.o -MD -MP -MF $(DEPDIR)/nip2-subcolumn.Tpo -c -o nip2-subcolumn.o `test -f 'subcolumn.c' || echo '$(srcdir)/'`subcolumn.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-subcolumn.Tpo $(DEPDIR)/nip2-subcolumn.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='subcolumn.c' object='nip2-subcolumn.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-subcolumn.o `test -f 'subcolumn.c' || echo '$(srcdir)/'`subcolumn.c nip2-subcolumn.obj: subcolumn.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-subcolumn.obj -MD -MP -MF $(DEPDIR)/nip2-subcolumn.Tpo -c -o nip2-subcolumn.obj `if test -f 'subcolumn.c'; then $(CYGPATH_W) 'subcolumn.c'; else $(CYGPATH_W) '$(srcdir)/subcolumn.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-subcolumn.Tpo $(DEPDIR)/nip2-subcolumn.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='subcolumn.c' object='nip2-subcolumn.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-subcolumn.obj `if test -f 'subcolumn.c'; then $(CYGPATH_W) 'subcolumn.c'; else $(CYGPATH_W) '$(srcdir)/subcolumn.c'; fi` nip2-subcolumnview.o: subcolumnview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-subcolumnview.o -MD -MP -MF $(DEPDIR)/nip2-subcolumnview.Tpo -c -o nip2-subcolumnview.o `test -f 'subcolumnview.c' || echo '$(srcdir)/'`subcolumnview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-subcolumnview.Tpo $(DEPDIR)/nip2-subcolumnview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='subcolumnview.c' object='nip2-subcolumnview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-subcolumnview.o `test -f 'subcolumnview.c' || echo '$(srcdir)/'`subcolumnview.c nip2-subcolumnview.obj: subcolumnview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-subcolumnview.obj -MD -MP -MF $(DEPDIR)/nip2-subcolumnview.Tpo -c -o nip2-subcolumnview.obj `if test -f 'subcolumnview.c'; then $(CYGPATH_W) 'subcolumnview.c'; else $(CYGPATH_W) '$(srcdir)/subcolumnview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-subcolumnview.Tpo $(DEPDIR)/nip2-subcolumnview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='subcolumnview.c' object='nip2-subcolumnview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-subcolumnview.obj `if test -f 'subcolumnview.c'; then $(CYGPATH_W) 'subcolumnview.c'; else $(CYGPATH_W) '$(srcdir)/subcolumnview.c'; fi` nip2-symbol.o: symbol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-symbol.o -MD -MP -MF $(DEPDIR)/nip2-symbol.Tpo -c -o nip2-symbol.o `test -f 'symbol.c' || echo '$(srcdir)/'`symbol.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-symbol.Tpo $(DEPDIR)/nip2-symbol.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='symbol.c' object='nip2-symbol.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-symbol.o `test -f 'symbol.c' || echo '$(srcdir)/'`symbol.c nip2-symbol.obj: symbol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-symbol.obj -MD -MP -MF $(DEPDIR)/nip2-symbol.Tpo -c -o nip2-symbol.obj `if test -f 'symbol.c'; then $(CYGPATH_W) 'symbol.c'; else $(CYGPATH_W) '$(srcdir)/symbol.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-symbol.Tpo $(DEPDIR)/nip2-symbol.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='symbol.c' object='nip2-symbol.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-symbol.obj `if test -f 'symbol.c'; then $(CYGPATH_W) 'symbol.c'; else $(CYGPATH_W) '$(srcdir)/symbol.c'; fi` nip2-toggle.o: toggle.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toggle.o -MD -MP -MF $(DEPDIR)/nip2-toggle.Tpo -c -o nip2-toggle.o `test -f 'toggle.c' || echo '$(srcdir)/'`toggle.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toggle.Tpo $(DEPDIR)/nip2-toggle.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toggle.c' object='nip2-toggle.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toggle.o `test -f 'toggle.c' || echo '$(srcdir)/'`toggle.c nip2-toggle.obj: toggle.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toggle.obj -MD -MP -MF $(DEPDIR)/nip2-toggle.Tpo -c -o nip2-toggle.obj `if test -f 'toggle.c'; then $(CYGPATH_W) 'toggle.c'; else $(CYGPATH_W) '$(srcdir)/toggle.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toggle.Tpo $(DEPDIR)/nip2-toggle.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toggle.c' object='nip2-toggle.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toggle.obj `if test -f 'toggle.c'; then $(CYGPATH_W) 'toggle.c'; else $(CYGPATH_W) '$(srcdir)/toggle.c'; fi` nip2-toggleview.o: toggleview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toggleview.o -MD -MP -MF $(DEPDIR)/nip2-toggleview.Tpo -c -o nip2-toggleview.o `test -f 'toggleview.c' || echo '$(srcdir)/'`toggleview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toggleview.Tpo $(DEPDIR)/nip2-toggleview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toggleview.c' object='nip2-toggleview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toggleview.o `test -f 'toggleview.c' || echo '$(srcdir)/'`toggleview.c nip2-toggleview.obj: toggleview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toggleview.obj -MD -MP -MF $(DEPDIR)/nip2-toggleview.Tpo -c -o nip2-toggleview.obj `if test -f 'toggleview.c'; then $(CYGPATH_W) 'toggleview.c'; else $(CYGPATH_W) '$(srcdir)/toggleview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toggleview.Tpo $(DEPDIR)/nip2-toggleview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toggleview.c' object='nip2-toggleview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toggleview.obj `if test -f 'toggleview.c'; then $(CYGPATH_W) 'toggleview.c'; else $(CYGPATH_W) '$(srcdir)/toggleview.c'; fi` nip2-tool.o: tool.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-tool.o -MD -MP -MF $(DEPDIR)/nip2-tool.Tpo -c -o nip2-tool.o `test -f 'tool.c' || echo '$(srcdir)/'`tool.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-tool.Tpo $(DEPDIR)/nip2-tool.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool.c' object='nip2-tool.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-tool.o `test -f 'tool.c' || echo '$(srcdir)/'`tool.c nip2-tool.obj: tool.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-tool.obj -MD -MP -MF $(DEPDIR)/nip2-tool.Tpo -c -o nip2-tool.obj `if test -f 'tool.c'; then $(CYGPATH_W) 'tool.c'; else $(CYGPATH_W) '$(srcdir)/tool.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-tool.Tpo $(DEPDIR)/nip2-tool.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tool.c' object='nip2-tool.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-tool.obj `if test -f 'tool.c'; then $(CYGPATH_W) 'tool.c'; else $(CYGPATH_W) '$(srcdir)/tool.c'; fi` nip2-toolkit.o: toolkit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkit.o -MD -MP -MF $(DEPDIR)/nip2-toolkit.Tpo -c -o nip2-toolkit.o `test -f 'toolkit.c' || echo '$(srcdir)/'`toolkit.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkit.Tpo $(DEPDIR)/nip2-toolkit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkit.c' object='nip2-toolkit.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkit.o `test -f 'toolkit.c' || echo '$(srcdir)/'`toolkit.c nip2-toolkit.obj: toolkit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkit.obj -MD -MP -MF $(DEPDIR)/nip2-toolkit.Tpo -c -o nip2-toolkit.obj `if test -f 'toolkit.c'; then $(CYGPATH_W) 'toolkit.c'; else $(CYGPATH_W) '$(srcdir)/toolkit.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkit.Tpo $(DEPDIR)/nip2-toolkit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkit.c' object='nip2-toolkit.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkit.obj `if test -f 'toolkit.c'; then $(CYGPATH_W) 'toolkit.c'; else $(CYGPATH_W) '$(srcdir)/toolkit.c'; fi` nip2-toolkitgroup.o: toolkitgroup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkitgroup.o -MD -MP -MF $(DEPDIR)/nip2-toolkitgroup.Tpo -c -o nip2-toolkitgroup.o `test -f 'toolkitgroup.c' || echo '$(srcdir)/'`toolkitgroup.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkitgroup.Tpo $(DEPDIR)/nip2-toolkitgroup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkitgroup.c' object='nip2-toolkitgroup.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkitgroup.o `test -f 'toolkitgroup.c' || echo '$(srcdir)/'`toolkitgroup.c nip2-toolkitgroup.obj: toolkitgroup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkitgroup.obj -MD -MP -MF $(DEPDIR)/nip2-toolkitgroup.Tpo -c -o nip2-toolkitgroup.obj `if test -f 'toolkitgroup.c'; then $(CYGPATH_W) 'toolkitgroup.c'; else $(CYGPATH_W) '$(srcdir)/toolkitgroup.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkitgroup.Tpo $(DEPDIR)/nip2-toolkitgroup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkitgroup.c' object='nip2-toolkitgroup.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkitgroup.obj `if test -f 'toolkitgroup.c'; then $(CYGPATH_W) 'toolkitgroup.c'; else $(CYGPATH_W) '$(srcdir)/toolkitgroup.c'; fi` nip2-toolkitgroupview.o: toolkitgroupview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkitgroupview.o -MD -MP -MF $(DEPDIR)/nip2-toolkitgroupview.Tpo -c -o nip2-toolkitgroupview.o `test -f 'toolkitgroupview.c' || echo '$(srcdir)/'`toolkitgroupview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkitgroupview.Tpo $(DEPDIR)/nip2-toolkitgroupview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkitgroupview.c' object='nip2-toolkitgroupview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkitgroupview.o `test -f 'toolkitgroupview.c' || echo '$(srcdir)/'`toolkitgroupview.c nip2-toolkitgroupview.obj: toolkitgroupview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkitgroupview.obj -MD -MP -MF $(DEPDIR)/nip2-toolkitgroupview.Tpo -c -o nip2-toolkitgroupview.obj `if test -f 'toolkitgroupview.c'; then $(CYGPATH_W) 'toolkitgroupview.c'; else $(CYGPATH_W) '$(srcdir)/toolkitgroupview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkitgroupview.Tpo $(DEPDIR)/nip2-toolkitgroupview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkitgroupview.c' object='nip2-toolkitgroupview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkitgroupview.obj `if test -f 'toolkitgroupview.c'; then $(CYGPATH_W) 'toolkitgroupview.c'; else $(CYGPATH_W) '$(srcdir)/toolkitgroupview.c'; fi` nip2-toolkitview.o: toolkitview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkitview.o -MD -MP -MF $(DEPDIR)/nip2-toolkitview.Tpo -c -o nip2-toolkitview.o `test -f 'toolkitview.c' || echo '$(srcdir)/'`toolkitview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkitview.Tpo $(DEPDIR)/nip2-toolkitview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkitview.c' object='nip2-toolkitview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkitview.o `test -f 'toolkitview.c' || echo '$(srcdir)/'`toolkitview.c nip2-toolkitview.obj: toolkitview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkitview.obj -MD -MP -MF $(DEPDIR)/nip2-toolkitview.Tpo -c -o nip2-toolkitview.obj `if test -f 'toolkitview.c'; then $(CYGPATH_W) 'toolkitview.c'; else $(CYGPATH_W) '$(srcdir)/toolkitview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkitview.Tpo $(DEPDIR)/nip2-toolkitview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkitview.c' object='nip2-toolkitview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkitview.obj `if test -f 'toolkitview.c'; then $(CYGPATH_W) 'toolkitview.c'; else $(CYGPATH_W) '$(srcdir)/toolkitview.c'; fi` nip2-defbrowser.o: defbrowser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-defbrowser.o -MD -MP -MF $(DEPDIR)/nip2-defbrowser.Tpo -c -o nip2-defbrowser.o `test -f 'defbrowser.c' || echo '$(srcdir)/'`defbrowser.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-defbrowser.Tpo $(DEPDIR)/nip2-defbrowser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='defbrowser.c' object='nip2-defbrowser.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-defbrowser.o `test -f 'defbrowser.c' || echo '$(srcdir)/'`defbrowser.c nip2-defbrowser.obj: defbrowser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-defbrowser.obj -MD -MP -MF $(DEPDIR)/nip2-defbrowser.Tpo -c -o nip2-defbrowser.obj `if test -f 'defbrowser.c'; then $(CYGPATH_W) 'defbrowser.c'; else $(CYGPATH_W) '$(srcdir)/defbrowser.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-defbrowser.Tpo $(DEPDIR)/nip2-defbrowser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='defbrowser.c' object='nip2-defbrowser.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-defbrowser.obj `if test -f 'defbrowser.c'; then $(CYGPATH_W) 'defbrowser.c'; else $(CYGPATH_W) '$(srcdir)/defbrowser.c'; fi` nip2-toolkitbrowser.o: toolkitbrowser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkitbrowser.o -MD -MP -MF $(DEPDIR)/nip2-toolkitbrowser.Tpo -c -o nip2-toolkitbrowser.o `test -f 'toolkitbrowser.c' || echo '$(srcdir)/'`toolkitbrowser.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkitbrowser.Tpo $(DEPDIR)/nip2-toolkitbrowser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkitbrowser.c' object='nip2-toolkitbrowser.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkitbrowser.o `test -f 'toolkitbrowser.c' || echo '$(srcdir)/'`toolkitbrowser.c nip2-toolkitbrowser.obj: toolkitbrowser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolkitbrowser.obj -MD -MP -MF $(DEPDIR)/nip2-toolkitbrowser.Tpo -c -o nip2-toolkitbrowser.obj `if test -f 'toolkitbrowser.c'; then $(CYGPATH_W) 'toolkitbrowser.c'; else $(CYGPATH_W) '$(srcdir)/toolkitbrowser.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolkitbrowser.Tpo $(DEPDIR)/nip2-toolkitbrowser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolkitbrowser.c' object='nip2-toolkitbrowser.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolkitbrowser.obj `if test -f 'toolkitbrowser.c'; then $(CYGPATH_W) 'toolkitbrowser.c'; else $(CYGPATH_W) '$(srcdir)/toolkitbrowser.c'; fi` nip2-toolview.o: toolview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolview.o -MD -MP -MF $(DEPDIR)/nip2-toolview.Tpo -c -o nip2-toolview.o `test -f 'toolview.c' || echo '$(srcdir)/'`toolview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolview.Tpo $(DEPDIR)/nip2-toolview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolview.c' object='nip2-toolview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolview.o `test -f 'toolview.c' || echo '$(srcdir)/'`toolview.c nip2-toolview.obj: toolview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-toolview.obj -MD -MP -MF $(DEPDIR)/nip2-toolview.Tpo -c -o nip2-toolview.obj `if test -f 'toolview.c'; then $(CYGPATH_W) 'toolview.c'; else $(CYGPATH_W) '$(srcdir)/toolview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-toolview.Tpo $(DEPDIR)/nip2-toolview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='toolview.c' object='nip2-toolview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-toolview.obj `if test -f 'toolview.c'; then $(CYGPATH_W) 'toolview.c'; else $(CYGPATH_W) '$(srcdir)/toolview.c'; fi` nip2-trace.o: trace.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-trace.o -MD -MP -MF $(DEPDIR)/nip2-trace.Tpo -c -o nip2-trace.o `test -f 'trace.c' || echo '$(srcdir)/'`trace.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-trace.Tpo $(DEPDIR)/nip2-trace.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='trace.c' object='nip2-trace.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-trace.o `test -f 'trace.c' || echo '$(srcdir)/'`trace.c nip2-trace.obj: trace.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-trace.obj -MD -MP -MF $(DEPDIR)/nip2-trace.Tpo -c -o nip2-trace.obj `if test -f 'trace.c'; then $(CYGPATH_W) 'trace.c'; else $(CYGPATH_W) '$(srcdir)/trace.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-trace.Tpo $(DEPDIR)/nip2-trace.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='trace.c' object='nip2-trace.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-trace.obj `if test -f 'trace.c'; then $(CYGPATH_W) 'trace.c'; else $(CYGPATH_W) '$(srcdir)/trace.c'; fi` nip2-tree.o: tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-tree.o -MD -MP -MF $(DEPDIR)/nip2-tree.Tpo -c -o nip2-tree.o `test -f 'tree.c' || echo '$(srcdir)/'`tree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-tree.Tpo $(DEPDIR)/nip2-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tree.c' object='nip2-tree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-tree.o `test -f 'tree.c' || echo '$(srcdir)/'`tree.c nip2-tree.obj: tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-tree.obj -MD -MP -MF $(DEPDIR)/nip2-tree.Tpo -c -o nip2-tree.obj `if test -f 'tree.c'; then $(CYGPATH_W) 'tree.c'; else $(CYGPATH_W) '$(srcdir)/tree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-tree.Tpo $(DEPDIR)/nip2-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tree.c' object='nip2-tree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-tree.obj `if test -f 'tree.c'; then $(CYGPATH_W) 'tree.c'; else $(CYGPATH_W) '$(srcdir)/tree.c'; fi` nip2-tslider.o: tslider.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-tslider.o -MD -MP -MF $(DEPDIR)/nip2-tslider.Tpo -c -o nip2-tslider.o `test -f 'tslider.c' || echo '$(srcdir)/'`tslider.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-tslider.Tpo $(DEPDIR)/nip2-tslider.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tslider.c' object='nip2-tslider.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-tslider.o `test -f 'tslider.c' || echo '$(srcdir)/'`tslider.c nip2-tslider.obj: tslider.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-tslider.obj -MD -MP -MF $(DEPDIR)/nip2-tslider.Tpo -c -o nip2-tslider.obj `if test -f 'tslider.c'; then $(CYGPATH_W) 'tslider.c'; else $(CYGPATH_W) '$(srcdir)/tslider.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-tslider.Tpo $(DEPDIR)/nip2-tslider.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tslider.c' object='nip2-tslider.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-tslider.obj `if test -f 'tslider.c'; then $(CYGPATH_W) 'tslider.c'; else $(CYGPATH_W) '$(srcdir)/tslider.c'; fi` nip2-util.o: util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-util.o -MD -MP -MF $(DEPDIR)/nip2-util.Tpo -c -o nip2-util.o `test -f 'util.c' || echo '$(srcdir)/'`util.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-util.Tpo $(DEPDIR)/nip2-util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util.c' object='nip2-util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-util.o `test -f 'util.c' || echo '$(srcdir)/'`util.c nip2-util.obj: util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-util.obj -MD -MP -MF $(DEPDIR)/nip2-util.Tpo -c -o nip2-util.obj `if test -f 'util.c'; then $(CYGPATH_W) 'util.c'; else $(CYGPATH_W) '$(srcdir)/util.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-util.Tpo $(DEPDIR)/nip2-util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util.c' object='nip2-util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-util.obj `if test -f 'util.c'; then $(CYGPATH_W) 'util.c'; else $(CYGPATH_W) '$(srcdir)/util.c'; fi` nip2-view.o: view.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-view.o -MD -MP -MF $(DEPDIR)/nip2-view.Tpo -c -o nip2-view.o `test -f 'view.c' || echo '$(srcdir)/'`view.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-view.Tpo $(DEPDIR)/nip2-view.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='view.c' object='nip2-view.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-view.o `test -f 'view.c' || echo '$(srcdir)/'`view.c nip2-view.obj: view.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-view.obj -MD -MP -MF $(DEPDIR)/nip2-view.Tpo -c -o nip2-view.obj `if test -f 'view.c'; then $(CYGPATH_W) 'view.c'; else $(CYGPATH_W) '$(srcdir)/view.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-view.Tpo $(DEPDIR)/nip2-view.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='view.c' object='nip2-view.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-view.obj `if test -f 'view.c'; then $(CYGPATH_W) 'view.c'; else $(CYGPATH_W) '$(srcdir)/view.c'; fi` nip2-call.o: call.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-call.o -MD -MP -MF $(DEPDIR)/nip2-call.Tpo -c -o nip2-call.o `test -f 'call.c' || echo '$(srcdir)/'`call.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-call.Tpo $(DEPDIR)/nip2-call.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='call.c' object='nip2-call.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-call.o `test -f 'call.c' || echo '$(srcdir)/'`call.c nip2-call.obj: call.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-call.obj -MD -MP -MF $(DEPDIR)/nip2-call.Tpo -c -o nip2-call.obj `if test -f 'call.c'; then $(CYGPATH_W) 'call.c'; else $(CYGPATH_W) '$(srcdir)/call.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-call.Tpo $(DEPDIR)/nip2-call.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='call.c' object='nip2-call.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-call.obj `if test -f 'call.c'; then $(CYGPATH_W) 'call.c'; else $(CYGPATH_W) '$(srcdir)/call.c'; fi` nip2-cache.o: cache.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-cache.o -MD -MP -MF $(DEPDIR)/nip2-cache.Tpo -c -o nip2-cache.o `test -f 'cache.c' || echo '$(srcdir)/'`cache.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-cache.Tpo $(DEPDIR)/nip2-cache.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cache.c' object='nip2-cache.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-cache.o `test -f 'cache.c' || echo '$(srcdir)/'`cache.c nip2-cache.obj: cache.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-cache.obj -MD -MP -MF $(DEPDIR)/nip2-cache.Tpo -c -o nip2-cache.obj `if test -f 'cache.c'; then $(CYGPATH_W) 'cache.c'; else $(CYGPATH_W) '$(srcdir)/cache.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-cache.Tpo $(DEPDIR)/nip2-cache.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cache.c' object='nip2-cache.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-cache.obj `if test -f 'cache.c'; then $(CYGPATH_W) 'cache.c'; else $(CYGPATH_W) '$(srcdir)/cache.c'; fi` nip2-watch.o: watch.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-watch.o -MD -MP -MF $(DEPDIR)/nip2-watch.Tpo -c -o nip2-watch.o `test -f 'watch.c' || echo '$(srcdir)/'`watch.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-watch.Tpo $(DEPDIR)/nip2-watch.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='watch.c' object='nip2-watch.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-watch.o `test -f 'watch.c' || echo '$(srcdir)/'`watch.c nip2-watch.obj: watch.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-watch.obj -MD -MP -MF $(DEPDIR)/nip2-watch.Tpo -c -o nip2-watch.obj `if test -f 'watch.c'; then $(CYGPATH_W) 'watch.c'; else $(CYGPATH_W) '$(srcdir)/watch.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-watch.Tpo $(DEPDIR)/nip2-watch.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='watch.c' object='nip2-watch.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-watch.obj `if test -f 'watch.c'; then $(CYGPATH_W) 'watch.c'; else $(CYGPATH_W) '$(srcdir)/watch.c'; fi` nip2-workspace.o: workspace.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspace.o -MD -MP -MF $(DEPDIR)/nip2-workspace.Tpo -c -o nip2-workspace.o `test -f 'workspace.c' || echo '$(srcdir)/'`workspace.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspace.Tpo $(DEPDIR)/nip2-workspace.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspace.c' object='nip2-workspace.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspace.o `test -f 'workspace.c' || echo '$(srcdir)/'`workspace.c nip2-workspace.obj: workspace.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspace.obj -MD -MP -MF $(DEPDIR)/nip2-workspace.Tpo -c -o nip2-workspace.obj `if test -f 'workspace.c'; then $(CYGPATH_W) 'workspace.c'; else $(CYGPATH_W) '$(srcdir)/workspace.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspace.Tpo $(DEPDIR)/nip2-workspace.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspace.c' object='nip2-workspace.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspace.obj `if test -f 'workspace.c'; then $(CYGPATH_W) 'workspace.c'; else $(CYGPATH_W) '$(srcdir)/workspace.c'; fi` nip2-workspacegroup.o: workspacegroup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspacegroup.o -MD -MP -MF $(DEPDIR)/nip2-workspacegroup.Tpo -c -o nip2-workspacegroup.o `test -f 'workspacegroup.c' || echo '$(srcdir)/'`workspacegroup.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspacegroup.Tpo $(DEPDIR)/nip2-workspacegroup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspacegroup.c' object='nip2-workspacegroup.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspacegroup.o `test -f 'workspacegroup.c' || echo '$(srcdir)/'`workspacegroup.c nip2-workspacegroup.obj: workspacegroup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspacegroup.obj -MD -MP -MF $(DEPDIR)/nip2-workspacegroup.Tpo -c -o nip2-workspacegroup.obj `if test -f 'workspacegroup.c'; then $(CYGPATH_W) 'workspacegroup.c'; else $(CYGPATH_W) '$(srcdir)/workspacegroup.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspacegroup.Tpo $(DEPDIR)/nip2-workspacegroup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspacegroup.c' object='nip2-workspacegroup.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspacegroup.obj `if test -f 'workspacegroup.c'; then $(CYGPATH_W) 'workspacegroup.c'; else $(CYGPATH_W) '$(srcdir)/workspacegroup.c'; fi` nip2-workspacegroupview.o: workspacegroupview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspacegroupview.o -MD -MP -MF $(DEPDIR)/nip2-workspacegroupview.Tpo -c -o nip2-workspacegroupview.o `test -f 'workspacegroupview.c' || echo '$(srcdir)/'`workspacegroupview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspacegroupview.Tpo $(DEPDIR)/nip2-workspacegroupview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspacegroupview.c' object='nip2-workspacegroupview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspacegroupview.o `test -f 'workspacegroupview.c' || echo '$(srcdir)/'`workspacegroupview.c nip2-workspacegroupview.obj: workspacegroupview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspacegroupview.obj -MD -MP -MF $(DEPDIR)/nip2-workspacegroupview.Tpo -c -o nip2-workspacegroupview.obj `if test -f 'workspacegroupview.c'; then $(CYGPATH_W) 'workspacegroupview.c'; else $(CYGPATH_W) '$(srcdir)/workspacegroupview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspacegroupview.Tpo $(DEPDIR)/nip2-workspacegroupview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspacegroupview.c' object='nip2-workspacegroupview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspacegroupview.obj `if test -f 'workspacegroupview.c'; then $(CYGPATH_W) 'workspacegroupview.c'; else $(CYGPATH_W) '$(srcdir)/workspacegroupview.c'; fi` nip2-workspacedefs.o: workspacedefs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspacedefs.o -MD -MP -MF $(DEPDIR)/nip2-workspacedefs.Tpo -c -o nip2-workspacedefs.o `test -f 'workspacedefs.c' || echo '$(srcdir)/'`workspacedefs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspacedefs.Tpo $(DEPDIR)/nip2-workspacedefs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspacedefs.c' object='nip2-workspacedefs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspacedefs.o `test -f 'workspacedefs.c' || echo '$(srcdir)/'`workspacedefs.c nip2-workspacedefs.obj: workspacedefs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspacedefs.obj -MD -MP -MF $(DEPDIR)/nip2-workspacedefs.Tpo -c -o nip2-workspacedefs.obj `if test -f 'workspacedefs.c'; then $(CYGPATH_W) 'workspacedefs.c'; else $(CYGPATH_W) '$(srcdir)/workspacedefs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspacedefs.Tpo $(DEPDIR)/nip2-workspacedefs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspacedefs.c' object='nip2-workspacedefs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspacedefs.obj `if test -f 'workspacedefs.c'; then $(CYGPATH_W) 'workspacedefs.c'; else $(CYGPATH_W) '$(srcdir)/workspacedefs.c'; fi` nip2-workspaceroot.o: workspaceroot.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspaceroot.o -MD -MP -MF $(DEPDIR)/nip2-workspaceroot.Tpo -c -o nip2-workspaceroot.o `test -f 'workspaceroot.c' || echo '$(srcdir)/'`workspaceroot.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspaceroot.Tpo $(DEPDIR)/nip2-workspaceroot.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspaceroot.c' object='nip2-workspaceroot.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspaceroot.o `test -f 'workspaceroot.c' || echo '$(srcdir)/'`workspaceroot.c nip2-workspaceroot.obj: workspaceroot.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspaceroot.obj -MD -MP -MF $(DEPDIR)/nip2-workspaceroot.Tpo -c -o nip2-workspaceroot.obj `if test -f 'workspaceroot.c'; then $(CYGPATH_W) 'workspaceroot.c'; else $(CYGPATH_W) '$(srcdir)/workspaceroot.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspaceroot.Tpo $(DEPDIR)/nip2-workspaceroot.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspaceroot.c' object='nip2-workspaceroot.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspaceroot.obj `if test -f 'workspaceroot.c'; then $(CYGPATH_W) 'workspaceroot.c'; else $(CYGPATH_W) '$(srcdir)/workspaceroot.c'; fi` nip2-workspaceview.o: workspaceview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspaceview.o -MD -MP -MF $(DEPDIR)/nip2-workspaceview.Tpo -c -o nip2-workspaceview.o `test -f 'workspaceview.c' || echo '$(srcdir)/'`workspaceview.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspaceview.Tpo $(DEPDIR)/nip2-workspaceview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspaceview.c' object='nip2-workspaceview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspaceview.o `test -f 'workspaceview.c' || echo '$(srcdir)/'`workspaceview.c nip2-workspaceview.obj: workspaceview.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -MT nip2-workspaceview.obj -MD -MP -MF $(DEPDIR)/nip2-workspaceview.Tpo -c -o nip2-workspaceview.obj `if test -f 'workspaceview.c'; then $(CYGPATH_W) 'workspaceview.c'; else $(CYGPATH_W) '$(srcdir)/workspaceview.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nip2-workspaceview.Tpo $(DEPDIR)/nip2-workspaceview.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='workspaceview.c' object='nip2-workspaceview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(nip2_CFLAGS) $(CFLAGS) -c -o nip2-workspaceview.obj `if test -f 'workspaceview.c'; then $(CYGPATH_W) 'workspaceview.c'; else $(CYGPATH_W) '$(srcdir)/workspaceview.c'; fi` .l.c: $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am check: check-recursive all-am: Makefile $(PROGRAMS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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." -rm -f lex.c -rm -f parse.c clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f ./$(DEPDIR)/nip2-action.Po -rm -f ./$(DEPDIR)/nip2-boxes.Po -rm -f ./$(DEPDIR)/nip2-builtin.Po -rm -f ./$(DEPDIR)/nip2-cache.Po -rm -f ./$(DEPDIR)/nip2-call.Po -rm -f ./$(DEPDIR)/nip2-class.Po -rm -f ./$(DEPDIR)/nip2-classmodel.Po -rm -f ./$(DEPDIR)/nip2-cli.Po -rm -f ./$(DEPDIR)/nip2-clock.Po -rm -f ./$(DEPDIR)/nip2-colour.Po -rm -f ./$(DEPDIR)/nip2-colourdisplay.Po -rm -f ./$(DEPDIR)/nip2-colourview.Po -rm -f ./$(DEPDIR)/nip2-column.Po -rm -f ./$(DEPDIR)/nip2-columnview.Po -rm -f ./$(DEPDIR)/nip2-compile.Po -rm -f ./$(DEPDIR)/nip2-conversion.Po -rm -f ./$(DEPDIR)/nip2-conversionview.Po -rm -f ./$(DEPDIR)/nip2-defbrowser.Po -rm -f ./$(DEPDIR)/nip2-doubleclick.Po -rm -f ./$(DEPDIR)/nip2-dump.Po -rm -f ./$(DEPDIR)/nip2-editview.Po -rm -f ./$(DEPDIR)/nip2-error.Po -rm -f ./$(DEPDIR)/nip2-expr.Po -rm -f ./$(DEPDIR)/nip2-expression.Po -rm -f ./$(DEPDIR)/nip2-expressionview.Po -rm -f ./$(DEPDIR)/nip2-filemodel.Po -rm -f ./$(DEPDIR)/nip2-filesel.Po -rm -f ./$(DEPDIR)/nip2-floatwindow.Po -rm -f ./$(DEPDIR)/nip2-fontname.Po -rm -f ./$(DEPDIR)/nip2-fontnameview.Po -rm -f ./$(DEPDIR)/nip2-formula.Po -rm -f ./$(DEPDIR)/nip2-graphicview.Po -rm -f ./$(DEPDIR)/nip2-graphwindow.Po -rm -f ./$(DEPDIR)/nip2-group.Po -rm -f ./$(DEPDIR)/nip2-gtkutil.Po -rm -f ./$(DEPDIR)/nip2-heap.Po -rm -f ./$(DEPDIR)/nip2-heapmodel.Po -rm -f ./$(DEPDIR)/nip2-iarrow.Po -rm -f ./$(DEPDIR)/nip2-icontainer.Po -rm -f ./$(DEPDIR)/nip2-idialog.Po -rm -f ./$(DEPDIR)/nip2-iimage.Po -rm -f ./$(DEPDIR)/nip2-iimageview.Po -rm -f ./$(DEPDIR)/nip2-imagedisplay.Po -rm -f ./$(DEPDIR)/nip2-imageheader.Po -rm -f ./$(DEPDIR)/nip2-imageinfo.Po -rm -f ./$(DEPDIR)/nip2-imagemodel.Po -rm -f ./$(DEPDIR)/nip2-imagepresent.Po -rm -f ./$(DEPDIR)/nip2-imageview.Po -rm -f ./$(DEPDIR)/nip2-iobject.Po -rm -f ./$(DEPDIR)/nip2-iregion.Po -rm -f ./$(DEPDIR)/nip2-iregiongroup.Po -rm -f ./$(DEPDIR)/nip2-iregiongroupview.Po -rm -f ./$(DEPDIR)/nip2-iregionview.Po -rm -f ./$(DEPDIR)/nip2-itext.Po -rm -f ./$(DEPDIR)/nip2-itextview.Po -rm -f ./$(DEPDIR)/nip2-iwindow.Po -rm -f ./$(DEPDIR)/nip2-lex.Po -rm -f ./$(DEPDIR)/nip2-link.Po -rm -f ./$(DEPDIR)/nip2-log.Po -rm -f ./$(DEPDIR)/nip2-main.Po -rm -f ./$(DEPDIR)/nip2-mainw.Po -rm -f ./$(DEPDIR)/nip2-managed.Po -rm -f ./$(DEPDIR)/nip2-managedfile.Po -rm -f ./$(DEPDIR)/nip2-managedgobject.Po -rm -f ./$(DEPDIR)/nip2-managedgvalue.Po -rm -f ./$(DEPDIR)/nip2-managedstring.Po -rm -f ./$(DEPDIR)/nip2-matrix.Po -rm -f ./$(DEPDIR)/nip2-matrixview.Po -rm -f ./$(DEPDIR)/nip2-model.Po -rm -f ./$(DEPDIR)/nip2-nipmarshal.Po -rm -f ./$(DEPDIR)/nip2-number.Po -rm -f ./$(DEPDIR)/nip2-numberview.Po -rm -f ./$(DEPDIR)/nip2-option.Po -rm -f ./$(DEPDIR)/nip2-optionview.Po -rm -f ./$(DEPDIR)/nip2-paintboxview.Po -rm -f ./$(DEPDIR)/nip2-pane.Po -rm -f ./$(DEPDIR)/nip2-panechild.Po -rm -f ./$(DEPDIR)/nip2-parse.Po -rm -f ./$(DEPDIR)/nip2-path.Po -rm -f ./$(DEPDIR)/nip2-pathname.Po -rm -f ./$(DEPDIR)/nip2-pathnameview.Po -rm -f ./$(DEPDIR)/nip2-plot.Po -rm -f ./$(DEPDIR)/nip2-plotmodel.Po -rm -f ./$(DEPDIR)/nip2-plotpresent.Po -rm -f ./$(DEPDIR)/nip2-plotstatus.Po -rm -f ./$(DEPDIR)/nip2-plotview.Po -rm -f ./$(DEPDIR)/nip2-plotwindow.Po -rm -f ./$(DEPDIR)/nip2-popupbutton.Po -rm -f ./$(DEPDIR)/nip2-predicate.Po -rm -f ./$(DEPDIR)/nip2-prefcolumnview.Po -rm -f ./$(DEPDIR)/nip2-prefs.Po -rm -f ./$(DEPDIR)/nip2-prefworkspaceview.Po -rm -f ./$(DEPDIR)/nip2-preview.Po -rm -f ./$(DEPDIR)/nip2-program.Po -rm -f ./$(DEPDIR)/nip2-progress.Po -rm -f ./$(DEPDIR)/nip2-real.Po -rm -f ./$(DEPDIR)/nip2-reduce.Po -rm -f ./$(DEPDIR)/nip2-regionview.Po -rm -f ./$(DEPDIR)/nip2-rhs.Po -rm -f ./$(DEPDIR)/nip2-rhsview.Po -rm -f ./$(DEPDIR)/nip2-row.Po -rm -f ./$(DEPDIR)/nip2-rowview.Po -rm -f ./$(DEPDIR)/nip2-secret.Po -rm -f ./$(DEPDIR)/nip2-slider.Po -rm -f ./$(DEPDIR)/nip2-sliderview.Po -rm -f ./$(DEPDIR)/nip2-spin.Po -rm -f ./$(DEPDIR)/nip2-statusview.Po -rm -f ./$(DEPDIR)/nip2-string.Po -rm -f ./$(DEPDIR)/nip2-stringview.Po -rm -f ./$(DEPDIR)/nip2-subcolumn.Po -rm -f ./$(DEPDIR)/nip2-subcolumnview.Po -rm -f ./$(DEPDIR)/nip2-symbol.Po -rm -f ./$(DEPDIR)/nip2-toggle.Po -rm -f ./$(DEPDIR)/nip2-toggleview.Po -rm -f ./$(DEPDIR)/nip2-tool.Po -rm -f ./$(DEPDIR)/nip2-toolkit.Po -rm -f ./$(DEPDIR)/nip2-toolkitbrowser.Po -rm -f ./$(DEPDIR)/nip2-toolkitgroup.Po -rm -f ./$(DEPDIR)/nip2-toolkitgroupview.Po -rm -f ./$(DEPDIR)/nip2-toolkitview.Po -rm -f ./$(DEPDIR)/nip2-toolview.Po -rm -f ./$(DEPDIR)/nip2-trace.Po -rm -f ./$(DEPDIR)/nip2-tree.Po -rm -f ./$(DEPDIR)/nip2-tslider.Po -rm -f ./$(DEPDIR)/nip2-util.Po -rm -f ./$(DEPDIR)/nip2-value.Po -rm -f ./$(DEPDIR)/nip2-valueview.Po -rm -f ./$(DEPDIR)/nip2-vector.Po -rm -f ./$(DEPDIR)/nip2-view.Po -rm -f ./$(DEPDIR)/nip2-vipsobject.Po -rm -f ./$(DEPDIR)/nip2-vobject.Po -rm -f ./$(DEPDIR)/nip2-watch.Po -rm -f ./$(DEPDIR)/nip2-workspace.Po -rm -f ./$(DEPDIR)/nip2-workspacedefs.Po -rm -f ./$(DEPDIR)/nip2-workspacegroup.Po -rm -f ./$(DEPDIR)/nip2-workspacegroupview.Po -rm -f ./$(DEPDIR)/nip2-workspaceroot.Po -rm -f ./$(DEPDIR)/nip2-workspaceview.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/nip2-action.Po -rm -f ./$(DEPDIR)/nip2-boxes.Po -rm -f ./$(DEPDIR)/nip2-builtin.Po -rm -f ./$(DEPDIR)/nip2-cache.Po -rm -f ./$(DEPDIR)/nip2-call.Po -rm -f ./$(DEPDIR)/nip2-class.Po -rm -f ./$(DEPDIR)/nip2-classmodel.Po -rm -f ./$(DEPDIR)/nip2-cli.Po -rm -f ./$(DEPDIR)/nip2-clock.Po -rm -f ./$(DEPDIR)/nip2-colour.Po -rm -f ./$(DEPDIR)/nip2-colourdisplay.Po -rm -f ./$(DEPDIR)/nip2-colourview.Po -rm -f ./$(DEPDIR)/nip2-column.Po -rm -f ./$(DEPDIR)/nip2-columnview.Po -rm -f ./$(DEPDIR)/nip2-compile.Po -rm -f ./$(DEPDIR)/nip2-conversion.Po -rm -f ./$(DEPDIR)/nip2-conversionview.Po -rm -f ./$(DEPDIR)/nip2-defbrowser.Po -rm -f ./$(DEPDIR)/nip2-doubleclick.Po -rm -f ./$(DEPDIR)/nip2-dump.Po -rm -f ./$(DEPDIR)/nip2-editview.Po -rm -f ./$(DEPDIR)/nip2-error.Po -rm -f ./$(DEPDIR)/nip2-expr.Po -rm -f ./$(DEPDIR)/nip2-expression.Po -rm -f ./$(DEPDIR)/nip2-expressionview.Po -rm -f ./$(DEPDIR)/nip2-filemodel.Po -rm -f ./$(DEPDIR)/nip2-filesel.Po -rm -f ./$(DEPDIR)/nip2-floatwindow.Po -rm -f ./$(DEPDIR)/nip2-fontname.Po -rm -f ./$(DEPDIR)/nip2-fontnameview.Po -rm -f ./$(DEPDIR)/nip2-formula.Po -rm -f ./$(DEPDIR)/nip2-graphicview.Po -rm -f ./$(DEPDIR)/nip2-graphwindow.Po -rm -f ./$(DEPDIR)/nip2-group.Po -rm -f ./$(DEPDIR)/nip2-gtkutil.Po -rm -f ./$(DEPDIR)/nip2-heap.Po -rm -f ./$(DEPDIR)/nip2-heapmodel.Po -rm -f ./$(DEPDIR)/nip2-iarrow.Po -rm -f ./$(DEPDIR)/nip2-icontainer.Po -rm -f ./$(DEPDIR)/nip2-idialog.Po -rm -f ./$(DEPDIR)/nip2-iimage.Po -rm -f ./$(DEPDIR)/nip2-iimageview.Po -rm -f ./$(DEPDIR)/nip2-imagedisplay.Po -rm -f ./$(DEPDIR)/nip2-imageheader.Po -rm -f ./$(DEPDIR)/nip2-imageinfo.Po -rm -f ./$(DEPDIR)/nip2-imagemodel.Po -rm -f ./$(DEPDIR)/nip2-imagepresent.Po -rm -f ./$(DEPDIR)/nip2-imageview.Po -rm -f ./$(DEPDIR)/nip2-iobject.Po -rm -f ./$(DEPDIR)/nip2-iregion.Po -rm -f ./$(DEPDIR)/nip2-iregiongroup.Po -rm -f ./$(DEPDIR)/nip2-iregiongroupview.Po -rm -f ./$(DEPDIR)/nip2-iregionview.Po -rm -f ./$(DEPDIR)/nip2-itext.Po -rm -f ./$(DEPDIR)/nip2-itextview.Po -rm -f ./$(DEPDIR)/nip2-iwindow.Po -rm -f ./$(DEPDIR)/nip2-lex.Po -rm -f ./$(DEPDIR)/nip2-link.Po -rm -f ./$(DEPDIR)/nip2-log.Po -rm -f ./$(DEPDIR)/nip2-main.Po -rm -f ./$(DEPDIR)/nip2-mainw.Po -rm -f ./$(DEPDIR)/nip2-managed.Po -rm -f ./$(DEPDIR)/nip2-managedfile.Po -rm -f ./$(DEPDIR)/nip2-managedgobject.Po -rm -f ./$(DEPDIR)/nip2-managedgvalue.Po -rm -f ./$(DEPDIR)/nip2-managedstring.Po -rm -f ./$(DEPDIR)/nip2-matrix.Po -rm -f ./$(DEPDIR)/nip2-matrixview.Po -rm -f ./$(DEPDIR)/nip2-model.Po -rm -f ./$(DEPDIR)/nip2-nipmarshal.Po -rm -f ./$(DEPDIR)/nip2-number.Po -rm -f ./$(DEPDIR)/nip2-numberview.Po -rm -f ./$(DEPDIR)/nip2-option.Po -rm -f ./$(DEPDIR)/nip2-optionview.Po -rm -f ./$(DEPDIR)/nip2-paintboxview.Po -rm -f ./$(DEPDIR)/nip2-pane.Po -rm -f ./$(DEPDIR)/nip2-panechild.Po -rm -f ./$(DEPDIR)/nip2-parse.Po -rm -f ./$(DEPDIR)/nip2-path.Po -rm -f ./$(DEPDIR)/nip2-pathname.Po -rm -f ./$(DEPDIR)/nip2-pathnameview.Po -rm -f ./$(DEPDIR)/nip2-plot.Po -rm -f ./$(DEPDIR)/nip2-plotmodel.Po -rm -f ./$(DEPDIR)/nip2-plotpresent.Po -rm -f ./$(DEPDIR)/nip2-plotstatus.Po -rm -f ./$(DEPDIR)/nip2-plotview.Po -rm -f ./$(DEPDIR)/nip2-plotwindow.Po -rm -f ./$(DEPDIR)/nip2-popupbutton.Po -rm -f ./$(DEPDIR)/nip2-predicate.Po -rm -f ./$(DEPDIR)/nip2-prefcolumnview.Po -rm -f ./$(DEPDIR)/nip2-prefs.Po -rm -f ./$(DEPDIR)/nip2-prefworkspaceview.Po -rm -f ./$(DEPDIR)/nip2-preview.Po -rm -f ./$(DEPDIR)/nip2-program.Po -rm -f ./$(DEPDIR)/nip2-progress.Po -rm -f ./$(DEPDIR)/nip2-real.Po -rm -f ./$(DEPDIR)/nip2-reduce.Po -rm -f ./$(DEPDIR)/nip2-regionview.Po -rm -f ./$(DEPDIR)/nip2-rhs.Po -rm -f ./$(DEPDIR)/nip2-rhsview.Po -rm -f ./$(DEPDIR)/nip2-row.Po -rm -f ./$(DEPDIR)/nip2-rowview.Po -rm -f ./$(DEPDIR)/nip2-secret.Po -rm -f ./$(DEPDIR)/nip2-slider.Po -rm -f ./$(DEPDIR)/nip2-sliderview.Po -rm -f ./$(DEPDIR)/nip2-spin.Po -rm -f ./$(DEPDIR)/nip2-statusview.Po -rm -f ./$(DEPDIR)/nip2-string.Po -rm -f ./$(DEPDIR)/nip2-stringview.Po -rm -f ./$(DEPDIR)/nip2-subcolumn.Po -rm -f ./$(DEPDIR)/nip2-subcolumnview.Po -rm -f ./$(DEPDIR)/nip2-symbol.Po -rm -f ./$(DEPDIR)/nip2-toggle.Po -rm -f ./$(DEPDIR)/nip2-toggleview.Po -rm -f ./$(DEPDIR)/nip2-tool.Po -rm -f ./$(DEPDIR)/nip2-toolkit.Po -rm -f ./$(DEPDIR)/nip2-toolkitbrowser.Po -rm -f ./$(DEPDIR)/nip2-toolkitgroup.Po -rm -f ./$(DEPDIR)/nip2-toolkitgroupview.Po -rm -f ./$(DEPDIR)/nip2-toolkitview.Po -rm -f ./$(DEPDIR)/nip2-toolview.Po -rm -f ./$(DEPDIR)/nip2-trace.Po -rm -f ./$(DEPDIR)/nip2-tree.Po -rm -f ./$(DEPDIR)/nip2-tslider.Po -rm -f ./$(DEPDIR)/nip2-util.Po -rm -f ./$(DEPDIR)/nip2-value.Po -rm -f ./$(DEPDIR)/nip2-valueview.Po -rm -f ./$(DEPDIR)/nip2-vector.Po -rm -f ./$(DEPDIR)/nip2-view.Po -rm -f ./$(DEPDIR)/nip2-vipsobject.Po -rm -f ./$(DEPDIR)/nip2-vobject.Po -rm -f ./$(DEPDIR)/nip2-watch.Po -rm -f ./$(DEPDIR)/nip2-workspace.Po -rm -f ./$(DEPDIR)/nip2-workspacedefs.Po -rm -f ./$(DEPDIR)/nip2-workspacegroup.Po -rm -f ./$(DEPDIR)/nip2-workspacegroupview.Po -rm -f ./$(DEPDIR)/nip2-workspaceroot.Po -rm -f ./$(DEPDIR)/nip2-workspaceview.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--depfiles check check-am clean clean-binPROGRAMS \ clean-generic clean-libtool cscopelist-am ctags ctags-am \ dist-hook distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ 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-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS .PRECIOUS: Makefile helpindex.h: ./makehelpindex.pl $(prefix) > helpindex.h nipmarshal.h: glib-genmarshal --prefix=nip --header nipmarshal.list > nipmarshal.h nipmarshal.c: echo "#include \"nipmarshal.h\"" > nipmarshal.c glib-genmarshal --prefix=nip --body nipmarshal.list >> nipmarshal.c .rc.o: cp ${top_srcdir}/share/nip2/data/nip2-icon.ico . ${WINDRES} $< -o $@ # we have to replace the standard .y.c rule: we are a bison-only GLR parser, # so we can't use autoconf's preferred -y yacc-compatibility stuff .y.c: $(BISON) --defines=$*.h -o $*.c $< nip2-model.o model.o: model.c parse.c dist-hook: ${RM} ${distdir}/parse.c ${distdir}/lex.c # 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: nip2-8.7.1/src/graphicview.c0000644000175000017500000000413313351443023012562 00000000000000/* run the display for a graphic in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; static void graphicview_link( View *view, Model *model, View *parent ) { Graphicview *graphicview = GRAPHICVIEW( view ); View *v; VIEW_CLASS( parent_class )->link( view, model, parent ); /* Find the enclosing subcolumnview. */ for( v = parent; v && !IS_SUBCOLUMNVIEW( v ); v = v->parent ) ; if( v ) graphicview->sview = SUBCOLUMNVIEW( v ); } static void graphicview_class_init( GraphicviewClass *class ) { ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); view_class->link = graphicview_link; } static void graphicview_init( Graphicview *graphicview ) { graphicview->sview = NULL; } GtkType graphicview_get_type( void ) { static GtkType graphicview_type = 0; if( !graphicview_type ) { static const GtkTypeInfo sinfo = { "Graphicview", sizeof( Graphicview ), sizeof( GraphicviewClass ), (GtkClassInitFunc) graphicview_class_init, (GtkObjectInitFunc) graphicview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; graphicview_type = gtk_type_unique( TYPE_VIEW, &sinfo ); } return( graphicview_type ); } nip2-8.7.1/src/numberview.c0000644000175000017500000000606113351443023012437 00000000000000/* a view of a text thingy */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static EditviewClass *parent_class = NULL; /* Re-read the text in a tally entry. */ static void * numberview_scan( View *view ) { Numberview *numberview = NUMBERVIEW( view ); Number *number = NUMBER( VOBJECT( numberview )->iobject ); Expr *expr = HEAPMODEL( number )->row->expr; double value; #ifdef DEBUG Row *row = HEAPMODEL( number )->row; printf( "numberview_scan: " ); row_name_print( row ); printf( "\n" ); #endif /*DEBUG*/ expr_error_clear( expr ); if( !get_geditable_double( EDITVIEW( numberview )->text, &value ) ) { expr_error_set( expr ); return( view ); } if( number->value != value ) { number->value = value; classmodel_update( CLASSMODEL( number ) ) ; } return( VIEW_CLASS( parent_class )->scan( view ) ); } static void numberview_refresh( vObject *vobject ) { Numberview *numberview = NUMBERVIEW( vobject ); Number *number = NUMBER( VOBJECT( numberview )->iobject ); #ifdef DEBUG Row *row = HEAPMODEL( number )->row; printf( "numberview_refresh: " ); row_name_print( row ); printf( " (%p)\n", vobject ); #endif /*DEBUG*/ editview_set_entry( EDITVIEW( numberview ), "%g", number->value ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void numberview_class_init( NumberviewClass *class ) { ViewClass *view_class = (ViewClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ vobject_class->refresh = numberview_refresh; view_class->scan = numberview_scan; } static void numberview_init( Numberview *numberview ) { } GtkType numberview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Numberview", sizeof( Numberview ), sizeof( NumberviewClass ), (GtkClassInitFunc) numberview_class_init, (GtkObjectInitFunc) numberview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_EDITVIEW, &info ); } return( type ); } View * numberview_new( void ) { Numberview *numberview = gtk_type_new( TYPE_NUMBERVIEW ); return( VIEW( numberview ) ); } nip2-8.7.1/src/sliderview.h0000644000175000017500000000312113351443023012430 00000000000000/* a sliderview in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_SLIDERVIEW (sliderview_get_type()) #define SLIDERVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_SLIDERVIEW, Sliderview )) #define SLIDERVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_SLIDERVIEW, SliderviewClass )) #define IS_SLIDERVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_SLIDERVIEW )) #define IS_SLIDERVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_SLIDERVIEW )) typedef struct _Sliderview { Graphicview parent_object; /* My instance vars. */ GtkWidget *label; Tslider *tslider; } Sliderview; typedef struct _SliderviewClass { GraphicviewClass parent_class; /* My methods. */ } SliderviewClass; GtkType sliderview_get_type( void ); View *sliderview_new( void ); nip2-8.7.1/src/plotstatus.c0000644000175000017500000001542413351443023012501 00000000000000/* widgets for the status bar */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GtkFrameClass *parent_class = NULL; /* The popup menu. */ static GtkWidget *plotstatus_menu = NULL; static void plotstatus_columns_destroy( Plotstatus *plotstatus ) { int i; for( i = 0; i < plotstatus->columns; i++ ) DESTROY_GTK( plotstatus->label[i] ); IM_FREE( plotstatus->label ); plotstatus->columns = 0; } static void plotstatus_destroy( GtkObject *object ) { Plotstatus *plotstatus; g_return_if_fail( object != NULL ); g_return_if_fail( IS_PLOTSTATUS( object ) ); plotstatus = PLOTSTATUS( object ); #ifdef DEBUG printf( "plotstatus_destroy\n" ); #endif /*DEBUG*/ plotstatus_columns_destroy( plotstatus ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } /* Hide this plotstatus. */ static void plotstatus_hide_cb( GtkWidget *menu, GtkWidget *host, Plotstatus *plotstatus ) { plotmodel_set_status( plotstatus->plotmodel, FALSE ); } static void plotstatus_class_init( PlotstatusClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidget *pane; parent_class = g_type_class_peek_parent( class ); object_class->destroy = plotstatus_destroy; /* Create signals. */ /* Init methods. */ pane = plotstatus_menu = popup_build( _( "Status bar menu" ) ); popup_add_but( pane, GTK_STOCK_CLOSE, POPUP_FUNC( plotstatus_hide_cb ) ); } static void plotstatus_init( Plotstatus *plotstatus ) { GtkWidget *vb, *hb; GtkWidget *eb; plotstatus->plotmodel = NULL; plotstatus->label = NULL; plotstatus->columns = 0; gtk_frame_set_shadow_type( GTK_FRAME( plotstatus ), GTK_SHADOW_OUT ); eb = gtk_event_box_new(); gtk_container_add( GTK_CONTAINER( plotstatus ), eb ); popup_attach( eb, plotstatus_menu, plotstatus ); vb = gtk_vbox_new( FALSE, 0 ); gtk_container_set_border_width( GTK_CONTAINER( vb ), 1 ); gtk_container_add( GTK_CONTAINER( eb ), vb ); plotstatus->top = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( plotstatus->top ), 0.0, 0.5 ); gtk_box_pack_start( GTK_BOX( vb ), plotstatus->top, TRUE, TRUE, 0 ); hb = gtk_hbox_new( FALSE, 5 ); gtk_box_pack_start( GTK_BOX( vb ), hb, TRUE, TRUE, 0 ); plotstatus->pos = gtk_label_new( "" ); set_fixed( plotstatus->pos, strlen( "(8888888,8888888)" ) ); gtk_misc_set_alignment( GTK_MISC( plotstatus->pos ), 0.0, 0.5 ); gtk_box_pack_start( GTK_BOX( hb ), plotstatus->pos, FALSE, FALSE, 0 ); plotstatus->hb = gtk_hbox_new( FALSE, 5 ); gtk_box_pack_start( GTK_BOX( hb ), plotstatus->hb, TRUE, TRUE, 0 ); plotstatus->mag = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( plotstatus->mag ), 0.0, 0.5 ); gtk_box_pack_end( GTK_BOX( hb ), plotstatus->mag, FALSE, FALSE, 0 ); gtk_widget_show_all( eb ); } GtkType plotstatus_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Plotstatus", sizeof( Plotstatus ), sizeof( PlotstatusClass ), (GtkClassInitFunc) plotstatus_class_init, (GtkObjectInitFunc) plotstatus_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( GTK_TYPE_FRAME, &info ); } return( type ); } /* Model has changed: rebuild everything. */ static void plotstatus_refresh( Plotstatus *plotstatus ) { Plotmodel *plotmodel = plotstatus->plotmodel; Plot *plot = plotmodel->plot; #ifdef DEBUG printf( "plotstatus_refresh: %p\n", plotstatus ); printf( " show_status = %d\n", plotmodel->show_status ); #endif /*DEBUG*/ widget_visible( GTK_WIDGET( plotstatus ), plotmodel->show_status ); /* If we're hidden, no need to do any more. */ if( !plotmodel->show_status ) return; set_glabel( plotstatus->mag, "%s %d%%", _( "Magnification" ), plotmodel->mag ); set_gcaption( plotstatus->top, "%s", IOBJECT( plot )->caption ); if( plotstatus->columns != plot->columns ) { /* Bands/fmt has changed ... rebuild band display widgets. */ int columns; int i; /* Don't display more than 8 series ... it'll make the window * too large. FIXME ... not very kewl */ plotstatus_columns_destroy( plotstatus ); columns = IM_MIN( 8, plot->columns ); if( !(plotstatus->label = IM_ARRAY( NULL, columns, GtkWidget * )) ) return; for( i = 0; i < columns; i++ ) plotstatus->label[i] = NULL; plotstatus->columns = columns; for( i = 0; i < columns; i++ ) { GtkWidget *label; plotstatus->label[i] = label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( label ), 0.0, 0.5 ); set_fixed( label, 8 ); gtk_box_pack_start( GTK_BOX( plotstatus->hb ), label, FALSE, FALSE, 0 ); gtk_widget_show( label ); } } } static void plotstatus_changed_cb( Plotmodel *plotmodel, Plotstatus *plotstatus ) { plotstatus_refresh( plotstatus ); } Plotstatus * plotstatus_new( Plotmodel *plotmodel ) { Plotstatus *plotstatus = gtk_type_new( TYPE_PLOTSTATUS ); plotstatus->plotmodel = plotmodel; g_signal_connect( G_OBJECT( plotmodel ), "changed", G_CALLBACK( plotstatus_changed_cb ), plotstatus ); return( plotstatus ); } /* Find nearest x, display that y. */ static void plotstatus_series_update( GtkWidget *widget, Plot *plot, int column, double x, double y ) { double *xcolumn = plot->xcolumn[column]; double *ycolumn = plot->ycolumn[column]; int i; int best; gdouble best_score; best = 0; best_score = IM_ABS( x - xcolumn[0] ); for( i = 1; i < plot->rows; i++ ) { double score = IM_ABS( x - xcolumn[i] ); if( score < best_score ) { best_score = score; best = i; } } set_glabel( widget, "%g", ycolumn[best] ); } void plotstatus_mouse( Plotstatus *plotstatus, double x, double y ) { Plotmodel *plotmodel = plotstatus->plotmodel; Plot *plot = plotmodel->plot; int i; set_glabel( plotstatus->pos, "(%05g, %05g)", x, y ); g_assert( plotstatus->columns <= plot->columns ); for( i = 0; i < plotstatus->columns; i++ ) plotstatus_series_update( plotstatus->label[i], plot, i, x, y ); } nip2-8.7.1/src/log.c0000644000175000017500000001067413351443023011042 00000000000000/* Abstract base class for a log window: errors, link report, log, etc. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Send log to stdout as well #define DEBUG_FILE */ #include "ip.h" static iWindowClass *parent_class = NULL; static void log_build( GtkWidget *widget ) { Log *log = LOG( widget ); iWindow *iwnd = IWINDOW( widget ); LogClass *log_class = LOG_GET_CLASS( log ); GError *error; GtkWidget *mbar; GtkWidget *swin; PangoFontDescription *font_desc; IWINDOW_CLASS( parent_class )->build( widget ); gtk_action_group_add_actions( iwnd->action_group, log_class->actions, log_class->n_actions, GTK_WINDOW( log ) ); gtk_action_group_add_toggle_actions( iwnd->action_group, log_class->toggle_actions, log_class->n_toggle_actions, GTK_WINDOW( log ) ); if( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager, log_class->ui_description, -1, &error ) ) { g_message( "building menus failed: %s", error->message ); g_error_free( error ); exit( EXIT_FAILURE ); } mbar = gtk_ui_manager_get_widget( iwnd->ui_manager, log_class->menu_bar_name ); gtk_box_pack_start( GTK_BOX( iwnd->work ), mbar, FALSE, FALSE, 0 ); gtk_widget_show( mbar ); swin = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_box_pack_start( GTK_BOX( iwnd->work ), swin, TRUE, TRUE, 0 ); gtk_widget_show( swin ); log->view = gtk_text_view_new(); gtk_text_view_set_editable( GTK_TEXT_VIEW( log->view ), FALSE ); gtk_text_view_set_cursor_visible( GTK_TEXT_VIEW( log->view ), FALSE ); font_desc = pango_font_description_from_string( "Monospace" ); gtk_widget_modify_font( log->view, font_desc ); pango_font_description_free( font_desc ); gtk_container_add( GTK_CONTAINER( swin ), log->view ); gtk_widget_show( log->view ); } static void log_class_init( LogClass *class ) { iWindowClass *iwindow_class = (iWindowClass *) class; parent_class = g_type_class_peek_parent( class ); iwindow_class->build = log_build; class->actions = NULL; class->n_actions = 0; class->toggle_actions = NULL; class->n_toggle_actions = 0; class->action_name = NULL; class->ui_description = NULL; class->menu_bar_name = NULL; } static void log_init( Log *log ) { } GtkType log_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Log", sizeof( Log ), sizeof( LogClass ), (GtkClassInitFunc) log_class_init, (GtkObjectInitFunc) log_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_IWINDOW, &info ); } return( type ); } void log_clear_action_cb( GtkAction *action, Log *log ) { GtkTextView *text_view = GTK_TEXT_VIEW( log->view ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); gtk_text_buffer_set_text( text_buffer, "", 0 ); } void log_text( Log *log, const char *buf ) { GtkTextView *text_view = GTK_TEXT_VIEW( log->view ); GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); GtkTextMark *mark = gtk_text_buffer_get_insert( text_buffer ); GtkTextIter iter; gtk_text_buffer_get_end_iter( text_buffer, &iter ); gtk_text_buffer_move_mark( text_buffer, mark, &iter ); gtk_text_buffer_insert_at_cursor( text_buffer, buf, -1 ); gtk_text_view_scroll_to_mark( text_view, mark, 0.0, TRUE, 0.5, 1 ); #ifdef DEBUG_FILE printf( "%s", buf ); #endif } void log_textf( Log *log, const char *fmt, ... ) { va_list ap; char buf[MAX_STRSIZE]; va_start( ap, fmt ); (void) im_vsnprintf( buf, MAX_STRSIZE, fmt, ap ); va_end( ap ); log_text( log, buf ); } nip2-8.7.1/src/workspacegroup.h0000644000175000017500000001023513351443023013332 00000000000000/* A set of workspaces loaded and saved from a ws file. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_WORKSPACEGROUP (workspacegroup_get_type()) #define WORKSPACEGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ TYPE_WORKSPACEGROUP, Workspacegroup )) #define WORKSPACEGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_WORKSPACEGROUP, WorkspacegroupClass)) #define IS_WORKSPACEGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WORKSPACEGROUP )) #define IS_WORKSPACEGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEGROUP )) #define WORKSPACEGROUP_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_WORKSPACEGROUP, WorkspacegroupClass )) /* Three sorts of workspace file load. */ typedef enum { WORKSPACEGROUP_LOAD_NEW, /* Load as new workspace */ WORKSPACEGROUP_LOAD_COLUMNS, /* Merge into current workspace */ WORKSPACEGROUP_LOAD_ROWS /* Merge rows into current column */ } WorkspacegroupLoadType; /* Save mode ... controls behaviour of column_save_test() and row_save_test() */ typedef enum { WORKSPACEGROUP_SAVE_ALL, /* Save everything */ WORKSPACEGROUP_SAVE_WORKSPACE, /* Save current workspace */ WORKSPACEGROUP_SAVE_SELECTED /* Only save selected rows */ } WorkspacegroupSaveType; /* Workspacegroups: group workspaces with these. One workspacegroup per * file loaded. */ struct _Workspacegroup { Filemodel parent_class; Workspaceroot *wsr; /* Control load/save for this wsg. */ WorkspacegroupLoadType load_type; WorkspacegroupSaveType save_type; guint autosave_timeout; /* workspacegroup_load_columns() etc. use this to display warnings * during load. */ iWindow *iwnd; }; typedef struct _WorkspacegroupClass { FilemodelClass parent_class; /* My methods. */ } WorkspacegroupClass; Workspace *workspacegroup_get_workspace( Workspacegroup *wsg ); int workspacegroup_get_n_objects( Workspacegroup *wsg ); void workspacegroup_set_load_type( Workspacegroup *wsg, WorkspacegroupLoadType load_type ); void workspacegroup_set_save_type( Workspacegroup *wsg, WorkspacegroupSaveType save_type ); Workspace *workspacegroup_map( Workspacegroup *wsg, workspace_map_fn fn, void *a, void *b ); GType workspacegroup_get_type( void ); gboolean workspacegroup_is_empty( Workspacegroup *wsg ); Workspacegroup *workspacegroup_new( Workspaceroot *wsr ); Workspacegroup *workspacegroup_new_blank( Workspaceroot *wsr, const char *name ); Workspacegroup *workspacegroup_new_filename( Workspaceroot *wsr, const char *filename ); Workspacegroup *workspacegroup_new_from_file( Workspaceroot *wsr, const char *filename, const char *filename_user ); Workspacegroup *workspacegroup_new_from_openfile( Workspaceroot *wsr, iOpenFile *of ); gboolean workspacegroup_merge_workspaces( Workspacegroup *wsg, const char *filename ); gboolean workspacegroup_merge_columns( Workspacegroup *wsg, const char *filename ); gboolean workspacegroup_merge_rows( Workspacegroup *wsg, const char *filename ); gboolean workspacegroup_save_selected( Workspacegroup *wsg, const char *filename ); gboolean workspacegroup_save_current( Workspacegroup *wsg, const char *filename ); gboolean workspacegroup_save_all( Workspacegroup *wsg, const char *filename ); Workspacegroup *workspacegroup_duplicate( Workspacegroup *wsg ); char *workspacegroup_autosave_recover( void ); void workspacegroup_autosave_clean( void ); nip2-8.7.1/src/conversionview.h0000644000175000017500000000340413351443023013337 00000000000000/* Decls for conversionview.c ... controls for manipulating a conversion */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_CONVERSIONVIEW (conversionview_get_type()) #define CONVERSIONVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_CONVERSIONVIEW, Conversionview )) #define CONVERSIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_CONVERSIONVIEW, ConversionviewClass )) #define IS_CONVERSIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_CONVERSIONVIEW )) #define IS_CONVERSIONVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_CONVERSIONVIEW )) struct _Conversionview { GtkFrame parent_class; Imagemodel *imagemodel; Tslider *scale; Tslider *offset; GtkWidget *falsecolour; /* Toggle menu items */ GtkWidget *type; }; typedef struct _ConversionviewClass { GtkFrameClass parent_class; /* My methods. */ } ConversionviewClass; GtkType conversionview_get_type( void ); Conversionview *conversionview_new( Imagemodel *imagemodel ); nip2-8.7.1/src/mainw.c0000644000175000017500000015301713351443023011373 00000000000000/* main processing window */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ /* Load and save recent items here. */ #define RECENT_WORKSPACE "recent_workspace" #define RECENT_IMAGE "recent_image" #define RECENT_MATRIX "recent_matrix" /* Recently loaded/saved workspaces, images and matricies. */ GSList *mainw_recent_workspace = NULL; GSList *mainw_recent_image = NULL; GSList *mainw_recent_matrix = NULL; /* Auto-recalc state. Don't do this as a preference, since preferences are * workspaces and need to have recalc working to operate. */ gboolean mainw_auto_recalc = TRUE; static gint mainw_layout_timeout = 0; static iWindowClass *parent_class = NULL; /* All the mainw. */ static GSList *mainw_all = NULL; void mainw_startup( void ) { IM_FREEF( recent_free, mainw_recent_workspace ); IM_FREEF( recent_free, mainw_recent_image ); IM_FREEF( recent_free, mainw_recent_matrix ); mainw_recent_workspace = recent_load( RECENT_WORKSPACE ); mainw_recent_image = recent_load( RECENT_IMAGE ); mainw_recent_matrix = recent_load( RECENT_MATRIX ); } void mainw_shutdown( void ) { recent_save( mainw_recent_workspace, RECENT_WORKSPACE ); recent_save( mainw_recent_image, RECENT_IMAGE ); recent_save( mainw_recent_matrix, RECENT_MATRIX ); IM_FREEF( recent_free, mainw_recent_workspace ); IM_FREEF( recent_free, mainw_recent_image ); IM_FREEF( recent_free, mainw_recent_matrix ); } static int mainw_recent_freeze_count = 0; void mainw_recent_freeze( void ) { mainw_recent_freeze_count += 1; } void mainw_recent_thaw( void ) { g_assert( mainw_recent_freeze_count > 0 ); mainw_recent_freeze_count -= 1; } void mainw_recent_add( GSList **recent, const char *filename ) { if( !mainw_recent_freeze_count ) { char buf[FILENAME_MAX]; im_strncpy( buf, PATH_TMP, FILENAME_MAX ); path_expand( buf ); if( filename && strcmp( filename, "" ) != 0 && !is_prefix( buf, filename ) ) *recent = recent_add( *recent, filename ); } } /* Pick a mainw at random. Used if we need a window for a dialog, and we're * not sure which to pick. */ Mainw * mainw_pick_one( void ) { if( !mainw_all ) /* Must be a cast here, since iwindow_pick_one() can return * NULL during shutdown. */ return( (Mainw *) iwindow_pick_one() ); return( MAINW( mainw_all->data ) ); } static void mainw_finalize( GObject *gobject ) { #ifdef DEBUG printf( "mainw_finalize: %p\n", gobject ); #endif /*DEBUG*/ g_return_if_fail( gobject != NULL ); g_return_if_fail( IS_MAINW( gobject ) ); G_OBJECT_CLASS( parent_class )->finalize( gobject ); } static void mainw_dispose( GObject *object ) { Mainw *mainw; g_return_if_fail( object != NULL ); g_return_if_fail( IS_MAINW( object ) ); mainw = MAINW( object ); #ifdef DEBUG printf( "mainw_dispose\n" ); #endif /*DEBUG*/ IM_FREEF( g_source_remove, mainw->refresh_timeout ); FREESID( mainw->changed_sid, mainw->wsg ); FREESID( mainw->imageinfo_changed_sid, main_imageinfogroup ); FREESID( mainw->heap_changed_sid, reduce_context->heap ); FREESID( mainw->watch_changed_sid, main_watchgroup ); FREESID( mainw->begin_sid, progress_get() ); FREESID( mainw->update_sid, progress_get() ); FREESID( mainw->end_sid, progress_get() ); UNREF( mainw->kitgview ); /* We don't unref wsg: it's destroyed by mainw_popdown() with * filemodel_inter_savenclose_cb(). */ mainw_all = g_slist_remove( mainw_all, mainw ); G_OBJECT_CLASS( parent_class )->dispose( object ); } static void * mainw_configure_event_sub( Workspace *ws, GdkEventConfigure *event ) { MODEL( ws )->window_x = event->x; MODEL( ws )->window_y = event->y; MODEL( ws )->window_width = event->width; MODEL( ws )->window_height = event->height; return( NULL ); } static gboolean mainw_configure_event( GtkWidget *widget, GdkEventConfigure *event ) { Mainw *mainw = MAINW( widget ); /* We have to record on all wses, since we don't know which will be * first on reload. */ workspacegroup_map( mainw->wsg, (workspace_map_fn) mainw_configure_event_sub, event, NULL ); return( GTK_WIDGET_CLASS( parent_class )-> configure_event( widget, event ) ); } static void mainw_class_init( MainwClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); GtkWidgetClass *widget_class = (GtkWidgetClass *) class; parent_class = g_type_class_peek_parent( class ); gobject_class->finalize = mainw_finalize; gobject_class->dispose = mainw_dispose; widget_class->configure_event = mainw_configure_event; } static void mainw_progress_begin( Progress *progress, Mainw *mainw ) { mainw->cancel = FALSE; gtk_widget_show( mainw->progress_box ); } static void mainw_progress_update( Progress *progress, gboolean *cancel, Mainw *mainw ) { gtk_progress_bar_set_text( GTK_PROGRESS_BAR( mainw->progress ), vips_buf_all( &progress->feedback ) ); gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( mainw->progress ), IM_CLIP( 0.0, (double) progress->percent / 100.0, 1.0 ) ); if( mainw->cancel ) *cancel = TRUE; } static void mainw_progress_end( Progress *progress, Mainw *mainw ) { gtk_widget_hide( mainw->progress_box ); mainw->cancel = FALSE; } static void mainw_init( Mainw *mainw ) { mainw->wsg = NULL; mainw->changed_sid = 0; mainw->imageinfo_changed_sid = 0; mainw->heap_changed_sid = 0; mainw->watch_changed_sid = 0; mainw->begin_sid = g_signal_connect( progress_get(), "begin", G_CALLBACK( mainw_progress_begin ), mainw ); mainw->update_sid = g_signal_connect( progress_get(), "update", G_CALLBACK( mainw_progress_update ), mainw ); mainw->end_sid = g_signal_connect( progress_get(), "end", G_CALLBACK( mainw_progress_end ), mainw ); mainw->cancel = FALSE; mainw->free_type = FALSE; mainw->toolbar_visible = MAINW_TOOLBAR; mainw->statusbar_visible = MAINW_STATUSBAR; mainw->kitgview = NULL; mainw->toolbar = NULL; mainw->statusbar_main = NULL; mainw->statusbar = NULL; mainw->space_free = NULL; mainw->space_free_eb = NULL; mainw->progress_box = NULL; mainw->progress = NULL; mainw_all = g_slist_prepend( mainw_all, mainw ); } GType mainw_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( MainwClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) mainw_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Mainw ), 32, /* n_preallocs */ (GInstanceInitFunc) mainw_init, }; type = g_type_register_static( TYPE_IWINDOW, "Mainw", &info, 0 ); } return( type ); } static void mainw_cancel_cb( GtkWidget *wid, Mainw *mainw ) { mainw->cancel = TRUE; } void mainw_find_disc( VipsBuf *buf ) { double sz = find_space( PATH_TMP ); if( sz < 0 ) vips_buf_appendf( buf, _( "No temp area" ) ); else { char txt[MAX_STRSIZE]; VipsBuf buf2 = VIPS_BUF_STATIC( txt ); vips_buf_append_size( &buf2, sz ); vips_buf_appendf( buf, _( "%s free" ), vips_buf_all( &buf2 ) ); } } void mainw_find_heap( VipsBuf *buf, Heap *heap ) { /* How much we can still expand the heap by ... this * can be -ve if we've closed a workspace, or changed * the upper limit. */ int togo = IM_MAX( 0, (heap->mxb - heap->nb) * heap->rsz ); vips_buf_appendf( buf, _( "%d cells free" ), heap->nfree + togo ); } Workspace * mainw_get_workspace( Mainw *mainw ) { Workspace *ws; if( mainw->wsg && (ws = WORKSPACE( ICONTAINER( mainw->wsg )->current )) ) return( ws ); return( NULL ); } Workspace * mainw_next_workspace( Mainw *mainw ) { Workspace *ws; if( mainw->wsg && (ws = WORKSPACE( icontainer_next( ICONTAINER( mainw->wsg ) ) )) ) return( ws ); return( NULL ); } /* Update the space remaining indicator. */ static void mainw_free_update( Mainw *mainw ) { Heap *heap = reduce_context->heap; char txt[80]; VipsBuf buf = VIPS_BUF_STATIC( txt ); Workspace *ws; if( (ws = mainw_get_workspace( mainw )) && workspace_selected_any( ws ) ) { vips_buf_appends( &buf, _( "Selected:" ) ); vips_buf_appends( &buf, " " ); workspace_selected_names( ws, &buf, ", " ); } else { /* Out of space? Make sure we swap to cell display. */ if( !heap->free ) mainw->free_type = FALSE; if( mainw->free_type ) mainw_find_heap( &buf, heap ); else mainw_find_disc( &buf ); } set_glabel( mainw->space_free, "%s", vips_buf_all( &buf ) ); } static void mainw_title_update( Mainw *mainw ) { Workspace *ws; char txt[512]; VipsBuf buf = VIPS_BUF_STATIC( txt ); char *filename; if( mainw->wsg && FILEMODEL( mainw->wsg )->modified ) vips_buf_appendf( &buf, "*" ); if( mainw->wsg && (filename = FILEMODEL( mainw->wsg )->filename) ) { char *base = g_path_get_basename( filename ); char *dir = g_path_get_dirname( filename ); vips_buf_appendf( &buf, "%s (%s)", base, dir ); g_free( base ); g_free( dir ); } else vips_buf_appends( &buf, _( "unsaved workspace" ) ); if( (ws = mainw_get_workspace( mainw )) ) { vips_buf_appends( &buf, " - " ); vips_buf_appendf( &buf, "%s", NN( IOBJECT( ws->sym )->name ) ); if( ws->compat_major ) { vips_buf_appends( &buf, " - " ); vips_buf_appends( &buf, _( "compatibility mode" ) ); vips_buf_appendf( &buf, " %d.%d", ws->compat_major, ws->compat_minor ); } } vips_buf_appendf( &buf, " - %s", PACKAGE ); iwindow_set_title( IWINDOW( mainw ), "%s", vips_buf_all( &buf ) ); } static void mainw_status_update( Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) && ws->status ) gtk_label_set_text( GTK_LABEL( mainw->statusbar ), ws->status ); else { char txt[256]; im_snprintf( txt, 256, _( NIP_COPYRIGHT ), PACKAGE ); gtk_label_set_markup( GTK_LABEL( mainw->statusbar ), txt ); } } static gboolean mainw_refresh_timeout_cb( gpointer user_data ) { static GtkToolbarStyle styles[] = { 0, /* Overwrite with system default */ GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT, GTK_TOOLBAR_BOTH, GTK_TOOLBAR_BOTH_HORIZ }; static gboolean inited_default_style = FALSE; /* Keep in step with the WorkspaceMode enum. */ const static char *view_mode[] = { "Normal", "ShowFormula", "NoEdit" }; Mainw *mainw = MAINW( user_data ); iWindow *iwnd = IWINDOW( mainw ); int pref = IM_CLIP( 0, MAINW_TOOLBAR_STYLE, IM_NUMBER( styles ) - 1 ); GtkAction *action; Workspace *ws; #ifdef DEBUG printf( "mainw_refresh_timeout_cb: %p\n", mainw ); #endif /*DEBUG*/ mainw->refresh_timeout = 0; mainw_status_update( mainw ); mainw_free_update( mainw ); mainw_title_update( mainw ); if( !inited_default_style ) { styles[0] = gtk_toolbar_get_style( GTK_TOOLBAR( mainw->toolbar ) ); inited_default_style = TRUE; } gtk_toolbar_set_style( GTK_TOOLBAR( mainw->toolbar ), styles[pref] ); action = gtk_action_group_get_action( iwnd->action_group, "AutoRecalculate" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), mainw_auto_recalc ); action = gtk_action_group_get_action( iwnd->action_group, "Toolbar" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), mainw->toolbar_visible ); widget_visible( mainw->toolbar, mainw->toolbar_visible ); action = gtk_action_group_get_action( iwnd->action_group, "Statusbar" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), mainw->statusbar_visible ); widget_visible( mainw->statusbar_main, mainw->statusbar_visible ); if( (ws = mainw_get_workspace( mainw )) ) { action = gtk_action_group_get_action( iwnd->action_group, "Lock" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), ws->locked ); action = gtk_action_group_get_action( iwnd->action_group, "Tabdefs" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), ws->lpane_open ); action = gtk_action_group_get_action( iwnd->action_group, "ToolkitBrowser" ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), ws->rpane_open ); action = gtk_action_group_get_action( iwnd->action_group, view_mode[ws->mode] ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ), TRUE ); workspace_jump_update( ws, mainw->jump_to_column_menu ); if( mainw->kitg != ws->kitg ) { UNREF( mainw->kitgview ); mainw->kitgview = TOOLKITGROUPVIEW( model_view_new( MODEL( ws->kitg ), NULL ) ); g_object_ref( G_OBJECT( mainw->kitgview ) ); gtk_object_sink( GTK_OBJECT( mainw->kitgview ) ); toolkitgroupview_set_mainw( mainw->kitgview, mainw ); gtk_menu_set_accel_group( GTK_MENU( mainw->kitgview->menu ), iwnd->accel_group ); mainw->kitg = ws->kitg; } } return( FALSE ); } static void mainw_refresh( Mainw *mainw ) { IM_FREEF( g_source_remove, mainw->refresh_timeout ); mainw->refresh_timeout = g_timeout_add( 100, (GSourceFunc) mainw_refresh_timeout_cb, mainw ); } static void mainw_duplicate_action_cb( GtkAction *action, Mainw *mainw ) { Workspacegroup *new_wsg; Mainw *new_mainw; progress_begin(); if( !(new_wsg = workspacegroup_duplicate( mainw->wsg )) ) { progress_end(); iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR ); return; } new_mainw = mainw_new( new_wsg ); gtk_widget_show( GTK_WIDGET( new_mainw ) ); symbol_recalculate_all(); progress_end(); } static void mainw_save_action_cb( GtkAction *action, Mainw *mainw ) { workspacegroup_set_save_type( mainw->wsg, WORKSPACEGROUP_SAVE_ALL ); filemodel_inter_save( IWINDOW( mainw ), FILEMODEL( mainw->wsg ) ); } static void mainw_save_as_action_cb( GtkAction *action, Mainw *mainw ) { workspacegroup_set_save_type( mainw->wsg, WORKSPACEGROUP_SAVE_ALL ); filemodel_inter_saveas( IWINDOW( mainw ), FILEMODEL( mainw->wsg ) ); } /* Event in the "space free" display ... toggle mode on left click. */ static gint mainw_space_free_event( GtkWidget *widget, GdkEvent *ev, Mainw *mainw ) { if( ev->type == GDK_BUTTON_RELEASE ) { mainw->free_type = !mainw->free_type; mainw_free_update( mainw ); } return( FALSE ); } /* Count number and sizes of all image objects. */ static void * mainw_count_images( VipsObject *object, int *n ) { if( VIPS_IS_IMAGE( object ) ) *n += 1; return( NULL ); } static void * mainw_size_images( VipsObject *object, size_t *size ) { if( VIPS_IS_IMAGE( object ) ) *size += VIPS_IMAGE_SIZEOF_IMAGE( VIPS_IMAGE( object ) ); return( NULL ); } static void mainw_space_free_tooltip_generate( GtkWidget *widget, VipsBuf *buf, Mainw *mainw ) { Heap *heap = reduce_context->heap; size_t size; int n; mainw_find_disc( buf ); /* Expands to (eg.) "14GB free in /pics/tmp" */ vips_buf_appendf( buf, _( " in \"%s\"" ), PATH_TMP ); vips_buf_appends( buf, ", " ); vips_buf_appendf( buf, _( "%d cells in heap, %d cells free, %d cells maximum" ), heap->ncells, heap->nfree, heap->max_fn( heap ) ); vips_buf_appends( buf, ", " ); if( mainw->wsg ) { vips_buf_appendf( buf, _( "%d objects in workspace" ), workspacegroup_get_n_objects( mainw->wsg ) ); vips_buf_appends( buf, ", " ); } vips_buf_appendf( buf, _( "%d vips calls cached" ), cache_history_size ); vips_buf_appends( buf, ", " ); vips_buf_appendf( buf, _( "using %d threads" ), im_concurrency_get() ); vips_buf_appends( buf, ", " ); size = 0; vips_object_map( (VipsSListMap2Fn) mainw_size_images, &size, NULL ); n = 0; vips_object_map( (VipsSListMap2Fn) mainw_count_images, &n, NULL ); vips_buf_append_size( buf, size ); vips_buf_appendf( buf, _( " in %d images" ), n ); } static void mainw_free_changed_cb( gpointer *dummy, Mainw *mainw ) { mainw_free_update( mainw ); mainw_status_update( mainw ); } /* Go to home page. */ void mainw_homepage_action_cb( GtkAction *action, iWindow *iwnd ) { box_url( GTK_WIDGET( iwnd ), VIPS_HOMEPAGE ); } /* About... box. */ void mainw_about_action_cb( GtkAction *action, iWindow *iwnd ) { box_about( GTK_WIDGET( iwnd ) ); } /* User's guide. */ void mainw_guide_action_cb( GtkAction *action, iWindow *iwnd ) { box_url( GTK_WIDGET( iwnd ), "file://" NIP_DOCPATH "/nipguide.html" ); } static void mainw_selected_duplicate_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; progress_begin(); if( (ws = mainw_get_workspace( mainw )) && !workspace_selected_duplicate( ws ) ) iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR ); progress_end(); } /* Ungroup the selected object(s), or the bottom object. */ static void mainw_ungroup_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; progress_begin(); if( (ws = mainw_get_workspace( mainw )) && !workspace_selected_ungroup( ws ) ) iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR ); progress_end(); } /* Group the selected object(s). */ void mainw_group_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) workspace_selected_group( ws ); } /* Select all objects. */ static void mainw_select_all_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) workspace_select_all( ws ); } static void mainw_find_action_cb( GtkAction *action, Mainw *mainw ) { error_top( _( "Not implemented." ) ); error_sub( _( "Find in workspace not implemented yet." ) ); iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO ); } static void mainw_find_again_action_cb( GtkAction *action, Mainw *mainw ) { error_top( _( "Not implemented." ) ); error_sub( _( "Find again in workspace not implemented yet." ) ); iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO ); } void mainw_next_error_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *first_ws; Workspace *ws; if( !(first_ws = mainw_get_workspace( mainw )) ) return; do { ws = mainw_get_workspace( mainw ); if( workspace_next_error( ws ) ) return; ws = mainw_next_workspace( mainw ); } while( ws != first_ws ); error_top( _( "No errors in workspace." ) ); error_sub( "%s", _( "There are no errors (that I can see) " "in this workspace." ) ); iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO ); } static void mainw_force_calc_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) && workspace_selected_any( ws ) ) { if( !workspace_selected_recalc( ws ) ) iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR ); } else symbol_recalculate_all_force( TRUE ); } Workspacegroup * mainw_open_workspace( Workspaceroot *wsr, const char *filename ) { Workspacegroup *wsg; Mainw *mainw; if( !(wsg = workspacegroup_new_from_file( wsr, filename, filename )) ) return( NULL ); mainw = mainw_new( wsg ); gtk_widget_show( GTK_WIDGET( mainw ) ); return( wsg ); } /* Track these during a load. */ typedef struct { Mainw *mainw; VipsBuf *buf; int nitems; } MainwLoad; /* Try to open a file. Workspace files we load immediately, other ones we * add the load to a buffer. */ static void * mainw_open_fn( Filesel *filesel, const char *filename, MainwLoad *load ) { Workspaceroot *wsr = load->mainw->wsg->wsr; if( is_file_type( &filesel_wfile_type, filename ) ) { if( !mainw_open_workspace( wsr, filename ) ) return( filesel ); mainw_recent_add( &mainw_recent_workspace, filename ); } else { if( load->nitems ) vips_buf_appends( load->buf, ", " ); if( !workspace_load_file_buf( load->buf, filename ) ) return( filesel ); mainw_recent_add( &mainw_recent_image, filename ); load->nitems += 1; } return( NULL ); } /* Callback from load browser. */ static void mainw_open_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Mainw *mainw = MAINW( client ); Filesel *filesel = FILESEL( iwnd ); char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); MainwLoad load; Workspace *ws; load.mainw = mainw; load.buf = &buf; load.nitems = 0; if( filesel_map_filename_multi( filesel, (FileselMapFn) mainw_open_fn, &load, NULL ) ) { nfn( sys, IWINDOW_ERROR ); return; } /* Some actual files (image, matrix) were selected. Load into * the current workspace. */ if( load.nitems && (ws = mainw_get_workspace( mainw )) ) { char txt2[MAX_STRSIZE]; VipsBuf buf2 = VIPS_BUF_STATIC( txt2 ); if( load.nitems > 1 ) vips_buf_appendf( &buf2, "Group [%s]", vips_buf_all( &buf ) ); else vips_buf_appends( &buf2, vips_buf_all( &buf ) ); if( !workspace_add_def_recalc( ws, vips_buf_all( &buf2 ) ) ) { error_top( _( "Load failed." ) ); error_sub( _( "Unable to execute:\n %s" ), vips_buf_all( &buf2 ) ); nfn( sys, IWINDOW_ERROR ); return; } } /* Wses will need a recalc. */ symbol_recalculate_all(); /* If we had an empty wsg, perhaps we've just started up, * kill it. */ if( workspacegroup_is_empty( mainw->wsg ) ) { filemodel_set_modified( FILEMODEL( mainw->wsg ), FALSE ); iwindow_kill( IWINDOW( mainw ) ); } nfn( sys, IWINDOW_YES ); } /* Show an open file dialog ... any type, but default to one of the image * ones. */ static void mainw_open( Mainw *mainw ) { GtkWidget *filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Open File" ) ); filesel_set_flags( FILESEL( filesel ), TRUE, FALSE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_mainw, IMAGE_FILE_TYPE ); filesel_set_filetype_pref( FILESEL( filesel ), "IMAGE_FILE_TYPE" ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) ); filesel_set_done( FILESEL( filesel ), mainw_open_done_cb, mainw ); filesel_set_multi( FILESEL( filesel ), TRUE ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } void mainw_open_action_cb( GtkAction *action, Mainw *mainw ) { mainw_open( mainw ); } /* Open one of the example workspaces ... just a shortcut. */ static void mainw_open_examples( Mainw *mainw ) { GtkWidget *filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Open File" ) ); filesel_set_flags( FILESEL( filesel ), TRUE, FALSE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) ); filesel_set_done( FILESEL( filesel ), mainw_open_done_cb, mainw ); filesel_set_multi( FILESEL( filesel ), TRUE ); iwindow_build( IWINDOW( filesel ) ); filesel_set_filename( FILESEL( filesel ), "$VIPSHOME" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S "data" G_DIR_SEPARATOR_S "examples" G_DIR_SEPARATOR_S "1_point_mosaic" ); /* Reset the filetype ... setting the filename will have changed it to * 'all', since there's no suffix. */ filesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); gtk_widget_show( GTK_WIDGET( filesel ) ); } static void mainw_open_examples_action_cb( GtkAction *action, Mainw *mainw ) { mainw_open_examples( mainw ); } static gboolean mainw_recent_open( Mainw *mainw, const char *filename ) { Workspacegroup *wsg = mainw->wsg; if( is_file_type( &filesel_wfile_type, filename ) ) { if( !mainw_open_workspace( wsg->wsr, filename ) ) return( FALSE ); /* If we had an empty wsg, perhaps we've just started up, * kill it. */ if( workspacegroup_is_empty( wsg ) ) { filemodel_set_modified( FILEMODEL( wsg ), FALSE ); iwindow_kill( IWINDOW( mainw ) ); } } else { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) && !workspace_load_file( ws, filename ) ) return( FALSE ); } return( TRUE ); } static void mainw_recent_open_cb( GtkWidget *widget, const char *filename ) { Mainw *mainw = MAINW( iwindow_get_root( widget ) ); progress_begin(); if( !mainw_recent_open( mainw, filename ) ) { iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR ); progress_end(); return; } progress_end(); symbol_recalculate_all(); } static void mainw_recent_build( GtkWidget *menu, GSList *recent ) { GSList *p; for( p = recent; p; p = p->next ) { const char *filename = (const char *) p->data; GtkWidget *item; char txt[80]; VipsBuf buf = VIPS_BUF_STATIC( txt ); char *utf8; vips_buf_appendf( &buf, " %s", im_skip_dir( filename ) ); utf8 = f2utf8( vips_buf_all( &buf ) ); item = gtk_menu_item_new_with_label( utf8 ); g_free( utf8 ); utf8 = f2utf8( filename ); set_tooltip( item, "%s", utf8 ); g_free( utf8 ); gtk_menu_append( GTK_MENU( menu ), item ); gtk_widget_show( item ); gtk_signal_connect( GTK_OBJECT( item ), "activate", GTK_SIGNAL_FUNC( mainw_recent_open_cb ), (char *) filename ); } } static void mainw_recent_clear_cb( GtkWidget *widget, const char *filename ) { IM_FREEF( recent_free, mainw_recent_workspace ); IM_FREEF( recent_free, mainw_recent_image ); IM_FREEF( recent_free, mainw_recent_matrix ); /* Need to remove files too to prevent merge on quit. */ (void) unlinkf( "%s" G_DIR_SEPARATOR_S "%s", get_savedir(), RECENT_WORKSPACE ); (void) unlinkf( "%s" G_DIR_SEPARATOR_S "%s", get_savedir(), RECENT_IMAGE ); (void) unlinkf( "%s" G_DIR_SEPARATOR_S "%s", get_savedir(), RECENT_MATRIX ); } static void mainw_recent_map_cb( GtkWidget *widget, Mainw *mainw ) { GtkWidget *menu = mainw->recent_menu; GtkWidget *item; gtk_container_foreach( GTK_CONTAINER( menu ), (GtkCallback) gtk_widget_destroy, NULL ); if( mainw_recent_image ) { item = gtk_menu_item_new_with_label( _( "Recent Images" ) ); gtk_menu_append( GTK_MENU( menu ), item ); gtk_widget_show( item ); gtk_widget_set_sensitive( item, FALSE ); mainw_recent_build( menu, mainw_recent_image ); } if( mainw_recent_workspace ) { item = gtk_menu_item_new_with_label( _( "Recent Workspaces" ) ); gtk_menu_append( GTK_MENU( menu ), item ); gtk_widget_show( item ); gtk_widget_set_sensitive( item, FALSE ); mainw_recent_build( menu, mainw_recent_workspace ); } if( mainw_recent_matrix ) { item = gtk_menu_item_new_with_label( _( "Recent Matricies" ) ); gtk_menu_append( GTK_MENU( menu ), item ); gtk_widget_show( item ); gtk_widget_set_sensitive( item, FALSE ); mainw_recent_build( menu, mainw_recent_matrix ); } if( !mainw_recent_workspace && !mainw_recent_image && !mainw_recent_matrix ) { item = gtk_menu_item_new_with_label( _( "No recent items" ) ); gtk_menu_append( GTK_MENU( menu ), item ); gtk_widget_show( item ); gtk_widget_set_sensitive( item, FALSE ); } else { item = gtk_menu_item_new_with_label( _( "Clear Recent Menu" ) ); gtk_menu_append( GTK_MENU( menu ), item ); gtk_widget_show( item ); gtk_signal_connect( GTK_OBJECT( item ), "activate", GTK_SIGNAL_FUNC( mainw_recent_clear_cb ), NULL ); } } /* Merge a .ws into this wsg. */ static void * mainw_workspace_merge_fn( Filesel *filesel, const char *filename, void *a, void *b ) { Mainw *mainw = MAINW( a ); if( !workspacegroup_merge_workspaces( mainw->wsg, filename ) ) return( filesel ); /* Process some events to make sure we rethink the layout and * are able to get the append-at-RHS offsets. */ process_events(); symbol_recalculate_all(); mainw_recent_add( &mainw_recent_workspace, filename ); return( NULL ); } /* Callback from load browser. */ static void mainw_workspace_merge_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Filesel *filesel = FILESEL( iwnd ); Mainw *mainw = MAINW( client ); if( filesel_map_filename_multi( filesel, mainw_workspace_merge_fn, mainw, NULL ) ) { symbol_recalculate_all(); nfn( sys, IWINDOW_ERROR ); return; } symbol_recalculate_all(); nfn( sys, IWINDOW_YES ); } /* Merge ws file into current ws. */ void mainw_workspace_merge( Mainw *mainw ) { GtkWidget *filesel = filesel_new(); iwindow_set_title( IWINDOW( filesel ), _( "Merge Workspace from File" ) ); filesel_set_flags( FILESEL( filesel ), FALSE, FALSE ); filesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) ); filesel_set_done( FILESEL( filesel ), mainw_workspace_merge_done_cb, mainw ); filesel_set_multi( FILESEL( filesel ), TRUE ); iwindow_build( IWINDOW( filesel ) ); gtk_widget_show( GTK_WIDGET( filesel ) ); } void mainw_workspace_merge_action_cb( GtkAction *action, Mainw *mainw ) { mainw_workspace_merge( mainw ); } /* Load a workspace, called from a yesno dialog. */ static void mainw_auto_recover_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { char *filename = (char *) client; Workspacegroup *new_wsg; Mainw *new_mainw; progress_begin(); if( !(new_wsg = workspacegroup_new_from_file( main_workspaceroot, filename, filename )) ) { progress_end(); nfn( sys, IWINDOW_ERROR ); return; } filemodel_set_filename( FILEMODEL( new_wsg ), NULL ); new_mainw = mainw_new( new_wsg ); gtk_widget_show( GTK_WIDGET( new_mainw ) ); symbol_recalculate_all(); progress_end(); nfn( sys, IWINDOW_YES ); } /* Auto recover. */ static void mainw_recover_action_cb( GtkAction *action, Mainw *mainw ) { char *filename; if( !(filename = workspacegroup_autosave_recover()) ) { if( !AUTO_WS_SAVE ) { error_top( _( "No backup workspaces found." ) ); error_sub( "%s", _( "You need to enable \"Auto workspace " "save\" in Preferences " "before automatic recovery works." ) ); } else { error_top( _( "No backup workspaces found." ) ); error_sub( _( "No suitable workspace save files found " "in \"%s\"" ), PATH_TMP ); } iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO ); return; } /* Tricksy ... free str with notify callack from yesno. */ box_yesno( GTK_WIDGET( mainw ), mainw_auto_recover_cb, iwindow_true_cb, filename, (iWindowNotifyFn) im_free, filename, GTK_STOCK_OPEN, _( "Open workspace backup?" ), _( "Found workspace backup:\n\n\t%s\n\n" "Do you want to recover this workspace?" ), filename ); } /* Callback from make new column. */ void mainw_column_new_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) (void) workspace_column_new( ws ); } /* Done button hit. */ static void mainw_column_new_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Mainw *mainw = MAINW( client ); Stringset *ss = STRINGSET( iwnd ); StringsetChild *name = stringset_child_get( ss, _( "Name" ) ); StringsetChild *caption = stringset_child_get( ss, _( "Caption" ) ); Workspace *ws; Column *col; char name_text[1024]; char caption_text[1024]; if( !(ws = mainw_get_workspace( mainw )) ) { nfn( sys, IWINDOW_YES ); return; } if( !get_geditable_name( name->entry, name_text, 1024 ) || !get_geditable_string( caption->entry, caption_text, 1024 ) ) { nfn( sys, IWINDOW_ERROR ); return; } if( !(col = column_new( ws, name_text )) ) { nfn( sys, IWINDOW_ERROR ); return; } if( strcmp( caption_text, "" ) != 0 ) iobject_set( IOBJECT( col ), NULL, caption_text ); workspace_column_select( ws, col ); column_scrollto( col, MODEL_SCROLL_TOP ); nfn( sys, IWINDOW_YES ); } /* Make a new column with a specified name. */ static void mainw_column_new_named_action_cb( GtkAction *action, Mainw *mainw ) { GtkWidget *ss = stringset_new(); char new_name[MAX_STRSIZE]; Workspace *ws; if( !(ws = mainw_get_workspace( mainw )) ) return; workspace_column_name_new( ws, new_name ); stringset_child_new( STRINGSET( ss ), _( "Name" ), new_name, _( "Set column name here" ) ); stringset_child_new( STRINGSET( ss ), _( "Caption" ), "", _( "Set column caption here" ) ); iwindow_set_title( IWINDOW( ss ), _( "New Column" ) ); idialog_set_callbacks( IDIALOG( ss ), iwindow_true_cb, NULL, NULL, mainw ); idialog_add_ok( IDIALOG( ss ), mainw_column_new_cb, _( "Create Column" ) ); iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( mainw ) ); iwindow_build( IWINDOW( ss ) ); gtk_widget_show( ss ); } /* Callback from program. */ static void mainw_program_new_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) { Program *program; program = program_new( ws->kitg ); gtk_widget_show( GTK_WIDGET( program ) ); } } static void mainw_workspace_new_action_cb( GtkAction *action, Mainw *mainw ) { workspace_new_blank( mainw->wsg ); } /* New workbook. */ static void mainw_workbook_new_action_cb( GtkAction *action, Mainw *mainw ) { Mainw *new_mainw; Workspacegroup *new_wsg; char name[256]; workspaceroot_name_new( mainw->wsg->wsr, name ); new_wsg = workspacegroup_new_blank( mainw->wsg->wsr, name ); new_mainw = mainw_new( new_wsg ); gtk_widget_show( GTK_WIDGET( new_mainw ) ); } /* Callback from auto-recalc toggle. */ static void mainw_autorecalc_action_cb( GtkToggleAction *action, Mainw *mainw ) { GSList *i; mainw_auto_recalc = gtk_toggle_action_get_active( action ); /* Yuk! We have to ask all mainw to refresh by hand, since we're not * using the prefs system for auto_recalc for reasons noted at top. */ for( i = mainw_all; i; i = i->next ) mainw_refresh( MAINW( i->data ) ); if( mainw_auto_recalc ) symbol_recalculate_all(); } /* Callback from lock toggle. */ static void mainw_lock_action_cb( GtkToggleAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) workspace_set_locked( ws, gtk_toggle_action_get_active( action ) ); } /* Callback from show toolbar toggle. */ static void mainw_toolbar_action_cb( GtkToggleAction *action, Mainw *mainw ) { mainw->toolbar_visible = gtk_toggle_action_get_active( action ); prefs_set( "MAINW_TOOLBAR", "%s", bool_to_char( mainw->toolbar_visible ) ); mainw_refresh( mainw ); } /* Callback from show statusbar toggle. */ static void mainw_statusbar_action_cb( GtkToggleAction *action, Mainw *mainw ) { mainw->statusbar_visible = gtk_toggle_action_get_active( action ); prefs_set( "MAINW_STATUSBAR", "%s", bool_to_char( mainw->statusbar_visible ) ); mainw_refresh( mainw ); } /* Expose/hide the toolkit browser. */ static void mainw_toolkitbrowser_action_cb( GtkToggleAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) { ws->rpane_open = gtk_toggle_action_get_active( action ); iobject_changed( IOBJECT( ws ) ); } } /* Expose/hide the workspace defs. */ static void mainw_tabdefs_action_cb( GtkToggleAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) { ws->lpane_open = gtk_toggle_action_get_active( action ); iobject_changed( IOBJECT( ws ) ); } } /* Remove selected items. */ static void mainw_selected_remove_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) workspace_selected_remove_yesno( ws, GTK_WIDGET( mainw ) ); } void mainw_revert_ok_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Prefs *prefs = PREFS( client ); Workspacegroup *wsg = workspace_get_workspacegroup( prefs->ws ); if( FILEMODEL( wsg )->filename ) { (void) unlinkf( "%s", FILEMODEL( wsg )->filename ); main_reload(); symbol_recalculate_all(); } nfn( sys, IWINDOW_YES ); } void mainw_revert_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Prefs *prefs = PREFS( client ); box_yesno( GTK_WIDGET( iwnd ), mainw_revert_ok_cb, iwindow_true_cb, prefs, nfn, sys, _( "Revert to Defaults" ), _( "Revert to installation defaults?" ), _( "Would you like to reset all preferences to their factory " "settings? This will delete any changes you have ever made " "to your preferences and may take a few seconds." ) ); } static void mainw_preferences_action_cb( GtkAction *action, Mainw *mainw ) { Prefs *prefs; /* Can fail if there's no prefs ws, or an error on load. */ if( !(prefs = prefs_new( NULL )) ) { iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR ); return; } iwindow_set_title( IWINDOW( prefs ), _( "Preferences" ) ); iwindow_set_parent( IWINDOW( prefs ), GTK_WIDGET( mainw ) ); idialog_set_callbacks( IDIALOG( prefs ), NULL, NULL, NULL, prefs ); idialog_add_ok( IDIALOG( prefs ), mainw_revert_cb, _( "Revert to Defaults ..." ) ); idialog_add_ok( IDIALOG( prefs ), iwindow_true_cb, GTK_STOCK_CLOSE ); iwindow_build( IWINDOW( prefs ) ); /* Just big enough to avoid a horizontal scrollbar on my machine. FIXME ... Yuk! There must be a better way to do this! Maybe a setting in prefs to suppress the h scrollbar? */ gtk_window_set_default_size( GTK_WINDOW( prefs ), 780, 480 ); gtk_widget_show( GTK_WIDGET( prefs ) ); } /* Make a magic definition for the selected symbol. FIXME .. paste this back when magic is reinstated static void mainw_magic_cb( gpointer callback_data, guint callback_action, GtkWidget *widget ) { Workspace *ws = main_workspaceroot->current; Row *row = workspace_selected_one( ws ); if( !row ) box_alert( mainw, "Select a single object with left-click, " "select Magic Definition." ); else if( !magic_sym( row->sym ) ) iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR ); else workspace_deselect_all( ws ); } */ #ifdef HAVE_LIBGVC static void mainw_graph_action_cb( GtkAction *action, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) { Graphwindow *graphwindow; graphwindow = graphwindow_new( ws, GTK_WIDGET( mainw ) ); gtk_widget_show( GTK_WIDGET( graphwindow ) ); } } #endif /*HAVE_LIBGVC*/ /* Set display mode. */ static void mainw_mode_action_cb( GtkRadioAction *action, GtkRadioAction *current, Mainw *mainw ) { Workspace *ws; if( (ws = mainw_get_workspace( mainw )) ) workspace_set_mode( ws, gtk_radio_action_get_current_value( action ) ); } /* Our actions. */ static GtkActionEntry mainw_actions[] = { /* Menu items. */ { "RecentMenu", NULL, N_( "Open _Recent" ) }, { "JumpToColumnMenu", NULL, N_( "Jump to _Column" ) }, { "ToolkitsMenu", NULL, N_( "_Toolkits" ) }, /* Dummy action ... replaced at runtime. */ { "Stub", NULL, "", NULL, "", NULL }, /* Actions. */ { "NewColumn", GTK_STOCK_NEW, N_( "C_olumn" ), NULL, N_( "Create a new column" ), G_CALLBACK( mainw_column_new_action_cb ) }, { "NewColumnName", GTK_STOCK_NEW, N_( "C_olumn" ), NULL, N_( "Create a new column with a specified name" ), G_CALLBACK( mainw_column_new_named_action_cb ) }, { "NewTab", GTK_STOCK_NEW, N_( "_Tab" ), "T", N_( "Create a new tab" ), G_CALLBACK( mainw_workspace_new_action_cb ) }, { "NewWorkspace", GTK_STOCK_NEW, N_( "_Workspace" ), NULL, N_( "Create a new workspace" ), G_CALLBACK( mainw_workbook_new_action_cb ) }, { "Open", GTK_STOCK_OPEN, N_( "_Open" ), NULL, N_( "Open a file" ), G_CALLBACK( mainw_open_action_cb ) }, { "OpenExamples", NULL, N_( "Open _Examples" ), NULL, N_( "Open example workspaces" ), G_CALLBACK( mainw_open_examples_action_cb ) }, { "DuplicateWorkspace", STOCK_DUPLICATE, N_( "_Duplicate Workspace" ), NULL, N_( "Duplicate workspace" ), G_CALLBACK( mainw_duplicate_action_cb ) }, { "Merge", NULL, N_( "_Merge Into Workspace" ), NULL, N_( "Merge workspace into this workspace" ), G_CALLBACK( mainw_workspace_merge_action_cb ) }, { "Save", GTK_STOCK_SAVE, N_( "_Save Workspace" ), NULL, N_( "Save workspace" ), G_CALLBACK( mainw_save_action_cb ) }, { "SaveAs", GTK_STOCK_SAVE_AS, N_( "_Save Workspace As" ), NULL, N_( "Save workspace as" ), G_CALLBACK( mainw_save_as_action_cb ) }, { "Recover", NULL, N_( "Search for Workspace _Backups" ), NULL, N_( "Load last automatically backed-up workspace" ), G_CALLBACK( mainw_recover_action_cb ) }, { "Delete", GTK_STOCK_DELETE, N_( "_Delete" ), "BackSpace", N_( "Delete selected items" ), G_CALLBACK( mainw_selected_remove_action_cb ) }, { "SelectAll", NULL, N_( "Select _All" ), "A", N_( "Select all items" ), G_CALLBACK( mainw_select_all_action_cb ) }, { "Duplicate", STOCK_DUPLICATE, N_( "D_uplicate Selected" ), "U", N_( "Duplicate selected items" ), G_CALLBACK( mainw_selected_duplicate_action_cb ) }, { "Recalculate", NULL, N_( "_Recalculate" ), NULL, N_( "Recalculate selected items" ), G_CALLBACK( mainw_force_calc_action_cb ) }, { "Find", GTK_STOCK_FIND, N_( "_Find" ), NULL, N_( "Find in workspace" ), G_CALLBACK( mainw_find_action_cb ) }, { "FindNext", NULL, N_( "Find _Next" ), NULL, N_( "Find again in workspace" ), G_CALLBACK( mainw_find_again_action_cb ) }, { "NextError", STOCK_NEXT_ERROR, NULL, NULL, N_( "Jump to next error" ), G_CALLBACK( mainw_next_error_action_cb ) }, { "Group", NULL, N_( "_Group" ), NULL, N_( "Group selected items" ), G_CALLBACK( mainw_group_action_cb ) }, { "Ungroup", NULL, N_( "U_ngroup" ), NULL, N_( "Ungroup selected items" ), G_CALLBACK( mainw_ungroup_action_cb ) }, { "Preferences", GTK_STOCK_PREFERENCES, N_( "_Preferences" ), NULL, N_( "Edit preferences" ), G_CALLBACK( mainw_preferences_action_cb ) }, #ifdef HAVE_LIBGVC { "Graph", NULL, N_( "Workspace as Grap_h" ), NULL, N_( "Show a graph of workspace dependencies" ), G_CALLBACK( mainw_graph_action_cb ) }, #endif /*HAVE_LIBGVC*/ { "EditToolkits", NULL, N_( "_Edit" ), NULL, N_( "Edit toolkits" ), G_CALLBACK( mainw_program_new_action_cb ) } }; static GtkToggleActionEntry mainw_toggle_actions[] = { { "AutoRecalculate", NULL, N_( "Au_to Recalculate" ), NULL, N_( "Recalculate automatically on change" ), G_CALLBACK( mainw_autorecalc_action_cb ), TRUE }, { "Lock", NULL, N_( "_Lock tab" ), NULL, N_( "Lock tab" ), G_CALLBACK( mainw_lock_action_cb ), TRUE }, { "Toolbar", NULL, N_( "_Toolbar" ), NULL, N_( "Show window toolbar" ), G_CALLBACK( mainw_toolbar_action_cb ), TRUE }, { "Statusbar", NULL, N_( "_Statusbar" ), NULL, N_( "Show window statusbar" ), G_CALLBACK( mainw_statusbar_action_cb ), TRUE }, { "ToolkitBrowser", NULL, N_( "Toolkit _Browser" ), NULL, N_( "Show toolkit browser" ), G_CALLBACK( mainw_toolkitbrowser_action_cb ), FALSE }, { "Tabdefs", NULL, N_( "Tab _Definitions" ), NULL, N_( "Show tab definitions" ), G_CALLBACK( mainw_tabdefs_action_cb ), FALSE }, }; static GtkRadioActionEntry mainw_radio_actions[] = { { "Normal", NULL, N_( "_Normal" ), NULL, N_( "Normal view mode" ), WORKSPACE_MODE_REGULAR }, { "ShowFormula", NULL, N_( "Show _Formula" ), NULL, N_( "Show formula view mode" ), WORKSPACE_MODE_FORMULA }, { "NoEdit", NULL, N_( "No _Edits" ), NULL, N_( "No edits view mode" ), WORKSPACE_MODE_NOEDIT }, }; static const char *mainw_menubar_ui_description = "" " " " " " " " " " " " " " " " " " " " " /* Dummy ... replaced on map */ " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " /* Dummy ... replaced on map */ " " " " " " " " " " " " " " " " " " " " " " " " " " #ifdef HAVE_LIBGVC " " " " #endif /*HAVE_LIBGVC*/ " " " " " " " " " " " " " " " " /* Toolkits pasted here at runtime */ " " " " " " " " " " " " " " " " ""; static const char *mainw_toolbar_ui_description = "" " " " " " " " " " " " " " " " " " " ""; static void mainw_watch_changed_cb( Watchgroup *watchgroup, Watch *watch, Mainw *mainw ) { if( strcmp( IOBJECT( watch )->name, "MAINW_TOOLBAR_STYLE" ) == 0 ) mainw->toolbar_visible = MAINW_TOOLBAR; mainw_refresh( mainw ); } /* Make the insides of the panel. */ static void mainw_build( iWindow *iwnd, GtkWidget *vbox ) { Mainw *mainw = MAINW( iwnd ); GtkWidget *mbar; GtkWidget *frame; GError *error; GtkWidget *cancel; GtkWidget *item; #ifdef DEBUG printf( "mainw_build: %p\n", mainw ); #endif /*DEBUG*/ /* Make main menu bar */ gtk_action_group_add_actions( iwnd->action_group, mainw_actions, G_N_ELEMENTS( mainw_actions ), GTK_WINDOW( mainw ) ); gtk_action_group_add_toggle_actions( iwnd->action_group, mainw_toggle_actions, G_N_ELEMENTS( mainw_toggle_actions ), GTK_WINDOW( mainw ) ); gtk_action_group_add_radio_actions( iwnd->action_group, mainw_radio_actions, G_N_ELEMENTS( mainw_radio_actions ), WORKSPACE_MODE_REGULAR, G_CALLBACK( mainw_mode_action_cb ), GTK_WINDOW( mainw ) ); error = NULL; if( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager, mainw_menubar_ui_description, -1, &error ) || !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager, mainw_toolbar_ui_description, -1, &error ) ) { g_message( "building menus failed: %s", error->message ); g_error_free( error ); exit( EXIT_FAILURE ); } mbar = gtk_ui_manager_get_widget( iwnd->ui_manager, "/MainwMenubar" ); gtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 ); gtk_widget_show( mbar ); /* Get the dummy item on the recent menu, then get the enclosing menu * for that dummy item. */ item = gtk_ui_manager_get_widget( iwnd->ui_manager, "/MainwMenubar/FileMenu/RecentMenu/Stub" ); mainw->recent_menu = gtk_widget_get_parent( GTK_WIDGET( item ) ); gtk_signal_connect( GTK_OBJECT( mainw->recent_menu ), "map", GTK_SIGNAL_FUNC( mainw_recent_map_cb ), mainw ); /* Same for the column jump menu. */ item = gtk_ui_manager_get_widget( iwnd->ui_manager, "/MainwMenubar/EditMenu/JumpToColumnMenu/Stub" ); mainw->jump_to_column_menu = gtk_widget_get_parent( GTK_WIDGET( item ) ); /* Same for the tk menu. */ item = gtk_ui_manager_get_widget( iwnd->ui_manager, "/MainwMenubar/ToolkitsMenu/Stub" ); mainw->toolkit_menu = gtk_widget_get_parent( GTK_WIDGET( item ) ); gtk_widget_destroy( item ); /* Attach toolbar. */ mainw->toolbar = gtk_ui_manager_get_widget( iwnd->ui_manager, "/MainwToolbar" ); gtk_box_pack_start( GTK_BOX( vbox ), mainw->toolbar, FALSE, FALSE, 0 ); widget_visible( mainw->toolbar, MAINW_TOOLBAR ); /* This will set to NULL if we don't have infobar support. */ if( (IWINDOW( mainw )->infobar = infobar_new()) ) gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( IWINDOW( mainw )->infobar ), FALSE, FALSE, 0 ); /* hbox for status bar etc. */ mainw->statusbar_main = gtk_hbox_new( FALSE, 2 ); gtk_box_pack_end( GTK_BOX( vbox ), mainw->statusbar_main, FALSE, FALSE, 2 ); widget_visible( mainw->statusbar_main, MAINW_STATUSBAR ); /* Make space free label. */ mainw->space_free_eb = gtk_event_box_new(); gtk_box_pack_start( GTK_BOX( mainw->statusbar_main ), mainw->space_free_eb, FALSE, FALSE, 0 ); gtk_widget_show( mainw->space_free_eb ); frame = gtk_frame_new( NULL ); gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN ); gtk_container_add( GTK_CONTAINER( mainw->space_free_eb ), frame ); gtk_widget_show( frame ); mainw->space_free = gtk_label_new( "space_free" ); gtk_misc_set_padding( GTK_MISC( mainw->space_free ), 2, 2 ); gtk_container_add( GTK_CONTAINER( frame ), mainw->space_free ); gtk_signal_connect( GTK_OBJECT( mainw->space_free_eb ), "event", GTK_SIGNAL_FUNC( mainw_space_free_event ), mainw ); set_tooltip_generate( mainw->space_free_eb, (TooltipGenerateFn) mainw_space_free_tooltip_generate, mainw, NULL ); gtk_widget_show( mainw->space_free ); mainw->imageinfo_changed_sid = g_signal_connect( main_imageinfogroup, "changed", G_CALLBACK( mainw_free_changed_cb ), mainw ); mainw->heap_changed_sid = g_signal_connect( reduce_context->heap, "changed", G_CALLBACK( mainw_free_changed_cb ), mainw ); /* Make message label. */ mainw->statusbar = gtk_label_new( "" ); gtk_label_set_ellipsize( GTK_LABEL( mainw->statusbar ), PANGO_ELLIPSIZE_MIDDLE ); /* 6 is enough to stop the statusbar changing height when the progress * indicator changes visibility. */ gtk_misc_set_padding( GTK_MISC( mainw->statusbar ), 2, 6 ); gtk_misc_set_alignment( GTK_MISC( mainw->statusbar ), 0.0, 0.5 ); gtk_box_pack_start( GTK_BOX( mainw->statusbar_main ), mainw->statusbar, TRUE, TRUE, 0 ); gtk_widget_show( mainw->statusbar ); mainw->progress_box = gtk_hbox_new( FALSE, 2 ); mainw->progress = gtk_progress_bar_new(); gtk_widget_set_size_request( GTK_WIDGET( mainw->progress ), 200, -1 ); gtk_box_pack_end( GTK_BOX( mainw->progress_box ), mainw->progress, FALSE, TRUE, 0 ); gtk_widget_show( mainw->progress ); cancel = gtk_button_new_with_label( "Cancel" ); g_signal_connect( cancel, "clicked", G_CALLBACK( mainw_cancel_cb ), mainw ); gtk_box_pack_end( GTK_BOX( mainw->progress_box ), cancel, FALSE, TRUE, 0 ); gtk_widget_show( cancel ); gtk_box_pack_end( GTK_BOX( mainw->statusbar_main ), mainw->progress_box, FALSE, TRUE, 0 ); mainw->wsgview = WORKSPACEGROUPVIEW( workspacegroupview_new() ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( mainw->wsgview ), TRUE, TRUE, 0 ); view_link( VIEW( mainw->wsgview ), MODEL( mainw->wsg ), NULL ); gtk_widget_show( GTK_WIDGET( mainw->wsgview ) ); /* Any changes to prefs, refresh (yuk!). */ mainw->watch_changed_sid = g_signal_connect( main_watchgroup, "watch_changed", G_CALLBACK( mainw_watch_changed_cb ), mainw ); } static void mainw_popdown( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) { Mainw *mainw = MAINW( iwnd ); /* We can be destroyed in two ways: either our iwnd tells us to go, or * our model is destroyed under us. If the model has gone, we just go. * If the model is still there, we need to ask about saving and * quitting. */ if( mainw->wsg ) filemodel_inter_savenclose_cb( IWINDOW( mainw ), FILEMODEL( mainw->wsg ), nfn, sys ); else nfn( sys, IWINDOW_YES ); } static void mainw_wsg_changed_cb( Workspacegroup *wsg, Mainw *mainw ) { mainw_refresh( mainw ); } static void mainw_wsg_destroy_cb( Workspacegroup *wsg, Mainw *mainw ) { mainw->wsg = NULL; } static void mainw_link( Mainw *mainw, Workspacegroup *wsg ) { Workspace *ws = workspacegroup_get_workspace( wsg ); /* Take ownership of the wsg. */ mainw->wsg = wsg; g_object_ref( G_OBJECT( mainw->wsg ) ); iobject_sink( IOBJECT( mainw->wsg ) ); wsg->iwnd = IWINDOW( mainw ); iwindow_set_build( IWINDOW( mainw ), (iWindowBuildFn) mainw_build, wsg, NULL, NULL ); iwindow_set_popdown( IWINDOW( mainw ), mainw_popdown, NULL ); iwindow_set_size_prefs( IWINDOW( mainw ), "MAINW_WINDOW_WIDTH", "MAINW_WINDOW_HEIGHT" ); iwindow_build( IWINDOW( mainw ) ); if( ws && MODEL( ws )->window_width != - 1 ) gtk_window_set_default_size( GTK_WINDOW( mainw ), MODEL( ws )->window_width, MODEL( ws )->window_height ); /* Set start state. */ (void) mainw_refresh( mainw ); mainw->changed_sid = g_signal_connect( mainw->wsg, "changed", G_CALLBACK( mainw_wsg_changed_cb ), mainw ); mainw->destroy_sid = g_signal_connect( mainw->wsg, "destroy", G_CALLBACK( mainw_wsg_destroy_cb ), mainw ); } Mainw * mainw_new( Workspacegroup *wsg ) { Mainw *mainw; mainw = MAINW( g_object_new( TYPE_MAINW, NULL ) ); mainw_link( mainw, wsg ); return( mainw ); } static void * mainw_cull_sub( Mainw *mainw ) { if( !ICONTAINER( mainw->wsg )->children ) { filemodel_set_modified( FILEMODEL( mainw->wsg ), FALSE ); iwindow_kill( IWINDOW( mainw ) ); } return( NULL ); } void mainw_cull( void ) { slist_map( mainw_all, (SListMapFn) mainw_cull_sub, NULL ); } static void * mainw_layout_sub( Workspace *ws ) { model_layout( MODEL( ws ) ); workspace_set_needs_layout( ws, FALSE ); return( NULL ); } static gboolean mainw_layout_timeout_cb( gpointer user_data ) { mainw_layout_timeout = 0; slist_map( workspace_get_needs_layout(), (SListMapFn) mainw_layout_sub, NULL ); return( FALSE ); } void mainw_layout( void ) { IM_FREEF( g_source_remove, mainw_layout_timeout ); mainw_layout_timeout = g_timeout_add( 300, (GSourceFunc) mainw_layout_timeout_cb, NULL ); } nip2-8.7.1/src/iwindow.h0000644000175000017500000001577313351443023011753 00000000000000/* make and manage windows ... subclass off this for dialog boxes */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifndef IWINDOW_H #define IWINDOW_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define TYPE_IWINDOW (iwindow_get_type()) #define IWINDOW( obj ) (GTK_CHECK_CAST( (obj), TYPE_IWINDOW, iWindow )) #define IWINDOW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_IWINDOW, iWindowClass )) #define IS_IWINDOW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IWINDOW )) #define IS_IWINDOW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_IWINDOW )) #define IWINDOW_GET_CLASS( obj ) \ (GTK_CHECK_GET_CLASS( (obj), TYPE_IWINDOW, iWindowClass )) typedef struct _iWindow iWindow; /* Our cursor shapes. */ typedef enum _iWindowShape { /* Tool shapes. */ IWINDOW_SHAPE_DROPPER = 0, IWINDOW_SHAPE_PEN, IWINDOW_SHAPE_SMUDGE, IWINDOW_SHAPE_SMEAR, IWINDOW_SHAPE_TEXT, IWINDOW_SHAPE_RECT, IWINDOW_SHAPE_FLOOD, IWINDOW_SHAPE_MOVE, IWINDOW_SHAPE_EDIT, IWINDOW_SHAPE_MAGIN, IWINDOW_SHAPE_MAGOUT, /* Resize shapes. */ IWINDOW_SHAPE_TOP, IWINDOW_SHAPE_BOTTOM, IWINDOW_SHAPE_LEFT, IWINDOW_SHAPE_RIGHT, IWINDOW_SHAPE_TOPRIGHT, IWINDOW_SHAPE_TOPLEFT, IWINDOW_SHAPE_BOTTOMRIGHT, IWINDOW_SHAPE_BOTTOMLEFT, /* Watch positions. */ IWINDOW_SHAPE_HGLASS1, IWINDOW_SHAPE_HGLASS2, IWINDOW_SHAPE_HGLASS3, IWINDOW_SHAPE_HGLASS4, IWINDOW_SHAPE_HGLASS5, IWINDOW_SHAPE_HGLASS6, IWINDOW_SHAPE_HGLASS7, IWINDOW_SHAPE_HGLASS8, /* No shape set (shape we inherit). */ IWINDOW_SHAPE_NONE, IWINDOW_SHAPE_LAST } iWindowShape; /* Keep a set of these, one for each of the clients who might want to set the * shape for a window. */ typedef struct { iWindow *iwnd; int priority; /* Higher priority == more on top */ const char *name; /* For debugging */ /* Shape currently requested by this user. */ iWindowShape shape; } iWindowCursorContext; /* The result from a window/dialog/whatever ... not just a bool. */ typedef enum iwindow_result { IWINDOW_ERROR = 0, /* Tried but failed */ IWINDOW_YES, /* User tried the action */ IWINDOW_NO /* User cancelled */ } iWindowResult; /* Our callbacks don't return iWindowResult, instead * they are given a notify function (plus an environment parameter) which * they use to inform their caller of their iWindowResult. */ typedef void (*iWindowNotifyFn)( void *, iWindowResult ); /* What our callbacks look like. */ typedef void (*iWindowFn)( iWindow *, void *, iWindowNotifyFn, void * ); /* Build function for window contents. */ typedef void (*iWindowBuildFn)( iWindow *, GtkWidget *, void *, void *, void * ); /* A suspension ... an iWindowFn plus a set of args we are saving for later. */ typedef struct { iWindowFn fn; iWindow *iwnd; void *client; iWindowNotifyFn nfn; void *sys; } iWindowSusp; #define IWINDOW_SUSP( X ) ((iWindowSusp *) (X)) struct _iWindow { GtkWindow parent_object; /* Parent window. Used for (eg.) image displays windows which we need * to float over the main workspace. */ GtkWidget *parent; /* Our parent widget */ iWindow *parent_window; /* Our parent window */ guint parent_unmap_sid; /* Watch parent death here */ GtkWidget *work; GtkAccelGroup *accel_group; Infobar *infobar; char *title; /* Action stuff. We init this and add a few common actions to help out * subclasses. */ GtkActionGroup *action_group; GtkUIManager *ui_manager; /* Per instance build function. */ iWindowBuildFn build; void *build_a, *build_b, *build_c; /* Called before cancellable popdown ... _TRUE from this will * destroy window, _FALSE won't, _ERROR won't and pops an error box. */ iWindowFn popdown; void *popdown_a; /* Notify handling. */ gboolean destroy; /* True if being destroyed */ int pending; /* Number of notifies waiting on */ /* Cursor handling. */ iWindowShape shape; /* Global shape ... for hglass */ GSList *contexts; /* Set of other requested shapes */ GdkWindow *work_window; /* The window we actually set */ /* Size memorization. */ const char *width_pref; /* Prefs we save width/height in */ const char *height_pref; }; typedef struct _iWindowClass { GtkWindowClass parent_class; /* Per class build/popdown functions. */ void (*build)( GtkWidget * ); void (*popdown)( GtkWidget * ); /* Whether windows of this class should be marked as transient for * their parents (eg. dialogs usually are). */ gboolean transient; } iWindowClass; int iwindow_number( void ); iWindow *iwindow_pick_one( void ); typedef void (*iWindowMapFn)( iWindow *, void * ); void *iwindow_map_all( iWindowMapFn fn, void *a ); iWindowCursorContext *iwindow_cursor_context_new( iWindow *, int, const char * ); void iwindow_cursor_context_set_cursor( iWindowCursorContext *, iWindowShape ); void iwindow_cursor_context_destroy( iWindowCursorContext *cntxt ); iWindowSusp *iwindow_susp_new( iWindowFn, iWindow *, void *, iWindowNotifyFn, void * ); void iwindow_susp_trigger( iWindowSusp * ); void iwindow_susp_return( void *, iWindowResult ); void iwindow_susp_comp( void *, iWindowResult ); void iwindow_notify_send( iWindow *iwnd, iWindowFn fn, void *client, iWindowNotifyFn back, void *sys ); void iwindow_notify_return( iWindow *iwnd ); void iwindow_true_cb( iWindow *, void *, iWindowNotifyFn nfn, void *sys ); void iwindow_false_cb( iWindow *, void *, iWindowNotifyFn nfn, void *sys ); void iwindow_notify_null( void *client, iWindowResult result ); GtkType iwindow_get_type( void ); GtkWidget *iwindow_new( GtkWindowType ); void iwindow_set_title( iWindow *, const char *, ... ) __attribute__((format(printf, 2, 3))); void iwindow_set_build( iWindow *, iWindowBuildFn, void *, void *, void * ); void iwindow_set_popdown( iWindow *, iWindowFn, void * ); void iwindow_set_size_prefs( iWindow *, const char *, const char * ); void iwindow_set_work_window( iWindow *iwnd, GdkWindow *work_window ); void iwindow_set_parent( iWindow *, GtkWidget *par ); void iwindow_build( iWindow * ); void *iwindow_kill( iWindow * ); void iwindow_kill_action_cb( GtkAction *action, iWindow *iwnd ); GtkWidget *iwindow_get_root( GtkWidget *widget ); GtkWidget *iwindow_get_root_noparent( GtkWidget *widget ); void iwindow_alert( GtkWidget *parent, GtkMessageType type ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* IWINDOW_H */ nip2-8.7.1/src/iimageview.c0000644000175000017500000002624313351443023012406 00000000000000/* run the display for an image in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static GraphicviewClass *parent_class = NULL; static void iimageview_realize( GtkWidget *widget ) { GTK_WIDGET_CLASS( parent_class )->realize( widget ); /* Mark us as a symbol drag-to widget. */ set_symbol_drag_type( widget ); } GtkWidget * iimageview_drag_window_new( int width, int height ) { GtkWidget *window; window = gtk_window_new( GTK_WINDOW_POPUP ); gtk_widget_set_app_paintable( GTK_WIDGET( window ), TRUE ); gtk_widget_set_size_request( window, width, height ); gtk_widget_realize( window ); #ifdef HAVE_SET_OPACITY gdk_window_set_opacity( window->window, 0.5 ); #endif /*HAVE_SET_OPACITY*/ return( window ); } static void iimageview_drag_begin( GtkWidget *widget, GdkDragContext *context ) { iImageview *iimageview = IIMAGEVIEW( widget ); Conversion *conv = iimageview->conv; GtkWidget *window; Imagedisplay *id; #ifdef DEBUG printf( "iimageview_drag_begin: \n" ); #endif /*DEBUG*/ window = iimageview_drag_window_new( conv->canvas.width, conv->canvas.height ); gtk_object_set_data_full( GTK_OBJECT( widget ), "nip2-drag-window", window, (GtkDestroyNotify) gtk_widget_destroy ); id = imagedisplay_new( conv ); gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( id ) ); gtk_widget_show( GTK_WIDGET( id ) ); gtk_drag_set_icon_widget( context, window, -2, -2 ); } static void iimageview_drag_end( GtkWidget *widget, GdkDragContext *context ) { #ifdef DEBUG printf( "iimageview_drag_end:\n" ); #endif /*DEBUG*/ gtk_object_set_data( GTK_OBJECT( widget ), "nip2-drag-window", NULL ); } static void iimageview_drag_data_get( GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time ) { #ifdef DEBUG printf( "iimageview_drag_data_get:\n" ); #endif /*DEBUG*/ if( info == TARGET_SYMBOL ) { iImageview *iimageview = IIMAGEVIEW( widget ); iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject ); Row *row = HEAPMODEL( iimage )->row; char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); /* Drag the fully-qualified row name. */ row_qualified_name_relative( main_workspaceroot->sym, row, &buf ); gtk_selection_data_set( selection_data, gdk_atom_intern( "text/symbol", FALSE ), 8, (guchar *) vips_buf_all( &buf ), strlen( vips_buf_all( &buf ) ) ); } } static void iimageview_drag_data_received( GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time ) { #ifdef DEBUG printf( "iimageview_drag_data_received:\n" ); #endif /*DEBUG*/ if( info == TARGET_SYMBOL && selection_data->length > 0 && selection_data->format == 8 ) { const char *from_row_path = (const char *) selection_data->data; iImageview *iimageview = IIMAGEVIEW( widget ); iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject ); Row *row = HEAPMODEL( iimage )->row; Row *from_row; #ifdef DEBUG printf( " seen TARGET_SYMBOL \"%s\"\n", from_row_path ); #endif /*DEBUG*/ /* Block drags to ourselves ... pointless. */ if( (from_row = row_parse_name( main_workspaceroot->sym, from_row_path )) && from_row != row ) { iText *itext = ITEXT( HEAPMODEL( iimage )->rhs->itext ); char txt[256]; VipsBuf buf = VIPS_BUF_STATIC( txt ); /* Qualify relative to us. We don't want to embed * workspace names unless we have to. */ if( row->top_row->sym ) row_qualified_name_relative( row->top_row->sym, from_row, &buf ); if( itext_set_formula( itext, vips_buf_all( &buf ) ) ) { itext_set_edited( itext, TRUE ); (void) expr_dirty( row->expr, link_serial_new() ); workspace_set_modified( row->ws, TRUE ); symbol_recalculate_all(); } /* Usually the drag-from row will be selected, very * annoying. Select the drag-to row. */ row_select( row ); } } } /* Not the same as model->edit :-( if this is a region, don't pop the region * edit box, pop a viewer on the image. */ static void iimageview_edit( GtkWidget *parent, iImageview *iimageview ) { iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject ); if( IS_IREGION( iimage ) && iimage->value.ii ) imageview_new( iimage, parent ); else model_edit( parent, MODEL( iimage ) ); } static void iimageview_link( View *view, Model *model, View *parent ) { iImageview *iimageview = IIMAGEVIEW( view ); Rowview *rview; VIEW_CLASS( parent_class )->link( view, model, parent ); if( (rview = ROWVIEW( parent->parent )) ) { Row *row = ROW( VOBJECT( rview )->iobject ); rowview_menu_attach( rview, GTK_WIDGET( iimageview->id ) ); if( row->popup && row->top_row == row ) { row->popup = FALSE; iimageview_edit( GTK_WIDGET( view ), iimageview ); } } } static void iimageview_refresh( vObject *vobject ) { iImageview *iimageview = IIMAGEVIEW( vobject ); iImage *iimage = IIMAGE( vobject->iobject ); Row *row = HEAPMODEL( iimage )->row; int w, h; gboolean enabled; double scale, offset; gboolean falsecolour, type; #ifdef DEBUG printf( "iimageview_refresh\n" ); #endif /*DEBUG*/ w = IM_MAX( GTK_WIDGET( iimageview->id )->requisition.width, DISPLAY_THUMBNAIL ); h = DISPLAY_THUMBNAIL; conversion_set_image( iimageview->conv, iimage->value.ii ); gtk_widget_set_size_request( GTK_WIDGET( iimageview->id ), w, h ); gtk_widget_queue_draw( GTK_WIDGET( iimageview->id ) ); set_gcaption( iimageview->label, "%s", NN( IOBJECT( iimage )->caption ) ); /* Set scale/offset for the thumbnail. Use the prefs setting, or if * there's a setting for this image, override with that. */ enabled = DISPLAY_CONVERSION; scale = row->ws->scale; offset = row->ws->offset; falsecolour = FALSE; type = TRUE; /* If the image_width has been set, a viewer must have popped down and * set it, so the recorded settings must be valid. */ if( MODEL( iimage )->window_width != -1 ) { enabled = iimage->show_convert; scale = iimage->scale; offset = iimage->offset; falsecolour = iimage->falsecolour; type = iimage->type; } conversion_set_params( iimageview->conv, enabled, scale, offset, falsecolour, type ); VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void iimageview_class_init( iImageviewClass *class ) { GtkWidgetClass *widget_class = (GtkWidgetClass *) class; vObjectClass *vobject_class = (vObjectClass *) class; ViewClass *view_class = (ViewClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ widget_class->realize = iimageview_realize; widget_class->drag_begin = iimageview_drag_begin; widget_class->drag_end = iimageview_drag_end; widget_class->drag_data_get = iimageview_drag_data_get; widget_class->drag_data_received = iimageview_drag_data_received; vobject_class->refresh = iimageview_refresh; view_class->link = iimageview_link; } static void iimageview_doubleclick_one_cb( GtkWidget *widget, GdkEvent *event, iImageview *iimageview ) { Heapmodel *heapmodel = HEAPMODEL( VOBJECT( iimageview )->iobject ); Row *row = heapmodel->row; row_select_modifier( row, event->button.state ); } static void iimageview_doubleclick_two_cb( GtkWidget *widget, GdkEvent *event, iImageview *iimageview ) { iimageview_edit( widget, iimageview ); } static gboolean iimageview_filedrop( iImageview *iimageview, const char *file ) { iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject ); gboolean result; if( (result = iimage_replace( iimage, file )) ) symbol_recalculate_all(); return( result ); } static void iimageview_tooltip_generate( GtkWidget *widget, VipsBuf *buf, iImageview *iimageview ) { iImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject ); Imageinfo *ii = iimage->value.ii; IMAGE *im = imageinfo_get( FALSE, ii ); vips_buf_rewind( buf ); vips_buf_appends( buf, vips_buf_all( &iimage->caption_buffer ) ); if( im ) { double size = (double) im->Ysize * IM_IMAGE_SIZEOF_LINE( im ); vips_buf_appends( buf, ", " ); vips_buf_append_size( buf, size ); vips_buf_appendf( buf, ", %.3gx%.3g p/mm", im->Xres, im->Yres ); } } static void iimageview_init( iImageview *iimageview ) { GtkWidget *eb; GtkWidget *vbox; #ifdef DEBUG printf( "iimageview_init\n" ); #endif /*DEBUG*/ eb = gtk_event_box_new(); gtk_box_pack_start( GTK_BOX( iimageview ), eb, FALSE, FALSE, 0 ); vbox = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER( eb ), vbox ); gtk_widget_show( vbox ); iimageview->conv = conversion_new( NULL ); iimageview->conv->tile_size = 16; iimageview->id = imagedisplay_new( iimageview->conv ); imagedisplay_set_shrink_to_fit( iimageview->id, TRUE ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( iimageview->id ), FALSE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( iimageview->id ) ); /* Need these events in the enclosing workspaceview. */ gtk_widget_add_events( GTK_WIDGET( iimageview->id ), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK ); iimageview->label = gtk_label_new( "" ); gtk_misc_set_alignment( GTK_MISC( iimageview->label ), 0, 0.5 ); gtk_misc_set_padding( GTK_MISC( iimageview->label ), 2, 0 ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( iimageview->label ), FALSE, FALSE, 0 ); gtk_widget_show( GTK_WIDGET( iimageview->label ) ); /* Set as file drop destination */ filedrop_register( GTK_WIDGET( iimageview ), (FiledropFunc) iimageview_filedrop, iimageview ); doubleclick_add( GTK_WIDGET( iimageview ), FALSE, DOUBLECLICK_FUNC( iimageview_doubleclick_one_cb ), iimageview, DOUBLECLICK_FUNC( iimageview_doubleclick_two_cb ), iimageview ); set_tooltip_generate( eb, (TooltipGenerateFn) iimageview_tooltip_generate, iimageview, NULL ); gtk_widget_set_name( eb, "caption_widget" ); gtk_widget_show( GTK_WIDGET( eb ) ); } GtkType iimageview_get_type( void ) { static GtkType iimageview_type = 0; if( !iimageview_type ) { static const GtkTypeInfo info = { "iImageview", sizeof( iImageview ), sizeof( iImageviewClass ), (GtkClassInitFunc) iimageview_class_init, (GtkObjectInitFunc) iimageview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; iimageview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info ); } return( iimageview_type ); } View * iimageview_new( void ) { iImageview *iimageview = gtk_type_new( TYPE_IIMAGEVIEW ); return( VIEW( iimageview ) ); } nip2-8.7.1/src/workspacedefs.h0000644000175000017500000000341213351443023013116 00000000000000/* Workspace-local defs */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_WORKSPACEDEFS (workspacedefs_get_type()) #define WORKSPACEDEFS( obj ) \ (GTK_CHECK_CAST( (obj), TYPE_WORKSPACEDEFS, Workspacedefs )) #define WORKSPACEDEFS_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), \ TYPE_WORKSPACEDEFS, WorkspacedefsClass )) #define IS_WORKSPACEDEFS( obj ) \ (GTK_CHECK_TYPE( (obj), TYPE_WORKSPACEDEFS )) #define IS_WORKSPACEDEFS_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEDEFS )) struct _Workspacedefs { vObject parent_object; Workspace *ws; /* Workspace we explore */ GtkWidget *text; gboolean changed; /* Text has been edited */ gboolean errors; /* Error on last process */ guint text_hash; /* Hash of the last text we set */ GtkWidget *status; }; typedef struct _WorkspacedefsClass { vObjectClass parent_class; } WorkspacedefsClass; GtkType workspacedefs_get_type( void ); Workspacedefs *workspacedefs_new( void ); nip2-8.7.1/src/preview.c0000644000175000017500000001054413351443023011736 00000000000000/* thumbnail widget */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ /* Number of columns of pixmaps we display. */ #define NUM_COLUMNS (4) static ImagedisplayClass *parent_class = NULL; static void preview_destroy( GtkObject *object ) { Preview *preview; g_return_if_fail( object != NULL ); g_return_if_fail( IS_PREVIEW( object ) ); preview = PREVIEW( object ); UNREF( preview->conv ); IM_FREE( preview->filename ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void preview_class_init( PreviewClass *class ) { GtkObjectClass *object_class; object_class = (GtkObjectClass *) class; object_class->destroy = preview_destroy; parent_class = g_type_class_peek_parent( class ); } static void preview_init( Preview *preview ) { #ifdef DEBUG printf( "preview_init: %p\n", preview ); #endif /*DEBUG*/ preview->filename = NULL; preview->conv = conversion_new( NULL ); preview->conv->tile_size = 16; gtk_widget_set_size_request( GTK_WIDGET( preview ), 128, 128 ); imagedisplay_set_conversion( IMAGEDISPLAY( preview ), preview->conv ); imagedisplay_set_shrink_to_fit( IMAGEDISPLAY( preview ), TRUE ); g_object_ref( G_OBJECT( preview->conv ) ); } GtkType preview_get_type( void ) { static GtkType type = 0; if( !type) { static const GtkTypeInfo info = { "Preview", sizeof( Preview ), sizeof( PreviewClass ), (GtkClassInitFunc) preview_class_init, (GtkObjectInitFunc) preview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_IMAGEDISPLAY, &info ); } return( type ); } Preview * preview_new( void ) { Preview *preview = (Preview *) gtk_type_new( TYPE_PREVIEW ); return( preview ); } static void preview_set_filename_idle( Preview *preview, char *filename ) { Imageinfo *ii; /* Make sure our enclosing preview wasn't been killed before this idle * starts. */ if( !preview->conv ) return; /* This is the call that can take ages and kill everything. */ if( !(ii = imageinfo_new_input( main_imageinfogroup, GTK_WIDGET( preview ), NULL, filename )) ) return; /* So test for alive-ness again. */ if( preview->conv ) { char txt[MAX_LINELENGTH]; VipsBuf buf = VIPS_BUF_STATIC( txt ); conversion_set_image( preview->conv, ii ); IM_SETSTR( preview->filename, filename ); /* How strange, we need this to get the * background to clear fully. */ gtk_widget_queue_draw( GTK_WIDGET( preview ) ); get_image_info( &buf, IOBJECT( preview->conv->ii )->name ); set_tooltip( GTK_WIDGET( preview ), "%s", vips_buf_all( &buf ) ); } MANAGED_UNREF( ii ); } typedef struct _UpdateProxy { Preview *preview; char *filename; } UpdateProxy; static gboolean preview_set_filename_idle_cb( UpdateProxy *proxy ) { preview_set_filename_idle( proxy->preview, proxy->filename ); UNREF( proxy->preview ); g_free( proxy ); /* Don't run again. */ return( FALSE ); } /* We can't load in-line, it can take ages and trigger progress callbacks, * which in turn, could kill our enclosing widget. * * Instead, we do the load in a idle callback and update the preview at the * end, if it's still valid. */ void preview_set_filename( Preview *preview, char *filename ) { UpdateProxy *proxy = g_new( UpdateProxy, 1 ); /* We are going to put the preview into the idle queue. It must remain * valid until the idle handler is handled, so we ref. */ g_object_ref( preview ); proxy->preview = preview; proxy->filename = g_strdup( filename ); g_idle_add( (GSourceFunc) preview_set_filename_idle_cb, proxy ); } nip2-8.7.1/src/toolkitgroup.c0000644000175000017500000000672013351443023013020 00000000000000/* Group toolkitgroup files together. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ModelClass *parent_class = NULL; Toolkit * toolkitgroup_map( Toolkitgroup *kitg, toolkit_map_fn fn, void *a, void *b ) { return( (Toolkit *) icontainer_map( ICONTAINER( kitg ), (icontainer_map_fn) fn, a, b ) ); } static void toolkitgroup_changed( iObject *iobject ) { #ifdef DEBUG g_print( "toolkitgroup_changed: " ); iobject_print( iobject ); #endif /*DEBUG*/ IOBJECT_CLASS( parent_class )->changed( iobject ); } static View * toolkitgroup_view_new( Model *model, View *parent ) { return( toolkitgroupview_new() ); } static void toolkitgroup_class_init( ToolkitgroupClass *class ) { iObjectClass *iobject_class = (iObjectClass *) class; ModelClass *model_class = (ModelClass *) class; parent_class = g_type_class_peek_parent( class ); /* Create signals. */ /* Init methods. */ iobject_class->changed = toolkitgroup_changed; model_class->view_new = toolkitgroup_view_new; } static void toolkitgroup_init( Toolkitgroup *kitg ) { } GType toolkitgroup_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ToolkitgroupClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) toolkitgroup_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Toolkitgroup ), 32, /* n_preallocs */ (GInstanceInitFunc) toolkitgroup_init, }; type = g_type_register_static( TYPE_MODEL, "Toolkitgroup", &info, 0 ); } return( type ); } static void toolkitgroup_link( Toolkitgroup *kitg, Symbol *root ) { char buf[256]; g_assert( root ); kitg->root = root; im_snprintf( buf, 256, _( "Toolkits for %s" ), IOBJECT( root )->name ); iobject_set( IOBJECT( kitg ), buf, NULL ); } Toolkitgroup * toolkitgroup_new( Symbol *root ) { Toolkitgroup *kitg; kitg = TOOLKITGROUP( g_object_new( TYPE_TOOLKITGROUP, NULL ) ); toolkitgroup_link( kitg, root ); return( kitg ); } /* Need a special sort function ... put kits not being displayed at the end so * they don't mess up the numbering of the visible kits. */ static gint toolkitgroup_sort_compare( Model *a, Model *b ) { if( !a->display && b->display ) return( 1 ); if( a->display && !b->display ) return( -1 ); return( strcasecmp( IOBJECT( a )->name, IOBJECT( b )->name ) ); } void toolkitgroup_sort( Toolkitgroup *kitg ) { iContainer *icontainer = ICONTAINER( kitg ); icontainer->children = g_slist_sort( icontainer->children, (GCompareFunc) toolkitgroup_sort_compare ); icontainer_pos_renumber( icontainer ); } nip2-8.7.1/src/imagedisplay.c0000644000175000017500000003313513351443023012726 00000000000000/* Imagedisplay widget code ... display entire image, place this widget in a * scrolledwindow to get clipping/scrolling behaviour. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ /* Trace painting actions #define DEBUG_PAINT */ /* #define DEBUG_GEO */ #include "ip.h" enum { SIG_AREA_CHANGED, /* xywh area changed, canvas cods */ SIG_LAST }; static GtkDrawingAreaClass *parent_class = NULL; static guint imagedisplay_signals[SIG_LAST] = { 0 }; /* Handy! */ void imagedisplay_queue_draw_area( Imagedisplay *id, Rect *area ) { #ifdef DEBUG_PAINT printf( "imagedisplay_queue_draw_area: " "left = %d, top = %d, width = %d, height = %d\n", area->left, area->top, area->width, area->height ); #endif /*DEBUG_PAINT*/ gtk_widget_queue_draw_area( GTK_WIDGET( id ), area->left, area->top, area->width, area->height ); } /* Repaint an area of the image. */ static void imagedisplay_paint_image( Imagedisplay *id, Rect *area ) { Conversion *conv = id->conv; guchar *buf; int lsk; #ifdef DEBUG_PAINT g_print( "imagedisplay_paint_image: at %d x %d, size %d x %d ", area->left, area->top, area->width, area->height ); gobject_print( G_OBJECT( id ) ); #endif /*DEBUG_PAINT*/ /* Request pixels. We ask the mask first, to get an idea of what's * currently in cache, then request tiles of pixels. We must always * request pixels, even if the mask is blank, because the request * will trigger a notify later which will reinvoke us. */ if( conv->mreg && im_prepare( conv->mreg, area ) ) { #ifdef DEBUG_PAINT printf( "imagedisplay_paint_image: mask paint error\n" ); printf( "\t%s\n", im_error_buffer() ); #endif /*DEBUG_PAINT*/ return; } if( im_prepare( conv->ireg, area ) ) { #ifdef DEBUG_PAINT printf( "imagedisplay_paint_image: paint error\n" ); printf( "\t%s\n", im_error_buffer() ); #endif /*DEBUG_PAINT*/ im_error_clear(); return; } /* Is the mask all zero? Skip the paint. */ if( conv->mreg ) { gboolean found; int x, y; buf = (guchar *) IM_REGION_ADDR( conv->mreg, area->left, area->top ); lsk = IM_REGION_LSKIP( conv->mreg ); found = FALSE; for( y = 0; y < area->height; y++ ) { for( x = 0; x < area->width; x++ ) if( buf[x] ) { found = TRUE; break; } if( found ) break; buf += lsk; } if( !found ) { #ifdef DEBUG_PAINT printf( "imagedisplay_paint_image: zero mask\n" ); #endif /*DEBUG_PAINT*/ return; } } /* Paint into window. */ buf = (guchar *) IM_REGION_ADDR( conv->ireg, area->left, area->top ); lsk = IM_REGION_LSKIP( conv->ireg ); if( conv->ireg->im->Bands == 3 ) gdk_draw_rgb_image( GTK_WIDGET( id )->window, GTK_WIDGET( id )->style->white_gc, area->left, area->top, area->width, area->height, GDK_RGB_DITHER_MAX, buf, lsk ); else if( conv->ireg->im->Bands == 1 ) gdk_draw_gray_image( GTK_WIDGET( id )->window, GTK_WIDGET( id )->style->white_gc, area->left, area->top, area->width, area->height, GDK_RGB_DITHER_MAX, buf, lsk ); } /* Paint an area with the background pattern. */ static void imagedisplay_paint_background( Imagedisplay *id, Rect *expose ) { #ifdef DEBUG_PAINT g_print( "imagedisplay_paint_background: at %d x %d, size %d x %d\n", expose->left, expose->top, expose->width, expose->height ); #endif /*DEBUG_PAINT*/ gdk_draw_rectangle( GTK_WIDGET( id )->window, id->back_gc, TRUE, expose->left, expose->top, expose->width, expose->height ); } /* Paint areas outside the image. */ static void imagedisplay_paint_background_clipped( Imagedisplay *id, Rect *expose ) { Conversion *conv = id->conv; Rect clip; #ifdef DEBUG_PAINT g_print( "imagedisplay_paint_background_clipped: canvas %d x %d\n", conv->canvas.width, conv->canvas.height ); #endif /*DEBUG_PAINT*/ /* If the expose touches the image, we cut it into two parts: * everything to the right of the image, and everything strictly * below. */ im_rect_intersectrect( expose, &conv->canvas, &clip ); if( !im_rect_isempty( &clip ) ) { Rect area; area = *expose; area.left = conv->canvas.width; area.width -= clip.width; if( area.width > 0 ) imagedisplay_paint_background( id, &area ); area = *expose; area.top = conv->canvas.height; area.width = clip.width; area.height -= clip.height; if( area.height > 0 ) imagedisplay_paint_background( id, &area ); } else imagedisplay_paint_background( id, expose ); } static void imagedisplay_paint( Imagedisplay *id, Rect *area ) { Conversion *conv = id->conv; const int tsize = conv->tile_size; Rect clip; int xs, ys; int x, y; /* There's no image to paint. */ if( !conv->ireg ) return; /* Clip non-image parts of the expose. */ im_rect_intersectrect( area, &conv->canvas, &clip ); if( im_rect_isempty( &clip ) ) return; #ifdef DEBUG_PAINT g_print( "imagedisplay_paint: at %d x %d, size %d x %d\n", clip.left, clip.top, clip.width, clip.height ); #endif /*DEBUG_PAINT*/ /* Round left/top down to the start tile. */ xs = (clip.left / tsize) * tsize; ys = (clip.top / tsize) * tsize; /* Now loop painting image tiles. */ for( y = ys; y < IM_RECT_BOTTOM( &clip ); y += tsize ) for( x = xs; x < IM_RECT_RIGHT( &clip ); x += tsize ) { Rect tile; Rect tile2; tile.left = x; tile.top = y; tile.width = conv->tile_size; tile.height = conv->tile_size; im_rect_intersectrect( &tile, &clip, &tile2 ); imagedisplay_paint_image( id, &tile2 ); } } /* Expose signal handler. */ static gint imagedisplay_expose( GtkWidget *widget, GdkEventExpose *event ) { Imagedisplay *id = IMAGEDISPLAY( widget ); GdkRectangle *rect; int i, n; if( !GTK_WIDGET_DRAWABLE( id ) || event->area.width == 0 || event->area.height == 0 || !GTK_WIDGET( id )->window || !GTK_WIDGET_VISIBLE( id ) ) return( FALSE ); gdk_region_get_rectangles( event->region, &rect, &n ); #ifdef DEBUG_PAINT g_print( "imagedisplay_expose: %d rectangles\n", n ); #endif /*DEBUG_PAINT*/ for( i = 0; i < n; i++ ) { Rect area; area.left = rect[i].x; area.top = rect[i].y; area.width = rect[i].width; area.height = rect[i].height; /* Clear to background. Always do this, to make sure we paint * outside the image area. */ imagedisplay_paint_background_clipped( id, &area ); /* And paint pixels. */ imagedisplay_paint( id, &area ); } g_free( rect ); return( FALSE ); } /* Resize signal. */ static gboolean imagedisplay_configure_event( GtkWidget *widget, GdkEventConfigure *event ) { Imagedisplay *id = IMAGEDISPLAY( widget ); #ifdef DEBUG_GEO g_print( "imagedisplay_configure_event: %d x %d:\n", event->width, event->height ); #endif /*DEBUG_GEO*/ /* Note new size in visible hint. Except if parent is a viewport ... * if it's a viewport, someone else will have to track the visible * area. */ if( !GTK_IS_VIEWPORT( gtk_widget_get_parent( widget ) ) ) { id->conv->visible.width = event->width; id->conv->visible.height = event->height; } /* Recalculate shrink to fit, if necessary. */ if( id->shrink_to_fit ) { #ifdef DEBUG_GEO g_print( "imagedisplay_configure_event_cb: shrink-to-fit\n" ); #endif /*DEBUG_GEO*/ conversion_set_mag( id->conv, 0 ); } return( FALSE ); } static void imagedisplay_destroy( GtkObject *object ) { Imagedisplay *id = IMAGEDISPLAY( object ); #ifdef DEBUG g_print( "imagedisplay_destroy: " ); gobject_print( G_OBJECT( id ) ); #endif /*DEBUG*/ FREESID( id->changed_sid, id->conv ); FREESID( id->area_changed_sid, id->conv ); UNREF( id->conv ); UNREF( id->back_gc ); UNREF( id->top_gc ); UNREF( id->bottom_gc ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } /* Conversion has changed ... resize to fit. */ static void imagedisplay_real_conversion_changed( Imagedisplay *id ) { GtkRequisition *requisition = >K_WIDGET( id )->requisition; Rect *canvas = &id->conv->canvas; g_assert( IS_IMAGEDISPLAY( id ) ); #ifdef DEBUG g_print( "imagedisplay_real_conversion_changed: " ); gobject_print( G_OBJECT( id ) ); #endif /*DEBUG*/ /* If we're in shrink-to-fit mode, do a shrink. * Otherwise resize to hold the new image. */ if( id->shrink_to_fit ) conversion_set_mag( id->conv, 0 ); else if( requisition->width != canvas->width || requisition->height != canvas->height ) { #ifdef DEBUG_GEO g_print( "imagedisplay_real_conversion_" "changed: requesting new size " "%d x %d\n", id->conv->canvas.width, id->conv->canvas.height ); #endif /*DEBUG_GEO*/ requisition->width = canvas->width; requisition->height = canvas->height; gtk_widget_queue_resize( GTK_WIDGET( id ) ); } } static void imagedisplay_real_area_changed( Imagedisplay *id, Rect *dirty ) { imagedisplay_queue_draw_area( id, dirty ); } static void imagedisplay_realize( GtkWidget *widget ) { Imagedisplay *id = IMAGEDISPLAY( widget ); GdkColor fg, bg; GTK_WIDGET_CLASS( parent_class )->realize( widget ); gdk_window_set_back_pixmap( widget->window, NULL, FALSE ); gtk_widget_set_double_buffered( widget, FALSE ); id->back_gc = gdk_gc_new( widget->window ); fg.red = fg.green = fg.blue = 0x90 << 8; bg.red = bg.green = bg.blue = 0xA0 << 8; gdk_gc_set_rgb_fg_color( id->back_gc, &fg ); gdk_gc_set_rgb_bg_color( id->back_gc, &bg ); id->top_gc = gdk_gc_new( widget->window ); id->bottom_gc = gdk_gc_new( widget->window ); } /* Init Imagedisplay class. */ static void imagedisplay_class_init( ImagedisplayClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = imagedisplay_destroy; widget_class->expose_event = imagedisplay_expose; widget_class->configure_event = imagedisplay_configure_event; widget_class->realize = imagedisplay_realize; class->conversion_changed = imagedisplay_real_conversion_changed; class->area_changed = imagedisplay_real_area_changed; imagedisplay_signals[SIG_AREA_CHANGED] = g_signal_new( "area_changed", G_OBJECT_CLASS_TYPE( class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( ImagedisplayClass, area_changed ), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER ); } static void imagedisplay_init( Imagedisplay *id ) { id->conv = NULL; id->changed_sid = 0; id->area_changed_sid = 0; id->shrink_to_fit = FALSE; id->back_gc = NULL; id->top_gc = NULL; id->bottom_gc = NULL; } GType imagedisplay_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( ImagedisplayClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) imagedisplay_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Imagedisplay ), 32, /* n_preallocs */ (GInstanceInitFunc) imagedisplay_init, }; type = g_type_register_static( GTK_TYPE_DRAWING_AREA, "Imagedisplay", &info, 0 ); } return( type ); } /* Conversion has changed ... repaint everything. */ static void imagedisplay_conversion_changed_cb( Conversion *conv, Imagedisplay *id ) { #ifdef DEBUG printf( "imagedisplay_conversion_changed_cb: " ); gobject_print( G_OBJECT( id ) ); #endif /*DEBUG*/ IMAGEDISPLAY_GET_CLASS( id )->conversion_changed( id ); g_signal_emit( G_OBJECT( id ), imagedisplay_signals[SIG_AREA_CHANGED], 0, &conv->canvas ); } /* Part of the repaint has changed. */ static void imagedisplay_conversion_area_changed_cb( Conversion *conv, Rect *dirty, Imagedisplay *id ) { #ifdef DEBUG printf( "imagedisplay_conversion_area_changed_cb: " "left = %d, top = %d, width = %d, height = %d, ", dirty->left, dirty->top, dirty->width, dirty->height ); gobject_print( G_OBJECT( id ) ); #endif /*DEBUG*/ g_signal_emit( G_OBJECT( id ), imagedisplay_signals[SIG_AREA_CHANGED], 0, dirty ); } /* Install a conversion. Only allow this once. */ void imagedisplay_set_conversion( Imagedisplay *id, Conversion *conv ) { g_assert( !id->conv ); if( conv ) { id->conv = conv; id->changed_sid = g_signal_connect( id->conv, "changed", G_CALLBACK( imagedisplay_conversion_changed_cb ), id ); id->area_changed_sid = g_signal_connect( id->conv, "area_changed", G_CALLBACK( imagedisplay_conversion_area_changed_cb ), id ); g_object_ref( G_OBJECT( conv ) ); iobject_sink( IOBJECT( conv ) ); /* Trigger a change on the conv so we update. */ iobject_changed( IOBJECT( conv ) ); } } /* Make a new Imagedisplay. Pass in the conversion we should show, conv can * be NULL ... wait for one to be installed. */ Imagedisplay * imagedisplay_new( Conversion *conv ) { Imagedisplay *id = g_object_new( TYPE_IMAGEDISPLAY, NULL ); #ifdef DEBUG g_print( "imagedisplay_new: " ); gobject_print( G_OBJECT( id ) ); #endif /*DEBUG*/ imagedisplay_set_conversion( id, conv ); return( id ); } void imagedisplay_set_shrink_to_fit( Imagedisplay *id, gboolean shrink_to_fit ) { id->shrink_to_fit = shrink_to_fit; if( shrink_to_fit ) conversion_set_mag( id->conv, 0 ); } nip2-8.7.1/src/util.h0000644000175000017500000002555613351443023011250 00000000000000/* Declarations for some basic util functions. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* chartype strings. Useful with break_token(). */ #define NUMERIC "0123456789" #define WHITESPACE " \t\r\b\n" /* Like IM_NEW() etc, but set ip's error buffer. */ #define INEW(IM,A) ((A *)imalloc((IM),sizeof(A))) #define IARRAY(IM,N,T) ((T *)imalloc((IM),(N) * sizeof(T))) /* No nulls! Handy for printf() %s */ #define NN( S ) ((S)?(S):"(null)") #define UNREF( X ) do { \ if( X ) { \ g_object_unref( G_OBJECT( X ) ); \ (X) = NULL; \ } \ } while( 0 ) #define GOG_UNREF( X ) do { \ if( X ) { \ gog_object_clear_parent( GOG_OBJECT( X ) ); \ g_object_unref( G_OBJECT( X ) ); \ (X) = NULL; \ } \ } while( 0 ) #define FREESID( SID, OBJ ) do { \ if( (SID) && (OBJ) ) { \ g_signal_handler_disconnect( (OBJ), (SID) ); \ (SID) = 0; \ } \ } while( 0 ) /* Swap two pointers. */ #define SWAPP( A, B ) { \ void *swapp_t; \ \ swapp_t = (A); \ (A) = (B); \ (B) = swapp_t; \ } void vips_buf_appendi( VipsBuf *buf, IMAGE *im ); gboolean vips_buf_appendsc( VipsBuf *buf, gboolean quote, const char *str ); gboolean set_prop( xmlNode *xnode, const char *name, const char *fmt, ... ) __attribute__((format(printf, 3, 4))); gboolean set_sprop( xmlNode *xnode, const char *name, const char *value ); gboolean set_iprop( xmlNode *xnode, const char *name, int value ); gboolean set_dprop( xmlNode *xnode, const char *name, double value ); gboolean set_slprop( xmlNode *xnode, const char *name, GSList *labels ); gboolean set_dlprop( xmlNode *xnode, const char *name, double *values, int n ); gboolean get_sprop( xmlNode *xnode, const char *name, char *buf, int sz ); gboolean get_spropb( xmlNode *xnode, const char *name, VipsBuf *buf ); gboolean get_iprop( xmlNode *xnode, const char *name, int *out ); gboolean get_dprop( xmlNode *xnode, const char *name, double *out ); gboolean get_bprop( xmlNode *xnode, const char *name, gboolean *out ); gboolean get_slprop( xmlNode *xnode, const char *name, GSList **out ); gboolean get_dlprop( xmlNode *xnode, const char *name, double **out ); xmlNode *get_node( xmlNode *base, const char *name ); Rect *rect_dup( Rect *init ); void *rect_free( Rect *rect ); /* Like GFunc, but return a value. */ typedef gpointer (*SListMapFn)( gpointer, gpointer ); typedef gpointer (*SListMap2Fn)( gpointer, gpointer, gpointer ); typedef gpointer (*SListMap3Fn)( gpointer, gpointer, gpointer, gpointer ); typedef gpointer (*SListMap4Fn)( gpointer, gpointer, gpointer, gpointer, gpointer ); typedef gpointer (*SListMap5Fn)( gpointer, gpointer, gpointer, gpointer, gpointer, gpointer ); typedef gpointer (*SListFoldFn)( gpointer, gpointer, gpointer ); typedef gpointer (*SListFold2Fn)( gpointer, gpointer, gpointer, gpointer ); /* Like foreach, but allow abandon. */ void *slist_map( GSList *list, SListMapFn fn, gpointer a ); void *slist_map2( GSList *list, SListMap2Fn fn, gpointer a, gpointer b ); void *slist_map3( GSList *list, SListMap3Fn fn, gpointer a, gpointer b, gpointer c ); void *slist_map4( GSList *list, SListMap4Fn fn, gpointer a, gpointer b, gpointer c, gpointer d ); void *slist_map5( GSList *list, SListMap5Fn fn, gpointer a, gpointer b, gpointer c, gpointer d, gpointer e ); void *slist_map_rev( GSList *list, SListMapFn fn, gpointer a ); void *slist_map2_rev( GSList *list, SListMap2Fn fn, gpointer a, gpointer b ); void *slist_map3_rev( GSList *list, SListMap3Fn fn, void *a, void *b, void *c ); void *map_equal( void *a, void *b ); gboolean slist_equal( GSList *l1, GSList *l2 ); void *slist_fold( GSList *list, void *start, SListFoldFn fn, void *a ); void *slist_fold2( GSList *list, void *start, SListFold2Fn fn, void *a, void *b ); void slist_free_all( GSList *list ); GSList *slist_remove_all( GSList *list, gpointer data ); /* An slist, which tracks the end of the list, for fast append. */ typedef struct _Queue { GSList *list; GSList *tail; int length; } Queue; Queue *queue_new( void ); /* All we need for now. */ void *queue_head( Queue *queue ); void queue_add( Queue *queue, void *data ); gboolean queue_remove( Queue *q, void *data ); int queue_length( Queue *q ); extern VipsBuf error_top_buf; extern VipsBuf error_sub_buf; void error( const char *fmt, ... ) __attribute__((noreturn, format(printf, 1, 2))); void error_block( void ); /* Block updates to error_string */ void error_unblock( void ); void error_clear( void ); void error_top( const char *fmt, ... ) __attribute__((format(printf, 1, 2))); void error_sub( const char *fmt, ... ) __attribute__((format(printf, 1, 2))); void error_vips( void ); void error_vips_all( void ); const char *error_get_top( void ); const char *error_get_sub( void ); gboolean is_postfix( const char *a, const char *b ); gboolean is_prefix( const char *a, const char *b ); gboolean is_caseprefix( const char *a, const char *b ); gboolean is_casepostfix( const char *a, const char *b ); const char *findrightmost( const char *a, const char *b ); char *my_strcasestr( const char *haystack, const char *needle ); void change_suffix( const char *name, char *out, const char *new, const char **olds, int nolds ); char *my_strccpy( char *output, const char *input ); char *my_strecpy( char *output, const char *input, gboolean quote ); const char *my_strrspn( const char *p, const char *spn ); char *trim_nonalpha( char *text ); char *trim_white( char *text ); void *get_element( REGION *ireg, int x, int y, int b ); const char *decode_bandfmt( int f ); const char *decode_type( int t ); void get_image_info( VipsBuf *buf, const char *name ); void expand_variables( const char *in, char *out ); void nativeize_path( char *buf ); void absoluteize_path( char *path ); void canonicalize_path( char *path ); const char *get_vipshome( const char *argv0 ); typedef void *(*callv_string_fn)( const char *name, void *a, void *b, void *c ); void *callv_string( callv_string_fn fn, const char *name, void *a, void *b, void *c ); void *callv_stringva( callv_string_fn fn, const char *name, va_list ap, void *a, void *b, void *c ); void *callv_stringf( callv_string_fn fn, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); void *callv_string_filename( callv_string_fn fn, const char *filename, void *a, void *b, void *c ); void *callv_string_filenameva( callv_string_fn fn, const char *name, va_list ap, void *a, void *b, void *c ); void *callv_string_filenamef( callv_string_fn fn, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); typedef int (*calli_string_fn)( const char *name, void *a, void *b, void *c ); int calli_string( calli_string_fn fn, const char *name, void *a, void *b, void *c ); int calli_stringva( calli_string_fn fn, const char *name, va_list ap, void *a, void *b, void *c ); int calli_stringf( calli_string_fn fn, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); int calli_string_filename( calli_string_fn fn, const char *filename, void *a, void *b, void *c ); int calli_string_filenameva( calli_string_fn fn, const char *name, va_list ap, void *a, void *b, void *c ); int calli_string_filenamef( calli_string_fn fn, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); char *f2utf8( const char *filename ); char *im_strdupn( const char *str ); void setenvf( const char *name, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); gboolean existsf( const char *name, ... ) __attribute__((format(printf, 1, 2))); gboolean isdir( const char *filename, ... ) __attribute__((format(printf, 1, 2))); time_t mtime( const char *filename, ... ) __attribute__((format(printf, 1, 2))); gboolean mkdirf( const char *name, ... ) __attribute__((format(printf, 1, 2))); int systemf( const char *fmt, ... ) __attribute__((format(printf, 1, 2))); FILE *popenf( const char *fmt, const char *mode, ... ) __attribute__((format(printf, 1, 3))); gboolean touchf( const char *fmt, ... ) __attribute__((format(printf, 1, 2))); int unlinkf( const char *fmt, ... ) __attribute__((format(printf, 1, 2))); gboolean is_absolute( const char *fname ); gboolean is_valid_filename( const char *name ); /* Text IO to/from files. Track the filename too, to help error messages. */ typedef struct _iOpenFile { FILE *fp; char *fname; /* File we were passed to make this open_file */ char *fname_real; /* File we opened (maybe after search) */ int last_errno; /* On error, last value for errno */ gboolean read; /* True for open read, false for open write */ } iOpenFile; void ifile_close( iOpenFile *of ); iOpenFile *ifile_open_read( const char *name, ... ) __attribute__((format(printf, 1, 2))); iOpenFile *ifile_open_read_stdin(); iOpenFile *ifile_open_write( const char *name, ... ) __attribute__((format(printf, 1, 2))); gboolean ifile_write( iOpenFile *of, const char *fmt, ... ) __attribute__((format(printf, 2, 3))); gboolean ifile_write_var( iOpenFile *of, const char *name, const char *value ); char *ifile_read( iOpenFile *of ); char *ifile_read_buffer( iOpenFile *of, char *buffer, size_t len ); int ifile_getc( iOpenFile *of ); double directory_size( const char *dirname ); char *escape_percent( const char *in, char *out, int len ); char *escape_markup( const char *in, char *out, int len ); char *escape_mode( const char *in, char *out, int len ); char *break_token( char *str, const char *brk ); const char *rpt( char ch, int n ); const char *spc( int n ); void number_to_string( int n, char *buf ); double find_space( const char *name ); gboolean temp_name( char *name, const char *ext ); int findmaxmin( IMAGE *in, int left, int top, int width, int height, double *min, double *max ); gboolean char_to_bool( char *str, void *out ); char *bool_to_char( gboolean b ); void increment_name( char *buf ); void increment_filename( char *filename ); int extract_first_line( char *buf, char *str, int len ); void name_from_filename( const char *in, char *out ); void util_check_all_destroyed( void ); void *imalloc( IMAGE *im, size_t len ); GSList *recent_add( GSList *recent, const char *filename ); GSList *recent_load( const char *filename ); void recent_free( GSList *recent ); void recent_save( GSList *recent, const char *filename ); const char *get_savedir( void ); void **slist_to_array( GSList *list ); int array_len( void **array ); nip2-8.7.1/src/nip2-cli.c0000644000175000017500000001204713351443023011672 00000000000000/* nip2-cli.c ... run the nip2 executable, connecting stdin and stdout to the * console * * 11/12/09 * - use SetHandleInformation() to stop the child inheriting the read * handle (thanks Leo) */ /* Copyright (C) 2008 Imperial College, London This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Adapted from sample code by Leo Davidson, with the author's permission. */ /* Windows does not let a single exe run in both command-line and GUI mode. To * run nip2 in command-line mode, we run this CLI wrapper program instead, * which starts the main nip2 exe, connecting stdin/out/err appropriately. */ #include #include #include #include #include void print_last_error () { char *buf; if (FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) & buf, 0, NULL)) { fprintf (stderr, "%s", buf); LocalFree (buf); } } int main (int argc, char **argv) { char *dirname; char command[2048]; gboolean quote; int i, j; HANDLE hChildStdoutRd; HANDLE hChildStdoutWr; SECURITY_ATTRIBUTES saAttr; PROCESS_INFORMATION processInformation; STARTUPINFO startUpInfo; DWORD dwRead; CHAR buf[1024]; /* we run the nip2.exe in the same directory as this exe: swap the last * pathname component for nip2.exe * we change the argv[0] pointer, probably not a good idea */ dirname = g_path_get_dirname (argv[0]); argv[0] = g_build_filename (dirname, "nip2.exe", NULL); g_free (dirname); if (_access (argv[0], 00)) { fprintf (stderr, "cannot access \"%s\"\n", argv[0]); exit (1); } /* build the command string ... we have to quote items containing spaces */ command[0] = '\0'; for (i = 0; i < argc; i++) { quote = FALSE; for (j = 0; argv[i][j]; j++) { if (isspace (argv[i][j])) { quote = TRUE; break; } } if (i > 0) { strncat (command, " ", sizeof (command) - 1); } if (quote) { strncat (command, "\"", sizeof (command) - 1); } strncat (command, argv[i], sizeof (command) - 1); if (quote) { strncat (command, "\"", sizeof (command) - 1); } } if (strlen (command) == sizeof (command) - 1) { fprintf (stderr, "command too long\n"); exit (1); } /* Create a pipe for the child process's STDOUT. */ hChildStdoutRd = NULL; hChildStdoutWr = NULL; saAttr.nLength = sizeof (SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; if (!CreatePipe (&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { fprintf (stderr, "CreatePipe failed: "); print_last_error (); fprintf (stderr, "\n"); exit (1); } /* Ensure the read handle to the pipe for STDOUT is not inherited. */ if (!SetHandleInformation(hChildStdoutRd, HANDLE_FLAG_INHERIT, 0)) { fprintf (stderr, "SetHandleInformation failed: "); print_last_error (); fprintf (stderr, "\n"); exit (1); } /* Run command. */ startUpInfo.cb = sizeof (STARTUPINFO); startUpInfo.lpReserved = NULL; startUpInfo.lpDesktop = NULL; startUpInfo.lpTitle = NULL; startUpInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; startUpInfo.hStdOutput = hChildStdoutWr; startUpInfo.hStdError = hChildStdoutWr; startUpInfo.cbReserved2 = 0; startUpInfo.lpReserved2 = NULL; startUpInfo.wShowWindow = SW_SHOWNORMAL; if (!CreateProcess (NULL, command, NULL, /* default security */ NULL, /* default thread security */ TRUE, /* inherit handles */ CREATE_DEFAULT_ERROR_MODE | DETACHED_PROCESS, NULL, /* use default environment */ NULL, /* set default directory */ &startUpInfo, &processInformation)) { fprintf (stderr, "error running \"%s\": ", command); print_last_error (); fprintf (stderr, "\n"); exit (1); } /* Close the write end of the pipe before reading from the read end. */ CloseHandle (hChildStdoutWr); while (ReadFile (hChildStdoutRd, buf, sizeof (buf) - 1, &dwRead, NULL) && dwRead > 0) { buf[dwRead] = '\0'; printf ("%s", buf); } CloseHandle (hChildStdoutRd); return (0); } nip2-8.7.1/src/parser.h0000644000175000017500000000530713351443023011557 00000000000000/* Global variables from parse.y. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Our input stream can be attached to either a string or a FILE. * Keep track of the state of play here. */ typedef struct { iOpenFile *of; /* Non-NULL if we read from a file */ char *str; /* Non-NULL if we read from a string */ char *strpos; /* Position in string */ char buf[MAX_STRSIZE]; /* Accumulate text of each definition here */ int bwp; /* Write point in the above */ int bsp[MAX_SSTACK]; /* Start point stack */ int bspsp; /* Stack pointer */ int lineno; /* Current line number */ int charno; /* Character in line */ int pcharno; /* Characters in previous line */ int charpos; /* Characters read by lex so far */ int oldchar; /* unget buffer, -1 for no unget */ } InputState; extern InputState input_state; /* Function declarations for parse.y. */ void nip2yyerror( const char *sub, ... ) __attribute__((format(printf, 1, 2))); void yyerror( const char *msg ); #ifdef YYLENG_IS_YY_SIZE_T /* Assume yy_size_t is size_t. */ extern size_t yyleng; #else extern int yyleng; /* lex stuff */ #endif /* Lex gathers tokens here for workspace.c */ extern VipsBuf lex_text; /* Attach input for lex. */ void attach_input_file( iOpenFile *of ); void attach_input_string( const char *str ); int ip_input( void ); void ip_unput( int ch ); void ip_unget( void ); gboolean is_EOF( void ); /* Parse stuff. */ /* Order and number important ... see table in parse_rhs() */ typedef enum { PARSE_RHS = 0, /* eg. "a + b" */ PARSE_PARAMS, /* eg. "a b = a + b" */ PARSE_SUPER /* eg. "fred c d" */ } ParseRhsSyntax; extern jmp_buf parse_error_point; gboolean parse_toplevel( Toolkit *kit, int pos ); gboolean parse_onedef( Toolkit *kit, int pos ); gboolean parse_rhs( Expr *expr, ParseRhsSyntax syntax ); void free_lex( int yychar ); char *parse_test_define( void ); Symbol *parse_set_symbol( void ); nip2-8.7.1/src/colourview.h0000644000175000017500000000312513351443023012455 00000000000000/* a colourview in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_COLOURVIEW (colourview_get_type()) #define COLOURVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_COLOURVIEW, Colourview )) #define COLOURVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_COLOURVIEW, ColourviewClass )) #define IS_COLOURVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_COLOURVIEW )) #define IS_COLOURVIEW_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_COLOURVIEW )) typedef struct _Colourview { Graphicview parent_object; Colourdisplay *colourdisplay; Conversion *conv; GtkWidget *label; } Colourview; typedef struct _ColourviewClass { GraphicviewClass parent_class; /* My methods. */ } ColourviewClass; GtkType colourview_get_type( void ); View *colourview_new( void ); nip2-8.7.1/src/plotpresent.c0000644000175000017500000001651713351443023012642 00000000000000/* a plot widget, plus some navigation stuff */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG_EVENT #define DEBUG */ #include "ip.h" #ifdef HAVE_LIBGOFFICE static GtkBinClass *parent_class = NULL; enum { SIG_MOUSE_MOVE, /* mose drag, axies cods */ SIG_LAST }; static guint plotpresent_signals[SIG_LAST] = { 0 }; static void plotpresent_mouse_move( Plotpresent *plotpresent, double x, double y ) { g_signal_emit( G_OBJECT( plotpresent ), plotpresent_signals[SIG_MOUSE_MOVE], 0, x, y ); } static void plotpresent_destroy( GtkObject *object ) { Plotpresent *plotpresent; g_return_if_fail( object != NULL ); g_return_if_fail( IS_PLOTPRESENT( object ) ); plotpresent = PLOTPRESENT( object ); #ifdef DEBUG printf( "plotpresent_destroy: %p\n", plotpresent ); #endif /*DEBUG*/ /* My instance destroy stuff. */ UNREF( plotpresent->grend ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void plotpresent_size_request( GtkWidget *widget, GtkRequisition *requisition ) { GtkBin *bin = GTK_BIN( widget ); if( bin->child && GTK_WIDGET_VISIBLE( bin->child ) ) gtk_widget_size_request( bin->child, requisition ); } static void plotpresent_size_allocate( GtkWidget *widget, GtkAllocation *allocation ) { GtkBin *bin = GTK_BIN( widget ); if( bin->child && GTK_WIDGET_VISIBLE( bin->child ) ) gtk_widget_size_allocate( bin->child, allocation ); } /* Spot mouse motion events, to update status bar. */ static gboolean plotpresent_motion_notify_event( GtkWidget *widget, GdkEventMotion *event ) { Plotpresent *plotpresent = PLOTPRESENT( widget ); GtkAllocation *allocation = >K_WIDGET( plotpresent->canvas )->allocation; GogView *view; GSList *axes; GogAxis *x_axis; GogAxis *y_axis; GogChartMap *map; #ifdef DEBUG_EVENT printf( "plotpresent_motion_notify_event: %p\n", plotpresent ); printf( "event->x = %g, event->y = %g\n", event->x, event->y ); #endif /*DEBUG_EVENT*/ gog_renderer_update( plotpresent->grend, allocation->width, allocation->height ); g_object_get( G_OBJECT( plotpresent->grend ), "view", &view, NULL ); view = gog_view_find_child_view( view, GOG_OBJECT( plotpresent->gplot ) ); axes = gog_chart_get_axes( plotpresent->gchart, GOG_AXIS_X ); x_axis = GOG_AXIS( axes->data ); g_slist_free( axes ); axes = gog_chart_get_axes( plotpresent->gchart, GOG_AXIS_Y ); y_axis = GOG_AXIS( axes->data ); g_slist_free( axes ); map = gog_chart_map_new( plotpresent->gchart, &(view->allocation), x_axis, y_axis, NULL, FALSE ); if( gog_chart_map_is_valid( map ) && event->x >= view->allocation.x && event->x < view->allocation.x + view->allocation.w && event->y >= view->allocation.y && event->y < view->allocation.y + view->allocation.h ) { GogAxisMap *x_map; GogAxisMap *y_map; double x; double y; x_map = gog_chart_map_get_axis_map( map, 0 ); y_map = gog_chart_map_get_axis_map( map, 1 ); x = gog_axis_map_from_view( x_map, event->x ); y = gog_axis_map_from_view( y_map, event->y ); plotpresent_mouse_move( plotpresent, x, y ); } gog_chart_map_free( map ); return( FALSE ); } static void plotpresent_class_init( PlotpresentClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; GtkWidgetClass *widget_class = (GtkWidgetClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = plotpresent_destroy; widget_class->size_request = plotpresent_size_request; widget_class->size_allocate = plotpresent_size_allocate; widget_class->motion_notify_event = plotpresent_motion_notify_event; /* Create signals. */ plotpresent_signals[SIG_MOUSE_MOVE] = g_signal_new( "mouse_move", G_OBJECT_CLASS_TYPE( class ), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET( PlotpresentClass, mouse_move ), NULL, NULL, nip_VOID__DOUBLE_DOUBLE, G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE ); /* Init methods. */ } static void plotpresent_init( Plotpresent *plotpresent ) { #ifdef DEBUG printf( "plotpresent_init: %p\n", plotpresent ); #endif /*DEBUG*/ plotpresent->gplot = NULL; plotpresent->canvas = go_graph_widget_new( NULL ); gtk_container_add( GTK_CONTAINER( plotpresent ), plotpresent->canvas ); gtk_widget_show( GTK_WIDGET( plotpresent->canvas ) ); plotpresent->ggraph = go_graph_widget_get_graph( GO_GRAPH_WIDGET( plotpresent->canvas ) ); plotpresent->gchart = go_graph_widget_get_chart( GO_GRAPH_WIDGET( plotpresent->canvas ) ); gtk_widget_add_events( plotpresent->canvas, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK ); /* You'd think we could set up the axies too, but we can't get them * from the chart until it's realized. Wait for the first refresh. */ plotpresent->grend = gog_renderer_new( plotpresent->ggraph ); } GType plotpresent_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( PlotpresentClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) plotpresent_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Plotpresent ), 32, /* n_preallocs */ (GInstanceInitFunc) plotpresent_init, }; type = g_type_register_static( GTK_TYPE_BIN, "Plotpresent", &info, 0 ); } return( type ); } static void plotpresent_build_plot( Plotpresent *plotpresent ) { Plotmodel *plotmodel = plotpresent->plotmodel; Plot *plot = plotmodel->plot; #ifdef DEBUG printf( "plotpresent_build_plot: %p\n", plotpresent ); #endif /*DEBUG*/ GOG_UNREF( plotpresent->gplot ); plotpresent->gplot = plot_new_gplot( plot ); gog_object_add_by_name( GOG_OBJECT( plotpresent->gchart ), "Plot", GOG_OBJECT( plotpresent->gplot ) ); plot_style_main( plot, plotpresent->gchart ); } static void plotpresent_changed_cb( Plotmodel *plotmodel, Plotpresent *plotpresent ) { Plot *plot = plotmodel->plot; #ifdef DEBUG printf( "plotpresent_changed_cb: %p\n", plotpresent ); #endif /*DEBUG*/ /* Can refresh before model build. */ if( plot->rows == 0 || plot->columns == 0 ) return; /* Rebuild plot and data. */ plotpresent_build_plot( plotpresent ); } static void plotpresent_link( Plotpresent *plotpresent, Plotmodel *plotmodel ) { /* All the model parts for our set of views. */ plotpresent->plotmodel = plotmodel; g_signal_connect( G_OBJECT( plotmodel ), "changed", G_CALLBACK( plotpresent_changed_cb ), plotpresent ); } Plotpresent * plotpresent_new( Plotmodel *plotmodel ) { Plotpresent *plotpresent = gtk_type_new( TYPE_PLOTPRESENT ); plotpresent_link( plotpresent, plotmodel ); return( plotpresent ); } #endif /*HAVE_LIBGOFFICE*/ nip2-8.7.1/src/imagedisplay.h0000644000175000017500000000470613351443023012735 00000000000000/* Imagedisplay widget stuff. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_IMAGEDISPLAY (imagedisplay_get_type()) #define IMAGEDISPLAY( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IMAGEDISPLAY, Imagedisplay )) #define IMAGEDISPLAY_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_IMAGEDISPLAY, ImagedisplayClass)) #define IS_IMAGEDISPLAY( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEDISPLAY )) #define IS_IMAGEDISPLAY_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEDISPLAY )) #define IMAGEDISPLAY_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_IMAGEDISPLAY, ImagedisplayClass )) /* Display an entire image. Put in a scrolled window to see just part of it. */ struct _Imagedisplay { GtkDrawingArea parent_object; /* Image we display. */ Conversion *conv; /* Conversion we display */ guint changed_sid; /* Watch conv with these */ guint area_changed_sid; gboolean shrink_to_fit; /* Auto-shrink mode */ /* GCs also used by region paint. */ GdkGC *back_gc; GdkGC *top_gc; GdkGC *bottom_gc; }; /* Class structure. */ typedef struct _ImagedisplayClass { /* Drawing area we paint in. */ GtkDrawingAreaClass parent_class; /* Virtual methods. */ void (*conversion_changed)( Imagedisplay * ); void (*area_changed)( Imagedisplay *, Rect * ); } ImagedisplayClass; void imagedisplay_queue_draw_area( Imagedisplay *id, Rect *area ); GType imagedisplay_get_type( void ); void imagedisplay_set_conversion( Imagedisplay *id, Conversion *conv ); Imagedisplay *imagedisplay_new( Conversion *conv ); void imagedisplay_set_shrink_to_fit( Imagedisplay *id, gboolean shrink_to_fit ); nip2-8.7.1/src/tree.h0000644000175000017500000001321113351443023011213 00000000000000/* Declarations for the tree builder. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* The kinds of nodes we can have in a parse tree. */ typedef enum { NODE_NONE, /* Empty */ NODE_APPLY, /* A function application */ NODE_BINOP, /* A binary operator */ NODE_UOP, /* A unary operator */ NODE_LEAF, /* A leaf .. a symbol of some sort */ NODE_CLASS, /* A class */ NODE_TAG, /* A tag .. rhs of '.' */ NODE_CONST, /* A constant */ NODE_GENERATOR, /* A list generator */ NODE_COMPOSE, /* Function composition */ NODE_SUPER, /* Superclass constructor */ NODE_PATTERN_CLASS, /* A class pattern match */ NODE_LISTCONST /* A list expression "[1, 2, 3]" */ } NodeTypes; /* Binary operators. Order important! Keep changes in step with operator_table[] in action.c */ typedef enum { BI_NONE = 0, /* Nothing */ BI_ADD, /* Addition and subtraction */ BI_SUB, BI_REM, /* Remainder after division */ BI_POW, /* Raise to power */ BI_SELECT, /* Select a channel/subscript */ BI_LSHIFT, /* Shift left */ BI_RSHIFT, /* Shift right */ BI_DIV, /* Divide by a constant */ BI_JOIN, /* Join of two objects */ BI_DOT, /* Projection operator */ BI_COMMA, /* Form complex number */ BI_MUL, /* Mult by a constant */ BI_LAND, /* Logical and */ BI_LOR, /* Logical or */ BI_BAND, /* Bitwise and */ BI_BOR, /* Bitwise or */ BI_EOR, /* Either - or */ BI_EQ, /* Equality */ BI_NOTEQ, BI_PEQ, /* Pointer equality */ BI_PNOTEQ, BI_LESS, /* Relational ops */ BI_LESSEQ, BI_MORE, BI_MOREEQ, BI_IF, /* if-then-else */ BI_CONS /* List cons ... has to be last, see below */ } BinOp; /* Unary operators. Order important! Keep changes in step with operator_table[] in action.c */ typedef enum { UN_NONE = BI_CONS + 1, /* Nothing */ UN_CSCHAR, /* Convert to signed char */ UN_CUCHAR, /* Convert to unsigned char */ UN_CSSHORT, /* Convert to signed short */ UN_CUSHORT, /* Convert to unsigned short */ UN_CSINT, /* Convert to signed int */ UN_CUINT, /* Convert to unsigned int */ UN_CFLOAT, /* Convert to signed float */ UN_CDOUBLE, /* Convert to signed double */ UN_CCOMPLEX, /* Convert to complex */ UN_CDCOMPLEX, /* Convert to double complex */ UN_MINUS, /* Unary minus */ UN_NEG, /* Logical negation, "!" */ UN_COMPLEMENT, /* 1s complement, "~" */ UN_PLUS, /* Unary plus */ UN_LAST /* Sanity check with this */ } UnOp; /* The sorts of constants we can have in expressions. */ typedef enum { PARSE_CONST_NONE, PARSE_CONST_STR, PARSE_CONST_BOOL, PARSE_CONST_NUM, PARSE_CONST_COMPLEX, /* Eg. 12j == (0, 12) */ PARSE_CONST_CHAR, PARSE_CONST_ELIST /* Empty list [] */ } ParseConstTypes; /* Constants in expressions. */ struct _ParseConst { ParseConstTypes type; union { double num; char *str; gboolean bool; int ch; } val; }; /* A parse tree node. */ struct _ParseNode { /* Compiled in here. */ Compile *compile; NodeTypes type; /* Bundle for node types with up to two arguments. */ BinOp biop; UnOp uop; ParseNode *arg1; ParseNode *arg2; /* Just for generators, eg. [a, b .. c] */ ParseNode *arg3; /* A symbol reference. */ Symbol *leaf; /* A class. */ Compile *klass; /* Expression list ... super constructor plus args, or list constant. */ GSList *elist; /* A tag. */ char *tag; /* A constant. */ ParseConst con; }; void tree_const_destroy( ParseConst *pc ); ParseNode *tree_binop_new( Compile *compile, BinOp op, ParseNode *l, ParseNode *r ); ParseNode *tree_generator_new( Compile *compile, ParseNode *s, ParseNode *i, ParseNode *f ); ParseNode *tree_lconst_new( Compile *compile, ParseNode *s ); ParseNode *tree_lconst_extend( Compile *compile, ParseNode *s, ParseNode *n ); ParseNode *tree_super_new( Compile *compile ); ParseNode *tree_super_extend( Compile *compile, ParseNode *base, ParseNode *n ); ParseNode *tree_ifelse_new( Compile *compile, ParseNode *c, ParseNode *t, ParseNode *e ); ParseNode *tree_appl_new( Compile *compile, ParseNode *l, ParseNode *r ); ParseNode *tree_tag_new( Compile *compile, const char *r ); ParseNode *tree_unop_new( Compile *compile, UnOp op, ParseNode *a ); ParseNode *tree_leaf_new( Compile *compile, const char *name ); ParseNode *tree_leafsym_new( Compile *compile, Symbol *sym ); ParseNode *tree_const_new( Compile *compile, ParseConst n ); ParseNode *tree_class_new( Compile *compile ); ParseNode *tree_compose_new( Compile *compile, ParseNode *f, ParseNode *g ); ParseNode *tree_pattern_new( Compile *compile ); ParseNode *tree_pattern_class_new( Compile *compile, const char *class_name, ParseNode *l ); void *tree_node_destroy( ParseNode *n ); typedef ParseNode *(*tree_map_fn)( Compile *, ParseNode *, void *, void * ); ParseNode *tree_map( Compile *compile, tree_map_fn fn, ParseNode *node, void *a, void *b ); /* Copy a tree into a new context. */ ParseNode *tree_copy( Compile *compile, ParseNode *node ); nip2-8.7.1/src/imageinfo.h0000644000175000017500000002054313351443023012220 00000000000000/* Decls for imageinfo.c */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* Meta we attach for the filename we loaded from. */ #define ORIGINAL_FILENAME "original-filename" /* Group imageinfo with this. */ #define TYPE_IMAGEINFOGROUP (imageinfogroup_get_type()) #define IMAGEINFOGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ TYPE_IMAGEINFOGROUP, Imageinfogroup )) #define IMAGEINFOGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_IMAGEINFOGROUP, ImageinfogroupClass)) #define IS_IMAGEINFOGROUP( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEINFOGROUP )) #define IS_IMAGEINFOGROUP_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEINFOGROUP )) #define IMAGEINFOGROUP_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_IMAGEINFOGROUP, ImageinfogroupClass )) typedef struct _Imageinfogroup { iContainer parent_object; /* Hash from filename to list of imageinfo. We can't use the * icontainer hash, since our filenames are not unique (we can have * the same file loaded several times, if some other application is * changing our files behind our back). */ GHashTable *filename_hash; } Imageinfogroup; typedef struct _ImageinfogroupClass { iContainerClass parent_class; } ImageinfogroupClass; GType imageinfogroup_get_type( void ); Imageinfogroup *imageinfogroup_new( void ); /* An image. */ #define TYPE_IMAGEINFO (imageinfo_get_type()) #define IMAGEINFO( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IMAGEINFO, Imageinfo )) #define IMAGEINFO_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IMAGEINFO, ImageinfoClass)) #define IS_IMAGEINFO( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEINFO )) #define IS_IMAGEINFO_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEINFO )) #define IMAGEINFO_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IMAGEINFO, ImageinfoClass )) /* A fragment of an undo buffer. */ typedef struct _Undofragment { struct _Undobuffer *undo; /* Main undo area */ IMAGE *im; /* Old area */ Rect pos; /* Where we took it from */ } Undofragment; /* Hold a list of the above, a bounding box for this list and a link back to * the main imageinfo. */ typedef struct _Undobuffer { struct _Imageinfo *imageinfo; /* Main paint area */ GSList *frags; /* List of paint fragments */ Rect bbox; /* Bounding box for frags */ } Undobuffer; /* Attach one of these to any IMAGE we monitor. It has the same lifetime as * the IMAGE and gets zapped by the imageinfo on dispose. This lets us spot * IMAGE events after the holding Imageinfo has gone. */ typedef struct _Imageinfoproxy { IMAGE *im; Imageinfo *imageinfo; } Imageinfoproxy; /* A VIPS image wrapped up nicely. */ struct _Imageinfo { Managed parent_object; IMAGE *im; /* Image we manage, LUT if delayed */ IMAGE *mapped_im; /* Cache image mapped-thru-lut here */ IMAGE *identity_lut; /* For base images, keep an id lut if poss */ Imageinfo *underlying; /* If we're a LUT, the image we are a LUT of */ Imageinfoproxy *proxy; /* Proxy for IMAGE callbacks */ gboolean dfile; /* delete_file on final close */ char *delete_filename; /* and the file we delete */ gboolean from_file; /* Set if ->name is a user file */ time_t mtime; /* What mtime was when we loaded this file */ /* Exprs which are thought to have this image as their value. See * expr_value_new(). */ GSList *exprs; /* Set if we've checked with the user that it's OK to paint on this * imageinfo. */ gboolean ok_to_paint; /* Undo/redo buffers. */ GSList *undo; /* List of undo buffers */ GSList *redo; /* List of redo buffers */ Undobuffer *cundo; /* Current buffer */ /* Have we attached progress stuff to this ii? */ gboolean monitored; /* If we're from a file, the timestamp on the file we loaded from ... * used to spot changes. */ time_t check_mtime; guint check_tid; }; typedef struct _ImageinfoClass { ManagedClass parent_class; /* An area of the screen needs repainting. This can happen for regions * being dragged, for example, and doesn't always mean pixels have * changed. */ void (*area_changed)( Imageinfo *, Rect * ); /* An area of the image has been paintboxed ... invalidate caches and * trigger area_changed. */ void (*area_painted)( Imageinfo *, Rect * ); /* Our IMAGE* has signaled "invalidate". This can happen indirectly: * if we paint on an image, im_invalidate() will trigger on that image * and all derived images. */ void (*invalidate)( Imageinfo * ); /* Update undo/redo button sensitivities. */ void (*undo_changed)( Imageinfo * ); /* The underlying file has changed ... higher levels should try to * reload. */ void (*file_changed)( Imageinfo * ); } ImageinfoClass; void *imageinfo_area_changed( Imageinfo *imageinfo, Rect *dirty ); void *imageinfo_area_painted( Imageinfo *imageinfo, Rect *dirty ); void *imageinfo_expr_remove( Expr *expr, Imageinfo *imageinfo ); void imageinfo_expr_add( Imageinfo *imageinfo, Expr *expr ); GSList *imageinfo_expr_which( Imageinfo *imageinfo ); IMAGE *imageinfo_get_underlying( Imageinfo *imageinfo ); GType imageinfo_get_type( void ); Imageinfo *imageinfo_new( Imageinfogroup *imageinfogroup, Heap *heap, IMAGE *im, const char *name ); Imageinfo *imageinfo_new_temp( Imageinfogroup *imageinfogroup, Heap *heap, const char *name, const char *mode ); Imageinfo *imageinfo_new_from_pixbuf( Imageinfogroup *imageinfogroup, Heap *heap, GdkPixbuf *pixbuf ); void imageinfo_set_underlying( Imageinfo *top_imageinfo, Imageinfo *imageinfo ); gboolean imageinfo_is_from_file( Imageinfo *imageinfo ); Imageinfo *imageinfo_new_input( Imageinfogroup *imageinfogroup, GtkWidget *parent, Heap *heap, const char *name ); IMAGE *imageinfo_get( gboolean use_lut, Imageinfo *imageinfo ); gboolean imageinfo_same_underlying( Imageinfo *imageinfo[], int n ); gboolean imageinfo_write( Imageinfo *imageinfo, const char *filename ); gboolean imageinfo_check_paintable( Imageinfo *imageinfo, GtkWidget *parent, iWindowNotifyFn nfn, void *sys ); void imageinfo_note( Symbol *sym, Imageinfo *imageinfo ); void imageinfo_forget( Symbol *sym, Imageinfo *imageinfo ); GSList *imageinfo_which( Imageinfo *im ); void imageinfo_make_sub( Imageinfo *out, int n, Imageinfo **in ); void imageinfo_mark( Imageinfo *imageinfo ); Imageinfo *imageinfo_sym_image( Symbol *sym ); void imageinfo_undo_mark( Imageinfo *imageinfo ); gboolean imageinfo_undo( Imageinfo *imageinfo ); gboolean imageinfo_redo( Imageinfo *imageinfo ); void imageinfo_undo_clear( Imageinfo *imageinfo ); gboolean imageinfo_paint_line( Imageinfo *imageinfo, Imageinfo *ink, Imageinfo *mask, int x1, int y1, int x2, int y2 ); gboolean imageinfo_paint_flood( Imageinfo *imageinfo, Imageinfo *ink, int x, int y, gboolean blob ); gboolean imageinfo_paint_smudge( Imageinfo *imageinfo, Rect *oper, int x1, int y1, int x2, int y2 ); gboolean imageinfo_paint_dropper( Imageinfo *imageinfo, Imageinfo *ink, int x, int iy ); gboolean imageinfo_paint_rect( Imageinfo *imageinfo, Imageinfo *ink, Rect *area ); gboolean imageinfo_paint_text( Imageinfo *imageinfo, const char *font_name, const char *text, Rect *tarea ); gboolean imageinfo_paint_nib( Imageinfo *imageinfo, int nib_radius ); gboolean imageinfo_paint_mask( Imageinfo *imageinfo, Imageinfo *ink, Imageinfo *mask, int x, int y ); void imageinfo_to_text( Imageinfo *imageinfo, VipsBuf *buf ); gboolean imageinfo_from_text( Imageinfo *imageinfo, const char *text ); void imageinfo_to_rgb( Imageinfo *imageinfo, double *rgb ); void imageinfo_from_rgb( Imageinfo *imageinfo, double *rgb ); void imageinfo_colour_edit( GtkWidget *parent, Imageinfo *imageinfo ); nip2-8.7.1/src/BITMAPS/0000755000175000017500000000000013417043451011270 500000000000000nip2-8.7.1/src/BITMAPS/mini_page.xpm0000644000175000017500000000071213351443023013662 00000000000000/* XPM */ static char * mini_page_xpm[] = { "16 16 4 1", " c None s None", ". c black", "X c white", "o c #808080", " ", " ....... ", " .XXXXX.. ", " .XoooX.X. ", " .XXXXX.... ", " .XooooXoo.o ", " .XXXXXXXX.o ", " .XooooooX.o ", " .XXXXXXXX.o ", " .XooooooX.o ", " .XXXXXXXX.o ", " .XooooooX.o ", " .XXXXXXXX.o ", " ..........o ", " oooooooooo ", " "}; nip2-8.7.1/src/BITMAPS/separator.xpm0000644000175000017500000000063413351443023013735 00000000000000/* XPM */ static char *separator[]={ "64 4 6 1", "# c #000040", ". c #0000ff", "c c #0080ff", "a c #58a8ff", "b c #a8dcff", "d c #ffffff", ".##############################################################.", "a..............................................................a", "bbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb", "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"}; nip2-8.7.1/src/BITMAPS/watch_msk.xbm0000644000175000017500000000053713351443023013701 00000000000000#define watch_msk_width 16 #define watch_msk_height 16 #define watch_msk_x_hot 7 #define watch_msk_y_hot 7 static unsigned char watch_msk_bits[] = { 0xe0, 0x63, 0xf8, 0xef, 0xfc, 0xdf, 0xfe, 0xbf, 0xfe, 0x7f, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x1f, 0xc0, 0x07}; nip2-8.7.1/src/BITMAPS/change.xbm0000644000175000017500000000157213351443023013146 00000000000000#define change_width 32 #define change_height 32 static unsigned char change_bits[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xff, 0xb2, 0x01, 0x0b, 0xd8, 0xb3, 0x01, 0x0d, 0xd8, 0xfe, 0xff, 0xfb, 0xff, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xff, 0x02, 0x1b, 0x8b, 0x0d, 0x03, 0x1b, 0x8d, 0x0d, 0xfe, 0xff, 0xfb, 0xff, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xff, 0xda, 0x00, 0x6b, 0x03, 0xdb, 0x00, 0x6d, 0x03, 0xfe, 0xff, 0xfb, 0xff, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xff, 0x02, 0x1b, 0x8b, 0x0d, 0x03, 0x1b, 0x8d, 0x0d, 0xfe, 0xff, 0xfb, 0xff, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55}; nip2-8.7.1/src/BITMAPS/paint.xpm0000644000175000017500000000111113351443023013037 00000000000000/* XPM */ static char * paint_xpm[] = { /* width height ncolors cpp [x_hot y_hot] */ "16 16 4 1 -1 -1", /* colors */ " s none m none c none", ". s iconColor2 m white c white", "x s iconColor1 m black c black", "a s iconGray2 m gray c #909090909090", /* pixels */ " x..xa", " x..xaa", " x..xa ", " x..xaa ", " x..xa ", " x..xaa ", " x..xa ", " xxxxaa ", " x..xxa ", " x...xxa ", " x..axxa ", " x..axxaa ", " x.axxaa ", " x.axxaa ", " xxxxaaa ", " aaaa "}; nip2-8.7.1/src/BITMAPS/toolbox_open.xpm0000644000175000017500000000105013351443023014435 00000000000000/* XPM */ static char *toolbox_open[]={ "16 16 12 1", ". c None", "b c #000000", "h c #2b1702", "a c #482704", "c c #82683b", "i c #8c4c07", "e c #8e8e8e", "j c #ca6d0a", "# c #cacbcb", "g c #ed800c", "d c #ffc0c0", "f c #ffff00", ".............#..", "...aab..........", ".baacca.........", "aaddccca........", "dddddccca.......", "dddddddaaaaaaaaa", "aadddaaeeecaafga", "gabaaeeeebafffga", "cchhhaaaaaafbggi", "haaijjjjhggfgggi", "..aiijjjaggggggi", "..aiiijjaggggii.", "..aaiijjaggii...", "..baaiijaii.....", "..bbaaaaa.......", "................"}; nip2-8.7.1/src/BITMAPS/book_open.xpm0000644000175000017500000000071213351443023013705 00000000000000/* XPM */ static char * book_open_xpm[] = { "16 16 4 1", " c None s None", ". c black", "X c #808080", "o c white", " ", " .. ", " .Xo. ... ", " .Xoo. ..oo. ", " .Xooo.Xooo... ", " .Xooo.oooo.X. ", " .Xooo.Xooo.X. ", " .Xooo.oooo.X. ", " .Xooo.Xooo.X. ", " .Xooo.oooo.X. ", " .Xoo.Xoo..X. ", " .Xo.o..ooX. ", " .X..XXXXX. ", " ..X....... ", " .. ", " "}; nip2-8.7.1/src/BITMAPS/automatic3.xbm0000644000175000017500000000161413351443023013767 00000000000000#define automatic3_width 32 #define automatic3_height 32 static const unsigned char automatic3_bits[] = { 0x33, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x66, 0x03, 0x00, 0x00, 0x64, 0x06, 0x00, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x08, 0x53, 0x55, 0x55, 0x90, 0xa3, 0xaa, 0xaa, 0x30, 0xc2, 0xff, 0x7f, 0x20, 0xa4, 0x00, 0xa0, 0x40, 0xc8, 0x00, 0x60, 0x80, 0xa8, 0x00, 0xa0, 0x80, 0xd0, 0xe0, 0x67, 0x00, 0xa1, 0x10, 0xa8, 0x00, 0xc2, 0x08, 0x70, 0x00, 0xc4, 0x74, 0xa7, 0x00, 0x84, 0xb5, 0x6b, 0x00, 0x08, 0xf5, 0xab, 0x00, 0x10, 0x66, 0x66, 0x00, 0x30, 0x34, 0xa0, 0x00, 0x20, 0xfc, 0x60, 0x00, 0xe0, 0xcf, 0xb0, 0x00, 0xc0, 0x64, 0x70, 0x00, 0xa0, 0xe4, 0xb1, 0x00, 0xc0, 0xcc, 0x73, 0x00, 0xa0, 0x18, 0xbb, 0x00, 0xc0, 0x10, 0x6c, 0x00, 0xa0, 0xff, 0xbf, 0x00, 0x40, 0x55, 0x55, 0x00, 0xa0, 0xaa, 0xaa}; nip2-8.7.1/src/BITMAPS/automatic.xpm0000644000175000017500000000245013351443023013721 00000000000000/* XPM */ static char *automatic[]={ "32 32 8 1", ". c None", "d c #000000", "b c #585858", "a c #808000", "# c #a0a0a0", "c c #c0c000", "e c #ffc0c0", "f c #ffffff", "................................", "................................", "................................", "......###################.......", "......#aaaaaaaaaaaaaaaaab.......", "......#abbbbbbbbbbbbbb#ab.......", "......#abccccccccccccc#ab.......", "......#abccccccccccccc#ab.......", "......#abccccddddddccc#ab.......", "......#abcccdeeeeeedcc#ab.......", "......#abccdeeeeeeeedc#ab.......", "......#abcdedddedddedc#ab.......", "......#abcdedddddddddc#ab.......", "......#abcdedffddffddc#ab.......", "......#abcdeeddeeddedc#ab.......", "......#abcdeddeeeeeedc#ab.......", "......#abcdeddddeeeedc#ab.......", "......#abcdeeeddeededc#ab.......", "......#abcdeeeeeeddedc#ab.......", "......#abcdeeeeeeddedc#ab.......", "......#abcddedddddeedc#ab.......", "......#abccddeddeeeddc#ab.......", "......#abcccddeeeeddcc#ab.......", "......#abccccdeeedcccc#ab.......", "......#a###############ab.......", "......#aaaaaaaaaaaaaaaaab.......", "......#bbbbbbbbbbbbbbbbbb.......", "................................", "................................", "................................", "................................", "................................"}; nip2-8.7.1/src/BITMAPS/watch_3.xbm0000644000175000017500000000044513351443023013247 00000000000000#define watch_3_width 16 #define watch_3_height 16 static unsigned char watch_3_bits[] = { 0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0x79, 0xcf, 0x79, 0xcf, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf, 0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff}; nip2-8.7.1/src/BITMAPS/tools.xpm0000644000175000017500000000072513351443023013076 00000000000000/* XPM */ static char *tools[]={ "16 16 7 1", ". c None", "# c #000000", "e c #00c0c0", "c c #808080", "a c #a0a0a0", "b c #c0ffff", "d c #c3c3c3", "................", "..........####..", ".........#abc...", ".........#b#..#.", ".........#bd#c#.", "........#bdeee#.", ".......#bde###..", "......#bde#.....", ".....#bde#......", "....#bde#.......", "...#bde#........", "..#bde#.........", ".#bde#..........", "#bee#...........", "#ee#............", ".##............."}; nip2-8.7.1/src/BITMAPS/automatic1.xpm0000644000175000017500000000245113351443023014003 00000000000000/* XPM */ static char *automatic1[]={ "32 32 8 1", ". c None", "# c #000000", "d c #585858", "c c #808000", "b c #a0a0a0", "e c #c0c000", "f c #ffc0c0", "a c #ffffff", "....#a#.........................", "#...#a##........................", "##..#aa#........................", "a####aa##.......................", "aa##aaaa#.......................", "aa#aa##a##......................", "###aa##aa##.....................", "..#aaaaaa###....................", "...#aaaa##aa#bbbbbbbbbbbbbbbbbbb", "....#aa###aa.bcccccccccccccccccd", "....#aaa####abcddddddddddddddbcd", ".....#aaa#.#.bcdeeeeeeeeeeeeebcd", ".....#aaa##.#bcdeeeeeeeeeeeeebcd", "......#aaa#..bcdeeeeeeeeeeeeebcd", ".......#aaa#.bcdeeeee######eebcd", ".......#aaaa#bcdeeee#ffffff#ebcd", "........#aaa#bcdeee#ffffffff#bcd", "........#aaaa#cdee#f###f###ffbcd", ".........#aaa#cdee#f##a###a#fbcd", "..........#aaa#dee#f######a#fbcd", "..........#aaaa#ee#ff##ff##ffbcd", "...........#aaa##e#f##fffffffbcd", "...........#aaaa#e#f####fffffbcd", "............#####e#fff##ffff#bcd", ".............bcdee#ff##fffff#bcd", ".............bcdee#ff####fff#bcd", ".............bcdee##ff####ff#bcd", ".............bcdeee##fff##f##bcd", ".............bcdeeee#fffff##ebcd", ".............bcbbbbbbbbbbbbbbbcd", ".............bcccccccccccccccccd", ".............bdddddddddddddddddd"}; nip2-8.7.1/src/BITMAPS/toolbox_closed.xpm0000644000175000017500000000101413351443023014745 00000000000000/* XPM */ static char *toolbox_closed[]={ "16 16 10 1", ". c None", "a c #000000", "b c #2b1702", "c c #482704", "f c #8c4c07", "h c #ca6d0a", "# c #cacbcb", "d c #ed800c", "g c #ffff00", "e c #ffffff", ".............#..", ".........abcc...", ".......ccabdec..", ".....cccfabeecc.", "...ccccffaddddc.", "..cfffccddddcfc.", ".bfffffcddccgfc.", ".afffffcacgggdc.", ".bbbcccccfgaddf.", ".cfhhhhbffgdddf.", ".cffhhhcddddddf.", ".cfffhhcddddff..", ".ccffhhcddff....", ".accffhcff......", ".aaccccc........", "................"}; nip2-8.7.1/src/BITMAPS/convol.xbm0000644000175000017500000000157213351443023013221 00000000000000#define convol_width 32 #define convol_height 32 static unsigned char convol_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x84, 0x3c, 0xf3, 0x1e, 0xc6, 0xa0, 0x44, 0x02, 0xa4, 0x10, 0x62, 0x0e, 0xe4, 0x09, 0x81, 0x10, 0x84, 0x88, 0x80, 0x10, 0x8e, 0x88, 0x77, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x31, 0x86, 0x08, 0x42, 0x4a, 0xc9, 0x0c, 0x8e, 0x49, 0xa9, 0x08, 0x52, 0x4a, 0xee, 0x09, 0x52, 0x4a, 0x88, 0x08, 0x8c, 0x31, 0x86, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x91, 0x67, 0x0c, 0x92, 0x99, 0x90, 0x12, 0x52, 0x91, 0x43, 0x08, 0xd2, 0x13, 0x24, 0x04, 0x12, 0x11, 0x14, 0x02, 0x0c, 0xb9, 0xf3, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x21, 0xe6, 0x19, 0x48, 0x32, 0x09, 0x25, 0x0c, 0x29, 0x86, 0x10, 0x90, 0x78, 0x49, 0x08, 0x50, 0x20, 0x49, 0x04, 0xce, 0x23, 0x46, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; nip2-8.7.1/src/BITMAPS/program.xbm0000644000175000017500000000157513351443023013373 00000000000000#define program_width 32 #define program_height 32 static unsigned char program_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x30, 0xf8, 0x38, 0x00, 0x28, 0x20, 0x44, 0x7c, 0x24, 0x10, 0x44, 0x00, 0x22, 0x10, 0x44, 0x7c, 0x7e, 0x10, 0x64, 0x01, 0x20, 0x10, 0x98, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x03, 0x40, 0x00, 0x46, 0x04, 0x30, 0x00, 0x04, 0x04, 0x48, 0x7c, 0x04, 0x02, 0x48, 0x00, 0x04, 0x01, 0x30, 0x7c, 0x84, 0x00, 0x08, 0x00, 0x44, 0x00, 0x70, 0x00, 0xce, 0x07, 0x88, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; nip2-8.7.1/src/BITMAPS/morph.xbm0000644000175000017500000000156713351443023013052 00000000000000#define morph_width 32 #define morph_height 32 static unsigned char morph_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x10, 0x07, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xfe, 0x30, 0x00, 0x00, 0xba, 0x28, 0x00, 0x00, 0x12, 0x99, 0x00, 0x00, 0xd6, 0xde, 0x00, 0x00, 0xe0, 0x6d, 0x03, 0x00, 0xb8, 0x10, 0x00, 0x00, 0x7c, 0x07, 0x00, 0x00, 0xce, 0x03, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00, 0xe0, 0x03, 0xe6, 0x00, 0xf0, 0x07, 0xfe, 0x00, 0xf8, 0x0f, 0xfc, 0x01, 0x60, 0x13, 0xf0, 0x03, 0x60, 0x33, 0xfc, 0x07, 0x60, 0x7e, 0xfe, 0x3f, 0xe0, 0xfe, 0xfe, 0x7f, 0xc0, 0xf1, 0xff, 0x7f, 0xc0, 0xff, 0xfe, 0x7f, 0x00, 0x7f, 0xfa, 0xff, 0x00, 0x30, 0xfc, 0xff, 0x00, 0x10, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0x33, 0x00, 0x00, 0x87, 0x01}; nip2-8.7.1/src/BITMAPS/magout_src.xbm0000644000175000017500000000045613351443023014064 00000000000000#define magout_src_width 16 #define magout_src_height 16 static unsigned char magout_src_bits[] = { 0x00, 0x00, 0xf0, 0x00, 0xfc, 0x03, 0xfc, 0x03, 0xfe, 0x07, 0x06, 0x06, 0x06, 0x06, 0xfe, 0x07, 0xfc, 0x03, 0xfc, 0x03, 0xf0, 0x08, 0x00, 0x14, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00}; nip2-8.7.1/src/BITMAPS/mag_msk.xbm0000644000175000017500000000044513351443023013335 00000000000000#define mag_msk_width 16 #define mag_msk_height 16 static unsigned char mag_msk_bits[] = { 0xf0, 0x00, 0xfc, 0x03, 0xfe, 0x07, 0xfe, 0x07, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0xfe, 0x07, 0xfe, 0x0f, 0xfc, 0x1f, 0xf0, 0x3e, 0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0xe0}; nip2-8.7.1/src/BITMAPS/col.xpm0000644000175000017500000000074213351443023012512 00000000000000/* XPM */ static char *col[]={ "16 16 8 1", ". c None", "# c #000000", "f c #303030", "e c #585858", "b c #808080", "d c #a0a0a0", "c c #c3c3c3", "a c #ffffff", "....#aaaaaaaaaa#", "....#aaaaaaaaaa#", "....############", "......#bca#bc#..", "......#bca#bc#..", "......#bca#bc#..", "......#bca#bc#..", "d.....#bca#bc#..", "ddd...#bca#bc#..", "eedd..#bca#bc#..", "eeeddd#bca#bc#..", "eeeeee#bca#bc#..", "ffeeee#bca#bc#..", "#ffe############", "##ff#aaaaaaaaaa#", "###f#aaaaaaaaaa#"}; nip2-8.7.1/src/BITMAPS/watch_4.xbm0000644000175000017500000000044513351443023013250 00000000000000#define watch_4_width 16 #define watch_4_height 16 static unsigned char watch_4_bits[] = { 0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcb, 0xfc, 0x9d, 0xfc, 0x9e, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf, 0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff}; nip2-8.7.1/src/BITMAPS/floppy.xpm0000644000175000017500000000100413351443023013236 00000000000000/* XPM */ static char *floppy[]={ "16 16 10 1", ". c None", "# c #000000", "e c #000080", "c c #0000c0", "a c #0000ff", "b c #303030", "g c #808080", "h c #a0a0a4", "f c #c0c0c0", "d c #ffffff", "................", ".......#........", "......#ab#......", ".....#acdd##....", "....#acddddd##..", "...#acdddddddc##", "..#aeaacddddcae#", ".#aefeeaacdcae#.", "#aefaffeeacae#..", "#egfffhaaeae#...", ".##g.haaeae#....", "...##gaeae#.....", ".....##ee#......", ".......##.......", "................", "................"}; nip2-8.7.1/src/BITMAPS/slider.xbm0000644000175000017500000000157213351443023013203 00000000000000#define slider_width 32 #define slider_height 32 static unsigned char slider_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x3f, 0x04, 0x36, 0x00, 0x20, 0x04, 0x36, 0x00, 0x20, 0xfc, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; nip2-8.7.1/src/BITMAPS/watch_5.xbm0000644000175000017500000000044513351443023013251 00000000000000#define watch_5_width 16 #define watch_5_height 16 static unsigned char watch_5_bits[] = { 0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f, 0xfc, 0x9f, 0x7c, 0x90, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf, 0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff}; nip2-8.7.1/src/BITMAPS/dropper_msk.xbm0000644000175000017500000000046113351443023014242 00000000000000#define dropper_msk_width 16 #define dropper_msk_height 16 static unsigned char dropper_msk_bits[] = { 0x00, 0x3c, 0x00, 0x7e, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x80, 0xff, 0x80, 0x7f, 0xc0, 0x07, 0xe0, 0x07, 0xf0, 0x01, 0xf8, 0x00, 0x7c, 0x00, 0x3e, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x03, 0x00}; nip2-8.7.1/src/BITMAPS/automatic1.xbm0000644000175000017500000000161413351443023013765 00000000000000#define automatic1_width 32 #define automatic1_height 32 static const unsigned char automatic1_bits[] = { 0x50, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x64, 0x03, 0x00, 0x00, 0x67, 0x06, 0x00, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x08, 0x53, 0x55, 0x55, 0x90, 0xa3, 0xaa, 0xaa, 0x10, 0xcf, 0xff, 0x7f, 0x20, 0xaa, 0x00, 0xa0, 0x20, 0xd6, 0x00, 0x60, 0x40, 0xa4, 0x00, 0xa0, 0x80, 0xc8, 0xe0, 0x67, 0x80, 0xb0, 0x10, 0xa8, 0x00, 0xd1, 0x08, 0x70, 0x00, 0xa1, 0x74, 0xa7, 0x00, 0xa2, 0xb4, 0x6b, 0x00, 0xc4, 0xf4, 0xab, 0x00, 0x84, 0x64, 0x66, 0x00, 0x88, 0x35, 0xa0, 0x00, 0x08, 0xf5, 0x60, 0x00, 0xf0, 0xc7, 0xb0, 0x00, 0xc0, 0x64, 0x70, 0x00, 0xa0, 0xe4, 0xb1, 0x00, 0xc0, 0xcc, 0x73, 0x00, 0xa0, 0x18, 0xbb, 0x00, 0xc0, 0x10, 0x6c, 0x00, 0xa0, 0xff, 0xbf, 0x00, 0x40, 0x55, 0x55, 0x00, 0xa0, 0xaa, 0xaa}; nip2-8.7.1/src/BITMAPS/kill.xbm0000644000175000017500000000043413351443023012650 00000000000000#define kill_width 16 #define kill_height 16 static unsigned char kill_bits[] = { 0x04, 0xc0, 0x0a, 0xe0, 0x16, 0x70, 0x2e, 0xb8, 0x5c, 0x5c, 0xb8, 0x2e, 0x70, 0x17, 0xe0, 0x0a, 0xc0, 0x05, 0xe0, 0x0a, 0x70, 0x17, 0xb8, 0x2e, 0x5c, 0x5c, 0x2e, 0xb8, 0x16, 0x70, 0x0a, 0xe0}; nip2-8.7.1/src/BITMAPS/watch_6.xbm0000644000175000017500000000044513351443023013252 00000000000000#define watch_6_width 16 #define watch_6_height 16 static unsigned char watch_6_bits[] = { 0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f, 0xfc, 0x9f, 0x7c, 0x9f, 0x7c, 0x9e, 0x7c, 0x9d, 0x79, 0xcb, 0x79, 0xcf, 0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff}; nip2-8.7.1/src/BITMAPS/image.xbm0000644000175000017500000000157513351443023013006 00000000000000#define program_width 32 #define program_height 32 static unsigned char program_bits[] = { 0x55, 0x55, 0x55, 0x55, 0xfe, 0xff, 0xff, 0xff, 0x03, 0x10, 0x00, 0x40, 0x02, 0x18, 0x00, 0xc0, 0x03, 0x08, 0x00, 0x40, 0x02, 0x00, 0x38, 0xc0, 0x03, 0x1c, 0xcc, 0x40, 0x02, 0x34, 0xc4, 0xc0, 0x03, 0xa0, 0x00, 0x40, 0x02, 0x90, 0x78, 0xc0, 0x03, 0x90, 0x5c, 0x40, 0x02, 0xc0, 0x18, 0xc0, 0x03, 0x20, 0x00, 0x40, 0x02, 0x30, 0x00, 0xc0, 0x03, 0x10, 0x00, 0x40, 0x02, 0x18, 0x06, 0xc0, 0x03, 0x08, 0x0c, 0x40, 0x02, 0xd0, 0x08, 0xc0, 0x03, 0xb0, 0x0f, 0x40, 0x02, 0x00, 0x00, 0xc0, 0x03, 0x80, 0x00, 0x40, 0x02, 0xc0, 0x01, 0xc0, 0x03, 0x80, 0x7f, 0x40, 0x02, 0x00, 0x39, 0xc0, 0x03, 0x00, 0x00, 0x40, 0x02, 0x00, 0x01, 0xe0, 0x03, 0x00, 0x1f, 0x60, 0x02, 0x00, 0x1c, 0xf0, 0x03, 0x00, 0x30, 0x58, 0x02, 0x00, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0xaa, 0xaa, 0xaa, 0xaa}; nip2-8.7.1/src/BITMAPS/automatic.xbm0000644000175000017500000000161113351443023013701 00000000000000#define automatic_width 32 #define automatic_height 32 static const unsigned char automatic_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0x00, 0x40, 0x55, 0x55, 0x01, 0x80, 0xff, 0xff, 0x00, 0x40, 0x01, 0x40, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x40, 0xe1, 0x47, 0x01, 0x80, 0x11, 0xc8, 0x00, 0x40, 0x09, 0x50, 0x01, 0x80, 0x75, 0xd7, 0x00, 0x40, 0xf5, 0x5f, 0x01, 0x80, 0x95, 0xd9, 0x00, 0x40, 0x65, 0x56, 0x01, 0x80, 0x35, 0xd0, 0x00, 0x40, 0xf5, 0x50, 0x01, 0x80, 0xc5, 0xd4, 0x00, 0x40, 0x05, 0x56, 0x01, 0x80, 0x05, 0xd6, 0x00, 0x40, 0xed, 0x53, 0x01, 0x80, 0xd9, 0xd8, 0x00, 0x40, 0x31, 0x4c, 0x01, 0x80, 0x21, 0xc2, 0x00, 0x40, 0xff, 0x7f, 0x01, 0x80, 0xaa, 0xaa, 0x00, 0x40, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; nip2-8.7.1/src/BITMAPS/automatic2.xpm0000644000175000017500000000245113351443023014004 00000000000000/* XPM */ static char *automatic2[]={ "32 32 8 1", ". c None", "# c #000000", "d c #585858", "c c #808000", "b c #a0a0a0", "e c #c0c000", "f c #ffc0c0", "a c #ffffff", ".....#a#........................", "....#aa#........................", "#...#aa#........................", "a####aa##.......................", "aa##aaaa##......................", "aa#aa##a####....................", "aa#aa##aa#aa#...................", "###aaaaaa#aa###.................", "..##aaaa##aaabbbbbbbbbbbbbbbbbbb", "...#aaa#.##aabcccccccccccccccccd", "....#aaa#..#abcddddddddddddddbcd", "....#aaaa#..#bcdeeeeeeeeeeeeebcd", ".....#aaa#...bcdeeeeeeeeeeeeebcd", ".....#aaaa#..bcdeeeeeeeeeeeeebcd", "......#aaa#..bcdeeeee######eebcd", "......#aaaa#.bcdeeee#ffffff#ebcd", ".......#aaa#.bcdeee#ffffffff#bcd", ".......#aaaa#bcdee#f###f###ffbcd", "........#aaa#bcdee#f##a###a#fbcd", "........#aaaa#cdee#f######a#fbcd", ".........#aaa#cdee#ff##ff##ffbcd", ".........#aaaa#dee#f##fffffffbcd", "..........#aaa#dee#f####fffffbcd", "..........#aaa#dee#fff##ffff#bcd", "...........####dee#ff##fffff#bcd", ".............bcdee#ff####fff#bcd", ".............bcdee##ff####ff#bcd", ".............bcdeee##fff##f##bcd", ".............bcdeeee#fffff##ebcd", ".............bcbbbbbbbbbbbbbbbcd", ".............bcccccccccccccccccd", ".............bdddddddddddddddddd"}; nip2-8.7.1/src/BITMAPS/watch_1.xbm0000644000175000017500000000044513351443023013245 00000000000000#define watch_1_width 16 #define watch_1_height 16 static unsigned char watch_1_bits[] = { 0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f, 0xfc, 0x9f, 0x04, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf, 0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff}; nip2-8.7.1/src/BITMAPS/magin.xpm0000644000175000017500000000111213351443023013020 00000000000000/* XPM */ static char * magin_xpm[] = { /* width height ncolors cpp [x_hot y_hot] */ "16 16 4 1 -1 -1", /* colors */ " s none m none c none", ". s iconColor1 m black c black", "X s iconColor2 m white c white", "o s iconGray1 m white c #dededededede", /* pixels */ " .... ", " ..XXXX.. ", " .XXXXXXXX. ", " .XXX..XXX. ", ".XXXX..XXXX. ", ".XX......XX.o ", ".XX......XX.o ", ".XXXX..XXXX.o ", " .XXX..XXX.o ", " .XXXXXXXX..o ", " ..XXXX...X. ", " ....o.X.X. ", " ooo o...X. ", " ...X.", " ...X", " ..."}; nip2-8.7.1/src/BITMAPS/book_closed.xpm0000644000175000017500000000075713351443023014226 00000000000000/* XPM */ static char * book_closed_xpm[] = { "16 16 6 1", " c None s None", ". c black", "X c red", "o c yellow", "O c #808080", "# c white", " ", " .. ", " ..XX. ", " ..XXXXX. ", " ..XXXXXXXX. ", ".ooXXXXXXXXX. ", "..ooXXXXXXXXX. ", ".X.ooXXXXXXXXX. ", ".XX.ooXXXXXX.. ", " .XX.ooXXX..#O ", " .XX.oo..##OO. ", " .XX..##OO.. ", " .X.#OO.. ", " ..O.. ", " .. ", " "}; nip2-8.7.1/src/BITMAPS/ant.xbm0000644000175000017500000000632113351443023012500 00000000000000#define ant_width 64 #define ant_height 64 static unsigned char ant_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x6a, 0x77, 0x77, 0xef, 0xfe, 0x5b, 0x55, 0x55, 0xb5, 0xad, 0xad, 0xb5, 0x6b, 0x17, 0xaa, 0x6a, 0x6b, 0xdb, 0x76, 0xdf, 0xde, 0x3d, 0xaa, 0x56, 0xd5, 0xb6, 0xad, 0xf5, 0x75, 0x57, 0x55, 0xd5, 0x2a, 0xd5, 0xf6, 0x5e, 0xdf, 0x2d, 0xaa, 0xad, 0xa4, 0x54, 0xad, 0xfb, 0x75, 0x3f, 0x55, 0x5b, 0x4a, 0x49, 0xdb, 0xae, 0xdf, 0x75, 0xaa, 0xaa, 0x28, 0x92, 0x74, 0xf7, 0xf6, 0x5f, 0xd5, 0x16, 0x45, 0x55, 0xad, 0xbd, 0x5b, 0x3b, 0xba, 0xaa, 0xa8, 0x88, 0xe8, 0xef, 0xfe, 0x2f, 0xa5, 0x45, 0x05, 0x25, 0x55, 0xbd, 0xab, 0x6a, 0x5d, 0x29, 0xaa, 0x48, 0xd2, 0xeb, 0xfe, 0x2d, 0x55, 0x42, 0x91, 0x92, 0x54, 0xbf, 0x95, 0x2a, 0xd5, 0x14, 0x24, 0x25, 0xa5, 0x6a, 0xb7, 0x56, 0x35, 0xa1, 0x42, 0x4a, 0xaa, 0xdf, 0xad, 0x2a, 0xad, 0x14, 0x94, 0x90, 0x54, 0x7a, 0x55, 0x55, 0x55, 0xa0, 0x22, 0x25, 0xd1, 0xaf, 0xa5, 0x2a, 0x55, 0x05, 0x48, 0x4a, 0x2a, 0xbd, 0xaa, 0x2a, 0x2a, 0xa8, 0x92, 0x90, 0xca, 0xaa, 0x54, 0x55, 0xad, 0x02, 0x44, 0x4a, 0xb2, 0x5e, 0x55, 0x2a, 0x2a, 0xa8, 0x90, 0x24, 0xa5, 0xb5, 0xaa, 0x52, 0x95, 0x04, 0x0a, 0x91, 0x28, 0xad, 0x4a, 0x55, 0x16, 0x42, 0x20, 0x42, 0xaa, 0xaa, 0x52, 0x6a, 0x55, 0x08, 0x82, 0x94, 0xaa, 0x7a, 0x55, 0x35, 0x0a, 0x91, 0x10, 0x20, 0x49, 0xa5, 0xaa, 0x6a, 0x55, 0x04, 0x40, 0x55, 0xaa, 0x7a, 0x91, 0x3a, 0x0d, 0x51, 0x02, 0x80, 0x4a, 0x65, 0x55, 0x55, 0x55, 0x04, 0x48, 0xaa, 0x54, 0xda, 0xaa, 0x3a, 0x0a, 0x91, 0x00, 0x11, 0xa9, 0x6a, 0xa9, 0x16, 0x55, 0x44, 0x52, 0xa4, 0x52, 0xd5, 0x52, 0x35, 0x8a, 0x10, 0x08, 0x29, 0x95, 0xaa, 0xaa, 0x4a, 0x55, 0x4a, 0xa1, 0x52, 0x6a, 0xad, 0x55, 0x1d, 0x95, 0x24, 0x0a, 0x85, 0xaa, 0x56, 0x55, 0x23, 0x15, 0x91, 0x54, 0x69, 0x79, 0x4b, 0x55, 0x2d, 0x6b, 0x4a, 0x51, 0x4a, 0xca, 0x92, 0xaa, 0x52, 0x96, 0x24, 0x95, 0xaa, 0xb5, 0xa4, 0x92, 0x15, 0x55, 0x49, 0xaa, 0xb4, 0x2a, 0x09, 0x25, 0x25, 0xad, 0x92, 0x12, 0xd5, 0x55, 0x52, 0x92, 0x54, 0x5b, 0xa4, 0xa4, 0xba, 0xa2, 0x84, 0x4a, 0x55, 0xaa, 0x55, 0x49, 0x6a, 0x95, 0x52, 0x11, 0x2a, 0xbb, 0x12, 0x92, 0xaa, 0x24, 0x25, 0xa6, 0x24, 0x56, 0xd5, 0xa4, 0xf2, 0x49, 0x45, 0x29, 0x29, 0xed, 0x2a, 0xa9, 0xb6, 0x52, 0x5b, 0x4b, 0x2a, 0x5b, 0x55, 0x45, 0x29, 0xd4, 0xaa, 0x54, 0x55, 0xb6, 0xab, 0x2a, 0xaa, 0x55, 0x55, 0x95, 0x2a, 0xd5, 0xde, 0x4a, 0x21, 0x48, 0xaa, 0x52, 0x25, 0xad, 0xaa, 0x55, 0x4a, 0x95, 0xad, 0xaa, 0x6a, 0xdb, 0xb6, 0x96, 0x24, 0x62, 0x6b, 0x95, 0x54, 0xaa, 0x6d, 0x55, 0x49, 0x59, 0xda, 0xaa, 0x2a, 0x6d, 0xb5, 0x57, 0x12, 0x52, 0xa7, 0x56, 0x55, 0xd5, 0x6a, 0xad, 0xa2, 0x94, 0x68, 0x55, 0x35, 0xad, 0x57, 0xb5, 0x14, 0x55, 0xaa, 0x55, 0x6b, 0xb5, 0xac, 0xaa, 0xa2, 0x24, 0x75, 0xd5, 0x36, 0x6d, 0xab, 0x54, 0x15, 0xa9, 0xac, 0xad, 0x6a, 0xaa, 0xaa, 0x4a, 0x4a, 0x55, 0xdb, 0x5a, 0x5d, 0x55, 0x15, 0x14, 0x54, 0x55, 0xb5, 0xd7, 0x36, 0xaa, 0x4a, 0x85, 0xa2, 0xaa, 0x7f, 0x55, 0x6b, 0x55, 0x91, 0x02, 0x54, 0x7d, 0xd5, 0x6a, 0x37, 0xaa, 0x4a, 0x4a, 0x48, 0xa5, 0x7f, 0x5b, 0x6d, 0x55, 0xa4, 0x02, 0x92, 0xea, 0xea, 0x56, 0x2b, 0x92, 0x12, 0x01, 0x40, 0xa8, 0xbd, 0x55, 0x55, 0x2a, 0xa4, 0x0a, 0x12, 0x45, 0xd7, 0xb5, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; nip2-8.7.1/src/BITMAPS/watch_8.xbm0000644000175000017500000000044513351443023013254 00000000000000#define watch_8_width 16 #define watch_8_height 16 static unsigned char watch_8_bits[] = { 0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f, 0xfc, 0x9f, 0x7c, 0x9f, 0x3c, 0x9f, 0x5c, 0x9f, 0x69, 0xcf, 0x79, 0xcf, 0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff}; nip2-8.7.1/src/BITMAPS/watch_2.xbm0000644000175000017500000000044513351443023013246 00000000000000#define watch_2_width 16 #define watch_2_height 16 static unsigned char watch_2_bits[] = { 0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xe9, 0xcf, 0xdc, 0x9f, 0xbc, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf, 0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff}; nip2-8.7.1/src/BITMAPS/automatic3.xpm0000644000175000017500000000245113351443023014005 00000000000000/* XPM */ static char *automatic3[]={ "32 32 8 1", "a c None", ". c #000000", "d c #585858", "c c #808000", "b c #a0a0a0", "e c #c0c000", "f c #ffc0c0", "# c #ffffff", "..##..aaaaaaaaaaaaaaaaaaaaaaaaaa", "#..###..aaaaaaaaaaaaaaaaaaaaaaaa", "##...##.aaaaaaaaaaaaaaaaaaaaaaaa", "##...##..aaaaaaaaaaaaaaaaaaaaaaa", ".#..####.aaaaaaaaaaaaaaaaaaaaaaa", "a..##..#..aaaaaaaaaaaaaaaaaaaaaa", "aa.##..##..aaaaaaaaaaaaaaaaaaaaa", "aa.######...aaaaaaaaaaaaaaaaaaaa", "aaa.####..##.bbbbbbbbbbbbbbbbbbb", "aaaa.##...###bcccccccccccccccccd", "aaaa..###.###bcddddddddddddddbcd", "aaaaa.####.##bcdeeeeeeeeeeeeebcd", "aaaaaa.####.#bcdeeeeeeeeeeeeebcd", "aaaaaaa.###.#bcdeeeeeeeeeeeeebcd", "aaaaaaa.####.bcdeeeee......eebcd", "aaaaaaaa.####.cdeeee.ffffff.ebcd", "aaaaaaaaa.####.deee.ffffffff.bcd", "aaaaaaaaaa.###.dee.f...f...ffbcd", "aaaaaaaaaa.####..e.f..#...#.fbcd", "aaaaaaaaaaa.####.e.f......#.fbcd", "aaaaaaaaaaaa.####..ff..ff..ffbcd", "aaaaaaaaaaaaa.####.f..fffffffbcd", "aaaaaaaaaaaaab.###......fffffbcd", "aaaaaaaaaaaaabc.....ff..ffff.bcd", "aaaaaaaaaaaaabcdee.ff..fffff.bcd", "aaaaaaaaaaaaabcdee.ff....fff.bcd", "aaaaaaaaaaaaabcdee..ff....ff.bcd", "aaaaaaaaaaaaabcdeee..fff..f..bcd", "aaaaaaaaaaaaabcdeeee.fffff..ebcd", "aaaaaaaaaaaaabcbbbbbbbbbbbbbbbcd", "aaaaaaaaaaaaabcccccccccccccccccd", "aaaaaaaaaaaaabdddddddddddddddddd"}; nip2-8.7.1/src/BITMAPS/select.xpm0000644000175000017500000000116413351443023013213 00000000000000/* XPM */ static char * select_xpm[] = { /* width height ncolors cpp [x_hot y_hot] */ "16 16 5 1 -1 -1", /* colors */ " s iconColor2 m white c white", ". s iconColor1 m black c black", "X s iconGray2 m white c #bdbdbdbdbdbd", "o s none m none c none", "O s iconGray3 m white c #adadadadadad", /* pixels */ " .", " XXXXXXXXXXXXXX.", " X............X.", " X. .ooo X.", " X. OOOOO.ooo X.", " X. OX.XO.ooo X.", " X. O...O.ooo X.", " X. O.X.O.ooo X.", " X. OOOOO.ooo X.", " X........ooo X.", " X.oooooooooo X.", " X.oooooooooo X.", " X.oooooooooo X.", " X. X.", " XXXXXXXXXXXXXX.", "................"}; nip2-8.7.1/src/BITMAPS/Makefile.am0000644000175000017500000000131513351443023013240 00000000000000EXTRA_DIST = \ ant.xbm \ automatic.xbm \ automatic.xpm \ automatic1.xbm \ automatic1.xpm \ automatic2.xbm \ automatic2.xpm \ automatic3.xbm \ automatic3.xpm \ change.xbm \ convol.xbm \ dropper.xpm \ dropper_msk.xbm \ dropper_src.xbm \ image.xbm \ kill.xbm \ mag_msk.xbm \ magin.xpm \ magin_src.xbm \ magout.xpm \ magout_src.xbm \ morph.xbm \ pan.xpm \ paint.xpm \ program.xbm \ select.xpm \ slider.xbm \ watch_1.xbm \ watch_2.xbm \ watch_3.xbm \ watch_4.xbm \ watch_5.xbm \ watch_6.xbm \ watch_7.xbm \ watch_8.xbm \ watch_msk.xbm \ book_open.xpm \ book_closed.xpm \ toolbox_open.xpm \ toolbox_closed.xpm \ tools.xpm \ col.xpm \ separator.xpm \ floppy.xpm \ mini_page.xpm nip2-8.7.1/src/BITMAPS/magout.xpm0000644000175000017500000000111313351443023013222 00000000000000/* XPM */ static char * magout_xpm[] = { /* width height ncolors cpp [x_hot y_hot] */ "16 16 4 1 -1 -1", /* colors */ " s none m none c none", ". s iconColor1 m black c black", "X s iconColor2 m white c white", "o s iconGray1 m white c #dededededede", /* pixels */ " .... ", " ..XXXX.. ", " .XXXXXXXX. ", " .XXXXXXXX. ", ".XXXXXXXXXX. ", ".XX......XX.o ", ".XX......XX.o ", ".XXXXXXXXXX.o ", " .XXXXXXXX.o ", " .XXXXXXXX..o ", " ..XXXX...X. ", " ....o.X.X. ", " ooo o...X. ", " ...X.", " ...X", " ..."}; nip2-8.7.1/src/BITMAPS/Makefile.in0000644000175000017500000003335413417043242013263 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = src/BITMAPS ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = 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 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ EXTRA_DIST = \ ant.xbm \ automatic.xbm \ automatic.xpm \ automatic1.xbm \ automatic1.xpm \ automatic2.xbm \ automatic2.xpm \ automatic3.xbm \ automatic3.xpm \ change.xbm \ convol.xbm \ dropper.xpm \ dropper_msk.xbm \ dropper_src.xbm \ image.xbm \ kill.xbm \ mag_msk.xbm \ magin.xpm \ magin_src.xbm \ magout.xpm \ magout_src.xbm \ morph.xbm \ pan.xpm \ paint.xpm \ program.xbm \ select.xpm \ slider.xbm \ watch_1.xbm \ watch_2.xbm \ watch_3.xbm \ watch_4.xbm \ watch_5.xbm \ watch_6.xbm \ watch_7.xbm \ watch_8.xbm \ watch_msk.xbm \ book_open.xpm \ book_closed.xpm \ toolbox_open.xpm \ toolbox_closed.xpm \ tools.xpm \ col.xpm \ separator.xpm \ floppy.xpm \ mini_page.xpm all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/BITMAPS/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/BITMAPS/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am check: check-am all-am: Makefile installdirs: 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: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am 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-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PRECIOUS: Makefile # 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: nip2-8.7.1/src/BITMAPS/automatic2.xbm0000644000175000017500000000161413351443023013766 00000000000000#define automatic2_width 32 #define automatic2_height 32 static const unsigned char automatic2_bits[] = { 0xe0, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x64, 0x0f, 0x00, 0x00, 0x64, 0x12, 0x00, 0x00, 0x07, 0x72, 0x00, 0x00, 0x0c, 0x43, 0x55, 0x55, 0x88, 0xa6, 0xaa, 0xaa, 0x10, 0xc9, 0xff, 0x7f, 0x10, 0xb2, 0x00, 0xa0, 0x20, 0xc2, 0x00, 0x60, 0x20, 0xa4, 0x00, 0xa0, 0x40, 0xc4, 0xe0, 0x67, 0x40, 0xa8, 0x10, 0xa8, 0x80, 0xc8, 0x08, 0x70, 0x80, 0xb0, 0x74, 0xa7, 0x00, 0xd1, 0xb4, 0x6b, 0x00, 0xa1, 0xf4, 0xab, 0x00, 0xe2, 0x64, 0x66, 0x00, 0xc2, 0x34, 0xa0, 0x00, 0xc4, 0xf4, 0x60, 0x00, 0xc4, 0xc4, 0xb0, 0x00, 0xf8, 0x64, 0x70, 0x00, 0xa0, 0xe4, 0xb1, 0x00, 0xc0, 0xcc, 0x73, 0x00, 0xa0, 0x18, 0xbb, 0x00, 0xc0, 0x10, 0x6c, 0x00, 0xa0, 0xff, 0xbf, 0x00, 0x40, 0x55, 0x55, 0x00, 0xa0, 0xaa, 0xaa}; nip2-8.7.1/src/BITMAPS/watch_7.xbm0000644000175000017500000000044513351443023013253 00000000000000#define watch_7_width 16 #define watch_7_height 16 static unsigned char watch_7_bits[] = { 0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f, 0xfc, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf, 0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff}; nip2-8.7.1/src/BITMAPS/magin_src.xbm0000644000175000017500000000045313351443023013660 00000000000000#define magin_src_width 16 #define magin_src_height 16 static unsigned char magin_src_bits[] = { 0x00, 0x00, 0xf0, 0x00, 0xfc, 0x03, 0x9c, 0x03, 0x9e, 0x07, 0x06, 0x06, 0x06, 0x06, 0x9e, 0x07, 0x9c, 0x03, 0xfc, 0x03, 0xf0, 0x08, 0x00, 0x14, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00}; nip2-8.7.1/src/BITMAPS/pan.xpm0000644000175000017500000000102213351443023012503 00000000000000/* XPM */ static char * pan_xpm[] = { /* width height ncolors cpp [x_hot y_hot] */ "16 16 3 1 -1 -1", /* colors */ " s none m none c none", ". s iconColor1 m black c black", "X c #929292929292", /* pixels */ " . ", " ... ", " ..... ", " .XXX ", " .X ", " . .X . ", " .. .X .. ", "............... ", " ..XXXX.XXXX..XX", " .X .X .XX ", " X .X X ", " .X ", " ..... ", " ...X ", " .X ", " X "}; nip2-8.7.1/src/BITMAPS/dropper_src.xbm0000644000175000017500000000046113351443023014237 00000000000000#define dropper_src_width 16 #define dropper_src_height 16 static unsigned char dropper_src_bits[] = { 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x40, 0x03, 0xa0, 0x03, 0xd0, 0x01, 0xe8, 0x00, 0x74, 0x00, 0x3a, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x03, 0x00}; nip2-8.7.1/src/BITMAPS/dropper.xpm0000644000175000017500000000111313351443023013401 00000000000000/* XPM */ static char * dropper_xpm[] = { /* width height ncolors cpp [x_hot y_hot] */ "16 16 4 1 -1 -1", /* colors */ " s none m none c none", ". s iconColor1 m black c black", "X s iconColor2 m white c white", "o s iconGray2 m gray c #909090909090", /* pixels */ " ... ", " .XX... ", " .X.... ", " .......", " .......", " .........", " XX......o", " X.XX.oooo ", " X.XXX.o ", " X.XXXooo ", " X.XXXo ", " X.XXXo ", " X.XXXo ", " XXXXo ", "XXXXo ", "XXoo "}; nip2-8.7.1/src/managedgobject.h0000644000175000017500000000336213351443023013214 00000000000000/* a managed gobject */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_MANAGEDGOBJECT (managedgobject_get_type()) #define MANAGEDGOBJECT( obj ) \ (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGEDGOBJECT, Managedgobject )) #define MANAGEDGOBJECT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_CAST( (klass), \ TYPE_MANAGEDGOBJECT, ManagedgobjectClass)) #define IS_MANAGEDGOBJECT( obj ) \ (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGEDGOBJECT )) #define IS_MANAGEDGOBJECT_CLASS( klass ) \ (G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGEDGOBJECT )) #define MANAGEDGOBJECT_GET_CLASS( obj ) \ (G_TYPE_INSTANCE_GET_CLASS( (obj), \ TYPE_MANAGEDGOBJECT, ManagedgobjectClass )) struct _Managedgobject { Managed parent_object; GObject *object; }; typedef struct _ManagedgobjectClass { ManagedClass parent_class; } ManagedgobjectClass; GType managedgobject_get_type( void ); Managedgobject *managedgobject_new( Heap *heap, GObject *value ); nip2-8.7.1/src/expression.h0000644000175000017500000000324713351443023012463 00000000000000/* an editable expression in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_EXPRESSION (expression_get_type()) #define EXPRESSION( obj ) (GTK_CHECK_CAST( (obj), TYPE_EXPRESSION, Expression )) #define EXPRESSION_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_EXPRESSION, ExpressionClass )) #define IS_EXPRESSION( obj ) (GTK_CHECK_TYPE( (obj), TYPE_EXPRESSION )) #define IS_EXPRESSION_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_EXPRESSION )) struct _Expression { Classmodel parent_class; /* We don't have a model for the expression: instead we just grab the * value/formula from our MEMBER_VALUE itext. Much simpler. */ }; typedef struct _ExpressionClass { ClassmodelClass parent_class; /* My methods. */ } ExpressionClass; GType expression_get_type( void ); iText *expression_get_itext( Expression *expression ); nip2-8.7.1/src/gtkutil.c0000644000175000017500000007157013351443023011746 00000000000000/* gtkutil functions. */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #include "ip.h" /* #define DEBUG */ /* All our tooltips. */ static GtkTooltips *our_tooltips = NULL; /* Set two adjustments together. */ void adjustments_set_value( GtkAdjustment *hadj, GtkAdjustment *vadj, float hval, float vval ) { gboolean hchanged = FALSE; gboolean vchanged = FALSE; if( hval != hadj->value ) { hadj->value = hval; hchanged = TRUE; } if( vval != vadj->value ) { vadj->value = vval; vchanged = TRUE; } #ifdef DEBUG if( hchanged ) printf( "adjustments_set_value: hadj = %g\n", hval ); if( vchanged ) printf( "adjustments_set_value: vadj = %g\n", vval ); #endif /*DEBUG*/ if( hchanged ) gtk_adjustment_value_changed( hadj ); if( vchanged ) gtk_adjustment_value_changed( vadj ); } void * object_destroy( void *obj ) { gtk_object_destroy( GTK_OBJECT( obj ) ); return( NULL ); } /* Like g_free, but return NULL for list maps. */ void * null_g_free( void *obj ) { g_free( obj ); return( NULL ); } /* Set visible/not. */ void widget_visible( GtkWidget *widget, gboolean visible ) { if( widget && visible ) gtk_widget_show( widget ); else if( widget && !visible ) gtk_widget_hide( widget ); } /* Make a button widget. */ GtkWidget * build_button( const char *stock_id, GtkSignalFunc cb, gpointer user ) { GtkWidget *but; but = gtk_button_new_from_stock( stock_id ); GTK_WIDGET_SET_FLAGS( but, GTK_CAN_DEFAULT ); gtk_signal_connect( GTK_OBJECT( but ), "clicked", cb, user ); return( but ); } /* Calculate the bounding box for a string rendered with a widget's default * font. Set geo to a rect with 0,0 positioned on the left-hand baseline. */ void get_geo( GtkWidget *widget, const char *text, Rect *geo ) { PangoLayout *layout; int width, height; layout = gtk_widget_create_pango_layout( widget, text ); pango_layout_get_pixel_size( layout, &width, &height ); g_object_unref( layout ); /* FIXME ... we left/top to 0 for now. */ geo->width = width; geo->height = height; geo->left = 0; geo->top = 0; } /* Set a widget to a fixed size ... width in characters. */ void set_fixed( GtkWidget *widget, int nchars ) { Rect geo; get_geo( widget, "8", &geo ); gtk_widget_set_size_request( widget, geo.width * nchars, geo.height ); } /* Build a GtkEntry, with a widget width specified in characters. */ GtkWidget * build_entry( int nchars ) { GtkWidget *entry; entry = gtk_entry_new(); gtk_entry_set_width_chars( GTK_ENTRY( entry ), nchars ); return( entry ); } /* Build a new menu. */ GtkWidget * menu_build( const char *name ) { GtkWidget *menu; menu = gtk_menu_new(); gtk_menu_set_title( GTK_MENU( menu ), name ); return( menu ); } /* Add a menu item. */ GtkWidget * menu_add_but( GtkWidget *menu, const char *stock_id, GtkSignalFunc cb, void *user ) { GtkWidget *but; /* We don't provide an accel group for popup menus. */ but = gtk_image_menu_item_new_from_stock( stock_id, NULL ); gtk_menu_shell_append( GTK_MENU_SHELL( menu ), but ); gtk_widget_show( but ); gtk_signal_connect( GTK_OBJECT( but ), "activate", cb, user ); return( but ); } /* Add a toggle item. */ GtkWidget * menu_add_tog( GtkWidget *menu, const char *name, GtkSignalFunc cb, void *user ) { GtkWidget *tog; tog = gtk_check_menu_item_new_with_mnemonic( name ); gtk_menu_shell_append( GTK_MENU_SHELL( menu ), tog ); gtk_widget_show( tog ); gtk_signal_connect( GTK_OBJECT( tog ), "toggled", cb, user ); return( tog ); } /* Add a separator. */ GtkWidget * menu_add_sep( GtkWidget *menu ) { GtkWidget *sep; sep = gtk_menu_item_new(); gtk_widget_set_sensitive( GTK_WIDGET( sep ), FALSE ); gtk_menu_shell_append( GTK_MENU_SHELL( menu ), sep ); gtk_widget_show( sep ); return( sep ); } /* Add a pullright. */ GtkWidget * menu_add_pullright( GtkWidget *menu, const char *stock_id ) { GtkWidget *pullright; GtkWidget *subpane; subpane = gtk_menu_new(); pullright = gtk_image_menu_item_new_from_stock( stock_id, NULL ); gtk_menu_item_set_submenu( GTK_MENU_ITEM( pullright ), subpane ); gtk_menu_shell_append( GTK_MENU_SHELL( menu ), pullright ); gtk_widget_show( pullright ); return( subpane ); } /* Four quarks: each menu item has a quark linking back to the main pane, * plus a quark for the user signal. The main pane has a quark linking to the * widget the menu was popped from, and that has the userdata for this context. * One more quark holds the popup in a host. */ static GQuark quark_main = 0; static GQuark quark_host = 0; static GQuark quark_data = 0; static GQuark quark_popup = 0; /* Build a new popup menu. */ GtkWidget * popup_build( const char *name ) { /* Build our quarks. */ if( !quark_main ) { quark_main = g_quark_from_static_string( "quark_main" ); quark_host = g_quark_from_static_string( "quark_host" ); quark_data = g_quark_from_static_string( "quark_data" ); quark_popup = g_quark_from_static_string( "quark_popup" ); } return( menu_build( name ) ); } /* Activate function for a popup menu item. */ static void popup_activate_cb( GtkWidget *item, PopupFunc cb ) { GtkWidget *qmain = gtk_object_get_data_by_id( GTK_OBJECT( item ), quark_main ); GtkWidget *qhost = gtk_object_get_data_by_id( GTK_OBJECT( qmain ), quark_host ); void *qdata = gtk_object_get_data_by_id( GTK_OBJECT( qhost ), quark_data ); (*cb)( item, qhost, qdata ); } /* Add a menu item to a popup. */ GtkWidget * popup_add_but( GtkWidget *popup, const char *name, PopupFunc cb ) { GtkWidget *but = menu_add_but( popup, name, GTK_SIGNAL_FUNC( popup_activate_cb ), (void *) cb ); gtk_object_set_data_by_id( GTK_OBJECT( but ), quark_main, popup ); return( but ); } /* Add a toggle item to a popup. */ GtkWidget * popup_add_tog( GtkWidget *popup, const char *name, PopupFunc cb ) { GtkWidget *tog = menu_add_tog( popup, name, GTK_SIGNAL_FUNC( popup_activate_cb ), (void *) cb ); gtk_object_set_data_by_id( GTK_OBJECT( tog ), quark_main, popup ); return( tog ); } /* Add a pullright item to a popup. Return the empty sub-pane. */ GtkWidget * popup_add_pullright( GtkWidget *popup, const char *name ) { GtkWidget *pullright = menu_add_pullright( popup, name ); gtk_object_set_data_by_id( GTK_OBJECT( pullright ), quark_main, popup ); return( pullright ); } /* Show the popup. */ void popup_show( GtkWidget *host, GdkEvent *ev ) { GtkWidget *popup = gtk_object_get_data_by_id( GTK_OBJECT( host ), quark_popup ); gtk_object_set_data_by_id( GTK_OBJECT( popup ), quark_host, host ); gtk_menu_popup( GTK_MENU( popup ), NULL, NULL, (GtkMenuPositionFunc) NULL, NULL, 3, ev->button.time ); } /* Event handler for popupshow. */ static gboolean popup_handle_event( GtkWidget *host, GdkEvent *ev, gpointer dummy ) { gboolean handled = FALSE; if( ev->type == GDK_BUTTON_PRESS && ev->button.button == 3 ) { popup_show( host, ev ); handled = TRUE; } else if( ev->type == GDK_KEY_PRESS && ev->key.keyval == GDK_F10 && ev->key.state & GDK_SHIFT_MASK ) { popup_show( host, ev ); handled = TRUE; } return( handled ); } /* Link a host to a popup. */ void popup_link( GtkWidget *host, GtkWidget *popup, void *data ) { gtk_object_set_data_by_id( GTK_OBJECT( host ), quark_popup, popup ); gtk_object_set_data_by_id( GTK_OBJECT( host ), quark_data, data ); } /* Add a callback to show a popup. */ guint popup_attach( GtkWidget *host, GtkWidget *popup, void *data ) { guint sid; popup_link( host, popup, data ); /* We can't just use gtk_menu_attach_to_widget(), since that can only * attach a menu to a single widget. We want to be able to attach a * single menu to meny widgets. */ sid = gtk_signal_connect( GTK_OBJECT( host ), "event", GTK_SIGNAL_FUNC( popup_handle_event ), NULL ); return( sid ); } void popup_detach( GtkWidget *host, guint sid ) { gtk_signal_disconnect( GTK_OBJECT( host ), sid ); } static void set_tooltip_events( GtkWidget *wid ) { gtk_widget_add_events( wid, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK ); } /* Set the tooltip on a widget. */ void set_tooltip( GtkWidget *wid, const char *fmt, ... ) { va_list ap; char *txt; if( !wid ) return; if( !fmt ) fmt = ""; va_start( ap, fmt ); txt = g_strdup_vprintf( fmt, ap ); va_end( ap ); if( !our_tooltips ) our_tooltips = gtk_tooltips_new(); gtk_tooltips_set_tip( our_tooltips, wid, txt, NULL ); if( !GTK_WIDGET_REALIZED( wid ) ) gtk_signal_connect( GTK_OBJECT( wid ), "realize", GTK_SIGNAL_FUNC( set_tooltip_events ), NULL ); else set_tooltip_events( wid ); g_free( txt ); } /* Track tooltips we generate with one of these. */ typedef struct _TooltipGenerate { GtkWidget *widget; TooltipGenerateFn generate; void *a; void *b; VipsBuf buf; char txt[256]; } TooltipGenerate; static void tooltip_generate_free( GtkWidget *widget, TooltipGenerate *gen ) { gen->widget = NULL; gen->generate = NULL; gen->a = NULL; gen->b = NULL; IM_FREE( gen ); } static gboolean tooltip_generate_rebuild( GtkWidget *widget, GdkEventCrossing *event, TooltipGenerate *gen ) { gboolean handled = FALSE; if( gen->widget ) { vips_buf_rewind( &gen->buf ); gen->generate( widget, &gen->buf, gen->a, gen->b ); set_tooltip( gen->widget, "%s", vips_buf_all( &gen->buf ) ); } return( handled ); } static void tooltip_generate_attach( GtkWidget *widget, TooltipGenerate *gen ) { /* Must have enter/leave. */ gtk_widget_add_events( widget, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK ); /* On enter, regenerate the tooltip. */ g_signal_connect( widget, "enter_notify_event", G_CALLBACK( tooltip_generate_rebuild ), gen ); } /* Set a callback to be used to generate the tooltip. */ void set_tooltip_generate( GtkWidget *widget, TooltipGenerateFn generate, void *a, void *b ) { TooltipGenerate *gen; if( !(gen = INEW( NULL, TooltipGenerate )) ) return; gen->widget = widget; gen->generate = generate; gen->a = a; gen->b = b; vips_buf_init_static( &gen->buf, gen->txt, 256 ); g_signal_connect( widget, "destroy", G_CALLBACK( tooltip_generate_free ), gen ); if( !GTK_WIDGET_REALIZED( widget ) ) g_signal_connect( widget, "realize", G_CALLBACK( tooltip_generate_attach ), gen ); else tooltip_generate_attach( widget, gen ); } /* Junk all tooltips, helps trim valgrind noise. */ void junk_tooltips( void ) { if( our_tooltips ) g_object_ref_sink( GTK_OBJECT( our_tooltips ) ); } /* Set a GtkEditable. */ void set_gentryv( GtkWidget *edit, const char *fmt, va_list ap ) { char buf[1000]; gint position; int i; int len; if( !edit ) return; if( !fmt ) fmt = ""; (void) im_vsnprintf( buf, 1000, fmt, ap ); /* Filter out /n and /t ... they confuse gtkentry terribly */ len = strlen( buf ); for( i = 0; i < len; i++ ) if( buf[i] == '\n' || buf[i] == '\t' ) buf[i] = ' '; gtk_editable_delete_text( GTK_EDITABLE( edit ), 0, -1 ); position = 0; gtk_editable_insert_text( GTK_EDITABLE( edit ), buf, strlen( buf ), &position ); } /* Set a GtkEditable. */ void set_gentry( GtkWidget *edit, const char *fmt, ... ) { va_list ap; va_start( ap, fmt ); set_gentryv( edit, fmt, ap ); va_end( ap ); } void set_glabel( GtkWidget *label, const char *fmt, ... ) { va_list ap; char buf[1000]; va_start( ap, fmt ); (void) im_vsnprintf( buf, 1000, fmt, ap ); va_end( ap ); gtk_label_set_text( GTK_LABEL( label ), buf ); } /* Like set_glabel(), but don't display multi-line strings (just display the * first line). */ void set_glabel1( GtkWidget *label, const char *fmt, ... ) { va_list ap; char txt[1000]; VipsBuf buf = VIPS_BUF_STATIC( txt ); va_start( ap, fmt ); vips_buf_vappendf( &buf, fmt, ap ); va_end( ap ); gtk_label_set_text( GTK_LABEL( label ), vips_buf_firstline( &buf ) ); } /* Like set_glabel, but do it caption-style. */ void set_gcaption( GtkWidget *label, const char *fmt, ... ) { va_list ap; char buf1[1000]; char buf2[1000]; va_start( ap, fmt ); (void) im_vsnprintf( buf1, 1000, fmt, ap ); va_end( ap ); escape_markup( buf1, buf2, 1000 ); (void) im_snprintf( buf1, 1000, "%s", buf2 ); gtk_label_set_markup( GTK_LABEL( label ), buf1 ); } gboolean get_geditable_name( GtkWidget *text, char *out, int sz ) { char *name; char *tname; name = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 ); tname = trim_nonalpha( name ); if( !tname ) { IM_FREEF( g_free, name ); error_top( _( "Bad identifier." ) ); error_sub( _( "Enter an identifier. Identifiers start with " "a letter, and then contain only letters, numbers, " "apostrophy and underscore." ) ); return( FALSE ); } im_strncpy( out, tname, sz ); g_free( name ); return( TRUE ); } gboolean get_geditable_string( GtkWidget *text, char *out, int sz ) { char *str; str = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 ); im_strncpy( out, str, sz ); g_free( str ); return( TRUE ); } gboolean get_geditable_filename( GtkWidget *text, char *out, int sz ) { char *filename; char *tfilename; filename = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 ); tfilename = trim_white( filename ); if( !is_valid_filename( tfilename ) ) { g_free( filename ); return( FALSE ); } im_strncpy( out, tfilename, sz ); g_free( filename ); return( TRUE ); } /* Get a geditable as a double. */ gboolean get_geditable_double( GtkWidget *text, double *out ) { char *txt; char *end; double t; txt = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 ); t = strtod( txt, &end ); if( end == txt ) { error_top( _( "Bad floating point number." ) ); error_sub( _( "\"%s\" is not a floating point number." ), txt ); g_free( txt ); return( FALSE ); } if( strspn( end, WHITESPACE ) != strlen( end ) ) { error_top( _( "Bad floating point number." ) ); error_sub( _( "Extra characters \"%s\" after number." ), end ); g_free( txt ); return( FALSE ); } g_free( txt ); *out = t; return( TRUE ); } /* Get as int. */ gboolean get_geditable_int( GtkWidget *text, int *n ) { int i; char *txt; /* Parse values. */ txt = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 ); if( sscanf( txt, "%i", &i ) != 1 ) { error_top( _( "Bad integer." ) ); error_sub( _( "\"%s\" is not an integer." ), txt ); g_free( txt ); return( FALSE ); } g_free( txt ); *n = i; return( TRUE ); } /* Get as unsigned int. */ gboolean get_geditable_uint( GtkWidget *text, int *n ) { int i; if( !get_geditable_int( text, &i ) || i < 0 ) { error_top( _( "Bad unsigned integer." ) ); return( FALSE ); } *n = i; return( TRUE ); } /* Get as positive int. */ gboolean get_geditable_pint( GtkWidget *text, int *n ) { int i; if( !get_geditable_int( text, &i ) || i <= 0 ) { error_top( _( "Bad positive integer." ) ); return( FALSE ); } *n = i; return( TRUE ); } /* Indent widget, label above. */ GtkWidget * build_glabelframe2( GtkWidget *widget, const char *name ) { GtkWidget *lab; GtkWidget *vb; GtkWidget *hb; GtkWidget *inv; char buf[1000]; hb = gtk_hbox_new( FALSE, 2 ); inv = gtk_label_new( "" ); gtk_box_pack_start( GTK_BOX( hb ), inv, FALSE, FALSE, 15 ); gtk_box_pack_start( GTK_BOX( hb ), widget, TRUE, TRUE, 0 ); vb = gtk_vbox_new( FALSE, 2 ); im_snprintf( buf, 1000, _( "%s:" ), name ); lab = gtk_label_new( buf ); gtk_misc_set_alignment( GTK_MISC( lab ), 0.0, 0.5 ); gtk_box_pack_start( GTK_BOX( vb ), lab, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( vb ), hb, TRUE, TRUE, 0 ); return( vb ); } /* Make a text field + label. Indent the text on a new line. */ GtkWidget * build_glabeltext3( GtkWidget *box, const char *label ) { GtkWidget *txt; GtkWidget *vb; txt = gtk_entry_new(); vb = build_glabelframe2( txt, label ); gtk_box_pack_start( GTK_BOX( box ), vb, FALSE, FALSE, 0 ); return( txt ); } /* Make text field plus label .. use a sizegroup for alignment. */ GtkWidget * build_glabeltext4( GtkWidget *box, GtkSizeGroup *group, const char *text ) { GtkWidget *hbox; GtkWidget *label; GtkWidget *entry; char buf[256]; hbox = gtk_hbox_new( FALSE, 12 ); im_snprintf( buf, 256, _( "%s:" ), text ); label = gtk_label_new( buf ); gtk_misc_set_alignment( GTK_MISC( label ), 0.0, 0.5 ); if( group ) gtk_size_group_add_widget( group, label ); gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 ); entry = gtk_entry_new(); gtk_box_pack_start( GTK_BOX( hbox ), entry, TRUE, TRUE, 0 ); gtk_box_pack_start( GTK_BOX( box ), hbox, FALSE, FALSE, 0 ); gtk_widget_show_all( hbox ); return( entry ); } /* Make a labeled toggle. */ GtkWidget * build_gtoggle( GtkWidget *box, const char *caption ) { GtkWidget *hb; GtkWidget *inv; GtkWidget *toggle; /* Indent left a bit. */ inv = gtk_label_new( "" ); hb = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX( hb ), inv, FALSE, FALSE, 2 ); toggle = gtk_check_button_new_with_label( caption ); gtk_container_set_border_width( GTK_CONTAINER( toggle ), 4 ); gtk_box_pack_start( GTK_BOX( hb ), toggle, TRUE, TRUE, 0 ); gtk_box_pack_start( GTK_BOX( box ), hb, FALSE, FALSE, 0 ); return( toggle ); } /* Make a label plus option menu. */ GtkWidget * build_goption( GtkWidget *box, GtkSizeGroup *group, const char *name, const char *item_names[], int nitem, GtkSignalFunc fn, void *value ) { GtkWidget *hb; GtkWidget *label; GtkWidget *om; int i; char buf[1000]; hb = gtk_hbox_new( FALSE, 12 ); im_snprintf( buf, 1000, _( "%s:" ), name ); label = gtk_label_new( buf ); if( group ) gtk_size_group_add_widget( group, label ); gtk_box_pack_start( GTK_BOX( hb ), label, FALSE, TRUE, 0 ); om = gtk_combo_box_new_text(); gtk_box_pack_start( GTK_BOX( hb ), om, FALSE, TRUE, 0 ); set_tooltip( om, _( "Left-click to change value" ) ); for( i = 0; i < nitem; i++ ) gtk_combo_box_append_text( GTK_COMBO_BOX( om ), _( item_names[i] ) ); if( fn ) gtk_signal_connect( GTK_OBJECT( om ), "changed", fn, value ); gtk_box_pack_start( GTK_BOX( box ), hb, FALSE, TRUE, 0 ); gtk_widget_show_all( hb ); return( om ); } /* Register a widget as a filename drag receiver. */ typedef struct { GtkWidget *widget; FiledropFunc fn; void *client; } FiledropInfo; static gboolean filedrop_trigger( FiledropInfo *fdi, const char *path ) { char buf[FILENAME_MAX]; gboolean result; im_strncpy( buf, path, FILENAME_MAX ); path_compact( buf ); result = fdi->fn( fdi->client, buf ); return( result ); } static void filedrop_drag_data_received( GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time, FiledropInfo *fdi ) { gchar *sPath = NULL; gchar *pFrom, *pTo; gboolean result; pFrom = strstr( (char *) data->data, "file:" ); while( pFrom ) { #if !GLIB_CHECK_VERSION (2,0,0) pFrom += 5; /* remove 'file:' */ #else GError *error = NULL; #endif pTo = pFrom; while( *pTo != 0 && *pTo != 0xd && *pTo != 0xa ) pTo += 1; sPath = g_strndup( pFrom, pTo - pFrom ); #if !GLIB_CHECK_VERSION (2,0,0) result = filedrop_trigger( fdi, sPath ); #else /* format changed with Gtk+1.3, use conversion */ pFrom = g_filename_from_uri( sPath, NULL, &error ); result = filedrop_trigger( fdi, pFrom ); g_free( pFrom ); #endif g_free( sPath ); if( !result ) iwindow_alert( fdi->widget, GTK_MESSAGE_ERROR ); pFrom = strstr( pTo, "file:" ); } gtk_drag_finish( context, TRUE, FALSE, time ); } /* HB: file dnd stuff lent by The Gimp via Dia, not fully understood * but working ... */ enum { TARGET_URI_LIST, TARGET_TEXT_PLAIN }; static void filedrop_destroy( GtkWidget *widget, FiledropInfo *fdi ) { im_free( fdi ); } void filedrop_register( GtkWidget *widget, FiledropFunc fn, void *client ) { static GtkTargetEntry target_table[] = { { "text/uri-list", 0, TARGET_URI_LIST }, { "text/plain", 0, TARGET_TEXT_PLAIN } }; FiledropInfo *fdi = INEW( NULL, FiledropInfo ); fdi->widget = widget; fdi->fn = fn; fdi->client = client; gtk_signal_connect( GTK_OBJECT( widget ), "destroy", GTK_SIGNAL_FUNC( filedrop_destroy ), fdi ); gtk_drag_dest_set( GTK_WIDGET( widget ), GTK_DEST_DEFAULT_ALL, target_table, IM_NUMBER( target_table ), GDK_ACTION_COPY | /* That's all you need to get draggable URIs in GNOME and * win32, but KDE needs these other flags too, apparently. */ GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK ); gtk_signal_connect( GTK_OBJECT( widget ), "drag_data_received", GTK_SIGNAL_FUNC( filedrop_drag_data_received ), fdi ); } /* Add symbol drag to the target list. */ void set_symbol_drag_type( GtkWidget *widget ) { static const GtkTargetEntry targets[] = { { "text/symbol", 0, TARGET_SYMBOL } }; GtkTargetList *target_list; if( !GTK_WIDGET_REALIZED( widget ) ) return; /* We can't always set the dest types, since we're probably already a * filedrop. Just add to the target list. */ if( (target_list = gtk_drag_dest_get_target_list( widget )) ) gtk_target_list_add_table( target_list, targets, IM_NUMBER( targets ) ); else gtk_drag_dest_set( widget, GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, targets, IM_NUMBER( targets ), GDK_ACTION_COPY ); gtk_drag_source_set( widget, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, targets, IM_NUMBER( targets ), GDK_ACTION_COPY | GDK_ACTION_MOVE ); } typedef struct _Listen { GObject *gobject; /* This object */ GObject *source; /* Listens for signals from this */ GObject **zap; /* NULL this on destroy */ const char *name; /* Signal name */ GCallback gcallback; /* Call this handler */ guint name_sid; guint gobject_destroy_sid; guint source_destroy_sid; } Listen; static void listen_gobject_destroy_cb( GObject *gobject, Listen *listen ) { /* gobject has gone ... source should no longer send us signals. */ FREESID( listen->name_sid, listen->source ); FREESID( listen->source_destroy_sid, listen->source ); g_free( listen ); } static void listen_source_destroy_cb( GObject *gobject, Listen *listen ) { /* Source has gone, these signals have been destroyed. */ listen->name_sid = 0; listen->source_destroy_sid = 0; /* Link broken, no need to auto-free us on gobject destroy. */ FREESID( listen->gobject_destroy_sid, listen->gobject ); /* Zap gobject member pointer to source. */ if( listen->zap ) { g_assert( !*(listen->zap) || *(listen->zap) == listen->source ); *(listen->zap) = NULL; } g_free( listen ); } void listen_add( GObject *gobject, GObject **zap, const char *name, GCallback gcallback ) { Listen *listen = g_new( Listen, 1 ); listen->gobject = gobject; listen->source = *zap; listen->zap = zap; listen->name = name; listen->gcallback = gcallback; listen->name_sid = g_signal_connect( listen->source, listen->name, listen->gcallback, listen->gobject ); listen->source_destroy_sid = g_signal_connect( listen->source, "destroy", G_CALLBACK( listen_source_destroy_cb ), listen ); listen->gobject_destroy_sid = g_signal_connect( gobject, "destroy", G_CALLBACK( listen_gobject_destroy_cb ), listen ); } void widget_update_pointer( GtkWidget *widget, GdkEvent *ev ) { if( ev->type == GDK_MOTION_NOTIFY && ev->motion.is_hint ) { GdkDisplay *display = gtk_widget_get_display( widget ); GdkScreen *screen; int x_root, y_root; gdk_display_get_pointer( display, &screen, &x_root, &y_root, NULL ); ev->motion.x_root = x_root; ev->motion.y_root = y_root; } } void * gobject_print( GObject *gobject ) { printf( "%s (%p)\n", G_OBJECT_TYPE_NAME( gobject ), gobject ); return( NULL ); } /* Get the default DPI. */ int get_dpi( void ) { GdkScreen *screen = gdk_screen_get_default(); if( screen ) { int width_pixels = gdk_screen_get_width( screen ); int width_mm = gdk_screen_get_width_mm( screen ); return( width_pixels / (width_mm / 25.4) ); } else return( 72 ); } GtkWidget * image_new_from_file( const char *name ) { GtkWidget *image; char *file; if( (file = path_find_file( name )) ) { image = (GtkWidget *) callv_string_filename( (callv_string_fn) gtk_image_new_from_file, file, NULL, NULL, NULL ); im_free( file ); } else /* We get a broken image icon if this fails. */ image = gtk_image_new_from_file( name ); return( image ); } void vfatal( GError **error ) { fprintf( stderr, PACKAGE ": fatal error\n" ); if( *error ) { fprintf( stderr, "%s\n", (*error)->message ); IM_FREEF( g_error_free, *error ); } exit( -1 ); } char * text_view_get_text( GtkTextView *text_view ) { GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); GtkTextIter start_iter; GtkTextIter end_iter; char *text; gtk_text_buffer_get_start_iter( text_buffer, &start_iter ); gtk_text_buffer_get_end_iter( text_buffer, &end_iter ); text = gtk_text_buffer_get_text( text_buffer, &start_iter, &end_iter, FALSE ); return( text ); } void text_view_set_text( GtkTextView *text_view, const char *text, gboolean editable ) { GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); gtk_text_buffer_set_text( text_buffer, text ? text : "", -1 ); gtk_text_view_set_editable( text_view, editable ); gtk_text_view_set_cursor_visible( text_view, editable ); } void text_view_select_text( GtkTextView *text_view, int start, int end ) { GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view ); GtkTextMark *mark = gtk_text_buffer_get_insert( text_buffer ); GtkTextIter start_iter; GtkTextIter end_iter; gtk_text_buffer_get_iter_at_offset( text_buffer, &start_iter, start ); gtk_text_buffer_get_iter_at_offset( text_buffer, &end_iter, end ); gtk_text_buffer_select_range( text_buffer, &start_iter, &end_iter ); gtk_text_view_scroll_mark_onscreen( text_view, mark ); } /* If parent dies, kill us too. Parent can be anything, but child must be an * iobject. */ typedef struct _DestroyIfDestroyed { GObject *child; GObject *parent; DestroyFn destroy_fn; } DestroyIfDestroyed; static void destroy_if_destroyed_parent_cb( DestroyIfDestroyed *difd, GObject *parent ); static void destroy_if_destroyed_child_cb( DestroyIfDestroyed *difd, GObject *child ); static void destroy_if_destroyed_parent_cb( DestroyIfDestroyed *difd, GObject *parent ) { GObject *child; DestroyFn destroy_fn; #ifdef DEBUG printf( "destroy_if_destroyed_parent_cb: %p\n", difd ); #endif /*DEBUG*/ /* Destroying the child will trigger the other half of difd, make sure * we remove the link first. */ child = difd->child; destroy_fn = difd->destroy_fn; g_object_weak_unref( difd->child, (GWeakNotify) destroy_if_destroyed_child_cb, difd ); destroy_fn( child ); difd->child = NULL; difd->parent = NULL; difd->destroy_fn = NULL; g_free( difd ); } static void destroy_if_destroyed_child_cb( DestroyIfDestroyed *difd, GObject *child ) { #ifdef DEBUG printf( "destroy_if_destroyed_child_cb: %p\n", difd ); #endif /*DEBUG*/ g_object_weak_unref( difd->parent, (GWeakNotify) destroy_if_destroyed_parent_cb, difd ); difd->child = NULL; difd->parent = NULL; difd->destroy_fn = NULL; g_free( difd ); } void destroy_if_destroyed( GObject *child, GObject *parent, DestroyFn destroy_fn ) { DestroyIfDestroyed *difd = g_new( DestroyIfDestroyed, 1 ); #ifdef DEBUG printf( "destroy_if_destroyed %p: parent=%p, child=%p\n", difd, parent, child ); #endif /*DEBUG*/ difd->child = child; difd->parent = parent; difd->destroy_fn = destroy_fn; g_object_weak_ref( parent, (GWeakNotify) destroy_if_destroyed_parent_cb, difd ); g_object_weak_ref( child, (GWeakNotify) destroy_if_destroyed_child_cb, difd ); } /* A 'safe' way to run a few events. */ void process_events( void ) { /* Max events we process before signalling a timeout. Without this we * can get stuck in event loops in some circumstances. */ static const int max_events = 100; /* Block too much recursion. 0 is from the top-level, 1 is from a * callback, we don't want any more than that. */ if( g_main_depth() < 2 ) { int n; #ifdef DEBUG printf( "progress_update: starting event dispatch\n" ); #endif /*DEBUG*/ for( n = 0; n < max_events && g_main_context_iteration( NULL, FALSE ); n++ ) ; #ifdef DEBUG printf( "progress_update: event dispatch done\n" ); if( n == max_events ) printf( "progress_update: event dispatch timeout\n" ); #endif /*DEBUG*/ } } nip2-8.7.1/src/fontname.h0000644000175000017500000000272113351443023012067 00000000000000/* a fontname in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_FONTNAME (fontname_get_type()) #define FONTNAME( obj ) (GTK_CHECK_CAST( (obj), TYPE_FONTNAME, Fontname )) #define FONTNAME_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_FONTNAME, FontnameClass )) #define IS_FONTNAME( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FONTNAME )) #define IS_FONTNAME_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_FONTNAME )) typedef struct _Fontname { Classmodel model; char *value; } Fontname; typedef struct _FontnameClass { ClassmodelClass parent_class; /* My methods. */ } FontnameClass; GType fontname_get_type( void ); nip2-8.7.1/src/group.h0000644000175000017500000000270713351443023011420 00000000000000/* a group in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #define TYPE_GROUP (group_get_type()) #define GROUP( obj ) (GTK_CHECK_CAST( (obj), TYPE_GROUP, Group )) #define GROUP_CLASS( klass ) \ (GTK_CHECK_CLASS_CAST( (klass), TYPE_GROUP, GroupClass )) #define IS_GROUP( obj ) (GTK_CHECK_TYPE( (obj), TYPE_GROUP )) #define IS_GROUP_CLASS( klass ) \ (GTK_CHECK_CLASS_TYPE( (klass), TYPE_GROUP )) typedef struct _Group { Value parent_object; } Group; typedef struct _GroupClass { ValueClass parent_class; /* My methods. */ } GroupClass; GType group_get_type( void ); gboolean group_save_item( PElement *item, char *filename ); nip2-8.7.1/src/subcolumnview.c0000644000175000017500000001412013351443023013151 00000000000000/* a subcolumnview button in a workspace */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* #define DEBUG */ #include "ip.h" static ViewClass *parent_class = NULL; static void * subcolumnview_destroy_sub( Rowview *rview, Subcolumnview *sview ) { DESTROY_GTK( rview ); return( NULL ); } static void subcolumnview_destroy( GtkObject *object ) { Subcolumnview *sview; #ifdef DEBUG printf( "subcolumnview_destroy\n" ); #endif /*DEBUG*/ g_return_if_fail( object != NULL ); g_return_if_fail( IS_SUBCOLUMNVIEW( object ) ); sview = SUBCOLUMNVIEW( object ); UNREF( sview->group ); /* Destroying us won't automatically destroy our rowviews, since they * are not true child-widgets. Do it by hand. */ (void) view_map( VIEW( sview ), (view_map_fn) subcolumnview_destroy_sub, sview, NULL ); DESTROY_GTK( sview->table ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void subcolumnview_link( View *view, Model *model, View *parent ) { Subcolumnview *sview = SUBCOLUMNVIEW( view ); Subcolumn *scol = SUBCOLUMN( model ); #ifdef DEBUG printf( "subcolumnview_link: " ); if( HEAPMODEL( scol )->row ) row_name_print( HEAPMODEL( scol )->row ); else printf( "(null)" ); printf( "\n" ); #endif /*DEBUG*/ VIEW_CLASS( parent_class )->link( view, model, parent ); /* Add to enclosing column, if there is one. Attached to enclosing row * by rowview_refresh() if we're a subcolumn. */ if( !scol->is_top ) sview->rhsview = RHSVIEW( parent ); gtk_widget_show( GTK_WIDGET( sview ) ); } static void * subcolumnview_refresh_sub( Rowview *rview, Subcolumnview *sview ) { Subcolumn *scol = SUBCOLUMN( VOBJECT( sview )->iobject ); Row *row = ROW( VOBJECT( rview )->iobject ); int i; /* Most predicates need a sym. */ if( !row->sym ) return( NULL ); for( i = 0; i <= scol->vislevel; i++ ) if( subcolumn_visibility[i].pred( row ) ) { rowview_set_visible( rview, TRUE ); sview->nvis++; break; } if( i > scol->vislevel ) rowview_set_visible( rview, FALSE ); return( NULL ); } static void subcolumnview_refresh( vObject *vobject ) { Subcolumnview *sview = SUBCOLUMNVIEW( vobject ); Subcolumn *scol = SUBCOLUMN( VOBJECT( sview )->iobject ); int model_rows = icontainer_get_n_children( ICONTAINER( scol ) ); int old_nvis = sview->nvis; gboolean editable = scol->top_col->ws->mode != WORKSPACE_MODE_NOEDIT; #ifdef DEBUG printf( "subcolumnview_refresh\n" ); #endif /*DEBUG*/ if( sview->rows != model_rows ) { sview->rows = model_rows; if( sview->rows ) gtk_table_resize( GTK_TABLE( sview->table ), sview->rows, 4 ); #ifdef DEBUG printf( "subcolumnview_refresh: resize to %d rows\n", sview->rows ); #endif /*DEBUG*/ } /* Top-level subcolumns look different in no-edit mode. */ if( scol->is_top && editable ) { gtk_alignment_set_padding( GTK_ALIGNMENT( sview->align ), 0, 0, 0, 0 ); gtk_table_set_row_spacings( GTK_TABLE( sview->table ), 0 ); gtk_table_set_col_spacings( GTK_TABLE( sview->table ), 0 ); } else if( scol->is_top && !editable ) { gtk_alignment_set_padding( GTK_ALIGNMENT( sview->align ), 5, 5, 5, 5 ); gtk_table_set_row_spacings( GTK_TABLE( sview->table ), 5 ); gtk_table_set_col_spacings( GTK_TABLE( sview->table ), 5 ); } /* Nested subcols: we just change the left indent. */ if( !scol->is_top && editable ) { gtk_alignment_set_padding( GTK_ALIGNMENT( sview->align ), 0, 0, 0, 0 ); } else if( !scol->is_top && !editable ) { gtk_alignment_set_padding( GTK_ALIGNMENT( sview->align ), 0, 0, 15, 0 ); } sview->nvis = 0; (void) view_map( VIEW( sview ), (view_map_fn) subcolumnview_refresh_sub, sview, NULL ); if( sview->nvis != old_nvis ) { view_resize( VIEW( sview ) ); iobject_changed( IOBJECT( scol->top_col ) ); } VOBJECT_CLASS( parent_class )->refresh( vobject ); } static void subcolumnview_class_init( SubcolumnviewClass *class ) { GtkObjectClass *object_class = (GtkObjectClass*) class; vObjectClass *vobject_class = (vObjectClass*) class; ViewClass *view_class = (ViewClass*) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = subcolumnview_destroy; /* Create signals. */ /* Init methods. */ vobject_class->refresh = subcolumnview_refresh; view_class->link = subcolumnview_link; } static void subcolumnview_init( Subcolumnview *sview ) { sview->rhsview = NULL; sview->rows = 0; sview->nvis = 0; sview->align = gtk_alignment_new( 0, 0, 1, 1 ); gtk_box_pack_start( GTK_BOX( sview ), sview->align, FALSE, FALSE, 0 ); sview->table = gtk_table_new( sview->rows, 4, FALSE ); gtk_container_add( GTK_CONTAINER( sview->align ), sview->table ); gtk_widget_show_all( sview->align ); sview->group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL ); } GtkType subcolumnview_get_type( void ) { static GtkType type = 0; if( !type ) { static const GtkTypeInfo info = { "Subcolumnview", sizeof( Subcolumnview ), sizeof( SubcolumnviewClass ), (GtkClassInitFunc) subcolumnview_class_init, (GtkObjectInitFunc) subcolumnview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; type = gtk_type_unique( TYPE_VIEW, &info ); } return( type ); } View * subcolumnview_new( void ) { Subcolumnview *sview = gtk_type_new( TYPE_SUBCOLUMNVIEW ); return( VIEW( sview ) ); } nip2-8.7.1/src/graphwindow.c0000644000175000017500000002612513351443023012610 00000000000000/* display workspaces with graphviz */ /* Copyright (C) 1991-2003 The National Gallery This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ /* TODO Don't generate DOT in a file, build the graph ourselves. We'd need some sort of graph hash thing to avoid relayouts. Or perhaps a workspace hash? A hash by column? After layout, don't render to a file, instead draw directly to the output window with cairo. Copy/paste code from the png:cairo render. Have some simple culling stuff to only render visible parts of the graph. As well as "view workspace as graph", have a "view column as graph" item. Don't show nodes which are not inside this workspace. Possibly add graph editing, or at least edge highlighting as you mouse. Let columns be collapsed / expanded, and start the view with columns collapsed if there's more than 1. This might be easier if columns were separate scopes, I suppose. Do we should dynamic dependencies? How about (A2 = untitled."A1") ? */ /* #define DEBUG */ #include "ip.h" #ifdef HAVE_LIBGVC static FloatwindowClass *parent_class = NULL; static int graph_write_cluster_index = 0; static void * graph_write_row_child( Link *link, VipsBuf *buf ) { if( link->child->expr && link->child->expr->row ) { vips_buf_appendf( buf, "\t\t%s -> %s;\n", IOBJECT( link->child )->name, IOBJECT( link->parent )->name ); } return( NULL ); } static void * graph_write_row( Row *row, VipsBuf *buf ) { if( row->sym ) slist_map( row->sym->topchildren, (SListMapFn) graph_write_row_child, buf ); return( NULL ); } static void * graph_write_column( Column *col, VipsBuf *buf ) { vips_buf_appendf( buf, "\tsubgraph cluster_%d {\n", graph_write_cluster_index++ ); vips_buf_appendf( buf, "\t\tlabel = \"%s", IOBJECT( col )->name ); if( IOBJECT( col )->caption ) vips_buf_appendf( buf, " - %s", IOBJECT( col )->caption ); vips_buf_appends( buf, "\"\n" ); vips_buf_appends( buf, "\t\tstyle=filled;\n" ); vips_buf_appends( buf, "\t\tcolor=lightgrey;\n" ); vips_buf_appends( buf, "\t\tnode [style=filled,color=white];\n" ); (void) column_map( col, (row_map_fn) graph_write_row, buf, NULL ); vips_buf_appends( buf, "\t}\n" ); return( NULL ); } /* Generate the workspace in dot format. */ static void graph_write_dot( Workspace *ws, VipsBuf *buf ) { graph_write_cluster_index = 0; vips_buf_appends( buf, "digraph G {\n" ); workspace_map_column( ws, (column_map_fn) graph_write_column, buf ); vips_buf_appends( buf, "}\n" ); } /* Print the workspace in dot format. Display with something like: * $ dot test1.dot -o test1.png -Tpng:cairo -v * $ eog test1.png */ void graph_write( Workspace *ws ) { char txt[1024]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graph_write_dot( ws, &buf ); printf( "%s", vips_buf_all( &buf ) ); } static void graphwindow_destroy( GtkObject *object ) { Graphwindow *graphwindow; g_return_if_fail( object != NULL ); g_return_if_fail( IS_GRAPHWINDOW( object ) ); graphwindow = GRAPHWINDOW( object ); #ifdef DEBUG printf( "graphwindow_destroy: %p\n", graphwindow ); #endif /*DEBUG*/ /* My instance destroy stuff. */ IM_FREE( graphwindow->dot ); IM_FREEF( g_source_remove, graphwindow->layout_timeout ); UNREF( graphwindow->imagemodel ); IM_FREEF( agclose, graphwindow->graph ); IM_FREEF( gvFreeContext, graphwindow->gvc ); FREESID( graphwindow->workspace_changed_sid, FLOATWINDOW( graphwindow )->model ); GTK_OBJECT_CLASS( parent_class )->destroy( object ); } static void graphwindow_class_init( GraphwindowClass *class ) { GtkObjectClass *object_class = (GtkObjectClass *) class; parent_class = g_type_class_peek_parent( class ); object_class->destroy = graphwindow_destroy; /* Create signals. */ /* Init methods. */ } static void graphwindow_init( Graphwindow *graphwindow ) { #ifdef DEBUG printf( "graphwindow_init: %p\n", graphwindow ); #endif /*DEBUG*/ graphwindow->dot = NULL; graphwindow->layout_timeout = 0; graphwindow->gvc = gvContext(); } GType graphwindow_get_type( void ) { static GType type = 0; if( !type ) { static const GTypeInfo info = { sizeof( GraphwindowClass ), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) graphwindow_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof( Graphwindow ), 32, /* n_preallocs */ (GInstanceInitFunc) graphwindow_init, }; type = g_type_register_static( TYPE_FLOATWINDOW, "Graphwindow", &info, 0 ); } return( type ); } static void graphwindow_refresh_title( Graphwindow *graphwindow ) { Workspace *ws = WORKSPACE( FLOATWINDOW( graphwindow )->model ); VipsBuf buf; char txt[512]; #ifdef DEBUG printf( "graphwindow_refresh_title\n" ); #endif /*DEBUG*/ vips_buf_init_static( &buf, txt, 512 ); if( ws->sym ) symbol_qualified_name( ws->sym, &buf ); iwindow_set_title( IWINDOW( graphwindow ), "%s", vips_buf_all( &buf ) ); } static gboolean graphwindow_build_graph( Graphwindow *graphwindow ) { char tname[FILENAME_MAX]; iOpenFile *of; if( !temp_name( tname, "dot" ) || !(of = ifile_open_write( "%s", tname )) ) return( FALSE ); if( !ifile_write( of, "%s", graphwindow->dot ) ) { ifile_close( of ); unlinkf( "%s", tname ); return( FALSE ); } ifile_close( of ); if( !(of = ifile_open_read( "%s", tname )) ) { unlinkf( "%s", tname ); return( FALSE ); } IM_FREEF( agclose, graphwindow->graph ); graphwindow->graph = agread( of->fp, NULL ); ifile_close( of ); unlinkf( "%s", tname ); return( TRUE ); } static gboolean graphwindow_update_image( Graphwindow *graphwindow ) { char tname[FILENAME_MAX]; iOpenFile *of; Imageinfo *ii; if( !temp_name( tname, "png" ) || !(of = ifile_open_write( "%s", tname )) ) return( FALSE ); gvRender( graphwindow->gvc, graphwindow->graph, "png:cairo", of->fp ); ifile_close( of ); if( !(ii = imageinfo_new_input( main_imageinfogroup, GTK_WIDGET( graphwindow ), NULL, tname )) ) { unlinkf( "%s", tname ); return( FALSE ); } conversion_set_image( graphwindow->imagemodel->conv, ii ); MANAGED_UNREF( ii ); /* We can unlink now: the png will have been converted to vips * format. */ unlinkf( "%s", tname ); return( TRUE ); } static gboolean graphwindow_layout( Graphwindow *graphwindow ) { if( !graphwindow_build_graph( graphwindow ) ) return( FALSE ); gvLayout( graphwindow->gvc, graphwindow->graph, "dot" ); if( !graphwindow_update_image( graphwindow ) ) return( FALSE ); return( TRUE ); } static gboolean graphwindow_layout_cb( Graphwindow *graphwindow ) { Workspace *ws = WORKSPACE( FLOATWINDOW( graphwindow )->model ); char txt[MAX_STRSIZE]; VipsBuf buf = VIPS_BUF_STATIC( txt ); graphwindow->layout_timeout = 0; graph_write_dot( ws, &buf ); if( !graphwindow->dot || strcmp( vips_buf_all( &buf ), graphwindow->dot ) != 0 ) { IM_FREE( graphwindow->dot ); graphwindow->dot = im_strdup( NULL, vips_buf_all( &buf ) ); #ifdef DEBUG printf( "graphwindow_changed_cb:\n%s\n", graphwindow->dot ); #endif /*DEBUG*/ if( !graphwindow_layout( graphwindow ) ) iwindow_alert( GTK_WIDGET( graphwindow ), GTK_MESSAGE_ERROR ); } /* Clear the timeout. */ return( FALSE ); } static void graphwindow_layout_queue( Graphwindow *graphwindow ) { IM_FREEF( g_source_remove, graphwindow->layout_timeout ); graphwindow->layout_timeout = g_timeout_add( 200, (GSourceFunc) graphwindow_layout_cb, graphwindow ); } /* The model has changed. */ static void graphwindow_changed_cb( Workspace *ws, Graphwindow *graphwindow ) { #ifdef DEBUG printf( "graphwindow_changed_cb: %p\n", graphwindow ); #endif /*DEBUG*/ graphwindow_refresh_title( graphwindow ); graphwindow_layout_queue( graphwindow ); } static const char *graphwindow_menubar_ui_description = "" " " " " " " " " " " " " " " " " " " " " " " " " ""; static void graphwindow_build( Graphwindow *graphwindow, GtkWidget *vbox, Workspace *ws ) { iWindow *iwnd = IWINDOW( graphwindow ); GError *error; GtkWidget *mbar; GtkWidget *frame; /* Make our model. */ graphwindow->imagemodel = imagemodel_new( NULL ); g_object_ref( G_OBJECT( graphwindow->imagemodel ) ); iobject_sink( IOBJECT( graphwindow->imagemodel ) ); graphwindow->workspace_changed_sid = g_signal_connect( G_OBJECT( ws ), "changed", G_CALLBACK( graphwindow_changed_cb ), graphwindow ); /* Make main menu bar */ error = NULL; if( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager, graphwindow_menubar_ui_description, -1, &error ) ) { g_message( "building menus failed: %s", error->message ); g_error_free( error ); exit( EXIT_FAILURE ); } mbar = gtk_ui_manager_get_widget( iwnd->ui_manager, "/GraphwindowMenubar" ); gtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 ); gtk_widget_show( mbar ); /* This will set to NULL if we don't have infobar support. */ if( (iwnd->infobar = infobar_new()) ) gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( iwnd->infobar ), FALSE, FALSE, 0 ); /* Graph area. */ frame = gtk_frame_new( NULL ); gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_OUT ); gtk_widget_show( frame ); gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( frame ), TRUE, TRUE, 0 ); graphwindow->ip = imagepresent_new( graphwindow->imagemodel ); gtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( graphwindow->ip ) ); gtk_widget_show( GTK_WIDGET( graphwindow->ip ) ); } static void graphwindow_link( Graphwindow *graphwindow, Workspace *ws, GtkWidget *parent ) { iwindow_set_build( IWINDOW( graphwindow ), (iWindowBuildFn) graphwindow_build, ws, NULL, NULL ); iwindow_set_parent( IWINDOW( graphwindow ), parent ); floatwindow_link( FLOATWINDOW( graphwindow ), MODEL( ws ) ); iwindow_set_size_prefs( IWINDOW( graphwindow ), "GRAPH_WINDOW_WIDTH", "GRAPH_WINDOW_HEIGHT" ); iwindow_build( IWINDOW( graphwindow ) ); /* Initial "changed" on the model to get all views to init. */ iobject_changed( IOBJECT( ws ) ); } Graphwindow * graphwindow_new( Workspace *ws, GtkWidget *parent ) { Graphwindow *graphwindow = gtk_type_new( TYPE_GRAPHWINDOW ); graphwindow_link( graphwindow, ws, parent ); return( graphwindow ); } #endif /*HAVE_LIBGVC*/ nip2-8.7.1/po/0000755000175000017500000000000013417043453010022 500000000000000nip2-8.7.1/po/en_GB.gmo0000644000175000017500000000132713351443023011415 00000000000000L | @  ? ]Bj  Color SpaceDouble-click to edit this color, or drag-and-drop between colorsEdit Color "%s"Set Color_False ColorProject-Id-Version: nip2 7.26.0 Report-Msgid-Bugs-To: PO-Revision-Date: 2011-07-26 12:40+0100 Last-Translator: John Cupitt Language-Team: en_GB Language: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=n != 1; Colour SpaceDouble-click to edit this colour, or drag-and-drop between coloursEdit Colour "%s"Set Colour_False Colournip2-8.7.1/po/en_GB.po0000644000175000017500000020137313351443023011254 00000000000000# UK english translation ... just swap color for colour # Copyright (C) 2011 # This file is distributed under the same license as the nip2 package. # John Cupitt , 2011. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: nip2 7.26.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-07-26 12:33+0100\n" "PO-Revision-Date: 2011-07-26 12:40+0100\n" "Last-Translator: John Cupitt \n" "Language-Team: en_GB \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: ../src/action.c:87 msgid "Bad arguments." msgstr "" #. Expands to eg. 'bad args to "+", called from "fred"' #. #: ../src/action.c:102 ../src/action.c:186 msgid "Called from" msgstr "" #: ../src/action.c:108 #, c-format msgid "" "Error in binary \"%s\".\n" "left = %s\n" "right = %s\n" "%s" msgstr "" #: ../src/action.c:142 ../src/class.c:190 #, c-format msgid "Member \"%s\" not found in class \"%s\"." msgstr "" #: ../src/action.c:149 #, c-format msgid "object = %s" msgstr "" #: ../src/action.c:153 #, c-format msgid "tag = %s" msgstr "" #: ../src/action.c:158 #, c-format msgid "Reference attempted in \"%s\"." msgstr "" #: ../src/action.c:162 ../src/class.c:189 msgid "Member not found." msgstr "" #: ../src/action.c:173 ../src/builtin.c:1008 ../src/call.c:249 #: ../src/class.c:49 ../src/class.c:1027 ../src/reduce.c:898 #: ../src/reduce.c:911 msgid "Bad argument." msgstr "" #: ../src/action.c:192 #, c-format msgid "" "Error in unary \"%s\".\n" "argument = %s\n" "%s" msgstr "" #: ../src/action.c:359 ../src/action.c:377 ../src/action.c:407 msgid "Bad right hand side of '.'." msgstr "" #: ../src/action.c:369 msgid "Symbol on left hand side of '.' is not scope" msgstr "" #: ../src/action.c:411 msgid "Property not found." msgstr "" #: ../src/action.c:425 msgid "Bad left hand side of '.'." msgstr "" #: ../src/action.c:937 msgid "Division by zero." msgstr "" #: ../src/action.c:1313 ../src/action.c:1593 msgid "Unimplemented." msgstr "" #: ../src/action.c:1677 ../src/action.c:1713 ../src/action.c:1971 msgid "invoking method:" msgstr "" #: ../src/boxes.c:251 msgid "Close _without Saving" msgstr "" #. Translators: translate this to a credit for you, and it'll appear in #. * the About box. #. #: ../src/boxes.c:270 msgid "translator_credits" msgstr "" #: ../src/boxes.c:279 #, c-format msgid "About %s." msgstr "" #: ../src/boxes.c:282 #, c-format msgid "%s is an image processing package." msgstr "" #: ../src/boxes.c:286 #, c-format msgid "" "%s comes with ABSOLUTELY NO WARRANTY. This is free software and you are " "welcome to redistribute it under certain conditions, see http://www.gnu.org." msgstr "" #: ../src/boxes.c:305 msgid "Personal start folder" msgstr "" #: ../src/boxes.c:309 msgid "Homepage" msgstr "" #: ../src/boxes.c:312 msgid "Linked to VIPS" msgstr "" #: ../src/boxes.c:315 msgid "Built against VIPS" msgstr "" #: ../src/boxes.c:328 msgid "Temp files in" msgstr "" #: ../src/boxes.c:394 msgid "Help page not found." msgstr "" #: ../src/boxes.c:395 #, c-format msgid "No indexed help page found for tag \"%s\"" msgstr "" #: ../src/boxes.c:604 msgid "Search for" msgstr "" #: ../src/boxes.c:605 msgid "Case sensitive" msgstr "" #: ../src/boxes.c:607 msgid "Regular expression" msgstr "" #: ../src/boxes.c:609 msgid "Search from start" msgstr "" #: ../src/boxes.c:814 msgid "Image header fields" msgstr "" #: ../src/boxes.c:830 msgid "Image history" msgstr "" #: ../src/boxes.c:946 ../src/boxes.c:957 ../src/boxes.c:986 msgid "Unable to view help file." msgstr "" #: ../src/boxes.c:947 #, c-format msgid "Unable to open URL \"%s\", windows error code = %d." msgstr "" #: ../src/boxes.c:958 #, c-format msgid "" "Attempt to view URL with xdg-open failed\n" "%s" msgstr "" #: ../src/boxes.c:963 ../src/boxes.c:995 msgid "Browser window opened." msgstr "" #: ../src/boxes.c:965 ../src/boxes.c:997 msgid "You may need to switch desktops to see the new window." msgstr "" #: ../src/boxes.c:988 #, c-format msgid "" "Attempted to launch browser with command:\n" " %s\n" "You can change this command in Preferences." msgstr "" #: ../src/boxes.c:1029 msgid "Select Font" msgstr "" #: ../src/boxes.c:1087 msgid "Font not found." msgstr "" #: ../src/boxes.c:1088 #, c-format msgid "Font \"%s\" not found on system." msgstr "" #: ../src/boxes.c:1168 msgid "Pick a font" msgstr "" #: ../src/boxes.c:1173 msgid "Set Font" msgstr "" #: ../src/boxes.c:1219 msgid "Click to select font" msgstr "" #: ../src/builtin.c:257 msgid "Out of range." msgstr "" #: ../src/builtin.c:258 msgid "gammq arguments must be a > 0, x >= 0." msgstr "" #: ../src/builtin.c:265 msgid "Not available." msgstr "" #: ../src/builtin.c:266 msgid "No GSL library available for gammq." msgstr "" #: ../src/builtin.c:422 ../src/classmodel.c:154 ../src/classmodel.c:227 #: ../src/filemodel.c:100 ../src/filemodel.c:145 ../src/filemodel.c:357 #: ../src/filemodel.c:583 ../src/filemodel.c:624 ../src/mainw.c:754 #: ../src/mainw.c:762 ../src/model.c:313 ../src/model.c:368 #: ../src/rowview.c:456 ../src/view.c:820 msgid "Not implemented." msgstr "" #: ../src/builtin.c:423 msgid "Complex math ops not implemented." msgstr "" #: ../src/builtin.c:498 msgid "Macro error." msgstr "" #: ../src/builtin.c:681 msgid "No such type" msgstr "" #: ../src/builtin.c:682 #, c-format msgid "GType %u not found." msgstr "" #: ../src/builtin.c:905 msgid "GSL library error." msgstr "" #: ../src/builtin.c:954 #, c-format msgid "Builtin \"%s\" takes %d argument." msgid_plural "Builtin \"%s\" takes %d arguments." msgstr[0] "" msgstr[1] "" #: ../src/builtin.c:1009 #, c-format msgid "" "Argument %d to builtin \"%s\" should be \"%s\", you passed:\n" " %s" msgstr "" #: ../src/cache.c:923 ../src/call.c:144 ../src/class.c:862 msgid "You passed:" msgstr "" #: ../src/cache.c:946 ../src/util.c:191 ../src/vipsobject.c:284 msgid "VIPS library error." msgstr "" #: ../src/cache.c:949 ../src/call.c:133 #, c-format msgid "Error calling library function \"%s\" (%s)." msgstr "" #: ../src/cache.c:952 #, c-format msgid "VIPS library: %s" msgstr "" #: ../src/call.c:132 msgid "CALL library error." msgstr "" #: ../src/call.c:192 msgid "Usage:" msgstr "" #: ../src/call.c:194 #, c-format msgid "CALL operator \"%s\"" msgstr "" #: ../src/call.c:196 #, c-format msgid "%s, from package \"%s\"" msgstr "" #: ../src/call.c:201 #, c-format msgid "\"%s\" takes %d argument:" msgid_plural "\"%s\" takes %d arguments:" msgstr[0] "" msgstr[1] "" #: ../src/call.c:208 #, c-format msgid "And produces %d result:" msgid_plural "And produces %d results:" msgstr[0] "" msgstr[1] "" #. Print any flags this function has. #. #: ../src/call.c:216 msgid "Flags:" msgstr "" #: ../src/call.c:220 msgid "PIO function" msgstr "" #: ../src/call.c:222 msgid "WIO function" msgstr "" #: ../src/call.c:225 msgid "coordinate transformer" msgstr "" #: ../src/call.c:227 msgid "no coordinate transformation" msgstr "" #: ../src/call.c:230 msgid "point-to-point operation" msgstr "" #: ../src/call.c:232 msgid "area operation" msgstr "" #: ../src/call.c:235 msgid "uncacheable operation" msgstr "" #: ../src/call.c:237 msgid "operation can be cached" msgstr "" #: ../src/call.c:252 #, c-format msgid "Argument %d (%s) to \"%s\" is the wrong type." msgstr "" #: ../src/call.c:269 ../src/class.c:657 ../src/class.c:889 ../src/class.c:986 #: ../src/compile.c:1766 ../src/vipsobject.c:125 msgid "Too many arguments." msgstr "" #: ../src/call.c:272 #, c-format msgid "Too many arguments to \"%s\"." msgstr "" #: ../src/call.c:290 msgid "Unknown type." msgstr "" #: ../src/call.c:291 #, c-format msgid "CALL type \"%s\" not supported" msgstr "" #: ../src/call.c:1262 ../src/call.c:1346 #, c-format msgid "image \"%s\"" msgstr "" #: ../src/call.c:1269 msgid "no image" msgstr "" #: ../src/call.c:1300 msgid "doublevec" msgstr "" #: ../src/call.c:1342 msgid "imagevec" msgstr "" #: ../src/class.c:50 #, c-format msgid "Object %s is not a class." msgstr "" #: ../src/class.c:333 msgid "No such secret." msgstr "" #: ../src/class.c:334 msgid "" "Editing local classes which reference non-local objects is a bit broken at " "the moment :-(" msgstr "" #: ../src/class.c:658 #, c-format msgid "You can't have more than %d arguments to a superclass constructor." msgstr "" #: ../src/class.c:794 ../src/class.c:854 msgid "Bad superclass." msgstr "" #: ../src/class.c:795 #, c-format msgid "Superclass constructor \"%s\" refers to non-local symbols %s" msgstr "" #: ../src/class.c:803 ../src/workspace.c:1693 msgid "Wrong number of arguments." msgstr "" #: ../src/class.c:804 #, c-format msgid "Superclass constructor \"%s\" expects %d arguments, not %d." msgstr "" #: ../src/class.c:858 #, c-format msgid "First element in superclass of \"%s\" must be class or constructor." msgstr "" #: ../src/class.c:890 ../src/class.c:987 #, c-format msgid "" "Too many arguments to class constructor \"%s\". No more than %d arguments " "are supported." msgstr "" #: ../src/class.c:980 msgid "Class not found." msgstr "" #: ../src/class.c:981 #, c-format msgid "Class \"%s\" not found." msgstr "" #: ../src/class.c:1018 #, c-format msgid "Member \"%s\" of class \"%s\" should be of type \"%s\", instead it's:" msgstr "" #: ../src/classmodel.c:155 ../src/classmodel.c:228 #, c-format msgid "_%s() method not implemented for %s." msgstr "" #: ../src/classmodel.c:163 #, c-format msgid "Save %s \"%s\"" msgstr "" #: ../src/classmodel.c:237 #, c-format msgid "Replace %s \"%s\"" msgstr "" #: ../src/classmodel.c:695 msgid "Set boolean value here" msgstr "" #: ../src/classmodel.c:701 msgid "Enter a floating point number here" msgstr "" #: ../src/classmodel.c:708 msgid "Enter a string here" msgstr "" #. Expands to "Edit Toggle A1". #. #: ../src/classmodel.c:762 #, c-format msgid "Edit %s %s" msgstr "" #: ../src/classmodel.c:773 #, c-format msgid "Set %s" msgstr "" #: ../src/classmodel.c:1069 msgid "Unknown option." msgstr "" #: ../src/classmodel.c:1070 #, c-format msgid "Option \"%s\" not known." msgstr "" #: ../src/classmodel.c:1144 ../src/matrixview.c:189 ../src/matrixview.c:210 #: ../src/plot.c:140 ../src/plot.c:150 ../src/plot.c:360 ../src/plot.c:379 #: ../src/plot.c:392 msgid "Bad value." msgstr "" #: ../src/classmodel.c:1145 #, c-format msgid "%d band value only" msgstr "" #: ../src/clock.c:59 ../src/clock.c:93 ../src/clock.c:190 msgid "Interval" msgstr "" #: ../src/clock.c:60 ../src/clock.c:96 msgid "Elapsed time" msgstr "" #: ../src/clock.c:93 msgid "Interval between ticks (seconds)" msgstr "" #: ../src/clock.c:96 msgid "Elapsed time (seconds)" msgstr "" #: ../src/clock.c:100 #, c-format msgid "Edit Clock \"%s\"" msgstr "" #: ../src/clock.c:104 msgid "Set Clock" msgstr "" #: ../src/clock.c:193 ../src/colour.c:305 ../src/fontname.c:61 #: ../src/matrix.c:262 ../src/number.c:68 ../src/option.c:71 #: ../src/pathname.c:84 ../src/plot.c:340 ../src/slider.c:57 #: ../src/string.c:70 ../src/toggle.c:51 msgid "Value" msgstr "" #: ../src/colour.c:264 #, c-format msgid "Edit Color \"%s\"" msgstr "Edit Colour \"%s\"" #: ../src/colour.c:270 msgid "Set Color" msgstr "Set Colour" #: ../src/colour.c:302 msgid "Color Space" msgstr "Colour Space" #: ../src/colourdisplay.c:259 msgid "Double-click to edit this color, or drag-and-drop between colors" msgstr "Double-click to edit this colour, or drag-and-drop between colours" #: ../src/column.c:326 ../src/tool.c:867 ../src/workspace.c:1529 #: ../src/workspacegroup.c:145 msgid "Name clash." msgstr "" #: ../src/column.c:327 #, c-format msgid "Can't create column \"%s\". A column with that name already exists." msgstr "" #: ../src/column.c:364 msgid "Empty column." msgstr "" #: ../src/column.c:365 msgid "There are no objects in the current column." msgstr "" #: ../src/column.c:384 msgid "Too few items." msgstr "" #: ../src/column.c:385 #, c-format msgid "This column only has %d items, but %s needs %d items." msgstr "" #: ../src/columnview.c:133 #, c-format msgid "Save Column \"%s\"" msgstr "" #: ../src/columnview.c:180 ../src/columnview.c:241 ../src/mainw.c:1369 #: ../src/mainw.c:1407 ../src/program.c:596 ../src/program.c:625 #: ../src/program.c:1052 ../src/program.c:1093 ../src/program.c:1139 #: ../src/program.c:1171 ../src/program.c:1503 ../src/program.c:1544 #: ../src/program.c:2201 ../src/row.c:480 ../src/workspacegroup.c:177 #: ../src/workspacegroup.c:213 msgid "Name" msgstr "" #: ../src/columnview.c:181 ../src/columnview.c:243 msgid "Toolkit" msgstr "" #: ../src/columnview.c:182 ../src/columnview.c:245 ../src/matrix.c:271 #: ../src/program.c:597 ../src/program.c:627 ../src/program.c:1140 #: ../src/program.c:1173 msgid "Filename" msgstr "" #: ../src/columnview.c:241 msgid "Set menu item text here" msgstr "" #: ../src/columnview.c:243 msgid "Add to this toolkit" msgstr "" #: ../src/columnview.c:245 msgid "Store column in this file" msgstr "" #: ../src/columnview.c:248 #, c-format msgid "New Menu Item from Column \"%s\"" msgstr "" #: ../src/columnview.c:253 msgid "Menuize" msgstr "" #: ../src/columnview.c:648 msgid "Edit caption, press enter to accept changes, press escape to cancel" msgstr "" #: ../src/columnview.c:701 msgid "Enter expressions here" msgstr "" #: ../src/columnview.c:755 msgid "doubleclick to set title" msgstr "" #: ../src/columnview.c:764 msgid "Fold the column away" msgstr "" #: ../src/columnview.c:769 msgid "Open the column" msgstr "" #: ../src/columnview.c:893 msgid "Column menu" msgstr "" #: ../src/columnview.c:894 msgid "_Edit Caption" msgstr "" #: ../src/columnview.c:896 ../src/mainw.c:1708 ../src/program.c:1719 msgid "Select _All" msgstr "" #: ../src/columnview.c:903 msgid "Make Column Into _Menu Item" msgstr "" #: ../src/columnview.c:940 msgid "Left-drag to move, left-double-click to set title, right-click for menu" msgstr "" #: ../src/columnview.c:973 msgid "Delete the column" msgstr "" #: ../src/compile.c:1448 msgid "Too many shared nodes in graph." msgstr "" #: ../src/compile.c:1450 msgid "Raise MAX_RELOC" msgstr "" #: ../src/compile.c:1767 #, c-format msgid "Member \"%s\" of class \"%s\" should have no arguments." msgstr "" #: ../src/compile.c:2644 msgid "pattern match failed" msgstr "" #: ../src/conversion.c:473 msgid "not uncoded" msgstr "" #: ../src/conversion.c:1415 #, c-format msgid "Header for \"%s\"" msgstr "" #: ../src/conversion.c:1417 msgid "OK" msgstr "" #: ../src/conversionview.c:66 msgid "Unable to find image range." msgstr "" #: ../src/conversionview.c:67 msgid "Find image range failed." msgstr "" #: ../src/conversionview.c:90 msgid "Unable to scale image." msgstr "" #: ../src/conversionview.c:91 msgid "Maximum and minimum pixel values are equal." msgstr "" #. Build menu. One for each window, as we need to track falsecolour #. * etc. toggles. Could just have one, and modify pre-popup, but this #. * is easier. #. #: ../src/conversionview.c:229 msgid "Convert menu" msgstr "" #: ../src/conversionview.c:230 msgid "_Scale" msgstr "" #: ../src/conversionview.c:232 msgid "_False Color" msgstr "_False Colour" #: ../src/conversionview.c:234 msgid "_Interpret" msgstr "" #: ../src/conversionview.c:236 ../src/regionview.c:1020 msgid "_Reset" msgstr "" #: ../src/conversionview.c:238 msgid "Set As Workspace _Default" msgstr "" #: ../src/dump.c:186 ../src/expr.c:641 msgid "value" msgstr "" #: ../src/dump.c:187 msgid "parameter" msgstr "" #: ../src/dump.c:188 msgid "zombie" msgstr "" #: ../src/dump.c:189 ../src/util.c:1349 msgid "workspace" msgstr "" #: ../src/dump.c:190 msgid "workspace group" msgstr "" #: ../src/dump.c:191 msgid "root symbol" msgstr "" #: ../src/dump.c:192 msgid "external symbol" msgstr "" #: ../src/dump.c:193 msgid "built-in symbol" msgstr "" #: ../src/editview.c:79 ../src/fontnameview.c:80 ../src/formula.c:198 #: ../src/gtkutil.c:756 ../src/gtkutil.c:791 ../src/gtkutil.c:845 #: ../src/optionview.c:172 ../src/pathnameview.c:80 ../src/sliderview.c:74 #, c-format msgid "%s:" msgstr "" #: ../src/editview.c:158 msgid "Escape to cancel edit, press Return to accept edit and recalculate" msgstr "" #: ../src/error.c:60 msgid "No ierrors found." msgstr "" #: ../src/error.c:100 msgid "No unresolved symbols found." msgstr "" #: ../src/error.c:115 ../src/trace.c:230 msgid "_Clear" msgstr "" #: ../src/error.c:116 msgid "Clear ierror window" msgstr "" #: ../src/error.c:120 msgid "List _iErrors" msgstr "" #: ../src/error.c:121 msgid "Search for all ierrors" msgstr "" #: ../src/error.c:125 msgid "List _Unresolved" msgstr "" #: ../src/error.c:126 msgid "Search for all unresolved references" msgstr "" #: ../src/error.c:202 #, c-format msgid "iError - %s" msgstr "" #: ../src/expr.c:64 #, c-format msgid "error in \"%s\"" msgstr "" #: ../src/expr.c:346 msgid "Error" msgstr "" #: ../src/expr.c:613 msgid "top level" msgstr "" #: ../src/expr.c:618 msgid "class" msgstr "" #: ../src/expr.c:621 msgid "instance" msgstr "" #: ../src/expr.c:625 msgid "definition" msgstr "" #: ../src/expr.c:632 #, c-format msgid "parameter \"%s\"" msgstr "" #: ../src/expr.c:636 msgid "member" msgstr "" #: ../src/expr.c:645 ../src/itext.c:446 msgid "function" msgstr "" #: ../src/expr.c:654 msgid "of" msgstr "" #: ../src/filemodel.c:101 ../src/filemodel.c:146 ../src/filemodel.c:584 #: ../src/filemodel.c:625 ../src/model.c:314 ../src/model.c:369 #: ../src/model.c:388 #, c-format msgid "_%s() not implemented for class \"%s\"." msgstr "" #: ../src/filemodel.c:270 ../src/filemodel.c:285 ../src/model.c:419 msgid "XML library error." msgstr "" #: ../src/filemodel.c:271 msgid "model_save_filename: xmlNewDoc() failed" msgstr "" #: ../src/filemodel.c:286 msgid "model_save_filename: xmlNewDocNode() failed" msgstr "" #: ../src/filemodel.c:302 msgid "Save failed." msgstr "" #: ../src/filemodel.c:303 #, c-format msgid "" "Save of %s \"%s\" to file \"%s\" failed.\n" "%s" msgstr "" #: ../src/filemodel.c:358 msgid "filemodel_real_save_all: no save method" msgstr "" #: ../src/filemodel.c:469 ../src/filemodel.c:478 ../src/filemodel.c:491 #: ../src/mainw.c:1022 ../src/model.c:130 msgid "Load failed." msgstr "" #: ../src/filemodel.c:470 #, c-format msgid "Can't load XML file \"%s\", it's not a %s save file." msgstr "" #: ../src/filemodel.c:479 #, c-format msgid "" "Can't load XML file \"%s\", unable to extract version information from " "namespace." msgstr "" #: ../src/filemodel.c:492 #, c-format msgid "Can't load XML file \"%s\", the file does not contain a %s." msgstr "" #. Expands to (eg.) "Save Column A2". #. #: ../src/filemodel.c:677 #, c-format msgid "Save %s %s" msgstr "" #: ../src/filemodel.c:753 ../src/filemodel.c:765 msgid "Object has been modified." msgstr "" #: ../src/filemodel.c:754 #, c-format msgid "" "%s \"%s\" has been modified since you loaded it from file \"%s\".\n" "\n" "Do you want to save your changes?" msgstr "" #: ../src/filemodel.c:766 #, c-format msgid "%s \"%s\" has been modified. Do you want to save your changes?" msgstr "" #: ../src/filesel.c:86 msgid "Workspace files (*.ws)" msgstr "" #: ../src/filesel.c:88 msgid "Recombination matrix files (*.rec)" msgstr "" #: ../src/filesel.c:90 msgid "Morphology matrix files (*.mor)" msgstr "" #: ../src/filesel.c:92 msgid "Convolution matrix files (*.con)" msgstr "" #: ../src/filesel.c:94 msgid "Matrix files (*.mat)" msgstr "" #: ../src/filesel.c:96 msgid "Definition files (*.def)" msgstr "" #: ../src/filesel.c:98 msgid "ICC profiles (*.icc, *.icm)" msgstr "" #: ../src/filesel.c:100 msgid "All files (*)" msgstr "" #. Used as eg. "VIPS image files (*.v)" #. #: ../src/filesel.c:133 msgid "image files" msgstr "" #: ../src/filesel.c:500 #, c-format msgid "Unable to determine space free in \"%s\"." msgstr "" #. Expands to (eg.) '6GB free in "/pics/tmp"' #. #: ../src/filesel.c:511 #, c-format msgid "free in \"%s\"" msgstr "" #: ../src/filesel.c:759 ../src/util.c:1932 ../src/util.c:1938 msgid "Bad filename." msgstr "" #: ../src/filesel.c:760 msgid "No file selected." msgstr "" #: ../src/filesel.c:973 msgid "Increment filename" msgstr "" #: ../src/filesel.c:979 msgid "After Save, add 1 to the last number in the file name" msgstr "" #: ../src/filesel.c:1220 #, c-format msgid "%s Save Preferences" msgstr "" #: ../src/filesel.c:1281 msgid "Overwrite" msgstr "" #: ../src/filesel.c:1282 msgid "Overwrite file?" msgstr "" #: ../src/filesel.c:1283 #, c-format msgid "File \"%s\" exists. OK to overwrite?" msgstr "" #: ../src/fontname.c:58 ../src/mainw.c:1370 ../src/mainw.c:1409 #: ../src/number.c:65 ../src/option.c:65 ../src/pathname.c:81 #: ../src/program.c:1053 ../src/program.c:1095 ../src/slider.c:48 #: ../src/string.c:67 ../src/toggle.c:48 ../src/workspacegroup.c:178 #: ../src/workspacegroup.c:215 msgid "Caption" msgstr "" #: ../src/formula.c:143 msgid "" "Press Escape to cancel edit, press Return to accept edit and recalculate" msgstr "" #: ../src/gtkutil.c:608 msgid "Bad identifier." msgstr "" #: ../src/gtkutil.c:610 msgid "" "Enter an identifier. Identifiers start with a letter, and then contain only " "letters, numbers, apostrophy and underscore." msgstr "" #: ../src/gtkutil.c:663 ../src/gtkutil.c:671 ../src/matrixview.c:96 msgid "Bad floating point number." msgstr "" #: ../src/gtkutil.c:664 ../src/matrixview.c:97 #, c-format msgid "\"%s\" is not a floating point number." msgstr "" #: ../src/gtkutil.c:672 #, c-format msgid "Extra characters \"%s\" after number." msgstr "" #: ../src/gtkutil.c:696 msgid "Bad integer." msgstr "" #: ../src/gtkutil.c:697 #, c-format msgid "\"%s\" is not an integer." msgstr "" #: ../src/gtkutil.c:715 msgid "Bad unsigned integer." msgstr "" #: ../src/gtkutil.c:731 msgid "Bad positive integer." msgstr "" #: ../src/gtkutil.c:853 ../src/toggleview.c:106 msgid "Left-click to change value" msgstr "" #: ../src/heap.c:812 msgid "Heap full." msgstr "" #: ../src/heap.c:818 #, c-format msgid "" "The compile heap for %s has filled. Make it smaller and less complicated." msgstr "" #: ../src/heap.c:823 msgid "" "The main calculation heap has filled. Raise the heap size limit in " "Preferences." msgstr "" #: ../src/heap.c:1852 msgid "Unimplemented list type." msgstr "" #: ../src/heap.c:1947 msgid "Unimplemented type." msgstr "" #: ../src/heap.c:1948 #, c-format msgid "Unable to convert %s to a nip type." msgstr "" #: ../src/heap.c:2111 msgid "circular" msgstr "" #: ../src/heap.c:2116 #, c-format msgid "circular to label %d" msgstr "" #: ../src/heap.c:2126 #, c-format msgid "label %d" msgstr "" #: ../src/heap.c:2143 msgid "unevaluated" msgstr "" #: ../src/heap.c:2178 #, c-format msgid "class (%p)" msgstr "" #: ../src/heap.c:2189 msgid "members" msgstr "" #: ../src/heap.c:2200 msgid "secret" msgstr "" #: ../src/heap.c:2253 #, c-format msgid "no value (type %d)" msgstr "" #: ../src/heap.c:2261 msgid "NULL pointer" msgstr "" #: ../src/heap.c:2270 msgid "symbol" msgstr "" #: ../src/heap.c:2278 msgid "constructor" msgstr "" #: ../src/heap.c:2286 msgid "symref" msgstr "" #: ../src/heap.c:2294 msgid "compileref" msgstr "" #: ../src/heap.c:2322 #, c-format msgid "tag \"%s\"" msgstr "" #: ../src/heap.c:2337 #, c-format msgid "unknown element tag %d" msgstr "" #: ../src/iarrow.c:117 msgid "No image" msgstr "" #. Used in (eg.) "Mark at (10, 10) on [A1, A2]" #. #. Expands to (eg.) "Region on A1 at (10, 10), size (50, 50)" #. #: ../src/iarrow.c:130 ../src/iregion.c:156 msgid "on" msgstr "" #: ../src/iarrow.c:148 ../src/iarrow.c:153 #, c-format msgid "at %d" msgstr "" #: ../src/iarrow.c:158 #, c-format msgid "at (%d, %d)" msgstr "" #: ../src/iarrow.c:165 #, c-format msgid "at (%d, %d), offset (%d, %d)" msgstr "" #: ../src/idialog.c:432 msgid "Pin up" msgstr "" #: ../src/idialog.c:434 msgid "Check this to pin the dialog up" msgstr "" #: ../src/iimage.c:115 msgid "Original filename" msgstr "" #: ../src/iimage.c:338 msgid "Save timer." msgstr "" #: ../src/iimage.c:339 #, c-format msgid "Image save took %g seconds." msgstr "" #: ../src/imageinfo.c:676 msgid "User cancelled operation" msgstr "" #: ../src/imageinfo.c:976 msgid "Unable to open image." msgstr "" #: ../src/imageinfo.c:977 #, c-format msgid "Unable to open file \"%s\" as image." msgstr "" #: ../src/imageinfo.c:1105 msgid "Unable to write to file." msgstr "" #: ../src/imageinfo.c:1106 #, c-format msgid "Error writing image to file \"%s\"." msgstr "" #: ../src/imageinfo.c:1122 msgid "Unable to paint on image." msgstr "" #: ../src/imageinfo.c:1123 #, c-format msgid "" "Unable to get write permission for file \"%s\".\n" "Check permission settings." msgstr "" #: ../src/imageinfo.c:1167 msgid "Modify" msgstr "" #: ../src/imageinfo.c:1168 msgid "Modify disc file?" msgstr "" #: ../src/imageinfo.c:1169 #, c-format msgid "" "This image is being shown directly from the disc file:\n" "\n" " %s\n" "\n" "If you paint on this file, it will be permanently changed. If something goes " "wrong, you may lose work. Are you sure you want to modify this file?" msgstr "" #: ../src/imageinfo.c:1771 msgid "Unable to paint text." msgstr "" #: ../src/imageinfo.c:1772 #, c-format msgid "Unable to paint text \"%s\" in font \"%s\"." msgstr "" #: ../src/imagemodel.c:510 msgid "No text specified." msgstr "" #: ../src/imagemodel.c:511 msgid "Enter some text to paint in the entry widget at the top of the window." msgstr "" #. Need one menu per image window (could have a single menu for all #. * windows, but then we'd have to set the state of the toggle buttons #. * before mapping) #. #: ../src/imagepresent.c:1579 msgid "Ruler menu" msgstr "" #: ../src/imagepresent.c:1580 msgid "Rulers In _mm" msgstr "" #: ../src/imagepresent.c:1582 msgid "Show _Offset" msgstr "" #: ../src/imageview.c:457 msgid "New _Mark" msgstr "" #: ../src/imageview.c:458 msgid "Create a new mark" msgstr "" #: ../src/imageview.c:462 msgid "New _Horizontal Guide" msgstr "" #: ../src/imageview.c:463 msgid "Create a new horizontal guide" msgstr "" #: ../src/imageview.c:467 msgid "New _Vertical Guide" msgstr "" #: ../src/imageview.c:468 msgid "Create a new vertical guide" msgstr "" #: ../src/imageview.c:472 msgid "New _Arrow" msgstr "" #: ../src/imageview.c:473 msgid "Create a new arrow" msgstr "" #: ../src/imageview.c:477 msgid "New _Region" msgstr "" #: ../src/imageview.c:478 msgid "Create a new region" msgstr "" #: ../src/imageview.c:482 msgid "Replace Image" msgstr "" #: ../src/imageview.c:483 msgid "Replace image from file" msgstr "" #: ../src/imageview.c:487 msgid "Save Image As" msgstr "" #: ../src/imageview.c:488 msgid "Save image to file" msgstr "" #: ../src/imageview.c:492 ../src/mainw.c:868 msgid "Recalculate" msgstr "" #: ../src/imageview.c:493 msgid "Recalculate image" msgstr "" #: ../src/imageview.c:497 msgid "Image _Header" msgstr "" #: ../src/imageview.c:498 msgid "View image header" msgstr "" #: ../src/imageview.c:502 ../src/imageview.c:556 msgid "Zoom _In" msgstr "" #: ../src/imageview.c:503 ../src/imageview.c:557 msgid "Zoom in on mouse cursor" msgstr "" #: ../src/imageview.c:507 ../src/imageview.c:561 msgid "Zoom _Out" msgstr "" #. IMAGEMODEL_MAGIN #: ../src/imageview.c:508 ../src/imageview.c:562 ../src/paintboxview.c:249 msgid "Zoom out" msgstr "" #: ../src/imageview.c:512 msgid "Zoom _100%" msgstr "" #: ../src/imageview.c:513 ../src/imageview.c:576 msgid "Zoom to 100%" msgstr "" #: ../src/imageview.c:517 msgid "Zoom to _Fit" msgstr "" #: ../src/imageview.c:518 msgid "Zoom to fit image to window" msgstr "" #: ../src/imageview.c:524 ../src/plotwindow.c:167 msgid "_Status" msgstr "" #: ../src/imageview.c:525 ../src/plotwindow.c:168 msgid "Show status bar" msgstr "" #: ../src/imageview.c:529 msgid "_Display Control" msgstr "" #: ../src/imageview.c:530 msgid "Show display control bar" msgstr "" #: ../src/imageview.c:534 msgid "_Paint" msgstr "" #: ../src/imageview.c:535 msgid "Show paint bar" msgstr "" #: ../src/imageview.c:539 msgid "_Rulers" msgstr "" #: ../src/imageview.c:540 msgid "Show rulers" msgstr "" #: ../src/imageview.c:546 msgid "_Select" msgstr "" #: ../src/imageview.c:547 msgid "Select and modify selections" msgstr "" #: ../src/imageview.c:551 msgid "_Pan" msgstr "" #: ../src/imageview.c:552 msgid "Pan image" msgstr "" #: ../src/imageview.c:568 msgid "6%" msgstr "" #: ../src/imageview.c:568 msgid "Zoom to 6%" msgstr "" #: ../src/imageview.c:570 msgid "12%" msgstr "" #: ../src/imageview.c:570 msgid "Zoom to 12%" msgstr "" #: ../src/imageview.c:572 msgid "25%" msgstr "" #: ../src/imageview.c:572 msgid "Zoom to 25%" msgstr "" #: ../src/imageview.c:574 msgid "50%" msgstr "" #: ../src/imageview.c:574 msgid "Zoom to 50%" msgstr "" #: ../src/imageview.c:576 msgid "100%" msgstr "" #: ../src/imageview.c:578 msgid "200%" msgstr "" #: ../src/imageview.c:578 msgid "Zoom to 200%" msgstr "" #: ../src/imageview.c:580 msgid "400%" msgstr "" #: ../src/imageview.c:580 msgid "Zoom to 400%" msgstr "" #: ../src/imageview.c:582 msgid "800%" msgstr "" #: ../src/imageview.c:582 msgid "Zoom to 800%" msgstr "" #: ../src/imageview.c:584 msgid "1600%" msgstr "" #: ../src/imageview.c:584 msgid "Zoom to 1600%" msgstr "" #: ../src/iregion.c:166 #, c-format msgid "at (%d, %d), size (%d, %d)" msgstr "" #: ../src/iregion.c:181 ../src/iregion.c:223 msgid "Left" msgstr "" #: ../src/iregion.c:182 ../src/iregion.c:226 msgid "Top" msgstr "" #: ../src/iregion.c:183 ../src/iregion.c:229 msgid "Width" msgstr "" #: ../src/iregion.c:184 ../src/iregion.c:232 msgid "Height" msgstr "" #: ../src/iregion.c:223 msgid "Left edge of region" msgstr "" #: ../src/iregion.c:226 msgid "Top edge of region" msgstr "" #: ../src/iregion.c:229 msgid "Width of region" msgstr "" #: ../src/iregion.c:232 msgid "Height of region" msgstr "" #: ../src/iregion.c:237 #, c-format msgid "Edit \"%s\"" msgstr "" #: ../src/iregion.c:241 msgid "Set Region" msgstr "" #: ../src/itext.c:67 msgid "Formula" msgstr "" #: ../src/itext.c:184 ../src/itext.c:325 msgid "no value" msgstr "" #: ../src/itext.c:503 ../src/itext.c:536 msgid "Dirty value" msgstr "" #. Common menus. #. #: ../src/iwindow.c:659 msgid "_File" msgstr "" #: ../src/iwindow.c:660 msgid "_New" msgstr "" #: ../src/iwindow.c:661 ../src/mainw.c:1765 ../src/program.c:727 #: ../src/regionview.c:1016 ../src/rowview.c:586 msgid "_Edit" msgstr "" #: ../src/iwindow.c:662 msgid "_View" msgstr "" #: ../src/iwindow.c:663 msgid "_Help" msgstr "" #: ../src/iwindow.c:668 msgid "_Close" msgstr "" #: ../src/iwindow.c:669 msgid "Close" msgstr "" #: ../src/iwindow.c:673 msgid "_Quit" msgstr "" #: ../src/iwindow.c:674 msgid "Quit nip2" msgstr "" #: ../src/iwindow.c:677 msgid "_Contents" msgstr "" #: ../src/iwindow.c:678 msgid "Open the users guide" msgstr "" #: ../src/iwindow.c:682 msgid "_About" msgstr "" #: ../src/iwindow.c:683 msgid "About this program" msgstr "" #: ../src/iwindow.c:687 msgid "_Website" msgstr "" #: ../src/iwindow.c:688 msgid "Open the VIPS Homepage" msgstr "" #: lex.l:91 lex.l:101 msgid "line too long" msgstr "" #: lex.l:109 msgid "end of line inside string" msgstr "" #: lex.l:111 msgid "no end of string" msgstr "" #: lex.l:132 lex.l:142 lex.l:150 msgid "bad char constant" msgstr "" #: lex.l:175 msgid "nested comment" msgstr "" #: lex.l:181 msgid "no end of comment" msgstr "" #: lex.l:311 #, c-format msgid "bad number %s" msgstr "" #: lex.l:364 #, c-format msgid "illegal character \"%c\"" msgstr "" #: ../src/link.c:578 msgid "Circular dependency." msgstr "" #: ../src/link.c:579 #, c-format msgid "Circular dependency detected near symbol \"%s\"." msgstr "" #: ../src/main.c:116 msgid "evaluate and print EXPRESSION" msgstr "" #: ../src/main.c:119 msgid "load FILE as a set of definitions" msgstr "" #: ../src/main.c:122 msgid "write value of 'main' to FILE" msgstr "" #: ../src/main.c:124 msgid "run in batch mode" msgstr "" #: ../src/main.c:126 msgid "set values" msgstr "" #: ../src/main.c:128 msgid "verbose error output" msgstr "" #: ../src/main.c:131 msgid "don't load menu definitions" msgstr "" #: ../src/main.c:133 msgid "don't try to load command-line arguments" msgstr "" #: ../src/main.c:135 msgid "load stdin as a workspace" msgstr "" #: ../src/main.c:137 msgid "load stdin as a set of definitions" msgstr "" #: ../src/main.c:139 msgid "print value of 'main' to stdout" msgstr "" #: ../src/main.c:142 msgid "start up and shut down" msgstr "" #: ../src/main.c:145 msgid "time image save operations" msgstr "" #: ../src/main.c:148 msgid "start as if installed to PREFIX" msgstr "" #: ../src/main.c:150 msgid "output strings for internationalisation" msgstr "" #: ../src/main.c:153 msgid "print version number" msgstr "" #: ../src/main.c:156 msgid "test for errors and quit" msgstr "" #: ../src/main.c:235 #, c-format msgid "error calculating \"%s\"" msgstr "" #: ../src/main.c:243 #, c-format msgid "error saving \"%s\"" msgstr "" #: ../src/main.c:297 msgid "no \"main\" found" msgstr "" #: ../src/main.c:475 msgid "Unknown file type." msgstr "" #: ../src/main.c:476 #, c-format msgid "Unable to load \"%s\"." msgstr "" #: ../src/main.c:487 msgid "Unable to load." msgstr "" #: ../src/main.c:488 #, c-format msgid "Error loading plug-in \"%s\"." msgstr "" #: ../src/main.c:696 msgid "Next _Error" msgstr "" #: ../src/main.c:697 msgid "Ink dropper" msgstr "" #: ../src/main.c:698 msgid "D_uplicate" msgstr "" #: ../src/main.c:699 msgid "Pen" msgstr "" #: ../src/main.c:700 ../src/plot.c:94 msgid "Line" msgstr "" #: ../src/main.c:701 ../src/matrix.c:149 msgid "Text" msgstr "" #. IMAGEMODEL_TEXT #: ../src/main.c:702 ../src/paintboxview.c:259 msgid "Smudge" msgstr "" #: ../src/main.c:703 msgid "Flood" msgstr "" #: ../src/main.c:704 msgid "Flood Blob" msgstr "" #: ../src/main.c:705 msgid "Fill Rectangle" msgstr "" #: ../src/main.c:706 msgid "Pan" msgstr "" #: ../src/main.c:707 msgid "Select" msgstr "" #. And the LEDs we use. #. #: ../src/main.c:711 msgid "Red LED" msgstr "" #: ../src/main.c:712 msgid "Green LED" msgstr "" #: ../src/main.c:713 msgid "Blue LED" msgstr "" #: ../src/main.c:714 msgid "Yellow LED" msgstr "" #: ../src/main.c:715 msgid "Cyan LED" msgstr "" #: ../src/main.c:716 msgid "Off LED" msgstr "" #: ../src/main.c:895 msgid "Empty temp area" msgstr "" #: ../src/main.c:896 msgid "Many files in temp area." msgstr "" #: ../src/main.c:897 #, c-format msgid "" "The temp area \"%s\" contains %s of files. Would you like to empty the temp " "area? This will delete any workspace backups and cannot be undone." msgstr "" #: ../src/main.c:913 #, c-format msgid "unable to make %s %s: %s" msgstr "" #: ../src/main.c:1095 msgid "- image processing spreadsheet" msgstr "" #: ../src/main.c:1127 #, c-format msgid "linked to vips-%s" msgstr "" #. -1 means can't-be-set, at least on os x, so don't #. * warn. #. #: ../src/main.c:1187 #, c-format msgid "" "unable to change max file descriptors\n" "max file descriptors still set to %d" msgstr "" #: ../src/main.c:1193 msgid "unable to read max file descriptors" msgstr "" #: ../src/main.c:1417 ../src/main.c:1463 #, c-format msgid "" "Startup error log:\n" "%s" msgstr "" #: ../src/main.c:1462 msgid "Startup error." msgstr "" #: ../src/main.c:1473 #, c-format msgid "Welcome to %s-%s!" msgstr "" #: ../src/main.c:1478 #, c-format msgid "" "A new directory has been created to hold startup, data and temporary files:\n" "\n" " %s\n" "\n" "If you've used previous versions of %s, you might want to copy files over " "from your old work area." msgstr "" #: ../src/mainw.c:173 msgid "Compatibility mode." msgstr "" #: ../src/mainw.c:174 #, c-format msgid "" "This workspace was created by version %d.%d.%d. A set of compatibility menus " "have been loaded for this window." msgstr "" #: ../src/mainw.c:350 msgid "No temp area" msgstr "" #: ../src/mainw.c:356 #, c-format msgid "%s free" msgstr "" #: ../src/mainw.c:369 #, c-format msgid "%d cells free" msgstr "" #. Display select message instead. #. #: ../src/mainw.c:384 msgid "Selected:" msgstr "" #: ../src/mainw.c:414 msgid "compatibility mode" msgstr "" #: ../src/mainw.c:424 msgid "unsaved workspace" msgstr "" #. Expands to (eg.) "14GB free in /pics/tmp" #: ../src/mainw.c:607 #, c-format msgid " in \"%s\"" msgstr "" #: ../src/mainw.c:611 #, c-format msgid "%d cells in heap, %d cells free, %d cells maximum" msgstr "" #: ../src/mainw.c:615 #, c-format msgid "%d objects in workspace" msgstr "" #: ../src/mainw.c:619 #, c-format msgid "%d vips calls cached" msgstr "" #: ../src/mainw.c:623 #, c-format msgid "using %d threads" msgstr "" #: ../src/mainw.c:755 msgid "Find in workspace not implemented yet." msgstr "" #: ../src/mainw.c:763 msgid "Find again in workspace not implemented yet." msgstr "" #: ../src/mainw.c:798 msgid "No errors." msgstr "" #: ../src/mainw.c:799 msgid "There are no errors (that I can see) in this workspace." msgstr "" #: ../src/mainw.c:869 msgid "Completely recalculate?" msgstr "" #: ../src/mainw.c:1023 #, c-format msgid "" "Unable to execute:\n" " %s" msgstr "" #: ../src/mainw.c:1041 ../src/mainw.c:1074 msgid "Open File" msgstr "" #: ../src/mainw.c:1188 msgid "Recent Images" msgstr "" #: ../src/mainw.c:1196 msgid "Recent Workspaces" msgstr "" #: ../src/mainw.c:1204 msgid "Recent Matricies" msgstr "" #: ../src/mainw.c:1213 msgid "No recent items" msgstr "" #: ../src/mainw.c:1219 msgid "Clear Recent Menu" msgstr "" #: ../src/mainw.c:1279 msgid "Merge Workspace from File" msgstr "" #: ../src/mainw.c:1407 msgid "Set column name here" msgstr "" #: ../src/mainw.c:1409 msgid "Set column caption here" msgstr "" #: ../src/mainw.c:1411 msgid "New Column" msgstr "" #: ../src/mainw.c:1415 msgid "Create Column" msgstr "" #: ../src/mainw.c:1554 msgid "Revert to Defaults" msgstr "" #: ../src/mainw.c:1555 msgid "Revert to installation defaults?" msgstr "" #: ../src/mainw.c:1556 msgid "" "Would you like to reset all preferences to their factory settings? This will " "delete any changes you have ever made to your preferences and may take a few " "seconds." msgstr "" #: ../src/mainw.c:1573 msgid "Preferences" msgstr "" #: ../src/mainw.c:1578 msgid "Revert to Defaults ..." msgstr "" #. Menu items. #. #: ../src/mainw.c:1641 msgid "Open _Recent" msgstr "" #: ../src/mainw.c:1642 ../src/mainw.c:2107 msgid "Jump to _Column" msgstr "" #: ../src/mainw.c:1643 msgid "_Toolkits" msgstr "" #: ../src/mainw.c:1653 ../src/mainw.c:2104 msgid "New C_olumn" msgstr "" #: ../src/mainw.c:1654 msgid "Create a new column" msgstr "" #: ../src/mainw.c:1658 msgid "New Named C_olumn" msgstr "" #: ../src/mainw.c:1659 msgid "Create a new column with a specified name" msgstr "" #: ../src/mainw.c:1663 ../src/program.c:1669 msgid "New _Workspace" msgstr "" #: ../src/mainw.c:1664 msgid "Create a new workspace" msgstr "" #: ../src/mainw.c:1668 msgid "_Open" msgstr "" #: ../src/mainw.c:1669 msgid "Open a file" msgstr "" #: ../src/mainw.c:1673 msgid "Open _Examples" msgstr "" #: ../src/mainw.c:1674 msgid "Open example workspaces" msgstr "" #: ../src/mainw.c:1678 msgid "_Duplicate Workspace" msgstr "" #: ../src/mainw.c:1679 msgid "Duplicate workspace" msgstr "" #: ../src/mainw.c:1683 msgid "_Merge Workspace" msgstr "" #: ../src/mainw.c:1684 msgid "Merge workspace into this workspace" msgstr "" #: ../src/mainw.c:1688 msgid "_Save Workspace" msgstr "" #: ../src/mainw.c:1689 msgid "Save workspace" msgstr "" #: ../src/mainw.c:1693 msgid "_Save Workspace As" msgstr "" #: ../src/mainw.c:1694 msgid "Save workspace as" msgstr "" #: ../src/mainw.c:1698 msgid "Search for Workspace _Backups" msgstr "" #: ../src/mainw.c:1699 msgid "Load last automatically backed-up workspace" msgstr "" #: ../src/mainw.c:1703 ../src/program.c:1714 msgid "_Delete" msgstr "" #: ../src/mainw.c:1704 msgid "Delete selected items" msgstr "" #: ../src/mainw.c:1709 msgid "Select all items" msgstr "" #: ../src/mainw.c:1713 msgid "D_uplicate Selected" msgstr "" #: ../src/mainw.c:1714 msgid "Duplicate selected items" msgstr "" #: ../src/mainw.c:1718 ../src/rowview.c:596 msgid "_Recalculate" msgstr "" #: ../src/mainw.c:1719 msgid "Recalculate selected items" msgstr "" #: ../src/mainw.c:1723 ../src/mainw.c:2108 msgid "Align _Columns" msgstr "" #: ../src/mainw.c:1724 msgid "Align columns to grid" msgstr "" #: ../src/mainw.c:1728 ../src/program.c:1739 msgid "_Find" msgstr "" #: ../src/mainw.c:1729 msgid "Find in workspace" msgstr "" #: ../src/mainw.c:1733 ../src/program.c:1744 msgid "Find _Next" msgstr "" #: ../src/mainw.c:1734 msgid "Find again in workspace" msgstr "" #: ../src/mainw.c:1739 msgid "Jump to next error" msgstr "" #: ../src/mainw.c:1743 msgid "_Group" msgstr "" #: ../src/mainw.c:1744 msgid "Group selected items" msgstr "" #: ../src/mainw.c:1748 ../src/rowview.c:590 msgid "U_ngroup" msgstr "" #: ../src/mainw.c:1749 msgid "Ungroup selected items" msgstr "" #: ../src/mainw.c:1753 msgid "_Preferences" msgstr "" #: ../src/mainw.c:1754 msgid "Edit preferences" msgstr "" #: ../src/mainw.c:1759 msgid "Workspace as Grap_h" msgstr "" #: ../src/mainw.c:1760 msgid "Show a graph of workspace dependencies" msgstr "" #: ../src/mainw.c:1766 msgid "Edit toolkits" msgstr "" #: ../src/mainw.c:1772 msgid "Au_to Recalculate" msgstr "" #: ../src/mainw.c:1773 msgid "Recalculate automatically on change" msgstr "" #: ../src/mainw.c:1777 msgid "_Toolbar" msgstr "" #: ../src/mainw.c:1778 msgid "Show window toolbar" msgstr "" #: ../src/mainw.c:1782 msgid "_Statusbar" msgstr "" #: ../src/mainw.c:1783 msgid "Show window statusbar" msgstr "" #: ../src/mainw.c:1787 msgid "Toolkit _Browser" msgstr "" #: ../src/mainw.c:1788 msgid "Show toolkit browser" msgstr "" #: ../src/mainw.c:1792 msgid "Workspace _Definitions" msgstr "" #: ../src/mainw.c:1793 msgid "Show workspace definitions" msgstr "" #: ../src/mainw.c:1799 msgid "_Normal" msgstr "" #: ../src/mainw.c:1800 msgid "Normal view mode" msgstr "" #: ../src/mainw.c:1804 msgid "Show _Formula" msgstr "" #: ../src/mainw.c:1805 msgid "Show formula view mode" msgstr "" #: ../src/mainw.c:1809 msgid "No _Edits" msgstr "" #: ../src/mainw.c:1810 msgid "No edits view mode" msgstr "" #: ../src/mainw.c:2103 msgid "Workspace menu" msgstr "" #: ../src/mainw.c:2113 msgid "_Merge Workspace from File" msgstr "" #: ../src/mainw.c:2116 msgid "_Group Selected" msgstr "" #. Toolkit Browser pane. #. #: ../src/mainw.c:2125 msgid "Toolkit Browser" msgstr "" #. Workspace-local defs pane. #. #: ../src/mainw.c:2144 msgid "Workspace Definitions" msgstr "" #: ../src/matrix.c:150 msgid "Sliders" msgstr "" #: ../src/matrix.c:151 msgid "Toggle buttons" msgstr "" #: ../src/matrix.c:152 msgid "Text, plus scale and offset" msgstr "" #: ../src/matrix.c:163 msgid "Display as" msgstr "" #: ../src/matrix.c:194 #, c-format msgid "Edit Matrix \"%s\"" msgstr "" #: ../src/matrix.c:199 msgid "Set Matrix" msgstr "" #: ../src/matrix.c:265 ../src/matrixview.c:425 msgid "Scale" msgstr "" #: ../src/matrix.c:268 ../src/matrixview.c:430 msgid "Offset" msgstr "" #: ../src/matrix.c:274 msgid "Display" msgstr "" #: ../src/matrixview.c:190 ../src/matrixview.c:211 #, c-format msgid "" "Cell (%d, %d):\n" "%s" msgstr "" #. Expands to (eg) "A2: cell (1,2): 45" ... status line display during #. * matrix traverse. #. #: ../src/matrixview.c:622 #, c-format msgid ": cell (%d, %d): %s" msgstr "" #: ../src/model.c:131 #, c-format msgid "" "Unable to load from file \"%s\". Error log is:\n" "%s" msgstr "" #: ../src/model.c:420 msgid "model_save: xmlNewChild() failed" msgstr "" #: ../src/model.c:487 msgid "XML load error." msgstr "" #: ../src/model.c:488 #, c-format msgid "Can't load node of type \"%s\" into object of type \"%s\"" msgstr "" #: ../src/model.c:716 msgid "Delete?" msgstr "" #: ../src/model.c:717 #, c-format msgid "Are you sure you want to delete %s \"%s\"?" msgstr "" #: ../src/option.c:68 msgid "Labels" msgstr "" #. Create signals. #. #. Init methods. #. #: ../src/paintboxview.c:109 msgid "Paintbox bar menu" msgstr "" #: ../src/paintboxview.c:210 msgid "Clear undo history?" msgstr "" #: ../src/paintboxview.c:211 msgid "" "Are you sure you want to clear all undo and redo? This will free up memory, " "but you will no longer be able to undo or redo any of the painting you have " "done so far." msgstr "" #: ../src/paintboxview.c:246 msgid "Manipulate regions" msgstr "" #. IMAGEMODEL_SELECT #: ../src/paintboxview.c:247 msgid "Pan window" msgstr "" #. IMAGEMODEL_PAN #: ../src/paintboxview.c:248 msgid "Zoom in on mouse" msgstr "" #. IMAGEMODEL_MAGOUT #: ../src/paintboxview.c:250 msgid "Read pixel into inkwell" msgstr "" #. IMAGEMODEL_DROPPER #: ../src/paintboxview.c:251 msgid "Freehand draw " msgstr "" #. IMAGEMODEL_PEN #: ../src/paintboxview.c:252 msgid "Draw straight lines" msgstr "" #. IMAGEMODEL_LINE #: ../src/paintboxview.c:253 msgid "Fill rectangles" msgstr "" #. IMAGEMODEL_RECT #: ../src/paintboxview.c:254 msgid "Flood while pixel not equal to ink" msgstr "" #. IMAGEMODEL_FLOOD #: ../src/paintboxview.c:256 msgid "Flood while pixel equal to click" msgstr "" #. IMAGEMODEL_BLOB #: ../src/paintboxview.c:258 msgid "Draw text" msgstr "" #: ../src/paintboxview.c:309 msgid "Undo last paint action" msgstr "" #: ../src/paintboxview.c:318 msgid "Redo last paint action" msgstr "" #: ../src/paintboxview.c:327 msgid "Clear all undo and redo buffers" msgstr "" #: ../src/paintboxview.c:376 msgid "Enter text for text tool" msgstr "" #: ../src/panechild.c:108 msgid "Close the pane" msgstr "" #: parse.y:244 parse.y:255 msgid "not top level" msgstr "" #: parse.y:260 msgid "not strings" msgstr "" #: parse.y:318 msgid "left-hand-side pattern contains no identifiers" msgstr "" #: parse.y:1064 ../src/program.c:1421 msgid "Parse error." msgstr "" #: parse.y:1067 #, c-format msgid "Error in %s: %s" msgstr "" #: parse.y:1070 #, c-format msgid "Error: %s" msgstr "" #: parse.y:1183 msgid "definition is too long" msgstr "" #: parse.y:1607 msgid "no leading identifier" msgstr "" #: parse.y:1613 msgid "'=' missing" msgstr "" #: parse.y:1643 msgid "identifier expected" msgstr "" #: parse.y:1653 #, c-format msgid "'%s' does not exist" msgstr "" #: parse.y:1655 #, c-format msgid "'%s' has no members" msgstr "" #: parse.y:1670 msgid "'.' or '=' expected" msgstr "" #. Not found? Maybe - error message anyway. #. #: ../src/path.c:332 ../src/path.c:360 ../src/program.c:1440 #: ../src/program.c:1492 ../src/program.c:1514 ../src/program.c:1522 #: ../src/symbol.c:502 msgid "Not found." msgstr "" #: ../src/path.c:333 #, c-format msgid "File \"%s\" not found." msgstr "" #: ../src/path.c:361 #, c-format msgid "File \"%s\" not found on path" msgstr "" #: ../src/pathnameview.c:173 msgid "Select a new file name" msgstr "" #: ../src/plot.c:80 msgid "YYYY" msgstr "" #: ../src/plot.c:81 msgid "XYYY" msgstr "" #: ../src/plot.c:82 msgid "XYXY" msgstr "" #: ../src/plot.c:93 msgid "Point" msgstr "" #: ../src/plot.c:95 msgid "Spline" msgstr "" #: ../src/plot.c:96 msgid "Bar" msgstr "" #: ../src/plot.c:141 msgid "More than one column needed or XY plots" msgstr "" #: ../src/plot.c:151 msgid "Even number of columns only for XY format plots" msgstr "" #: ../src/plot.c:316 msgid "Format" msgstr "" #: ../src/plot.c:319 msgid "Style" msgstr "" #: ../src/plot.c:322 msgid "Xmin" msgstr "" #: ../src/plot.c:325 msgid "Xmax" msgstr "" #: ../src/plot.c:328 msgid "Ymin" msgstr "" #: ../src/plot.c:331 msgid "Ymax" msgstr "" #: ../src/plot.c:337 msgid "Options" msgstr "" #: ../src/plot.c:361 msgid "1xn or nx1 images only for Plot" msgstr "" #: ../src/plot.c:380 msgid "Unable to prepare image." msgstr "" #: ../src/plot.c:393 msgid "1xn or nx1 images only" msgstr "" #. Create signals. #. #. Init methods. #. #: ../src/plotstatus.c:99 ../src/statusview.c:108 msgid "Status bar menu" msgstr "" #: ../src/plotstatus.c:190 ../src/statusview.c:223 ../src/statusview.c:226 msgid "Magnification" msgstr "" #. Probably failed to load prefs on startup for some reason. #. #: ../src/prefs.c:207 msgid "Unable to display preferences." msgstr "" #: ../src/prefs.c:208 #, c-format msgid "" "No preferences workspace was found. Preferences probably failed to load when " "%s started." msgstr "" #: ../src/program.c:73 msgid "Edit window" msgstr "" #: ../src/program.c:263 ../src/workspacedefs.c:108 msgid "modified" msgstr "" #: ../src/program.c:625 msgid "Menu item text" msgstr "" #: ../src/program.c:628 msgid "Load column from this file" msgstr "" #: ../src/program.c:630 #, c-format msgid "Edit Column Item \"%s\"" msgstr "" #: ../src/program.c:635 msgid "Set column item" msgstr "" #: ../src/program.c:656 ../src/program.c:662 msgid "Unable to save." msgstr "" #: ../src/program.c:657 msgid "You can only save toolkits, not tools." msgstr "" #: ../src/program.c:663 msgid "You can't save auto-generated toolkits." msgstr "" #. Create signals. #. #. Init methods. #. #: ../src/program.c:726 msgid "Toolkit menu" msgstr "" #: ../src/program.c:1093 msgid "Set toolkit name here" msgstr "" #: ../src/program.c:1095 msgid "Set toolkit caption here" msgstr "" #: ../src/program.c:1096 msgid "New Toolkit" msgstr "" #: ../src/program.c:1100 ../src/program.c:1178 msgid "Create" msgstr "" #: ../src/program.c:1111 msgid "Nothing selected." msgstr "" #: ../src/program.c:1112 msgid "No toolkit selected." msgstr "" #: ../src/program.c:1171 msgid "Display this name" msgstr "" #: ../src/program.c:1173 msgid "Load this file" msgstr "" #: ../src/program.c:1241 msgid "Load Definition" msgstr "" #: ../src/program.c:1295 msgid "Reload" msgstr "" #: ../src/program.c:1296 msgid "Reload startup objects?" msgstr "" #: ../src/program.c:1297 msgid "" "Would you like to reload all startup menus, workspaces and plugins now? This " "may take a few seconds." msgstr "" #: ../src/program.c:1379 msgid "No tool selected" msgstr "" #: ../src/program.c:1422 msgid "Bad regular expression." msgstr "" #: ../src/program.c:1441 #, c-format msgid "No match found for \"%s\"." msgstr "" #: ../src/program.c:1454 msgid "Find in all Toolkits" msgstr "" #: ../src/program.c:1464 msgid "Enter search string here" msgstr "" #: ../src/program.c:1515 #, c-format msgid "No top-level symbol called \"%s\"." msgstr "" #: ../src/program.c:1523 #, c-format msgid "Symbol \"%s\" has no tool inforation." msgstr "" #: ../src/program.c:1544 msgid "Go to definition of this symbol" msgstr "" #: ../src/program.c:1546 msgid "Go to Definition" msgstr "" #: ../src/program.c:1576 msgid "Object information." msgstr "" #: ../src/program.c:1627 msgid "No documentation available." msgstr "" #: ../src/program.c:1628 msgid "" "On-line documentation is only currently available for VIPS functions and nip " "builtins." msgstr "" #: ../src/program.c:1644 msgid "New _Tool" msgstr "" #: ../src/program.c:1645 msgid "Make a new tool" msgstr "" #: ../src/program.c:1649 msgid "New Tool_kit" msgstr "" #: ../src/program.c:1650 msgid "Make a new toolkit" msgstr "" #: ../src/program.c:1654 msgid "New _Separator" msgstr "" #: ../src/program.c:1655 msgid "Make a new separator" msgstr "" #: ../src/program.c:1659 msgid "New _Column Item" msgstr "" #: ../src/program.c:1660 msgid "Make a new column item" msgstr "" #: ../src/program.c:1664 msgid "New _Program Window" msgstr "" #: ../src/program.c:1665 msgid "Make a new program window" msgstr "" #: ../src/program.c:1670 msgid "Make a new workspace" msgstr "" #: ../src/program.c:1674 msgid "_Open Toolkit" msgstr "" #: ../src/program.c:1675 msgid "_Open toolkit" msgstr "" #: ../src/program.c:1679 msgid "Save Toolkit" msgstr "" #: ../src/program.c:1680 msgid "_Save toolkit" msgstr "" #: ../src/program.c:1684 msgid "Save Toolkit _As" msgstr "" #: ../src/program.c:1685 msgid "Save toolkit as" msgstr "" #: ../src/program.c:1689 msgid "_Process" msgstr "" #: ../src/program.c:1690 msgid "Process text" msgstr "" #: ../src/program.c:1694 msgid "_Reload All Toolkits" msgstr "" #: ../src/program.c:1695 msgid "Remove and reload all startup data" msgstr "" #: ../src/program.c:1699 msgid "C_ut" msgstr "" #: ../src/program.c:1700 msgid "Cut selected text" msgstr "" #: ../src/program.c:1704 msgid "_Copy" msgstr "" #: ../src/program.c:1705 msgid "Copy selected text" msgstr "" #: ../src/program.c:1709 msgid "_Paste" msgstr "" #: ../src/program.c:1710 msgid "Paste selected text" msgstr "" #: ../src/program.c:1715 msgid "Delete selected text" msgstr "" #: ../src/program.c:1720 msgid "Select all text" msgstr "" #: ../src/program.c:1724 msgid "Dese_lect All" msgstr "" #: ../src/program.c:1725 msgid "Deselect all text" msgstr "" #: ../src/program.c:1729 msgid "Delete _Tool" msgstr "" #: ../src/program.c:1730 msgid "Delete current tool" msgstr "" #: ../src/program.c:1734 msgid "Delete Tool_kit" msgstr "" #: ../src/program.c:1735 msgid "Delete current toolkit" msgstr "" #: ../src/program.c:1740 msgid "Find text in toolkits" msgstr "" #: ../src/program.c:1745 msgid "Find text again" msgstr "" #: ../src/program.c:1749 msgid "_Jump To Definition" msgstr "" #: ../src/program.c:1750 msgid "Jump to definition" msgstr "" #: ../src/program.c:1754 msgid "_Info" msgstr "" #: ../src/program.c:1755 msgid "Info on selected object" msgstr "" #: ../src/program.c:1759 msgid "_Trace" msgstr "" #: ../src/program.c:1760 msgid "Make a new trace window" msgstr "" #: ../src/program.c:1764 msgid "_Errors" msgstr "" #: ../src/program.c:1765 msgid "Show all errors" msgstr "" #: ../src/program.c:1769 msgid "Help on _Tool" msgstr "" #: ../src/program.c:1770 msgid "View docs for this tool" msgstr "" #: ../src/program.c:2015 msgid "Bad drag." msgstr "" #: ../src/program.c:2017 msgid "" "Sorry, you can only drag tools between toolkits. You can't reorder toolkits, " "you can't nest toolkits and you can't drag tools to the top level." msgstr "" #: ../src/program.c:2196 msgid "Tool" msgstr "" #: ../src/progress.c:120 msgid "Cancelling" msgstr "" #: ../src/progress.c:153 #, c-format msgid "%d minute left" msgid_plural "%d minutes left" msgstr[0] "" msgstr[1] "" #: ../src/progress.c:158 #, c-format msgid "%d second left" msgid_plural "%d seconds left" msgstr[0] "" msgstr[1] "" #: ../src/progress.c:179 msgid "Calculating" msgstr "" #: ../src/progress.c:198 msgid "Loading" msgstr "" #: ../src/reduce.c:135 msgid "Typecheck error." msgstr "" #: ../src/reduce.c:137 #, c-format msgid "%s expected %s, instead saw:" msgstr "" #: ../src/reduce.c:148 ../src/reduce.c:1056 ../src/trace.c:126 #: ../src/workspace.c:1704 msgid "Overflow error." msgstr "" #: ../src/reduce.c:149 #, c-format msgid "%s too long." msgstr "" #: ../src/reduce.c:532 ../src/reduce.c:597 msgid "Not rectangular." msgstr "" #: ../src/reduce.c:533 ../src/reduce.c:598 #, c-format msgid "" "Matrix of real is not rectangular. Found row of length %d, should be %d." msgstr "" #: ../src/reduce.c:557 msgid "Zero dimension." msgstr "" #: ../src/reduce.c:558 #, c-format msgid "Matrix has width %d, height %d." msgstr "" #: ../src/reduce.c:850 msgid "List length" msgstr "" #: ../src/reduce.c:899 #, c-format msgid "List index must be positive, not %d" msgstr "" #: ../src/reduce.c:907 msgid "List index" msgstr "" #: ../src/reduce.c:912 #, c-format msgid "List only has %d elements, unable to get element %d." msgstr "" #: ../src/reduce.c:955 msgid "No arguments allowed." msgstr "" #: ../src/reduce.c:956 #, c-format msgid "Object \"%s\" should have no arguments." msgstr "" #: ../src/reduce.c:1057 msgid "C stack overflow. Expression too complex." msgstr "" #: ../src/reduce.c:1073 msgid "Cancelled." msgstr "" #: ../src/reduce.c:1074 msgid "Evaluation cancelled." msgstr "" #: ../src/reduce.c:1169 msgid "No value." msgstr "" #: ../src/reduce.c:1170 #, c-format msgid "Symbol \"%s\" has no value." msgstr "" #: ../src/reduce.c:1645 ../src/reduce.c:1650 ../src/reduce.c:1656 msgid "List generator" msgstr "" #: ../src/reduce.h:75 ../src/reduce.h:105 msgid "Stack overflow." msgstr "" #: ../src/reduce.h:76 msgid "Spine stack overflow, runaway recursion?" msgstr "" #: ../src/reduce.h:106 msgid "Frame stack overflow, expression too complex." msgstr "" #: ../src/reduce.h:119 ../src/reduce.h:131 msgid "Stack underflow." msgstr "" #: ../src/reduce.h:120 msgid "Frame stack underflow, you've found a bug!" msgstr "" #: ../src/reduce.h:132 msgid "Spine stack underflow, you've found a bug!" msgstr "" #: ../src/regionview.c:935 ../src/rowview.c:302 msgid "Can't duplicate." msgstr "" #: ../src/regionview.c:937 msgid "You can only duplicate top level regions." msgstr "" #: ../src/regionview.c:979 msgid "Can't delete." msgstr "" #: ../src/regionview.c:980 msgid "You can only delete top level regions." msgstr "" #: ../src/regionview.c:989 msgid "Delete Region?" msgstr "" #: ../src/regionview.c:990 #, c-format msgid "Are you sure you want to delete Region \"%s\"?" msgstr "" #. Other init. #. #: ../src/regionview.c:1015 msgid "Region menu" msgstr "" #: ../src/row.c:288 msgid "Error in row." msgstr "" #. Elements are name of row, principal error, #. * secondary error. #. #: ../src/row.c:292 #, c-format msgid "" "Error in row %s: %s\n" "%s" msgstr "" #. Expands to eg. "B1 refers to: B2, B3". #. #: ../src/row.c:497 msgid "refers to" msgstr "" #. Expands to eg. "B1 is referred to by: B2, B3". #. #: ../src/row.c:508 msgid "is referred to by" msgstr "" #: ../src/row.c:521 msgid "is blocked on" msgstr "" #: ../src/rowview.c:304 msgid "You can only duplicate top level rows." msgstr "" #: ../src/rowview.c:457 msgid "Drag between columns not yet implemented." msgstr "" #. Other init. #. #: ../src/rowview.c:585 msgid "Row menu" msgstr "" #: ../src/rowview.c:594 ../src/workspacedefs.c:262 msgid "Replace From _File" msgstr "" #: ../src/rowview.c:598 msgid "Re_set" msgstr "" #: ../src/rowview.c:664 msgid "Click to open or close class" msgstr "" #: ../src/slider.c:51 msgid "From" msgstr "" #: ../src/slider.c:54 msgid "To" msgstr "" #: ../src/spin.c:223 msgid "Expand or collapse row" msgstr "" #: ../src/symbol.c:503 #, c-format msgid "Symbol %s is not defined." msgstr "" #: ../src/symbol.c:507 #, c-format msgid "%s is referred to by" msgstr "" #: ../src/symbol.c:721 #, c-format msgid "Redefinition of \"%s\"." msgstr "" #: ../src/symbol.c:725 #, c-format msgid "Previously defined at line %d." msgstr "" #: ../src/symbol.c:748 #, c-format msgid "Attempt to redefine root symbol \"%s\"." msgstr "" #. Parameter, workspace, etc. #. #: ../src/symbol.c:773 #, c-format msgid "Can't redefine %s \"%s\"." msgstr "" #. used as in "fred refers to undefined symbol jim" #. #: ../src/tool.c:75 msgid "refers to undefined symbol" msgstr "" #: ../src/tool.c:868 #, c-format msgid "" "Can't create dialog with name \"%s\", an object with that name already " "exists in kit \"%s\"." msgstr "" #: ../src/toolkitbrowser.c:242 msgid "Search:" msgstr "" #: ../src/toolkitbrowser.c:267 msgid "Action" msgstr "" #: ../src/toolkitbrowser.c:275 msgid "Parameters" msgstr "" #: ../src/toolkitbrowser.c:283 msgid "Menu Item" msgstr "" #: ../src/toolkitgroup.c:139 #, c-format msgid "Toolkits for %s" msgstr "" #: ../src/trace.c:127 msgid "Trace buffer stack overflow." msgstr "" #: ../src/trace.c:231 msgid "Clear trace window" msgstr "" #: ../src/trace.c:237 msgid "_Operators" msgstr "" #: ../src/trace.c:238 msgid "trace operators" msgstr "" #: ../src/trace.c:242 msgid "_Builtin Functions" msgstr "" #: ../src/trace.c:243 msgid "trace calls to built in functions" msgstr "" #: ../src/trace.c:247 msgid "_Class Construction" msgstr "" #: ../src/trace.c:248 msgid "trace class constructors" msgstr "" #: ../src/trace.c:252 msgid "_VIPS Operations" msgstr "" #: ../src/trace.c:253 msgid "trace calls to VIPS" msgstr "" #: ../src/trace.c:331 msgid "Trace" msgstr "" #: ../src/tslider.c:369 msgid "Slider value ... edit!" msgstr "" #: ../src/tslider.c:390 msgid "Left-drag to set number" msgstr "" #: ../src/util.c:211 msgid "Unable to set XML property." msgstr "" #: ../src/util.c:212 #, c-format msgid "Unable to set property \"%s\" to value \"%s\"." msgstr "" #: ../src/util.c:830 msgid "(no image)" msgstr "" #: ../src/util.c:844 #, c-format msgid "%dx%d %s, %d band, %s" msgid_plural "%dx%d %s, %d bands, %s" msgstr[0] "" msgstr[1] "" #: ../src/util.c:1257 msgid "8-bit unsigned integer" msgstr "" #. IM_BANDFMT_UCHAR #: ../src/util.c:1258 msgid "8-bit signed integer" msgstr "" #. IM_BANDFMT_CHAR #: ../src/util.c:1259 msgid "16-bit unsigned integer" msgstr "" #. IM_BANDFMT_USHORT #: ../src/util.c:1260 msgid "16-bit signed integer" msgstr "" #. IM_BANDFMT_SHORT #: ../src/util.c:1261 msgid "32-bit unsigned integer" msgstr "" #. IM_BANDFMT_UINT #: ../src/util.c:1262 msgid "32-bit signed integer" msgstr "" #. IM_BANDFMT_INT #: ../src/util.c:1263 msgid "32-bit float" msgstr "" #. IM_BANDFMT_FLOAT #: ../src/util.c:1264 msgid "64-bit complex" msgstr "" #. IM_BANDFMT_COMPLEX #: ../src/util.c:1265 msgid "64-bit float" msgstr "" #. IM_BANDFMT_DOUBLE #: ../src/util.c:1266 msgid "128-bit complex" msgstr "" #: ../src/util.c:1274 msgid "" msgstr "" #: ../src/util.c:1316 msgid "" msgstr "" #: ../src/util.c:1340 msgid "directory" msgstr "" #: ../src/util.c:1599 msgid "Unable to find install area." msgstr "" #: ../src/util.c:1775 msgid "" msgstr "" #: ../src/util.c:1933 msgid "Filename is too long." msgstr "" #: ../src/util.c:1939 msgid "Filename contains only blank characters." msgstr "" #: ../src/util.c:2002 ../src/util.c:2011 ../src/util.c:2066 msgid "Unable to open." msgstr "" #: ../src/util.c:2003 ../src/util.c:2012 #, c-format msgid "" "Unable to open file \"%s\" for reading.\n" "%s." msgstr "" #: ../src/util.c:2067 #, c-format msgid "" "Unable to open file \"%s\" for writing.\n" "%s." msgstr "" #: ../src/util.c:2088 msgid "Unable to write." msgstr "" #: ../src/util.c:2089 #, c-format msgid "" "Unable to write to file \"%s\".\n" "%s." msgstr "" #: ../src/util.c:2124 ../src/util.c:2137 ../src/util.c:2162 msgid "Unable to read." msgstr "" #: ../src/util.c:2125 #, c-format msgid "File \"%s\" too large." msgstr "" #: ../src/util.c:2138 ../src/util.c:2163 #, c-format msgid "" "Unable to read from file \"%s\".\n" "%s." msgstr "" #. File length unit. #. #: ../src/util.c:2454 msgid "bytes" msgstr "" #. Kilo byte unit. #. #: ../src/util.c:2458 msgid "KB" msgstr "" #. Mega byte unit. #. #: ../src/util.c:2462 msgid "MB" msgstr "" #. Giga byte unit. #. #: ../src/util.c:2466 msgid "GB" msgstr "" #. Tera byte unit. #. #: ../src/util.c:2470 msgid "TB" msgstr "" #: ../src/util.c:2513 msgid "Unable to create temporary file." msgstr "" #: ../src/util.c:2514 #, c-format msgid "" "Unable to make file \"%s\"\n" "%s" msgstr "" #: ../src/util.c:2721 msgid "Out of memory." msgstr "" #: ../src/util.c:2722 #, c-format msgid "Request for %s of RAM triggered memory allocation failure." msgstr "" #: ../src/vipsobject.c:94 msgid "No such type." msgstr "" #: ../src/vipsobject.c:95 #, c-format msgid "Type \"%s\" not found as a subclass of VipsObject." msgstr "" #: ../src/vipsobject.c:126 #, c-format msgid "No more than %d arguments allowed." msgstr "" #: ../src/vipsobject.c:253 msgid "Wrong number of required arguments." msgstr "" #: ../src/vipsobject.c:254 #, c-format msgid "Operation \"%s\" has %d required arguments, you supplied %d." msgstr "" #: ../src/vipsobject.c:285 msgid "Unable to build object." msgstr "" #: ../src/workspace.c:156 msgid "No objects selected." msgstr "" #: ../src/workspace.c:157 ../src/workspace.c:162 msgid "Select exactly one object and try again." msgstr "" #: ../src/workspace.c:161 msgid "More than one object selected." msgstr "" #: ../src/workspace.c:791 ../src/workspace.c:799 msgid "No backup workspaces found." msgstr "" #: ../src/workspace.c:793 msgid "" "You need to enable \"Auto workspace save\" in Preferences before automatic " "recovery works." msgstr "" #: ../src/workspace.c:800 #, c-format msgid "No suitable workspace save files found in \"%s\"" msgstr "" #: ../src/workspace.c:816 msgid "Open workspace backup?" msgstr "" #: ../src/workspace.c:817 #, c-format msgid "" "Found workspace \"%s\", dated %s. Do you want to recover this workspace?" msgstr "" #: ../src/workspace.c:1327 msgid "Version mismatch." msgstr "" #: ../src/workspace.c:1328 #, c-format msgid "" "File \"%s\" was saved from %s-%d.%d.%d. You may see compatibility problems." msgstr "" #: ../src/workspace.c:1485 msgid "// private definitions for this workspace\n" msgstr "" #: ../src/workspace.c:1530 #, c-format msgid "Can't create workspace \"%s\". A symbol with that name already exists." msgstr "" #: ../src/workspace.c:1621 msgid "Default empty workspace" msgstr "" #: ../src/workspace.c:1694 #, c-format msgid "%s needs %d arguments, there are %d selected." msgstr "" #: ../src/workspace.c:1705 msgid "Too many names selected." msgstr "" #: ../src/workspace.c:1845 msgid "You can only remove top level rows." msgstr "" #: ../src/workspace.c:1846 msgid "Not all selected objects are top level rows." msgstr "" #: ../src/workspace.c:1896 msgid "Delete selected objects?" msgstr "" #: ../src/workspace.c:1897 #, c-format msgid "Are you sure you want to delete %s?" msgstr "" #: ../src/workspace.c:1955 msgid "Unable to ungroup." msgstr "" #: ../src/workspace.c:1956 #, c-format msgid "Row \"%s\" is not a Group or a list." msgstr "" #: ../src/workspacedefs.c:97 #, c-format msgid "%d definition" msgid_plural "%d definitions" msgstr[0] "" msgstr[1] "" #: ../src/workspacedefs.c:103 msgid "errors" msgstr "" #: ../src/workspacedefs.c:181 msgid "Replace Definition From File" msgstr "" #: ../src/workspacedefs.c:261 msgid "Workspace definitions" msgstr "" #: ../src/workspacedefs.c:282 msgid "Process" msgstr "" #: ../src/workspacegroup.c:146 #, c-format msgid "" "Can't create workspacegroup \"%s\". A symbol with that name already exists." msgstr "" #: ../src/workspacegroup.c:213 msgid "Set workspace name here" msgstr "" #: ../src/workspacegroup.c:215 msgid "Set workspace caption here" msgstr "" #: ../src/workspacegroup.c:217 msgid "New Workspace" msgstr "" #: ../src/workspacegroup.c:221 msgid "Create Workspace" msgstr "" nip2-8.7.1/po/ChangeLog0000644000175000017500000000002413351443023011502 00000000000000+ en_UK translation nip2-8.7.1/po/LINGUAS0000644000175000017500000000000013351443023010747 00000000000000nip2-8.7.1/po/nip2.pot0000644000175000017500000020656513417043453011354 00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=glib&keywords=I18N+L10N&component=general\n" "POT-Creation-Date: 2019-01-14 08:24+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: ../src/conversionview.c:50 msgid "Unable to find image range." msgstr "" #: ../src/conversionview.c:51 msgid "Find image range failed." msgstr "" #: ../src/conversionview.c:74 msgid "Unable to scale image." msgstr "" #: ../src/conversionview.c:75 msgid "Maximum and minimum pixel values are equal." msgstr "" #. Build menu. One for each window, as we need to track falsecolour #. * etc. toggles. Could just have one, and modify pre-popup, but this #. * is easier. #. #: ../src/conversionview.c:207 msgid "Convert menu" msgstr "" #: ../src/conversionview.c:208 msgid "_Scale" msgstr "" #: ../src/conversionview.c:210 msgid "_False Color" msgstr "" #: ../src/conversionview.c:212 msgid "_Interpret" msgstr "" #: ../src/conversionview.c:214 ../src/regionview.c:989 msgid "_Reset" msgstr "" #: ../src/conversionview.c:216 msgid "Set As Workspace _Default" msgstr "" #: ../src/tslider.c:386 msgid "Slider value ... edit!" msgstr "" #: ../src/tslider.c:407 msgid "Left-drag to set number" msgstr "" #: ../src/fontnameview.c:63 ../src/optionview.c:185 ../src/sliderview.c:58 #: ../src/gtkutil.c:761 ../src/gtkutil.c:796 ../src/gtkutil.c:850 #: ../src/editview.c:60 ../src/pathnameview.c:63 ../src/formula.c:198 #, c-format msgid "%s:" msgstr "" #: ../src/workspacegroup.c:400 ../src/workspacegroup.c:459 msgid "Version mismatch." msgstr "" #: ../src/workspacegroup.c:401 ../src/workspacegroup.c:460 #, c-format msgid "" "File \"%s\" needs version %d.%d. Merging into this tab may cause " "compatibility problems." msgstr "" #: ../src/workspacegroup.c:739 msgid "Workspace" msgstr "" #. Changed later. #. #: ../src/workspacegroup.c:802 msgid "Empty workspace" msgstr "" #: ../src/workspacegroup.c:835 msgid "Default empty workspace" msgstr "" #: ../src/iobject.c:175 msgid "Object" msgstr "" #: ../src/matrix.c:149 ../src/main.c:694 msgid "Text" msgstr "" #: ../src/matrix.c:150 msgid "Sliders" msgstr "" #: ../src/matrix.c:151 msgid "Toggle buttons" msgstr "" #: ../src/matrix.c:152 msgid "Text, plus scale and offset" msgstr "" #: ../src/matrix.c:163 msgid "Display as" msgstr "" #. Expands to eg. "Edit Toggle A1". #. #: ../src/matrix.c:191 ../src/iregion.c:236 ../src/colour.c:265 #: ../src/classmodel.c:763 ../src/clock.c:99 #, c-format msgid "Edit %s %s" msgstr "" #: ../src/matrix.c:199 ../src/iregion.c:242 ../src/colour.c:273 #: ../src/classmodel.c:774 ../src/clock.c:105 #, c-format msgid "Set %s" msgstr "" #: ../src/matrix.c:276 ../src/option.c:71 ../src/slider.c:57 #: ../src/pathname.c:78 ../src/string.c:70 ../src/colour.c:309 #: ../src/number.c:51 ../src/imageheader.c:231 ../src/toggle.c:51 #: ../src/clock.c:194 ../src/plot.c:363 ../src/fontname.c:61 msgid "Value" msgstr "" #: ../src/matrix.c:279 ../src/matrixview.c:398 msgid "Scale" msgstr "" #: ../src/matrix.c:282 ../src/matrixview.c:403 msgid "Offset" msgstr "" #: ../src/matrix.c:285 ../src/columnview.c:231 ../src/columnview.c:294 #: ../src/program.c:597 ../src/program.c:627 ../src/program.c:1223 #: ../src/program.c:1256 msgid "Filename" msgstr "" #: ../src/matrix.c:288 msgid "Display" msgstr "" #: ../src/matrix.c:309 msgid "Matrix" msgstr "" #: ../src/option.c:65 ../src/slider.c:48 ../src/pathname.c:75 #: ../src/string.c:67 ../src/number.c:48 ../src/mainw.c:1283 #: ../src/mainw.c:1334 ../src/toggle.c:48 ../src/plot.c:343 #: ../src/program.c:1136 ../src/program.c:1178 ../src/fontname.c:58 msgid "Caption" msgstr "" #: ../src/option.c:68 msgid "Labels" msgstr "" #: ../src/vipsobject.c:106 ../src/call.c:273 ../src/class.c:657 #: ../src/class.c:889 ../src/class.c:986 ../src/compile.c:1765 msgid "Too many arguments." msgstr "" #: ../src/vipsobject.c:107 #, c-format msgid "No more than %d arguments allowed." msgstr "" #: ../src/vipsobject.c:239 msgid "Wrong number of required arguments." msgstr "" #: ../src/vipsobject.c:240 #, c-format msgid "Operation \"%s\" has %d required arguments, you supplied %d." msgstr "" #: ../src/vipsobject.c:276 ../src/vipsobject.c:409 ../src/util.c:191 #: ../src/cache.c:875 msgid "VIPS library error." msgstr "" #: ../src/toolkitbrowser.c:282 msgid "Action" msgstr "" #: ../src/toolkitbrowser.c:290 msgid "Parameters" msgstr "" #: ../src/toolkitbrowser.c:298 msgid "Menu Item" msgstr "" #. Need one menu per image window (could have a single menu for all #. * windows, but then we'd have to set the state of the toggle buttons #. * before mapping) #. #: ../src/imagepresent.c:1564 msgid "Ruler menu" msgstr "" #: ../src/imagepresent.c:1565 msgid "Rulers In _mm" msgstr "" #: ../src/imagepresent.c:1567 msgid "Show _Offset" msgstr "" #. Create signals. #. #. Init methods. #. #: ../src/paintboxview.c:109 msgid "Paintbox bar menu" msgstr "" #: ../src/paintboxview.c:210 msgid "Clear undo history?" msgstr "" #: ../src/paintboxview.c:211 msgid "" "Are you sure you want to clear all undo and redo? This will free up memory, " "but you will no longer be able to undo or redo any of the painting you have " "done so far." msgstr "" #: ../src/paintboxview.c:246 msgid "Manipulate regions" msgstr "" #. IMAGEMODEL_SELECT #: ../src/paintboxview.c:247 msgid "Pan window" msgstr "" #. IMAGEMODEL_PAN #: ../src/paintboxview.c:248 msgid "Zoom in on mouse" msgstr "" #. IMAGEMODEL_MAGIN #: ../src/paintboxview.c:249 ../src/imageview.c:506 ../src/imageview.c:560 msgid "Zoom out" msgstr "" #. IMAGEMODEL_MAGOUT #: ../src/paintboxview.c:250 msgid "Read pixel into inkwell" msgstr "" #. IMAGEMODEL_DROPPER #: ../src/paintboxview.c:251 msgid "Freehand draw " msgstr "" #. IMAGEMODEL_PEN #: ../src/paintboxview.c:252 msgid "Draw straight lines" msgstr "" #. IMAGEMODEL_LINE #: ../src/paintboxview.c:253 msgid "Fill rectangles" msgstr "" #. IMAGEMODEL_RECT #: ../src/paintboxview.c:254 msgid "Flood while pixel not equal to ink" msgstr "" #. IMAGEMODEL_FLOOD #: ../src/paintboxview.c:256 msgid "Flood while pixel equal to click" msgstr "" #. IMAGEMODEL_BLOB #: ../src/paintboxview.c:258 msgid "Draw text" msgstr "" #. IMAGEMODEL_TEXT #: ../src/paintboxview.c:259 ../src/main.c:695 msgid "Smudge" msgstr "" #: ../src/paintboxview.c:309 msgid "Undo last paint action" msgstr "" #: ../src/paintboxview.c:318 msgid "Redo last paint action" msgstr "" #: ../src/paintboxview.c:327 msgid "Clear all undo and redo buffers" msgstr "" #: ../src/paintboxview.c:377 msgid "Enter text for text tool" msgstr "" #: ../src/boxes.c:245 msgid "Close _without Saving" msgstr "" #. Translators: translate this to a credit for you, and it'll appear in #. * the About box. #. #: ../src/boxes.c:264 msgid "translator_credits" msgstr "" #: ../src/boxes.c:273 #, c-format msgid "About %s." msgstr "" #: ../src/boxes.c:276 #, c-format msgid "%s is an image processing package." msgstr "" #: ../src/boxes.c:280 #, c-format msgid "" "%s comes with ABSOLUTELY NO WARRANTY. This is free software and you are " "welcome to redistribute it under certain conditions, see http://www.gnu.org." msgstr "" #: ../src/boxes.c:299 msgid "Personal start folder" msgstr "" #: ../src/boxes.c:303 msgid "Homepage" msgstr "" #: ../src/boxes.c:306 msgid "Linked to VIPS" msgstr "" #: ../src/boxes.c:309 msgid "Built against VIPS" msgstr "" #: ../src/boxes.c:322 msgid "Temp files in" msgstr "" #. Expands to (eg.) "14GB free in /pics/tmp" #: ../src/boxes.c:332 ../src/mainw.c:652 #, c-format msgid " in \"%s\"" msgstr "" #: ../src/boxes.c:336 ../src/mainw.c:656 #, c-format msgid "%d cells in heap, %d cells free, %d cells maximum" msgstr "" #: ../src/boxes.c:342 #, c-format msgid "%d vips calls cached by nip2" msgstr "" #: ../src/boxes.c:346 #, c-format msgid "%d vips operations cached by libvips" msgstr "" #: ../src/boxes.c:350 ../src/mainw.c:670 #, c-format msgid "using %d threads" msgstr "" #: ../src/boxes.c:353 #, c-format msgid "%d pixel buffers in vips" msgstr "" #: ../src/boxes.c:358 msgid " of ram in pixel buffers" msgstr "" #: ../src/boxes.c:362 msgid " of ram highwater mark" msgstr "" #: ../src/boxes.c:425 msgid "Help page not found." msgstr "" #: ../src/boxes.c:426 #, c-format msgid "No indexed help page found for tag \"%s\"" msgstr "" #: ../src/boxes.c:618 msgid "Search for" msgstr "" #: ../src/boxes.c:619 msgid "Case sensitive" msgstr "" #: ../src/boxes.c:621 msgid "Regular expression" msgstr "" #: ../src/boxes.c:623 msgid "Search from start" msgstr "" #: ../src/boxes.c:691 ../src/boxes.c:702 ../src/boxes.c:731 msgid "Unable to view help file." msgstr "" #: ../src/boxes.c:692 #, c-format msgid "Unable to open URL \"%s\", windows error code = %d." msgstr "" #: ../src/boxes.c:703 #, c-format msgid "" "Attempt to view URL with xdg-open failed\n" "%s" msgstr "" #: ../src/boxes.c:708 ../src/boxes.c:740 msgid "Browser window opened." msgstr "" #: ../src/boxes.c:710 ../src/boxes.c:742 msgid "You may need to switch desktops to see the new window." msgstr "" #: ../src/boxes.c:733 #, c-format msgid "" "Attempted to launch browser with command:\n" " %s\n" "You can change this command in Preferences." msgstr "" #: ../src/boxes.c:774 msgid "Select Font" msgstr "" #: ../src/boxes.c:832 msgid "Font not found." msgstr "" #: ../src/boxes.c:833 #, c-format msgid "Font \"%s\" not found on system." msgstr "" #: ../src/boxes.c:913 msgid "Pick a font" msgstr "" #: ../src/boxes.c:918 msgid "Set Font" msgstr "" #: ../src/boxes.c:964 msgid "Click to select font" msgstr "" #: ../src/toggleview.c:87 ../src/gtkutil.c:858 msgid "Left-click to change value" msgstr "" #: ../src/columnview.c:131 #, c-format msgid "Merge Into Column \"%s\"" msgstr "" #: ../src/columnview.c:182 #, c-format msgid "Save Column \"%s\"" msgstr "" #: ../src/columnview.c:229 ../src/columnview.c:290 ../src/row.c:482 #: ../src/mainw.c:1282 ../src/mainw.c:1332 ../src/defbrowser.c:253 #: ../src/program.c:596 ../src/program.c:625 ../src/program.c:1135 #: ../src/program.c:1176 ../src/program.c:1222 ../src/program.c:1254 #: ../src/program.c:1580 ../src/program.c:1621 msgid "Name" msgstr "" #: ../src/columnview.c:230 ../src/columnview.c:292 msgid "Toolkit" msgstr "" #: ../src/columnview.c:290 msgid "Set menu item text here" msgstr "" #: ../src/columnview.c:292 msgid "Add to this toolkit" msgstr "" #: ../src/columnview.c:294 msgid "Store column in this file" msgstr "" #: ../src/columnview.c:297 #, c-format msgid "New Menu Item from Column \"%s\"" msgstr "" #: ../src/columnview.c:302 msgid "Menuize" msgstr "" #: ../src/columnview.c:757 msgid "Edit caption, press enter to accept changes, press escape to cancel" msgstr "" #: ../src/columnview.c:810 msgid "Enter expressions here" msgstr "" #: ../src/columnview.c:883 msgid "doubleclick to set title" msgstr "" #: ../src/columnview.c:892 msgid "Fold the column away" msgstr "" #: ../src/columnview.c:897 msgid "Open the column" msgstr "" #: ../src/columnview.c:1032 msgid "Column menu" msgstr "" #: ../src/columnview.c:1033 msgid "_Edit Caption" msgstr "" #: ../src/columnview.c:1035 ../src/mainw.c:1663 ../src/program.c:1807 msgid "Select _All" msgstr "" #: ../src/columnview.c:1039 msgid "Merge Into Column" msgstr "" #: ../src/columnview.c:1044 msgid "Make Column Into _Menu Item" msgstr "" #: ../src/columnview.c:1112 msgid "Left-drag to move, left-double-click to set title, right-click for menu" msgstr "" #: ../src/columnview.c:1145 msgid "Delete the column" msgstr "" #: lex.l:89 lex.l:99 msgid "line too long" msgstr "" #: lex.l:107 msgid "end of line inside string" msgstr "" #: lex.l:109 msgid "no end of string" msgstr "" #: lex.l:126 lex.l:136 lex.l:144 msgid "bad char constant" msgstr "" #: lex.l:169 msgid "nested comment" msgstr "" #: lex.l:175 msgid "no end of comment" msgstr "" #: lex.l:305 #, c-format msgid "bad number %s" msgstr "" #: lex.l:385 #, c-format msgid "illegal character \"%c\"" msgstr "" #: ../src/row.c:287 msgid "Error in row." msgstr "" #. Elements are name of row, principal error, #. * secondary error. #. #: ../src/row.c:291 #, c-format msgid "" "Error in row %s: %s\n" "%s" msgstr "" #. Expands to eg. "B1 refers to: B2, B3". #. #: ../src/row.c:501 msgid "refers to" msgstr "" #. Expands to eg. "B1 is referred to by: B2, B3". #. #: ../src/row.c:512 msgid "is referred to by" msgstr "" #: ../src/row.c:527 msgid "is blocked on" msgstr "" #: ../src/imagemodel.c:491 msgid "No text specified." msgstr "" #: ../src/imagemodel.c:492 msgid "Enter some text to paint in the entry widget at the top of the window." msgstr "" #: ../src/matrixview.c:155 ../src/classmodel.c:1146 ../src/plot.c:148 #: ../src/plot.c:158 ../src/plot.c:383 ../src/plot.c:402 ../src/plot.c:415 msgid "Bad value." msgstr "" #: ../src/matrixview.c:156 #, c-format msgid "" "Cell (%d, %d):\n" "%s" msgstr "" #. Common menus. #. #: ../src/iwindow.c:678 msgid "_File" msgstr "" #: ../src/iwindow.c:679 msgid "_New" msgstr "" #: ../src/iwindow.c:680 ../src/rowview.c:581 ../src/mainw.c:1715 #: ../src/regionview.c:985 ../src/program.c:727 msgid "_Edit" msgstr "" #: ../src/iwindow.c:681 msgid "_View" msgstr "" #: ../src/iwindow.c:682 msgid "_Help" msgstr "" #: ../src/iwindow.c:687 msgid "_Close" msgstr "" #: ../src/iwindow.c:688 msgid "Close" msgstr "" #: ../src/iwindow.c:692 msgid "_Quit" msgstr "" #: ../src/iwindow.c:693 msgid "Quit nip2" msgstr "" #: ../src/iwindow.c:696 msgid "_Contents" msgstr "" #: ../src/iwindow.c:697 msgid "Open the users guide" msgstr "" #: ../src/iwindow.c:701 msgid "_About" msgstr "" #: ../src/iwindow.c:702 msgid "About this program" msgstr "" #: ../src/iwindow.c:706 msgid "_Website" msgstr "" #: ../src/iwindow.c:707 msgid "Open the VIPS Homepage" msgstr "" #: ../src/heap.c:818 msgid "Heap full." msgstr "" #: ../src/heap.c:824 #, c-format msgid "" "The compile heap for %s has filled. Make it smaller and less complicated." msgstr "" #: ../src/heap.c:829 msgid "" "The main calculation heap has filled. Raise the heap size limit in " "Preferences." msgstr "" #: ../src/heap.c:1786 ../src/heap.c:1801 ../src/trace.c:130 #: ../src/workspace.c:1229 ../src/reduce.c:148 ../src/reduce.c:1092 msgid "Overflow error." msgstr "" #: ../src/heap.c:1787 msgid "C stack overflow. Circular definition." msgstr "" #: ../src/heap.c:1802 ../src/reduce.c:1093 msgid "C stack overflow. Expression too complex." msgstr "" #: ../src/heap.c:1929 msgid "Unimplemented list type." msgstr "" #: ../src/heap.c:1942 msgid "Unimplemented argument type." msgstr "" #: ../src/heap.c:1944 #, c-format msgid "Cannot convert %s to GValue." msgstr "" #: ../src/heap.c:2044 msgid "Unimplemented type." msgstr "" #: ../src/heap.c:2045 #, c-format msgid "Unable to convert %s to a nip type." msgstr "" #: ../src/heap.c:2211 msgid "circular" msgstr "" #: ../src/heap.c:2216 #, c-format msgid "circular to label %d" msgstr "" #: ../src/heap.c:2226 #, c-format msgid "label %d" msgstr "" #: ../src/heap.c:2243 msgid "unevaluated" msgstr "" #: ../src/heap.c:2278 #, c-format msgid "class (%p)" msgstr "" #: ../src/heap.c:2289 msgid "members" msgstr "" #: ../src/heap.c:2300 msgid "secret" msgstr "" #: ../src/heap.c:2353 #, c-format msgid "no value (type %d)" msgstr "" #: ../src/heap.c:2361 msgid "NULL pointer" msgstr "" #: ../src/heap.c:2370 msgid "symbol" msgstr "" #: ../src/heap.c:2378 msgid "constructor" msgstr "" #: ../src/heap.c:2386 msgid "symref" msgstr "" #: ../src/heap.c:2394 msgid "compileref" msgstr "" #: ../src/heap.c:2422 #, c-format msgid "tag \"%s\"" msgstr "" #: ../src/heap.c:2437 #, c-format msgid "unknown element tag %d" msgstr "" #. Probably failed to load prefs on startup for some reason. #. #: ../src/prefs.c:208 msgid "Unable to display preferences." msgstr "" #: ../src/prefs.c:209 #, c-format msgid "" "No preferences workspace was found. Preferences probably failed to load when " "%s started." msgstr "" #. Not found? Maybe - error message anyway. #. #: ../src/symbol.c:502 ../src/path.c:559 ../src/path.c:590 #: ../src/program.c:1517 ../src/program.c:1569 ../src/program.c:1591 #: ../src/program.c:1599 msgid "Not found." msgstr "" #: ../src/symbol.c:503 #, c-format msgid "Symbol %s is not defined." msgstr "" #: ../src/symbol.c:507 #, c-format msgid "%s is referred to by" msgstr "" #: ../src/symbol.c:724 msgid "Name in use." msgstr "" #: ../src/symbol.c:725 #, c-format msgid "Can't rename %s \"%s\" as \"%s\". The name is already in use." msgstr "" #: ../src/symbol.c:756 #, c-format msgid "Redefinition of \"%s\"." msgstr "" #: ../src/symbol.c:760 #, c-format msgid "Previously defined at line %d." msgstr "" #: ../src/symbol.c:783 #, c-format msgid "Attempt to redefine root symbol \"%s\"." msgstr "" #. Parameter, workspace, etc. #. #: ../src/symbol.c:809 #, c-format msgid "Can't redefine %s \"%s\"." msgstr "" #: ../src/imageview.c:455 msgid "_Mark" msgstr "" #: ../src/imageview.c:456 msgid "Create a new mark" msgstr "" #: ../src/imageview.c:460 msgid "_Horizontal Guide" msgstr "" #: ../src/imageview.c:461 msgid "Create a new horizontal guide" msgstr "" #: ../src/imageview.c:465 msgid "_Vertical Guide" msgstr "" #: ../src/imageview.c:466 msgid "Create a new vertical guide" msgstr "" #: ../src/imageview.c:470 msgid "_Arrow" msgstr "" #: ../src/imageview.c:471 msgid "Create a new arrow" msgstr "" #: ../src/imageview.c:475 msgid "_Region" msgstr "" #: ../src/imageview.c:476 msgid "Create a new region" msgstr "" #: ../src/imageview.c:480 msgid "Replace Image" msgstr "" #: ../src/imageview.c:481 msgid "Replace image from file" msgstr "" #: ../src/imageview.c:485 msgid "Save Image As" msgstr "" #: ../src/imageview.c:486 msgid "Save image to file" msgstr "" #: ../src/imageview.c:490 msgid "Recalculate" msgstr "" #: ../src/imageview.c:491 msgid "Recalculate image" msgstr "" #: ../src/imageview.c:495 ../src/rowview.c:583 msgid "_Header" msgstr "" #: ../src/imageview.c:496 msgid "View image header" msgstr "" #: ../src/imageview.c:500 ../src/imageview.c:554 msgid "Zoom _In" msgstr "" #: ../src/imageview.c:501 ../src/imageview.c:555 msgid "Zoom in on mouse cursor" msgstr "" #: ../src/imageview.c:505 ../src/imageview.c:559 msgid "Zoom _Out" msgstr "" #: ../src/imageview.c:510 msgid "Zoom _100%" msgstr "" #: ../src/imageview.c:511 ../src/imageview.c:574 msgid "Zoom to 100%" msgstr "" #: ../src/imageview.c:515 msgid "Zoom to _Fit" msgstr "" #: ../src/imageview.c:516 msgid "Zoom to fit image to window" msgstr "" #: ../src/imageview.c:522 ../src/plotwindow.c:235 msgid "_Status" msgstr "" #: ../src/imageview.c:523 ../src/plotwindow.c:236 msgid "Show status bar" msgstr "" #: ../src/imageview.c:527 msgid "_Display Control" msgstr "" #: ../src/imageview.c:528 msgid "Show display control bar" msgstr "" #: ../src/imageview.c:532 msgid "_Paint" msgstr "" #: ../src/imageview.c:533 msgid "Show paint bar" msgstr "" #: ../src/imageview.c:537 msgid "_Rulers" msgstr "" #: ../src/imageview.c:538 msgid "Show rulers" msgstr "" #: ../src/imageview.c:544 msgid "_Select" msgstr "" #: ../src/imageview.c:545 msgid "Select and modify selections" msgstr "" #: ../src/imageview.c:549 msgid "_Pan" msgstr "" #: ../src/imageview.c:550 msgid "Pan image" msgstr "" #: ../src/imageview.c:566 msgid "6%" msgstr "" #: ../src/imageview.c:566 msgid "Zoom to 6%" msgstr "" #: ../src/imageview.c:568 msgid "12%" msgstr "" #: ../src/imageview.c:568 msgid "Zoom to 12%" msgstr "" #: ../src/imageview.c:570 msgid "25%" msgstr "" #: ../src/imageview.c:570 msgid "Zoom to 25%" msgstr "" #: ../src/imageview.c:572 msgid "50%" msgstr "" #: ../src/imageview.c:572 msgid "Zoom to 50%" msgstr "" #: ../src/imageview.c:574 msgid "100%" msgstr "" #: ../src/imageview.c:576 msgid "200%" msgstr "" #: ../src/imageview.c:576 msgid "Zoom to 200%" msgstr "" #: ../src/imageview.c:578 msgid "400%" msgstr "" #: ../src/imageview.c:578 msgid "Zoom to 400%" msgstr "" #: ../src/imageview.c:580 msgid "800%" msgstr "" #: ../src/imageview.c:580 msgid "Zoom to 800%" msgstr "" #: ../src/imageview.c:582 msgid "1600%" msgstr "" #: ../src/imageview.c:582 msgid "Zoom to 1600%" msgstr "" #: parse.y:244 parse.y:255 msgid "not top level" msgstr "" #: parse.y:260 msgid "not strings" msgstr "" #: parse.y:318 msgid "left-hand-side pattern contains no identifiers" msgstr "" #: parse.y:1066 ../src/program.c:1498 msgid "Parse error." msgstr "" #: parse.y:1069 #, c-format msgid "Error in %s: %s" msgstr "" #: parse.y:1072 #, c-format msgid "Error: %s" msgstr "" #: parse.y:1193 msgid "definition is too long" msgstr "" #: parse.y:1657 msgid "identifier expected" msgstr "" #: parse.y:1667 #, c-format msgid "'%s' does not exist" msgstr "" #: parse.y:1671 #, c-format msgid "'%s' has no members" msgstr "" #: parse.y:1687 msgid "'.' or '=' expected" msgstr "" #: ../src/conversion.c:470 msgid "not uncoded" msgstr "" #: ../src/trace.c:131 msgid "Trace buffer stack overflow." msgstr "" #: ../src/trace.c:234 ../src/error.c:115 msgid "_Clear" msgstr "" #: ../src/trace.c:235 msgid "Clear trace window" msgstr "" #: ../src/trace.c:241 msgid "_Operators" msgstr "" #: ../src/trace.c:242 msgid "trace operators" msgstr "" #: ../src/trace.c:246 msgid "_Builtin Functions" msgstr "" #: ../src/trace.c:247 msgid "trace calls to built in functions" msgstr "" #: ../src/trace.c:251 msgid "_Class Construction" msgstr "" #: ../src/trace.c:252 msgid "trace class constructors" msgstr "" #: ../src/trace.c:256 msgid "_VIPS Operations" msgstr "" #: ../src/trace.c:257 msgid "trace calls to VIPS" msgstr "" #: ../src/trace.c:335 msgid "Trace" msgstr "" #: ../src/gtkutil.c:613 msgid "Bad identifier." msgstr "" #: ../src/gtkutil.c:615 msgid "" "Enter an identifier. Identifiers start with a letter, and then contain only " "letters, numbers, apostrophy and underscore." msgstr "" #: ../src/gtkutil.c:668 ../src/gtkutil.c:676 msgid "Bad floating point number." msgstr "" #: ../src/gtkutil.c:669 #, c-format msgid "\"%s\" is not a floating point number." msgstr "" #: ../src/gtkutil.c:677 #, c-format msgid "Extra characters \"%s\" after number." msgstr "" #: ../src/gtkutil.c:701 msgid "Bad integer." msgstr "" #: ../src/gtkutil.c:702 #, c-format msgid "\"%s\" is not an integer." msgstr "" #: ../src/gtkutil.c:720 msgid "Bad unsigned integer." msgstr "" #: ../src/gtkutil.c:736 msgid "Bad positive integer." msgstr "" #: ../src/slider.c:51 msgid "From" msgstr "" #: ../src/slider.c:54 msgid "To" msgstr "" #: ../src/action.c:87 msgid "Bad arguments." msgstr "" #. Expands to eg. 'bad args to "+", called from "fred"' #. #: ../src/action.c:102 ../src/action.c:186 msgid "Called from" msgstr "" #: ../src/action.c:108 #, c-format msgid "" "Error in binary %s.\n" "left = %s\n" "right = %s\n" "%s" msgstr "" #: ../src/action.c:142 ../src/class.c:190 #, c-format msgid "Member \"%s\" not found in class \"%s\"." msgstr "" #: ../src/action.c:149 #, c-format msgid "object = %s" msgstr "" #: ../src/action.c:153 #, c-format msgid "tag = %s" msgstr "" #: ../src/action.c:158 #, c-format msgid "Reference attempted in \"%s\"." msgstr "" #: ../src/action.c:162 ../src/class.c:189 msgid "Member not found." msgstr "" #: ../src/action.c:173 ../src/call.c:253 ../src/class.c:49 ../src/class.c:1024 #: ../src/builtin.c:381 ../src/builtin.c:1144 ../src/reduce.c:934 #: ../src/reduce.c:947 msgid "Bad argument." msgstr "" #: ../src/action.c:192 #, c-format msgid "" "Error in unary %s.\n" "argument = %s\n" "%s" msgstr "" #: ../src/action.c:361 ../src/action.c:379 ../src/action.c:409 msgid "Bad right hand side of '.'." msgstr "" #: ../src/action.c:371 msgid "Symbol on left hand side of '.' is not scope" msgstr "" #: ../src/action.c:413 msgid "Property not found." msgstr "" #: ../src/action.c:427 msgid "Bad left hand side of '.'." msgstr "" #: ../src/action.c:939 msgid "Division by zero." msgstr "" #: ../src/action.c:1315 ../src/action.c:1595 msgid "Unimplemented." msgstr "" #: ../src/action.c:1679 ../src/action.c:1715 ../src/action.c:1973 msgid "invoking method:" msgstr "" #: ../src/rowview.c:281 ../src/regionview.c:904 msgid "Can't duplicate." msgstr "" #: ../src/rowview.c:283 msgid "You can only duplicate top level rows." msgstr "" #: ../src/rowview.c:436 ../src/model.c:424 ../src/model.c:441 #: ../src/model.c:496 ../src/mainw.c:764 ../src/mainw.c:772 #: ../src/filemodel.c:100 ../src/filemodel.c:169 ../src/filemodel.c:418 #: ../src/filemodel.c:635 ../src/filemodel.c:674 ../src/builtin.c:482 #: ../src/view.c:916 ../src/classmodel.c:153 ../src/classmodel.c:225 msgid "Not implemented." msgstr "" #: ../src/rowview.c:437 msgid "Drag between columns not yet implemented." msgstr "" #. Other init. #. #: ../src/rowview.c:580 msgid "Row menu" msgstr "" #: ../src/rowview.c:587 ../src/mainw.c:1698 msgid "U_ngroup" msgstr "" #: ../src/rowview.c:591 ../src/workspacedefs.c:270 msgid "Replace From _File" msgstr "" #: ../src/rowview.c:593 ../src/mainw.c:1673 msgid "_Recalculate" msgstr "" #: ../src/rowview.c:595 msgid "Re_set" msgstr "" #: ../src/rowview.c:658 msgid "Click to open or close class" msgstr "" #. Create signals. #. #. Init methods. #. #: ../src/column.c:277 msgid "Column" msgstr "" #: ../src/column.c:345 ../src/workspace.c:1160 ../src/tool.c:914 msgid "Name clash." msgstr "" #: ../src/column.c:346 #, c-format msgid "Can't create column \"%s\". A column with that name already exists." msgstr "" #: ../src/column.c:408 msgid "Too few items." msgstr "" #: ../src/column.c:409 #, c-format msgid "This column only has %d items, but %s needs %d items." msgstr "" #: ../src/model.c:198 ../src/mainw.c:900 ../src/filemodel.c:526 #: ../src/filemodel.c:535 msgid "Load failed." msgstr "" #: ../src/model.c:199 #, c-format msgid "" "Unable to load from file \"%s\". Error log is:\n" "%s" msgstr "" #: ../src/model.c:425 ../src/model.c:442 ../src/model.c:497 ../src/model.c:516 #: ../src/filemodel.c:101 ../src/filemodel.c:170 ../src/filemodel.c:636 #: ../src/filemodel.c:675 #, c-format msgid "_%s() not implemented for class \"%s\"." msgstr "" #: ../src/model.c:561 ../src/filemodel.c:333 ../src/filemodel.c:348 msgid "XML library error." msgstr "" #: ../src/model.c:562 msgid "model_save: xmlNewChild() failed" msgstr "" #: ../src/model.c:629 msgid "XML load error." msgstr "" #: ../src/model.c:630 #, c-format msgid "Can't load node of type \"%s\" into object of type \"%s\"" msgstr "" #: ../src/model.c:877 msgid "Delete?" msgstr "" #: ../src/model.c:878 #, c-format msgid "Are you sure you want to delete %s \"%s\"?" msgstr "" #: ../src/panechild.c:108 msgid "Close the pane" msgstr "" #. Expands to (eg.) "Region on A1 at (10, 10), size (50, 50)" #. #. Used in (eg.) "Mark at (10, 10) on [A1, A2]" #. #: ../src/iregion.c:157 ../src/iarrow.c:114 msgid "on" msgstr "" #: ../src/iregion.c:167 #, c-format msgid "at (%d, %d), size (%d, %d)" msgstr "" #: ../src/iregion.c:182 ../src/iregion.c:224 msgid "Left" msgstr "" #: ../src/iregion.c:183 ../src/iregion.c:227 msgid "Top" msgstr "" #: ../src/iregion.c:184 ../src/iregion.c:230 msgid "Width" msgstr "" #: ../src/iregion.c:185 ../src/iregion.c:233 msgid "Height" msgstr "" #: ../src/iregion.c:224 msgid "Left edge of region" msgstr "" #: ../src/iregion.c:227 msgid "Top edge of region" msgstr "" #: ../src/iregion.c:230 msgid "Width of region" msgstr "" #: ../src/iregion.c:233 msgid "Height of region" msgstr "" #: ../src/iregion.c:465 msgid "Region" msgstr "" #: ../src/expr.c:64 #, c-format msgid "error in \"%s\"" msgstr "" #: ../src/expr.c:347 msgid "Error" msgstr "" #: ../src/expr.c:616 msgid "top level" msgstr "" #: ../src/expr.c:622 msgid "class" msgstr "" #: ../src/expr.c:625 msgid "instance" msgstr "" #: ../src/expr.c:629 msgid "definition" msgstr "" #: ../src/expr.c:636 #, c-format msgid "parameter \"%s\"" msgstr "" #: ../src/expr.c:640 msgid "member" msgstr "" #: ../src/expr.c:645 ../src/dump.c:186 msgid "value" msgstr "" #: ../src/expr.c:649 ../src/itext.c:451 msgid "function" msgstr "" #: ../src/expr.c:658 msgid "of" msgstr "" #: ../src/itext.c:67 msgid "Formula" msgstr "" #: ../src/itext.c:184 ../src/itext.c:330 msgid "no value" msgstr "" #: ../src/itext.c:508 ../src/itext.c:541 msgid "Dirty value" msgstr "" #: ../src/iarrow.c:106 msgid "No image" msgstr "" #: ../src/iarrow.c:132 ../src/iarrow.c:137 #, c-format msgid "at %d" msgstr "" #: ../src/iarrow.c:142 #, c-format msgid "at (%d, %d)" msgstr "" #: ../src/iarrow.c:149 #, c-format msgid "at (%d, %d), offset (%d, %d)" msgstr "" #: ../src/workspace.c:222 msgid "No objects selected." msgstr "" #: ../src/workspace.c:223 ../src/workspace.c:228 msgid "Select exactly one object and try again." msgstr "" #: ../src/workspace.c:227 msgid "More than one object selected." msgstr "" #: ../src/workspace.c:1061 msgid "Tab" msgstr "" #: ../src/workspace.c:1116 msgid "// private definitions for this tab\n" msgstr "" #: ../src/workspace.c:1161 #, c-format msgid "Can't create workspace \"%s\". A symbol with that name already exists." msgstr "" #: ../src/workspace.c:1192 msgid "Default empty tab" msgstr "" #: ../src/workspace.c:1218 ../src/class.c:803 msgid "Wrong number of arguments." msgstr "" #: ../src/workspace.c:1219 #, c-format msgid "%s needs %d arguments, there are %d selected." msgstr "" #: ../src/workspace.c:1230 msgid "Too many names selected." msgstr "" #: ../src/workspace.c:1342 msgid "You can only remove top level rows." msgstr "" #: ../src/workspace.c:1343 msgid "Not all selected objects are top level rows." msgstr "" #: ../src/workspace.c:1393 msgid "Delete selected objects?" msgstr "" #: ../src/workspace.c:1394 #, c-format msgid "Are you sure you want to delete %s?" msgstr "" #: ../src/workspace.c:1452 msgid "Unable to ungroup." msgstr "" #: ../src/workspace.c:1453 #, c-format msgid "Row \"%s\" is not a Group or a list." msgstr "" #: ../src/toolkitgroup.c:119 #, c-format msgid "Toolkits for %s" msgstr "" #: ../src/iimage.c:115 msgid "Original filename" msgstr "" #: ../src/iimage.c:151 #, c-format msgid "Header for \"%s\"" msgstr "" #: ../src/iimage.c:153 msgid "OK" msgstr "" #: ../src/iimage.c:366 msgid "Save timer." msgstr "" #: ../src/iimage.c:367 #, c-format msgid "Image save took %g seconds." msgstr "" #: ../src/iimage.c:424 msgid "Image" msgstr "" #: ../src/main.c:105 msgid "evaluate and print EXPRESSION" msgstr "" #: ../src/main.c:108 msgid "load FILE as a set of definitions" msgstr "" #: ../src/main.c:111 msgid "write value of 'main' to FILE" msgstr "" #: ../src/main.c:113 msgid "run in batch mode" msgstr "" #: ../src/main.c:115 msgid "set values" msgstr "" #: ../src/main.c:117 msgid "verbose error output" msgstr "" #: ../src/main.c:120 msgid "don't load menu definitions" msgstr "" #: ../src/main.c:122 msgid "don't try to load command-line arguments" msgstr "" #: ../src/main.c:124 msgid "load stdin as a workspace" msgstr "" #: ../src/main.c:126 msgid "load stdin as a set of definitions" msgstr "" #: ../src/main.c:128 msgid "print value of 'main' to stdout" msgstr "" #: ../src/main.c:131 msgid "start up and shut down" msgstr "" #: ../src/main.c:134 msgid "time image save operations" msgstr "" #: ../src/main.c:137 msgid "profile workspace calculation" msgstr "" #: ../src/main.c:140 msgid "start as if installed to PREFIX" msgstr "" #: ../src/main.c:142 msgid "output strings for internationalisation" msgstr "" #: ../src/main.c:145 msgid "print version number" msgstr "" #: ../src/main.c:148 msgid "test for errors and quit" msgstr "" #: ../src/main.c:231 #, c-format msgid "error calculating \"%s\"" msgstr "" #: ../src/main.c:239 #, c-format msgid "error saving \"%s\"" msgstr "" #: ../src/main.c:293 msgid "no \"main\" found" msgstr "" #: ../src/main.c:469 ../src/workspaceview.c:985 msgid "Unknown file type." msgstr "" #: ../src/main.c:470 ../src/workspaceview.c:986 #, c-format msgid "Unable to load \"%s\"." msgstr "" #: ../src/main.c:481 msgid "Unable to load." msgstr "" #: ../src/main.c:482 #, c-format msgid "Error loading plug-in \"%s\"." msgstr "" #: ../src/main.c:689 msgid "Next _Error" msgstr "" #: ../src/main.c:690 msgid "Ink dropper" msgstr "" #: ../src/main.c:691 msgid "D_uplicate" msgstr "" #: ../src/main.c:692 msgid "Pen" msgstr "" #: ../src/main.c:693 ../src/plot.c:98 msgid "Line" msgstr "" #: ../src/main.c:696 msgid "Flood" msgstr "" #: ../src/main.c:697 msgid "Flood Blob" msgstr "" #: ../src/main.c:698 msgid "Fill Rectangle" msgstr "" #: ../src/main.c:699 msgid "Pan" msgstr "" #: ../src/main.c:700 msgid "Select" msgstr "" #: ../src/main.c:701 msgid "Locked" msgstr "" #. And the LEDs we use. #. #: ../src/main.c:705 msgid "Red LED" msgstr "" #: ../src/main.c:706 msgid "Green LED" msgstr "" #: ../src/main.c:707 msgid "Blue LED" msgstr "" #: ../src/main.c:708 msgid "Yellow LED" msgstr "" #: ../src/main.c:709 msgid "Cyan LED" msgstr "" #: ../src/main.c:710 msgid "Off LED" msgstr "" #: ../src/main.c:884 msgid "Empty temp area" msgstr "" #: ../src/main.c:885 msgid "Many files in temp area." msgstr "" #: ../src/main.c:886 #, c-format msgid "" "The temp area \"%s\" contains %s of files. Would you like to empty the temp " "area? This will delete any workspace backups and cannot be undone." msgstr "" #: ../src/main.c:902 #, c-format msgid "unable to make %s %s: %s" msgstr "" #: ../src/main.c:976 msgid "Unable to find install area." msgstr "" #: ../src/main.c:1116 msgid "- image processing spreadsheet" msgstr "" #: ../src/main.c:1141 #, c-format msgid "linked to vips-%s" msgstr "" #. -1 means can't-be-set, at least on os x, so don't #. * warn. #. #: ../src/main.c:1193 #, c-format msgid "" "unable to change max file descriptors\n" "max file descriptors still set to %d" msgstr "" #: ../src/main.c:1199 msgid "unable to read max file descriptors" msgstr "" #: ../src/main.c:1475 ../src/main.c:1533 #, c-format msgid "" "Startup error log:\n" "%s" msgstr "" #: ../src/main.c:1532 msgid "Startup error." msgstr "" #: ../src/main.c:1543 #, c-format msgid "Welcome to %s-%s!" msgstr "" #: ../src/main.c:1548 #, c-format msgid "" "A new directory has been created to hold startup, data and temporary files:\n" "\n" " %s\n" "\n" "If you've used previous versions of %s, you might want to copy files over " "from your old work area." msgstr "" #: ../src/imageinfo.c:1023 msgid "Unable to open image." msgstr "" #: ../src/imageinfo.c:1024 #, c-format msgid "Unable to open file \"%s\" as image." msgstr "" #: ../src/imageinfo.c:1152 msgid "Unable to write to file." msgstr "" #: ../src/imageinfo.c:1153 #, c-format msgid "Error writing image to file \"%s\"." msgstr "" #: ../src/imageinfo.c:1169 msgid "Unable to paint on image." msgstr "" #: ../src/imageinfo.c:1170 #, c-format msgid "" "Unable to get write permission for file \"%s\".\n" "Check permission settings." msgstr "" #: ../src/imageinfo.c:1216 msgid "Modify" msgstr "" #: ../src/imageinfo.c:1217 msgid "Modify disc file?" msgstr "" #: ../src/imageinfo.c:1218 #, c-format msgid "" "This image is being shown directly from the disc file:\n" "\n" " %s\n" "\n" "If you paint on this file, it will be permanently changed. If something goes " "wrong, you may lose work. Are you sure you want to modify this file?" msgstr "" #: ../src/imageinfo.c:1822 msgid "Unable to paint text." msgstr "" #: ../src/imageinfo.c:1823 #, c-format msgid "Unable to paint text \"%s\" in font \"%s\"." msgstr "" #: ../src/editview.c:136 msgid "Escape to cancel edit, press Return to accept edit and recalculate" msgstr "" #: ../src/dump.c:187 msgid "parameter" msgstr "" #: ../src/dump.c:188 msgid "zombie" msgstr "" #: ../src/dump.c:189 ../src/util.c:1311 msgid "workspace" msgstr "" #: ../src/dump.c:190 msgid "workspace root" msgstr "" #: ../src/dump.c:191 msgid "root symbol" msgstr "" #: ../src/dump.c:192 msgid "external symbol" msgstr "" #: ../src/dump.c:193 msgid "built-in symbol" msgstr "" #: ../src/colour.c:306 msgid "Color Space" msgstr "" #. Init methods. #. #: ../src/number.c:66 msgid "Number" msgstr "" #: ../src/mainw.c:322 msgid "No temp area" msgstr "" #: ../src/mainw.c:328 #, c-format msgid "%s free" msgstr "" #: ../src/mainw.c:341 #, c-format msgid "%d cells free" msgstr "" #: ../src/mainw.c:381 msgid "Selected:" msgstr "" #: ../src/mainw.c:423 msgid "unsaved workspace" msgstr "" #: ../src/mainw.c:430 msgid "compatibility mode" msgstr "" #: ../src/mainw.c:661 #, c-format msgid "%d objects in workspace" msgstr "" #: ../src/mainw.c:666 #, c-format msgid "%d vips calls cached" msgstr "" #: ../src/mainw.c:679 #, c-format msgid " in %d images" msgstr "" #: ../src/mainw.c:765 msgid "Find in workspace not implemented yet." msgstr "" #: ../src/mainw.c:773 msgid "Find again in workspace not implemented yet." msgstr "" #: ../src/mainw.c:795 msgid "No errors in workspace." msgstr "" #: ../src/mainw.c:796 msgid "There are no errors (that I can see) in this workspace." msgstr "" #: ../src/mainw.c:901 #, c-format msgid "" "Unable to execute:\n" " %s" msgstr "" #: ../src/mainw.c:931 ../src/mainw.c:958 msgid "Open File" msgstr "" #: ../src/mainw.c:1085 msgid "Recent Images" msgstr "" #: ../src/mainw.c:1093 msgid "Recent Workspaces" msgstr "" #: ../src/mainw.c:1101 msgid "Recent Matricies" msgstr "" #: ../src/mainw.c:1110 msgid "No recent items" msgstr "" #: ../src/mainw.c:1116 msgid "Clear Recent Menu" msgstr "" #: ../src/mainw.c:1175 msgid "Merge Workspace from File" msgstr "" #: ../src/mainw.c:1234 ../src/mainw.c:1241 msgid "No backup workspaces found." msgstr "" #: ../src/mainw.c:1236 msgid "" "You need to enable \"Auto workspace save\" in Preferences before automatic " "recovery works." msgstr "" #: ../src/mainw.c:1242 #, c-format msgid "No suitable workspace save files found in \"%s\"" msgstr "" #: ../src/mainw.c:1257 msgid "Open workspace backup?" msgstr "" #: ../src/mainw.c:1258 #, c-format msgid "" "Found workspace backup:\n" "\n" "\t%s\n" "\n" "Do you want to recover this workspace?" msgstr "" #: ../src/mainw.c:1332 msgid "Set column name here" msgstr "" #: ../src/mainw.c:1334 msgid "Set column caption here" msgstr "" #: ../src/mainw.c:1336 msgid "New Column" msgstr "" #: ../src/mainw.c:1340 msgid "Create Column" msgstr "" #: ../src/mainw.c:1497 msgid "Revert to Defaults" msgstr "" #: ../src/mainw.c:1498 msgid "Revert to installation defaults?" msgstr "" #: ../src/mainw.c:1499 msgid "" "Would you like to reset all preferences to their factory settings? This will " "delete any changes you have ever made to your preferences and may take a few " "seconds." msgstr "" #: ../src/mainw.c:1516 msgid "Preferences" msgstr "" #: ../src/mainw.c:1521 msgid "Revert to Defaults ..." msgstr "" #. Menu items. #. #: ../src/mainw.c:1591 msgid "Open _Recent" msgstr "" #: ../src/mainw.c:1592 ../src/workspaceview.c:1216 msgid "Jump to _Column" msgstr "" #: ../src/mainw.c:1593 msgid "_Toolkits" msgstr "" #: ../src/mainw.c:1603 ../src/mainw.c:1608 msgid "C_olumn" msgstr "" #: ../src/mainw.c:1604 msgid "Create a new column" msgstr "" #: ../src/mainw.c:1609 msgid "Create a new column with a specified name" msgstr "" #: ../src/mainw.c:1613 msgid "_Tab" msgstr "" #: ../src/mainw.c:1614 msgid "Create a new tab" msgstr "" #: ../src/mainw.c:1618 msgid "_Workspace" msgstr "" #: ../src/mainw.c:1619 msgid "Create a new workspace" msgstr "" #: ../src/mainw.c:1623 msgid "_Open" msgstr "" #: ../src/mainw.c:1624 msgid "Open a file" msgstr "" #: ../src/mainw.c:1628 msgid "Open _Examples" msgstr "" #: ../src/mainw.c:1629 msgid "Open example workspaces" msgstr "" #: ../src/mainw.c:1633 msgid "_Duplicate Workspace" msgstr "" #: ../src/mainw.c:1634 msgid "Duplicate workspace" msgstr "" #: ../src/mainw.c:1638 msgid "_Merge Into Workspace" msgstr "" #: ../src/mainw.c:1639 msgid "Merge workspace into this workspace" msgstr "" #: ../src/mainw.c:1643 msgid "_Save Workspace" msgstr "" #: ../src/mainw.c:1644 msgid "Save workspace" msgstr "" #: ../src/mainw.c:1648 msgid "_Save Workspace As" msgstr "" #: ../src/mainw.c:1649 msgid "Save workspace as" msgstr "" #: ../src/mainw.c:1653 msgid "Search for Workspace _Backups" msgstr "" #: ../src/mainw.c:1654 msgid "Load last automatically backed-up workspace" msgstr "" #: ../src/mainw.c:1658 ../src/program.c:1802 msgid "_Delete" msgstr "" #: ../src/mainw.c:1659 msgid "Delete selected items" msgstr "" #: ../src/mainw.c:1664 msgid "Select all items" msgstr "" #: ../src/mainw.c:1668 msgid "D_uplicate Selected" msgstr "" #: ../src/mainw.c:1669 msgid "Duplicate selected items" msgstr "" #: ../src/mainw.c:1674 msgid "Recalculate selected items" msgstr "" #: ../src/mainw.c:1678 ../src/program.c:1827 msgid "_Find" msgstr "" #: ../src/mainw.c:1679 msgid "Find in workspace" msgstr "" #: ../src/mainw.c:1683 ../src/program.c:1832 msgid "Find _Next" msgstr "" #: ../src/mainw.c:1684 msgid "Find again in workspace" msgstr "" #: ../src/mainw.c:1689 msgid "Jump to next error" msgstr "" #: ../src/mainw.c:1693 msgid "_Group" msgstr "" #: ../src/mainw.c:1694 msgid "Group selected items" msgstr "" #: ../src/mainw.c:1699 msgid "Ungroup selected items" msgstr "" #: ../src/mainw.c:1703 msgid "_Preferences" msgstr "" #: ../src/mainw.c:1704 msgid "Edit preferences" msgstr "" #: ../src/mainw.c:1709 msgid "Workspace as Grap_h" msgstr "" #: ../src/mainw.c:1710 msgid "Show a graph of workspace dependencies" msgstr "" #: ../src/mainw.c:1716 msgid "Edit toolkits" msgstr "" #: ../src/mainw.c:1722 msgid "Au_to Recalculate" msgstr "" #: ../src/mainw.c:1723 msgid "Recalculate automatically on change" msgstr "" #: ../src/mainw.c:1727 msgid "_Lock tab" msgstr "" #: ../src/mainw.c:1728 msgid "Lock tab" msgstr "" #: ../src/mainw.c:1732 msgid "_Toolbar" msgstr "" #: ../src/mainw.c:1733 msgid "Show window toolbar" msgstr "" #: ../src/mainw.c:1737 msgid "_Statusbar" msgstr "" #: ../src/mainw.c:1738 msgid "Show window statusbar" msgstr "" #: ../src/mainw.c:1742 msgid "Toolkit _Browser" msgstr "" #: ../src/mainw.c:1743 msgid "Show toolkit browser" msgstr "" #: ../src/mainw.c:1747 msgid "Tab _Definitions" msgstr "" #: ../src/mainw.c:1748 msgid "Show tab definitions" msgstr "" #: ../src/mainw.c:1754 msgid "_Normal" msgstr "" #: ../src/mainw.c:1755 msgid "Normal view mode" msgstr "" #: ../src/mainw.c:1759 msgid "Show _Formula" msgstr "" #: ../src/mainw.c:1760 msgid "Show formula view mode" msgstr "" #: ../src/mainw.c:1764 msgid "No _Edits" msgstr "" #: ../src/mainw.c:1765 msgid "No edits view mode" msgstr "" #: ../src/regionview.c:906 msgid "You can only duplicate top level regions." msgstr "" #: ../src/regionview.c:948 msgid "Can't delete." msgstr "" #: ../src/regionview.c:949 msgid "You can only delete top level regions." msgstr "" #: ../src/regionview.c:958 msgid "Delete Region?" msgstr "" #: ../src/regionview.c:959 #, c-format msgid "Are you sure you want to delete Region \"%s\"?" msgstr "" #. Other init. #. #: ../src/regionview.c:984 msgid "Region menu" msgstr "" #: ../src/idialog.c:432 msgid "Pin up" msgstr "" #: ../src/idialog.c:434 msgid "Check this to pin the dialog up" msgstr "" #: ../src/call.c:136 msgid "CALL library error." msgstr "" #: ../src/call.c:137 ../src/cache.c:878 #, c-format msgid "Error calling library function \"%s\" (%s)." msgstr "" #: ../src/call.c:148 ../src/class.c:862 ../src/cache.c:852 msgid "You passed:" msgstr "" #: ../src/call.c:196 msgid "Usage:" msgstr "" #: ../src/call.c:198 #, c-format msgid "CALL operator \"%s\"" msgstr "" #: ../src/call.c:200 #, c-format msgid "%s, from package \"%s\"" msgstr "" #: ../src/call.c:205 #, c-format msgid "\"%s\" takes %d argument:" msgid_plural "\"%s\" takes %d arguments:" msgstr[0] "" msgstr[1] "" #: ../src/call.c:212 #, c-format msgid "And produces %d result:" msgid_plural "And produces %d results:" msgstr[0] "" msgstr[1] "" #. Print any flags this function has. #. #: ../src/call.c:220 msgid "Flags:" msgstr "" #: ../src/call.c:224 msgid "PIO function" msgstr "" #: ../src/call.c:226 msgid "WIO function" msgstr "" #: ../src/call.c:229 msgid "coordinate transformer" msgstr "" #: ../src/call.c:231 msgid "no coordinate transformation" msgstr "" #: ../src/call.c:234 msgid "point-to-point operation" msgstr "" #: ../src/call.c:236 msgid "area operation" msgstr "" #: ../src/call.c:239 msgid "uncacheable operation" msgstr "" #: ../src/call.c:241 msgid "operation can be cached" msgstr "" #: ../src/call.c:256 #, c-format msgid "Argument %d (%s) to \"%s\" is the wrong type." msgstr "" #: ../src/call.c:276 #, c-format msgid "Too many arguments to \"%s\"." msgstr "" #: ../src/call.c:294 msgid "Unknown type." msgstr "" #: ../src/call.c:295 #, c-format msgid "CALL type \"%s\" not supported" msgstr "" #: ../src/call.c:1266 ../src/call.c:1350 #, c-format msgid "image \"%s\"" msgstr "" #: ../src/call.c:1273 msgid "no image" msgstr "" #: ../src/call.c:1304 msgid "doublevec" msgstr "" #: ../src/call.c:1346 msgid "imagevec" msgstr "" #: ../src/class.c:50 #, c-format msgid "Object %s is not a class." msgstr "" #: ../src/class.c:333 msgid "No such secret." msgstr "" #: ../src/class.c:334 msgid "" "Editing local classes which reference non-local objects is a bit broken at " "the moment :-(" msgstr "" #: ../src/class.c:658 #, c-format msgid "You can't have more than %d arguments to a superclass constructor." msgstr "" #: ../src/class.c:794 ../src/class.c:854 msgid "Bad superclass." msgstr "" #: ../src/class.c:795 #, c-format msgid "Superclass constructor \"%s\" refers to non-local symbols %s" msgstr "" #: ../src/class.c:804 #, c-format msgid "Superclass constructor \"%s\" expects %d arguments, not %d." msgstr "" #: ../src/class.c:858 #, c-format msgid "First element in superclass of \"%s\" must be class or constructor." msgstr "" #: ../src/class.c:890 ../src/class.c:987 #, c-format msgid "" "Too many arguments to class constructor \"%s\". No more than %d arguments " "are supported." msgstr "" #: ../src/class.c:980 msgid "Class not found." msgstr "" #: ../src/class.c:981 #, c-format msgid "Class \"%s\" not found." msgstr "" #: ../src/class.c:1014 #, c-format msgid "Member \"%s\" of class \"%s\" should be of type \"%s\", instead it's:" msgstr "" #: ../src/filemodel.c:334 msgid "model_save_filename: xmlNewDoc() failed" msgstr "" #: ../src/filemodel.c:349 msgid "model_save_filename: xmlNewDocNode() failed" msgstr "" #: ../src/filemodel.c:363 msgid "Save failed." msgstr "" #: ../src/filemodel.c:364 #, c-format msgid "" "Save of %s \"%s\" to file \"%s\" failed.\n" "%s" msgstr "" #: ../src/filemodel.c:419 msgid "filemodel_real_top_save: no save method" msgstr "" #: ../src/filemodel.c:527 #, c-format msgid "Can't load XML file \"%s\", it's not a %s save file." msgstr "" #: ../src/filemodel.c:536 #, c-format msgid "" "Can't load XML file \"%s\", unable to extract version information from " "namespace." msgstr "" #. Expands to (eg.) "Save Column A2". #. #: ../src/filemodel.c:724 #, c-format msgid "Save %s %s" msgstr "" #: ../src/filemodel.c:800 ../src/filemodel.c:811 msgid "Object has been modified." msgstr "" #: ../src/filemodel.c:801 #, c-format msgid "" "%s has been modified since you loaded it from file \"%s\".\n" "\n" "Do you want to save your changes?" msgstr "" #: ../src/filemodel.c:812 #, c-format msgid "%s has been modified. Do you want to save your changes?" msgstr "" #: ../src/builtin.c:262 msgid "Out of range." msgstr "" #: ../src/builtin.c:263 msgid "gammq arguments must be a > 0, x >= 0." msgstr "" #: ../src/builtin.c:270 msgid "Not available." msgstr "" #: ../src/builtin.c:271 msgid "No GSL library available for gammq." msgstr "" #: ../src/builtin.c:382 #, c-format msgid "" "Argument 2 to \"%s\" should be instance of \"%s\", you passed:\n" " %s" msgstr "" #: ../src/builtin.c:483 msgid "Complex math ops not implemented." msgstr "" #: ../src/builtin.c:558 msgid "Macro error." msgstr "" #: ../src/builtin.c:743 msgid "No such type" msgstr "" #: ../src/builtin.c:744 #, c-format msgid "GType %u not found." msgstr "" #. Other. #. #: ../src/builtin.c:898 msgid "return list of names of members" msgstr "" #: ../src/builtin.c:901 msgid "search for file" msgstr "" #: ../src/builtin.c:904 msgid "raise error" msgstr "" #: ../src/builtin.c:907 msgid "convert to [char]" msgstr "" #: ../src/builtin.c:910 msgid "expand environment variables" msgstr "" #: ../src/builtin.c:913 msgid "convert [char] to GType" msgstr "" #: ../src/builtin.c:916 msgid "convert GType to [char]" msgstr "" #: ../src/builtin.c:919 msgid "look up localised string" msgstr "" #. vips8 wrapper. #. #: ../src/builtin.c:925 msgid "create new vips8 object" msgstr "" #: ../src/builtin.c:928 msgid "call vips8 operator" msgstr "" #. Predicates. #. #: ../src/builtin.c:934 msgid "true if argument is primitive image" msgstr "" #: ../src/builtin.c:937 msgid "true if argument is primitive bool" msgstr "" #: ../src/builtin.c:940 msgid "true if argument is primitive real number" msgstr "" #: ../src/builtin.c:943 msgid "true if argument is class" msgstr "" #: ../src/builtin.c:946 msgid "true if argument is primitive char" msgstr "" #: ../src/builtin.c:949 msgid "true if argument is primitive list" msgstr "" #: ../src/builtin.c:952 msgid "true if argument is primitive complex" msgstr "" #: ../src/builtin.c:955 msgid "true if argument class instance of type" msgstr "" #: ../src/builtin.c:958 msgid "true if class has named member" msgstr "" #. List and complex projections. #. #: ../src/builtin.c:964 msgid "real part of complex" msgstr "" #: ../src/builtin.c:967 msgid "imaginary part of complex" msgstr "" #: ../src/builtin.c:970 msgid "head of list" msgstr "" #: ../src/builtin.c:973 msgid "tail of list" msgstr "" #. Math. #. #: ../src/builtin.c:979 msgid "sine of real number" msgstr "" #: ../src/builtin.c:982 msgid "cosine of real number" msgstr "" #: ../src/builtin.c:985 msgid "tangent of real number" msgstr "" #: ../src/builtin.c:988 msgid "arc sine of real number" msgstr "" #: ../src/builtin.c:991 msgid "arc cosine of real number" msgstr "" #: ../src/builtin.c:994 msgid "arc tangent of real number" msgstr "" #: ../src/builtin.c:997 msgid "log base e of real number" msgstr "" #: ../src/builtin.c:1000 msgid "log base 10 of real number" msgstr "" #: ../src/builtin.c:1003 msgid "e to the power of real number" msgstr "" #: ../src/builtin.c:1006 msgid "10 to the power of real number" msgstr "" #: ../src/builtin.c:1009 msgid "real to int, rounding up" msgstr "" #: ../src/builtin.c:1012 msgid "real to int, rounding down" msgstr "" #. Optional GSL funcs. #. #: ../src/builtin.c:1018 msgid "gamma function" msgstr "" #. Constructors. #. #: ../src/builtin.c:1024 msgid "load vips image" msgstr "" #: ../src/builtin.c:1027 msgid "load text file" msgstr "" #: ../src/builtin.c:1030 msgid "generate image from Plot object" msgstr "" #: ../src/builtin.c:1041 msgid "GSL library error." msgstr "" #: ../src/builtin.c:1090 #, c-format msgid "Builtin \"%s\" takes %d argument." msgid_plural "Builtin \"%s\" takes %d arguments." msgstr[0] "" msgstr[1] "" #: ../src/builtin.c:1145 #, c-format msgid "" "Argument %d to builtin \"%s\" should be \"%s\", you passed:\n" " %s" msgstr "" #: ../src/compile.c:1447 msgid "Too many shared nodes in graph." msgstr "" #: ../src/compile.c:1449 msgid "Raise MAX_RELOC" msgstr "" #: ../src/compile.c:1766 #, c-format msgid "Member \"%s\" of class \"%s\" should have no arguments." msgstr "" #: ../src/compile.c:2643 msgid "pattern match failed" msgstr "" #: ../src/pathnameview.c:153 msgid "Select a new file name" msgstr "" #: ../src/spin.c:197 msgid "Expand or collapse row" msgstr "" #: ../src/error.c:60 msgid "No ierrors found." msgstr "" #: ../src/error.c:100 msgid "No unresolved symbols found." msgstr "" #: ../src/error.c:116 msgid "Clear ierror window" msgstr "" #: ../src/error.c:120 msgid "List _iErrors" msgstr "" #: ../src/error.c:121 msgid "Search for all ierrors" msgstr "" #: ../src/error.c:125 msgid "List _Unresolved" msgstr "" #: ../src/error.c:126 msgid "Search for all unresolved references" msgstr "" #: ../src/error.c:202 #, c-format msgid "iError - %s" msgstr "" #. used as in "fred refers to undefined symbol jim" #. #: ../src/tool.c:75 msgid "refers to undefined symbol" msgstr "" #: ../src/tool.c:915 #, c-format msgid "" "Can't create dialog with name \"%s\", an object with that name already " "exists in kit \"%s\"." msgstr "" #: ../src/util.c:211 msgid "Unable to set XML property." msgstr "" #: ../src/util.c:212 #, c-format msgid "Unable to set property \"%s\" to value \"%s\"." msgstr "" #: ../src/util.c:790 msgid "(no image)" msgstr "" #: ../src/util.c:804 #, c-format msgid "%dx%d %s, %d band, %s" msgid_plural "%dx%d %s, %d bands, %s" msgstr[0] "" msgstr[1] "" #: ../src/util.c:1217 msgid "8-bit unsigned integer" msgstr "" #. IM_BANDFMT_UCHAR #: ../src/util.c:1218 msgid "8-bit signed integer" msgstr "" #. IM_BANDFMT_CHAR #: ../src/util.c:1219 msgid "16-bit unsigned integer" msgstr "" #. IM_BANDFMT_USHORT #: ../src/util.c:1220 msgid "16-bit signed integer" msgstr "" #. IM_BANDFMT_SHORT #: ../src/util.c:1221 msgid "32-bit unsigned integer" msgstr "" #. IM_BANDFMT_UINT #: ../src/util.c:1222 msgid "32-bit signed integer" msgstr "" #. IM_BANDFMT_INT #: ../src/util.c:1223 msgid "32-bit float" msgstr "" #. IM_BANDFMT_FLOAT #: ../src/util.c:1224 msgid "64-bit complex" msgstr "" #. IM_BANDFMT_COMPLEX #: ../src/util.c:1225 msgid "64-bit float" msgstr "" #. IM_BANDFMT_DOUBLE #: ../src/util.c:1226 msgid "128-bit complex" msgstr "" #: ../src/util.c:1234 msgid "" msgstr "" #: ../src/util.c:1278 msgid "" msgstr "" #: ../src/util.c:1302 msgid "directory" msgstr "" #: ../src/util.c:1711 msgid "" msgstr "" #: ../src/util.c:1908 ../src/util.c:1914 ../src/filesel.c:760 msgid "Bad filename." msgstr "" #: ../src/util.c:1909 msgid "Filename is too long." msgstr "" #: ../src/util.c:1915 msgid "Filename contains only blank characters." msgstr "" #: ../src/util.c:1978 ../src/util.c:1987 ../src/util.c:2042 msgid "Unable to open." msgstr "" #: ../src/util.c:1979 ../src/util.c:1988 #, c-format msgid "" "Unable to open file \"%s\" for reading.\n" "%s." msgstr "" #: ../src/util.c:2043 #, c-format msgid "" "Unable to open file \"%s\" for writing.\n" "%s." msgstr "" #: ../src/util.c:2064 ../src/plotwindow.c:191 msgid "Unable to write." msgstr "" #: ../src/util.c:2065 #, c-format msgid "" "Unable to write to file \"%s\".\n" "%s." msgstr "" #: ../src/util.c:2101 ../src/util.c:2137 msgid "Unable to read." msgstr "" #: ../src/util.c:2102 #, c-format msgid "File \"%s\" too large." msgstr "" #: ../src/util.c:2138 #, c-format msgid "" "Unable to read from file \"%s\".\n" "%s." msgstr "" #: ../src/util.c:2445 msgid "Unable to create temporary file." msgstr "" #: ../src/util.c:2446 #, c-format msgid "" "Unable to make file \"%s\"\n" "%s" msgstr "" #: ../src/util.c:2653 msgid "Out of memory." msgstr "" #: ../src/util.c:2654 #, c-format msgid "Request for %s of RAM triggered memory allocation failure." msgstr "" #: ../src/formula.c:143 msgid "" "Press Escape to cancel edit, press Return to accept edit and recalculate" msgstr "" #: ../src/colourdisplay.c:246 msgid "Double-click to edit this color, or drag-and-drop between colors" msgstr "" #: ../src/plotwindow.c:223 msgid "Export Plot As" msgstr "" #: ../src/plotwindow.c:242 msgid "Export Plot" msgstr "" #: ../src/plotwindow.c:243 msgid "Export plot to file" msgstr "" #: ../src/path.c:560 #, c-format msgid "File \"%s\" not found." msgstr "" #: ../src/path.c:591 #, c-format msgid "File \"%s\" not found on path" msgstr "" #: ../src/workspaceview.c:1071 msgid "No errors in tab." msgstr "" #: ../src/workspaceview.c:1072 msgid "There are no errors (that I can see) in this tab." msgstr "" #. Toolkit Browser pane. #. #: ../src/workspaceview.c:1185 msgid "Toolkit Browser" msgstr "" #. Workspace-local defs pane. #. #: ../src/workspaceview.c:1201 msgid "Tab Definitions" msgstr "" #: ../src/workspaceview.c:1211 msgid "Workspace menu" msgstr "" #: ../src/workspaceview.c:1213 msgid "New C_olumn" msgstr "" #: ../src/workspaceview.c:1218 msgid "_Group Selected" msgstr "" #: ../src/imageheader.c:224 msgid "Field" msgstr "" #: ../src/imageheader.c:239 msgid "Image history" msgstr "" #: ../src/filesel.c:86 msgid "Workspace files (*.ws)" msgstr "" #: ../src/filesel.c:88 msgid "Recombination matrix files (*.rec)" msgstr "" #: ../src/filesel.c:90 msgid "Morphology matrix files (*.mor)" msgstr "" #: ../src/filesel.c:92 msgid "Convolution matrix files (*.con)" msgstr "" #: ../src/filesel.c:94 msgid "Matrix files (*.mat)" msgstr "" #: ../src/filesel.c:96 msgid "Definition files (*.def)" msgstr "" #: ../src/filesel.c:98 msgid "ICC profiles (*.icc, *.icm)" msgstr "" #: ../src/filesel.c:100 msgid "All files (*)" msgstr "" #. Used as eg. "VIPS image files (*.v)" #. #: ../src/filesel.c:133 msgid "image files" msgstr "" #: ../src/filesel.c:502 #, c-format msgid "Unable to determine space free in \"%s\"." msgstr "" #. Expands to (eg.) '6GB free in "/pics/tmp"' #. #: ../src/filesel.c:513 #, c-format msgid "free in \"%s\"" msgstr "" #: ../src/filesel.c:761 msgid "No file selected." msgstr "" #: ../src/filesel.c:985 msgid "Increment filename" msgstr "" #: ../src/filesel.c:991 msgid "After Save, add 1 to the last number in the file name" msgstr "" #: ../src/filesel.c:1236 #, c-format msgid "%s Save Preferences" msgstr "" #: ../src/filesel.c:1297 msgid "Overwrite" msgstr "" #: ../src/filesel.c:1298 msgid "Overwrite file?" msgstr "" #: ../src/filesel.c:1299 #, c-format msgid "File \"%s\" exists. OK to overwrite?" msgstr "" #: ../src/link.c:582 msgid "Circular dependency." msgstr "" #: ../src/link.c:583 #, c-format msgid "Circular dependency detected near symbol \"%s\"." msgstr "" #: ../src/classmodel.c:154 ../src/classmodel.c:226 #, c-format msgid "_%s() method not implemented for %s." msgstr "" #: ../src/classmodel.c:162 #, c-format msgid "Save %s \"%s\"" msgstr "" #: ../src/classmodel.c:235 #, c-format msgid "Replace %s \"%s\"" msgstr "" #: ../src/classmodel.c:697 msgid "Set boolean value here" msgstr "" #: ../src/classmodel.c:703 msgid "Enter a floating point number here" msgstr "" #: ../src/classmodel.c:710 msgid "Enter a string here" msgstr "" #: ../src/classmodel.c:1070 msgid "Unknown option." msgstr "" #: ../src/classmodel.c:1071 #, c-format msgid "Option \"%s\" not known." msgstr "" #: ../src/classmodel.c:1147 #, c-format msgid "%d band value only" msgstr "" #: ../src/clock.c:59 ../src/clock.c:92 ../src/clock.c:191 msgid "Interval" msgstr "" #: ../src/clock.c:60 ../src/clock.c:95 msgid "Elapsed time" msgstr "" #: ../src/clock.c:92 msgid "Interval between ticks (seconds)" msgstr "" #: ../src/clock.c:95 msgid "Elapsed time (seconds)" msgstr "" #: ../src/clock.c:216 msgid "Clock" msgstr "" #: ../src/workspacedefs.c:96 #, c-format msgid "%d definition" msgid_plural "%d definitions" msgstr[0] "" msgstr[1] "" #: ../src/workspacedefs.c:102 msgid "errors" msgstr "" #: ../src/workspacedefs.c:107 ../src/program.c:254 msgid "modified" msgstr "" #: ../src/workspacedefs.c:192 msgid "Replace Definition From File" msgstr "" #: ../src/workspacedefs.c:269 msgid "Workspace definitions" msgstr "" #: ../src/workspacedefs.c:285 msgid "Process" msgstr "" #. Create signals. #. #. Init methods. #. #: ../src/statusview.c:108 ../src/plotstatus.c:99 msgid "Status bar menu" msgstr "" #: ../src/statusview.c:223 ../src/statusview.c:226 ../src/plotstatus.c:190 msgid "Magnification" msgstr "" #: ../src/reduce.c:135 msgid "Typecheck error." msgstr "" #: ../src/reduce.c:137 #, c-format msgid "%s expected %s, instead saw:" msgstr "" #: ../src/reduce.c:149 #, c-format msgid "%s too long." msgstr "" #: ../src/reduce.c:532 ../src/reduce.c:597 msgid "Not rectangular." msgstr "" #: ../src/reduce.c:533 ../src/reduce.c:598 #, c-format msgid "" "Matrix of real is not rectangular. Found row of length %d, should be %d." msgstr "" #: ../src/reduce.c:557 msgid "Zero dimension." msgstr "" #: ../src/reduce.c:558 #, c-format msgid "Matrix has width %d, height %d." msgstr "" #: ../src/reduce.c:886 msgid "List length" msgstr "" #: ../src/reduce.c:935 #, c-format msgid "List index must be positive, not %d" msgstr "" #: ../src/reduce.c:943 msgid "List index" msgstr "" #: ../src/reduce.c:948 #, c-format msgid "List only has %d elements, unable to get element %d." msgstr "" #: ../src/reduce.c:991 msgid "No arguments allowed." msgstr "" #: ../src/reduce.c:992 #, c-format msgid "Object \"%s\" should have no arguments." msgstr "" #: ../src/reduce.c:1109 msgid "Cancelled." msgstr "" #: ../src/reduce.c:1110 msgid "Evaluation cancelled." msgstr "" #: ../src/reduce.c:1205 msgid "No value." msgstr "" #: ../src/reduce.c:1206 #, c-format msgid "Symbol \"%s\" has no value." msgstr "" #: ../src/reduce.c:1681 ../src/reduce.c:1686 ../src/reduce.c:1692 msgid "List generator" msgstr "" #: ../src/defbrowser.c:259 msgid "Tooltip" msgstr "" #: ../src/plot.c:80 msgid "YYYY" msgstr "" #: ../src/plot.c:81 msgid "XYYY" msgstr "" #: ../src/plot.c:82 msgid "XYXY" msgstr "" #: ../src/plot.c:97 msgid "Point" msgstr "" #: ../src/plot.c:99 msgid "Spline" msgstr "" #: ../src/plot.c:100 msgid "Bar" msgstr "" #: ../src/plot.c:149 msgid "More than one column needed or XY plots" msgstr "" #: ../src/plot.c:159 msgid "Even number of columns only for XY format plots" msgstr "" #: ../src/plot.c:325 msgid "Format" msgstr "" #: ../src/plot.c:328 msgid "Style" msgstr "" #: ../src/plot.c:331 msgid "Xmin" msgstr "" #: ../src/plot.c:334 msgid "Xmax" msgstr "" #: ../src/plot.c:337 msgid "Ymin" msgstr "" #: ../src/plot.c:340 msgid "Ymax" msgstr "" #: ../src/plot.c:346 msgid "X Axis Caption" msgstr "" #: ../src/plot.c:349 msgid "Y Axis Caption" msgstr "" #: ../src/plot.c:353 msgid "Series Captions" msgstr "" #: ../src/plot.c:360 msgid "Options" msgstr "" #: ../src/plot.c:384 msgid "1xn or nx1 images only for Plot" msgstr "" #: ../src/plot.c:403 msgid "Unable to prepare image." msgstr "" #: ../src/plot.c:416 msgid "1xn or nx1 images only" msgstr "" #: ../src/program.c:72 msgid "Edit window" msgstr "" #: ../src/program.c:625 msgid "Menu item text" msgstr "" #: ../src/program.c:628 msgid "Load column from this file" msgstr "" #: ../src/program.c:630 #, c-format msgid "Edit Column Item \"%s\"" msgstr "" #: ../src/program.c:635 msgid "Set column item" msgstr "" #: ../src/program.c:656 ../src/program.c:662 msgid "Unable to save." msgstr "" #: ../src/program.c:657 msgid "You can only save toolkits, not tools." msgstr "" #: ../src/program.c:663 msgid "You can't save auto-generated toolkits." msgstr "" #. Create signals. #. #. Init methods. #. #: ../src/program.c:726 msgid "Toolkit menu" msgstr "" #: ../src/program.c:1176 msgid "Set toolkit name here" msgstr "" #: ../src/program.c:1178 msgid "Set toolkit caption here" msgstr "" #: ../src/program.c:1179 msgid "New Toolkit" msgstr "" #: ../src/program.c:1183 ../src/program.c:1261 msgid "Create" msgstr "" #: ../src/program.c:1194 msgid "Nothing selected." msgstr "" #: ../src/program.c:1195 msgid "No toolkit selected." msgstr "" #: ../src/program.c:1254 msgid "Display this name" msgstr "" #: ../src/program.c:1256 msgid "Load this file" msgstr "" #: ../src/program.c:1317 msgid "Load Definition" msgstr "" #: ../src/program.c:1371 msgid "Reload" msgstr "" #: ../src/program.c:1372 msgid "Reload startup objects?" msgstr "" #: ../src/program.c:1373 msgid "" "Would you like to reload all startup menus, workspaces and plugins now? This " "may take a few seconds." msgstr "" #: ../src/program.c:1455 msgid "No tool selected" msgstr "" #: ../src/program.c:1499 msgid "Bad regular expression." msgstr "" #: ../src/program.c:1518 #, c-format msgid "No match found for \"%s\"." msgstr "" #: ../src/program.c:1531 msgid "Find in all Toolkits" msgstr "" #: ../src/program.c:1541 msgid "Enter search string here" msgstr "" #: ../src/program.c:1592 #, c-format msgid "No top-level symbol called \"%s\"." msgstr "" #: ../src/program.c:1600 #, c-format msgid "Symbol \"%s\" has no tool inforation." msgstr "" #: ../src/program.c:1621 msgid "Go to definition of this symbol" msgstr "" #: ../src/program.c:1623 msgid "Go to Definition" msgstr "" #: ../src/program.c:1653 msgid "Object information." msgstr "" #: ../src/program.c:1709 msgid "No documentation available." msgstr "" #: ../src/program.c:1710 msgid "" "On-line documentation is only currently available for VIPS functions and nip " "builtins." msgstr "" #: ../src/program.c:1737 msgid "New _Tool" msgstr "" #: ../src/program.c:1738 msgid "Make a new tool" msgstr "" #: ../src/program.c:1742 msgid "New Tool_kit" msgstr "" #: ../src/program.c:1743 msgid "Make a new toolkit" msgstr "" #: ../src/program.c:1747 msgid "New _Separator" msgstr "" #: ../src/program.c:1748 msgid "Make a new separator" msgstr "" #: ../src/program.c:1752 msgid "New _Column Item" msgstr "" #: ../src/program.c:1753 msgid "Make a new column item" msgstr "" #: ../src/program.c:1757 msgid "New _Program Window" msgstr "" #: ../src/program.c:1758 msgid "Make a new program window" msgstr "" #: ../src/program.c:1762 msgid "_Open Toolkit" msgstr "" #: ../src/program.c:1763 msgid "_Open toolkit" msgstr "" #: ../src/program.c:1767 msgid "Save Toolkit" msgstr "" #: ../src/program.c:1768 msgid "_Save toolkit" msgstr "" #: ../src/program.c:1772 msgid "Save Toolkit _As" msgstr "" #: ../src/program.c:1773 msgid "Save toolkit as" msgstr "" #: ../src/program.c:1777 msgid "_Process" msgstr "" #: ../src/program.c:1778 msgid "Process text" msgstr "" #: ../src/program.c:1782 msgid "_Reload All Toolkits" msgstr "" #: ../src/program.c:1783 msgid "Remove and reload all startup data" msgstr "" #: ../src/program.c:1787 msgid "C_ut" msgstr "" #: ../src/program.c:1788 msgid "Cut selected text" msgstr "" #: ../src/program.c:1792 msgid "_Copy" msgstr "" #: ../src/program.c:1793 msgid "Copy selected text" msgstr "" #: ../src/program.c:1797 msgid "_Paste" msgstr "" #: ../src/program.c:1798 msgid "Paste selected text" msgstr "" #: ../src/program.c:1803 msgid "Delete selected text" msgstr "" #: ../src/program.c:1808 msgid "Select all text" msgstr "" #: ../src/program.c:1812 msgid "Dese_lect All" msgstr "" #: ../src/program.c:1813 msgid "Deselect all text" msgstr "" #: ../src/program.c:1817 msgid "Delete _Tool" msgstr "" #: ../src/program.c:1818 msgid "Delete current tool" msgstr "" #: ../src/program.c:1822 msgid "Delete Tool_kit" msgstr "" #: ../src/program.c:1823 msgid "Delete current toolkit" msgstr "" #: ../src/program.c:1828 msgid "Find text in toolkits" msgstr "" #: ../src/program.c:1833 msgid "Find text again" msgstr "" #: ../src/program.c:1837 msgid "_Jump To Definition" msgstr "" #: ../src/program.c:1838 msgid "Jump to definition" msgstr "" #: ../src/program.c:1842 msgid "_Info" msgstr "" #: ../src/program.c:1843 msgid "Info on selected object" msgstr "" #: ../src/program.c:1847 msgid "_Trace" msgstr "" #: ../src/program.c:1848 msgid "Make a new trace window" msgstr "" #: ../src/program.c:1852 msgid "_Errors" msgstr "" #: ../src/program.c:1853 msgid "Show all errors" msgstr "" #: ../src/program.c:1857 msgid "Help on _Tool" msgstr "" #: ../src/program.c:1858 msgid "View docs for this tool" msgstr "" #: ../src/program.c:1864 msgid "Definition _Browser" msgstr "" #: ../src/program.c:1865 msgid "Show definition browser" msgstr "" #: ../src/program.c:2120 msgid "Bad drag." msgstr "" #: ../src/program.c:2122 msgid "" "Sorry, you can only drag tools between toolkits. You can't reorder toolkits, " "you can't nest toolkits and you can't drag tools to the top level." msgstr "" #: ../src/program.c:2315 msgid "Tool" msgstr "" #. Toolkit Browser pane. #. #: ../src/program.c:2338 msgid "Definition Browser" msgstr "" #: ../src/cache.c:881 #, c-format msgid "VIPS library: %s" msgstr "" #: ../src/progress.c:120 msgid "Cancelling" msgstr "" #: ../src/progress.c:152 #, c-format msgid "%d minute left" msgid_plural "%d minutes left" msgstr[0] "" msgstr[1] "" #: ../src/progress.c:157 #, c-format msgid "%d second left" msgid_plural "%d seconds left" msgstr[0] "" msgstr[1] "" #: ../src/progress.c:178 msgid "Calculating" msgstr "" #: ../src/progress.c:198 msgid "Loading" msgstr "" nip2-8.7.1/po/Makefile.in.in0000644000175000017500000001762613417042640012425 00000000000000# Makefile for program source directory in GNU NLS utilities package. # Copyright (C) 1995, 1996, 1997 by Ulrich Drepper # # This file file be copied and used freely without restrictions. It can # be used in projects which are not available under the GNU Public License # but which still want to provide support for the GNU gettext functionality. # Please note that the actual code is *not* freely available. # # - Modified by Owen Taylor to use GETTEXT_PACKAGE # instead of PACKAGE and to look for po2tbl in ./ not in intl/ # # - Modified by jacob berkman to install # Makefile.in.in and po2tbl.sed.in for use with glib-gettextize GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ PACKAGE = @PACKAGE@ VERSION = @VERSION@ SHELL = @SHELL@ @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ datadir = @datadir@ libdir = @libdir@ localedir = $(libdir)/locale gnulocaledir = $(datadir)/locale gettextsrcdir = $(datadir)/glib-2.0/gettext/po subdir = po INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ MKINSTALLDIRS = mkdir -p CC = @CC@ GENCAT = @GENCAT@ GMSGFMT = @GMSGFMT@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ XGETTEXT = @XGETTEXT@ MSGMERGE = msgmerge DEFS = @DEFS@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ INCLUDES = -I.. -I$(top_srcdir)/intl COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(XCFLAGS) SOURCES = POFILES = @POFILES@ GMOFILES = @GMOFILES@ DISTFILES = LINGUAS ChangeLog Makefile.in.in POTFILES.in $(GETTEXT_PACKAGE).pot \ $(POFILES) $(GMOFILES) $(SOURCES) POTFILES = \ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ INSTOBJEXT = @INSTOBJEXT@ .SUFFIXES: .SUFFIXES: .c .o .po .pox .gmo .mo .msg .cat .c.o: $(COMPILE) $< .po.pox: $(MAKE) $(GETTEXT_PACKAGE).pot $(MSGMERGE) $< $(srcdir)/$(GETTEXT_PACKAGE).pot -o $*.pox .po.mo: $(MSGFMT) -o $@ $< .po.gmo: $(AM_V_GEN) file=$(srcdir)/`echo $* | sed 's,.*/,,'`.gmo \ && rm -f $$file && $(GMSGFMT) $(MSGFMT_OPTS) -o $$file $< .po.cat: sed -f ../intl/po2msg.sed < $< > $*.msg \ && rm -f $@ && $(GENCAT) $@ $*.msg all: all-@USE_NLS@ all-yes: $(CATALOGS) all-no: $(srcdir)/$(GETTEXT_PACKAGE).pot: $(POTFILES) $(XGETTEXT) --default-domain=$(GETTEXT_PACKAGE) --from-code=UTF-8 \ --msgid-bugs-address='http://bugzilla.gnome.org/enter_bug.cgi?product=glib&keywords=I18N+L10N&component=general' \ --add-comments --keyword=_ --keyword=N_ \ --keyword=C_:1c,2 \ --keyword=NC_:1c,2 \ --keyword=g_dcgettext:2 \ --keyword=g_dngettext:2,3 \ --keyword=g_dpgettext2:2c,3 \ --flag=N_:1:pass-c-format \ --flag=C_:2:pass-c-format \ --flag=NC_:2:pass-c-format \ --flag=g_dngettext:2:pass-c-format \ --flag=g_strdup_printf:1:c-format \ --flag=g_string_printf:2:c-format \ --flag=g_string_append_printf:2:c-format \ --flag=g_error_new:3:c-format \ --flag=g_set_error:4:c-format \ --flag=g_markup_printf_escaped:1:c-format \ --flag=g_log:3:c-format \ --flag=g_print:1:c-format \ --flag=g_printerr:1:c-format \ --flag=g_printf:1:c-format \ --flag=g_fprintf:2:c-format \ --flag=g_sprintf:2:c-format \ --flag=g_snprintf:3:c-format \ --flag=g_scanner_error:2:c-format \ --flag=g_scanner_warn:2:c-format \ $(POTFILES) \ && test ! -f $(GETTEXT_PACKAGE).po \ || ( rm -f $(srcdir)/$(GETTEXT_PACKAGE).pot \ && mv $(GETTEXT_PACKAGE).po $(srcdir)/$(GETTEXT_PACKAGE).pot ) install: install-exec install-data install-exec: install-data: install-data-@USE_NLS@ install-data-no: all install-data-yes: all $(MKINSTALLDIRS) $(DESTDIR)$(datadir); \ catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ case "$$cat" in \ *.gmo) destdir=$(gnulocaledir);; \ *) destdir=$(localedir);; \ esac; \ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ dir=$(DESTDIR)$$destdir/$$lang/LC_MESSAGES; \ $(MKINSTALLDIRS) $$dir; \ if test -r $$cat; then \ $(INSTALL_DATA) $$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ echo "installing $$cat as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \ else \ $(INSTALL_DATA) $(srcdir)/$$cat $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ echo "installing $(srcdir)/$$cat as" \ "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT)"; \ fi; \ if test -r $$cat.m; then \ $(INSTALL_DATA) $$cat.m $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ echo "installing $$cat.m as $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \ else \ if test -r $(srcdir)/$$cat.m ; then \ $(INSTALL_DATA) $(srcdir)/$$cat.m \ $$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ echo "installing $(srcdir)/$$cat as" \ "$$dir/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m"; \ else \ true; \ fi; \ fi; \ done if test "$(PACKAGE)" = "glib"; then \ $(MKINSTALLDIRS) $(DESTDIR)$(gettextsrcdir); \ $(INSTALL_DATA) $(srcdir)/Makefile.in.in \ $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \ else \ : ; \ fi # Define this as empty until I found a useful application. installcheck: uninstall: catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ rm -f $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT); \ rm -f $(DESTDIR)$(gnulocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE)$(INSTOBJEXT).m; \ done if test "$(PACKAGE)" = "glib"; then \ rm -f $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \ fi check: all dvi info tags TAGS ID: mostlyclean: rm -f core core.* *.pox $(GETTEXT_PACKAGE).po *.old.po cat-id-tbl.tmp rm -fr *.o clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." rm -f $(GMOFILES) distdir = ../$(GETTEXT_PACKAGE)-$(VERSION)/$(subdir) dist distdir: $(DISTFILES) dists="$(DISTFILES)"; \ for file in $$dists; do \ ln $(srcdir)/$$file $(distdir) 2> /dev/null \ || cp -p $(srcdir)/$$file $(distdir); \ done update-po: Makefile $(MAKE) $(GETTEXT_PACKAGE).pot tmpdir=`pwd`; \ cd $(srcdir); \ catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed 's/\$(CATOBJEXT)$$//'`; \ echo "$$lang:"; \ if $(MSGMERGE) $$lang.po $(GETTEXT_PACKAGE).pot -o $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ exit 1; \ fi; \ fi; \ else \ echo "msgmerge for $$cat failed!"; \ rm -f $$tmpdir/$$lang.new.po; \ fi; \ done # POTFILES is created from POTFILES.in by stripping comments, empty lines # and Intltool tags (enclosed in square brackets), and appending a full # relative path to them POTFILES: POTFILES.in ( if test 'x$(srcdir)' != 'x.'; then \ posrcprefix='$(top_srcdir)/'; \ else \ posrcprefix="../"; \ fi; \ rm -f $@-t $@ \ && (sed -e '/^#/d' \ -e "s/^\[.*\] +//" \ -e '/^[ ]*$$/d' \ -e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \ | sed -e '$$s/\\$$//') > $@-t \ && chmod a-w $@-t \ && mv $@-t $@ ) Makefile: Makefile.in.in ../config.status POTFILES cd .. \ && $(SHELL) ./config.status $(subdir)/$@.in # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: nip2-8.7.1/po/POTFILES.in0000644000175000017500000000403113351443023011507 00000000000000src/conversionview.c src/vector.c src/tslider.c src/fontnameview.c src/workspacegroup.c src/iobject.c src/plotview.c src/matrix.c src/option.c src/managed.c src/vipsobject.c src/optionview.c src/toolkitbrowser.c src/imagepresent.c src/secret.c src/paintboxview.c src/prefworkspaceview.c src/boxes.c src/toggleview.c src/columnview.c src/lex.c src/row.c src/nipmarshal.c src/imagemodel.c src/imagedisplay.c src/sliderview.c src/colourview.c src/matrixview.c src/subcolumn.c src/iwindow.c src/real.c src/pane.c src/log.c src/heap.c src/heapmodel.c src/prefs.c src/symbol.c src/imageview.c src/parse.c src/managedgvalue.c src/conversion.c src/trace.c src/gtkutil.c src/slider.c src/action.c src/rowview.c src/column.c src/model.c src/iregiongroupview.c src/pathname.c src/panechild.c src/stringview.c src/iregion.c src/expr.c src/itext.c src/iregiongroup.c src/predicate.c src/icontainer.c src/iarrow.c src/expressionview.c src/workspace.c src/toolkitgroup.c src/iimage.c src/main.c src/toolkitview.c src/imageinfo.c src/string.c src/editview.c src/tree.c src/plotpresent.c src/dump.c src/colour.c src/number.c src/mainw.c src/popupbutton.c src/iimageview.c src/managedstring.c src/regionview.c src/idialog.c src/call.c src/class.c src/preview.c src/filemodel.c src/builtin.c src/compile.c src/pathnameview.c src/spin.c src/error.c src/tool.c src/floatwindow.c src/util.c src/view.c src/plotmodel.c src/iregionview.c src/formula.c src/valueview.c src/colourdisplay.c src/plotwindow.c src/numberview.c src/path.c src/workspaceview.c src/rhsview.c src/imageheader.c src/toggle.c src/filesel.c src/toolkitgroupview.c src/link.c src/rhs.c src/classmodel.c src/toolview.c src/toolkit.c src/watch.c src/expression.c src/clock.c src/graphwindow.c src/managedgobject.c src/workspacedefs.c src/group.c src/statusview.c src/itextview.c src/graphicview.c src/reduce.c src/doubleclick.c src/nip2-cli.c src/defbrowser.c src/plotstatus.c src/vobject.c src/plot.c src/subcolumnview.c src/value.c src/program.c src/fontname.c src/prefcolumnview.c src/managedfile.c src/cache.c src/progress.c nip2-8.7.1/test-driver0000755000175000017500000001104013351443337011520 00000000000000#! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2013-07-13.22; # UTC # Copyright (C) 2011-2014 Free Software Foundation, Inc. # # This program is free software; you can 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 # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <$log_file 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then tweaked_estatus=1 else tweaked_estatus=$estatus fi case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report the test outcome and exit status in the logs, so that one can # know whether the test passed or failed simply by looking at the '.log' # file, without the need of also peaking into the corresponding '.trs' # file (automake bug#11814). echo "$res $test_name (exit status: $estatus)" >>$log_file # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: nip2-8.7.1/config.sub0000755000175000017500000010645013417042641011313 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2018 Free Software Foundation, Inc. timestamp='2018-02-22' # 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; 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 Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo "$1" | sed 's/-[^-]*$//'` if [ "$basic_machine" != "$1" ] then os=`echo "$1" | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pru \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | wasm32 \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pru-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | wasm32-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-pc os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; asmjs) basic_machine=asmjs-unknown ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2*) basic_machine=m68k-bull os=-sysv3 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=$os"spe" ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=-linux ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; nsv-tandem) basic_machine=nsv-tandem ;; nsx-tandem) basic_machine=nsx-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh5el) basic_machine=sh5le-unknown ;; simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; x64) basic_machine=x86_64-pc ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases that might get confused # with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # es1800 is here to avoid being matched by es* (a different OS) -es1800*) os=-ose ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ | -midnightbsd*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -xray | -os68k* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo "$os" | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4*) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -pikeos*) # Until real need of OS specific support for # particular features comes up, bare metal # configurations are quite functional. case $basic_machine in arm*) os=-eabi ;; *) os=-elf ;; esac ;; -nacl*) ;; -ios) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; pru-*) os=-elf ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` ;; esac echo "$basic_machine$os" exit # Local variables: # eval: (add-hook 'write-file-functions 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: nip2-8.7.1/COPYING0000644000175000017500000004325413351443023010361 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. nip2-8.7.1/configure0000755000175000017500000215624713417043243011251 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for nip2 8.7.1. # # Report bugs to . # # # 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 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || 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 and $0: vipsip@jiscmail.ac.uk about your system, including any $0: error possibly output before this message. Then install $0: a modern shell, or manually run the script under such a $0: 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'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &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='nip2' PACKAGE_TARNAME='nip2' PACKAGE_VERSION='8.7.1' PACKAGE_STRING='nip2 8.7.1' PACKAGE_BUGREPORT='vipsip@jiscmail.ac.uk' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS TOP_SRCDIR IP_LIBS IP_CFLAGS UPDATE_DESKTOP_FALSE UPDATE_DESKTOP_TRUE UPDATE_DESKTOP_DATABASE UPDATE_MIME_DATABASE XDG_OPEN GSL_LIBS GSL_CFLAGS LIBGVC_LIBS LIBGVC_CFLAGS LIBGOFFICE_LIBS LIBGOFFICE_CFLAGS LIBGSF_LIBS LIBGSF_CFLAGS FFTW3_LIBS FFTW3_CFLAGS ALLOCA REQUIRED_PACKAGES_LIBS REQUIRED_PACKAGES_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG MKINSTALLDIRS POSUB POFILES PO_IN_DATADIR_FALSE PO_IN_DATADIR_TRUE INTLLIBS INSTOBJEXT GMOFILES DATADIRNAME CATOBJEXT CATALOGS XGETTEXT GMSGFMT MSGFMT_OPTS MSGFMT INTL_MACOSX_LIBS USE_NLS GETTEXT_PACKAGE CPP LT_SYS_LIBRARY_PATH OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL ac_ct_AR NM ac_ct_DUMPBIN DUMPBIN FGREP EGREP GREP SED LIBTOOL LD AS AR BISON RANLIB OBJDUMP DLLTOOL DLLWRAP WINDRES LN_S LEXLIB LEX_OUTPUT_ROOT LEX 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 OS_WIN32_FALSE OS_WIN32_TRUE host_os host_vendor host_cpu host build_os build_vendor build_cpu build 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_debug enable_largefile enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_aix_soname with_gnu_ld with_sysroot enable_libtool_lock with_dmalloc with_fftw3 with_libgsf with_libgoffice with_libgvc with_gsl enable_update_desktop ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS LT_SYS_LIBRARY_PATH CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR REQUIRED_PACKAGES_CFLAGS REQUIRED_PACKAGES_LIBS FFTW3_CFLAGS FFTW3_LIBS LIBGSF_CFLAGS LIBGSF_LIBS LIBGOFFICE_CFLAGS LIBGOFFICE_LIBS LIBGVC_CFLAGS LIBGVC_LIBS GSL_CFLAGS GSL_LIBS' # 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 nip2 8.7.1 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/nip2] --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 System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of nip2 8.7.1:";; 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-debug=[no/minimum/yes] turn on debugging [default=debug_default()] --disable-largefile omit support for large files --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-update-desktop disable update of desktop database Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-aix-soname=aix|svr4|both shared library versioning (aka "SONAME") variant to provide on AIX, [default=aix]. --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-dmalloc use dmalloc, as in http://www.dmalloc.com --without-fftw3 build without fftw3 (default: test) --without-libgsf build without libgsf (default: test) --without-libgoffice build without libgoffice (default: test) --without-libgvc build without libgvc (default: test) --without-gsl build without gsl (default: test) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory LT_SYS_LIBRARY_PATH User-defined run-time library search path. CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path REQUIRED_PACKAGES_CFLAGS C compiler flags for REQUIRED_PACKAGES, overriding pkg-config REQUIRED_PACKAGES_LIBS linker flags for REQUIRED_PACKAGES, overriding pkg-config FFTW3_CFLAGS C compiler flags for FFTW3, overriding pkg-config FFTW3_LIBS linker flags for FFTW3, overriding pkg-config LIBGSF_CFLAGS C compiler flags for LIBGSF, overriding pkg-config LIBGSF_LIBS linker flags for LIBGSF, overriding pkg-config LIBGOFFICE_CFLAGS C compiler flags for LIBGOFFICE, overriding pkg-config LIBGOFFICE_LIBS linker flags for LIBGOFFICE, overriding pkg-config LIBGVC_CFLAGS C compiler flags for LIBGVC, overriding pkg-config LIBGVC_LIBS linker flags for LIBGVC, overriding pkg-config GSL_CFLAGS C compiler flags for GSL, overriding pkg-config GSL_LIBS linker flags for GSL, overriding pkg-config 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 . _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 nip2 configure 8.7.1 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 # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext 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>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_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" 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_cpp conftest.$ac_ext") 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; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; 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_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack 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; } && { ac_try='./conftest$ac_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 : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------ ## ## Report this to vipsip@jiscmail.ac.uk ## ## ------------------------------------ ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=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 eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type 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 nip2 $as_me 8.7.1, 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 # foreign stops complaints about a missing README (we use README.md instead) # and missing INSTALL (the standard Gnu INSTALL is not very useful) 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 case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac 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='nip2' VERSION='8.7.1' 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: # # 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: 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: . 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_config_headers="$ac_config_headers config.h" MAJOR_VERSION=8 MINOR_VERSION=7 MICRO_VERSION=1 cat >>confdefs.h <<_ACEOF #define MAJOR_VERSION $MAJOR_VERSION _ACEOF cat >>confdefs.h <<_ACEOF #define MINOR_VERSION $MINOR_VERSION _ACEOF cat >>confdefs.h <<_ACEOF #define MICRO_VERSION $MICRO_VERSION _ACEOF # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for native Win32" >&5 $as_echo_n "checking for native Win32... " >&6; } case "$host" in *-*-mingw*) nip_os_win32=yes ;; *) nip_os_win32=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nip_os_win32" >&5 $as_echo "$nip_os_win32" >&6; } if test x"$nip_os_win32" = "xyes"; then $as_echo "#define OS_WIN32 1" >>confdefs.h # makes gcc use win native alignment IP_CFLAGS="-mms-bitfields $IP_CFLAGS" fi # src/Makeile.am uses this to add an icon to the .exe if test x"$nip_os_win32" = "xyes"; then OS_WIN32_TRUE= OS_WIN32_FALSE='#' else OS_WIN32_TRUE='#' OS_WIN32_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Mac OS X" >&5 $as_echo_n "checking for Mac OS X... " >&6; } case "$host" in *-*-darwin*) nip_os_darwin=yes ;; *) nip_os_darwin=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nip_os_darwin" >&5 $as_echo "$nip_os_darwin" >&6; } if test x"$nip_os_darwin" = "xyes"; then $as_echo "#define OS_DARWIN 1" >>confdefs.h fi # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; else enable_debug=no fi if test "x$enable_debug" = "xyes"; then NIP_DEBUG_FLAGS="-DDEBUG_FATAL -DDEBUG_LEAK" else NIP_DEBUG_FLAGS="-DG_DISABLE_CAST_CHECKS" if test "x$enable_debug" = "xno"; then NIP_DEBUG_FLAGS="$GLIB_DEBUG_FLAGS -DG_DISABLE_ASSERT -DG_DISABLE_CHECKS" fi fi IP_CFLAGS="$NIP_DEBUG_FLAGS $IP_CFLAGS" # we want largefile support, if possible 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 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 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 #include 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 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 # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi # Checks for programs. 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 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 { $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 #include 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 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 flex lex 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_LEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # 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_LEX="$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 LEX=$ac_cv_prog_LEX if test -n "$LEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 $as_echo "$LEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then cat >conftest.l <<_ACEOF %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ yyless ((input () != 0)); } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% #ifdef YYTEXT_POINTER extern char *yytext; #endif int main (void) { return ! yylex () + ! yywrap (); } _ACEOF { { ac_try="$LEX conftest.l" 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 "$LEX conftest.l") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 $as_echo_n "checking lex output file root... " >&6; } if ${ac_cv_prog_lex_root+:} false; then : $as_echo_n "(cached) " >&6 else if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 $as_echo "$ac_cv_prog_lex_root" >&6; } LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test -z "${LEXLIB+set}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 $as_echo_n "checking lex library... " >&6; } if ${ac_cv_lib_lex+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS=$LIBS ac_cv_lib_lex='none needed' for ac_lib in '' -lfl -ll; do LIBS="$ac_lib $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_lex=$ac_lib fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext test "$ac_cv_lib_lex" != 'none needed' && break done LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 $as_echo "$ac_cv_lib_lex" >&6; } test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 $as_echo_n "checking whether yytext is a pointer... " >&6; } if ${ac_cv_prog_lex_yytext_pointer+:} false; then : $as_echo_n "(cached) " >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no ac_save_LIBS=$LIBS LIBS="$LEXLIB $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 $as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then $as_echo "#define YYTEXT_POINTER 1" >>confdefs.h fi rm -f conftest.l $LEX_OUTPUT_ROOT.c fi # we must have flex or lex if test x"$LEX" = x:; then as_fn_error $? "lex/flex not found: $PACKAGE requires one of these" "$LINENO" 5 fi IP_LIBS="$IP_LIBS $LEXLIB" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. set dummy ${ac_tool_prefix}windres; 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_WINDRES+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$WINDRES"; then ac_cv_prog_WINDRES="$WINDRES" # 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_WINDRES="${ac_tool_prefix}windres" $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 WINDRES=$ac_cv_prog_WINDRES if test -n "$WINDRES"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WINDRES" >&5 $as_echo "$WINDRES" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_WINDRES"; then ac_ct_WINDRES=$WINDRES # Extract the first word of "windres", so it can be a program name with args. set dummy windres; 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_WINDRES+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_WINDRES"; then ac_cv_prog_ac_ct_WINDRES="$ac_ct_WINDRES" # 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_WINDRES="windres" $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_WINDRES=$ac_cv_prog_ac_ct_WINDRES if test -n "$ac_ct_WINDRES"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_WINDRES" >&5 $as_echo "$ac_ct_WINDRES" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_WINDRES" = x; then WINDRES="" 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 WINDRES=$ac_ct_WINDRES fi else WINDRES="$ac_cv_prog_WINDRES" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dllwrap", so it can be a program name with args. set dummy ${ac_tool_prefix}dllwrap; 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_DLLWRAP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLWRAP"; then ac_cv_prog_DLLWRAP="$DLLWRAP" # 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_DLLWRAP="${ac_tool_prefix}dllwrap" $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 DLLWRAP=$ac_cv_prog_DLLWRAP if test -n "$DLLWRAP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLWRAP" >&5 $as_echo "$DLLWRAP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLWRAP"; then ac_ct_DLLWRAP=$DLLWRAP # Extract the first word of "dllwrap", so it can be a program name with args. set dummy dllwrap; 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_DLLWRAP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLWRAP"; then ac_cv_prog_ac_ct_DLLWRAP="$ac_ct_DLLWRAP" # 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_DLLWRAP="dllwrap" $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_DLLWRAP=$ac_cv_prog_ac_ct_DLLWRAP if test -n "$ac_ct_DLLWRAP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLWRAP" >&5 $as_echo "$ac_ct_DLLWRAP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLWRAP" = x; then DLLWRAP="" 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 DLLWRAP=$ac_ct_DLLWRAP fi else DLLWRAP="$ac_cv_prog_DLLWRAP" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; 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_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # 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_DLLTOOL="${ac_tool_prefix}dlltool" $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 DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; 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_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # 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_DLLTOOL="dlltool" $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_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="" 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 DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; 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_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # 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_OBJDUMP="${ac_tool_prefix}objdump" $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 OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; 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_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # 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_OBJDUMP="objdump" $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_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="" 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 OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; 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_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # 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_RANLIB="${ac_tool_prefix}ranlib" $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 RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; 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_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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_RANLIB="ranlib" $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_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB="" 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 RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi 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 if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}bison", so it can be a program name with args. set dummy ${ac_tool_prefix}bison; 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_BISON+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$BISON"; then ac_cv_prog_BISON="$BISON" # 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_BISON="${ac_tool_prefix}bison" $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 BISON=$ac_cv_prog_BISON if test -n "$BISON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5 $as_echo "$BISON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_BISON"; then ac_ct_BISON=$BISON # Extract the first word of "bison", so it can be a program name with args. set dummy bison; 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_BISON+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_BISON"; then ac_cv_prog_ac_ct_BISON="$ac_ct_BISON" # 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_BISON="bison" $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_BISON=$ac_cv_prog_ac_ct_BISON if test -n "$ac_ct_BISON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_BISON" >&5 $as_echo "$ac_ct_BISON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_BISON" = x; then BISON="" 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 BISON=$ac_ct_BISON fi else BISON="$ac_cv_prog_BISON" fi # we have to have bison :-( maybe we could ship the generated .c/.h files? not # clear on their portability if test x"$BISON" = x; then as_fn_error $? "bison not found: $PACKAGE uses bison-only features" "$LINENO" 5 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; 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_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # 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_AR="${ac_tool_prefix}ar" $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 AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; 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_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # 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_AR="ar" $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_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" 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 AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; 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_AS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AS"; then ac_cv_prog_AS="$AS" # 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_AS="${ac_tool_prefix}as" $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 AS=$ac_cv_prog_AS if test -n "$AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 $as_echo "$AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AS"; then ac_ct_AS=$AS # Extract the first word of "as", so it can be a program name with args. set dummy as; 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_AS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AS"; then ac_cv_prog_ac_ct_AS="$ac_ct_AS" # 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_AS="as" $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_AS=$ac_cv_prog_ac_ct_AS if test -n "$ac_ct_AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 $as_echo "$ac_ct_AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AS" = x; then AS="" 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 AS=$ac_ct_AS fi else AS="$ac_cv_prog_AS" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. set dummy ${ac_tool_prefix}ld; 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_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LD"; then ac_cv_prog_LD="$LD" # 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_LD="${ac_tool_prefix}ld" $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 LD=$ac_cv_prog_LD if test -n "$LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LD"; then ac_ct_LD=$LD # Extract the first word of "ld", so it can be a program name with args. set dummy ld; 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_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LD"; then ac_cv_prog_ac_ct_LD="$ac_ct_LD" # 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_LD="ld" $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_LD=$ac_cv_prog_ac_ct_LD if test -n "$ac_ct_LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5 $as_echo "$ac_ct_LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LD" = x; then LD="" 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 LD=$ac_ct_LD fi else LD="$ac_cv_prog_LD" fi enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; 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_AS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AS"; then ac_cv_prog_AS="$AS" # 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_AS="${ac_tool_prefix}as" $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 AS=$ac_cv_prog_AS if test -n "$AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 $as_echo "$AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AS"; then ac_ct_AS=$AS # Extract the first word of "as", so it can be a program name with args. set dummy as; 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_AS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AS"; then ac_cv_prog_ac_ct_AS="$ac_ct_AS" # 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_AS="as" $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_AS=$ac_cv_prog_ac_ct_AS if test -n "$ac_ct_AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 $as_echo "$ac_ct_AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AS" = x; then AS="false" 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 AS=$ac_ct_AS fi else AS="$ac_cv_prog_AS" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; 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_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # 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_DLLTOOL="${ac_tool_prefix}dlltool" $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 DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; 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_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # 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_DLLTOOL="dlltool" $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_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" 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 DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; 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_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # 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_OBJDUMP="${ac_tool_prefix}objdump" $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 OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; 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_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # 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_OBJDUMP="objdump" $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_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" 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 OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi ;; esac test -z "$AS" && AS=as test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$OBJDUMP" && OBJDUMP=objdump case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.6' macro_revision='2.4.6' ltmain=$ac_aux_dir/ltmain.sh # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case $ECHO in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST 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_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD=$ac_prog ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test yes = "$with_gnu_ld"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD=$ac_dir/$ac_prog # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM=$NM else lt_nm_to_check=${ac_tool_prefix}nm if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. tmp_nm=$ac_dir/$lt_tmp_nm if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then # Check to see if the nm accepts a BSD-compat flag. # Adding the 'sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in mingw*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS=$lt_save_ifs done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test no != "$lt_cv_path_NM"; then NM=$lt_cv_path_NM else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" 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_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # 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_DUMPBIN="$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 DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" 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_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # 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_DUMPBIN="$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_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" 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 DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; *) DUMPBIN=: ;; esac fi if test : != "$DUMPBIN"; then NM=$DUMPBIN fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring=ABCD case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test X`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test 17 != "$i" # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n "$lt_cv_sys_max_cmd_len"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; then reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; 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_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # 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_OBJDUMP="${ac_tool_prefix}objdump" $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 OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; 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_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # 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_OBJDUMP="objdump" $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_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" 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 OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure # whether 'pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. if ( file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; os2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; 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_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # 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_DLLTOOL="${ac_tool_prefix}dlltool" $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 DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; 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_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # 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_DLLTOOL="dlltool" $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_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" 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 DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd=$ECHO ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar 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_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # 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_AR="$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 AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar 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_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # 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_AR="$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_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" 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 AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -eq "$ac_status"; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test 0 -ne "$ac_status"; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test no = "$lt_cv_ar_at_file"; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi 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 test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; 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_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # 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_RANLIB="${ac_tool_prefix}ranlib" $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 RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; 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_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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_RANLIB="ranlib" $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_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" 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 RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in bitrig* | openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test ia64 = "$host_cpu"; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" lt_c_name_lib_hook="\ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" else # Disable hooks by default. lt_cv_sys_global_symbol_to_import= lt_cdecl_hook= lt_c_name_hook= lt_c_name_lib_hook= fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ " /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ " /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ " {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ " s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined __osf__ /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS=conftstm.$ac_objext CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test yes = "$pipe_works"; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5 $as_echo "$with_sysroot" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5 $as_echo_n "checking for a working dd... " >&6; } if ${ac_cv_path_lt_DD+:} false; then : $as_echo_n "(cached) " >&6 else printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i : ${lt_DD:=$DD} if test -z "$lt_DD"; then ac_path_lt_DD_found=false # Loop through the user's path and test for each of PROGNAME-LIST 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_prog in dd; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_lt_DD" || continue if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: fi $ac_path_lt_DD_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_lt_DD"; then : fi else ac_cv_path_lt_DD=$lt_DD fi rm -f conftest.i conftest2.i conftest.out fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5 $as_echo "$ac_cv_path_lt_DD" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5 $as_echo_n "checking how to truncate binary pipes... " >&6; } if ${lt_cv_truncate_bin+:} false; then : $as_echo_n "(cached) " >&6 else printf 0123456789abcdef0123456789abcdef >conftest.i cat conftest.i conftest.i >conftest2.i lt_cv_truncate_bin= if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then cmp -s conftest.i conftest.out \ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" fi rm -f conftest.i conftest2.i conftest.out test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5 $as_echo "$lt_cv_truncate_bin" >&6; } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test no = "$enable_libtool_lock" || enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out what ABI is being produced by ac_compile, and set mode # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; *ELF-64*) HPUX_IA64_MODE=64 ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test yes = "$lt_cv_prog_gnu_ld"; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; mips64*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then emul=elf case `/usr/bin/file conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; *64-bit*) emul="${emul}64" ;; esac case `/usr/bin/file conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; *LSB*) emul="${emul}ltsmip" ;; esac case `/usr/bin/file conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; esac LD="${LD-ld} -m $emul" fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when # doing 32-bit compilation for a host where ld defaults to 64-bit, or # vice versa); the common cases where no linker options are needed do # not appear in the list. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*linux*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else 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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext 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 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test yes != "$lt_cv_cc_needs_belf"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS=$SAVE_CFLAGS fi ;; *-*solaris*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*|x86_64-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD=${LD-ld}_sol2 fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks=$enable_libtool_lock if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; 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_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # 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_MANIFEST_TOOL="${ac_tool_prefix}mt" $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 MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; 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_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # 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_MANIFEST_TOOL="mt" $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_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" 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 MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test yes != "$lt_cv_path_mainfest_tool"; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; 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_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # 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_DSYMUTIL="${ac_tool_prefix}dsymutil" $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 DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; 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_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # 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_DSYMUTIL="dsymutil" $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_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" 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 DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; 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_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # 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_NMEDIT="${ac_tool_prefix}nmedit" $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 NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; 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_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # 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_NMEDIT="nmedit" $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_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" 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 NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; 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_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # 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_LIPO="${ac_tool_prefix}lipo" $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 LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; 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_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # 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_LIPO="lipo" $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_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" 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 LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; 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_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # 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_OTOOL="${ac_tool_prefix}otool" $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 OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; 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_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # 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_OTOOL="otool" $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_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" 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 OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; 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_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # 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_OTOOL64="${ac_tool_prefix}otool64" $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 OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; 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_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # 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_OTOOL64="otool64" $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_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" 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 OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "$LT_MULTI_MODULE"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test 0 = "$_lt_result"; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; 10.[012][,.]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' fi if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } 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 how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : 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 $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS=$lt_save_ifs ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS=$lt_save_ifs ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for lt_pkg in $withval; do IFS=$lt_save_ifs if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS=$lt_save_ifs ;; esac else pic_mode=default fi # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, for pkg in $enableval; do IFS=$lt_save_ifs if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS=$lt_save_ifs ;; esac else enable_fast_install=yes fi shared_archive_member_spec= case $host,$enable_shared in power*-*-aix[5-9]*,yes) { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5 $as_echo_n "checking which variant of shared library versioning to provide... " >&6; } # Check whether --with-aix-soname was given. if test "${with_aix_soname+set}" = set; then : withval=$with_aix_soname; case $withval in aix|svr4|both) ;; *) as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5 ;; esac lt_cv_with_aix_soname=$with_aix_soname else if ${lt_cv_with_aix_soname+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_with_aix_soname=aix fi with_aix_soname=$lt_cv_with_aix_soname fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5 $as_echo "$with_aix_soname" >&6; } if test aix != "$with_aix_soname"; then # For the AIX way of multilib, we name the shared archive member # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, # the AIX toolchain works better with OBJECT_MODE set (default 32). if test 64 = "${OBJECT_MODE-32}"; then shared_archive_member_spec=shr_64 else shared_archive_member_spec=shr fi fi ;; *) with_aix_soname=aix ;; esac # This can be used to rebuild libtool when needed LIBTOOL_DEPS=$ltmain # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a '.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld old_CC=$CC old_CFLAGS=$CFLAGS # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o func_cc_basename $compiler cc_basename=$func_cc_basename_result # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/${ac_tool_prefix}file"; then lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD=$MAGIC_CMD lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS=$lt_save_ifs test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/file"; then lt_cv_path_MAGIC_CMD=$ac_dir/"file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD=$lt_cv_path_MAGIC_CMD if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS=$lt_save_ifs MAGIC_CMD=$lt_save_MAGIC_CMD ;; esac fi MAGIC_CMD=$lt_cv_path_MAGIC_CMD if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC=$CC 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 # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test yes = "$GCC"; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test yes = "$GCC"; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi lt_prog_compiler_pic='-fPIC' ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the '-m68020' flag to GCC prevents building anything better, # like '-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test ia64 = "$host_cpu"; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' case $cc_basename in nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; esac ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' case $host_os in os2*) lt_prog_compiler_static='$wl-static' ;; esac ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='$wl-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64, which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; tcc*) # Fabrice Bellard et al's Tiny C Compiler lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms that do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test yes = "$lt_cv_prog_compiler_pic_works"; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test yes = "$lt_cv_prog_compiler_static_works"; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links=nottested if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test no = "$hard_links"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ' (' and ')$', so one must not match beginning or # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', # as well as any symbol that contains 'd'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd* | bitrig*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test yes = "$with_gnu_ld"; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test yes = "$lt_use_gnu_ld_interface"; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='$wl' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' export_dynamic_flag_spec='$wl--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test ia64 != "$host_cpu"; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='$wl--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' link_all_deplibs=yes ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test linux-dietlibc = "$host_os"; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test no = "$tmp_diet" then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 tmp_sharedflag='-Wl,-shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) export_dynamic_flag_spec='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test no = "$ld_shlibs"; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test ia64 = "$host_cpu"; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag= else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to GNU nm, but means don't demangle to AIX nm. # Without the "-l" option, or with the "-B" option, AIX nm treats # weak defined symbols like other global defined symbols, whereas # GNU nm marks them as "W". # While the 'weak' keyword is ignored in the Export File, we need # it in the Import File for the 'aix-soname' feature, so we have # to replace the "-B" option with "-P" for AIX nm. if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # have runtime linking enabled, and use it for executables. # For shared libraries, we enable/disable runtime linking # depending on the kind of the shared library created - # when "with_aix_soname,aix_use_runtimelinking" is: # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables # "aix,yes" lib.so shared, rtl:yes, for executables # lib.a static archive # "both,no" lib.so.V(shr.o) shared, rtl:yes # lib.a(lib.so.V) shared, rtl:no, for executables # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a(lib.so.V) shared, rtl:no # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables # lib.a static archive case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then aix_use_runtimelinking=yes break fi done if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then # With aix-soname=svr4, we create the lib.so.V shared archives only, # so we don't have lib.a shared libs to link our executables. # We have to force runtime linking in this case. aix_use_runtimelinking=yes LDFLAGS="$LDFLAGS -Wl,-brtl" fi ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='$wl-f,' case $with_aix_soname,$aix_use_runtimelinking in aix,*) ;; # traditional, no import file svr4,* | *,yes) # use import file # The Import File defines what to hardcode. hardcode_direct=no hardcode_direct_absolute=no ;; esac if test yes = "$GCC"; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`$CC -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test yes = "$aix_use_runtimelinking"; then shared_flag="$shared_flag "'$wl-G' fi # Need to ensure runtime linking is disabled for the traditional # shared library, or the linker may eventually find shared libraries # /with/ Import File - we do not want to mix them. shared_flag_aix='-shared' shared_flag_svr4='-shared $wl-G' else # not using gcc if test ia64 = "$host_cpu"; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test yes = "$aix_use_runtimelinking"; then shared_flag='$wl-G' else shared_flag='$wl-bM:SRE' fi shared_flag_aix='$wl-bM:SRE' shared_flag_svr4='$wl-G' fi fi export_dynamic_flag_spec='$wl-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag else if test ia64 = "$host_cpu"; then hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test set = "${lt_cv_aix_libpath+set}"; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=/usr/lib:/lib fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' $wl-bernotok' allow_undefined_flag=' $wl-berok' if test yes = "$with_gnu_ld"; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' # -brtl affects multiple linker settings, -berok does not and is overridden later compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`' if test svr4 != "$with_aix_soname"; then # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' fi if test aix != "$with_aix_soname"; then archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' else # used by -dlpreopen to get the symbols archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir' fi archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile=$lt_outputfile.exe lt_tool_outputfile=$lt_tool_outputfile.exe ;; esac~ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test yes = "$lt_cv_ld_force_load"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag=$_lt_dar_allow_undefined case $cc_basename in ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test yes = "$GCC"; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='$wl-E' ;; hpux10*) if test yes,no = "$GCC,$with_gnu_ld"; then archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test yes,no = "$GCC,$with_gnu_ld"; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test yes = "$lt_cv_prog_compiler__b"; then archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test no = "$with_gnu_ld"; then hardcode_libdir_flag_spec='$wl+b $wl$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='$wl-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test yes = "$GCC"; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test yes = "$lt_cv_irix_exported_symbol"; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' fi link_all_deplibs=no else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; linux*) case $cc_basename in tcc*) # Fabrice Bellard et al's Tiny C Compiler ld_shlibs=yes archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd* | bitrig*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='$wl-rpath,$libdir' export_dynamic_flag_spec='$wl-E' else archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='$wl-rpath,$libdir' fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported shrext_cmds=.dll archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ $ECHO EXPORTS >> $output_objdir/$libname.def~ prefix_cmds="$SED"~ if test EXPORTS = "`$SED 1q $export_symbols`"; then prefix_cmds="$prefix_cmds -e 1d"; fi~ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' enable_shared_with_static_runtimes=yes ;; osf3*) if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test yes = "$GCC"; then allow_undefined_flag=' $wl-expect_unresolved $wl\*' archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' hardcode_libdir_flag_spec='$wl-rpath $wl$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test yes = "$GCC"; then wlarc='$wl' archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='$wl' archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands '-z linker_flag'. GCC discards it without '$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test yes = "$GCC"; then whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test sequent = "$host_vendor"; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='$wl-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We CANNOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='$wl-z,text' allow_undefined_flag='$wl-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='$wl-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='$wl-Bexport' runpath_var='LD_RUN_PATH' if test yes = "$GCC"; then archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test sni = "$host_vendor"; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='$wl-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test no = "$ld_shlibs" && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test yes,yes = "$GCC,$enable_shared"; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test yes = "$GCC"; then case $host_os in darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary... lt_tmp_lt_search_path_spec= lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` # ...but if some path component already ends with the multilib dir we assume # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). case "$lt_multi_os_dir; $lt_search_path_spec " in "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) lt_multi_os_dir= ;; esac for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" elif test -n "$lt_multi_os_dir"; then test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS = " "; FS = "/|\n";} { lt_foo = ""; lt_count = 0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo = "/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([A-Za-z]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=.so postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='$libname$release$shared_ext$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test ia64 = "$host_cpu"; then # AIX 5 supports IA64 library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line '#! .'. This would cause the generated library to # depend on '.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # Using Import Files as archive members, it is possible to support # filename-based versioning of shared library archives on AIX. While # this would work for both with and without runtime linking, it will # prevent static linking of such archives. So we do filename-based # shared library versioning with .so extension only, which is used # when both runtime linking and shared linking is enabled. # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the # archive as well as the shared archive member, telling the # bitwidth (32 or 64) of that shared object, and providing the # list of exported symbols of that shared object, eventually # decorated with the 'weak' keyword # *) the shared object with the F_LOADONLY flag set, to really avoid # it being seen by the linker. # At run time we better use the real file rather than another symlink, # but for link time we create the symlink libNAME.so -> libNAME.so.V case $with_aix_soname,$aix_use_runtimelinking in # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. aix,yes) # traditional libtool dynamic_linker='AIX unversionable lib.so' # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; aix,no) # traditional AIX only dynamic_linker='AIX lib.a(lib.so.V)' # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' ;; svr4,*) # full svr4 only dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,yes) # both, prefer svr4 dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)" library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' # unpreferred sharedlib libNAME.a needs extra handling postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' # We do not specify a path in Import Files, so LIBPATH fires. shlibpath_overrides_runpath=yes ;; *,no) # both, prefer aix dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)" library_names_spec='$libname$release.a $libname.a' soname_spec='$libname$release$shared_ext$major' # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' ;; esac shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='$libname$shared_ext' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec=$LIB if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' soname_spec='$libname$release$major$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' if test 32 = "$HPUX_IA64_MODE"; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" sys_lib_dlsearch_path_spec=/usr/lib/hpux32 else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" sys_lib_dlsearch_path_spec=/usr/lib/hpux64 fi ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test yes = "$lt_cv_prog_gnu_ld"; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes dynamic_linker='Android linker' # Don't embed -rpath directories since the linker doesn't support them. hardcode_libdir_flag_spec='-L$libdir' ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Ideally, we could use ldconfig to report *all* directores which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, # even though it is searched at run-time. Try to do the best guess by # appending ld.so.conf contents (and includes) to the search path. if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd* | bitrig*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then need_version=no else need_version=yes fi library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; os2*) libname_spec='$name' version_type=windows shrext_cmds=.dll need_version=no need_lib_prefix=no # OS/2 can only load a DLL with a base name of 8 characters or less. soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; v=$($ECHO $release$versuffix | tr -d .-); n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); $ECHO $n$v`$shared_ext' library_names_spec='${libname}_dll.$libext' dynamic_linker='OS/2 ld.exe' shlibpath_var=BEGINLIBPATH sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec postinstall_cmds='base_file=`basename \$file`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='$libname$release$shared_ext$major' library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test yes = "$with_gnu_ld"; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec; then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' soname_spec='$libname$shared_ext.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=sco need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test yes = "$with_gnu_ld"; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' soname_spec='$libname$release$shared_ext$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test no = "$dynamic_linker" && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test yes = "$GCC"; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec fi if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec fi # remember unaugmented sys_lib_dlsearch_path content for libtool script decls... configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec # ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" # to be used as default LT_SYS_LIBRARY_PATH value in generated libtool configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test yes = "$hardcode_automatic"; then # We can hardcode non-existent directories. if test no != "$hardcode_direct" && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" && test no != "$hardcode_minus_L"; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test relink = "$hardcode_action" || test yes = "$inherit_rpath"; then # Fast installation is not supported enable_fast_install=no elif test yes = "$shlibpath_overrides_runpath" || test no = "$enable_shared"; then # Fast installation is not necessary enable_fast_install=needless fi if test yes != "$enable_dlopen"; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen=load_add_on lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen=dlopen lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else lt_cv_dlopen=dyld lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; tpf*) # Don't try to run any link tests for TPF. We know it's impossible # because TPF is a cross-compiler, and we know how we open DSOs. lt_cv_dlopen=dlopen lt_cv_dlopen_libs= lt_cv_dlopen_self=no ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen=shl_load else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen=dlopen else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld fi fi fi fi fi fi ;; esac if test no = "$lt_cv_dlopen"; then enable_dlopen=no else enable_dlopen=yes fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS=$CPPFLAGS test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS=$LDFLAGS wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS=$LIBS LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test yes = "$cross_compiling"; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test yes = "$lt_cv_dlopen_self"; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test yes = "$cross_compiling"; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS=$save_CPPFLAGS LDFLAGS=$save_LDFLAGS LIBS=$save_LIBS ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP"; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report what library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test no = "$can_build_shared" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test yes = "$enable_shared" && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test ia64 != "$host_cpu"; then case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in yes,aix,yes) ;; # shared object as lib.so file only yes,svr4,*) ;; # shared object as lib.so archive member only yes,*) enable_static=no ;; # shared object in lib.a archive as well esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test yes = "$enable_shared" || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } 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 CC=$lt_save_CC ac_config_commands="$ac_config_commands libtool" # Only expand once: # dmalloc option { $as_echo "$as_me:${as_lineno-$LINENO}: checking if malloc debugging is wanted" >&5 $as_echo_n "checking if malloc debugging is wanted... " >&6; } # Check whether --with-dmalloc was given. if test "${with_dmalloc+set}" = set; then : withval=$with_dmalloc; if test "$withval" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define WITH_DMALLOC 1" >>confdefs.h LIBS="$LIBS -ldmalloc" LDFLAGS="$LDFLAGS -g" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # i18n GETTEXT_PACKAGE=nip2 cat >>confdefs.h <<_ACEOF #define GETTEXT_PACKAGE "$GETTEXT_PACKAGE" _ACEOF # ALL_LINGUAS="en_GB malkovich" ALL_LINGUAS="en_GB" for ac_header in locale.h do : ac_fn_c_check_header_mongrel "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" if test "x$ac_cv_header_locale_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LOCALE_H 1 _ACEOF fi done if test $ac_cv_header_locale_h = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LC_MESSAGES" >&5 $as_echo_n "checking for LC_MESSAGES... " >&6; } if ${am_cv_val_LC_MESSAGES+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { return LC_MESSAGES ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_val_LC_MESSAGES=yes else am_cv_val_LC_MESSAGES=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_val_LC_MESSAGES" >&5 $as_echo "$am_cv_val_LC_MESSAGES" >&6; } if test $am_cv_val_LC_MESSAGES = yes; then $as_echo "#define HAVE_LC_MESSAGES 1" >>confdefs.h fi fi USE_NLS=yes gt_cv_have_gettext=no CATOBJEXT=NONE XGETTEXT=: INTLLIBS= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 $as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; } if ${gt_cv_func_CFPreferencesCopyAppValue+:} false; then : $as_echo_n "(cached) " >&6 else gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { CFPreferencesCopyAppValue(NULL, NULL) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : gt_cv_func_CFPreferencesCopyAppValue=yes else gt_cv_func_CFPreferencesCopyAppValue=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$gt_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 $as_echo "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then $as_echo "#define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 $as_echo_n "checking for CFLocaleCopyCurrent... " >&6; } if ${gt_cv_func_CFLocaleCopyCurrent+:} false; then : $as_echo_n "(cached) " >&6 else gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { CFLocaleCopyCurrent(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : gt_cv_func_CFLocaleCopyCurrent=yes else gt_cv_func_CFLocaleCopyCurrent=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$gt_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 $as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } if test $gt_cv_func_CFLocaleCopyCurrent = yes; then $as_echo "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi ac_fn_c_check_header_mongrel "$LINENO" "libintl.h" "ac_cv_header_libintl_h" "$ac_includes_default" if test "x$ac_cv_header_libintl_h" = xyes; then : gt_cv_func_dgettext_libintl="no" libintl_extra_libs="" # # First check in libc # { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ngettext in libc" >&5 $as_echo_n "checking for ngettext in libc... " >&6; } if ${gt_cv_func_ngettext_libc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { return !ngettext ("","", 1) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : gt_cv_func_ngettext_libc=yes else gt_cv_func_ngettext_libc=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_ngettext_libc" >&5 $as_echo "$gt_cv_func_ngettext_libc" >&6; } if test "$gt_cv_func_ngettext_libc" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dgettext in libc" >&5 $as_echo_n "checking for dgettext in libc... " >&6; } if ${gt_cv_func_dgettext_libc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { return !dgettext ("","") ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : gt_cv_func_dgettext_libc=yes else gt_cv_func_dgettext_libc=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_dgettext_libc" >&5 $as_echo "$gt_cv_func_dgettext_libc" >&6; } fi if test "$gt_cv_func_ngettext_libc" = "yes" ; then for ac_func in bind_textdomain_codeset do : ac_fn_c_check_func "$LINENO" "bind_textdomain_codeset" "ac_cv_func_bind_textdomain_codeset" if test "x$ac_cv_func_bind_textdomain_codeset" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_BIND_TEXTDOMAIN_CODESET 1 _ACEOF fi done fi # # If we don't have everything we want, check in libintl # if test "$gt_cv_func_dgettext_libc" != "yes" \ || test "$gt_cv_func_ngettext_libc" != "yes" \ || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for bindtextdomain in -lintl" >&5 $as_echo_n "checking for bindtextdomain in -lintl... " >&6; } if ${ac_cv_lib_intl_bindtextdomain+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char bindtextdomain (); int main () { return bindtextdomain (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_bindtextdomain=yes else ac_cv_lib_intl_bindtextdomain=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_bindtextdomain" >&5 $as_echo "$ac_cv_lib_intl_bindtextdomain" >&6; } if test "x$ac_cv_lib_intl_bindtextdomain" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ngettext in -lintl" >&5 $as_echo_n "checking for ngettext in -lintl... " >&6; } if ${ac_cv_lib_intl_ngettext+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ngettext (); int main () { return ngettext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_ngettext=yes else ac_cv_lib_intl_ngettext=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_ngettext" >&5 $as_echo "$ac_cv_lib_intl_ngettext" >&6; } if test "x$ac_cv_lib_intl_ngettext" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dgettext in -lintl" >&5 $as_echo_n "checking for dgettext in -lintl... " >&6; } if ${ac_cv_lib_intl_dgettext+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dgettext (); int main () { return dgettext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_dgettext=yes else ac_cv_lib_intl_dgettext=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_dgettext" >&5 $as_echo "$ac_cv_lib_intl_dgettext" >&6; } if test "x$ac_cv_lib_intl_dgettext" = xyes; then : gt_cv_func_dgettext_libintl=yes fi fi fi if test "$gt_cv_func_dgettext_libintl" != "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -liconv is needed to use gettext" >&5 $as_echo_n "checking if -liconv is needed to use gettext... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 $as_echo "" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ngettext in -lintl" >&5 $as_echo_n "checking for ngettext in -lintl... " >&6; } if ${ac_cv_lib_intl_ngettext+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl -liconv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ngettext (); int main () { return ngettext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_ngettext=yes else ac_cv_lib_intl_ngettext=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_ngettext" >&5 $as_echo "$ac_cv_lib_intl_ngettext" >&6; } if test "x$ac_cv_lib_intl_ngettext" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dcgettext in -lintl" >&5 $as_echo_n "checking for dcgettext in -lintl... " >&6; } if ${ac_cv_lib_intl_dcgettext+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl -liconv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dcgettext (); int main () { return dcgettext (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_intl_dcgettext=yes else ac_cv_lib_intl_dcgettext=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_dcgettext" >&5 $as_echo "$ac_cv_lib_intl_dcgettext" >&6; } if test "x$ac_cv_lib_intl_dcgettext" = xyes; then : gt_cv_func_dgettext_libintl=yes libintl_extra_libs=-liconv else : fi else : fi fi # # If we found libintl, then check in it for bind_textdomain_codeset(); # we'll prefer libc if neither have bind_textdomain_codeset(), # and both have dgettext and ngettext # if test "$gt_cv_func_dgettext_libintl" = "yes" ; then glib_save_LIBS="$LIBS" LIBS="$LIBS -lintl $libintl_extra_libs" unset ac_cv_func_bind_textdomain_codeset for ac_func in bind_textdomain_codeset do : ac_fn_c_check_func "$LINENO" "bind_textdomain_codeset" "ac_cv_func_bind_textdomain_codeset" if test "x$ac_cv_func_bind_textdomain_codeset" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_BIND_TEXTDOMAIN_CODESET 1 _ACEOF fi done LIBS="$glib_save_LIBS" if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then gt_cv_func_dgettext_libc=no else if test "$gt_cv_func_dgettext_libc" = "yes" \ && test "$gt_cv_func_ngettext_libc" = "yes"; then gt_cv_func_dgettext_libintl=no fi fi fi fi if test "$gt_cv_func_dgettext_libc" = "yes" \ || test "$gt_cv_func_dgettext_libintl" = "yes"; then gt_cv_have_gettext=yes fi if test "$gt_cv_func_dgettext_libintl" = "yes"; then INTLLIBS="-lintl $libintl_extra_libs $INTL_MACOSX_LIBS" fi if test "$gt_cv_have_gettext" = "yes"; then $as_echo "#define HAVE_GETTEXT 1" >>confdefs.h # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; 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_path_MSGFMT+:} false; then : $as_echo_n "(cached) " >&6 else case "$MSGFMT" in /*) ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"; then ac_cv_path_MSGFMT="$ac_dir/$ac_word" break fi fi done IFS="$ac_save_ifs" test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT="no" ;; esac fi MSGFMT="$ac_cv_path_MSGFMT" if test "$MSGFMT" != "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 $as_echo "$MSGFMT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$MSGFMT" != "no"; then glib_save_LIBS="$LIBS" LIBS="$LIBS $INTLLIBS" for ac_func in dcgettext do : ac_fn_c_check_func "$LINENO" "dcgettext" "ac_cv_func_dcgettext" if test "x$ac_cv_func_dcgettext" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DCGETTEXT 1 _ACEOF fi done MSGFMT_OPTS= { $as_echo "$as_me:${as_lineno-$LINENO}: checking if msgfmt accepts -c" >&5 $as_echo_n "checking if msgfmt accepts -c... " >&6; } cat >conftest.foo <<_ACEOF msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Project-Id-Version: test 1.0\n" "PO-Revision-Date: 2007-02-15 12:01+0100\n" "Last-Translator: test \n" "Language-Team: C \n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" _ACEOF if { { $as_echo "$as_me:${as_lineno-$LINENO}: \$MSGFMT -c -o /dev/null conftest.foo"; } >&5 ($MSGFMT -c -o /dev/null conftest.foo) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then MSGFMT_OPTS=-c; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } echo "$as_me: failed input was:" >&5 sed 's/^/| /' conftest.foo >&5 fi # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; 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_path_GMSGFMT+:} false; then : $as_echo_n "(cached) " >&6 else case $GMSGFMT in [\\/]* | ?:[\\/]*) ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. ;; *) 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_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext" $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 test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" ;; esac fi GMSGFMT=$ac_cv_path_GMSGFMT if test -n "$GMSGFMT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 $as_echo "$GMSGFMT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; 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_path_XGETTEXT+:} false; then : $as_echo_n "(cached) " >&6 else case "$XGETTEXT" in /*) ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then if test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"; then ac_cv_path_XGETTEXT="$ac_dir/$ac_word" break fi fi done IFS="$ac_save_ifs" test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" ;; esac fi XGETTEXT="$ac_cv_path_XGETTEXT" if test "$XGETTEXT" != ":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 $as_echo "$XGETTEXT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { extern int _nl_msg_cat_cntr; return _nl_msg_cat_cntr ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : CATOBJEXT=.gmo DATADIRNAME=share else case $host in *-*-solaris*) ac_fn_c_check_func "$LINENO" "bind_textdomain_codeset" "ac_cv_func_bind_textdomain_codeset" if test "x$ac_cv_func_bind_textdomain_codeset" = xyes; then : CATOBJEXT=.gmo DATADIRNAME=share else CATOBJEXT=.mo DATADIRNAME=lib fi ;; *-*-openbsd*) CATOBJEXT=.mo DATADIRNAME=share ;; *) CATOBJEXT=.mo DATADIRNAME=lib ;; esac fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$glib_save_LIBS" INSTOBJEXT=.mo else gt_cv_have_gettext=no fi fi fi if test "$gt_cv_have_gettext" = "yes" ; then $as_echo "#define ENABLE_NLS 1" >>confdefs.h fi if test "$XGETTEXT" != ":"; then if $XGETTEXT --omit-header /dev/null 2> /dev/null; then : ; else { $as_echo "$as_me:${as_lineno-$LINENO}: result: found xgettext program is not GNU xgettext; ignore it" >&5 $as_echo "found xgettext program is not GNU xgettext; ignore it" >&6; } XGETTEXT=":" fi fi # We need to process the po/ directory. POSUB=po ac_config_commands="$ac_config_commands default-1" for lang in $ALL_LINGUAS; do GMOFILES="$GMOFILES $lang.gmo" POFILES="$POFILES $lang.po" done if test "$gt_cv_have_gettext" = "yes"; then if test "x$ALL_LINGUAS" = "x"; then LINGUAS= else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for catalogs to be installed" >&5 $as_echo_n "checking for catalogs to be installed... " >&6; } NEW_LINGUAS= for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then NEW_LINGUAS="$NEW_LINGUAS $presentlang" fi done LINGUAS=$NEW_LINGUAS { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINGUAS" >&5 $as_echo "$LINGUAS" >&6; } fi if test -n "$LINGUAS"; then for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done fi fi MKINSTALLDIRS= if test -n "$ac_aux_dir"; then MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" fi if test -z "$MKINSTALLDIRS"; then MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" fi test -d po || mkdir po if test "x$srcdir" != "x."; then if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then posrcprefix="$srcdir/" else posrcprefix="../$srcdir/" fi else posrcprefix="../" fi rm -f po/POTFILES sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ < $srcdir/po/POTFILES.in > po/POTFILES # check for flex ... nip needs to adjust itself a bit if test "${LEX}" = "flex"; then $as_echo "#define HAVE_FLEX 1" >>confdefs.h fi # flex >= 2.5.36 uses a nonstandard type for yyleng { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yyleng is yy_size_t" >&5 $as_echo_n "checking whether yyleng is yy_size_t... " >&6; } cat > conftest.l <conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define YYLENG_IS_YY_SIZE_T 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext rm -f conftest.l $LEX_OUTPUT_ROOT.c # get packages we need # gtk before 2.4.9 crashes with the way we use combobox :-( # vips before 7.30 used "vips-x.y" as the pkg name if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; 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_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) 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_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $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 ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; 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_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) 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_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $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 ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" 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 PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for REQUIRED_PACKAGES" >&5 $as_echo_n "checking for REQUIRED_PACKAGES... " >&6; } if test -n "$REQUIRED_PACKAGES_CFLAGS"; then pkg_cv_REQUIRED_PACKAGES_CFLAGS="$REQUIRED_PACKAGES_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30\""; } >&5 ($PKG_CONFIG --exists --print-errors "gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_REQUIRED_PACKAGES_CFLAGS=`$PKG_CONFIG --cflags "gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$REQUIRED_PACKAGES_LIBS"; then pkg_cv_REQUIRED_PACKAGES_LIBS="$REQUIRED_PACKAGES_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30\""; } >&5 ($PKG_CONFIG --exists --print-errors "gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_REQUIRED_PACKAGES_LIBS=`$PKG_CONFIG --libs "gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then REQUIRED_PACKAGES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30" 2>&1` else REQUIRED_PACKAGES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$REQUIRED_PACKAGES_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30) were not met: $REQUIRED_PACKAGES_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables REQUIRED_PACKAGES_CFLAGS and REQUIRED_PACKAGES_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables REQUIRED_PACKAGES_CFLAGS and REQUIRED_PACKAGES_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else REQUIRED_PACKAGES_CFLAGS=$pkg_cv_REQUIRED_PACKAGES_CFLAGS REQUIRED_PACKAGES_LIBS=$pkg_cv_REQUIRED_PACKAGES_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi IP_CFLAGS="$REQUIRED_PACKAGES_CFLAGS $IP_CFLAGS" IP_LIBS="$REQUIRED_PACKAGES_LIBS $IP_LIBS" # gdk_window_set_opacity() was added in gtk 2.12 if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.12\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.12") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then nip_set_opacity=yes else nip_set_opacity=no fi if test x"$nip_set_opacity" = x"yes"; then $as_echo "#define HAVE_SET_OPACITY 1" >>confdefs.h fi # GtkInfoBar was added in gtk 2.18 if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.18\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.18") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then nip_use_infobar=yes else nip_use_infobar=no fi if test x"$nip_use_infobar" = x"yes"; then $as_echo "#define USE_INFOBAR 1" >>confdefs.h fi # notebook action widgets came in 2.20 if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.20\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.20") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then nip_use_notebook_action=yes else nip_use_notebook_action=no fi if test x"$nip_use_notebook_action" = x"yes"; then $as_echo "#define USE_NOTEBOOK_ACTION 1" >>confdefs.h fi # notebook group names widgets came in 2.24 if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.24\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.24") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then nip_use_notebook_group_name=yes else nip_use_notebook_group_name=no fi if test x"$nip_use_notebook_group_name" = x"yes"; then $as_echo "#define USE_NOTEBOOK_GROUP_NAME 1" >>confdefs.h fi # GRegex was added in glib-2.14 # we need it for regex searching in the program window if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.14\""; } >&5 ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.14") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then nip_use_gregex=yes else nip_use_gregex=no fi if test x"$nip_use_gregex" = x"yes"; then $as_echo "#define HAVE_GREGEX 1" >>confdefs.h fi # Check for the function strccpy in libgen ac_fn_c_check_header_mongrel "$LINENO" "libgen.h" "ac_cv_header_libgen_h" "$ac_includes_default" if test "x$ac_cv_header_libgen_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strccpy in -lgen" >&5 $as_echo_n "checking for strccpy in -lgen... " >&6; } if ${ac_cv_lib_gen_strccpy+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgen $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strccpy (); int main () { return strccpy (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_gen_strccpy=yes else ac_cv_lib_gen_strccpy=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gen_strccpy" >&5 $as_echo "$ac_cv_lib_gen_strccpy" >&6; } if test "x$ac_cv_lib_gen_strccpy" = xyes; then : $as_echo "#define HAVE_STRCCPY 1" >>confdefs.h IP_LIBS="$IP_LIBS -lgen" fi fi # Checks for header files. ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi for ac_header in limits.h pwd.h fnmatch.h sys/statvfs.h sys/vfs.h sys/mount.h sys/resource.h sys/wait.h malloc.h sys/time.h sys/param.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Checks for typedefs, structures, and compiler characteristics. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi # Checks for library functions. ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 $as_echo_n "checking for working alloca.h... " >&6; } if ${ac_cv_working_alloca_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *) alloca (2 * sizeof (int)); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_working_alloca_h=yes else ac_cv_working_alloca_h=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 $as_echo "$ac_cv_working_alloca_h" >&6; } if test $ac_cv_working_alloca_h = yes; then $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 $as_echo_n "checking for alloca... " >&6; } if ${ac_cv_func_alloca_works+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # ifdef _MSC_VER # include # define alloca _alloca # else # ifdef HAVE_ALLOCA_H # include # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ void *alloca (size_t); # endif # endif # endif # endif #endif int main () { char *p = (char *) alloca (1); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_func_alloca_works=yes else ac_cv_func_alloca_works=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 $as_echo "$ac_cv_func_alloca_works" >&6; } if test $ac_cv_func_alloca_works = yes; then $as_echo "#define HAVE_ALLOCA 1" >>confdefs.h else # The SVR3 libPW and SVR4 libucb both contain incompatible functions # that cause trouble. Some versions do not even contain alloca or # contain a buggy version. If you still want to use their alloca, # use ar to extract alloca.o from them instead of compiling alloca.c. ALLOCA=\${LIBOBJDIR}alloca.$ac_objext $as_echo "#define C_ALLOCA 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 $as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } if ${ac_cv_os_cray+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined CRAY && ! defined CRAY2 webecray #else wenotbecray #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "webecray" >/dev/null 2>&1; then : ac_cv_os_cray=yes else ac_cv_os_cray=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 $as_echo "$ac_cv_os_cray" >&6; } if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define CRAY_STACKSEG_END $ac_func _ACEOF break fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 $as_echo_n "checking stack direction for C alloca... " >&6; } if ${ac_cv_c_stack_direction+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_c_stack_direction=0 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int find_stack_direction (int *addr, int depth) { int dir, dummy = 0; if (! addr) addr = &dummy; *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; dir = depth ? find_stack_direction (addr, depth - 1) : 0; return dir + dummy; } int main (int argc, char **argv) { return find_stack_direction (0, argc + !argv + 20) < 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_stack_direction=1 else ac_cv_c_stack_direction=-1 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 $as_echo "$ac_cv_c_stack_direction" >&6; } cat >>confdefs.h <<_ACEOF #define STACK_DIRECTION $ac_cv_c_stack_direction _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working POSIX fnmatch" >&5 $as_echo_n "checking for working POSIX fnmatch... " >&6; } if ${ac_cv_func_fnmatch_works+:} false; then : $as_echo_n "(cached) " >&6 else # Some versions of Solaris, SCO, and the GNU C Library # have a broken or incompatible fnmatch. # So we run a test program. If we are cross-compiling, take no chance. # Thanks to John Oleynick, Franc,ois Pinard, and Paul Eggert for this test. if test "$cross_compiling" = yes; then : ac_cv_func_fnmatch_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include # define y(a, b, c) (fnmatch (a, b, c) == 0) # define n(a, b, c) (fnmatch (a, b, c) == FNM_NOMATCH) int main () { return (!(y ("a*", "abc", 0) && n ("d*/*1", "d/s/1", FNM_PATHNAME) && y ("a\\\\bc", "abc", 0) && n ("a\\\\bc", "abc", FNM_NOESCAPE) && y ("*x", ".x", 0) && n ("*x", ".x", FNM_PERIOD) && 1)); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_fnmatch_works=yes else ac_cv_func_fnmatch_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fnmatch_works" >&5 $as_echo "$ac_cv_func_fnmatch_works" >&6; } if test $ac_cv_func_fnmatch_works = yes; then : $as_echo "#define HAVE_FNMATCH 1" >>confdefs.h fi for ac_func in vprintf do : ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" if test "x$ac_cv_func_vprintf" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VPRINTF 1 _ACEOF ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" if test "x$ac_cv_func__doprnt" = xyes; then : $as_echo "#define HAVE_DOPRNT 1" >>confdefs.h fi fi done for ac_func in geteuid getcwd getpwnam getrlimit getpwent getwd putenv regcomp strcspn strspn strstr do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # need fftw so we load and unload wisdom on startup/shutdown # Check whether --with-fftw3 was given. if test "${with_fftw3+set}" = set; then : withval=$with_fftw3; fi if test "x$with_fftw3" != "xno"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FFTW3" >&5 $as_echo_n "checking for FFTW3... " >&6; } if test -n "$FFTW3_CFLAGS"; then pkg_cv_FFTW3_CFLAGS="$FFTW3_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"fftw3\""; } >&5 ($PKG_CONFIG --exists --print-errors "fftw3") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_FFTW3_CFLAGS=`$PKG_CONFIG --cflags "fftw3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$FFTW3_LIBS"; then pkg_cv_FFTW3_LIBS="$FFTW3_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"fftw3\""; } >&5 ($PKG_CONFIG --exists --print-errors "fftw3") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_FFTW3_LIBS=`$PKG_CONFIG --libs "fftw3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then FFTW3_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "fftw3" 2>&1` else FFTW3_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "fftw3" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$FFTW3_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: fftw3 not found; disabling fftw support" >&5 $as_echo "$as_me: WARNING: fftw3 not found; disabling fftw support" >&2;} with_fftw3=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: fftw3 not found; disabling fftw support" >&5 $as_echo "$as_me: WARNING: fftw3 not found; disabling fftw support" >&2;} with_fftw3=no else FFTW3_CFLAGS=$pkg_cv_FFTW3_CFLAGS FFTW3_LIBS=$pkg_cv_FFTW3_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_FFTW3 1" >>confdefs.h with_fftw3=yes fi IP_CFLAGS="$FFTW3_INCLUDES $FFTW3_CFLAGS $IP_CFLAGS" IP_LIBS="$FFTW3_LIBS $IP_LIBS" fi # goffice needs libgsf to save plots to files # Check whether --with-libgsf was given. if test "${with_libgsf+set}" = set; then : withval=$with_libgsf; fi if test "x$with_libgsf" != "xno"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBGSF" >&5 $as_echo_n "checking for LIBGSF... " >&6; } if test -n "$LIBGSF_CFLAGS"; then pkg_cv_LIBGSF_CFLAGS="$LIBGSF_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libgsf-1\""; } >&5 ($PKG_CONFIG --exists --print-errors "libgsf-1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBGSF_CFLAGS=`$PKG_CONFIG --cflags "libgsf-1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBGSF_LIBS"; then pkg_cv_LIBGSF_LIBS="$LIBGSF_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libgsf-1\""; } >&5 ($PKG_CONFIG --exists --print-errors "libgsf-1") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBGSF_LIBS=`$PKG_CONFIG --libs "libgsf-1" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBGSF_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libgsf-1" 2>&1` else LIBGSF_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libgsf-1" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBGSF_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libgsf not found; disabling save plot to file" >&5 $as_echo "$as_me: WARNING: libgsf not found; disabling save plot to file" >&2;} with_libgsf=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libgsf not found; disabling save plot to file" >&5 $as_echo "$as_me: WARNING: libgsf not found; disabling save plot to file" >&2;} with_libgsf=no else LIBGSF_CFLAGS=$pkg_cv_LIBGSF_CFLAGS LIBGSF_LIBS=$pkg_cv_LIBGSF_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LIBGSF 1" >>confdefs.h with_libgsf=yes fi IP_CFLAGS="$LIBGSF_CFLAGS $LIBGSF_INCLUDES $IP_CFLAGS" IP_LIBS="$LIBGSF_LIBS $IP_LIBS" fi # optional ... use libgoffice to draw plots # pretty basic functionality, really, but we need to be able to build without # it for testing # Check whether --with-libgoffice was given. if test "${with_libgoffice+set}" = set; then : withval=$with_libgoffice; fi if test "x$with_libgoffice" != "xno"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBGOFFICE" >&5 $as_echo_n "checking for LIBGOFFICE... " >&6; } if test -n "$LIBGOFFICE_CFLAGS"; then pkg_cv_LIBGOFFICE_CFLAGS="$LIBGOFFICE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libgoffice-0.8\""; } >&5 ($PKG_CONFIG --exists --print-errors "libgoffice-0.8") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBGOFFICE_CFLAGS=`$PKG_CONFIG --cflags "libgoffice-0.8" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBGOFFICE_LIBS"; then pkg_cv_LIBGOFFICE_LIBS="$LIBGOFFICE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libgoffice-0.8\""; } >&5 ($PKG_CONFIG --exists --print-errors "libgoffice-0.8") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBGOFFICE_LIBS=`$PKG_CONFIG --libs "libgoffice-0.8" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBGOFFICE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libgoffice-0.8" 2>&1` else LIBGOFFICE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libgoffice-0.8" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBGOFFICE_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libgoffice not found; disabling plot display" >&5 $as_echo "$as_me: WARNING: libgoffice not found; disabling plot display" >&2;} with_libgoffice=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libgoffice not found; disabling plot display" >&5 $as_echo "$as_me: WARNING: libgoffice not found; disabling plot display" >&2;} with_libgoffice=no else LIBGOFFICE_CFLAGS=$pkg_cv_LIBGOFFICE_CFLAGS LIBGOFFICE_LIBS=$pkg_cv_LIBGOFFICE_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LIBGOFFICE 1" >>confdefs.h with_libgoffice=yes fi IP_CFLAGS="$LIBGOFFICE_CFLAGS $LIBGOFFICE_INCLUDES $IP_CFLAGS" IP_LIBS="$LIBGOFFICE_LIBS $IP_LIBS" fi # optional ... use libgvc to draw graphs of workspace dependencies # Check whether --with-libgvc was given. if test "${with_libgvc+set}" = set; then : withval=$with_libgvc; fi # gvc 2.30 is broken in a number of ways and we can't use it, see for example # http://lists.research.att.com/pipermail/graphviz-devel/2012/001544.html if test "x$with_libgvc" != "xno"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBGVC" >&5 $as_echo_n "checking for LIBGVC... " >&6; } if test -n "$LIBGVC_CFLAGS"; then pkg_cv_LIBGVC_CFLAGS="$LIBGVC_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libgvc > 2.30\""; } >&5 ($PKG_CONFIG --exists --print-errors "libgvc > 2.30") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBGVC_CFLAGS=`$PKG_CONFIG --cflags "libgvc > 2.30" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$LIBGVC_LIBS"; then pkg_cv_LIBGVC_LIBS="$LIBGVC_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libgvc > 2.30\""; } >&5 ($PKG_CONFIG --exists --print-errors "libgvc > 2.30") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_LIBGVC_LIBS=`$PKG_CONFIG --libs "libgvc > 2.30" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then LIBGVC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libgvc > 2.30" 2>&1` else LIBGVC_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libgvc > 2.30" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBGVC_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libgvc not found; disabling workspace dep graph display" >&5 $as_echo "$as_me: WARNING: libgvc not found; disabling workspace dep graph display" >&2;} with_libgvc=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libgvc not found; disabling workspace dep graph display" >&5 $as_echo "$as_me: WARNING: libgvc not found; disabling workspace dep graph display" >&2;} with_libgvc=no else LIBGVC_CFLAGS=$pkg_cv_LIBGVC_CFLAGS LIBGVC_LIBS=$pkg_cv_LIBGVC_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LIBGVC 1" >>confdefs.h with_libgvc=yes fi IP_CFLAGS="$LIBGVC_CFLAGS $LIBGVC_INCLUDES $IP_CFLAGS" IP_LIBS="$LIBGVC_LIBS $IP_LIBS" fi # optional ... we add some gsl funcs as builtins if available # Check whether --with-gsl was given. if test "${with_gsl+set}" = set; then : withval=$with_gsl; fi if test "x$with_gsl" != "xno"; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GSL" >&5 $as_echo_n "checking for GSL... " >&6; } if test -n "$GSL_CFLAGS"; then pkg_cv_GSL_CFLAGS="$GSL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gsl\""; } >&5 ($PKG_CONFIG --exists --print-errors "gsl") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GSL_CFLAGS=`$PKG_CONFIG --cflags "gsl" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$GSL_LIBS"; then pkg_cv_GSL_LIBS="$GSL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gsl\""; } >&5 ($PKG_CONFIG --exists --print-errors "gsl") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GSL_LIBS=`$PKG_CONFIG --libs "gsl" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gsl" 2>&1` else GSL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gsl" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$GSL_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: gsl not found; disabling extra numerical functions" >&5 $as_echo "$as_me: WARNING: gsl not found; disabling extra numerical functions" >&2;} with_gsl=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: gsl not found; disabling extra numerical functions" >&5 $as_echo "$as_me: WARNING: gsl not found; disabling extra numerical functions" >&2;} with_gsl=no else GSL_CFLAGS=$pkg_cv_GSL_CFLAGS GSL_LIBS=$pkg_cv_GSL_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_GSL 1" >>confdefs.h with_gsl=yes fi IP_CFLAGS="$GSL_CFLAGS $GSL_INCLUDES $IP_CFLAGS" IP_LIBS="$GSL_LIBS $IP_LIBS" fi # optional ... use this to open the help browser, if available # Extract the first word of "xdg-open", so it can be a program name with args. set dummy xdg-open; 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_path_XDG_OPEN+:} false; then : $as_echo_n "(cached) " >&6 else case $XDG_OPEN in [\\/]* | ?:[\\/]*) ac_cv_path_XDG_OPEN="$XDG_OPEN" # Let the user override the test with a path. ;; *) 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_path_XDG_OPEN="$as_dir/$ac_word$ac_exec_ext" $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 test -z "$ac_cv_path_XDG_OPEN" && ac_cv_path_XDG_OPEN="no" ;; esac fi XDG_OPEN=$ac_cv_path_XDG_OPEN if test -n "$XDG_OPEN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XDG_OPEN" >&5 $as_echo "$XDG_OPEN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$XDG_OPEN" != "xno"; then $as_echo "#define HAVE_XDG_OPEN 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define XDG_OPEN "$XDG_OPEN" _ACEOF fi # optional ... use these to update desktop after install # Extract the first word of "update-mime-database", so it can be a program name with args. set dummy update-mime-database; 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_path_UPDATE_MIME_DATABASE+:} false; then : $as_echo_n "(cached) " >&6 else case $UPDATE_MIME_DATABASE in [\\/]* | ?:[\\/]*) ac_cv_path_UPDATE_MIME_DATABASE="$UPDATE_MIME_DATABASE" # Let the user override the test with a path. ;; *) 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_path_UPDATE_MIME_DATABASE="$as_dir/$ac_word$ac_exec_ext" $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 test -z "$ac_cv_path_UPDATE_MIME_DATABASE" && ac_cv_path_UPDATE_MIME_DATABASE="no" ;; esac fi UPDATE_MIME_DATABASE=$ac_cv_path_UPDATE_MIME_DATABASE if test -n "$UPDATE_MIME_DATABASE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UPDATE_MIME_DATABASE" >&5 $as_echo "$UPDATE_MIME_DATABASE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "update-desktop-database", so it can be a program name with args. set dummy update-desktop-database; 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_path_UPDATE_DESKTOP_DATABASE+:} false; then : $as_echo_n "(cached) " >&6 else case $UPDATE_DESKTOP_DATABASE in [\\/]* | ?:[\\/]*) ac_cv_path_UPDATE_DESKTOP_DATABASE="$UPDATE_DESKTOP_DATABASE" # Let the user override the test with a path. ;; *) 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_path_UPDATE_DESKTOP_DATABASE="$as_dir/$ac_word$ac_exec_ext" $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 test -z "$ac_cv_path_UPDATE_DESKTOP_DATABASE" && ac_cv_path_UPDATE_DESKTOP_DATABASE="no" ;; esac fi UPDATE_DESKTOP_DATABASE=$ac_cv_path_UPDATE_DESKTOP_DATABASE if test -n "$UPDATE_DESKTOP_DATABASE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UPDATE_DESKTOP_DATABASE" >&5 $as_echo "$UPDATE_DESKTOP_DATABASE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi nip_desktop_update=no if test "x$UPDATE_MIME_DATABASE" != "xno"; then if test "x$UPDATE_DESKTOP_DATABASE" != "xno"; then nip_desktop_update=yes fi fi # stop the DBs being updated: useful for packagers # Check whether --enable-update-desktop was given. if test "${enable_update_desktop+set}" = set; then : enableval=$enable_update_desktop; nip_desktop_update=$enableval fi if test x"$nip_desktop_update" = "xyes"; then if true; then UPDATE_DESKTOP_TRUE= UPDATE_DESKTOP_FALSE='#' else UPDATE_DESKTOP_TRUE='#' UPDATE_DESKTOP_FALSE= fi else if false; then UPDATE_DESKTOP_TRUE= UPDATE_DESKTOP_FALSE='#' else UPDATE_DESKTOP_TRUE='#' UPDATE_DESKTOP_FALSE= fi fi # we always need -lm IP_LIBS="$IP_LIBS -lm" # needed by test/test_all.sh # :( what's a better way to do this, argh TOP_SRCDIR=$ac_pwd ac_config_files="$ac_config_files nip2.desktop Makefile man/Makefile man/man1/Makefile share/Makefile share/nip2/Makefile share/nip2/data/Makefile share/nip2/rc/Makefile share/nip2/start/Makefile share/nip2/compat/Makefile share/nip2/compat/7.8/Makefile share/nip2/compat/7.9/Makefile share/nip2/compat/7.10/Makefile share/nip2/compat/7.12/Makefile share/nip2/compat/7.14/Makefile share/nip2/compat/7.16/Makefile share/nip2/compat/7.24/Makefile share/nip2/compat/7.26/Makefile share/nip2/compat/7.28/Makefile share/nip2/compat/7.38/Makefile share/nip2/compat/7.40/Makefile share/nip2/compat/8.2/Makefile share/nip2/compat/8.3/Makefile share/nip2/compat/8.4/Makefile share/nip2/compat/8.5/Makefile share/nip2/compat/8.6/Makefile src/BITMAPS/Makefile src/Makefile test/Makefile test/test_all.sh po/Makefile.in nip2.spec" 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}' DEFS=-DHAVE_CONFIG_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 "${OS_WIN32_TRUE}" && test -z "${OS_WIN32_FALSE}"; then as_fn_error $? "conditional \"OS_WIN32\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 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 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 if test -z "${UPDATE_DESKTOP_TRUE}" && test -z "${UPDATE_DESKTOP_FALSE}"; then as_fn_error $? "conditional \"UPDATE_DESKTOP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${UPDATE_DESKTOP_TRUE}" && test -z "${UPDATE_DESKTOP_FALSE}"; then as_fn_error $? "conditional \"UPDATE_DESKTOP\" 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 nip2 $as_me 8.7.1, 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 case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" 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 --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ nip2 config.status 8.7.1 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;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --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}" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`' configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in AS \ DLLTOOL \ OBJDUMP \ SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_import \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ lt_cv_nm_interface \ nm_file_list_spec \ lt_cv_truncate_bin \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ configure_time_dlsearch_path \ configure_time_lt_sys_library_path; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' RM='$RM' ofile='$ofile' _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 "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; "nip2.desktop") CONFIG_FILES="$CONFIG_FILES nip2.desktop" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; "man/man1/Makefile") CONFIG_FILES="$CONFIG_FILES man/man1/Makefile" ;; "share/Makefile") CONFIG_FILES="$CONFIG_FILES share/Makefile" ;; "share/nip2/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/Makefile" ;; "share/nip2/data/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/data/Makefile" ;; "share/nip2/rc/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/rc/Makefile" ;; "share/nip2/start/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/start/Makefile" ;; "share/nip2/compat/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/Makefile" ;; "share/nip2/compat/7.8/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.8/Makefile" ;; "share/nip2/compat/7.9/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.9/Makefile" ;; "share/nip2/compat/7.10/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.10/Makefile" ;; "share/nip2/compat/7.12/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.12/Makefile" ;; "share/nip2/compat/7.14/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.14/Makefile" ;; "share/nip2/compat/7.16/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.16/Makefile" ;; "share/nip2/compat/7.24/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.24/Makefile" ;; "share/nip2/compat/7.26/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.26/Makefile" ;; "share/nip2/compat/7.28/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.28/Makefile" ;; "share/nip2/compat/7.38/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.38/Makefile" ;; "share/nip2/compat/7.40/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/7.40/Makefile" ;; "share/nip2/compat/8.2/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/8.2/Makefile" ;; "share/nip2/compat/8.3/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/8.3/Makefile" ;; "share/nip2/compat/8.4/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/8.4/Makefile" ;; "share/nip2/compat/8.5/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/8.5/Makefile" ;; "share/nip2/compat/8.6/Makefile") CONFIG_FILES="$CONFIG_FILES share/nip2/compat/8.6/Makefile" ;; "src/BITMAPS/Makefile") CONFIG_FILES="$CONFIG_FILES src/BITMAPS/Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; "test/test_all.sh") CONFIG_FILES="$CONFIG_FILES test/test_all.sh" ;; "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; "nip2.spec") CONFIG_FILES="$CONFIG_FILES nip2.spec" ;; *) 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_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers 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` 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 ' >$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" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :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 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _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" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :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. 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 } ;; "libtool":C) # See if we are running on zsh, and set the options that allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}"; then setopt NO_GLOB_SUBST fi cfgfile=${ofile}T trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. # Written by Gordon Matzigkeit, 1996 # Copyright (C) 2014 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can 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 of of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program or library that is built # using GNU Libtool, you may include this file under the same # distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # The names of the tagged configurations supported by this script. available_tags='' # Configured defaults for sys_lib_dlsearch_path munging. : \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} # ### BEGIN LIBTOOL CONFIG # Assembler program. AS=$lt_AS # DLL creation program. DLLTOOL=$lt_DLLTOOL # Object dumper program. OBJDUMP=$lt_OBJDUMP # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shared archive member basename,for filename based shared library versioning on AIX. shared_archive_member_spec=$shared_archive_member_spec # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm into a list of symbols to manually relocate. global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # The name lister interface. nm_interface=$lt_lt_cv_nm_interface # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and where our libraries should be installed. lt_sysroot=$lt_sysroot # Command to truncate a binary pipe. lt_truncate_bin=$lt_lt_cv_truncate_bin # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Detected run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path # Explicit LT_SYS_LIBRARY_PATH set during ./configure time. configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \$shlibpath_var if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF cat <<'_LT_EOF' >> "$cfgfile" # ### BEGIN FUNCTIONS SHARED WITH CONFIGURE # func_munge_path_list VARIABLE PATH # ----------------------------------- # VARIABLE is name of variable containing _space_ separated list of # directories to be munged by the contents of PATH, which is string # having a format: # "DIR[:DIR]:" # string "DIR[ DIR]" will be prepended to VARIABLE # ":DIR[:DIR]" # string "DIR[ DIR]" will be appended to VARIABLE # "DIRP[:DIRP]::[DIRA:]DIRA" # string "DIRP[ DIRP]" will be prepended to VARIABLE and string # "DIRA[ DIRA]" will be appended to VARIABLE # "DIR[:DIR]" # VARIABLE will be replaced by "DIR[ DIR]" func_munge_path_list () { case x$2 in x) ;; *:) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\" ;; x:*) eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\" ;; *::*) eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\" ;; *) eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\" ;; esac } # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. func_cc_basename () { for cc_temp in $*""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` } # ### END FUNCTIONS SHARED WITH CONFIGURE _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test set != "${COLLECT_NAMES+set}"; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain=$ac_aux_dir/ltmain.sh # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; "default-1":C) case "$CONFIG_FILES" in *po/Makefile.in*) sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile esac ;; 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 # generated script needs to be executable chmod +x test/test_all.sh { $as_echo "$as_me:${as_lineno-$LINENO}: result: * general build options native win32: $nip_os_win32 native os x: $nip_os_darwin update desktop after install: $nip_desktop_update debug: $enable_debug * optional packages and modules use fftw3 for FFT: $with_fftw3 use gsl for numeric functions: $with_gsl use libgoffice to show plots: $with_libgoffice use libgsf to save plots to files: $with_libgsf use libgvc to show ws dep graphs: $with_libgvc (requires gvc > 2.30) use gtkinfobar to show messages: $nip_use_infobar (requires gtk+-2.0 >= 2.18) use notebook action widget: $nip_use_notebook_action (requires gtk+-2.0 >= 2.20) use notebook group name: $nip_use_notebook_group_name (requires gtk+-2.0 >= 2.24) allow regex searches: $nip_use_gregex (requires glib-2.0 >= 2.14) display help files with xdg: $XDG_OPEN " >&5 $as_echo " * general build options native win32: $nip_os_win32 native os x: $nip_os_darwin update desktop after install: $nip_desktop_update debug: $enable_debug * optional packages and modules use fftw3 for FFT: $with_fftw3 use gsl for numeric functions: $with_gsl use libgoffice to show plots: $with_libgoffice use libgsf to save plots to files: $with_libgsf use libgvc to show ws dep graphs: $with_libgvc (requires gvc > 2.30) use gtkinfobar to show messages: $nip_use_infobar (requires gtk+-2.0 >= 2.18) use notebook action widget: $nip_use_notebook_action (requires gtk+-2.0 >= 2.20) use notebook group name: $nip_use_notebook_group_name (requires gtk+-2.0 >= 2.24) allow regex searches: $nip_use_gregex (requires glib-2.0 >= 2.14) display help files with xdg: $XDG_OPEN " >&6; } nip2-8.7.1/Makefile.am0000644000175000017500000000236113351443023011354 00000000000000SUBDIRS = \ src \ test \ man \ share \ po EXTRA_DIST = \ autogen.sh \ doc \ proj \ m4 \ nip2.desktop.in \ nip2.xml \ nip2.appdata.xml nip2appdir = $(datadir)/applications nip2mimedir = $(datadir)/mime/packages nip2appdatadir = $(datadir)/appdata nip2app_DATA = nip2.desktop nip2mime_DATA = nip2.xml nip2appdata_DATA = nip2.appdata.xml install-exec-hook: -rm -rf ${DESTDIR}$(datadir)/doc/nip2 $(mkinstalldirs) ${DESTDIR}$(datadir)/doc/nip2 -cp -r ${top_srcdir}/doc/html ${top_srcdir}/doc/pdf ${DESTDIR}$(datadir)/doc/nip2 -rm -rf ${DESTDIR}$(datadir)/doc/nip2/html/CVS -rm -rf ${DESTDIR}$(datadir)/doc/nip2/pdf/CVS if UPDATE_DESKTOP install-data-hook: -$(UPDATE_MIME_DATABASE) ${DESTDIR}$(datadir)/mime -$(UPDATE_DESKTOP_DATABASE) ${DESTDIR}$(datadir)/applications endif dist-hook: # make sure we don't get any .svn dirs from EXTRA_DIST # also "fred" gets left around occasionally -find $(distdir) -name .svn -exec rm -rf {} \; -find $(distdir) -name fred -exec rm {} \; uninstall-hook: # make sure we have write permission for 'rm' -chmod -R u+w ${DESTDIR}$(datadir)/doc/nip2 -rm -rf ${DESTDIR}$(datadir)/doc/nip2 -$(UPDATE_MIME_DATABASE) ${DESTDIR}$(datadir)/mime -$(UPDATE_DESKTOP_DATABASE) ${DESTDIR}$(datadir)/applications nip2-8.7.1/compile0000755000175000017500000001632713417042641010711 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2018 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*) 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/*) 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: nip2-8.7.1/autogen.sh0000755000175000017500000000244413351443023011323 00000000000000#!/bin/sh # set -x # remove /everything/ ready to remake rm -f Makefile Makefile.in aclocal.m4 config.* configure depcomp rm -rf autom4te.cache rm -f install-sh intltool-* ltmain.sh missing mkinstalldirs rm -f src/*.o src/nip2 src/Makefile src/Makefile.in # glib-gettextize asks us to copy these files to m4 if they aren't there # I don't have $ACDIR/isc-posix.m4, how mysterious ACDIR=`aclocal --print-ac-dir` # OS X with brew sets ACDIR to # /usr/local/Cellar/automake/x.y.z/share/aclocal, the staging area, which is # totally wrong argh if [ ! -d $ACDIR ]; then ACDIR=/usr/local/share/aclocal fi mkdir -p m4 cp $ACDIR/codeset.m4 m4 cp $ACDIR/gettext.m4 m4 cp $ACDIR/glibc21.m4 m4 cp $ACDIR/iconv.m4 m4 cp $ACDIR/lcmessage.m4 m4 cp $ACDIR/progtest.m4 m4 # some systems need libtoolize, some glibtoolize ... how annoying echo -n "testing for glibtoolize ... " if glibtoolize --version >/dev/null 2>&1; then LIBTOOLIZE=glibtoolize echo using glibtoolize else LIBTOOLIZE=libtoolize echo using libtoolize fi aclocal # this produces a lot of benign but misleading output ... hide it and hope for # the best glib-gettextize --force --copy > /dev/null test -r aclocal.m4 && chmod u+w aclocal.m4 autoconf autoheader $LIBTOOLIZE --copy --force --automake automake --add-missing --copy ./configure $* nip2-8.7.1/Makefile.in0000644000175000017500000010035013417043241011363 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(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_HEADER = config.h CONFIG_CLEAN_FILES = nip2.desktop nip2.spec CONFIG_CLEAN_VPATH_FILES = 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 = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac 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)$(nip2appdir)" \ "$(DESTDIR)$(nip2appdatadir)" "$(DESTDIR)$(nip2mimedir)" DATA = $(nip2app_DATA) $(nip2appdata_DATA) $(nip2mime_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(srcdir)/nip2.desktop.in $(srcdir)/nip2.spec.in AUTHORS \ COPYING ChangeLog NEWS THANKS TODO compile config.guess \ config.sub depcomp install-sh ltmain.sh missing ylwrap 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) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip 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@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ SUBDIRS = \ src \ test \ man \ share \ po EXTRA_DIST = \ autogen.sh \ doc \ proj \ m4 \ nip2.desktop.in \ nip2.xml \ nip2.appdata.xml nip2appdir = $(datadir)/applications nip2mimedir = $(datadir)/mime/packages nip2appdatadir = $(datadir)/appdata nip2app_DATA = nip2.desktop nip2mime_DATA = nip2.xml nip2appdata_DATA = nip2.appdata.xml all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign 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; $(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): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 nip2.desktop: $(top_builddir)/config.status $(srcdir)/nip2.desktop.in cd $(top_builddir) && $(SHELL) ./config.status $@ nip2.spec: $(top_builddir)/config.status $(srcdir)/nip2.spec.in cd $(top_builddir) && $(SHELL) ./config.status $@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt install-nip2appDATA: $(nip2app_DATA) @$(NORMAL_INSTALL) @list='$(nip2app_DATA)'; test -n "$(nip2appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(nip2appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(nip2appdir)" || 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)$(nip2appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(nip2appdir)" || exit $$?; \ done uninstall-nip2appDATA: @$(NORMAL_UNINSTALL) @list='$(nip2app_DATA)'; test -n "$(nip2appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(nip2appdir)'; $(am__uninstall_files_from_dir) install-nip2appdataDATA: $(nip2appdata_DATA) @$(NORMAL_INSTALL) @list='$(nip2appdata_DATA)'; test -n "$(nip2appdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(nip2appdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(nip2appdatadir)" || 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)$(nip2appdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(nip2appdatadir)" || exit $$?; \ done uninstall-nip2appdataDATA: @$(NORMAL_UNINSTALL) @list='$(nip2appdata_DATA)'; test -n "$(nip2appdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(nip2appdatadir)'; $(am__uninstall_files_from_dir) install-nip2mimeDATA: $(nip2mime_DATA) @$(NORMAL_INSTALL) @list='$(nip2mime_DATA)'; test -n "$(nip2mimedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(nip2mimedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(nip2mimedir)" || 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)$(nip2mimedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(nip2mimedir)" || exit $$?; \ done uninstall-nip2mimeDATA: @$(NORMAL_UNINSTALL) @list='$(nip2mime_DATA)'; test -n "$(nip2mimedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(nip2mimedir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files 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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook -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-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 ;;\ 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) dvi \ && $(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-recursive all-am: Makefile $(DATA) config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(nip2appdir)" "$(DESTDIR)$(nip2appdatadir)" "$(DESTDIR)$(nip2mimedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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: 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." @UPDATE_DESKTOP_FALSE@install-data-hook: clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-nip2appDATA install-nip2appdataDATA \ install-nip2mimeDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -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-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-nip2appDATA uninstall-nip2appdataDATA \ uninstall-nip2mimeDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: $(am__recursive_targets) all install-am install-data-am \ install-exec-am install-strip uninstall-am .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \ dist-tarZ dist-xz dist-zip distcheck distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-data-hook install-dvi \ install-dvi-am install-exec install-exec-am install-exec-hook \ install-html install-html-am install-info install-info-am \ install-man install-nip2appDATA install-nip2appdataDATA \ install-nip2mimeDATA install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-hook uninstall-nip2appDATA \ uninstall-nip2appdataDATA uninstall-nip2mimeDATA .PRECIOUS: Makefile install-exec-hook: -rm -rf ${DESTDIR}$(datadir)/doc/nip2 $(mkinstalldirs) ${DESTDIR}$(datadir)/doc/nip2 -cp -r ${top_srcdir}/doc/html ${top_srcdir}/doc/pdf ${DESTDIR}$(datadir)/doc/nip2 -rm -rf ${DESTDIR}$(datadir)/doc/nip2/html/CVS -rm -rf ${DESTDIR}$(datadir)/doc/nip2/pdf/CVS @UPDATE_DESKTOP_TRUE@install-data-hook: @UPDATE_DESKTOP_TRUE@ -$(UPDATE_MIME_DATABASE) ${DESTDIR}$(datadir)/mime @UPDATE_DESKTOP_TRUE@ -$(UPDATE_DESKTOP_DATABASE) ${DESTDIR}$(datadir)/applications dist-hook: # make sure we don't get any .svn dirs from EXTRA_DIST # also "fred" gets left around occasionally -find $(distdir) -name .svn -exec rm -rf {} \; -find $(distdir) -name fred -exec rm {} \; uninstall-hook: # make sure we have write permission for 'rm' -chmod -R u+w ${DESTDIR}$(datadir)/doc/nip2 -rm -rf ${DESTDIR}$(datadir)/doc/nip2 -$(UPDATE_MIME_DATABASE) ${DESTDIR}$(datadir)/mime -$(UPDATE_DESKTOP_DATABASE) ${DESTDIR}$(datadir)/applications # 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: nip2-8.7.1/test/0000755000175000017500000000000013417043451010361 500000000000000nip2-8.7.1/test/test_all.sh.in0000644000175000017500000000264413351443023013053 00000000000000#!/bin/sh # set -x main_result=0 test_result() { if [ $1 = 0 ]; then echo ok else echo failed main_result=1 fi } test_result_fail() { if [ $1 = 0 ]; then echo error: did not fail main_result=1 else echo fail expected fi } # run the test workspaces test_workspaces() { for i in @TOP_SRCDIR@/test/workspaces/*.ws; do base=$(basename $i) echo -n "testing $base ... " @TOP_SRCDIR@/src/nip2 --prefix=@TOP_SRCDIR@ --test "$i" result=$? # test_fail.ws is supposed to fail if [ x"$base" = x"test_fail.ws" ]; then test_result_fail $result else test_result $result fi done } # run the test defs test_defs() { for i in @TOP_SRCDIR@/test/workspaces/*.def; do base=$(basename $i) echo -n "testing $base ... " @TOP_SRCDIR@/src/nip2 --prefix=@TOP_SRCDIR@ --test $i test_result $? done } # load all the example workspaces too test_examples() { for i in @TOP_SRCDIR@/share/nip2/data/examples/*/*.ws; do base=$(basename $i) # have to skip these two, they use a non-free plugin if test x"$base" = x"framing.ws" ; then continue fi if test x"$base" = x"registering.ws" ; then continue fi echo -n "testing $base ... " @TOP_SRCDIR@/src/nip2 --prefix=@TOP_SRCDIR@ --test $i test_result $? done } test_workspaces test_defs test_examples echo "repeating tests with the vectorising system disabled" export IM_NOVECTOR=1 test_workspaces test_defs test_examples exit $main_result nip2-8.7.1/test/images/0000755000175000017500000000000013351443023011622 500000000000000nip2-8.7.1/test/images/slanted_oval_vase2.jpg0000644000175000017500000005646313351443023016035 00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?'֔pxJ P=3GGQJ:2iFz4,OJ֓=0sItN9<c8Hzր m8`IgӭGjZZ`.0h#'_ΖRQA9 1-&~j1F)qHr!?@sKZ"sրqHxȤ(xEQ׌R'ZZC@ 3@KIj;@ zS@Ϩi> 1K&9)jNZJq4(})9=(:\Z=P;G&OҎ `3I@ AПJSHG87ZLs8@H KOILC N4R\)旽9?JSi0AҀ SE>@zRcR(A֗4}(# K):_4u){;@ ϥ-!$}(3'ZpIs@CH =iǵ's@hPZA tIz'{Ҍv(O֊='& d`Ri;Қ`74Rɤ3FI]` EZ1L.H`J9Hp}(hZCH:S"o=x.)1AQ i9ޝ֛@uKg9/#G^ih贆&CKF==(84 9)E4GJ\g֗xBKӊ\CPׯJ3Oʓ;Sך)(1HibPhPh h4p !@ĥ)֔JyJ"Qڀ/ғE (zҏJLRc"^JM)sQ1):sGoQI@fs%"PtK֔t uS H{RCp2hS)bރ֌fPc%wN&oSA)qGj@4RRwJ1K!R%NQip:PjLON(is@G=?@8)(q B>i4ғJ1Ƞ80)c$Rpi @1֊Z:uQ =ڔfx8t4ȥ#4h dQ iq}GjhJ)r)ړi?L4Q v)) c-&9zzҞ;g?Jbbڊ^Z7ӱR{) cN4q`7QQڀitA֒Qޗ'Qii1i.9jyJ:GNM 4=isJr:SN}(z1ڊ(ғ֓<恅/O=)X$;)ؤ(RwO\IHG8(;PG4vLv`.3I;@ E.3ILzsH=(#.S1?(QiiE>4)~&~ZMԤ;yF)p)ҝc'LfP341җh֗Ac4S Hr{w\v-Ydl)vqؤu h$v4]JT!8*) ծʔ8};@ru=AF$OrsIҧzs & &9I|X帕OUO ahPQSG<3 C\,#d GVIS؎*]ٝ88;ZdFjJ!48h@ ;)@#`KF)pE&EHSi;Pzяj^ -&G=h=(A&zKNh)hҔ)1 ^)z% ~4󎔘斖1:֔@i1Ki1@'yϵ@ Jqc= ѷJ]sG8!;ڗPGbu ޔwchPqu4@?*^)ǥ::ހ9\P=Gb3\׉m,stŷt@7 8~M!Wu vF:*V2j_(x '4zqǵ0E.3I40ipNi p?ڂiO!⎜ґ.8 {iCKbJ=Ҁ 8tEjJ2sA4Aydt@ 8`ҁ (^pr;1PvgУ iNccOh4 (bQR9 }(;҃Hhn8w;8b&zqN=h#"ޓ'ҝzNS@7n@w!D)O@|:\gZB &;INI> K0@9Kx4KvsNҁҌ/^@A('ޓ>IdD141ޱ|MwجҞ~3|Zĭss,՛5bj0k_JMr求Թh78Z鱘ɤ[!y1 zOt,tQҪ&;$Km0(ˌ?}?w޽CWh`t~ oSN(7!nr:fq?6O7zTGԐ;ק^ 9 J93ҐSW-'6qL5I3RGҁ3U@u ڴu\ŇLzRI)j!/%ix8vs#ff8 R}M {`(A94))zS'٤)yIN8>.qP"2E0?J;N#iy.9#`(7mX_KU<'񞆧]j;❏c0p`RqKu!Қhދ) ۿ:p=) \ԥȠ/=)q֙#B8x*g,PNxPhAԀtNޜsGs@exA8ZZFW;.$F+, 1¨'ҼRk&=v,TVa[Գ~=qrrsQI^EM\)ۃQe+sG\Zq.2=Mi 6(#8s $9Ov'^!\2>\}k5L%SZKHuf PqzXxcqTO5ҧ=ieڟ" T #3۩4GLV"PJK鉞Z3"_ OnUSv3Z 3ӺZ^s]&hg>vh(&8"; RzR"=x \}i ץFPG)aR){R3F:i1#SژXh 90sMҞNq"❎94 fG8zfuasH;fOZm E v(?OZaMJG8(B%)pq\)çAa'(zK}zw zqӁ4q8R~i n8cq89=^dsF@01Ewm0<};N[>kuHU`<曻.*ȵk ш9?LWcǭzW>vvqק.Twv, b9Ҥvmx!H"ؤOWYzA8 hU=NSk֮0ڸSb2X~1RIZs7FGoJ֪Z3&ztv*XTD !sHcD݁#z&ǡV9ԡ~۰CVOcp;^_> 3A֟S #lcIN& !㞽Þ< &h w8ҁK1CoapADD&T6` lj2*HqVs[]Hi\\J4=QƟ?]lWRgol%du?m.vG$t W>ݦ6uWZ.;Ϗi[h $pONË hڙ0We]~Q ?b/-$.M]%Hdd :Tʜ:ֶT*cYd}k;ݼ#/ڔzL VF|f8ϭg޴qǽ 5"ڥaGJstȻ^~@9;99޳[ N5XTќL@QOTb+Pp:W=Yr<0?t@q]0w2kQ;80EP 6㎴=4 ^48ɠ`J&GM`?! FN@rZ; F%))'uz*-$_aRM0KTVҫbӘF npՉұ1ɦJ֜A(sһRsI&N3֚F9`qA84(┌qEi4u)qяcփێR XCq{Zr1$PzӰsҐ{S^Gv ⎸9PN;(9)Fmb"MⲙjySsIF,jD9#&: STUʻ!uhyzz/?κ(c90޴ƍ<lR2){ҕ`֗h!EaVt<y#lIa{٢t:8ǥF+$0P92 „}Q O *Þ0q5UY)l=+w䷈ԃq^rhǵ ғSqIaxg z|esԀrF~a57y3H-A8$5z | 5rsJ)6T7JIiYGp;?i(qڮLn+{N6Ms+ _Xw3ۭeRwи-nSMnX{9E1X89>niA)!DpkVq+2.Z-98?|Fj4P4y>3@ՒgRIzt6 QsNh40N)HǦhFGzSz_&yOE}z:u/5ÖP[-H=O*U_nzCfw9$!5  ӚSRKe=e$U9+7+ұ  9dRPc94I:S@i[A؎VjgP`/5/{f̫v_dK0qޥj<H}kti6k½@9aoZ/Ҍ}Lcq[܄D3zRN)ph8zP:ӱ4mjB35H wK6=TMo Z4X@xGlw,?qf7͌R'ӊckq\[wɪw@'ʰ ?f:::Tgw\L1ۥ4\4`皐.H)\ p^)Ib֛4 yH} n=i1R1I8xi1Ojn=uQmN4y4,;hF(8dddӱ׎iq;1"%r\όao $9v'i+$~5l8$}J*5`RFirrzRP m c49=(#]r*["vy5c PǠp3JZ8O8)1NY?Jы5hCv5 hFx֤-Pc|t:N fKZn3ڳfD)iqKyȠvNi@ҕh #;ӻӂ90/^kg+k&uWLgQs'8=:}h`j))B3$ӷ@J859IA?ZFbGF[N':lI9@4cZr;2I2G?^P>n"F=X מi?Z皑#ҐC333?S$sȩXQ&FF1u]j@S@Uf"BTG apywpތ2FcqLjں`2i6Z`J {SqS`p}\cJ?҃ @G]dS㠦@ n|ԝM"M#x␎A)A<)vt;d GpiqJqqJA Ny`4wkZ_3\AO^ \`Hsa^gic4dd@;& Åu]zΙA#uKSV%Y9Y!HI2HE4Tr| uwn[ȪF軣-v.R‿6DqA=)=qz@F'B=)HM0ZB)ҹҘZ'֤=)NqN0M R  @8 gOjzF\ӆqp_~h_ҟ4F)BvGZ6&QAlr+u}3z`EG~k5Co3Jff8Q@1Z3 ւpqހtguEt4zqG88)q<8$)>S0֥5jE(l~ R L@Xb)`_J|m\W`⸏@>,WRG^+L'ɥ#czv)歒'@iݑӥwNLʽi1{m\Ge]>N+;0|;j1O6d m=i6֤4࣮i1Ii,F9JK_hr?݌cGиc$/$U*5یqԱ*9X"v>VpZD\9()ų *IU ֣!y ةOQ7|z16HW4=)F}(1`gS :tKJ3P1@Ob) p~ ֚)I#0&xR18#l̀OxVꖑc!Pxk7dzfJF:IWM1@tP~EfbR|FDcqA0j&8pj&F2qK31n9bOZr旜QI49HH( bAQ99.\W=5a)Co^qo_-ܞc/j~m`GQUu'6Aޯe[b1?= Ev==+Qsު[1j2+@b%UAc­Gu6Y?wV{9UrNLDLxqiĂ~i3Is@dR*^WJ=S/AQH3T8FP&S(.t4ΟրUi CV9E"dqvb{m SBc<6בOɠ=*FE›k zQq#/HFJBҤ׏NhFOO—oniqN 9qNNۭ(^qݸڔ v]k&l7O^)'=)N> =ݽRc)Iڀi?^S)H0)ڝל隌ϩh1@jy#QQkkkQ#xf;כ|1yqtL;WKqݍxN(DZdz~qǠӭ 1Pj,S XTB*+DD?#h4jvpz xndP4JS'8y3MIn:SO_Τb{Hn @QNYX7O!OJ P")8W>U5Y ׷J #ҝJhϥ.:zgS\s 5k\t1:ӱ)HI##S$eGizZhi\Z3M`EqF?:~i;Q :b~_qڟE QqOQP ٥um34yӤȿ]LW) `a30j$Tw\Js֔}J@! ~4$R=*p1j?1J 4 Ap)Fyp w/qP?LP3KsH08!:PRG  ai ɐdHTb'B omHjM&83h=i9֤֐)F #ic8==)RM OiBNۚihZp҅杷OJ\q.9HVtoqo𬍁JZk1O +~L)2T[i'${Ef؏Թ8LRw(<'b8kr)HN(@3l{ISw{|Ȫ1q\In+>XVDymE-U}.)RVP_n?Zg@1HNHQ2ܴHyIџ֔@l[>:SZBGC3֓zvi anr:f hn7q8 8 T Pr($4+s@1KL|h ^):fyIPyoqSODsMnONiF9̈ʌ⑗{)1ҝD{ LqT;} 59<րv8֜Ԍn *AN|杴~4>xC.3c ~4 JFo )>Cnk[^nyz'ֳ?JӹQ=,dS&k"yHi q%``SYE;ZCddsҘF!OzzKc'v`V[ԝiqa9= ztLMN1On9&zP ZxH P?;N0Jw>Ը>:Qq h:ӰsրHFu+~;Rsjn3kFW ;5ȄzYc5J1D5i;R~ԲiJqLcڄH)OLrq֘ 0dsFGI}(p (R4Ԁ(<1ڃp) ǧLSZJqjKAc+${x,Mgl|UO_GҚ3 NSmT#5Ʃ dC"'֣2j[(:}sHNH'7N) @) t" i^)柜ny=(ӎM&=@9JO^LnJpF!^2)ST GN#qL4x1Ml9aR{ 3p7AÉɨzc?<`)Za#4L/'饱ңf4`rhۚP8W$=NeEw~=M# L*'M"'9R13v  wKޟA~$R2!0?{?j{-#^~SFRPiԃ>PHc-Hxqs[°y$w&Մ c N:Re);)8$r{ iݑZ2zqsJzC'4 NsR@x>lc E'\dsG/IйJg=/ގzw GJF擏 wRzsKڐ|R ɥP1x4I@<Rr)Oޞ)4H {S5IJ3Jld)sHOjaLcMa⁊O74SCJb:<ڗB4{ޝڪ4 \s֊Q֓1F)ph74ցK" %b{JːCLץM\k6:ۯ5+iqܤAd0 O4&J 7'֘ PMqZPpSqZQ`83Q;cPy6KQjZ:de班 gxY>ٱp/*u-Tq(5o3x#җ) ;a^\klEb^5HkQT0W`Բ"v9d~#4␄#qA4f@i;ȠzhGs)B@ 9ǭCfAnOJ1Kq֓zрM#{R ;Р8`CҤQcJGw@"N`wv4]͌9ȣSQґlS<|޴cך^r(a@ zRm*.*jns7pEHhQK(gO8ɤx#4dRIZzQށqց׭0b[Q9WOZ n!ui) yPvO4\mhۜԇL瞔L;HI oq -!M4i)s@ÿ.yڋ S { (\>gBI;wt8WC+z?u%PR> i`H+z64U5u=9Y zS c`8q^8yȠ (tu&g ֽ ndXryz6zI +4&L߉`O֤dWQGCjct{xf+➰yᲣsUP2kzSdbksm*8אOM)k+.0oͦ "GV[i&] B5+bE8Wo?a&v6h'LJĺcB8;1QVrM|Һh3{RciLB@<ޙNzQ5''9=)Xd34<'{licLiz v~iI3IÏJhWho $ 3҆ 1`WS2SLfiVJ{lf'blܯAcCQg^]G\BD赆S^6dc L74C[v7ZK!a*2v dF=hտt$Tfzs?< pVQ W3D_G<\.8Kޛ@=iԅM1HT皛M@$qMv֬lIisR"OOT=*uMv様vpSRR=)pG4]S.) *{Ƨ>mr6ot7ټ)\˧DXt ֺ RlZFTOb1D=Vjk) qSs1뺂O5)~2# -kW_=fqMldTOuٔh}9,|8n0lƝLj2  WeKzsK9cc^ ızxqć_s+㏟W|wHUKMUg΍r)D9[f~rjxAl';](ǵ .y{K~OAWb츫xoq*LRPԘ&?JJRpycQ@:IۚB?nip2-8.7.1/test/extras/0000755000175000017500000000000013351443023011663 500000000000000nip2-8.7.1/test/extras/test-5x5.v0000644000175000017500000000246113351443023013373 00000000000000??
im_black /home/john/.nip2-7.11.10/tmp/untitled-nip2-22-XCCNIRa.v 5 5 3 # Fri Jul 7 16:08:51 2006 im_identity /home/john/.nip2-7.11.10/tmp/untitled-nip2-25-XV4JasU.v 3 # Fri Jul 7 16:08:51 2006 im_lintra 1 /home/john/.nip2-7.11.10/tmp/untitled-nip2-25-XV4JasU.v 0 /home/john/.nip2-7.11.10/tmp/untitled-nip2-24-XnmRZfF.v # Fri Jul 7 16:08:51 2006 im_maplut /home/john/.nip2-7.11.10/tmp/untitled-nip2-22-XCCNIRa.v /home/john/.nip2-7.11.10/tmp/untitled-nip2-28-XTqLP2D.v /home/john/.nip2-7.11.10/tmp/untitled-nip2-24-XnmRZfF.v # Fri Jul 7 16:08:51 2006 im_clip2fmt /home/john/.nip2-7.11.10/tmp/untitled-nip2-28-XTqLP2D.v /home/john/.nip2-7.11.10/tmp/untitled-nip2-27-X4AUAQo.v 0 # Fri Jul 7 16:08:51 2006 im_copy_set /home/john/.nip2-7.11.10/tmp/untitled-nip2-27-X4AUAQo.v /home/john/.nip2-7.11.10/tmp/untitled-nip2-30-XSKPvr8.v 17 1 1 0 0 # Fri Jul 7 16:08:51 2006 im_copy_set /home/john/.nip2-7.11.10/tmp/untitled-nip2-30-XSKPvr8.v /home/john/.nip2-7.11.10/tmp/untitled-nip2-32-XUyimQC.v 17 1 1 0 0 # Fri Jul 7 16:08:51 2006
nip2-8.7.1/test/extras/test_recomp_order.ws0000644000175000017500000001214513351443023015700 00000000000000 nip2-8.7.1/test/extras/test_transform.ws0000644000175000017500000007737713351443023015255 00000000000000 nip2-8.7.1/test/extras/test_magick2.ws0000644000175000017500000041260613351443023014543 00000000000000 nip2-8.7.1/test/workspaces/0000755000175000017500000000000013351443023012536 500000000000000nip2-8.7.1/test/workspaces/test_stats.ws0000644000175000017500000002342213351443023015231 00000000000000 nip2-8.7.1/test/workspaces/test_fourier.ws0000644000175000017500000002767113351443023015560 00000000000000 nip2-8.7.1/test/workspaces/test_image.ws0000644000175000017500000027205513351443023015165 00000000000000 nip2-8.7.1/test/workspaces/test_snip.def0000644000175000017500000000522713351443023015154 00000000000000// all the image formats we test, and their matching number format // we can't use uchar as a number format directly since it'll become 'a' or // whatever and arithmetic ops will start failing fmts = [ ["uchar", cast_unsigned_char, cast_unsigned_int @ cast_unsigned_char], ["char", cast_signed_char, cast_signed_int @ cast_signed_char], ["ushort", cast_unsigned_short, cast_unsigned_short], ["short", cast_signed_short, cast_signed_short], ["uint", cast_unsigned_int, cast_unsigned_int], ["int", cast_signed_int, cast_signed_int], ["float", cast_float, cast_float], ["double", cast_double, cast_double], ["complex", cast_complex, cast_complex], ["dcomplex", cast_double_complex, cast_double_complex] ]; // we need a to_real that does images as well to_real x = abs x, is_complex x = mean x, is_Image x = x; // numbers we test numbers = [-10, 0, 1, 10, 3.1415927]; test_unary op_name fn = foldr1 logical_and [test fname ifmt nfmt x :: [fname, ifmt, nfmt] <- fmts; x <- numbers] { // image == number can fail due to rounding differences test fname ifmt nfmt x = true, abs (image - number) < 0.001 = error (join_sep " " (map print ["unary", fname, op_name, x, "==", image, number])) { image = (to_real @ fn @ ifmt @ to_image) x; number = (to_real @ fn @ nfmt) x; } } test_binary op_name fn = foldr1 logical_and [test fname ifmt nfmt x y :: [fname, ifmt, nfmt] <- fmts; x <- numbers; y <- numbers] { // image == number can fail due to rounding differences test fname ifmt nfmt x y = true, abs (image - number) < 0.001 = error (join_sep " " (map print ["binary", fname, x, op_name, y, "==", image, number])) { image = to_real (fn ((ifmt @ to_image) x) ((ifmt @ to_image) y)); number = to_real (fn (nfmt x) (nfmt y)); } } tests = [ test_binary "add" add, test_binary "subtract" subtract, test_binary "multiply" multiply, test_binary "divide" test_div, test_unary "square" square, test_unary "constant plus" (add 12), test_unary "plus constant" (converse add 12), test_unary "divided by constant" (converse test_div 3), test_unary "multiply constant" (multiply 7), test_unary "constant multiplied by" (converse multiply 7), test_unary "constant subtracted from" (subtract 4), test_unary "subtract constant" (converse subtract 4), "" ++ "a" == "a", hd [1, error "nope"] == 1 ] { // libvips divide returns 0 for divide by zero test_div a b = 0, is_real b && b == 0 = 0, is_complex b && re b == 0 && im b == 0 = divide a b; } main = "all tests pass", fail == [] = "failed: " ++ join_sep ", " (map print fail_numbers) { numbered = zip2 tests [1..]; fail = filter (not @ extract 0) numbered; fail_numbers = map (extract 1) failed; } nip2-8.7.1/test/workspaces/test_colour.ws0000644000175000017500000014665613351443023015415 00000000000000 nip2-8.7.1/test/workspaces/test_widgets.ws0000644000175000017500000000523213351443023015540 00000000000000 nip2-8.7.1/test/workspaces/test_tasks.ws0000644000175000017500000010654713351443023015232 00000000000000 nip2-8.7.1/test/workspaces/big_and_small_disks.ws0000644000175000017500000041254013351443023017007 00000000000000 nip2-8.7.1/test/workspaces/test_matrix.ws0000644000175000017500000003107213351443023015377 00000000000000 nip2-8.7.1/test/workspaces/gold_sample.v0000644000175000017500000031167213351443023015145 00000000000000T.q8lAq8lA̻ĸŻƾľ;˽ѿľǼȹ|zqoijgba^_a`__[[[^ahda[]`^gab]`XXT\WYXV[YRVRTYXQNVU\XV]TVZZTQ[UWRHKPORRLOVUYOVVPX[YZYa]T]YWWVSS\X[`ac^ZZZXZTYY[]NWSSSUTSQVMOTORXZUVRRQT]OSTYRQZVXUUTXVRUUUUUX`Sb][U_YXWY[^SU^bZfYZ¼·ǽǼùȿŽɾĻüȺw}ysqtupogg_W^cX_YUa_`a^b\]^fa`aedXXV[ZW]SZ^W]X^SWPOVSV[T\WXU[UVNQSQVYSUQWPNOPSUMMNPU\YVW[][\\[]ZV]V_Y_\^_[_ZQLNYX[T^PUPPRRWQQXZYWYOWVSYYXVVVWXZa^WPSOQUTKQU\Wa^Zf[\]TWU[[XW]TXZZV[cU^ú½Ǿ¹ɽ}ymwtmmhi`a\c^^[aX_cf^fbbZ`e[a`eb[^]YTYTZ^TZYWWVSVKURZY_RSSW[XZ_WWTT]SXRMTIPNSTIQRYWNP\ZY^]^XS[^Wd\WWSY][`_]U^YV\`YU[MQQSNSUN]ZXWY\V[ZXYUNSVPT]WMTQOTUWSRUV\Y]UWYXZ_^\ZXWYW[Z[^]`Z\\aƾȾ̿|wsrrrirfeg_`\d_`bX``b[cb\dba]_Y[^[`[ZeXU\SWQZMSWX[VVLQRQZ[U[WVX[STWKR]SNKNLPGLNSSQVPZNMWW[_Z^YWVVZ[SQPWZ^ZQ^UVUSXQU[LNPENVWWQVU[[[YXTZSUZYZYTP[W\PQWPNT[XQQ`UWYX^`Y\aW\SXZ^]Y[ZY^^a`\Z²Ļлȼ̾ľƺĵĻȼ}xudjvjj`ldac`Yb][a]`UeaZd[]`\c[_Z^T]UYWUUSURSMQOMQZWUXW_UZURWRWPTPRSVU\TTSLWMKMRNMLT\V\ZTWV]`]_\\VYYVU][]_\[dXWY\[XRVRTSRRWKRUReVYYWRYVTT[[RTU\UPOUOUQZQZW_VZZ]]\c`]`^X^X_`_Vhb^Y[aW]_ŲƼνǼymnjiofggepcebepfceXaXaZZcf`_e]\^^]W^\dWd^VRPTSQSSYMRPKMTT`V\^YTQYIUSHRROXTVTMPWNHPVPSQQWRQX^YSTZY^_`_^cVZ\Z[\]\XVVWQUOOSTOVQ^WYYQSXW[TU\^VTYUVR[QYWPSNUQ[]WUTWWTS[TY\]Z_^V__WX[`\Z_[[]]ͻĿþvqrmeqjhfeeecdgfjkgiX^a^Xf`^Z[RY__^X\][[QWYXTMPPSSTUROJLRTYWYVJPLUUQMRTSNNRTXHKH@OQMO^YZWPUVV\bYXaX\[\YUWTa]W_YW_`ZV]WQXWWTVRRWTXb\WXVYXRYZZVYRYWRRZUPOUVWc_P^Y\Q^Z]]]ac`_^]b[Z\_^^`]baµûʺļĿ½ɾʼɻ˼Ļxwrnsrtfrdchf`bf_elcg_[d^^Z\X_Y\]^^dY_[`bY^XSQTXTNSQQURRSS[VTVWNNMLKQPNHQPNYSPMNMJSQT[PUQNQTY\Y]^YU]YYZYQRY[^RWVTUXVY\TTX]X[POY\X`X][VWeXY]UXXUTUQRTPSSSUNSUVRO[TO^ZUT`a_]]haaZ^`Zfbaa`iʸľžǿżżɾýźwsh`epend_gcajdabe]bcab\ZXU`U\^^d]_VUaX_]`UUSTZWZTWRQPUUOQRU\QOHMJJVONVQPKQTELKHESPQSY]YZRNORX[`[X^\XVW\MWYY[]X[[TNXZVQSWZXVQPWYT\^dhY[VP]]WWZJVUVZ[ZQU]QUOVZUZROUXUTX\WWU]\^[Y`Ye^b]Z\]ľſ½Ŀƿ˿Ĺ½Ÿʿ¹rslsgfjoqjdalhc]eh`k]g_S_^ZVYVT[_WYX\Y[_SOXSUZRKNPQVSYWPQMRJITULFFHHRNOPQJHSQHLFOKPORU^WRSV^XUPVV\[S[UTWSUX\a_ZVR]Y^X`VTSWRQYPXZ_aXc[`_Y`\[X^WSR\SQMPTTQVYLUZXUV\\UPNW]Y\]_]^U^^\dcY[b[ZûŶƺ¿ð¿ĹǺżû{nqjhpmpegnhcbba^a]^\dc_V^[X^X_ZfXbc_bb[\RYTTUWTPXTUUSPKPKDMOMQMMOKPFLUTPPOPKNQMGJHLMSWUSZSZZ^U[SRV\_Y^ZRTSU]VTSKLWTLWb`]^^_XTT\YU\Z^Z_]aY`WQY\VXUTYVWTQSVNJR^\YSWYV`VT[[WWV]ZYXXeajge][aſʻͷĺľƼƿǼžujdmjurldogk\fgeeba^b]]][^cYXXZ[[YX[`d]XZWQTPTQYPSVVKPOOQMDKEIPMNKGOMLNNMMFKINMHIJEJHKQQTSRRUW[MX]KaQYSP[NNU[VX\[WZ[V\VZN[WYQWU][[_`b[]Y_ZXWXVXNUYY]UUTWZWY[\UVTSZVXWYSZYUZV_Xd_e]afagZd[úĽɿøĵżƼº{odlmknolyccehibjd^a\c\ZZ[`b`_`[Xc^^`dceXTSVYUTSQMMKSMJNMINFFMEFNLLPMJMFEKKKNDOFJKHTJOWKQRQOVTW]WMOSXOPSTYPPXTWPQL[TROQWZX[T\RW\\Q[`aZX^^U\URXVbR[[S[VX`SOXUY]ZPZV[YXTe^^aZX\W`a`ad]eeYb\ŻijɾƸƶſøſshhilflkgsf_gqjfca]^a`][ZXZYW\\eZ\]_]eidZUVVYRSUNMGMOOIKNNGRIDHFICFNHGNQPMIHBIRNTSMLORLOWNWQSXONRRQRWVUUSPOUXORX\NT]QX]]WZZ]W_bX\YZXZY^UW\RW[T^WTVXXYUS\`V[TZTWTW`aV_UV^]U`R^R`]d]a_lYY][ļûſĹ¿ʺ¾þȽuqdgalkhqldhld`efahY[X]^XT[_\X_d\`\hZb`_Y_TSSRORMJKMPCKEFOJGHQGHKSMGTOOMFJLGKEJEGGMMLRJLPIUXLQUVSVHPPSOINRPUSKNMLQPMQQUQZZQXa\V\ZT`[^Z^_[YSW\\Sa[UVTSXOXUWU_W\TUY^`[aY]`Z]ZZUWYZXUZ]Z`b_cŹúǽʿýƾövpnrsppjnllilmf^__W^[\Y[YXYYRYW`fccl\cc`f\WRTNOQTMGIKHJFKINGKRPKJHIIFHFJKJHCCERMOHQPKJLQMIOXSUSHSRTLPPXOOOYSUSQXRPXNWXU[[\dXab^`[\YfXWYVUZ\UVVX]ZV[OWS_VUZXVYSS[]_]VXURZ]V]V_U^_]\e_]\\X\½û˾ȾȻzsnwqmsororhhmm`_b[Z\W\bYWZSWRZX^c^]]b```b^WMRSHJJGEHO@AJDKIHLMHNLIHJGBLNF@FFG@FDKHOGEOHNVWTNQKMKNRKQOQTVULVRQ[USOOOYS[TTQYZ^ZcZ^YXY^Z_X^SWXXQVSZSSSYPSTXOZaTSXTWXX^]ZZbZ[Y[YR]Z][\WY\be\YĻȽͻļwrmywtsvwuyeggmlaa__X_Z_ZWXPZUR^TX^[\f^hfZcTOSNHIHIINGNOLNHHMNED@LGHMFHJFJIFJEJLLILUSOXNOPLSNJOPUQNJRNKQNPOORY]]\XORPVP[U\YbbZ]Y]UY]]e]d[_X\\^XVYTYZZRVSU_Y\^ZY[YT`YXba\SU]TY_ZY]YV]eZZ]Ugμžȿ¿¿ź}tpxqpx`u|ntxnulffgaZ__]`]VZPX[S[]X_bc^[cei]_aaRMOMIEGJAGKJKHLCRLDIDCEMQJSJQMHHKJOGIADQTSINILROXPMNJHKHINLOVUQYXRPSOSTSWUVZWWUVVYS^^UVWU_^XZ[WZ]WVUWXWWUUQX]QUY_\VX[\XVT\Y[WV\ZY^_T]UUYc\ec`bĸ̽ȾŻȹʼǽļĽ¼|xquvunpm|ovptohnde]c\\Zb^ZYZZYZWX]Y[`^]`[a_`VWOSQETOJKLSLNNPQLIHDGBOFJIIRHIOGTKKNKMMJNPNQIJRRIKVNOLNKLLJONIMMOWY`TSSTNU[XSTVZZV]]ZY\XUW^]`[\bc\\`V\TSSSUXQROYSYXW^[T[X^d\YeZZ]`XXba[__e`X[b`ƽ̻ûȺɹqnniyvrvsp{vpinicfdf_`_^Y\c^[WZUV_^SX\eb_U]VX]_OHVKVJQJKIINOGLHDGJLQKLHKLJLSJNPLHJNGOMJJUSJIMJMQNHRFHLLQOLVRKFPPQSVONQ\USYSNUOUN\W]X^^WYZT`Z]XV\]R\WVX]UPWXU_RQW[^UZYV\[cY`_]WYZVa\c\Z[b^b`]b¶źɿýŷ¶}xnpvrvrrxttx{wlmi]Za`de^Y_e`d__]\Z]Z^aaYWb\ZORUWURKPHFLOLKJTIJ?KHILRIJHDNPNNQOMNMOHLQKHMPPLMNLFDKMNNIKLFELQNONQOEOJQOMNQYORRZTZ[\a^\_\UVSXUZZ`^_Y[Z\SSXWYW[\\]WVTRTRYYX]Z_hS`\Z\Z]c_ahb]a[bdaǼϾ¿ʽŴwqpfp|uzvvq{uqkke]^a`hca]W\^c^dl`\ZW^fW_d[XS\LRPMTTNIPIFGJOGXOMKDEJKSMJPAHITPJFOMIICEGLMLNOMEPRKKLJKQNHHRDRNNPHKDROOHQUQMVUWW[XRU^T`Y_VQ\[SZ[ZYXT``T^[YX[TaWM[TY[^aXWVZWV__Y[ZX_``a]da^b_f`^^f˻ù̿ʾĿ°øwvjury|y~w|wxxyekccba`^\Z]f\]bejncpi^`WUXZ_Z_UTSXUUTRSSLLMHIOIYKPHKJPSMKKPLPLGONOOUONOOTKOMPJNMGKELKKPRFNEEIOIKFISHCUYTRSSRWSYRTOPUU`Z[[]V^VPY[_ddXPSYX[Z]\XX[PSSXbSYNTWZ_TZb^`_^[_XW\U_^[`\bdb¼ɿüüºyvtiut~x~vy|~ttqmchW_d[__^aekcegidgc`W\`adXV\UW][SNWZNEHTPQSTSTKOKKNLISOXJFQNILOKNNNHOMKRLJNNJGSKEGDFMNHMHQOOFHKUYVONSOVMYWWWSUW[YOYYZVSUWT[W_Y^VZW[Z`SXUVWT\VUX\T\YZTVSU\[[hZba_`X__cg^heaic\Ҿþɾļ÷ľñw|y}xqs}y|{wxuoqk_^cbaaab_d_ebneldae]Z][ZXX`YZYZ\YYRUSMSMWUSWTWLLOOIQVVSTLNPROLVKILPNJLVUOMRTGLSMGJNGHIMJLJGHRNJOQRKKROJUTQOWRTXP]WYZWX[\]Y[]XU[[ZV\Z_^XUWXUUU^aOVYUXW]VXWZZa^[_aVd][]]ea_dafX˿Ⱦº~zzu~vtuxxz}sut{vptrfghe^`a[ba\dadlckc^[ZUXZU[[^Y`YUWV[YKTVSPQVU\YGTQJHLHJUNRKFMFJHMGITPFSGQLNXQPIQGNGMFLCGMGKAPHMELOUOOMSPLPRVOULTUQPUOQUVYYYY^[WWXTUWXXdTZ[W[XSPTYXV_\WZ^LWY[W^VcdbcYZ]][]``YZ]bƹþ}{xwwt~zyxtw|yxyvzdci]j]gcd[]efjjhjma^YTWUSS\[\ZU\[[Y\WVUXUXYQQRXTQKMLROOKQPNDNQHFOQMNXPOWQUNTMSSUOHCDOFIJFGCGNNLJLIQLRRVNTTRWM^ZR[VVSTRVYXRX^VTRZ]XROWXUXXUTRQXTWST_[ZY[\W\]_cbaec\^SY^caeZ[\X^ʼ½»źĴwpvsxv~vxuzqxwrskolotnfbeceebea``eb_ad\aTX[SV[\W]]WRYT^[VTU]VX\YURRUSILSIIOPQNNHNIGOSUOSTULNSSNLRNNMUPIJJIICMKLFLEFHPJSNVLGMLORPQRMOUURRUYUV[SVY[XZS^WWS]Y\X_UZSTZSN]U]]Y]^S[Y\b`[\V`^[b\P__b^aade«Ŀͺƺ¼Ʋyrwyxv|x|vyyxvyxmuwtveaicjgjjceZ`]ee__b`[^RUYW`SV^V`T[`\^Z_PZYUZ^UNLLKNJNGNKMRMPJUSPPIRQVV[XVNP]XLSNRQLKOHIMIBEHGCEGMILKQOTGMLRPY]SQQZYSVX[V\YWWT[TWUSQSBSWb]QQV\WTYZR]XYXX[]^\ZYQX^[Vb\[Va[Zcc]]`cѽǻɻij{z~q{vtt}wtnv{wy~usjpoqqoioflddih]\bae\cad_bVYXSU^ZLT]VV^]X_[U^]UaWTLTPROKLHQQKNJQONOPNS[Y][XSWUVRQY[OXNPSMINNLEAGCGGKMLFHJMYQMLLMPFDPKMOR^QVYOVXTYXVRZ]TQMXXZW\b]VTNORYZX_`Z`\Zb_^YW]]W^YXSZYZ]Z^Za^b½Żļö̾{tzu|zxzw}}wzz~|~wsnsrupkkiqqljgia`^ig]^\c]aYZWUX\UVURR[a`a^\XZ\^bXUUSJKRMPNMIMWRONUN]XSS\][`ZYUTTXPVPLOSJUIFOMKHBDFIEPJMELGNQQKNFPJGOPMUWY^USWWZYZWTPXUTNV[YY]YRZQRXXPVZX]Z\WZTT_`QV_]^U\]\\_d\`__][`Żÿõ}xrrytxwvzstxyty}xqlsjpsoohflsffhh^\a[_f`_Waa_YVVZQ[PSTP[\[Z\]Z[Z^_`TU^TTTMNHEFPNNNTNPPVZa[[WcX\T][YTQUTPHPKPPKBGFJHRLIONLQNNOQLNQMIMLLLYVZZW]QWVQQNU[V^SZUTSYVWZYY]YVSYQV[Z\ZZYV^Z^X]W^a\WV]SXXgZ\c]_\ŸIJʺżƻĶ´sxsnvzn||xwxtsxzxy{wjtruqnosqpnpuoffbX[^fegh\`a[a[[XT\VVOWSY`b]WaXa`Z[[ZWTPJLQFJLMPIRWSTYR]Z\YS^]X\]XW[VQULRGJKQGDFJFFNFNRFQDIHLNIHNPRURVSQMYZUUWVYWUUXOLTUYUUTZ[\ZZU\NSMHYS\R]\cYQTYSWYWT[WZ`]VYZb\[YZUfľĹz}qqwquxqzysqmxxy{zyopffqmpsshmfinmk`b]b[]eaZ\[[]W[bYW`][TPWcYTZ]cb`dY[b^`SMNQIIRRRPQXSZ]TYY[^^ZX[YVQaWSTPOKEKEOIMGOKJKLLOKIHMIQSKIKLTKNPHQDKRGU[V\TUbPTWLZTWSSVPTXUW]ZWXR[UZV[XW]PVd\[Z`^\X]^XWWaabQbc_^^¿ûſķĶxtnfrwuvyw}yxplwqrywsvktlpvqtvzqlmmqb]\^_\baY\c^`_f]\XV[U[\X`Ye^\Xbc`Z^bbVWTTROMQIMOJOVTYXYTWVTOV\X[ZWVUWIPIHIDGFGELMHOKQPOORGBCMILKONNQTMRQTSQV`XUVWYPWSXXUOQYUTSUWY[XXWMQW[_\[Z\Ta_Z_X]][]\\UXS][X]cVc`\ľþŶǼùɼȸ¼xxqkqqihlp|ytzrorxkvvwvntlpronvvuoome_c^[Xe`Y[c^c^cf_`WZ[XYbc_U^\YdZ^^[\[]X_[XSUOPWQNQQWS]R]^XZYURYVTO]XPSNKFABB@CIILKFILMIRJHLJKMUNKBLJNJNKLQJLQSQUT[XRRPWYSTXUVOY\[PS\XYSWXM[VX\W^d\XZRV_ZY^a_ZNbV[X^aba^`Żȼþȼ~othnmgqvvuv|}zywvw|rsvlldqulonvpsph_jdb[Ycga__dc^Zff^\]a\\[`[X\Y`_^bc`]cea_]aSVWPIOIKKLZ[Q^W]YPTSZUTQUWSMMIQLQFEGHDGJKDFJQWWNILDGLJKHOLOHHSQLMOPRWSTQTRUKLTSOWXXWaZWTPRSX\MY^]SYTTX]YX[QV\_Wace`RT]VVY\_\``»ǿüxtj\jhfkoqxuwszxwzvzrvnmirylqkvpqjpoqhhddiSb`cbbb\ecfbZb][Z\_]\UYRUS]ad_ac^i[`i\YXSJKTUWVNYWYY[WW_X\aYbUXZRGQBKOEGJMGFKIGKBPUPWGHHINNKRNMPPLMQMPPPPKMQTRUQOPNVSPWPOZRUYXPU^[`UJRSWW\\V_XZWX^[_a`_^[[XX[^]`b_``úŹ»¿ýʵƻ¼ljU^aberqrpuwyu~{xzvreqmpoqjknnkmqjga`bc^e`]\hbl`b_a]]^][VW\ZZU_TVed\[`[dc`^cdVYOPSHLUU[V\XVTZ^[T[[YXSZUQPLFHKNGGDHHGGMNCDMSSTVKIRSSLCMHJOKJQKMMVWSLSNNIUKTTNPKWUUZW[]YXRVUabXXOT^SW[ZbS]PYa]^^cd^V[`\a^Xb\]úĹľtg_WQNYXhstvpprxyxqvvpknvsrqsqrhomighgjajd_affhgne_f\cbb\VVd]WZ^aZW[^YZ]WXX`^V_ZYSPVPSOSN`Z\`W]a]U]`ZfWVVNCINQPOGHH>IOACLDHSWQURMWPPNQMIIRIEJONKRRMOPXQTRUIUWXYUSP`[YXVW]TR^VYZXWQWYWX]WO]V[_cbY[YX^`^YZXZaaZŶ¼ŻĻŽü²ĿypcONJMQ[bklmxtyzz}u}trrpnffqoonwfi`enncbbhefgbkacdc_fh]]YYRUPY`\Za]^b`hc_[]Z`VZY^\UTSP[YJN\\YQ[cZSVWVS[a\X[UWRNNJMOCHGJJEEFBEHSSKSJHSMOQKLGQOHNNRQSMRLTPLPUWURRMJLRMQQTYW]VOY[WRTPNTSWVXY[VRPW\X]VXXV][T[YYWWc`YƹĻŽľÿuo\RKFDIU]ebkpsmtv{sxtrknkmnhrnkmojmmejnfchbdkf`_ef`aafaa[WSTT`aZZZ_^]daaVXUYZY\Z[XW\PVURRRX\W]^``b\^VXX[\[TTQHLGGILKGHFFJG?CBPQUTQQLRPQNSPOSMNIGPVYNQKINPUPOOPPLTWXQQMWT_\TQURSSU[SVRTY\_UUXPVYXaYWX[\VZWZXY^e\]ļϻƾ¿ɾžźzrZTLHNNUalkolsoovrmqk`hgdgkimlnivpnkei`kfjeedglcbc_\f^]a[]ZSW\W[gdWX`\`YUVTZYYZ]WUU[TVPRRNVXY^`aZ[_ZVU`]XXRSOQHFEGNPIJFBHMBHHFMNKUMKNNSIKHKGGSPKPWVLNPIOSNXPWPRKQSRXPWSVVVXWZWVXQRMSTZZcYUOROS[V\[^WXYXZc_\YeagYüƾɽŻƼùŸ±}~}jc[QTMPS\irnljpmrvpmjd_gblbnljotvkkieadbcajf`dcecVY[bfbZ\YTV[]W^Ze^aV]a^^T[RSNUVUXV^\YSSMVWSUW[U[_\ZVSU[bWWZOONMKLTMLJGLGPDIOQPSXHFTQPHPLQSKGFJMNPPSKIOKLXVUXSWOYVZWVVW`]YZTZUW[YY[NOSYX]ZTWVZY[[[_X\VY[\cc^]cbbƶȿļʺø¿öy|{||kkcV^XW[dgdkmqgopqjiehic\iloimqireof`^\Vc[_dcdgdcdcaab^Y\UQVTVW[Z_W[`]WXORWYQRR\S\QU\[TUUWTRSY\YW[]ZUV][]^U]RDOPELKGLIE?NDLJOWVTRKPQROPQIGILKONMMGOTSPLJNOXWWPQNRLTVRXQVSZ[RV[[SPSPTR^XX_QQYT_WZWaUWWYX[c[d[^]VQºĶ³ùƾùù|xtxoohe`[\elrkmhkinhfad`ddeqjnpee[ephe_aW\[^adk]ee_d]Uih`\aZTTZVT[`[_XT[\^U\VTZRY[UU]Y]RYVU^`TY_XV]SYQYN[WTRVXPKLLOLOLJGIDIJKJIOPORKOWUJOGRHQJIORJMLUMJKPMPMOUV\WXRKVSVVWZT^ZXVT\_b^\XXSYZ\XPOR\]cYZXYYV]`b`\_\][Wȸżƻô{ww}{yzkkccohnjkhhnkkhggdoddaYkeip`f]_d`X`X^`\fe`mfem]bc_]^dc^XP\]ZbZZUZWZUYTQYUPQT^T[[[XYPUYWYY]Xa`XX[SWV^XTWOJPKQFMMKLDEKELOHTHSSTNHPPOPEPMKHKMQSMHOFQTNQQWSWWZKW\TNQTZUZ]Y\ZaWX\\UY]UYSXV[TZX\WUXYZY^X_V_TWX[[X[ĽüĿ̺~||xuxxuuholpqlfgfi`d``kfcgjphbc`Z]ijc[cc_Z^_eeUbagfZ\_`Y[]`]Z[`]XZ^Z[PXUUYXUYW[PTXSZ\VWT\]VWW[Z\VZVRXURO[\U[TQRJINJMJHMMIFKQPSYRZUSUSTSMIMLNUMLNWJMOQMOPMUXOT]UNSSRTOQR]ZZX`XV\__\U[UMVXVVTJXTWUY`Y^]VWZYWXQYRS^YĶø|~~|||}yxr{|~tppksbjfgkhihjjhkmgggcf`][`]e]dacebcccaa_ffgf[^ga`ZZ\ZXM\R\_a]WTKPVQZ^^[TXVPX]V]ZY\O\X[X^\U^WT[XXW[X\VYNRMMKLHIMMLKJJQSSJQTTOSWNUTSUTMHMOOJOMROTWSSRRVWWOZVRXHLTYUYXYTXWf[^[VTTXY\TQRXXUX]Y^VX\Va]YaU_X^_b[ŶȻ¹Ļ¿ij{tz~}~oxyl~~xvrttlrmpfhtnddljgcafehbeigg_`d\af`gdaefia^^[la]a_U``YZUWXYTS][]ZSUQVOP`U_XXQSZNSWXYXVOWVLR[SURROWSU^Xc]Y]WXSIOHINGMK@ANOOUVZPSNP[TRTRTONJXRPRLPOQSNPQQMKRXGNOQNOTNSVRZZSSOWX]\YTX_Y[\Z][[Q[WZheaV\^^[\[UYaVU[½uvwxvv|||wz}yytsv{}swzwslgiedinfbeehkkh`akd]eW`Ydkecagmc^mcd^h]bage^`a]XZYQQZUQ^`YYRRTTWSY_ZYROUNTYYUU]SQUXT_cW^U]NUYYScXYVVMORMLIOHLKBSKRNVXWSUW[X]QNSRRN\RNWQQGISUVXNPPPGPTNZMMUHPTZYSUNP\SUWVTY^ZWXWYYcXeaRYZ\[]\ZZYUQY[Z`\bǸxx{~wx~y~~txx{x{q}usjuwtilklnmmhfkcfjhc[dehd\bb]]`ordjlemhec`dhfVheXX^]QVVXTVTSa`ZSWPPSU[[babWWUUZYZYTYUSSYWVSNV^XVWQZZWZ[]SUPTLUJRTPLLHNXRRQWSTUVTRNS[O[WQ]XR[XGSYVMUUPYQTOLZUTJNOPOOXWWUTOW\NW\TQY]]^R\[XZY\c`[a]`^[UWXY]b_`Zǽ~}tuzyuw~{vw{yq|wt~znricjrmmkpjnefchadebci`eghb`babamccgkdhdhff^Y`aeaZeaZc\WNZUXZWXW][RTW\[X_XUPOKQW^YPTZRXVW`_WWTX[TT^^XeZT^SYWLOHLLKLIMLJSNMUNYWURUN\Y[PTQQSRTTMWOSYTRLOJEHKTOSTKQHNZNTTOOQQ_[ZYR]XZPRYW\]\XW\`ca_^aV[TY[Z]Yaa½ĻĺüŽýƿǷ}|u{wy~||z|||t}qxuvpxutlrqnokohilfd`e]l^dc_djhelcfg[gde^bdehbeffZdd]acq^]YVVUXPSVXZVVXV[WXR[\Xe]^TXTZUcTSOZ\OSTVYOUSXTX]W[cZWXRVUUVQKNRWLUPVQMRXRTKSYYS[U\UXTXeUUSWPSUOVUNZXTSKQQNRSNJKMIOVOUTQTRVWUUO\\]WZ^[bZWYZ^a``_V]WU[Zd^U_]ŷƼĻø}vwx|}~y{|qv~|{szpxpywulvifojtsgkfifea^becgdcihgj`^][\c_njcgcmhb_Z[\abZ[]_OPQZYTU[YZaXXU\UPWQP[WTVVZOUWVTROVNPYQWXRSX[[XV_WXP^`[SWNQUUQSLROQPOPYTV^[\Z[`]XVYPRVYRUSXTXRURX[bWSQHNOKVMPPGNQPRPQKWTVSTOUZWZS\X\[[X^[XYWZ^UXZV\[`e``UǿûŻüzw~qzw{yurtoz}qlsqoqowx~uqkinqjsiypgi`ef_cd\]_ekchebZ`]]_k_jehgj`c]`[^[bV_bd\\\[XZ]TYaV^VSYVUVXaVV][QTUWXMQNUQRUZORZXXUVXX[^YS[Z]]W]WWVQZJRXPLQRUUTNYUXR\UbR\SWQVSRNS^TV[QSSVWPMIONSTMMHEHJ[SUO\QPPWSUS]^Y^\P`][^c_Z\\^^^XZVW`[\ea\]û½ȿź²³Ľywmzur{}vzvqptusltqslxutsoloilqqvtqrrkcimmlmdbcbhmfece[X[^lkqiodcc_[]VZ\a\_`cXYVYXW]^YZZXYUVWTXYX^XXSW[UTSSQVVPM_[WUUSRKR[[V[_NO[Y\XTTSWOPRTTTVQURRTJSR]X\cW`[[VPWNSUK[ZTWUTXSYWNQVSOQJLNHQLNKOWXWQYQOQLYV[Z\V\[_f\Xa`dV[^^Sb^^Z\^_[XĿ¾¹¾ȶusxko{vz{sossotsrllmovrsotnwtskgorupgec`ioligc``dfce`beda_^fbilgg_``c[\^\`]bZ`]SYZVT`VVLYY`S[PXXbRYWWjWdZZSWHZMWTRSUZVRTYXZTX\USVX\^ZWXUYUXTSPUOSTYQWOSR[V[]VXUTRMRLUGIUP[[X[\ZVTPWRMNNLQMHOKOQIRLQT[MOQPTUZUXWSYZaaXYUY_]^YX`[_VT_^d`ȿûøķûywurtqqqxttytoqnmossrnmrnqnsotriqjlsrrjfdadimlni`_^^bcebhbdZ\Y^afooqhkad][[_WZb_c_a^]a[Z[[WZTPVQPZOYNPZPXSWUVRQWLNVVTRVYSSTNQQOYWRPUY\\ZTWUUVTSQSVWSSWRQWMHTWW[XeVWQWPVVVMPUSZUVZZVTQVNNTRSUTRULOOPSOSJXSVQPVTWYV\[_Y[aYWVXWWVUcWc\^YUUZZĻĺľĿwyxotnnowsvvxnmsjmpqnmkgrrqzkmvovonmrdmpseY[gumggge[Zf]ada]dbb[_eeql_im_b]\\`daX^eXUbZXVRMVQVMUVQXTNXSWYZ[VSYPYVSVUYSTXOQKVQVVX\PVWT\[S]TVWQPRTQRUSUJQZXXQTSWST^]QWLINROMJHVWUSTWWQ]XSQQWNUNKOFRQLRNOULHKPMOTVSPZ]WZZ\Y]YYUX\b\bWVYWZWV`_úüù˸½÷uyvnlegvnnvymmmlmtnnisjpknwolphirinmvsif]_abgnffcag_cifc_ce^Y\a`amonmgd^ab\\_]`kgadX[]WY]ZYXTXPTXUOUTQS`S]TTTX_SJOXYPRPPTPXWNROQPNW\\`Yb\UVZVVXTXUXTRWQXZVP[Y[[a_RYRL[XNRLOTHTVWTWSTSZTNUNTROKRLIOLTRMVOJKSPQXX[[Y_[a_^YTVU^MaadV^\WXSYedſɼƻǵĿwsqpknblfsyt}wlohwxyspkonpksuhpeflmuipjpaeofahkhcb\\^e`^ia`ab`Wdce_kj`hj_baZ`\T`bcj]_\]cY^]YYTYZWQYRR\UYVYZYUQ[XYOPQUOPPHW_YQXOPOQVUYRVZX\WXWWSVPRPSROTPWVSRQV^UcYVVRTSRUXVSKKNOTRPSTRUQLOJTIOMMLKOUMSKKIKMNPQSIVXWYVY\]XTVZYQcU_Z[YX^W_aj·ȷ¼ƽʼ¼|tlurmqjljlomitwvsnqsvoiokpppqsvqivhjpmoqmbdciemikiaa_^``\\Ze\f\U]\cjhqlgcb][Z``\\^^`c\b\e`_^__XYXUVZOXUPXW[YTUTR]YWTXLKOIPVZWNSRRUWURWQZ_VS[XWWYYXQXZVTXNRY[QX\\ZWXXYVTXXYXRILIQPRUWVU\SX\[VSSQMROLMQNFFLROFVJOSORWTTYS[\XYTX_]V^][b]W\S[g`Žźöÿ}{uoslhleaorimsqhqozrolsmpqrmnlnedlgktkmila`bfhqmd`[g]^aV]]\^_[`[^^i`b`cbZie_\d[]^feib`]Zd_WXZ[UXRPMYTVYXQVOSYTPLU[PNORNRPZ\ZYWWKPKLXXWVW\`ZYYYYVUQRSTZX[WW^\UZSSVQaXXTYKQPUSKVRFWOVPLTURSSNNTIJNJMSMNOBJLMOJEIRSMOZYYMZ]\RWZY[\[WXX^YXXZYUýĽŸƹĶysyqpjnpqrnicjkuqpysqmowimnvpmnmobghiggd^mdaYXb]^a`[Zaab\a^^_^d^YXb[g`cb_eYcbgff\^Z^ab_cee^__ccWbUUXRRVVXTWTPXVMXOXVNRRPRQKQV]STRNPRUNVWXXW[WQ\[[]VPLSYZRPIPQ\V\RO[[a]\WZSMMQSPIKMITQWUXVRYRMTLPROSIMINFHMNJRNRBIIIOFQOWX[Z]\^X_[Xb_^Y[X\V[[¶ɿ}ztwnqqhghiqlornoketrnuvzmqmiibi_fb^lbmidmf_e`dcgaYX_bbb`e^b`bcd`XWYccacffhakkc]YdX\\``fZba_V]_YZZVSUVXNS[[VW\V`NSXNSYRMOQTVYWUVURPOYYVUYZRXZZZ[W][TYTUT\XQUVY][ZVX\]^Z[TMXPWUNMKIOUPNQTUVZZSUTLRNMMLQJFKECDSLJHDPKJSNVY^]cZ]][\V]Zb\_d\[`\ZþûƼ²zmprkntlqmpnrwrtllpjosmputdbba\^\^`hcdcbg\g^][W\]V_]^]Z\\\Z][[^^[\W]Ze[[ielhhldaY\^a_ZZcZcc^Z]\WVU[LRQRaZ^]WUWYSPQLPVNPOLILVPSNTQSYTSUTTRXU\X_aYT]WTVQ^[O^RT[YZU\XZU\W[TRSOLMKHHLNRPQW\SVSZXRPOPOOHSNHDNOHJQLEOQOOJGQMVSXX[\YWZ\XZd[W][^X_búƾ»÷ɿó˿zsnmkindodlpinikjrqijmrnidka[Z\dYW]dlq__^bc^]ZY\MNVXa[a_`_^abh\[\TTS[\^_egkcgf`_]ZX]b\`ZZXY[Y]USXa]PUZX]d_TW\UKNHORRTNSPFRUSXSZXTRVSZUYSVUSWd_YYTOZZYWSYRVRSNSRSYYUU[PXUQONSWGTQTQCQNUTWTTWQRUQPROPKJEOADOJHOPQIPMUPSPUQU^VS[YZ]WZ]\a\Z_^b^˶þƼ~s|qgfikjbkoursxvmlkpermosjbbXMSRTTWb]beca_b`aYMUSKLS]\h[W`[XZX^RYWTaZ^Yc[d`ige`g`W`V]XZa^\YZ`SV^WS`XY[_WaZbU[SVSLNNQNJKOOILTSTVSRUSQSXUST[WZWT`Qd^aWRZW]XL[KSNMWZ^SYKRMSUXQRONQHQFHMMPW]MWSOPJMOMONMOGK?JCLMJNNOMQLMPOQWWYXV[`SWZ_V^Z\]e\_cþƻȰž{}tqmnfejlenomunonqmptopljggZXPLHLW[[jci`beeZ`OUOGIGOW[WZ`XTPUTOXVV[[[_[f]b`cckdg__]_ZX]V\YYYYSRUMUUX\[^V[YYTVPIIGINPUTRSRPQORWSYQRTQ^[]WOYTQZWR_RZ_YSUPTSUKPSOPUURZROPVSRKTUTVOIUPKMKSUXT_SUMLNGKGFLCIILFJQNIGKUFIQOTQTUUUZUXW\`Z[\UURTfVdd̸¾~{|msrnmi^kerppqomttuqpkokrfe]QHDE@GOX]gi]b_fX[_PLABPJMS[bccaWVUUTXWYRX[]\\Z[[b[j_bacaa^c`]b]UXVTSXTVSa[b\X^VWQLMKEEILONNIMOLOLRKVVVWZRS^W]YUXTVSRV[YY[WXLQWSX\SZYSWUUWWXNNSWTRMUPMPELPVNQRQOPMMPOJIQIFMHIGHHOGIIEKONQMOQXUMSVRSVR^^]_YV\_d_faǺƸ¿Ŀ|v}u{zokutegedkqoqkpxxxsuspgoj\YOI@ABKJW_df]c^cTSIJECGBRVX[c\X[UUWWTUV\We_^d_^]Z[^__`e]gY^W^Y[WX_^^TUW]V]b\UYLPPNNHIDBFQHGGOKQHKNJRTP^ZS^YZUWXZWRLRU`[Y]ZRRIWTUUWQZSVVY]\WXVSURPLNNOIGIPQPZYTQHSVRLJMGLVIPCLHLILOLTNLKPNNLSVTQJ^UMS^d\YY\WVca^]üþyx|{y{ntioihlmjmnnqsqntohhkuwh[SSHFJPNVY^afiicaWOIDGDAGIZZ`]cV[`[YVYX]^`Ya^_bcZ_\Zdebi\ache`YS[T_WW^]a[ZXXVVSOKECHAAABFHKROJTOKOPRLOXUZZXYX[YRTP\MVP_][SWZWU]U^SPTRXUaTYYXXPRS[ROFEGNQKMVQ\RZMRVKOKLLGMDHHMKHIFHMMOXKMKQMOKSRRTQJUUYY`]WR`[^aZcµûƿͿq{yw{lyvxqqfjgnmkpssqemqpfpuqmb`RNPJINLR`de^dd]VWPIECIKPSUZ^^]TTTYU`WU`_\b`d]`[[UZ^][_Zde\][Xe\aX\U\XSUYOSLIPKJDEIBHH@FHIQHMHNGOQURLSXNZTY[WVTU]KYQX[WVXS_STVW\ZW]XZVW`ZaWQRWSVNWNLLLOPLPNQTYSPOVMOKMLIKFKHDMJOISUMTSPNPNNJKTLVZPY^[]]ZZVXW\\_[ſsvut~~rsytlimhhnmhiglqpqrpoovsuoe\ZSOTSZRU^dilefaYXUNKEMSRRZXY[[WY]OYXY[Sba\`_bfY\ZVWb^Zed^bi_^]Z^]^b[TPYZNPHAJICBB?C?<:AFFEIIMLPYUVZRZXXaaTPVSPUOQXVZYVVZYZRUX\U]U\]]_\W\YYWVMPXPPSRMKTNONO[LQQOTSVKJAMMHHEHKKHKPGHUITOESLTUYSUQTVNQSY_YRT`W^][Zżº}~xwu|urllmojlmioeoqjjpdinlqmoflf\\\XWZ\^a\hfdbcUQMTNNOYQUYY\[Z`a_\f[\X^X]bb_aaf[YV[aY\S_`^_cab]aZ`]ZWPQMKHGJG??=BCD@;>D?IDKGEANPSTZTQNWW]YTRWWVX[VSZX^^WXVVTRZUWWTXV\V^Z`\UTNXNYUSTTGMNQRJMOPRRNGIKOPMNNFGFJEHMKNPIHDOMLTQTVSVTTVSTXU[TWY[`ZZ^[ź}wzvyx|wsuqpmnohljqimpgqljgilfodliee`W]fdXbbehgdadZ[ROQONXZ]\S[ce]Y\\XU^YV[\a[[bcd]_\^^dd]a`ac^Z\SW^XWPSNNIAF@EB;<9D?CCIIGIMHMKTWSUOTWYUVVW[\USTZYZ[ZZVZZTTPOWXTRYYWU^_YVVQOTQOXV]TOKUPRNSTSYYSNOPMIMRFHGDCNOMSVNVOQMNNMSUS\OONQVZZWKXWNVYZYXZy~v{w|~wnnrlqlrlhsrnpjihehbegoojjsl`g`]_c\eYdcdfe^YMS[[Wcb^ZZZU[baa``heWWRQRQVZ__[Y\^Y[]WZU[^dc`YX`YXVQOEB>C>=?D?<8<72=59>?:;?JHLIKPVVUZQNRQTRP\`^^\TXTKU^Z[UUY\TSSYSQPXSZXZRQX]UVUWQ\\UOQSLGLRLRPIQLTQIRORFHOWLRKINNJQSMKTPPKRQVVQUUUVW]U\_T\\XSZTa~v~{|vy|y{srnulpokkgjnkkfogfbdgdicgginopg_]f[d\fgagd\fcZ[`_YZ__Za__dcc^bd[RWWZWcZ\YZ_X\^\^XYZ_e_eZ[[Z[WNLA@@?G=DDEMRRNPVPNYX\[XW\^]Z`b_VRV[[ZTU\WRSQOVSRQV]YYOXR^YVbWSSU_]RUSJKPRQVINLRSQNPKKKQMFIWMEOSQVLMLTQMSYYYXU[VVZYYSS[YSTO[\Y~ytys}svk|{wnwpqhk]nvloigncc`dahcnkdjgfj\`b`dec^cddak_]\[ab[ca`]X_bjid_b_Z[VZ[ZY\U^XZ\a_hWadfZeda[]W[U[ZXLGC9BE@=<7521-**+,-/,57>EEIJRPOBZUXTRaYZ\TT[]`UYYS\U]VZ[XQZYSSQPXXVNWY]P\^XZTYWVRZMSMQHIMETQQUKVOLNQTNTPRMHTTTRPLJMNQSWNY`T[TVYXZcXZaX]X[Y``}|rvxrnzu}usnxqdpggfphhbdhihkfifijobilkhd`bZfcfjeo`bc`d[aa_]X`[e]bbhdZ\[`[X]W[Ta^]]VUY\Z^\YYW___`Y\[XTWRHC>CGDA<;660-&+1+%%*/3@E@IONOOSSRU[XXZZVTY[QY]UYP_YSXRZX]VXWVUVRT[V\ZTYWa\]ZXZZ[OPWSKKQJHKOINRPRLLPONMNPOQOSQRMVOZPWWXSMUTV\\Sg_]]Uc]YW]Z]Swz}{|xyzx{s{vottvoljrnk`ejfhnbnnnrlhff_^g^V]^aijdgde_cgfbbgac\_cbe`c`]_ZWYTZ[[YZ]Y[WZaZ[][[f\d[V\aa^\a\\ULSDG??D>;=21*%&( # "&".5333,) %5=GGILLPQKKLS^XXXX\TP[\SWZYWVXSPVZ[UU^ZZZ\\WZOVZVY\_Y_W]TYNFKOMVVOVYZ\NPJMQOQUUQ^QNIGKHOIVbYY^[aZc^W\Y``Z]eeX[bcd}{}}yywvz~s~}zwvtxrsvtnqnvrvqrptxwoopffqogo_jhjlcbfeogYa`jeaigbccgdghfbggbhe`abegbefbd^``_g_f[_^aYb_MOKPHGH?74*,#    "+14?ENQTPNPVSUTOUQTT[VSYa^]UVRXNW[RTWVSMY\U\a]MZV_S]VZUZ\[`WXTVHQ[RQUSQYWXUUXSLRYTXRUOONSRP[`[ZaW^_\`Z`_d^h]``beblcñ{vu~x~sz{x}zzmru{}s{tw{swttxsvokdhfhmkghgi_khgb_bdifefigfdedblnegbgdbbhhceedho`aabf]chbhcdb][WSCIEAE;=-/&%#  !%/7>CLLKRNYMKOYYSXY]Y]\^V\_SXTSSTYSYSYXUUYV]ZTZXZY[YRW[YTXXVYPGGQXUKUQXXTWURRNUTTRWWVSOPQOW]Y[b]]dfa[[b_a_kddYU^lbp~|z}vyozz~y{wxy|u|uuvsy|}tvqv}vsroumeiojleinqliechddXhbmirchhcggkoolgbdecf`^ebdhedfcejhh\db]cg\b_UKI@H@JHA?1+# '+4:CIMHMUYRVRXLTV\]UYT]]T[Y[UQX[ZR^]ZQ\TVRZ[WVQXXWUUSVQWXYZUUUOOOUQWZ]W^YWYZSPNWPUWNOVRTNVY\Yh\_]]c_[ZZaXcia_`c_e]^~|z}v{v}~~uyys|qszyxz{y{}xsqppnrmhijkkgsjpioehfjppljkhnuoikkieaaba_\eig^ha_kgfaf_Y_`af^_YYYOOBAGA@46*)# "' 1;DFELPVPWTWVY_N\XX\_^^Z[WXUPHUQYXXQVTXWYXYYYOOMSRT]U[XVQ\ZUSQSSZ]S[V\XUTVZWOQ[STXTMZVZXQXb_d\`]^\]_][`cdhl`jje]_b||~ts{}u~}xww|yys~zyx}}{tvuy{clgjdnrdpqqxogjlg_fmopmokjjapqjdfc`dXhbdbaejeagdaldc]Z\WUabbaZ]QPMPKEF;55)&&-8>HHLFTQWU[ZW]]_YZUVUW]YWMXSTTWYTYV]]\WUWW[UUOWQ[]^[RXV[\S\TSRXZPZ[XWWQWZPTVTUSVXRV]\ZURV[Wdd]Ya^ZXZZgfekkf]kiab\]z}z}y}wu|qvv}~zrzsxzto}w|wt||wvkpmupfhcugnqyusjiiiokvnhgfcklogkjhgaieaghfdffj\m_a`cb`ZXX^fd`YWUIICHGJB?3/! !-3@EGHFNNUWTZY\VZ_\`SX[VT`PVZQPVWWY\WRUYVWSYUVOSOPT[YV[RXWR]OPLPT\S\U]_^`SZRU`ZVTUTZW[\\TXXVca[b^\Z^WYZ\Y`hjgbmg`aZasw{vzz|{}x}x~uw}ryyyxtw|yzrmlnjmstknjhimkmjsughmjnphnkipnlgnjjcrmjkebffi`bffogc_ahmdb`^V_acic_UQNIJNMACC82-#"..=7FLHOJUVTU\Y_Va_^WU^]aX]WZ^[]XUTUTX]X_\TXcVURKRPXWZ`dWRVRRQQWQTWTSR\[UURUTNSWbQVTXX^YUWWZ`W\]Ua]Y\_^Z_a[]okg^_baZ^}{w{t|{y~}}zxx|~xvttuqppwwuomuvrrokpjagfoqhpjrlggnjnginfjinjknnhjb]ibce^hlljjja`ikhY`VZabe^\cW\OOFHFHAA3/%"##$'3/5AGDIJJHVPR_VZWXd_VW`WX^^c[eY[UXZSV\^SZ[YUTYUQTOVRU\Z[Yc`SNZKROVQQTSTX\Q\URUUU\S\YP[YVYZ]VX\\_a_`cbWYVSZ`Y\hrjfei_b`~|vus}}~{yuz|}vrr~zp}yuu|vomnpkjlrquomhojjplnqkkrkjmhigdlihggjnnnjjeljfdhkgokjhghkah`fWWb]cigcc\VNOPLE;C=I56..#$&(%4669;DKHOLTSWVZV^XY\RRTUYTgadXYa[WWVTVZXV]QYTWVQWQPNRZWWV[WNVYWWSPRQXUUWOYTTZVTTWWZ][TW\U]Za^UYYXX[_ZWY`Za\dh\idgdhmjgc{~|zx|xszsszuywtx~}wwzuwptpvmtjn|yxrthiljbkkekpnzixnkjliinaekkimloioec`ag`fjofm[jlff``a``e`albaYYSPPCMH?A=8@0-11*&0.+79>EGFLQURWTK[]YY\]WZ^ZVZVWS[[_\`Y^\TW[WPTWYSPWRSNFNQVWRYXUSPQVYOKZUSY\S[WWVWYZS^X^[X^WUUX_a`bd[^d\gh\]]^_\^[\blhi_k]`e}}}|}uywyyvr{u|}wsxzqtwzxxporxuu~wzrqpqorleonnjkdlkdcjiijigknpmskghlhffgloknbjqmkghbZ]aa_hafa[\OSLOLHL?HDB599?5.559=FBHJHMNSQSSPW[]TWZQUYKYRQV[PS[fWVTVPSO^Y][XYZXV[^VSP[TSYRVQMQMIOGURPTWU\[SWYW^YX`[_WYYSWY]]Yb]^Y\TbY]bbdd^\`eha^ha]`da~z~~wvuxwu}{|xv|wszwzwryrjru}qrilkgik`nklmigsnpdclllfkmtfipoiliegdpkrpselklegf[]ce[deca^[Z]RHULLFFDJLCL;@=;868>?>?LLHRYT\]VcXTYU_ZXPTVSTRW[]^X[ZaTX][TXWZYT[X\YSVQRXSQTVR[SPMNQRPQUXYPV[aWW\ZY\T[_]STM[YXWVZYU[_^b]Z`bl_a\a^adcih^cbd}~yyyz|}{z}{yx~~xusxu}uphnsmphtgipqmqnvqnskhksigdlghouomflqjgglmliicgigdgdgbigggfckdhYTT]PTTNFJKMKILEDC<9?EQJMQLRPVYYX[YYZR[[a[ZRRSTRYSVOXXdWWVWWTPZU]Z]c]_SVSSSUTNOTZQNOOQXPNLXV`YYX\WXb[Ya_[^RURMU]\R[\[^[aec_cdcfdbf]Zcif_^db_c{}s|~z~~v|v~wxvzqtxtkomqtnsmmkhqjjrtkipdigvmkgfkfpntrm``onflgjmfgcgefhneofhdcejd`[aX]RNPRQLKNWMMUNMFEO@EHKDIPJY\W^_Z]X\`YY\Y\RZTSQNVZRWPUT`_]__XVTUY_XV^[[UWVZZWURQUUNM\NLOSPQQVVWX_YXV]W\XX`]YWUTT]Z[\d\^\XeXae_aakbaejdg`bfjc~}~~{xxxxxwrttlktvv_gngukyvnqhofmljheijmeprrhemf`hidgbgicgd^bncd__jbc]bacc]_TUOXLWQNXRTJTOOOGJOMJUVTQ\`_Yb]^[[\ZWXWX`ZVPZVXNS[RM\]d__]_SVRV^SZ]WVYYZZZGTXRUYLMMSKMSPQZLWPT]]_`hSW`[[\YXWS[Q[`c[Xa]`fa_ad`b_a`_`bccceY`}zqw~zvyyqwsksrnkmimpjmklmopppnlmjhjkojisohfffjole^iihfdeklhcmbcblce_edbh[]SVNSYPKWQWNLIHOKQPUTKPTRXT]`c`\SY\_R[S[[YZ[LSSPMMRXWWm`b_XN\USUV]ZYYQZURSZV[ZXXUTSVOSUUZPSOY\dTWU[X[[WZa^W\\WSYeae\dcXfjbbU[dc^nga`aedl`gvy||x}~uxvpnkjhmonulidsqejigckkhdhktmimfpngpjiagi]fekfkoakka`hedahcW\_cd`VX^YXURQURVRLOOKR\RWQTW^VXe]]a\YZQWYTTba`U`[]RUUXSSWcU^caZVbYQYX\R_QWY_bZUSUNTRRHOQLRKFLRTTSPSbXYNQ[[YYU^XXV`[\\aZ\_d_ea^bd\Z[[]cc\ae_dac}|~~{usy|{zuwkojnrqorndjppupmukjnigkltfgmmoijpipjigehsbpnjjbffbj__bdaa\^bae^Z]W[W[ULQUUQRMNSPTTY`\UWY`WZ[ZXW\_TXTXUWWZXUSYS[V[TP[b\Z_a_WTY^]S]\WVZXY[XURTXRVPQRQSTQSROTWT\XSYVTW[[Y^`XVO[ZX_ebWcdecdfcbZ[WgaeceahbibgƳwyvxpyzwn{twtledibnmlontnmkokksokjjgportllrlnonkngmbgkolmjphgacfcdfage`]aa`_]f_ZXYRXRNTSSSKTS^_W[]]TVU[W]_`eZ\Z[WQTXTY^[_YXTN\TY]Z\]\WYZXTYZ^Z_YXP\S[YTOSPJNSROKNPVTQX[OSTS^XWY_SUSTQTZ[\W[SURV_ababb`d__^c`chddealdf~|xzqosnrmms|qwzqhhdjgpkoqopulflinoknnhgdpmoqvlnutprqkdgklklamhc_\hh^\^[\__b_eh^W_]\TZVPQTNORMTXR]Y[X[Q\YZQ]ZZRXZZSRMN^SY]bYUS_\XTT_]`ae`U[\RTUZV\YVXTQ[ZS\SLVNOGQP[XONOTTRVRZWXSS`TUZPYXXb]b[OVY][[Xc_`b_dc\c[[d`gdafffqqcb_d`acfikuutgj`g[cgproohjpqqjgkvgodgdoqrzvmivhmtglkkpksnsi`fibc`g_gha]aXkdb_eac[ZVUSUSURSRXXX[XZZQXZTVX`U^`^Y[][SX\Z]]_^XTTVXWYVbX_aaTV^TV\[TVYUVLRXSSUJIPNOVPNQJIKLWRUVTZUYOWWX\ZU[^_Y^ZWWQ[X`]YWaZ]gdda`c[bcdkf`hl{lg`bRRNUJQZZennnjkccbhmgtoooqplilonkbbdkpxmmsornmhsmlqppinpih_hcd_\a_bZ_d][_ece\fbXZUV^UXOSS[PaW\XZZW\YU[ZWV^Z\Y`WZZO[QY`[]]SdXTR^Y]Z_a^^VUUU[SWYUUNOSUTPMQLNOLPVPQTWSNVZRZXWS]TZYR^UZSZYSTWa\XcWR`Y]]ZSWY^c\^[`b]ijdecmt^]XNNDJ=DDKR[fkluugfhdnmmwqkmmknqkvnifbgmputrooimuqwrhssglifklhgb^cb`aZ\agaemeadg``UXWWY^_ZUVX[VYSY\YU`UXZ]`^[YX[V[WURWY]\]ZdX^ZV^VT\_bWYXVUUSV`VU[ROPQROQEQMJIKWXYTRPPLMZQTV\SPUP\UTTPW[b^Wdc\]\ZZ]XZY^]aXba`[[[fgghih}wqdSOIE@786::=CGV_eemjdliplhiqkifehjsnmorihfjtlmyfjgnmjjirkllcllcbef_lcd]Y]]`Yagbegc\e[`ZYa\Y^W^a\WUUZTVWWaa_WVa^[[UWZTXSUXO^SZc]c\[`Z[X\ZSMWVZX]VWQSRQQSVRWTLKFRNSGVRLXQHOUPOU\ZVZaT[[[OVQ^V[_\]a]]``ZbfVccY\W\^ZY[a`ehdevl]VMFA8=330+56?BKV`bnidfcjehgkfdfbfnktjfdiegmpttqhemrwjmvqtsfmfqjhcag^\h^_adlkqoa_ggedb_^cUf\dWRb`[QUYYUYV]X^[X[Y[[\`ZV[SQX[]`b^Y\]\TVXZ]aQUVX]YZ]\SWQURXRNTHMPLKNMKKJKJRONPRZ[[a]XZUROUUYb_TUZZg_bWebV][a_`_^[c_cdbaeflb^}t]OFFG120-,+-,,24BEQXlhfngfdidgdh]`dlmpnmjgmiprnhlfpmnruvpvrsnmrlmilf_hgd_aa^jdbje`_aeceb\]]^W`Z`XcYSRSUVVY]\W[ZZcYUaVUV[SZWU_Waec^[][_Q[UT[OSTTWUYZZ[XXQRYRVPLLLEDJHNNHLITRNMNTY\NU]WPWYZXYYaXY\fe[b_[Ybe^ibc`b`gbhcbijd[dzhZEC:;6983'('(*.,7FP^[lmljgdhkdh_Zafemovwpndkoqnsinmkjgmkqnupjcfjndifdgifcdidakli`[`^b`^[]aa]ZR\VWW\Y\WTU\]_V^__^[XUZ\W\Z\YZ^cbf\__Y_Y`[c\ZWZUYVUVOVXUZRRJSRLRGILUIQNJJRQUSKIQPVYbXX`YVYRSRc[][YW`cdWXe\Y\d\`]]V\XY]]cafehawjUK==091*(!"( ",25CP]elmejohae[adc]kmnqklqknoqtungjhusotstslqsijjfllgcehcfgfkg`k\XZ[bgad^facZYZcY]ZZYU\\]Z]ZZYT]XRX\a^]Y^\_P]Zcgg^_T]`X[Z]ZMOUSPQUZ[VOX[UHOMPOIJNJJPPIMLKNNIJMQZ\Z[_UOONR]]_\_dac][]a_\bbp`ma]c[]gX^`fqakcteKF9:4/#0'&#%($-=GN]nmoldghkgh`a^`akkjtnkkpgjokilikmnulrnpuijmegfeig`baccefcjh`a^ce\gjgbZ_^]Yab_d\cVU]]VUV\]TVYS]\[b^]`\Z^Ya`aV]aaXYXY_UXUQRNRX_W[^XPVTRFGHJOMOMSNKRQOTWNQKIOURZVW\VVXXNab]aXXaZ^\UY[acgcfhc]][a_d`]hcl[eucJ?53/+)*!# !!(4:CRkprmaifiggin_ahfnqwhpsgljbjxtknmmkoqurjnrfhhcijgg_edjhhljjj[gah^deai_a[^[[_[]\YU__Ta]]XYV^ZPZ[X]W^g^^__^T\_Z]]P\Xca[OQPUQTX\YVRYURTNIGNIHJLGKHGKM\SKEPKOGPV_Z_[RMRP^Zc]_]`^gU\c^]Y^caaf_g\Y`Z^eYbiecnügQL<443,#'" !$&/#"=B[ksqzmjiqhichj_cgrmtmmmlhblitvlottpnmqmjnbedeicb_b[cbheggj^ed`]bce_b^aW^SW_\ae^V]Xc`\\\Yd`SW[X`[dddgbZX`\[_WZYVVVYZWV[QUUZZZZSUYYUPUMQJOJGHKOMJHMOSPUYXMUNMOV^aXYZV^UZXZY\WS^[`]ZeW`_aggfe`_ad`c^`_e`k¸ylRK33652&(%% &'$+-5ETcmjheahkf^_gji\hiligmzihjpupkplqrrrugllqphihjglk]ceb^lbikafXa\Y^cc[f`YdZ]\[]Z\[X^VXa\bY`][bSXYZYacd]^\][ZZ]^Y]WWUZY\[PXXQWWVRTTUPSJWMULGDFMDOEHKNNLVMTOUSQTSX[UX]UUVYT\`a]bcYa\``]adaacd[_`eba`]fedc`ĸĻx}znRK;5/++"!'"%(/7I\nifhjg]nnqcefbfjfnpsptrnkikqpjlurosuhllmqf^_acb`_a`_kcegfab`h^bYbXQZ_^^\Z`d[bXU\\]^a^e__XS]Zb[a[_W]\Ybe\\Y]_Za^cXY\VYXYVYUWW\_QUYSDNFKNPQNKJQGKSHJPURTTQXQRQ^UQQUU^[[ZZVU\[X_``e_][^[[\bdac_YYc`e_dd]{wgbN>710/..(!"!#'$(-7AWbioeddljgegikhbokamolqlofpqsqjvhrqrheahki`abfdc]f_`^ffehhc\`Z[_ai]^`[\^W\ZZY^^Z[WU^aZ`b_b^Z_UU]V]__WZW]_U\ZddZXQW_\XT``QXUSZ][W]USRPGQQNIMOTNKKMSTROOUYXNTWOT[XWVWVSV\UT[cTW]_`]_Z^Z^abW_b^_[^][Ubg[`ļ~~kZH;:--),'!&""!#)36@YRZlmehbc`cjbjbeadlfnpxporyuutliowrqqhljjicc[ekjcffecgfhfi^abdi^^aZ`d^^Z[e[^Xc_]]g]b`Zf_c^_cZWY_^`__XYZ^Y`[\fig`c[^Z\UTPVWWSSWaVWV[QQOOOPNLQEFKQLKSMYTQYVVTSW[ZYWWOVWUU_ZV_QZY^bYZ\^[^^_e^ce_b]UX]Y`^ac|oeYC:30+/) "*"(#*2=JKZaoaehba_eccjcdmjmnmlmkkmntstporqonhltlkhcgidk^l\dcehdbkn]]`ka`_`e^\X\XVO[X\W]_ab\`h\cZadVZY_[\_bZZY[[_Ub\[][[[baXXWXbYZ\UTWRYS_SQVRSLGSMNRGLQLIZPUVUQSXZ]VZZQOW[UVWW\_Z^b_WZZX\d\aYZ[]fgidf]b[\aZa^\\ueXJA5,*,%&1(##$%,4BPX^fgd`eji]^[fihfdieinibdmjq}tungnjglhhmrijgbfd]f`da^^bfafecc`h_aiaed[bVaaa__\i`^a_d_hVV`^eX\\[[Z`^_Y[_XZ`^]^]^[_dX\[YR\^YZ\XX]Z[VSOVTJRNVUNPLONKWS]RUTVS\ZWWT^\VXUYT[X]aXcc_dcYZYY\ab_f[a`g^]W^fR_\V^Te{hVP<5/+(#&!1,!-/7;I[d]`didrdd``iccdfliieig`gooqogdrnpmmroqhllggopgfehid]ccd_cdccgbb_]`b]_Y^Z\b_UWV\dY_[dY]d^_^^_WXYUT]WX^Z[VZZZ_\Z`^ge[\a[R\[[YXYW^XXVYRRKMQUSQXHPWTTU^UTQOS\[]YX\UY\U\P[Va\]d^`T\WZ^]V_^_[XZcdee_e[QYW[\[`uk^OD97-+).,)#/267EVYc^deanmhgb\adgkgjnjmkabaixxmkimflnusnjrotmkpfhi``a_dehhaa]`cf\Z]XY_`cWd\_bTZd``^`bc]_\YZ\Z]Z^[SZVXSZ`W`YYa]]Weh`bf_^V^X^ZX[\^\WZ[US\T\UXVITVOMSSW\]\PX[XQ\\R[^Y_[XU\abbX^_``cb`\UXZ]b^c^ead]bcbXZYZ][]e||qhZLB@3%//,3739@IKV^keh`igj`drhidjilbkph`ddgenhmppninmnsqfeukhlonnmkllqeehb^\Vc`dee_^aaib\]Yh\`[^[ae`^[d]e]ic_eb]WYQTU][\[YWbXU\bYa_b[WW]VUXbU_\W]aTYXUTPP\RaRUUV`ZVX^a`RPU\VVYW\WSXXRUWW\ca\\kca\a\_WZebS`]adbab`X]dY[Y^a]wrccS??>56<2:=EHSY^ff^aibejflcaehijitkggnmbikemgoljehiqmooiukmolkfchjhgbbf^eeb`ffk_\`_cdcbd\aYa[ae[ddX[][_^^aZYYUPWY\V[ZXXX[Y\Yc_^Z\YdbUUXYYTXVaf]`[SROOXVSQTUNRRS\WW[]X[YWU[\]WSZWTVUW`Xdd`_]``_^_[Y_[^_[^dedb\\XbYXe[`dbc{ztlc\RKHC8:FCPNYR_]`fie``hejjj^bjkmnmslbhidfjgmvskiiijtkrlglfgh_hekdghcbbmahhdaad`bZfc^Z[_][`c]aYYb^bXXY`[_d]_]\_VWUWU[[XVb]`[_e^Y\[_b_^SXZUPXZa]\bdXWUTWTZXZV[W_ZZRZX`Xa_[\WYUVWU\Y[ZY]X`beW_bYXZYa\^Y\^_]]\]^Z`\X^YYZ_b`j}{|tvupdg[UJZOQS\baffc^gbiifhadgfaijbohlplpijalhqjooejkmnmojjkgqkgmhjo`Zbglelhheda`YU\`^V\Z`^b_d`dZa[PaU_\SV]b[\WZZT_VW]YV[[ZXZ^^[`_ajd__W^V[^YYX]UZ`]][XLSVSUUSUUVQOS^VXRZTVXaXXVZOSVRXUTT`]g^^][[a]W\]Y[`^[cbc_h\_W^^YZd_dkc}yt{w{}|zxxpka\__a\gk`igbf^eiddcmgfdlntlqhtrqjekhhojnnkkirn_lfmbmegakiicehdlijbs`ggXZcY`VTYYYWYWY[`bY_[Y\YW_]abaoc_`\_X`VYY[]O[][Y^aa\^be[\_^\`_VYZTac`UZ\[WSQVXTXTQQOUQZ[[[YZZZX^[QST]Z\^\TXO]`d\a^_]^YY\VaZU[W_\`da]`XZZV^[`^d~~~~~}uyspqmhmupsyoedcae_idjfgejpogphpklfjsehidklqujgtkigekimmemjidkhcijfnjki_`^bee__^`\b^[U\a`]`bUcWZZh\b]_d^ad]_`_X[TYSZ\[]Z__j_bc]]]\P]]fYX\Z[a`\X\UZYW\MVVVVNPTSX[TRTRVXSVYWV\\ZWWRQTWYf\ci]^YX^W`[U__`\_\W[YZXTVS]e`[a\z~}z}{}yyxosozljcdgfjpfidgeeoonpoqjoljetnnmsqpoojjfklkiaoioehme`fd^Z^cbbhlhZf^a\ac^c\[eWX[ZXa][^\X_VZWea`jcda]^a\\TQWSU^^Zb^\\`a[aaa^_`_ZdbXcac_^_^^]SP\ZTS\YYTLNQ[Y\ZW[TWYXZ^Y[]X`dY]W^`^ideZb^bZa]\b^XhY[c`Y_`WWWZe_ghfx}|z}r|rxhncg`^gnkjjdigirjclopqiloinjjebmijcmqtnmikgkegeojp_cYegibe_djg_^agc`Wc[ZZTX\XY]aa[\_Y]_[b\ZcaW]`]ef`W_\W[Z`]Y]Ubc]da]`[S[[cX^\dZ][_\]VSZ`XRJXS[_[RNUSPYYQRSVTYROSS[Q]V\[^\e^cda_^^dec``^_gZa`a`]\`]Y]\c^]dg^²|vwmopcf`cciqik`e_`hnlmnioefmyrinkghijlrikkvsqoiejglidfgcakhjid_`mc`gehZb_]ScTZQV\_YS^ZX[`UY]]g\`b\`h\b\\YYYVd^`Z^^`\]Vea`eXb_a``[`b_\a[UT[d]UPTTPOUYWTQUSQR\UWYVUPYZ\Wa`dc\[ZV^e]d^b\[d]]fbeU_`]\\ZZd_R]ZW`faec_{{wssqmgnba`ghh_c^X\beinpjdmpqjmjnkkhjelkkgilnonhjjkjkfjhifecfeginnf`h]\`b^]a_^^]WT\_`[_Y_\_X\Y^a_`]Zb^\d_Y_XYZV[]]Yd]Z\[`]bb[[aZ^YZZ]\[b[ZR^T]^UUUYZV]Y`[WRSQWTYZ\XU[^UXcad_^]\[YYZ\YZ[e^abg_c_b\cbaUce_]m]_Wcbhfb|yvpnqrsj_]ifrmiaib_[`fgqhqjdntltlmnjokmolphokqhijeegchafkhhcnggnief_]b\g[Yb[XYXYTS]WZVb]W][`\[b[Wb]X``[ffc^ZY[_^gZ`\WT]Y^W__\_]^_aV]^WZT^\Y^YYVSSRYSZ\^YX\URTZTTZQVS]YX\\^aZ^X_W^a\eic[Xgbfajbia`fXaYf[ee]``hg_aad}|w|urnqjjnf]^kmdeX]]cacmlkglilltqpketltqhnofnplognnbhffdcgfffcbcfqhmcg`e_a[aZfcfdYXZ]\^\[^SVX[X^X_hca^][X`aZRXZZ`b`\__`aUaY^XU_`ZXdeZZX[]XY]WZVUVW[VWaWWZXY`Z\[U\]LYYZ\\VZ]_b]Y]a``eb_]e___ahckioh]ac`_cci^^]]jfkbh{}{y||wrmmgcffcgkjcd_fba`_ca`ggelspledkplrqvqliimlplkqgaflrfdjfqfbgikdbg_edY[c^^bdb\bWTVcf[__\c^\bYa`[U^dc]e_g^ZX`d`c^ZccV]]]ZV\^\]`UWTYX[]^]]V_^XZUVSXYZ^XYY\ZZW_S``QRa[Z][`_Y\YZ_c]ebpecjh`gkcdi`ffba_Yd[[_bZ`bahbh~y{yutkypr|jpqjfmhhei]bfbiihgrpslosjlgowutqnunscnokjadafgvjmk^d`gehlg`_a_hgac`]Y^V^[W^YZ^_^[U_Y]\W_Y^^\cb]Z_^V\\U^b`^X]bfa^][Y__ZZWWQZ]^_Xd\TVP[`QZ[UW\ZTYXW`\\\]Z_`V\SYXZbd^\`Zclhih]Z]`hjljdelg`kgeW^bWZ\_``abad_|y{z~}zvrlqjuninhomling\gcfkf_ghjnmelhstsptuwqjverjfebhcp^nedbbfcigcc_c\bSa^ea[d\_[dY]_d`d__Zeaa^d^b[Z`a\[[Z]Y`^\c_hdabadWZ]`[fa^^`]V[]fa\^XOXX^^W[WT]W\]QWZP]Xba_]]VVdU]ba\YW\\[\cje[^]Ycgiidgrifb_a`]aae\`^]``Y[\~}oy{yrvxx}urvp}z{vpsnhhnpin\hfjkefeiqblabhqpxuslijiokgb`bf\dcijij`^abgg_Z]ececf^a^gZ^aY__ad]`^]_`YWZV^Z`_l\UV^Z\XXYaab^`^ddY^ZW]\_^\[b[XWZb^e`_[VZWaU\[aaTWW[Y[YQRWTV_aZX_YQ[[[]\WW]Y]]hdgd]Zeedlmcd_bddc^^cdc_bY\V][XYvy}y}ztxywvy}wxy{wzyximmimvulb`f_j`ediimfmekmrrtnekhlmopkihhfbiijjmebgefbW^]_]_fXV[WbdXcY\Y`ib\acX_\\_]g`\ebY\X`YYXZ__V]\]`bac`^`XY`e\XU]OZV[]V\[VXY[X[[]XTS\Z[TWTUNTUVX]_[TZXZR[\`[XW^Xcb_YXW\ee`cbdag_adZh_^bhe\_[]b_V^üô~y|yxzptyw~~{xtzrnojorli`cbdbknfhlholkooptlkbkikiisgcfe^cbekmlhjigh[_af\c\ga_Z]ba`b`cZg``Z`b`]`ZedZc^b[^WWV\ZUVTbc^_Z_\cd^\]`U\WYUUTVZ[Xdb^[ZPWU`Y[^eYYYYV[WK[RLQVYZZVUOUVYY^ZTaa^_^k]Web]_cee_bcacdad`_\iegZYUVX``^|||z|wzv~~}|}stqwrnmgjrk_kihoseoimlkiegkokhdgbofoeh^cadgegc_^ffilh_gcebiahh\`[YZ``geed^ZX`YVRWW^bchba\Z\[X^VZ\Y][Y[aa^eZ__b^^][aaVWXNU^^Za^ZXU[_UXT[\PRXRXXSWXTLOXW\WZ]RPTO]TbYYVVYdZ^\Zbb``c_fiZ`bYY]`_cekbbW]b\cY}~}yxz}~{~ywwwsvkfilhligffpmspmmnwilohnplbihmaog`ba_]e`gae`fbg`deZ`afegcaca^T_Ze^__a__TZ\QY]\^\acXaYUXXa[\_^XZZ[\`a_ec_ZaSO\`be_XZTSZ]Z]_ZY[YVY]\SWVVRU[XSQUJPLRPUWY_[USOXU^Z\a\VOT\ZZX_bdY`dajd\Z^ecgdkbgce\a^dafyw||omliflmohhtpjonimfpmlfkdib_jhagjmhee]`ac_aedodb]c_\a`bUb_]bf[bf_`_ih]^e\\^W]X[c[cZZZZ[\]]^d`]Y\`^[\\g__WbVYY_]_\RWU\ZX_X^]``]_eb`ZUY]XRUW]XSOJSSVQ]VYS[TSOKSS^a]TWY]eUU]W]V]^`X_h[]b`d^c_d`cYa\W`]a|~zykqofggdeefifjjnosreidcjdgic``ahhe`fZZZ\a[b]d_^[h\`b_`]dafce`bigea^a\\aVd[[Z\\URb`aWWY__`aZ]^`UY_k^``Z`]S[^RX\c^][aPU`[gYYX\a`aaX_ZQTZYZY]Z[OSVQQNQTNVQZUOTPPYUYZY\WLPQW\TRS]ZW_^^\c_Z^[Ya^]Zcc_VY[}uothjbcbbcjjqkwqiliekghkiee``bca[bZWXYW`ea^ec_i_W^bbgZacf]hccfafdc^aYZ[[]]TUSXY^^YRXY]]^T`^Y]d^aaV[ZYVWP[YU\\\eb\Y]WYUX_Y\[c^_ZWXX\ZSUX^]Z\ZMVZWVUUNWXSSNQNSVQ[_WTPQT[TTW_WZZ]X]`ecYaa\dQagbbb_`aaywxpf^`^cghkqmospjlcicaheiif^U_\XWYTT\`dfd`e`d\Z]\^`\e_`]ead\^]`cca^Z]_YSX[ZX^U[_XaWUY\YYe[[_^Y`]TT^WS]TSW[[W[`STWSYa^\XY_Zi]aZXUUQXXUX[`bZTTSOSY]V]XTWTSOM\USSOSVXSZOXSPX]Xf``\cZbW^^`]`\```c`]bW~uqrjbfeb_knfnkl`nrhieefo``bQUYVSGPLGOTWZg``k[b_\^gcd_a_]bgbcWX][ZbYf^ae^^XXXXa]^]]U`b]^^Z[U^`Z[X_W^QU_USZUW]VUVVUSSR\^YWd_]\a]\YT^TWOTVbZXSP]XWSWORPMRTWLOWXLVPSOURRSSZZVV_VX_\Zfb^_aTaZ]af_^_b\Z|wxske[haifklpojrmofhhbcefVNNIJD@?9/-'*"*% )-..8WU[_jjh`]fcgebghfdcc[[|rvy|u|y~~|y}}}ux~w|msojnrtvyrsmkmqleciieoimogbSND91'&#*2AGSZY]VWfdYa]b]d^bTc]\fi^ccc`d^VS[X`^bdf\ba`\[X`d\fXc`^Y[XSMMULWPNORPSVW[X^[[Z\\[WRTWeU_]`c]cc\XTSPUQQMPNLRJNSPQQRVRTMSJMLKNIKQP[`ejdg]b`Zc]acZg]chbuz{v}yw~|}~y}}z}~}}z}{qxgsqeegeYejgqvkvrqplslhpfkffkghb\QM>7,'&59LSUYbb`Xb][^^[gehad``fdbhj_dY[TdZVhd_f_ea\f^_Xg^]^``[YYQ\VQTMXJWQQSRUUPS\\]\^XVYZUZYWTQUTeec]fZ^\QPOTWUOOKUNYSMSJNXZYRNNNQSORLXXamocm`ibbehgfjd_]bawy~wyvz~||~|~|~~~~yy~}}yq|vjlj\^]ZWUWQY^drpyvkvqikjfi\igigfg^ZF;/+!#!" %//>JMWSWb_V^\aW[ebdb]\]Zic`eiY[X^cdYa`^bZh_c`_abdc[c[]d]^YWSTSPPZSNPILTUQTSJZTaZ`[a]V_W[]]`PZba^`bVZU]W][V\TUUNRUSXPXQVUOQOKNXRRTTX^bkeeb[fg_d`Y_ZZegb{w||w{~}}|}}{~x}|y~xw||||uwnrjcd]PUSNOGIDEOZanlntqsiijfpcf\gd_cXVN@1%("/0>KTXVZY^_^]_aa_iicdcabgeaoe\Y\WZ_Y_e_likc`[YcW^ecbaYV[Zb[ZWYS]VXKSSUYTRQZY[Y[`]eY]^aUY\RVWZcaciaf]XRWVWZ_YRMRVPUWQSSVZSYZU]UTMYZ_chma`]]`kcnk`aX_a`a|uus~z|{}~~~}y|{y~{|{{yyw~~utrtb`VKLFD?@<:=>?QTa\gmmqehnfkg]hfjmg^ZXF910#'27BPVU]Uae^_YeeXYW\e`dcfhfbgle`WW]]W]]]ebjbm^`^e^`cia^aWY]M`\ZVZYW^TNVS[WMNWVafdcb`\da]WYZS[W^dh`a][[X]R^YY_TZXXYUZ__YZWTZUWbVRY`Xdd_`kdebgfdb[b\UX^[m{y}wzx}~wz~|v}zyw|}wv||~{x}{z{y|}~|}}y}oobYTEC>;8730446BBR[dkjrknkfgfa]e[_]b`VPB-+$&,@JPYVZUW_YbX]VbS^`ddcejhkplda_[[V``Ye`l`hhgZ]d][^hf\h^`ccU\^^\aZZZ[UVOUUZT[[Ybh^Y_[XaZ^Y^`Z^Ubclae_]^YU^Xa\a[\[RXYZXUURVXW\`X][_Wbbeleaeahidgd^^[X\bY~}~|yzx}z{y|{}~}w~{q}z~uz|~}yy}ytu{|plcRRGG=;41640422:@NW[ertrioejhb\^gaZb]WP@A7+* %+,?BJTT^YS_[[`kcZb^P`^^jf`giojj`_]VXbV`b_c^g_gac_]c]d]a_d\\Z\\Z_a\^_QZZ]WacZZZ\ceX^]^YS`]]ZXVXUUb`efbbc^`_[[]T__^[ZWX_YUY^^VYZZS^bWW_aahbeielecdcc^kXZbZ~}}s}|~{}x~vuzy~}ut}mtxxyzzx{vxyz~{ylsmyx~||yxvz{{{~z~~{~{~vt|tvtvfTFG?;-24,10(*217ARXlopmronei^\b]bX\b\QQC68.!"$'""('.7@AFUUQTSa\_aahgb]h`\dgje`flsfb[[a`Zeb^^`eib^X]_\bichaZca\_caeab`hc_[YWXWe]^a^bgZZV[_TZ_XY\__[`YcagZaZ\VUV\__aa[_]WYYY][WUUUNVXX\]Y[_aif_fcajc]ef^`T]\^{{x~{vxzyvv~wswwzxy{{{~s{|u{wy|zyv|s{||~y|tyy{}}||{twzsv|yyz||u~}~svywtsyrumaSG><4.0.-,*)-,/7?P[ghjnphhn`aehhbb^Y\ZXIF76,($+*)%065;CHOW\XZZb][Uab^dd]ecdddljbhfhk`e\b]`jfirbib\ZaZ^[[e_ibc]aZ_^^\i`abc``be^^e][_fbccd\[V`\f\_dbc_\Z[e_gb\d^_`S\`_]ae]TWY\^W[][\TWX]abbdabnfcg_akaeichY[dd_}}~z{z|}}ytvz~{yw{{vy~ztu}}x{{x|}rrvy~||}|{~vu{~}xvvt}ryu{vquukv{tmwwnw{xyyw}zw~wzwtq{tibXI=8-.()*,)+%+/,47GRYjllqmiegagll`_[b\X]aUNE?E=:@@CA>IIPOYO^YTVZ[XXZ]ibimeigngbglfdejfd\`effdf``^d^\[_[^Z\i\dYda\^becZ][cafb\c\h_cjdaXg`_bX_Y]X^cfdd`]gafa_becXXZUaZa_`_VZ[`[ZXYSVXZ^aX_cab`kgdhgafcejilg__`bezxxuyx|}yvtyvz~z||}qu|zwzy}tzxry{{}~wqusxu}x~}zyx}vxrzxxsvuoorzztnptionkmpiqlnkhlmpl~t|t}}~{}v|{|xswo_\K@<8-)#.%++'&).57DXbempn]hfb_`nnjea`Vb`^RLJFFD@GFDLHLK]UXY^[[\]_\Y\ahighcfh\`^eflh^e^e`d[jlfehijc^\]`^Y[Zib\]]^]]e^daU`a`]Zg\Tacf`]]_lbf]^]cg^^`^b\d]b_dcb[[cc[eWWd^b``e]Z]a_Y`\YXY[f``eb^iebeggi__``cX`eeag^~stuorstvxsqtuvy|}{zouvy|~{~t}x}~|z{x{}pusv{v~wvzu}|}}|wsqsz~~pwwnszxhel^hdd`fkiehhmqrwwyt~}uzz}z{z{yldSB802(&&&(/)"$()12CO`dfnjlfhisjokde]bOT`^ZWWKNXLKMOPRXZ\X]_]]W\^gegf_eh_bifmiefahffgee_iebipeed\c`^_]]_`_`Zcd^^Z[`_ja`\\c^b^ge]^aibZjaca^_]_i]`did_blh]bd^dd__Y[Y]\dbZi`VY_[^\`]_eZ^biic\fbhdj_jfighc]hdehcbZ`tsusnutwolmqstvzq|rt||uwvnkz}x|y~|y{~zxssyzw{|~|ywrsqtlyyvuxtvvvrwvtmqd\ff]daYX[R^^`_Zmhljllutqy~z{|z{w{|ux}~vgdLI<,(*( " +()&-2/5DSZiirfnjdotrvim`^_`^]XY^[XYQJNPVVXXZT\_^[c`bZb[Zce]]fbgedibajdl_[bhgiggmmgfhjged_\_\_ZY]_fb\WX_ad^_dfVUgbc[ab`^^dcabak`XaZY\`^ba[YZ`]aa\b`\_`b^baeh_`[^`_lg\e[Wafbma^\cbjb``dhfhcfcgki`mlk]ppfmx{qqrqjmqmwrtputwyztkxvsr~~||}wt|}{|tyy~{{|{zwxt|spysmrtsnrzx|ticee\SVSOHMHORTVd`gejirtquwvs|~w}{vvzxm[MB;,'+$##. !"+(,0@PUcgkkjinhpmlpq`h^\ZY\WSXWR[UXS[WQZU][\^_cWb\ae]_edb_]ccedf^Z_beggahbahkih]`f^f^]bU\Xd_^^j`a]WZVWXa^^b]_X^_[]^dgd`\[^f_d`e_`ca_fbed`a^^bdj\a^[`aXf_]e`^Zcd`je`[]c]`_da`a`khfhegilkhehd`afld\owtwmtwmipqslkqrxzwu}v~rrwlv~r{|z{}{~|uzxussxvqowpnrutnow}|pnvvyohXWHMQHIBB;@HGFISV^mkpirklqlklz|~y|wxr}}yzwqeTL=40%$'!"&+)(+3ANYhlgeflqpxrsqobcgeZ_a\\`Xc[`YXW`\^aZ[SXW_]ca^X[__]WVdd`hfd^`^Yfgfcefgfiimnmmbgbg]Y\_Yij^af`Z_]`_a``a_deg_b\_^W[_fcaffjkfdd__df_ci]]]Y_^e]Ykb_Zfa`b`Zi\cWjb_\ga\g`YdWZ]d^jn`ikonmgkklibh]fcatlqupopxjogkwooxirrqwtst}}{w}v}y~yzxz~}sqjvpwourmvwkromyvxyvpe^QKGE=8=8>5296AGIOP^erupoupkrpxvz~{|zy{t|wu{sm]JD@2( !$"-*3-21?GVdmjpihmsokulwfhk`^`^[[\cY`[\\^T]fe`[^\_`ZVW\[_[W^Z^c]dfbfbbecf]ccecgcleppcjhgcfeYba[_fackmgja_dh][`^b^^a`[]`_]Yagaad`efbee````Xbdg`ma_c^XeaZb_b]cc_bb[fa_db]b`ea^cd^gcahkbdfefmnjklc_h_d\bhnqpmzylrpysszyrsvrpuxwzwyzvyr{}w}|~zy{~{wrslkkkopppsinkkzxwoleUPC;>9791/+05379CHZ]fklrkmopwkwzz|~{ut|{|tzlf\TE@.1,(&"-)+/1:>Paeojnrlsqpmxv|lgg\We_`\_ZYc^ZX\Vd\^gccW_d^aa]eac\^^h_Yda_^cb^cfea`bgjbaphhcjdl`ddZ]__chefhdegfebg_c[eaee]Za]ib\\Xaebgeaj]a\_^_T[[]ab`hm_Y^d]`aZbcd`^`Ua_b`Zcgbedd[c_`]^^cabclj`fikg_khi`cWb`pgqtsnwzspnxjqhihlfrmor{|{yx|}|xtzzy~}~}|}yyyzsnwuz|z{uskvzxytdWSE98./750$+*#-(:@AOY_inhokpmjvhsq}}xzz|{}wtyxutzm^TNA61,,6.<9=FQ]kilmpurrsw{zz|w}||vq{wuuupieXRLC=91:8>SW]cpmpeinnlfppturgbe]`[YUY]__cc[[\ddabfmhd`^`[]]\T[bhiflb^aea]gaebihebjbhbnkgmhafl_f]^`hfknlkgejfefe][edj`ac^b_e`dcbcdkekecfZ\ZX\Zb^[jgiagbaY[X\a^b]_a^YY_``eigZ]e]^gbTaeadhc]egda`]kgel\`jeajqiorklmfnprxjptimqtkpus|y~~}r~yxsuz|}tt~{vy{~}z}qtpqprwnrwwtrssuyyodcUE:-/++*)0'$#"!)->?S\Wdejgqlusp}u}~{vyntustxvrrnlb]XRQCFEEGRTQUjinssouggkhoqmrxgnhg^]__Xgd_f_dZcc_eafgibfaaba`[[W\e\`bdbgghc^h^\ggiajbhflchfkcdagjcYX\^aficknijkhhfk^gfncc]`b`d\]hd^bi]bgcc\W]_TZ[baecj]b`bbaXcb\`_^d]c`^`fZXaWX`jgcnb__``]eekg][^eepic^_cZ[epqjjltygmnqrvthikhioiwrqwszz~z|ywu|zyz}~}ztyy{{z|stoosptwvrrysrrnpwncZK79+))(!%#!'2=JT[bdjlorrvzz~|{zz|w{qxxoy{xiichg`XLPPTVS\hfjqumrpuprphqjptquohihd^_Wagb[P\ffd^ggfe`ea\^W\aaZ^[Y^`_clbgf]`a]cjhiaaff_ifojfhflagidelemjdnlnhalZd_j]cnfbd^[`^gece`fjcpf`f_gc`]_c_`b\bX]_^_dacaef`afegdb_aacbaf`ilfe[Zf`\]_lbcX^[Zchfecfc[g[gcolpjjgkglspmhtpmvfgoornxr{{xsvzkrt~xrxwp{zysv|vzps}}ouoqqu{vuwvvvtrvyrngaQ>61*,,)%")8=LS^]glmqtx}z}||{trtpsuwvnmomijaf]fbalelcomlknwxmqjhnnvuwmfjmecdbba]^`T\Z`\[a^`gbaaV[db`[\aY][a\`^ac\aaabfash`c`^ifnfeemhbhdie`sdeibibggmeffghei`fg]T`c`^accccaX`\_\bZiV^h^e[aca\ecacea]d^V``^hd`b\bVefe[b^bejfdcbcffbgedfbahcjma`c_ag`hipfphkdjqlgqspjkiilolorqztyrrrprps~w{rzzuw{yzvz~{wtlqplkknpswsoyvutwsgf^C;71%&" % !$)=DTZ^^jitz||{~lqjywrqyqwpnpusuzsoqldukptskttxuosoolnfntpdnnegfke^`heX[_Z^bddf^abe]a[`e_^^Z[\\^`[`S]_]]^]fejck`_c^dg^bfnogcmimbnnbm`da[iik]dedgisoeZfYVafdf\_accbdd_bde^gb\ejdde`ci]__heXbbcgcdd_d_`eaedf^gdigefed\ehbidaXdgajg]f`b^dY]mpoolijioiekqfjkkgiphqhpmsuxxyzkjpw~sw{xvv{ts{wvxz}qqqios~pysrstusvvrursvj`P@4+$"$#$.;JQ[`flgpx{~wtplnwnlpxtqtwyttqyslspotpswrwuwhhliiifnpnkbmncgjf\ib`a\Y`_\dc^de]]\Z`^`ce_\XWZaWe``^c]c_d]lgfdhddaacdajhldfbiabljn`_dacfihmc`bkh^[_^Z[^`_^b_ce^gbg`edq\^_bkg`ecdd`_bdfi`b_^[akj_iYb[e]fb[hhcjku\aa_fhoeogffcijeq[hcfc`mtjhqeioklikoekeicoifjkpmnwytonlyikurxyyymxvsyxzwutstsottclmstdunrusvqol`[C6/'*#$ %$@BWY`imqvv}v{|~{~}zwlnoqsqyypzskmvpy}}mtiuspnssnqqmwurehfloomijmmhbindec\]^[Y[[adgcaZZX\Z_`b`\cZaWb\[]YXc`]bca^aajej`c`begdcecdhijjhegbkebeidhkg\b]mdcifZZ^[ZZ[ada\ac^]fc_`b_koil^e`bc^fb[edc`f^acadce]YWfckhieigjcbnpfcgcdcd_ejenec`ccV_ednsisokmkiqjptvrdfojlroiocqwutwomppqtt~w}wx}tu}|q~wwuvrsryupvvotntvyxuvnk[QB1+-#'### $,>BS``eetmivr}ju}otu~|}|}yy|xru|qmptwvpspwywz{suspvzqu}wtmrinlkglsnmgjehhaccdb`b`c^bfhf_`a[\^d_`dc]][_\_^g[k^_f``aZc^`\fhima`fbde]m`dfc`kifhfef`ffhkeebca[__cbe[Y``b]\\]\cfZbb^a]cfd\bied^gg[jj_llj`eafahfgea[^accnhd`fhfgj`acchpkemjmgj^__`]efenquooolbcdfkdisjnncwmokndnnrzr{n|szoxsxyxuww~{|{zzutwxw~qpommroqx|txxytqcY?8-,&!#" #1;EMVaeheiffdjacb]lt|ys~x}yu}xorsvtvxwz~qsmq{vrsssqqmrvoluxttdhfiimesnhlmjf`ce]Zgb`\^]^_]ccY`\Tb^^_Y]\YXW\^cgjfbXb`ccgfd^blhodcjk``go`jiih`dge`baaccfhhhebjlaf_b`]dY_h[[c``_Y\YYXY_f]`eae]dfdfcghddle`jajcdikbba_bdghcfgci]kl[hlcca`cbdbcejgccYajj\civvuuqrngnnpyjpeclojcmtkcjroyspq{lwzy~{{~zywz|{r{qxzxvtuqrujsswwst~x{g]X>7,-(%"$1;GKZ\g^ZVRUVMSPRXcjk|y{y|x{{}stwq~nnw|qtxxznwqtsp~vssyx|t{rtmlgilcixjnfieai]_]`h]ZY^Sd^f_ccUYZ^VR\YNQOZP\Z\`[^Z[\_b^`Z]bhelpokkgcb`bddhilkk`nhkgdheeacaa`\abc^_\Z[_d^aa`[XX[ZZYXa]b__ncocdohbekmijffdeinadid`^]`\hnlmpkfZagheijgifchpjilf[^a\^^ecdpmrqjqjqdeorhiiklhqqrlkhjnrwutxmpwmuyrvy{us}v~rtvx{s|yy~qssnomjstw||uxndOB:-'($&"!$,4COSRPVOWSRNHD>9EBQVbqww|y{qltuy|}~{zsquptlpsqqrvs}~~~~xxrqsoftnkoflhih]ie``Xb^_[XXYd_^Zc`[YRQPHJNOJKPX[_bc^Zbg`affkhnlkhcdeia``dgmfhkgghjedgcf_jmjgbi`h_Z[m]WZ_c]b]_]`YZW^_^cg[f]bh]e\d_dbnibbgbfch^hmcf`]a\^\dlljihddjfjirjhe^fefofcbhldk]b[baqppmqvlonpmoppmoqjjqwhopsqtrowlosr|{zzz~zwzrxy}z}rrssyz~}pxrmjwkvvrwxvupdUE32.'#%"#)2:GRMTOSILE:8:?8;8@DH@?LX^]dhg^]aZgbb`kndljdjpjecY]ilfngkcifffgib`dcaad\YZ][\\Y[Z^lda]jd]``\_ea\]]`b_g_``b_hjelecfdjgoho`ae\b[chbdggfhtigbfefkkf\eZbghaaeag\d_c_^furjowttjhnipmvftrijjbhplqopuvtiqpqrvmosxx|p{ry}xxuqnsrvtywvnlnoqttvqpuvydVEG2-+!$(" $'19HSQRQPEAK>:44/.0):;Q\cvzw{u{}y|vwqoqprpyqqyztyvp{tlkjhjnfd`hi]ld`gbZ\YZ]YP_df_[XMNE>E8:;<;8=DBETZbbaVa\aj]leeienb`d]iejcediiomhhidcbha`eadcee]YXabZ[aWc`_^b[a__gdaa``bacfg_`]\_[`dgbdfduikccbfij^g`ca^^dgdbccainnoncfei`d`i^e^`_`]V\abdenpfsm{qgdfsnqplhljlbfgjlprqvlurtltns{swyrzry}}ws|nhquyzxtoqoorqdwoywxse`IC50++)#  ),;HMTVRI@?@4021/,),.16>P[gy}}yxz~x|yunnnwopy{myuxquwxojiinmplaahi``^d_U_^YXV_`[__XSJA<883,1)1*04ARMabdac[T]^]d__^ff`agcha_icijjmgeeb^_]TZfb^gfic]^[TZ]c__ddk`bgd`bbccah_ffica^`[_a_d^_djhjlqiafchhiniacaachZc__jdkelljcfnkkb_aj`bil_abcd^gonlpkoogoiiinnmlijiifhnqcsgotnmieqoptqtwwrjz{}{vtsuuhphqroqwtnnmpiorpynp^LD<80(,&)"'"'-4@DOOOTKA=81/.*)''!)/)>JXgu}u}{~~zz}vxpmrrwrz|tzoyspz{ntjtwolmjinbhc_ab]c]a\]WZO^Zck_[SC;4.20.$)'$(-09FVZb]Y]LYTbbca^\^a_hkgffjmirpwnddc`a_[bdchia\ac\WW[a]_\`eel\^caeahffmafd`be^]a[ZbXjcefedjfff_beeh___gne_fdefb]l_eefjdkkh`kcbdd^ead^]`g`fdjffhvrqvridjjeigdvldfhclesvsgikimlpvwsusr|nttwu|vuntuszpsronmqptpigmtyrtof]NC131+-)''*(-+79CPOaXOI<5//-.(& )(,/>P^n|}}v{xwzuvpururpp}}}xnqqmpvutsuqjkpbqkjclg_a\_`YZYZY[bXY^O>982))*-!$&!%'/=DPW]a[\NXYWUY]ZXUbcjahkpgidpfhhpdchS_b_dhbZcda]^Y``a_]aecc`bggbefghlnii]^cgba\fa^fbeadpkijgddgdeedsofefcgibd]ddchh_ejpmhdic\ab^_cikbacejlljgppsspiqkehfqkeqfmglldssobuglj_lkkgoospmsrtqtwpxwsprrjwqsvqsomrlpgsjtrod^SL;<28,5(+3119=@OTZeZRBG334(#&!"!%+0=L_qyz{~v{|zyy{|sqqjoprxu{yrolriuqrphjonljhkgifghj_e`Z]YYSZUYSOG@/)&%$$!#"#")(8FPIYXVXXSZ_`]\`e^dj__fsmgljmntcdac`Wheg_c`[[ca_ab[[aY`\^aej[acccefgjeciqgfhheaV____cfiehljee^idkja]niihc_e`ldiibhidhmefigd[Yb_[_`bfgjhehegcbljrkmjbcdichkqrojkhvtniliidqmomkrsssrmoaimlpmvruyrmsksrqrqvqhlh]dkopmi`RNLE6972518A9?=KMX^iYSA;761.(# # '3@GYf~y~~|x|zz~}~zzy||u}zw}suv}u||{pnxznmtpmklujibffgdi_f]^\c^[VVQPSND95.(#$"" )0BGNUcUVWPTZX\TTXa`iafillkgpomkee_a]bigdfaafbmZ\``_`^]a[\_ecfga]^cha`_fcga_jdblcd^]\fcg\cefa_hgifemgjpkiijceefgddchfcaiaQZecY^b`edYd`acepnnjfioohmfmfqlkijbgpijoorloqblfkkonqllhljbeZe]fakslmxqrijmqvpoppuspiflflllh^VXSK=@9=@@>AEGMW]ag\XH<9..5+*"$'(6FWlp}{xw}t{u|zzyw|v{wtnt}vyu|{zrovwrplnnnphmcgjhh^kgfbg_[VXYTIFIA9-%''"%))5==NUUQTPSSSGUSU[`i_edokblciciocajm]be^ajdmeXfck^adaaaZQ\bhdfgee]adc_]gfe^pcccgd^adb_hghg`deeehdeg^qhthghhfiibabfccefc`gc`\]]gccecgbgfggnehjmofgoobfnpihj`eootpughjmikifknktpg][]UZNRT_\elionruoqjrpupqhhhgo\belpmbc\YVRNGJJJOLLGRWXZgh]^L<540,+( (+9AXnlu|}uqutqw{wwptxnm~~~uw{tvv{{z~{vvtxstrxvmrhjmoddahn`b\a`ib[ZQQHJF823,)%&"01>KQTQPQQOUQLRL\_^fcfciofglegfhla``\d``djdhfbaddbaZdaXc]ecmdfkb`^e`edda`bj`cffdbd^^cfc_bcc^hmelqffcbimmfeohd]dbigi`^bcf__cbcVb_ae\`\dcjlkfbnkkiquplnhsflgmyntttljkdfmgpoiqjorh_YKMHEGOJRZabddmqnejplsurmkklhd`hqkmflb]`Z\VVSXURNW_[`if^^RC<6--/*'"$'17AWfmtzuwpyx}svsjuyuz|qwsmvvwyuwywxyz{}ryvxrmwkderlfinkhge__fc^VVVXFC80/+&'!&.3AJYQPSXQSNNRHTWVbcdngggfbdfhi]aaZh`fd^^dg`\WY_a^][h^a`]^cnhla\c`ncccff_^]`c]caefihcf_bbbi_mpnek`\fmklrmfhjehjcfa_^\\cUa_a_diae_faeaecceljjegqktunmpmllfggegtstuokefodqmtvqdf`TCG>6==>>KSUWoqomjfqknujogeffeb`ekheldagigc]aY\`[[X\[aggf]VD@9,-&'#%!-0APT_fpxmxuminytoqwxqxsspvjq}zwuy~~z~v|yxyttqnqotornhk`hjeaU[TO\ZSSG;9-'"""$%3>ILQLYXVQOHHMWWU^_fgedmahpidjac__^_`jfc[b__e\bb`gfdbbe^^ennljcbd[h`da]f]abbccefdkdcl\g_jlhfmknlibd\dfmgbhilgmkejh`b`j_bdffc^kba`bee_g\ajjidpqplqsrnnhfsrmktqwlpljgihmnqik`fY[PHA68+0/6;@KPcgskhreconkkheg_`ecfkejikfplkdlb_gae[\abcdo`cVJE50+'&&%(&#'/Tblqprlkfikn`ad_b`elhhggffgjafZc^eggdede_[hqlh`UOFA9:.83B?DIQckooppuknxpsyq}|vz~zzzzu|rnvqtvqpsyq{|yxnwvuypyrupvirtwzrfcTFLPOYTUKS?8,)$"*3KHV_WS_`\adYU][X[U[Za^a^]cgigfmj`]Z[VYcZg__k]b\aa_e^hcibf_bddfgb``kfg_feigebghmih^^\XdZga_gdedh_ikkhhgiiidbeeedjmjb_b`epinlibbidgb^grgiqqktooqvxnpksktktmpmilfhjoedfjlsoe]OD>6*1%!" '18BN^lvzvjpm_je^if`f`dabendb[^eX^idlmh`_jh^\hmglbcZMEAE>ABGKLXZimcoqprxwltzvyrxx{z{wytnptsw|{|||v~yzwxq}{zp{oktzrkwwpucbWXKQSRRTNPE96,')07?FXZ`[Ye^c]c_V\ab\Q\cc^[__eahekied[^[Uc`aa`c`afmb^hd[d]acl^_efhdYkcfbkjoilhmlgpeh`\]Ybbbbhf`g^accei_cdaikdgicdjhl]ja^]i`jggcejcghhffnjjglqomqilplkjnhnfjhiknglglnichfknd\F?B1,)#&$#"%(+=SZlitnoglpkkbad_a_Ya_`fcX^f`g^bjsitpc_f][akpunk^_PLRQOURYchfirqpxtrwqrvv}{x{||{r|u|trv|vq~wo}}vp}~yryr{rlvo{zuqvxvtulc[TTOPVUSRID?>82,,$  (..EGLTZ]fX`cbfdbe_^bXZ]][`ceedendmeaj]YehZigeceel]fadecg`^eki_bb_ed_[fekghcgifmkodabdd]fb``ccabfff\^jjojfkggck\dalfgdc`afbmdlghcjji]jkgznpomkvztrzmtqfjkemelysgefbekigmtpjk]PFA4;3&$$.6HVhnvoohcifg__b^]aa[hgfe^c\]]\^efeglghcb\Z[poplh\^be]Y^]hddoiuxuonwvuuovq}xwzuzt|y|vw|y{|}}vu{}x~}px}|~wysvt}rvvwrozssnd]]UOSPZXQMJCA>:.-(  "03CBRYUZ_f\aa^dbd`^]]b_]a]_^aef`X`c[aW]`\X_da_]`jad`dfb`h`_b`fjg`^cc[_`hacieijijndjja^]a^cgd]`f_keb^bgbmeeb^depgdj`ci`fd_ghjducfghjbeZdlxpyqmpprvqwjtdlikgjkponrjplbhfjeircaTH?4+('* *17K^`okrkjiknhkc]ae_edcgagZ^`WZYfdhnjeefbXd]eiry{s_kgjisobstipsnhpuxotvt~w~uxz{uxrs}rw{t{}sv{{{~wp~~|zsytqotrszxuur|smidYcXSXSTOTRJMKC334&#(&##*08AKRZ\[`^`bZb]^_]`]gf`[[X[Xcbfge[_ah\\T\ee\abccb^m`elhrj`^`bdgrcbc^gbbacbdccifibnhbi_Y```a_[[Ybb`c_efelelgfpgndpf[ff_gglkacdja^cqjiddheqvtskvusrmrpltujnckibmwke^agf_ddgicaOO@;4,,&"! )+4GXcnooskosnkihhbcccklfbfaXV]Z^^`cff`diiYd[eepinimqo|yjurvrnqmvquutrmpswxwuv}xuxuxwt~s{w}vztqux{z~zzu{}~}|usuxsvozt{~somd^XPUQWYTMPPOIH>B:4--,/.14?@HRT_]Y_\Xaf_Ze_`fabdc_ZY][W[_cd_WYZ[\aaXb\Z_bX^]_fckkj\aa\`bbgje^aajhc^hedcikkgdgjddc[`ccc\Z^Z`^`ffiecfmblfbppeghi^hfncnhhhkpmckfiXfdgtoxmhoohosjwqufdec[gbovlpeeca\gkif_YKE8.+$)++" !0>HVhmoqgikgmnmge]a`dllhecYZZYYYih`aX_fk`\f`fjkpsqtklztsrxtwwptvrotnuwussxntrxvw~}zxtxz~vrqppyuyz{w~~{|xtwsnrotquv~voqmj[`YWQPOKLOSKI<@@=:9<<6;>CIFOU[Ye`]cX[b`[\Zaaj`c\_YW\[`[Z\WTZaYbdeX_dYY\\`]\`\gii`aebh_]fhg\c_fbc\a^clfaldfmgainca`eacVdeca\dkhaigihqt_iffcf^fjkgegimke_hlijngchcwssrpmvqdormoqgk`\`_giilikbc]bahgabORNC8-,%!!" !$,6@Qdtppnqgihlffi_bdbi]eeh\[Z^_`ahgda\_aibc^dliiplrpmxv{zlioprrrqzpijnqpt{mwuv|~w{~z|~x}zrjsnpvov|wqw{~{|zy}{xswrps|svwyqoc]d^YYSVONLOPRRNLGHF?=C@GSaig`jlhqkjmjlrc\bhchkjn_V[XY\]a_b__adibccdkoildihlkjgktrstnsknrpnokpwolswqzruww{wqrktrxwzorqoqursyx~uuw|tyusktmuvtxnppupsoid\[WWVYVMTZTTRUPRMVSZ[YS[USZVVV[]]]_^c`aa`lgfa``^bYebb\^^TRVWVWbXZT`^cU_`_^`fele`bicdh^hcec[`kdZadaaae__XY\W`a`a_h`ebc`ifcc_`_a^f_`bbfhdkeidimkmjjbe`hfdb_edneets{y|wqmej^\ffokh]]eccqhntdh]ZU_^_^`[SJ?=25()#!)&,+29FQX__fknjfhjeu`hme`hacYfg`dZZZSXX\a[[Y`edcceplkpkstnhsqpiuoujriltuookjgojkounm}zpmwzpr|sxtrsrzvq|wptwuysv{uzxwwpoqmsvrzyqtwthkaac[_ZXWaTVU[ZWYRUPRR^Yc`\\X^ZW[^_X\]Veegbe[``[^V]`abfea]caURT]Xa_[]USYUXdfY_hdac`]]baahcjc__^c_^]^c_^ZX[]Z[XRUWX`aeYje_\]``ddafice[Xgmgbhiqciklmlifhgcd_ibffekaqu~qyrqrhke`jgmi`be_ldbjlajmhdc_bbgdVVOED9020)*.)//@;?8426;A?IQT]dedb_UV_c`glfmpfhjlhindgjemnjiirdpjhjdiigrzrvwq``a\`f\^c`ff^`dc_addbe^WY`Z\e]g`\c^_ddfigcceb__`dkcahbifeihsfnjikmsqotrqr~vwupjqe_`]`_a]adeadd`bfdaddfciifeeggjfife_`a^U`lif`hbfnjmlkqosl~~{ysxy|~uxwo{rmqnuozxzrmwiqzkuwmtylgffiidjecfd^[`d^_^bW\S]\`__Y_[YXZYb_g[[]XY]]```b`^\^da`ghcf_Yc_U\W\[^cm\_c\id`^_ac_^XbYdV\\S\W[W``[ZUJ@:44=:.2050829FMOT]aYc[__^acgiajZf]aej^fjfbeikidnemkhhqksimwvwtwW]_c^f__`ebecdfbb]^\][_V_^acmecl^gf^]`ackhgdgdb_egfggmlldjfpghklhkiqjsouxsvxrtqsnqhaa\ffnhac]dehcc\^liddcbid_`\bfd`aZXSaYc_gcca_epphhgnu|q}~|u{||r}qqlrtvsurgrrxrsnnruuvx{wrkilefhijlfjckb\cZ`_[Y[W\[`e]\TSN[`k_cZ]_c\]Y]h^`^Z\ddc`d[``]c_`ZUYa^cac^a_cbmhjdZX^W_c`^WOYW_eY\Tc^WOJH86074+33),1/49BLRV\aZ[^Xcgc`mlfddjmfkghhkifemioulmshsljrlrt{yn`]ZZahccc_gfdali`^ce][X_]^[dbcff^c^hbfcbhcfabgn_difitmnfobejkklspijz|tnsxxwlrsttmac`ce`ce_mf_WhfceafmecbbebcfeljccZZYW[Xe`bdd\]af_flnkkuzvvt}{y|wxvvrrroqqy{uyqpirnqrrtwvpvtpolkejkibdklfdc\eah[W_\]a[c_dYSQQO[W`^b`c]]a^^bZdf__\[_b\`\[U_W^\ZY^[aafc\_\c\fdZZ_[^`fd^QV\YXe^c^[STCB9/8,20-.)-+)(',:AHWYZ]__^_aYcff`baifcgifdhiftkmfntkjjnjfpnorrryr`a_d`b_`_^`ckbhlb^`[YX^[`^_[bfb^b`_\^bjipmbiabjgebjgjmqlljeicbefplnnslssooroqqjlllf``cehededaf^faeda^ggjhcbdlcgdgcbe[^\aX^WXVY]W_db`apjtp}wy{zw|y}ywroqnnnsynwqrtxxsrwwvpuxvsoolnnieijgafdf`]YW^\cZ[W^][\WR\MYZ]^a^`_ZUWZ[cafi_dbaa\`[]U`bg]cWZ_[[faXagchfe]\\]\``__bYPTXYg[^VUL@8=00),).-),'*)-//AGPSS]Z[Y^_cf`bc\[edgfeeegbitfhminnlotjgfgmqiqtrWa`bbffcejcg\ea]]Y]\Y_[UZd[ab\c^e[aedd\c]fbbahiikkijmmjoechgknfskppkquynyupokmtlkqdjb^gmatikikd^_`cahljfa^gglf_gce_d]Y[X_Y\b^\YZcd^_adklsmqsz~v{vv~xu{zhu|topxwgpnuqpzzopxutrtppsjhggfhtbeg\``[U[V`W]aa`R_^XSU[VXX_`[_e][W[baX[`cdbY^^]]ad]_]_h`ZYY[ZX_fegmfa_[Vca]dgk^T^Y_Tb_]VJIB0+212((&)'#"&"."2HJTT\[^VafheXZbaaacbc_^iacjnjlkqkfnmwnttiilprr{dVXZdcffXXjf`dai`_\[]VYUV\W__c`cced`dgd^dehbdgcc`fhiemjfgeefdjkjlkmirnrmimjpmltmprnijkcefhbehjcfcccfidmgeaiXhi``lmcaf_g]Y[XV^XZXcZXZ^fbbdppk||yz{z~qsiqtqzvooqtvwum|xmutp{}uonmfmcbfhf`eiWdhc`YYf^]a\_c[cUXTYUSUagf[_\\V[_dbg_]bg`b_a\\bhcjZX]\\Pe\bhfkdjhf][]Y^]_fdTXXVTa`Z[PG:.-('++*(%"$"*1=MT[ZW[Ya[b[ZY]T__Wa^f^^gkpbeggigdk_nrkoslkushWWZb]\epf]fbcb[`chabb_[\]^V[a]V\]ZZ]`aa^]e[[f]b_bfgokcfkg`jei_lhgqpnppjklkpojlkojrgge^^Z`bdhdeel```dijkpgefhegtngY``hh_aaVX]Y^]b[V\^^\YW__b_oioxyz|tkpifhottqmnmuqyquxqpsxutjusmkigbg[\cbjfkeiiea_^[U]`e][_edX[YZ^^][]`^Z][VWaYYfad_\``eZ]^c]aYaWa]^lccbc^beX\\]Z^WZd_^b]RZbcecXSL:0$)-%   #180&*' "#",9ELUW\`Z]`]aclmfgfb`ba`bcbk]d_dillkpdhojjllm{sz`Z[YVXi^i_ba[a[_gngjb`_\id`\dX`T]][_fkfXdZ`_``\blmigm`doff]dfca`ilifohbhhdkigie^_dfbijaZTbYkg\dngbankkmoifbegbcih_g``XZ^Y\Z[WZ__^]WY^VVST\W`ceginjltsuomtbelllsmhmrlmmunjjqnkqmkiedhl[_`bhnpefdh\^\_Z_\^cc]`a`X^_V_XXa[W]V]Y^[X[Y_d\df^`cfe`b^e`cb]ggkjc^^__ZY_[`b\]UU^[a^`]faf\XK:2)*("" %#(*6ILU_\^a^bfconpbbf`^fgghejihj__bc]kqmgmZfbkolsu]T^YQaifegj^\^_`Zdgae_e^[a_e]`bb]TY`Y_caf\UXf_d]iggbkkn`c]ame\bdj^ehhc`cb`bjgedcgYd^bfYb_bed`dgbljgl]khldafdiaadl_i]g]Zc[cZZU[X^Z]ZX[SSPTOYXX`e`jnvqxjhphffiqmgmhlknmmhpdjlulflee_bkicgeiabfX`[]^`a_]Z\cWb`\\_[OXU^VZ\`__YaZa`eXZ]agfddg\[ace_ghddeanlji\`_Y^ZWd\V`aV][[XZb`]gebWUE;3+$ % $!&).4@AIWZR]Y\Zefediijdcg_adikkfdjcihjdicfjdeqnjjnsoZaX[[d[cga^dgWWY]e`_Zbc\gac^Zb]aQW^\Va^a\d\\\d`ehgijedifca_`^c^bbeacel^adfe`d_Ye^[b`eh`][_e]edfhlkh_adiwmfciha\c```h^`^\X^PUWXTZeVV[VSUOV[TRYZ\bbkywqpjpfdjpefqiekicikjkccqnih`W_cYb\[bbdab`fg[e_]]\VY]c[cf_``^YY\a[d]ZQZW[`VW`WYd[^ahjbbe]f`ae_fbedYfcaX[UV^[^ad]^[Zd^^Z]^g_fb^ZXO?5//" # %)%%&35?=VRV\`W]T_dfffg``]]dahcjopqhglhhhqifhka_^bfgpraWSS`^agc`^^Xa]_^_[b_ade^`^`c]cY[ZV\^gYV\YXbW^_d`hofgel`dfbdmflidmiimrmcg[a`b[a__]`h]^af___`]^acndd`ahkekagddhha``e^_khc]`VWUOTZ[XY[WNLNKUSWPY`Ubnpvwkhpkjbhqggniixloogglbgghc^TZ^\[XWU_elf][dafX[f]e_^aV_]`[YUTZYS^YRZU\[V]TV`]`a^be`d]ZVbd`dcbeh_eec]ccbb]WU`hedbd`aci`^^^\\ee]\VPC8,&#$ "%!#*-/9;CQLW\X[S[Wgdbdaadiadd\feeif^edhhdckccgd`d`acgqph^kaa_gce^ccab]\ZXkcbZ`ca]^aef`^^UW[\[\`T\^^a`\chcgjk_`a`e_Tbeahbcihejecdadd^bQ[^Z_]dWXaa`bgf`enhie`e]\\ejahfab[ceifc^_^[_[Z^]ZZXXYXXSYRQQQY\X_^cfoumpiseijeiaijljmlinfhgdidgbWPOEGRRY\a``adgaf_aV^YYa`V_V_^[TSVVYXWOSXYRSZZ`]bZY]_[bdfa`a`ca_hemgd]aafd_^eadVe]`g\hc`_a^bX^X]gb][ZPH97/++')'&-,37ACDHUUXc_XbX_[fc^[b`_^]`ggkgbchcaejakfedqk]bc^e]cebZY`]\_b`dbZ`ib[d\_WZ\]Z`d_abd_`c]_b`aZ`YYdg\]__fihhhf^]b_c_cjdafhqkovl_^d_bZe][gY^_fV^Z^bb^ddecch\_bc]_Zajfhf`fcdkpae[__]Z^WYY]Wb]VZSZPPPMP[VXY^cejhhfjgilqndhmnhoojkpdfc]UTYMAJFE@FFNOY\\__eb]b`c[VZ[]]U\XX`[URMZ`QX[ZVSUX`TVQY__W[^]Z[]Y^a`gedeaa_`[Zc`caa`[^`ck`d[b^d`[]\]cZ`_a]L@;572+20/5<<>HDILWUY_aXXZ\Ya`g]f_abcdgda`kigjbjkcgefhhhdb\cce_l]Y[[XZ^\cdcc`ddd_`a[c[a\cab\`][b\`]_YX__Zb`b`_bfkjkih]Xe`fad[^aY^d\hdnhcjadaed^[_dW[^_g_gcbbbdcageccbhb_e_\eedjehgfahfcXZ]\^]ia^]aW_QX]VYW[WV`dYbabjf^cmjfbodhdmonghsoekifcUPJD;;7118>>>KNW_`hhdfa^\^bZ`Yja]a^YZUZYXTYZXVPXZ[VPUTU[[]V[^`a``\bdgg_jch^ecged]ZXYbb\]beYY\a`gcfX`aefhTXHKB<87B?9?DHVQMWQUZ`Y\V][\^cdab[keoekjhbfgkgblceejecedfabf]\abcZb\YZW]Xa_bd^bhmbT]R\U^_^\`^_XV[X][f\`\effgbpabihjiideZemib\]_Za\gbbjijc`d^\[b^fWZW\^__`dakdjcibmcc]XSW^Y]]_gijghljdhkokjghg[_^^`]ZYYSU[UR[XZcc[b_egcf`dhedhkimjbiggmpkZ_\ZOFB>98-4210008CHVbbkfa`[]X]\ZVUUX^^[VZXWY[TTZTSW^cYYXSY\[Z[_[\\e__dbgfdnaY^efab[a\Z``df`c\Y`a]cdY_bcagebcZ[VRKCQCGIIQSXWSZXX]ZX\X]UQ\heabc_efcdcmdececgmkcceklejgcjcg]fhc][YZ_bY`ff`dfdc_ZYch^\\^d[c[[_\`a\WYa\j`W]djccjdcoifilndcgb\_aefWb\cghen`^gdjk]_`ZYRdY_X\d]d_a]^f_h\YZ[[\\a^jnbhcfjdcliealg\jl]__^][YRVXV\X`Z^[g_dgd_\^Z_ijigikdqhlefhlhj_RH=6>0-+'-(),/6=BIM]cfnfcVVaZ\YX]YX\]dXZX]PZTRXRUQR^VWQRY\SZ_aYSa^X][cjbgeeeaW]\^Xb]^X`[fac[YY]`\]^^hdhg`jh`VXWWX\TQIJZT_Uba\gYa`Y[ZX_\]ehXgcfbddfnilegjdjgedihjhhdhfgaa^_X`\\_a_]^\i_fbl]`Z\]^\bi]Wed`a[_a[][c_`Zhjdfecdaccifdfi_jeeb]bbcadchbgc`^\edbXc]XT\[Tb[d_adc\fabaad[`YdZY``[Zfklflniifelmmgdgb\_g^baSY[_a_[`^f`e`fc_a_d_b\chkggmfjhnhnmhZYJI>:)(++')',*'&0;HMXei[`_XXXY[\R[]][\WTVPUPUM\QVV\W`WeYZZUY_]bfXWad`dbaddb^^`X\ccZ^`Y]_c_^\ahd`[_e``f]`bkkb[`ba_c\UU\Z\bd`ag^YZVY\b__Za_ilgnjjofffkmeegciklefffhkcekfdgdabbZW`V[eYe]eja\a`e_V\_bdhZ^X_`\dYZc[YYb^bb[^]aicbgkoejcfhjheeb\a\b]]cc\jjfadgdf][aZ_Xdg`aagkbb\U]e_b^_X[\_gb\ld_`_hbghpefiakbd_a\]^^d^d__ZX_`a`kijlbaflaZ]cniakrnonmkkiieWXI54-+%'#), $%)..9?MVjadZ]USTRQJSMUWVW]`]`\_XUY[\VY[c\Z`]XW\V^d`Xdea[k^h``dagZ^gf\_dbf_ka`b\a\b\_dZacaf]biaZb[g]hYX]b\Vb]`]^``__caYY_cccadg_ehciehehiagci`kdi_eb_mae_gdabd\aX`_a`][_\bigc_bZ]Y_^`bcYjZWcfbabY^V\]\c[abc_fie`mbpnmgbicg^a`Y_hackkegbfcni[eabcaWhee_Xe_cojd[XW\`b\`^[\_cc`odlcsokfmhj[cceb__b^Tc`_adbY_bkichkefjplktiffcgrnknwlhphed_VH=.%-)%%$ %&'9?IV[ga\]`WXR]WSURUURZQ]]hTY\^]\WZWY^c`V^]gda`b[bjjejb`lebedeeaae_^`[a^]Z`cb\`_U`_edba`gk_fb^dcgge[^c^`]W`]^bYW_a\`bc`g]fjdgegllkaillojhjcbgcbeg^gf^bbih^[\dZa^^^Y\c^\]UV[\W]RbXV]c[d`\^b[XY^\^ghb_d^``cgcqrqnlmbaebf`ca`ghd`ab_eb]_e\^__]decihhef]ck\ggb_[^\ca`ea^^^ebdb`fddhofdggaa_b_ZVgde`^ab`_U`^aghklp^plpoenkjcmojksnnnlm_[SC77)("*&! # #!(6MX[f[^]\VXW\Y^[\SVWW[V[_\_[\[dYWZ\\]bdW\dhme__abde`eefjfbdakhacc`hbfacdfcbe^]\gYYh``bbeaWe^dfga[gWWS\^_[]\`_cdV[feedmdigojigjffl]gekbieef`cdYWa_b`il`ab``bec`ca_d_Z[[\Xc[[\_\ZY[\b[_a^W`Z\T\[c``^]c]_efmqnhidocqjhhgh^kg]jdfgc_a`^daeZg^ccbjegb]``eegfg_`\[Z]`X`b`\UW\\`^jjihbla`geaXV`[_Z\fa`fgbd]ebfcjqdhqjonjrbkljjnqhebedjgZO?7+*$#"##,-BST_d^]Z]T]^`eVZQ[\VTYY]VZga^WXYWg[[`_a[ac\Yeabec_cik^kfailhbn^mmchd`]_ccb]W^bkc]ahef^mgbaY^aebf]fYZ_]ZYab\_ZXdaa_fceihijemfuprkqkmpliklbg`^[aY_``]bc`j`djf`[[ZZWa[VTSSS[ZV]YU\Wa]WZ\_`Tdaa__cbbW_\_l]lkuswssttpmigkdef_cdidklic]_c`b[acgieajehe`_g`a``_YY\[XY]`^ZZ[f\]e[fjblhad`b_YWZ_b^Z\ac\afbhichegnkjmmslmultppnmfklnhkmodTJ832+$&"23KX_dagcaZ_`]bZZVXQ\dZ`Z`dc^_`UURZY`_d\echbi[YXh``d`hd`fbd_hkdmdlkac[Zd[`gi_b]_\bbicemXYZ`bY`YZ[dZ_a_cW^b_bb]ddjjdfejfthciiinphhllgggebb\_ZcgYZb]`f]kZc[`ca^ee[_b^ZQTZY\[ZQZXd]`aZ`[bfegaebbgbce_]b]fietrpmssimpjppdbbjmlbciinkafdcfd`habf_aiffa`c_bge^ae_Z[``a`a\W]^eb`iehamch^_d`ZX]`YZa__cfdghgfhhgjophqwknmoujliojjmeloqjknYP@2*)##$&# %/=CQZ_ca\_^Z[a_b_[UVYZ]Y^a\`RZZWUOS\^^__bf_d^Y\h`_e_mleea[gbhjlpfecefc_i]g`cc]`a\h`bhcf`^aa\dg`ac]c`_[ae^hedaW^bjjb`egleohmqhqjquqhkppkgebb^^a[ec`]ba^c[^`[\d^]`VWXZXUZ\VXTRYXZ^_ZXe_[c_a_cdifdfYc]fahhqnqosrnupplqoophglnldkiilfkfhYfbci]`koke]hcac]^a\hbhe_e[`[X^\\Ydg`dgccd^db_j^ccY]\`_[cccfephmjlckhmooqnkoqspksplgjnflskoh\M=/-"  *4HS^c^V]hXZ]_a\_U[\Zbdd\`ZXZWVVOUVZ`Wafd\c]__`Y`blgdecdedc`fijjajhgcba][c`^_ed_^\X^gcib]ac`]__Ybee[dld^`adXcd\afiedeijjfnokhfhlnjiqekggejf[_egc^^dbf]Yf[]cgga_c_Z\X^X]^\YVWX_^Z`acaaad^^_ghmecce_Zefedqhkyoqwlhqnpkoohidcn_jfhfhjeiddf^eabdhhdjfa]`led^ddecccdd_dbbX]b^R][cbejhei^_]f_aa`T]]aiknmttisookrrrgyxrwlsjqgqffkqmnlogbHC7,+"  #,:DW][aTVZXec_c\afYYYZZc`__b^ZZROVY]^Y\\ac[^\^]a_^]d]\_ab`Zc_`ihifd[d]\deZYX`U_^\baf_h\ae`a]\j`\`bca]_\f^aaaZdXfce]dafmddbjidhqioohfifkhjke^bbb^_d``c^]g[[^\]VZabRW^^[VbY[]YU_]gaddXb\focgitgi_nkelbicmfjijjmunknhflkkghok_dgeboeglonfnbj^bgafh^^bbj[e\b`ebbY_eV^]^]f`^cedfh]ajfe\^XYWa^\dca\dhdiompqjnprltrprttfknostoebepsojd]SL?3(#  /3KMRXZ^a`^_e]hgnemleckkikiejmoj`\\__\^aa]^^`Y`^ekd]ec^fkegeaeb[ddh^]`fZa_edkggdaa^Zc`begegbde`dceae^c_`ab`befb]c\_hfebheefhmfhjjcdb]eledY[ZR][Z_[][_\`cgbQWXR[Ye\b_d]b`YZ_e]ad`fb]]__a`]`^c^bmpmoprjtjphnfhhhifskgjhnoodjjjtcnbdfcelfdkh]`f_]c_e``hf_gg[eicccef`ke_`becheaadbdhg\]bZZeaofkfg\]binejlignprpirxymtzxogxkqpvxrnikbie_fSJ732+("(+''(,7BKS\]a`d_g^cfjluondjdohidkepttckgc`^[Y_V]cZX_\Xfd_`bihkoegkiaokga_b__`_]bafgdkd`cbcYg_jhie_gg]ddcaebddacfbgj`hd`pddaZ^danfmghjijcaedd^ah`_U[\a[VZ^`b]`Zb^\[[]]^d^dYV\W\W[W]bfdiccacWabc_haedblkmsjkpopuokse_gmfnwkvmhpkpinjmgmphigjisnhji\W\_^afgg`ef`acef`kgfah`b_aZbefa`]\na]^c[[__degedgbgk_^cdkmpmoprtrsrzzxx~t{vthjpkqrtpknjcogh_TB<74/**().67>ISWY_^kcdeebfhikdnpoenocjmeuqtnnijb^[[b\cbaceanXaefaZbeekojfffcdeggebbce_a`agncaa]Zellnkebd_c`bgeab[gicg]a_i_eebfdde]bfc^hjigfgifjfam_bfaa[V[T^[[_ZYe_^[gWVL^PWVkbc`a`WW[^gich[nf`_edgbbgabflbglilniomopkccejljkprooqqongeinieleca]cgphgfg_eaci`ec_]`caj\bgbq^aaad]_ji]gdjfga\X]bXc\]`chdeb_g``eehhjngqofirz|wy||oumggmrt{rhph`plfe]YHE9:=588>AHHPUY^gb_ebddhecojomkjmcjenmjkwkiml`g`c`]b_fe[gfc]`gfkcchghlkjggdflojelcbc^]_]hbh[cc^_ggilgkgid[\]cjjlfgc]gkglgmigkgd_Xd[Ybegigdhbldgfggf[c^YV[VUVXU^^Yb\]^XST\VYijc^[W[\\Z^f^dcbb`bb_ad^ccih_d^ikcnronpqplmkbhngpnlnmjpnclkgkshfe\llidnjjhjb^`h_fdlab\^bbZgb`ahdadacf_a`gi^idd\Xa\a^^hkmfmihg`^bfploosihfohpwu{}|xwtrwkmrnpnsnljkemirnkcSQI@?BCFJKVQVWZbecihjolhekngldllpjslgrkjxkvqig`cbZb^h_b`d]chigc__gsinhegjgkedb_gie`[hgfmmfqeb_`dbik`jcaeadc[^jejhah\fhfgjdpadcif`_a_d^gejkbeei^gobfdc^YX_UTYVVZX[VWdjUTSV[WV`a^^^V[abgccijj_d^Xgd_^gfdcdhidenrumujokp}xniinnfjirmrmiiqhosnhahchgfmokcdbdgbh`ddf\\f]a^]fe]^beea`^g]ci]`bfbcba_bZ^]\^bcfgbb^`ehigjsahkthijsq{yxul{rlskvqmvhka[f_rvimm_[aRSQSRXX_T]Xcb`dfhqkknttsorqtpqtzqibrkhouuwntnjc\emc`h^bcf_djljedgegcitjeemdkjdkhiZfghnlba^acbgjhhjigdbbghjmqggl]kdjjkrgacjfeecd`eafkiobkjhdhccpc`_f[WaY\VTY]\[a[a`UQGSRVhca]fbWVT_adcmfjfe]Xe^\`dd_`aae\nlqnkbrmnjntmsgedpgkljslngcnmsrfoahj`hjfkkhcehdgl`agic[^^Zc`c`g`]c`ej]aYcYl`f^`ba]_Zbba`ecapg`dbdgijch`qnepmpqrxttujutlqtwhuluskjeokknmrhdef`]ZQ^Zbd^f_caalkjmmmqvrssqvvhsoutpmqftrmqxqhhbad`bcdbgioekg_aifjolb`hlljacfehc_a`cj`ghjkoeiddogmiibdcdkeknndaijq^ghjjkehgkghjm_l^cjegmijdlaihqghgbZ\[^^abYVb_Zc\`aP\RWV^`__`d\c`_ddfhdfqjfg]chdfc`idgjjmmlkqjodqkjqnlogmfmchfehkknhhoojmjbfbajii`bbjjidhffedh]eed^Xaafi^^_bcjcdb`bcfbbZb`b`W[Y_aabhiddhchdi_decmhjhmhhqpnpsyrzyr}wsvnonhshkibesnhiqcefbacbjj`^fZajirgeotqxyxyvuqqtuqlcgsgmfnywghfabacba`igekdfiihg\`chmifhgiffddehdmmibknqgmjgdfiafhfhjbcfcfbcha`cf`[d`gebhnfhfdilnd_dbkgimjshkjmehgbai\ZX[c^c]^accamRU^Z[\`^]eacdY\dbdgclkmbab]^dabcdjmihfieolokhejnrquyukkqjhgiihiidnimlkborsgedhojndcbbgbbkflfgc[^hffjgbdf]ba]bcbeb]jfafgei_ef_`ddgdldfanhidc_d^f`egelptisqhtqszxxrrohvnlohdcffmtpjsjaajjdpmggijljonupxxp~{zu{~yvzvmlmtppstuvhhgad`Yadkb^mmqbe`eihjjlakfleilcfgjbbhqkfljiekqkjfe`cd_fhbnomhdcdjij^g^plfgdjidmigcceiglihcjlikjjbjeiaa^c``]``\_b[`c`bVWU\ZT_b_ga]e^`d^_ceacgoleg`gh^iegqknluufkgkhejkvrlqwpmd_baglrjpilekgitfnpmlikcaageicdggfpieYc]^ad^faafcdibabb\]o`[_ceme^]haZ\\h_^mdkocgihab_cdghfohqlktoln{yxrx|tqjpuoioochhqqnmkiroutppkhfsulp|ktnnuw}}~y|vs{|ywnihlloxunojjgbe_Yobg`klgmaj`\e`f`\`h`bhljeokpkkimcipnukqe^i`Z]ccbekkgglkifgdd\^aijljfhckkkmmnjjowesifgjplcelhaecfjm_Yed`e^adj_cRVNW]cb\fd^c_`\^b`abc`jkihfbbaegenngosnhic`]cjrnwno{oplkc`ddfnklffpjoruphojekjokahdeecdiadhackf\d_f_h`jgldfcbce_`ej`flhldd`^_clbimdceje_d[Zkamcjbjqqnvrqqhrsxvswxzyitfqsislmealeunsmjjrtnoqnuvlx}|{y~|y}x}x{p|~pvsrwpkel[d`^_iccghfbhgjcc`bYfdcejfhhilbemgbfgbokingkiee]Zfhcesmhfgfefc`ajbdh_gfcb`hfhgnlfoelglghohknhaa_befgid_bc`gcdeffmVWY^_^`eeX\c]cYgf\\acU_focchc[]aglijmljkkqi_dlhblmmjtljfnh`dckoqmjdojzgahrkhgpmbfjdhajggacckmebbf^khs^jiphjifd[fdcafhuprnd_[g^ebf`ejnhqaihg\beghlieinfqurqtmux~v~yntnominkmklfhpjolxp|onwups~ux~{zx~yyyyrupvxwuysqsrgfc`g]a[`mjcfhdmcj`bZ]cdfcf\aimkkljhieklijfce[ccg]^flnnjlne^idi`ibfjoujinakfbnckkqolfjiipojfghfag_cdhicdalamiionkfYUV_Y_^`b`WWb_]`b]V^[`caceh]bZe[jennihllifff`jginyslmngkimgcdeklollqqqjjomplijjiokfmkkla^enihfgdhhegnpjjhdffjdhcfd]cmgptpegc`cfjhnjqhrzoiimej`^ceilkiimszrqzvyrqsp{vpvtkqmlppnmnnqmpujtvpv}vxv~~z~~}||uy}xuy|wnsvoyuxpnhgafcbcc`d`iberdefb]d``eehlfhgekgknadjbegfgkef_bg`ddiljpje_eaW_kcd_nkjhffeljoic]grphjhnnggjhgfef^a`ie^j\klrkkjohmY\Y`W^heagcgg_fad^`S[aYWehbbZd`_cfimigfllj]ahkdgkhnqqjkkfkgcecliromrtkmnlsumpggkgvoturicgjofll_bfolorlogninlabff^baclusqgioef`cgoiikmr|lkgighgaddbdjkncnpnvvqvtsssnizerpvhmnkkpphmrlyxz|z~rxs|u}}{}|xx{}|u}xu{{{ruuxyxqmqkb_^gZZ`Zcjqkogedb_Ykjhlihcdgpkihhbbi\fdflahb]dd`rsqokjjce`kehdcehgfjcdceipngllfnkjkgkijhbicfegahhlfojiulomlkfl`bYc[e_`c``__iYb`[g^Z^^^^\^YX]`d_`ffhlgagjgd\`^fpgqkkomsvoldidkromggooilkrurpj_heloennmkhhkpm^eihjihksjomkpibkcd^_ecohongciacahgdqifjiiiijhjkgjkpimjmmpiql}rrronynsltyy|qljhskonlwntyrzknp|x}w}~}~~~zx|tyzx{s|}z}zxklokebda`bbhipgnhd]e`ffehh`ljafkpbjje__d_abbcopnfgojkc`fgc_diifdlhiclhcf\l`dfhmkjhjipmoccohajhkagfinmklinjriklfj\heffb\fh\haa_a`cb_]_][dbZd]gbkkbmdfnplgbkccgj`adkjkojokrqkhefcnjiokimjfoonokfnhlmkqslqgnkgkfecgc]niknhilg`mjaa[_W_dmmijkkafcbjjtlngialnnfegfmnmldjedjgejoxusrmprll`ihlqmplllkolrqlgpuv{|yszouux}x|w~}zvy|w{r~}u}u~rwys~zq|xvrrflibaWcbciegedgfcigmhdfbkdd`obbkdjc`ce`geebkghnbbpmhgdh`ebahdkimfijoddfggfgrighhgdgdkhedh`heqigcdhmhjinuuprfl\^f_hdhehdai`a_X]m_co^\ddbic]_ddfloumfsknmhlcifgltmpmnjloonhiikkqhfnilgooivxhamhjielyospoefhfflfgqlmphodqhn^lcc^Z`]^ehiqknhchdhhonlledmjjdikjbjkkgjqdiijpppssurmqmnmmjrlmpmokktmormoukprtxtxyuy}z~z||y{{wsw{w~~uu{yllnk_d]lenkjhhdd[`gdmlel_bfclfejghcbb]b^efkmrkpklhpgpffbefjhc`aghimhvfbfokldm`drlhhlcebcckipihjjqhilhfnpnjil_^f\geijc_kfda[V\_eZ`^^VYfb]aifliontoxsuqvhgdmpuhpotoiijpnrlpqksihkohlijghmmenihjqstqtoqrkpkjgjbromkfelcnmkhkakR\aY[_efokeiljabelgigeegqgjgimrhd_kikffhdmmppopqlhgimjkqrrlqrjqlrjmijnkws|{{~syu|s}y~w~}yv~z~vzx}|~{u|}s~tvth]bchhmjpckbhddmfcga]eeffhjfhia^]a^]ajkigfqknoikbhb`bagbflgflinkggbfmc`lijhbjclgmfbdbgkbhqikhidjlolijmohhZ[f_fa`gc_``haa[aedeYZ`Wed]bohXknrxljpptplhrnoljqunofkompqemflhacgkmhpilhrrinliifillmvmkiqnplrkortsqeeeikjhihhceg`cZbadtjdllccgenhrg`jeemjrknbebhhpke^ghepokpurmi_kgojortmnslshkghtotlrswsz{~yxmswzryw~y}}|}~}xvowjj_ilchecfdhiaijidpi\mfhhealjghc^agcZbfokkdsjmogdibdkkemeiidcjeedgnhhkbmachghbfcihhjkisllicokjjef`ehek^[\[^\]ag`hbbWWY^ea_[[[Z`bhmghjhnrx{rxpynmtjqmqnmpspg_iggdookihsfjlhsjodjggfpjlmcfhlorjjenpmkpukfelpmlbelmnggeadcg]\`b_iknje]ckgqjchhtg`gbeffceccjhemjgppsjhgiliohihlnlvsswryosjjhrpqvups|z{{syyx{zyz}}{zu}{~~~z}yozrqnnkdcbkdjaea[bghbecjidmfcimed`ekhcbkfgkpgnhnhbkpggndthjsiomlibgaijjidkfgijfjpelfmclomjlounkfonpnfihWW^ea_^gcf`dace\diXl`a_deejlchlmiprunlloxpusqnowsljjibefhlrdmflljltvkqjlnfreijkimlfkjqokrhnqorwphvqjidYmhdhlccc[\c`gccfckddebdldlmnjojkskpkajhbkujomiknldongknkloolhlquqryuotrwqimsrvpq~{u{xz{{{wy}u}}z{yxv{|~}zv|zz}yspje_caagbgfgcmhngnjlejjeglhjpnsibejjjiqosnigbgge`ifbhghhillpegchqlfhejei^hhmosmckmmlsihkkrmroegjnlkj]W^YS^[cfacjb[bcb^ac_fXbbelmlgbidbwrljpvt{romptimnlkhicedihhihjpulzjiuilljelicjhknijjhjfpjuqnvuqqpm__[ffdngglcfadafj_g_bfkebfcihngfllnnklcqkgtbijmfjhjhaljskngkxyvojifwussjsxtqpu|uwz|uswu|s{xtyz{vzuw~}yx~|~}z}qlcc[cffjhabb`^fgdlgdcjdffhfnmlnkqigckjkrphb`bgkkbhiahimpdf`gieihoniedgb_eifliuofidkjmlhmusutpt{qrhnV[\_]a[]`^a`gahea_gbbfbeafgjb`_bejgmlnrwsuloinxswjkmja_aehimkiodulsxmtmoifqholigkiegchmhsljntnygppgfg^ec`mfh[dd``cdeh^acichl`_heerjupknqofogkl_fljlmmbncdgmcmprpyzpsmppppxwsvt|wsqvxwvs|zy{vzy{s|xt|v}{z~|~w}{|}wyw}{vvyrdgcaheibg^celebe`fb^cjfdilnljwebZifnlkhjg__gogg[jcgkbccjekagfefhmfhieb^jomkmpekoipnpqquqttxvsooclZY_\_`]_^bi^delcabfadfhh^dg_oe_^`lhiqgnknxosrqqrosvpmhoifkkcdfiinoqekinmqfijefkrgfnip_f`pkspswnonpgfacikirqna_gfabfadcadgica`Yhbmlnlmqnrdfhiqlihojfmllki`llppxmqzwzzvtpmtqtyuuyu{zvus}zy~xqmosrpsyr{{{~}~z}{yxv|}ux|~qyhd`f^gdgpeg^gke`ch]chfklhifohgkegg`gtmhfifjc\hdfhbf`b_bfj]ace_aiihaimee`mdqgrhgnfloohohnivxwqqprkk[T]]^Zaa[Z_]ab`\ec]]_ggea`fggdb\aZ\iookrpomtorpvsqmfkkelfjqahkpnrzjtovmhhi_nkjojkhifkb^jjpuokpqpjqecnmfkgceiabca__d_c^eham_j``jbimkiniigfc`bfejmgoqillfhelqusgqwqvzruqovuyy}vxquwy|~x}yyzu{zwwv~uotx}y|{~~utux|{x||}}wxqxgcfhclfbffZlgie`bb_`ioedgdcefhgje\eolmmlafgigdckfggfcbb^cd]acefgamegghpkikfpgkmkfekjiknjojojqpigjZZb_aaif_`bb`_feda`_fhcbgd_i`d]^abgeigjollwpuqssopiqfdge^iblijmpumisnzjfiljmfjiiiikomqgmopiltqqrlkqmipchfila]]jb\_aZidmgd^^\ab^lcibifldkchcilfrqvlfheohijdlpknq}wpswtthsr{{utyu|xw~vz|z|{|uz{}rw{q|{{ux~{vrwm{yvuxxmw{}wz{}~|~zzzvkjlijgjmgc\f`dbc^_[[e`feeafjggsjcbdmjmimeidcfchbhljh^^j^\_`fehdbcbgefeilgnpmogjhjhdkvjmhhrorllj\k[^Y]_fcg]aYc_e`ddcf^`_]ghdei^Zb_ZcadiptkmfjitnohlsmijnhgidibpdknwqnsmnmdjlgiopqgrtoposhhtqillmjnigbkgkehlkjfjjhgZ_`bdejeelcgfa`cljhge`gbZ_bgbcokimpkohipkj`pqttoympqupssrtttwy{zy~xxt|z|wyysqnw~v|u{}t~r|wzwy|v}r}zy~|y{y{xuxloigidilhg_ab[^W_adbel`b\cgmenhcfagjijgkl_lfdmshqhcbhh`dbab\ac`aaa`glmplpogrjgmikoeklpwsmfsmgf^dbaa_c[cfhc`Y`aba`]]ba_c`de`el[\\`hhanjrprnwulpnnunolpjefekfcglojnjnkkjkssjmoii_slfkjqjqrqsmrljhpjinnedjjdg`e``eb\Z]bd_jehdh`eg]^b_]aa^Y]\icfkjdmpnrghfjhiknmqllsruuurtmsuwvzpxxmytx{t~uvywxw{z}|rurzzxuv|}x|x{rtt{uy|sx~ys{|t{{{ywsurnfdoeldiigc]mZ]^Yab^`aecioihskrcekhnlcec[cebclgddj]`fkai`ilpggd__flkgljqmdgkfdhmovlorkhmgohcfd`c`]\`ckf`_`V_\abg`]c^[^dhgk_]cdW\a^_frwtmellqsrqmjeqqklhfdcaejrnomorqrkorqjffnnrkoxhqnptmtkjsqrimqeljgiolamebfe_eaW_`ebeca^cge_f_d]`b\jdZ]hff`ojilmefme`digjmnumivxotsqisqvrrurwx{}wuzwwt}x}u||vz|yvuwv{u}~ssy|{w|vp{{|uy{{}{u{nqlibbb^lje_feg``X_^h`kke`deimjqijf\febcf`h`hgnhmikjglh`eicigqcfgedbijmhqharmpmgkwstmjmqnjicff[c`e``ce`cgde\adbbcT^[^[d^ca`YWbf]Z]^igsszsro{stvkwxssxnjgibgdejihvwpwvtm|ligudlhhnlvcqgltqwmvzztoqmlgli]^bfnojill\dY_[Zeelc\`a`afdde`\aZ_afemfhdql`djieohknpklomltlpownonnosovvz}{wwkjts~x}y{zzxyqxyxo~{}}zyz|ttt{xy~s{uyxvvyrvytzzzxvnpolhnjhflgfbbceedabeeebbc]dfjjhkhglmnqs_dbbdachbficcc_fifjkkkmf^ba_lliniccgkkgfglrnnphqjimjjk_Zcgkccf`jddc`a`aa``_d^[hd\__h]]`cX\Zkoq|yustnqwx{|uus}uvpheomginumpnmrusttmrwnrjlkmmqrlpgqyx}}yqslpsnqmejlbhhjjpih`_[]Xdhla`_\d_e`bdffaX^`]`eheg_abifcagdikkrrnmhooun{qtmqsuzr{yty|rttt|u~|vsupusy|yvvuyy{vtwv{|uu{|{}}xyvy|yxovw~~sw|ulnkbdebdfjg]dfcm`bbhhdkife_klqefogfojjllehicfcbejbaiiagbehfgblxke_`Zh`bmhoieeiclkimlfrnhnejc^gfedoiqgejpgh_deef`he\_\X_a\]aaaafd``bguorwwtvu|yxx{~xz{{pqkmmrpnorpqqp{yuqwvmxqvqomuttklgm~zsyxwtwpnnjdgjcgsesologda_\\che_fYj\^af`cba`gd_diddgdaa`gaehippmqfkjqorrsvppnuxptqx|wvu~~}y|vzz{}yws{uvp{xywwy}x}zur{{~{}ty}vzz~}t}~|tjkjecbghgpbkcbhhh_cib^_gfbkjeffkdpflljo_mdb__bebg\cf__Xfajfdhokhi`[_gaokjddahjlinjtrqjjijgihfjhe}puecnml_ccgefichdeipkghdklhjmgginns|{y~wv}qowxxqouukqnquysysstpxzuqrzomofvrzzu}uwusutlmfcfgektvlmgbcbfdhmda`c]bcab`dada\aibfebfac_`ihiijfeommgijfnp{}z|wosxwxsr||x|wstx}ywwt}rutrvrsnsuvs~uzwzy{zwrpp~jz}x|x~}wvw|~{|}yrhvkpijhgltcf]jfheiilhpiaaab_ee`ffegedfjgege]a]cfidcccdheb`bc]c`_`aadegnhhjcingmqlootoilmefdhkh^d|opkipnnohplrkgjeinslmdknmrwlsz{|}|z}x}{vrrmsnup{y}{vtyvwyolulkkkstrqvsrlxwwssnrnhhgghorjpghd^fdXaf\`_W[de`Z`bdieciqoakcfcaZjdddmmoqpjolnu{uuxqqqvu}wuky||}|||puuxutzqnrtpyv|wtupu|{x~ywrvt|{~ztv|zzx}{}|z~{{ulwtsmiibmikvkcgfgkq`cbfhfhfeh_ciZdlkkmfjgjdicfhkkeegd_e_^]^g^ibab]cdffcmijfdaffuhonkhlrrhiecd_cncX
im_copy /home/john/Desktop/5-14413.tif /home/john/.nip2-7.23.0/tmp/untitled-nip2-1-XBLOEMV.v # Mon Nov 22 11:12:02 2010 im_extract_area "/home/john/.nip2-7.23.0/tmp/untitled-nip2-1-XBLOEMV.v" "/home/john/.nip2-7.23.0/tmp/untitled-nip2-66-X754IMV.v" 630 710 340 302 # Mon Nov 22 11:12:20 2010
in/home/john/Desktop/5-14413.tif
nip2-8.7.1/test/workspaces/test_conv.ws0000644000175000017500000005667213351443023015055 00000000000000 nip2-8.7.1/test/workspaces/test_fail.ws0000644000175000017500000000211213351443023014777 00000000000000 nip2-8.7.1/test/workspaces/test_math.ws0000644000175000017500000013735113351443023015033 00000000000000 nip2-8.7.1/test/workspaces/test_histogram.ws0000644000175000017500000005134613351443023016076 00000000000000 nip2-8.7.1/test/workspaces/test_filter.ws0000644000175000017500000022012413351443023015356 00000000000000 nip2-8.7.1/test/Makefile.am0000644000175000017500000000011313351443023012324 00000000000000 EXTRA_DIST = \ workspaces \ extras \ images TESTS = \ test_all.sh nip2-8.7.1/test/Makefile.in0000644000175000017500000006530513417043242012355 00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 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@ 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 = : build_triplet = @build@ host_triplet = @host@ subdir = test ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = test_all.sh CONFIG_CLEAN_VPATH_FILES = 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 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } 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__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/test_all.sh.in \ $(top_srcdir)/test-driver DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BISON = @BISON@ CATALOGS = @CATALOGS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DLLWRAP = @DLLWRAP@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FFTW3_CFLAGS = @FFTW3_CFLAGS@ FFTW3_LIBS = @FFTW3_LIBS@ FGREP = @FGREP@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GMOFILES = @GMOFILES@ GMSGFMT = @GMSGFMT@ GREP = @GREP@ GSL_CFLAGS = @GSL_CFLAGS@ GSL_LIBS = @GSL_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ IP_CFLAGS = @IP_CFLAGS@ IP_LIBS = @IP_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBGOFFICE_CFLAGS = @LIBGOFFICE_CFLAGS@ LIBGOFFICE_LIBS = @LIBGOFFICE_LIBS@ LIBGSF_CFLAGS = @LIBGSF_CFLAGS@ LIBGSF_LIBS = @LIBGSF_LIBS@ LIBGVC_CFLAGS = @LIBGVC_CFLAGS@ LIBGVC_LIBS = @LIBGVC_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MKINSTALLDIRS = @MKINSTALLDIRS@ MSGFMT = @MSGFMT@ MSGFMT_OPTS = @MSGFMT_OPTS@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POFILES = @POFILES@ POSUB = @POSUB@ PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@ PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@ RANLIB = @RANLIB@ REQUIRED_PACKAGES_CFLAGS = @REQUIRED_PACKAGES_CFLAGS@ REQUIRED_PACKAGES_LIBS = @REQUIRED_PACKAGES_LIBS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TOP_SRCDIR = @TOP_SRCDIR@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WINDRES = @WINDRES@ XDG_OPEN = @XDG_OPEN@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ 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 = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ 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@ EXTRA_DIST = \ workspaces \ extras \ images TESTS = \ test_all.sh all: all-am .SUFFIXES: .SUFFIXES: .log .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign test/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): test_all.sh: $(top_builddir)/config.status $(srcdir)/test_all.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? test_all.sh.log: test_all.sh @p='test_all.sh'; \ b='test_all.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @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 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: 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: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: 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 clean-libtool mostlyclean-am distclean: distclean-am -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-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: 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 Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: all all-am check check-TESTS check-am clean clean-generic \ clean-libtool cscopelist-am ctags-am distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am 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-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags-am \ uninstall uninstall-am .PRECIOUS: Makefile # 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: nip2-8.7.1/configure.ac0000644000175000017500000002727013414612631011617 00000000000000# Process this file with autoconf to produce a configure script. AC_INIT([nip2], [8.7.1], [vipsip@jiscmail.ac.uk]) # foreign stops complaints about a missing README (we use README.md instead) # and missing INSTALL (the standard Gnu INSTALL is not very useful) AM_INIT_AUTOMAKE([-Wno-portability foreign]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4]) dnl dnl We do the version number components as m4 macros dnl so that we can base configure --help output off dnl of them. dnl m4_define([nip_major_version], [8]) m4_define([nip_minor_version], [7]) m4_define([nip_micro_version], [1]) m4_define([nip_version], [nip_major_version.nip_minor_version.nip_micro_version]) MAJOR_VERSION=nip_major_version() MINOR_VERSION=nip_minor_version() MICRO_VERSION=nip_micro_version() AC_DEFINE_UNQUOTED(MAJOR_VERSION, $MAJOR_VERSION, [Major version number]) AC_DEFINE_UNQUOTED(MINOR_VERSION, $MINOR_VERSION, [Minor version number]) AC_DEFINE_UNQUOTED(MICRO_VERSION, $MICRO_VERSION, [Micro version number]) AC_CANONICAL_HOST AC_MSG_CHECKING([for native Win32]) case "$host" in *-*-mingw*) nip_os_win32=yes ;; *) nip_os_win32=no ;; esac AC_MSG_RESULT([$nip_os_win32]) if test x"$nip_os_win32" = "xyes"; then AC_DEFINE(OS_WIN32,1,[native win32]) # makes gcc use win native alignment IP_CFLAGS="-mms-bitfields $IP_CFLAGS" fi # src/Makeile.am uses this to add an icon to the .exe AM_CONDITIONAL(OS_WIN32, test x"$nip_os_win32" = "xyes") AC_MSG_CHECKING([for Mac OS X]) case "$host" in *-*-darwin*) nip_os_darwin=yes ;; *) nip_os_darwin=no ;; esac AC_MSG_RESULT([$nip_os_darwin]) if test x"$nip_os_darwin" = "xyes"; then AC_DEFINE(OS_DARWIN,1,[native Mac OS X]) fi AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug=@<:@no/minimum/yes@:>@], [turn on debugging @<:@default=debug_default()@:>@]),, enable_debug=no) if test "x$enable_debug" = "xyes"; then NIP_DEBUG_FLAGS="-DDEBUG_FATAL -DDEBUG_LEAK" else NIP_DEBUG_FLAGS="-DG_DISABLE_CAST_CHECKS" if test "x$enable_debug" = "xno"; then NIP_DEBUG_FLAGS="$GLIB_DEBUG_FLAGS -DG_DISABLE_ASSERT -DG_DISABLE_CHECKS" fi fi IP_CFLAGS="$NIP_DEBUG_FLAGS $IP_CFLAGS" # we want largefile support, if possible AC_SYS_LARGEFILE # Checks for programs. AC_PROG_AWK AC_PROG_CC AM_PROG_CC_C_O AC_PROG_LEX # we must have flex or lex if test x"$LEX" = x:; then AC_MSG_ERROR([lex/flex not found: $PACKAGE requires one of these]) fi IP_LIBS="$IP_LIBS $LEXLIB" AC_PROG_INSTALL AC_PROG_LN_S AC_CHECK_TOOL(WINDRES, windres) AC_CHECK_TOOL(DLLWRAP, dllwrap) AC_CHECK_TOOL(DLLTOOL, dlltool) AC_CHECK_TOOL(OBJDUMP, objdump) AC_CHECK_TOOL(RANLIB, ranlib) AC_CHECK_TOOL(STRIP, strip) AC_CHECK_TOOL(BISON, bison) # we have to have bison :-( maybe we could ship the generated .c/.h files? not # clear on their portability if test x"$BISON" = x; then AC_MSG_ERROR([bison not found: $PACKAGE uses bison-only features]) fi AC_CHECK_TOOL(AR, ar) AC_CHECK_TOOL(AS, as) AC_CHECK_TOOL(LD, ld) AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL # dmalloc option AM_WITH_DMALLOC # i18n GETTEXT_PACKAGE=nip2 AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [The prefix for our gettext translation domains.]) # ALL_LINGUAS="en_GB malkovich" ALL_LINGUAS="en_GB" AM_GLIB_GNU_GETTEXT # check for flex ... nip needs to adjust itself a bit if test "${LEX}" = "flex"; then AC_DEFINE(HAVE_FLEX,1,[using flex, rather than lex]) fi # flex >= 2.5.36 uses a nonstandard type for yyleng AC_MSG_CHECKING([whether yyleng is yy_size_t]) cat > conftest.l <= 2.4.9 libxml-2.0 vips >= 7.30) IP_CFLAGS="$REQUIRED_PACKAGES_CFLAGS $IP_CFLAGS" IP_LIBS="$REQUIRED_PACKAGES_LIBS $IP_LIBS" # gdk_window_set_opacity() was added in gtk 2.12 PKG_CHECK_EXISTS(gtk+-2.0 >= 2.12, [nip_set_opacity=yes], [nip_set_opacity=no] ) if test x"$nip_set_opacity" = x"yes"; then AC_DEFINE(HAVE_SET_OPACITY,1,[define if you have gdk_window_set_opacity()]) fi # GtkInfoBar was added in gtk 2.18 PKG_CHECK_EXISTS(gtk+-2.0 >= 2.18, [nip_use_infobar=yes], [nip_use_infobar=no] ) if test x"$nip_use_infobar" = x"yes"; then AC_DEFINE(USE_INFOBAR,1,[define if you have GtkInfoBar]) fi # notebook action widgets came in 2.20 PKG_CHECK_EXISTS(gtk+-2.0 >= 2.20, [nip_use_notebook_action=yes], [nip_use_notebook_action=no] ) if test x"$nip_use_notebook_action" = x"yes"; then AC_DEFINE(USE_NOTEBOOK_ACTION,1,[define if you have gtk_notebook_set_action_widget()]) fi # notebook group names widgets came in 2.24 PKG_CHECK_EXISTS(gtk+-2.0 >= 2.24, [nip_use_notebook_group_name=yes], [nip_use_notebook_group_name=no] ) if test x"$nip_use_notebook_group_name" = x"yes"; then AC_DEFINE(USE_NOTEBOOK_GROUP_NAME,1,[define if you have gtk_notebook_set_group_name()]) fi # GRegex was added in glib-2.14 # we need it for regex searching in the program window PKG_CHECK_EXISTS(glib-2.0 >= 2.14, [nip_use_gregex=yes], [nip_use_gregex=no] ) if test x"$nip_use_gregex" = x"yes"; then AC_DEFINE(HAVE_GREGEX,1,[define if you have GRegex]) fi # Check for the function strccpy in libgen AC_CHECK_HEADER(libgen.h, AC_CHECK_LIB(gen, strccpy, AC_DEFINE(HAVE_STRCCPY,1,[have strccpy() in -lgen]) IP_LIBS="$IP_LIBS -lgen" ), ) # Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS(limits.h pwd.h fnmatch.h sys/statvfs.h sys/vfs.h sys/mount.h sys/resource.h sys/wait.h malloc.h sys/time.h sys/param.h unistd.h) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_STRUCT_TM # Checks for library functions. AC_FUNC_ALLOCA AC_FUNC_FNMATCH AC_FUNC_VPRINTF AC_CHECK_FUNCS(geteuid getcwd getpwnam getrlimit getpwent getwd putenv regcomp strcspn strspn strstr) # need fftw so we load and unload wisdom on startup/shutdown AC_ARG_WITH([fftw3], AS_HELP_STRING([--without-fftw3], [build without fftw3 (default: test)])) if test "x$with_fftw3" != "xno"; then PKG_CHECK_MODULES(FFTW3, fftw3, [AC_DEFINE(HAVE_FFTW3,1,[define if you have fftw3 installed.]) with_fftw3=yes ], [AC_MSG_WARN([fftw3 not found; disabling fftw support]) with_fftw3=no ]) IP_CFLAGS="$FFTW3_INCLUDES $FFTW3_CFLAGS $IP_CFLAGS" IP_LIBS="$FFTW3_LIBS $IP_LIBS" fi # goffice needs libgsf to save plots to files AC_ARG_WITH([libgsf], AS_HELP_STRING([--without-libgsf], [build without libgsf (default: test)])) if test "x$with_libgsf" != "xno"; then PKG_CHECK_MODULES(LIBGSF, libgsf-1, [AC_DEFINE(HAVE_LIBGSF,1,[define if you have libgsf installed.]) with_libgsf=yes ], [AC_MSG_WARN([libgsf not found; disabling save plot to file]) with_libgsf=no ]) IP_CFLAGS="$LIBGSF_CFLAGS $LIBGSF_INCLUDES $IP_CFLAGS" IP_LIBS="$LIBGSF_LIBS $IP_LIBS" fi # optional ... use libgoffice to draw plots # pretty basic functionality, really, but we need to be able to build without # it for testing AC_ARG_WITH([libgoffice], AS_HELP_STRING([--without-libgoffice], [build without libgoffice (default: test)])) if test "x$with_libgoffice" != "xno"; then PKG_CHECK_MODULES(LIBGOFFICE, libgoffice-0.8, [AC_DEFINE(HAVE_LIBGOFFICE,1,[define if you have libgoffice installed.]) with_libgoffice=yes ], [AC_MSG_WARN([libgoffice not found; disabling plot display]) with_libgoffice=no ]) IP_CFLAGS="$LIBGOFFICE_CFLAGS $LIBGOFFICE_INCLUDES $IP_CFLAGS" IP_LIBS="$LIBGOFFICE_LIBS $IP_LIBS" fi # optional ... use libgvc to draw graphs of workspace dependencies AC_ARG_WITH([libgvc], AS_HELP_STRING([--without-libgvc], [build without libgvc (default: test)])) # gvc 2.30 is broken in a number of ways and we can't use it, see for example # http://lists.research.att.com/pipermail/graphviz-devel/2012/001544.html if test "x$with_libgvc" != "xno"; then PKG_CHECK_MODULES(LIBGVC, libgvc > 2.30, [AC_DEFINE(HAVE_LIBGVC,1,[define if you have libgvc installed.]) with_libgvc=yes ], [AC_MSG_WARN([libgvc not found; disabling workspace dep graph display]) with_libgvc=no ]) IP_CFLAGS="$LIBGVC_CFLAGS $LIBGVC_INCLUDES $IP_CFLAGS" IP_LIBS="$LIBGVC_LIBS $IP_LIBS" fi # optional ... we add some gsl funcs as builtins if available AC_ARG_WITH([gsl], AS_HELP_STRING([--without-gsl], [build without gsl (default: test)])) if test "x$with_gsl" != "xno"; then PKG_CHECK_MODULES(GSL, gsl, [AC_DEFINE(HAVE_GSL,1,[define if you have gsl installed.]) with_gsl=yes ], [AC_MSG_WARN([gsl not found; disabling extra numerical functions]) with_gsl=no ]) IP_CFLAGS="$GSL_CFLAGS $GSL_INCLUDES $IP_CFLAGS" IP_LIBS="$GSL_LIBS $IP_LIBS" fi # optional ... use this to open the help browser, if available AC_PATH_PROG(XDG_OPEN, xdg-open, no) if test "x$XDG_OPEN" != "xno"; then AC_DEFINE(HAVE_XDG_OPEN,1,[define if you have xdg-open]) AC_DEFINE_UNQUOTED(XDG_OPEN, "$XDG_OPEN", [path of xdg-open binary]) fi # optional ... use these to update desktop after install AC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no) AC_PATH_PROG(UPDATE_DESKTOP_DATABASE, update-desktop-database, no) nip_desktop_update=no if test "x$UPDATE_MIME_DATABASE" != "xno"; then if test "x$UPDATE_DESKTOP_DATABASE" != "xno"; then nip_desktop_update=yes fi fi # stop the DBs being updated: useful for packagers AC_ARG_ENABLE(update-desktop, AC_HELP_STRING([--disable-update-desktop], [disable update of desktop database]), [nip_desktop_update=$enableval],) if test x"$nip_desktop_update" = "xyes"; then AM_CONDITIONAL(UPDATE_DESKTOP, true) else AM_CONDITIONAL(UPDATE_DESKTOP, false) fi # we always need -lm IP_LIBS="$IP_LIBS -lm" AC_SUBST(IP_CFLAGS) AC_SUBST(IP_LIBS) # needed by test/test_all.sh # :( what's a better way to do this, argh TOP_SRCDIR=$ac_pwd AC_SUBST(TOP_SRCDIR) AC_OUTPUT([ nip2.desktop Makefile man/Makefile man/man1/Makefile share/Makefile share/nip2/Makefile share/nip2/data/Makefile share/nip2/rc/Makefile share/nip2/start/Makefile share/nip2/compat/Makefile share/nip2/compat/7.8/Makefile share/nip2/compat/7.9/Makefile share/nip2/compat/7.10/Makefile share/nip2/compat/7.12/Makefile share/nip2/compat/7.14/Makefile share/nip2/compat/7.16/Makefile share/nip2/compat/7.24/Makefile share/nip2/compat/7.26/Makefile share/nip2/compat/7.28/Makefile share/nip2/compat/7.38/Makefile share/nip2/compat/7.40/Makefile share/nip2/compat/8.2/Makefile share/nip2/compat/8.3/Makefile share/nip2/compat/8.4/Makefile share/nip2/compat/8.5/Makefile share/nip2/compat/8.6/Makefile src/BITMAPS/Makefile src/Makefile test/Makefile test/test_all.sh po/Makefile.in nip2.spec ]) # generated script needs to be executable chmod +x test/test_all.sh AC_MSG_RESULT([ * general build options native win32: $nip_os_win32 native os x: $nip_os_darwin update desktop after install: $nip_desktop_update debug: $enable_debug * optional packages and modules use fftw3 for FFT: $with_fftw3 use gsl for numeric functions: $with_gsl use libgoffice to show plots: $with_libgoffice use libgsf to save plots to files: $with_libgsf use libgvc to show ws dep graphs: $with_libgvc (requires gvc > 2.30) use gtkinfobar to show messages: $nip_use_infobar (requires gtk+-2.0 >= 2.18) use notebook action widget: $nip_use_notebook_action (requires gtk+-2.0 >= 2.20) use notebook group name: $nip_use_notebook_group_name (requires gtk+-2.0 >= 2.24) allow regex searches: $nip_use_gregex (requires glib-2.0 >= 2.14) display help files with xdg: $XDG_OPEN ]) nip2-8.7.1/doc/0000755000175000017500000000000013414613100010136 500000000000000nip2-8.7.1/doc/README0000644000175000017500000000074013351443023010744 00000000000000nip documentation Type "make install" to rebuild html/ and ps/ directories with formatted docuimentation. You'll need latex and tex4ht. The Makefile.am in nip2-x.x copies the contents of the html/ and ps/ to $prefix/share/doc/nip2 during the main nip2 install process. Once you have the docs installed, rebuild nip2's help index with: cd nip2-x.x/src make helpindex.h to index the HTML docs and link the HELP buttons in nip to the correct place in the formatted pages. nip2-8.7.1/doc/pdf/0000755000175000017500000000000013414613100010707 500000000000000nip2-8.7.1/doc/pdf/nipguide.pdf0000644000175000017500000573415413414613100013151 00000000000000%PDF-1.5 % 3 0 obj << /Length 451 /Filter /FlateDecode >> stream xuRMo0Db+GZ{:R=EoxB="VaAVHs  vo>0Œ bj)&R{ bKĆmVJgV3^qVcAX 3[M)\\=Xnɀ(ОEa v}JsчGW!_j**c07Mt2ԌTY R%[ōhϸZ,X)9\i/<ŏu*g*jL(:L6 /\%%^:\q?Mrd"~nIUgX;? ׃3#$&+"Mlj #pu/B4ųI,wUt0Bn} ֓ɪ endstream endobj 11 0 obj << /Length 105 /Filter /FlateDecode >> stream x+T0THbw< 443500W013010Q(JUHS2*4Ppr w32VԳ432SIS05316Q073ֳ01VIQԌ kB]CBH endstream endobj 14 0 obj << /Length 1176 /Filter /FlateDecode >> stream xZMs6WH1$v&UOIIl(RI(<[G6 C{o.`aoAJBd,A8DL  ד>Pv?9LfspSΫ2kK]A%w# 9NF!JEJLg$Z#B$N0i @k�Q "܁8{=7[{i`fb$S.UƄC2aH#,j ٮ"GBܑ@aH$jB0(5`۠~Ӽ0-]FAiU,LjVEӲ™HXV#BLTRs6d[is9d*u,kE:&1!YD ,xkc9NܜٝEv'--e{kIhh ?vfݾ5e)werr:2:rH7ɺqtVbTU2Fy'ira[ʲ*͓*-r+RJOF/;ZyZVI>l.lh׋Q #[#)?alf;n)UYϭ*":Aí #7D:Pu%8\Vm۝;P0Oz"H"/O_y87޷Lw{_zOzV7j7T$P_+ ekض۵ӽS|A>+'-EiX(ufʵbiz$(1 C|zkSLuYxmB()GNOz,~sSؖ8q<3'Tϧ6-QZ^&CΫK֦ ݨ­ۖ0~iBBxAI5]`cn|ޘZ&WjgBAkkJ7= Dq&wNWF% {h^& jI}(QMn'U T<=Ptyկ3gxǘ(yx˩I. mAʆ-ȇ`C}j !D8 uW}")vS|WR " Si~?9> endstream endobj 18 0 obj << /Length 1432 /Filter /FlateDecode >> stream x\KSHW:X㘥 KW aȒ#Yȯi S%[Ʈ/dDȠHBH54f 0*Ts0P 8 %%`|.IkyK)!LU;=GG#y#!NM0i 9̣,즹7Y'"C̚o'!*!ӛ4b< 3.T-M:0(HZ܆]j IP%yxC1{RVM' ipZ) O-31s[J%3HߨLj8TzjvCF:jƁC]ޙ\Q%`4F6i5+LX$4; B:#=y?Kmd(%( 5u^$Y d^LC|FD(#lAYS29Gd6A2XQzܼn.tlPyeE2ӸYwo)#Ӥqp/l ,r=Q^E/֢urZ=GFMNYQֶ.͟F1vH{huW0W3.]||b a 6>\R2꣋6Ĺ,tF?| {Te*/Nl^;d+[qF2vL8Qƽo1kT'/Yo p~dyd.0B^&?#$=Ϫ"O>T5O2#$ׁ lx)c_~VnSˬ#PQZO%)[wa# . yҷ`\x,hc*$kkQB|kL/{̅z)|uKG܃$Իqnf93 n̊64SPUv߇Ϋh: 宼I|k Kr*)~'%& ާmO`1ߛXW75W8=; endstream endobj 22 0 obj << /Length 1273 /Filter /FlateDecode >> stream xZ[oF~T&s`u 2ʒn^B(bjd@fD Ӵre45'q޲3FW ( /G [|9Kh9? {XhΫS!%K҅T!c_}4ASbuWX m'=+lkYg:-,fD|QTqz*5p:Gb0l? ơ B?k\"X1p?+ ,{e%XݴpU/U3QSPdw>jkXUk?M] O=(^uؙu\yBq5- Mh;n}n}wo"C[H/sIċ Ŭ_ j mJ_‰j?釗rswˣ 6 <$>)5@ss_V[*5;w^Q'Wq7=K>R!l H}n pަQ64CuiC IrH={x?wZgkɮu޷t7Bu+n\ET@L Gw GnRdoĵ-J7u'~ #JW ޿':(M.N*yʉ0RB H7gK[;Up &р+8|j a-x:>kt,\# P%/·|&?R j-Z_6f"%5zs-~ÒO`ky\^\P)qF)T'~e*N'nbC7Ksݩ?{yɉBak/B\nFֱ,rsZB2}~H6`jІh.?g`n [fY}}}hGnN Fj4TPOPzi=[%笊Gy"c]?+r##i!}}}'n 3e5#2FH,x-ˡL endstream endobj 25 0 obj << /Length 102 /Filter /FlateDecode >> stream xe 0C~EF]v&t7:vr {i .ѓe<{ņQp6WSy"H%IeT=G=;uY% endstream endobj 28 0 obj << /Length 521 /Filter /FlateDecode >> stream xn0^6mNJtvAX&Q߾g:)ӤMթ4"c߹|EmB="p P. A-z"Ha,W#1STИ  Nӌ vTLH?o/,Gkn ʱeb%-'C kEc k({w)ltif/fZ2M֝7ۅ N3A \ˑ@UtQI—'e3q*.PR{F~:&NMH2nNrϹ5uWE0!H?tUt>, :ܶ7=xS5Lg AI 4X":KUTb6x^\BI^L/KXD>!v&5h;RMvG,1BC'QoLlo\>bZ7Bصl^ĖJQ+Hڅr#l endstream endobj 32 0 obj << /Length 104 /Filter /FlateDecode >> stream xڅ 0C~EF]vTp:vr G\b'>xc "2_I4҈rH;$TtYVՓs4~.g endstream endobj 36 0 obj << /Length 1256 /Filter /FlateDecode >> stream xڵWKo6WVc \@wkH%DIn}g8mydEaplt*2xgA(Ɠ4Oゃ \/n$TzJi\`]?z?aIC{+J&p1-7t[Z0NzLˎIdȸ_w^)2 V2E)3 lqJÈ "t7KC]nzy;uЗfQyP ܙPNnA/Tle\ Vt2cv68МeT?K:\)퇧,Z|fִ fg;! MtW褌__ ne2]#s 5^9ָoɱ:󡙜ac &%Anp A \d(;RjN?aMfg0sqzBO=fM$YlG"guSb.IgYpC~,D8]0ktol@ҁZ+[)96,q-}~Ym.C0%"_,a̽d{݋0C D|n7{O4zkkQH,Zo-"DFr} r"9q,߃\fml3'.!钝G]$!!|3K .ʃM}TM7cZ/w5r0y\$|0#z~c3Dvox"('MX*:$ڪjFhL3X:yҀ7M-A + 5\C9}!CU%nswAdL4.k hݔe~wql hzLqAQ9m)S׻]VDDEql"|^Ig 2X|&u\XHl ŨVfQ> stream JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2otm;VYy`Ŀve }ñnuz$zgA=-B72V}iiW:׆%-/DjX! 垟J_@8m>S LK`J aCӬR 8=y<j6C}GAEEaΊ1FES'cZ8n@H{+I&^[[fZ,6A}A dZF-lj+Hq mM£ Ygƀ/8 nFBđ1 v>WS@}VRo-ɲ]9m$FAc: խŲZ"[U1+I pyPx8mk :ۦc~ycw1(p+3s2,2#|uuv3r>iBM3W2~`G>թkگ䶽o춺Kl df}3{`-mp6 j(]B' P>QM?$Z- lQՎ:s^oj^ѭ443^'tBF$轸s~ԧm_GXfz KPZ7Tt6w7B;;iy6?Y>(^5IbU,3 [ZW_?-q7U]Bř.-+!?\TSNdte7 QH &q8[黟WԣNF$Y0AsۥP/GssI;}XhoEȺky1U: Y>hf9V4/$owp#3J 9c?Iu^_2(™g#j5 xyV!0+ББU mvb|+6sҜu;/s3y{"qw4Iq*6PvJPqЖfY} #c8IV(Zѥ* Q)l|p“η5ЌHlc 4[BO \ yl49V7}ʤ\{W7V5 tTc4/oX`㞴tbꍡa-K kcqE ]6H'\'EӭWݽ%U$71, s*n,\f/m$h 9y#4]zx"{k褗)t r{4z_֣ I#Vb_5KVG7+HpEK}.;;._>[,xT,H99hOaX^M爦Ǜz9R1۶;S0 }3qrc"VcRWr0`dw=1XkjwWnDh 8$-l8dFQ;Cq ^Fͅճ^4m)ȁ`@Xkogec$ktѐ#A/HVٌZkZD6"nF|Lֲ5V]D@-J B&NORI$$wKo(E(((((((((((((((((((((((((((+g)WAcpJDRJ+DRJ*-Q@XVXP}m/mf;e\38_A(:V?-JEYWc:H],q@A'9OV?A'@+Vu:;{۵ ev} kTԮ<`1yDB(e,{SEs k,vRpAkѭ,2hNZҾ?-EWÿ?_K8µ3#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / Ԛhy[lqwlg \ ).B`Muc^hBlX&t6k2V ^q:p?*5kx K[.|=S$r6A WǍ~/zu#R<ihW[`hW[hEolop5kv˫zTQ`\χ>; W iZ553]0Y]7 !vZWcԑ9Ȩi ]mtӳj=|][r}5} M6JVEAO >i?PRQ=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@,.-whc8#8kfea2 _V9ߥun?'IO;|ݍkxщ ImiHNw>2 _bx(%5ʠ~|[$siMו9qJ#F<iW[`hW[nEoloqZO]\/GU}:jߍ2vW*>o>tV^yQבGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^smC#.esHK\yLk濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭yͪLk5_ XMUp95w'VX'V[Eolor~? Uˏj?iOgm?ZΧȩJ\Hh=aRdD2U^ Nuny;[ۖH,zUufW1r nyȪگEU~S˔vN)LEq %]zCIC6?סמxgF_kliG (5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( U5}U k+ ?S?hW[`hW[tEolor~? Uˏj?iOܧz+ JǑQ^Eg|̽WGcydHbyd`1y<"F%U¢fj Q_]gh ~?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?q~:k xduP)qA5fIh5MXQEc ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( T5}U k+ ?S?hW[`hW[tEolor~? Wr/ZHcb ( zѬȹ׬ )|qA+x#NuBjy zӿjeq[KvQE1Q@Q@Q@Q@Q@Q@Q@Q@Q@4׌2:TidUr֦0*Š((((((((((((((((((((((((((? o_ozMyAJƇ:v'VX'V] QEc[[c[@?iO!k/ZjC$dz#Q*:(LQUoiVL4alfwFl7W6 qpnZDT,W.݁皱}@+V5UWbW_.]EBEWbW_.]EA#2?]uj9_?Ge_]?/ur/ʿtl_ ժ(i_/uؾTQ?ȿ*l_ }@+V3?=~?UؾbW_.QG+g{H"̫}@+G?]ZW EWbW_.]EA#2BUڵB3eb~R@(W袪133 (!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^lR&? o_oa?CTz;}J+|t J+|tZ(ұo-ұo-Oß4Aj/ZjC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( d5}5 k+ ?S?W[`hW[tEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW'I6O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((? o_ozMyAJƇ:v'VX'V] QEc[[c[@?iOW_vԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE k+k4ɴ: 6fg #QJqn_tSU Ž]S?ԯҷJ?ԯҷJ(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((// ]J+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݲ|Jݲ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((/? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݳ|J髙ݳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݳ|J髙ݳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ܳ|J髙ܳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?}? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܳ|J髙wܳxJ?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O}O MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܴxJ髚wܴxJ?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O}O_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s^.+kriW[`hW[1 EPzV>zV>sFt-]q>? WmHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\׋kwܴx1@z'VX'VLBEoloq:.!yL Y2 ' rG^,ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG{Hm⑑.2jpkέzU"Y?أ_*z+CY?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?خ2$ ߥt_ [?ԯҷJ?ԯҷJb(}[K}+`}[K}(?tֺB q3,؅''_ι?֎뫘&2ܼe{pt,N3Ku]bK'm7}Ew8T8r+JYbi-3>a=+ =FMYu핲d(NcҴ/.Ak}M?3"&U>a#m<⎁ԩ Am5퉆fPiڜWwVoq Up9Z}WᥒX\Fc@ tUNTk 9yC9n cL] YLEv,? .{m}˝y>TX5]$jֶ-w ĒM Lї GCfϤ]݄G=a4%I~E%}멹k%փ&!d,)@#2:-7 mDWdTX&R _Z]x*[7ڛR\RXh,Y{iyR~ }~"-OiE$:T嶎܁N4DLbyhƒǿJ4>2[Y-ssUfȰ-RDA'~c:,so4Nee9lMҮsSڐ\q֧()F[q_z7r^`!r:-5}ً!u[nO͟ӴiM4<Y}T0h4{?G-S8>U& GRBO6*B~qۊv_~ (խ /tudqǡ5oiQp֛ Frpyk G]MWku)dYLИ9 9:xY'o/JQq`8i}:彨ӖAF6?($p="Ė/=6;r,~8҇=]GO=?IO-Q7,hfaV'rsxY9%n^QA<{u\Pi6zwA6a/2GqkRK3}`{s2#BI\zw͠C{}&&[ $H'uFp=|wFdF@@})uil|:ut_-$1ppx8U|Io%?d:Sno$0Ǩ3TgVƮۀNN=Z>KkSwMџsRZK8O2Q$NWH+Rѯ!BoE=x͍ϩ^x/}XzToi^c_OO\fD_P qEtg ie_^XG5j:$X+{+c֕XZ0(S;qQh>[+k>͛h2e MSVv%;m:}>3_o/˅8]4ʀٓџsXڇ+ϳz7\㧽TjW$fբT4IaNp{Q:->{wW٢:nL5]ۛ˘t(^El)fDU^q O&<]9CJ=*Zq{[_OpI茅Jb:3/FZf*{p!`y+82{USXoEҚ?-Ulx'bܮC[Usޛ/ȉ>l ojCeeI\<,R&s zA٤-pdBiK@N=뚓Dԅŝf-dr+)ϭNxv.lU펞$sܐ{SWo&7rHvwq;!A {Zp H0==[cj)kws rBZޛwB `~Rֺ&dDɡ%$˼X ~@'߶ <^I^ > ~@'߶ <^I^ > ~@'߶ <^I^ > ~@'߶ <^I^ > ~@ήp9FOk~ ~G ~@EyB``p푚e+ҳ!:SQESC ( 3٣ (z ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PIAet(hqRQEQE endstream endobj 40 0 obj << /Length 252 /Filter /FlateDecode >> stream xun0ELLxIKU !<B"QAuFt,k;gcZp:6x Xb k>'!Q<<+@)xdw>E=V#|,guUeՐ\> stream xڥXK۸ϯ-TIdnwqT*DA3!ߧ P >h4F??K’# IeSeQUR2/eLrH>? X$?i /rxlIdT^3lɿӏ'}d,R/JpUEZ4<':ݣrO\$M(p,rS7n2QWiŁ}Ըg}|s7x~`:EQ8LgMaߺ|;`0sm2VECAT;N\ ӯv]V|&d^4Utķ%B"׆f|<ٹ {6ө8Ti= 8@3w ?S1ޯtu2bV= WN4[Hx ]}'@ 4Xmy/={gc4Z1 U$ M}$G^m.}7' [g..F ]aO8wDtaYc>.mޤ LZ]HO-Bv_bÁdk6@5UJC5.T3&ޝ3^fl=UR0W*ec,z^ Wvyr1Zր 5SQ#z Mߊ={ ~.K(qzO,aZh 9NHt׭`Qv 9$w4|y I7F?xqFɒmqnW 0{w+c]H,#B < y<6\5/^DBԈoT"λ>p[Huϻ` 9TX;0nME %omQhL*Ѓho8A헞^ ꡺ٳ*r^,U}7csIZcjxT/*C 0AiH-6Vh1 uG8@?|M4b]`)8 $ v{{=`a\:sɾ[u:ţ OK0}CwP%1R%y!*7pCdPj)ˆ@4r0QfW-dxիBcxV`k3Z,UާU tĎE#GT҆l.XVWh< bQI*"H"vd&,s1a :1n#9гr ^!d?dw_)i; {{*3\;ۯ!pߡ7ZO` ؤH/^wQ.S4D1T$d<_0Xt4.0DS6!R4޼":_$A?YrsofR xЊ,cx:|Jxqfo tu5gW@>uӉ(jj<Hޖx|A./7zqoi,\RRV=?|yyoH?U~3|yvϮJP,WJW5XZ#um0~~YV))IS#S[Sf5[>VL)~0|IgX\,q?jg` endstream endobj 41 0 obj << /Type /XObject /Subtype /Image /Width 739 /Height 534 /BitsPerComponent 8 /Length 32715 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJUs}}謽=syy#k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZzV>sFt-V|m.?e? Uˏk: "r]*!s $KUU{X+u9պjonZ0V!#SбV*՛]\]'r?%^dw]Y*;0Ռ;K6kL0 Ř7Cᵂݘ F_7`v, n|d*]WuQvG%Oq<{KFv fQ+HA$j)Z[xB j;C2ŻVT6 F/Lcm`bg@<`v$| 9wxn?j#Y6vҘ-$VtJlM8W@Ł.hX*Ҙ8gm;:fmg~$hCX6+IWPm=ʖ*],G1oǛ,ݗm1*EQ1>Ro"Wj>RiVyO.S;Cm0VR!(Lɣ@КKb7k^Ʋm\ڛ4pj ݎ⣂ɣ %<4$ı\<2cVcG%BȪ2F8'ןJ[hz…j:M;/VCI9fCqGv+q?ik,F- Ď _ג:cSzp&f]cT&%bȡCyŠ((((((((((_I4V$5SQk7Kf{S[ng;W~xeOa)pcpkm8)sj@52jЩ:٫K?ljkZ ?QVXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWJ5O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Z\U9#K;]XRWV<֖4dWuVsp=xMzp+?ce|"sɺ|W'M0t{/0>g^x?.jW7*c$L){/0>gQV?,+) |E8+$ (5v-ė<9oj=~BIyTVk/hb(Dc&9$``O^co;^ʄn[(Qg73(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO6/f;k+8b:aZ5UbQE2(((((((((((((((? o_ozUyAJƇ:w'VX'V] QEc[[c[@?iOܧz9#K;>յ4E!E&# ; "Eep3*8A6LϩY*jv9Xd2!4\wdV5~> d }lU^X.Yaw ;s蹬-CLto&FmgY(#jpzxo_HkrN1 Y'W:K<:$@ 1ZFKxxk3Y$A>v$cB*mNgYؽ[p?*]uCk/¯j:UI&F(݀,q1*3XZӖKΕ.eb3Gw=w:ΑY8qڡ׮FA8 dX1.J|*8Ljsqa׹ $Ե'zӭ&F)Y7ss`)[R`g@+@jao=0FF+1Xђ$gIhQsOjJTJUbmwL[Onmn[lIu[=B(%Jf;m '^Jӂ-Fknn';3 +g:^iYL\H6|u; -՞P!eYa:qXA:׫))_=S6,v}⺴ͭvK04Q g=꽼B.e.z@kInM,wO ;pFzʝ5@Uی:Fm~33«Er0CfW8T5PDۑp3K)l[Vuu3tǥkwdž8vWg\Ñ̾MuQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEzWYmZolV!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@yAJd5}uRwO+Ұ4O+ҺAhJտԷҶJտԷҀ9?NxsFt-]w3VŮAvGdzc^U jF*Zo?!LELnLnVN☒C!rC:Pz[u^/l96 󃎾3GwlM"Pl;ٝ(fkzXhڥ-_ke@p  J,zy\M*B)ʲТYKɧȇ`2@o'9 p8c!`D"1l3$䁊[ 2Ĥ%1!BY'${ſ3-/{:ێrqr*];۠KR< GEH>0 OJGŠ( (((((((((((((((Ҽ-"͟Cj׬ ȳgڵ ((((((((((((((((+͓@ Wכ''h|COXo_o_or EPzV>zV>sFt-]wß4AjS!]B%G7O"Ѧ7Jy7J'Z&Mib1+@'  jְW0UpNXd[pGzLg'K]Nf6$c#$/Ccv;/ fIn"l I ۝l|$zq~&&h"  #+d H+2}~=E"> I\q\ʝ󱦒zhvi @0 $FC63PK$2_L7ngV[$ny}4eZO{3tK; #^kFⷙf9Jd}Jں5/!XBi3,pO,q߽Zi+ɩkF 322r;K{?e{\樮mYU ]`)b 瞝Sm-AS,.r@n> /d֍3F;pQq1r=Fƣ>g%P̛.7ln*)~]Z颴Ѯf[-2%<8zǭ*[rH'hX!>w=sWT,hnۛaapvYh0ۥįBrF![sG?w2rWCom\h5pa,.7Ln qM_GZ//4Bcf5b[-e CPN/?bSc{u-pG<ɘ~ӌ>yߏ]_0/Q]>eMdԝ?Jei- iYpg4,}7k'9+6j2}w~Lgv(s3 ɵi-!+xn#`X31y⳵˖0av*nqp}t ?nt ?nic_pA.-vp0iP c c^qVmE+F/ޤ*C-#+z6k(6k(񺧇n-?*-v֬sC/<ÁzRL/&$Qٸ]`xǩk(6k(񺅅Vw}fjdDi#$h̗35ё$198$>º͚t ?nt ?n_z34 "OuBc7ˌcO=̺6cn"X{8f@]?f@]?0ӯUr\}L֫n[xQNz7l*;P[& 1 ܈G]#:u555 M_޿ o'qk-(J"3HϧyAxݤk0fnَ;G? Qtl? Qti$L}o޿oݧ[kgM϶PŎFj\ڵʹ֬*MJg,3y;WAX.GѳX.GӖRVobJݾg!^mɆ[]\>39|tQǣL,#͜&$ bN.sy]c7Fc7O?? k_piż1"\ƒLUm߰r;jvmjKU0#!)f)#ۯw55R+~q~_z3/ZyuE[HayAI\ҝ={E<^b6'b0C]c7Fc7SykOʦt<+geb3 d8"qrՌ :j3L͑y={xf@]?f@]?iO[_q'NԟGӭ4R.BgEKgh^+k 0Ld|}Ӝn"Ϧ?̾}+2!+YL,[_sZݽ ń5+*H#*H8xwQL9$oVi#1'haÿl? Qtl? QtU5~z30j66e+UgC dcHa+ir f{0/{;Is޻t ?nt tkg0je?u5W02Dpv0V+Ѥ#i;QVHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW'I6O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Z\7?iOܧzCESQEVw?\O֍gxEOdMLiK㏪}`/k N_n[-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEaiQ_EGW: o(2 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( m+"wNϻn1Wq\NjT%')NJ.+g'VX'VV@QEc[[c[@?iO)9ß4Aj pp 7Z7Zp}aqhUf$uTPVX%lXs:qd&^>gl/E?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|kL?kL?\G݇_ʿOzi'zi'QW)]M3dt}]M3dur9v*e?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|kL?kL?\G݇_ʿOzi'zi'QW)]M3dt}]M3dur9v*e?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|ʶ6[3#Oq1] `g 9TQTJRrwaESQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW1e1e_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s/_]=s/_@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3eW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>.]5s>.@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3iW3i_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>.]5s^.@z'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW5i5ib4O+Ұ4O+Ҙ(=+VRJ=+VRJ9#Kڸ0((((((((((((((((((((((((((((((((((((((((((krtxZ =J+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܴx1]-s^.(ODRJ+DRJ)Z(ұo-ұo-7GR$1)O뵻eC\˓?II?|QI?|Qj}aܿOteC\W(W(>ߋ0n_sr'?OuyR+yR+}Zo}vu/9?k?]r'O>[\5}.?k?]tY?޻eA =Z>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'޷())r,@֭W QLשUZoK u}>e?pb1 u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}S"O ȈK)WOX^+\_J+|t J+|t!hJտԷҶJտԷҀ9??Ak**1RȭX.{rx?hk;ۃ-ZG GBː=~wU.2vwW|x Ls"e+f<.ҰcdՐO\[*Id 1}+BTd2*beS98s(J0ދիFTrd0qW4N[E*Ywt״hYD]WrGRT @\mD܂&O1llŐV-'ێi4Ro&]`G, q\=PykwÂN*O\ͧK{ r|ƕXYO8;/BfZjZU 2C8Кѷ8kM 98<5ګz5Ⱥ,hLpGPp2q}lմ9`6r9Lu9S<],HY slWf^Xiyh cr#q`q8imKXŝi9\ pgiC.ŧi(ɖ430+na񓎹֏@^eI,z^גjn(dgrǞ=^x(4=B;V0n?ΣTՎef=u$NpGA=;fn=\a-$Vl:VWZ_#GZt >;x2Jr# N>>:@/8b8<u$)trȂ7gcfizǁ}PcWmo`W'' }QnFu%юHrhϹ-|AGrܜ['('Bwa$pyhcomuȏs]fgԯZ
,q*[4o뱯L'm.KKxI"x/ G:U4IJ\PF#ؚVMyMJe-P)wOe-x͉@2m&;iOe6q>rgBޜf}ZL@c hϹOmCzg\ǽ{JqުxHֵ ˈ3j]C '8=a}=ƻl7&Oך:N/"sIp"R㪯8I[xVHѮOU]HJ-[A -'{tFB%X1yw-3O`ϰ<DA =*][j7A"PMuϖq6z 1nWUE!-*䁌MKDhF6bmg{fٍ_z5!.xR9[ =zT^ pO2! 4 'IjBK 3`2FO9֧ki<;zV*OX tz~nH=ɫ]|KCoo;];O=ȭ8fHPrWz-ҵM9!hoM?yC) ]f2Z]GAdmfec,H}zsE]A>BͦcPvFw_xJn~wtPfB{V`]V-{.;)_`{WVzư-t"-!W3'WS^:^2up?4y0;A4]KHKhO2!4PN=U?F,<"Ғ[ӯJ4_C[+6 k4)2+Aݏj/&HCS,@ fsUA'U-Q1[%XUz8it4syQYXv*@ E[.Xg=\r#PNNAZԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]ݬ/./J+|t J+|t!hJ17ҵ[Њ))8OWmj6v򼶒 `W9qsecU?Rrzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_OYgWh8| {Ե?l_O+FȊ* B"ƊQFT`+ ~G ~E",haUF^C^ > ~@^+}?EyM _#϶x_Q^ :Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Ey> stream JFIFExifII*JR(iZ)( )( 02100100g4C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222224g" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?3A#'.4̣p-/GkWy&_ RHk+Xŝ@篭zגԳK?.Z{Gp=o_Z<%g>]zמy^K N}/?G-;O]ּ_Z_Zvy?iϥC篭zגӴK N}/?E=}hּ^?.Zvy.yG?!tҴKҸ篭zגҴK J}/?E=}hּ^?.ZVw.G?!tҴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-_篭zדѵK?.]qt\X֏=}khZϥG- _篭zדеK/.Zu}Ep=c_Z<'k>__]-zǞy^O B}.8?hZϥE=}hּ]qtеK/.z篭y7- _k>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-O篭zדѴK?.ZVwp=g_Z<&i>]?!t\Y֏=}kɿiZϥC?iZϥC篭zגҴK J}/?E=}hּ^?.ZVy.yG?!tӴKӸ篭zגӴK N}/?E=}hּ^?.Zvy.yG!tӳK?.^z篭y/-K??jYϥE=}hּ^QtVu$8k,>)iSN̗6oWhXנZ^謌Xdr )Q@ \y5L~C\?+@%HŤ=wT*(R.6[pjrںYNbԞvßj ^ݶXTr]?MtuuPNlȔ/c]:UoI.c*H+-t&GN<9XZ>'5=RMixLPsi'Z\mv_tB{)lcbT MyK0d8B{סpgAFڑ&?0؆r OHu|w4_/5ys:SZDp[Ex8w'*;6FЪpT^y*[I,|E7/$euIϔO4ag8[}> eqmsgX%$@$9?vc?mS%q!s/5F(5ITm5tK߯4OmyY@ 2#ڽa[_x= [Ŭ)ه0MX?̻|汈F9o'qVcz6Hٽ*s%-uB7vt3b \^״ Aӷ;Pd:OOƷ?"NuIĩ+"r#@sHVf VAI{}wO9͐EV&MkEմk-*'i nʯn?G&m/t4O ,Wq)]~?z6be-B o9'8ペ;mn+ 4-ᣀ嘂a1ҸiiP[IJNA96021hǧC;u-nDQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuKIHR9¨PD!~LnsZ% Zvpמ9z]rK-@v"Hǫ3VKB;_ Ki\k2zb:}Μ2mȽ >% o5 L&LrqU[Pi ݠJ)]یh7zfc2[uc*}Sw:u\GpP/v\dy|8.۵RO=~Ǔ$1vϩe{Xe]4^Ku{7ÝFI|(r *+3B&U뽟Up(LԌh#Rb_<]=G=EW2Hހ$ݚw_%Ld[x1mAہR,d$Xvy<{:R7)Fz@ 1JRA(cwRd?=T~Uq6DL&G@NqZ$ dzRα=ޏeȑyl w''8Pq:{;227QQQ_ʴ".!Ц#Hi8Ssw:mr@Sh ='Wyi}p<9ŗ27~},T-վW8?EhjG'}۲-[܌j@;OP _ʛEZ] kk$Eqیr23Z>,n|L"v' k7f]ym+]'=MZ=ApG8 ˢ4(Q#2~G<zenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@Feԡ Atj#řR{z(wĻQa~ֹ28iaUh 5$d֋R{uFgYn\bk*~IOΝk~6?֨;/CE_Ҋb'U뽟U]NK]K=rԶ,P7c=j{>|1SRVht:[|ܒIS%4++"&gF]esS\kZs$qنQH1cHǭ8kʼn)EBʧV u_gU2M3S@~#ERvwW泏AYԡ:{cnv;Y<8CCLL-=wZTe<;56:j_Y @YiW&x.綆(j\ Qw(!*ιY[X BnC:M^ nXy]ֹv{Im.'m=sqOb*姊 y $ lP8# kFn2pnW)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW6l*Uk oMv_Ҋ,O?5xS{?5xS'?S)%,Nߓی~"_KJY<-n19U'h\d ?ϴ ie$;R4ل獻I=z\}mnwL?/R&]LiͫNI[9C6y?l:u#3 ҩ\IP֙`(Z$=CrdREiSY= w=wM-l^p׷<4kå2MQc[8mI0۷yA򜑞!:92_xc*w6sn.b(]QgcXKw&k&&]ZO/n : [[O\[v"63$2rI#y`Zt,2)|_h}SQX,g}Unmr"8̝c9󞆝o؛IWTѝh-NqLIsٮ.#c\dwNIU?؋ x[V/uRw185[;IicW,|Bg'ⲖM;A-ew7M;L ^@ tKI5&;Hn4)t '`u;S_]#[wvEKWG6ʹ+p.R_vZmWFeVGFާkӉ.巻]?`wYD_嵍Dǧܾ% kx `B f1#<:;QQ帷[2f26{к;O&(a15{]jK !iJl#*|W:4Ifҝk}l#9=Cgogs8 y%)E-8Գczz (>Dc#81[I~ש{ n纵I$Ne$sL+7s= KeHT7D9ߑ9Moa_Ky0\},vYWjW"Yd1K1:U /IԖi`Ծ$r,1s={R[Z%O5!Yyk HjX<јو츒5#Q\-m.f'6# m,|dj:(+=_%R*Y,KEHTL?/W:_XϨItl<)T̓98zfGcx4jBHQe$&YN>c39WlzgHʥŽ9vuj@4-G{Mɧuo5@J0>j;SIӧHn(qN8Q2p*lbc\%M8/8ϭcjvԤNq 9GW'/t7toŔ19eOfX OI*c9$tN5Qswl ZuPux52}OUXCo4MICFS'jKPOu >e9{:l5M/RUUChi@uq\̺NMly}4ZRFp\SoSWV{ dZ<BF ;h^Ϊ5kvecy6)IZe{D_fy!ٍf-9 ̈0R zg?Tլ~]R^"@Kv'?4>Zؚ-oEkxPܫ w W'=9V,u (b:؊Z./o-m vl`@gy0OM.!(SvH =Y|[4/ɂѝG6KM%ƣͬLIۆA9zSz6-6?"Ҿ/~՘LW}ٍj֟jhK@w ^MᙼwOUԗU2XNWsן ^_wuGQtɝqA8zI&"h!bpcvw$RcEEAgov{1F‚x%NjI".J\{ 57@g_ڿ G,ǿ'H`-ӮVe`$&qtQE!Q@6HX9] B)P{K =>3ѓV(UQvb(((UjQ)h (jߴn3qKEQEQER2VPz2)h((( ia ;7H8)iGQxȒw3Y^.;49wɪݶ [Ya3}a;9#= IVӾkXh8w8掗=xlb L8=zָ>OkK8^l0vTR'$2ϰ|W. ;;K]MdM29 }q5~n;REKyFxФ(cw}*ᣍ/Pŀ,i8'S~`vWi֍srbRHE:[.< \`rxp[͔rRT9淑ִO}- zSM.#g$jo3nOb-YZDPZڗ Ϧ +^ ^wWhW 9w?>¦D$3u AY^(o /$Qk+F̠;#ң?vf?fo[pnǧ_’wv4TTLkldX$a'zu_iڭ4Yڛ:]2'00wS#T>Qe}( /zg/zղ; [X\ZM,/l1Z;je;@e?Zf,C|Gd= #5 L?:͞u ?1-sTq|Q?8N}ٳqpG]qхoiͻ6w8#F<{a?gXeI.̈?+`Mr9f :n>?0]=&nqpîFx wڤK⏵I>rXɟKߛ=.Xu?F'%8\OgI?RϥX']K=.uxчj59.u?Fx 3N$h2y)$?j}.?iYj1KovHDw-.H瑌lcw~9=ڔXg$ >_ qz&;I>j}.?ɾ)#.fxMgO~lw?FЏCTq|Q?=Z1Gsj']>ӏ]iNowv3Tq|Q?NO}h e8b H'?N?0ټib5sutbtuj}.?>'\Ńi’H#͟F^ПwKu~sMdU_j}.?>'\{A-j6sw?1 CvDRluݟ2VzڤK⏵I>yS|oݝ3ZI@뻧?F7O !!kv]ӏ~taj}.?>'\3QkYlc;x~3ycc#>'\}O+?9ӵ=&]щb\(A9wӏsҾ'\}O+ fSq9wqш⾆dxΟ|uO)5X✝z/ڤK⏵I>yŷŭۦg >X}ƳN,Kwt?Lg*㤙j~'\}O+O\$ wtF(LX[@s\}tbV&H~§cTq|Q?. 'Z x#n>qщOR>?0}f>'\}O+d6z\w_i-CK:n>?0}j'\}O+o:[n͖3|Avl=.뻧qх?§cTq|Q?(L}ٲs\wOO8ӟw9.뻦t`oi6w \0>qуt=Na?Rϥ\kMuݜZ/c󜅜֨0{ RϥGڤKq\%d7x0?1#66z\0ߏ~taj>'\}O+>4ܰ69.u?Ó6kH,ETgvNwq1p,Uuj}.?>'\ȟi %͞ :S;,>{z\뻧?F֨0{ RϥGڤK#==f :hS+, swth8?§cTq|Q?+.F}Awt?·=C#7G>GTvj}.?>'\Ʒ4;=.ѸkxLbj8#7x8?§cTq|Q?,L|P:n>qс{6T=Ni?GLmRG˫-,˻"cn͖3?vls\wO~t`cS-"[9tTq|WX-C'9uxC Iݛ-Gw\}i0{ RϥGڤKSI`Oص=.>qс#-6Z9.>qч_ƧcTq|Q?$i8$_6~uxskBU96:ӏ5ZًMt=RϥGڤK0bvsw|}Q㯆U[MֻlutcE$%ŭYTq|Q?#o>m5sJ]ӏO#|znΙP:}2O]7l&p=ҹ9=u8?u(X^."1̀36r<`aoNWh# yB;{/CE_Ҋb'U뽟UnUjzYJ3+ޣC!d)@5VQ9^:dxF-3zƮȴta&WzAdpW4YqZ,ږ2KGg;c't)G&*e=gpf׉tZ- d D~]:gO-S%+xݏjT dnӭvsmF6I~{O@}`S֝p>ǭcGtqzzTC?iTЧ#V@B8Ӌ\Sd9>Vi&[՝m2}q} CFw+PJ$S MI[vczm;R63Ir1I'+[jB'Ok$yӉ攨*a 3Z1Uojfb~UݰlJj{6TY[lg%W$v+Yb>|/ .?c[ (J؃^{'ASAbv J=*;)ڬq}[Z-nWE~9'wK˔yV23@GXacY4P>B1WDnOsleBxsUtl-2\QۼɅԀ=R6s2 p?*(kRV5ӫm+ rbw5G%/xbY9ç85cٯa/&xX) qWaw,pG?&7P023OQ5ut-A1J4wg@GІUVe{2_ZR1{PC eH縥9;Q ${8'6^UCCZO|x!EZ| +.1O?ysMB#'=n#0s֖& y?$0aϥqiyn@ zvsL`zq#c!3& $?Z'K9ۇ_KaϽFG;%Npr=i'ӷ=s <Ω 1 g'ۚa9˚Bö3GLCOM'q: 2 )Tz`>qdE VhS$ 0=Rb*g9WIr\d+ׇZ܉EpvFN0~tZaLܱNkӢzF})(-ns\xIwi#n6c7f .2ma:wBPQE/zg/z۷_ZޖRǷ#o>̑^n*m,ӕoQӡG+ifNdxr)JZA5e=CA⧉ָ͉+NϯҐZ03Rl- 4Bݢ"[yciO=#cQf@q}UfcND!qi˰]c&d.Eq#FVƬqJLlB#ڭCgP䯦?kY7n+ST؁"hdy/RcFrPW7h12G)ԭ=¢mBض<|^E5i# =>aSꬤkE4SJudU34eV߁+'!8錊^%Rq^i/.ĹK{D0ڥ(;˖JzQ,?N8X?~ 1[xzK䂽O#Uc"Tarjr3TfN=BVh^ۂ>ңK9ҒUW>Zr (NaC1]nNHS*ZqiܶCI=`W,ꘆ:V20[ĸ2q!kŗS8t$#?_–1X\i1NʲP.9|fJC+ZJ9;?$dĎT kuӡ \HM+cy!*׷0ܤ 0U<[I3 #cn:s|Om 1JICۏƵ8OUNRK23l ;tRZ?B ĝs׶=Ͼ3R3ʥ3ƊHh!̟zyHz}A!` z›t홌[de w瓏¹y5 Մo$?|GQ@^QwA?X.ltA#`JӅazUM^2xxk 0?y{;*JNN:zκT⮻O\V|uxUb/x{&p ~?\R(jkzj.$2A@N(p{z6 3i&6xV9qjv+4Ã2Q `T}ZORB:TA\A桿b$SfzdFԀzTQ+9'tⅽ&=~^~t3Db:ti%cFH@)zri`pZ^qMWa <ԠJh;oƒ:xaT263jv8u}k.]\ҩ(㎝kХDo[zԜ"rsXsZQ5VT.f7qښZf(4Z,zqTaR+P|TdMH\hSZ;N}i}ۢWeAy,CVuNl7]%[PjhMi\I|?bRʇ+>kKӛjä6[8KH{wiɶiy%}s0t̴DEQ*?CIZ嬙[9ۀ@Mr:mZ@->a礋Ϡ=={9~_.6WQlPZz3S0"p zJwZxb,K:C2 f1;q㋶$Kְ|L!+ s>⚧)ik#u+.F\[Op{|Glf`s4HA6z YoIT<7\r@=r[eMhʯ,vעR哉fE.n(8޳ﵭ3M.ݹz|'-(t@eGRW鶬u Jlp|\~/ l< ޭHȖ͘jJ;LNNqܹ@ 8Qk!|G> ՃX0ݏoʳe Yl¨(VlqFf.">gjtѤLD7BU=x`,;c'5/wrGkH`{-֓4XgHč`zFqh9#Q"Hqǰp(g'J0AvGLќ'\[H{JLM$/VX豣 ݜ5&;T):sHOqڷ+[+l-$xdhvmpq':k޵sfpAl1Ec7$`Bfq=״67-t..$h}x?{W睂^W,qM a)UsP4-xeQ=9j:α۴Ē6n#c޵sj*sZsA.o- 2b@]8IZ搡yYomr$9 ݴ{ .?VntƄ,Э)l.dY>d,ݹdxբ`ѐ GlVl>᫒-p-\օpn4ffNzkj^gҳRF(S0Ole`*@$!GM_:=kj6ORv(le+ 4yĖA1@:)sߝѢ Rk,Z* F'<iWbI.]v+x/mMyWZ`k9.W2'G=rs+)荣wVʦx pG z>?@L $ueC331 |zz'-9zfmv2; HP|Þ!*_xU@41xҬl~9ǭmxOJ]-9LhĹ đ8T| whMl[J~~^F';J%iFkbh^(L#OIzObxOc\5)9"0k|]_oOOFbp>3mt )l&%q:|/' ^r٠|B~U#V6k ÷8k% ʑ#`{''vnjt{ۢ8n[<Ɠm(" Spw澴@pg!XN:ʠKck(.֏-P}A>BHѼ `/5Ϸ_7th ,+՟/?`?\ك^*o=Ҫ]K=זOQI חg3r~S֠kt4$;WTk376ӓ}*##t_ʷL ~lGUr]4sgG>HS6y!=>hNc],n3ǒM$V`Je 냊ʭg5bWt*ضKd{ӌ1 Mgr~@{"Mׯ4GN)/o׽KC@3IjO' ]cSLF6=hǏp)Tx'۟G$ cGJi/֕ Yy>~Gfjͽ&Y̠@F$ִmj%a^%y#2ZCKI]R,GRq@ZIwi#n6c7f{ .2ma:uB/CE1 p^*T p^*Tn*m,ӕoQӡGww7QHʲVQ9^:d| Ypdrj\JQrvGqvgd1O ݫ{LL:n[&d'߇W|D;!,{w+g_Sjɛ[ B6TDIZ8Ze`XyA`;DŔ_E H,t ljYu<-T)G+ne}rJG8O IRoOO.6/W>&}aW 8}3E2VFN_gV\YI aANϧoT 欤8G_zI 1FNXwFlMw?LՇ 3`K)?(2t?j$*vX撖]_YcWPXG [^4bϣ[:$VD0Gwm -I> !yLkn%Dwr|E''8v29$m/{2 wFx}9 @flsNxxz+Β.rypAߓr8Əwme$ &'^׿pTث,nls$}3ɮj+ Ą,Mliڕ|y^tL0=N:g~56乔Ey‘ۂZ )$,@Kds~3nҘP2`/r9`y>ƝbO s0 *$1 .f*2ci\;TgiJO,FWUȤAV?t1I͇)gN N W=2Bj8S͸;{wz5.Üiք:Rr?Ϝ;7\ZΙ҈40Yyn:$r+[aZMr]-Ă8I-r~HK9'zu81N!]'U$rUSLܞ QxIwi#n6c7f{ .2ma:uBPQE/zg/z۷_ZޖRǷ"Rq\_ZޖRǷ"%ePێ=L)$/DND:S"@=A$CXd¤v9hŘۘ\LG:~U<=fQ%лQ8*X.aA]d>[0݇O[SVGxZ֌gei2dHI+V$i4O(U4ZjS}GTQ+E,Iá #R⾂|M+1:aϷ5#2`>L=*+TdɫX }|v >nԚhD5ܚM\9:S.^U«@RryWW7Rږ$lznnJ%TQ4ކ5_xD>n$\|9o:OHCzqAnv|c'osV[`q#Wv>5G TR0ש|GO'W9LڋY;X72zxrbfܓJw.|) .I*7#5_I˰ S,ʓeXt;|yv;O5H>X.B1yQ?[isPcxf9'#MʄeT'7}3ɩxF̖``l p[L#⼳ljK3mb}F+(~k*baNn2?CJ<ȼx0{{\3 n Ia[$ȥ7˞5`YnθUT=7 &%si(Z'tW*T E\]ڹ%KhL8WE! ٗj>h=#?Η,J{mj'= h;ebfAy\꘮MXd\֭6ݣvQjn'ݩ_`u(6nX\ Ci RC*@07A9AGB)a>] R!}=i$sҮl GsHF?EJq&HϦMLxnԍ + rų؏RG\Tx>brLsHv ;ULL>mGը[mȋz~qq v>c#${O_J•ny4eO&'EmvX^sT-L-9vM##9 ƅ'f]gw[O+ 4R2N3ϭy^W g >˪AC qzaqXkq xkR/m<.0NiYߩz?ž,ͽsȷZ-dː 0gb˩%rk5 ͠[2n4z >rYY'hb62壐.YO@1pjJQik[+9biB_'8=:JבlQ:p ۗ'ӍfД12MG`dA4i"4r(dpU^j:?SgٻA+d#2Zc6ZW}(,GqՂ6+NgGf=!)i3Q<0H (^NǜnȭFQI777w"k u 6S7p+F}qXWJQ߯mRᶕm&w h߀HӴw" {S+b$"0vGk $*ENKobdSZF4V#'kƖR;$P둃2+,qC/?uqE{grv>'/Kq3}0m1zvT#1 rߘlVvD`2T] %;YgM1ׂ1-#:C 2w?m "GtǯY>&b|r6$Up<9N..$zF szf._J$>a`s^lȍݧB=sHh.g-@N[H.O4ƈc׵ ;"{{O'2ۊUtr (;C@U 'Kn9˨\t3>pKN؝8pl(8>ҋ5IpC<`ۺzFz'8g?ҩNKڍu'Jl?݌YEN Uf8f|j_f -ir+w08(~bO qqH((q=@,^fw~@!J<7r "'?\ 1r;:jn(׹)/ CתrP7z*RFȸlj E龁y/ (WB?A$W3n;Nu6Km<`)ra#H$ URp8nR>ʈ#\dTF$n-(q{1G*g&<~4AWJFde+ex)DLN|OS<pO]pO@vVQ9^:d[42+UlKuUme(ޜ|{z2<5K8MN~ta ?Ls/1څٲhBx^IC V:MnUB7 yeߌ/6yRH~Vz_±o%%wQs1XĨ- 6^҅RY) ? E/mGETM}jUs^s&QJȸH%Qˈ#]Jq`3n*ά|I2 ásJ>u] eI7VbϦF1s\3Z }N8V`OL`Ԉ&rT6ޜʹ.!V-3ʒ6;-b"vy?uBWG$cqmlӎN?|5o$cslE8Fcz s+R`Gu\c8\?zWvH] `ӽ)% J#l= [Xd*pGTd1G01 Vn$ö;}j25&9W V_fӮHڦ[as0"@{ rNN+֖E@ѡcհ:1 "VЙ*H') yEIqn wOW+,6 2 Z$hfRC׷'-͒t6`zҼR`1;-ΪJ C/Ҳ.oo/MøAc|v#[Y_/Ҿs%Gބdp9ұfh㷂ܼ@erp9,r{EKśUv|ξNIAF2|? Ruyo@vx Rn}9B JAF=SbMyquj;ɞ^yiroaO<aIu#q1ER̆ I>sQ|)pI_b9&Hk#9́ӹ}k~߭φJjԖ{û߱xO.; ο2 ^3 ~ %kgTWGQU/uK 5C^^AA*$p cu?rڏĭ"0kT>#[ql٭+!}=E>Uh>crp3#;1ׯ¥@NKh̬1+S\Plb<_e(IU[OT玺ψtbAq!?Oֲ'tm-^ $K(Wb:juP ʴQT+KЩwǺgZǖGV*;F^A;rp}xeݜR)i;IM/֜jD>Z|=u`.c]^p^axsQqu6N:t^ŏJՄg\,T{}>yU$+fDe992t, }J/[`qq^ ϕ7Բ㸔$!x'[%A8"0~j1s-r;{?ֺ4#󣚆&S,fGBدOW5qC0j+gXߥtP#Zy溟 LHĄW*N+WGdiH 8hWKLwq={F{xIwi#n6c4uUd/CE1 p^*T p^*Tn*m,ӕoQӡGϩ\\M3<澁_ZޖRǷ#5kX켠 ?c+)J-O2gdxLg#5ca}9eal,ɳgcp||0#3SS!G$GK+bœ$9K,/hFdp7.qЂy=:`1Oa2Z^Vl#,+xzv4Ҩrמ¾k,E 5/nFJ<#ZҮ@ZTs `}Oǧ\:ɋǗ7G?xӓY?+xF1nfVs>2ֽL)M~U# 9~%h7(KڸQ'I]VS`H𑰻;u{d۵Pz;q^Cu[ usFPTo8%x7n躁is |i GּW0HT߄ĹՃykb?0kzSFI'Xťi'=?b Ы|`\:fA/&O|.OY]6k)H\BqRJ#5>uMf } $ *9F@N+({l,7õzKޫi&Mf{ۖ1 Փ 8 _5gc͔\dr~$Z](P%_);'*? ٸtu?]R}n㳱nsȫjލ9^] ԫƪVHvsTrOD$Ps:ʮhuH>V?1-"M v]0-3~fn"ԡ_ 2DdU$3[m1࿖;\01ˀ߮kح,m,QkVFo/m"%ſ5b3,F'JӱCHG'$(=NsVcijAb70G\}F|Bl#v~>k@uRIhp6¸o$U# 6gڹ[tY2`Ò;8į9ǭ;4-bj dfz$m+4df!DI>qMylQפUU֭{yaw n8'VDdwH~cNeY7.MZ֜etuG1'FK?fUNz?jZxL8H9U`>rMY!o24 FdfF@zEpԑ]jv-ίAʵ$9늹k5)(Pp?3X8mxͣ o'6sʤeHӢm%_ǟUu)hоabxU `M*W?εTm2|~&%MuF*z77_ ޣ*2@¬{*f?֥яW:d|pG9TFp }E%q S|Ѕ[˘tf_P-߂ǧ?Θ6ċQj21NM{W:8IPofݎ 'qMld=3\~(?ye !_j^* Mc$|g(T tE!t`9YDG~dXMcN'n2]4˻*zvw<QQŴ򧍉jG2q~]l Řp qQ2 >@sHv9Ol.F1mF~#i]eۻ&#/u ?3?hfv_Ҋ,O?5xS{?5xSݺĪնgoNW=GN"v:c;\88WVVQ9^:d|-KJOO2OuI''$ڦvVc"8>`9 m~*ɭ]/ڎڏOzaog. Lefc==)(HVlnf`y^x2˷e, \#XSMSo\ r+wN0& [6ݠOT 'xtB =imK Cp^u'Ca"gx- Mi4\ҹHrI?/qVS#6 qv+v 緡{Ůc崢kyWr9Ops^izNKn>l8b3xp8oQ=խnM,R9)r)G V ĨԊ{ÚdR.yAH_^Iڞ$ܘ2̟|\ޑyh0R\K-طVcR?3` AxiNFֳ.4)v㕼7ZPUfOݻ;Nzs޴=6j/le9IdqL9[M.1]}q8sОTqX<\/foyZao %ّ(mH<hc)˕<0?kI]ۛ=J9<r>Jc<'$-*>?}ȯk/CTqزξj;J|PC|I}*MmP[q2"€ɓ*'4#MK V8*$cd~t{Oּ#X1R$2ϱV@K)b; nݨbUD(5sXPtԜ0O#tYU{-*o-a,Rp̀ ׹C7滕9a&;lbkaOzjVe}gTP9I$v÷C5i^搪a"PnĎ gSqROޞ Eݳm;Gi>aldN2j;&OZƠMcTXXԙJc_"_4m3myKy0 j6a^^a%9%i;hr)?=oب‘˧Zͦ˧-%h@F cQTAM 4K-n-.Q9;'~57[_= D.0 9eIl6W6ZMk1o*h7pvb<%m¤s&LϠ*񮒰u/  C }3"Z-{6@XՀRHCMVMgIZ8e:`/_Ot9^bII|+e(HB~'-řʡFڻԂǿ>zK6*`-щ8 *lP7˅|3p:5qQƜd pBJ#d=!M}GRH#i\̒12""CL# ~hKK-VKU1?4=I?z H]U:r?{F6ƓlPKg2{FHuMm|R 78<SWFױ^%7E-('0p3j͵t6''dO!92LZ y⵴+ZK8@V/Oo8K6q;F2XEvznm(?^]QUq;wqUbFob\A^/*NesM$^4>Pf&?uBv2+ ;"UB<QD1 lp9$8WT:3htgAH2)}d̵3\*ؖ_f:I{4v+WZ 7?M֓ܳB׀l'`['vӎޝ+]H'W5+<\<_~J [T'M9gYݸ>; :"Ms: n'a4_(B rsn45 3,x- Jz&k{V3Eץr1*.w.N2qU776< ؠ?ͼqs<xCHUýÌ|ĒGL{Ӆ)ӝXAld ua.xsID^;z~K5Ǖsh3E {ry6IƉUH9\E֏Ci Y,}IWAҀG]U4֨7ğ$%ymcӐk3g"X4o$qq7,j?|wWK-Z1 5ƣ ;I }nR9iO(vؚs׭znj7e$`Q@$M8i755xCO:?Xf'Ծ]eۻ&#/u ?3?;KLwq={?VAJ(T>S<pO]pO@vVQ9^:dy6X(!H9=ۓN_ZޖRǷ#c׮3$ZEĒ*O~g׊>FՎRӎq:e$QOS}zV>j:VIhAz/^ZLDj,nEUzm(SU;:fnvY$ uV l# 3еK]Imf1a0t661{ep7y>`.>9?JcKVOCROvAC.~*W?|/Zi6](em{gr2xŝՅI$lHАBs\^[FdZ^":I,ROL32g;Ksi*rt79tAs:^e[XFB=q98Q3eTo8wBFj=Yj>T-1%c#;Ssø}cHJ< rcp=k5=Lp@8v?j;_ аܥIpO=YԦENa [2@:> Lk<_lq xD<;90ʏ&ո2/|&[T]+e(rѿߺdZky޻E]Юa,`]8 6܀̬{`k YgoYlgsxGY4[h zdÞN8<՜VKGM(K6nc;Jd1# (#j/>!Y>Fm7LU#1r 1*Iq\i,kQ~C89̓Ք)bK=>±79UFͪfQuյy,vmx %q%&6#MO]>_y;vơ0P|tªâܝuTG-\M:_7 4) ,**A9ۆ rͻ`T^#֡tEn$rΆ(gCۜs;5ikN G?i9KC`XF|#wuK8?0S[izZp؎h$ֺĄW=j xۏs^\GwdQ4s@ּVP*TVS-ȧ[! S*ȳ&C98+ /krZ,G+|c N?.6$Gq#`N֨ą!:qV{=)@@v'vkԴhom)l mOZVĄc9}Rl1Ep~o0/4*~u]Y:U8_6#-rpOcb1أӡ%ީ1%:QT(?ZQwy~UkTKE%dpq-b,S>ۄj? *vD,#.k9ŵhؘbrm\A"G&J#.m^CwpN+cx>!A*,m Ќc:pLMi_˴JYldC-ԎұC:WDcag *~,ȭq~iOaySVb4pGP0]"g|\MDM$F-_c>s$KK{K̨bGe'8&ZyVdGצk8܊T}?+Ŀ36={͟[D' ^+ 4Z$ i !YN8rsq4]D\F8,Ksӑ+{TMJVaO\pwP\٤he9P⸭/Q6Č F;g~zh)>If9 Ǡ4AݙՃtfP?(v:@O{- d , 9ƴtܮl>dl_^6,@pv``Zܮw6av<-wɗ"b3u N9y\I=:q({iԒJ=K2uŧ\FCxv=Ii^z}X 8f%yPzwlr, q(pF8WxN0n*U3:pZ+3gR{"7]p(UTd+ux=ݜ6k6ldrG#8< q"Q׭m."&8+I(EQe}("y _ꞻ _Ꞁ6%V;zr:t8ϵ]9àl:UjzYJ3+ޣCW*\e>܃U㜴8![AִgHу9հkJG[\l1[!~Q3:$IQ-xJ󹏠`U sԘkwGaur=kUG ιQҚgY}8l J/<޹גk2gEܕT%d,Uܹ##y޷OZll0gvn8kWzYTO,aLÀ-]}?SWpcU!J奝Ho$ :Md- FN9=OԀq;'>oaI$0 |8sz_I.#Fx}?LTJqZ"t8sD}Lq2K o(# | qY^MgX6$Z 6R:hRÞA 玬J50Zm_a'֓0jfy$TWvuA9 2N'5Qx$}UHA*=+Zfr#&;V7 E$rNMz}x^ExV pG`OF}Qq /5ĩH7;U.74/ 1+|Mjj2Ǫj3_ YW? =eΛ({3X]@+fHR>ׅ\q{>,m܌DsP!:W/ӷT{d2E ,Fy}ITm k 9T R]2=?%[;2I9#9=zu$Z7lkZ>H?:1F7gx@[}d8;O=JWALig#!ۿ?A[^"Α.!!w"Eަ%6囁0G=O#n0A2J6”=v K׶`Bcd0]s19Dw`8?^xږ1.m\yXUN0y\Jr4xGxE54kY..&,YF#88x)JgƨQ sǯ}>`pwm ܱ=8՘ a%<ӧ)JŜ D9εDϯZMMQ`[{k+͞h|xS$T[2H=.[B6q1=n^Ooe<D&mu7*X,NAm֯#ɾ1 p `N> ~j.(%}F5Ϲd;@A]$vmg qkyMc5dN . Dp*`gڦ-ril@hʪJaxCd~~2L 1QA$r:Jn6͕)EW 5vӺBmk0 Lk@.r>^.Kec VYE^HnwI>2 co)'>=Fy$gx^5&"9:X5rq#,ez39c6Dyg1\ӥ :)שh*. dc$f!+<~$Ò֓`3_jII1< $d[TJ̆+9htcHlY,Q?i۹kcV9횥I^Uݭmv@H@pP“M\ׯ]c%Yֹ}Z/M&p[Aǭi]oyfs4lv#ߐro0IoG $` n#ҺԆtyx8{.y'99=Jh|S:{tJ惎-dLBsy@kbR HGXɾ8[[Gr{{WvVQ9^:d|ۥKCf_2dyJ;Zf ~eERqZt٥BRy`{}G FdjƬ%QrᯈSLU<'` xMb e؛x2 ;B:/-3K[W^v+ 8Q'*} #0u'8j'E.XwLgySTRV (ϖm q$;.01kigv yyeAʲ$W2,Nʥq^oSgN>g9khL7. twa '#ҸO ϩ]KV9fvkյ+t=DP%/VUcRvr~)"\26;`1큏Pj܉Ur}xDZ})o5wrTg-#w8F~ղK[R4>rTt-`E}QR (/ʝ:uvc%A۟>mD&t@R(y~C T {o$RAUr0~~[a'sήc1$x4tSyS#Tv]3dUPP3~Yk\|ҿ8 zz4p4d-Bs1{ Wy m>_^VgRr~ci\Y7P@cg-T pH=x-錩l 傁}Y <0JҸԋĨmxFp]2 9sTOXzOvelCg' b2=*6tf!`y>H85E1`:WVZNV=NEt͸6tHQlXd{3+g7r}*x㵅[tca1\3MMN%1:1z+]+,}jM ,d-#l dg[z F#U,IL֥]_B[lpoʑ  UFNEדui3 $>9+1-M7'=\xIE"I6kAaw"e| ǽ,Sew '?Ϯ*н[r`bw؃@'[řneO5HcF7w7V+vp1g'l~I<ᇨ /.Zz&**ۚzZ%HXy_W6rN<*? P Т =%OcZs˚:U9+s87}-w'߹!A믳+<. =WYYn'9W'iwbU2 WYE叐{:bD\޽#ҦH])ʿ+ hx 5sqT q9M?s^ y/Cbå AbǓA9#?vr6Inz0?BʗKLwq={?Qv_Ҋ,O?5xS{?5xSݺĪնgoNW=GNcD$5VVQ9^:dqdH6G9%Z⓱x0ENX#@TMtS[[DRA0>j5:M~Z5h-qqVL.@SQҔXvYm~`;q5OS籕=8ooDwBq@zκӹr-w7"w8=ZKbmRk˪ FK`XvE#Kyq(E$ArHðnnP)h9y&w_k{_<g!;& ۨ΢е+W|k$g(tsqrǝۙ7 O'Ғ7D~LÉF<$gʖua&)Gv%xRy{mW##VU͓,m D cA?KCRژ%[j1C\q]<јA+- .L;v"Cc"l~sq<~ 5EZ![T@vo 207`ӭ`xOFFzҜ&~R7 e' igL{luly qRHNd}]&—WP.6{ 6zp`ZGR<:r$Z>FsycK'ssyxyV!Wq{ e[ijc,/]S=iN:ؗw[~ocFvc&2O{G&*)#qmh<1WlvqʂvUHz~Fs q47-8?? 0IVF-(|{y$v=i}Xu$7\F iN˦) 1i >|nAWsxa=_*9&KkiTl3!;9wF8Pw1QǦk9I"ŵHQ RۑU8GM.[R$y$~U3NWżeOkk_c/a[#'kuzj*L|@U3Gҹxϖn2:U@9iVQwե)v.'$W:0@qXڽȎ?=cr {cj@Ugqc*z'KTLG?yAp8WO֥$VL8uķPH3H:zX.23`WMg,E^0LOqJu'I꣩`F^ 9Uq#`0+Pft vf{(J:#8nJBQ', 0z [s:z* ́FG_*[m;ytC#,~Q?yhL kJґpq?5?ؾ͸FU9#9*X$?gD\ێ95"vZNN%X}[$O\Հ HTdҜ.JQИsNv~*.C~9Zf ]wG ?ai.t&$Fv nһ8+kaG ˖M\&CKr\$=ӤP9>n1I+3rd$On3RuEu tQX<ɶ;ʼnݲn ݺL5̖a79HF0-'"U?;pǑѮ ݑ^m~v[ai݈*}g X NbOw.cԏPiJMP`2;.Bh粈"G<8ǧӧ@.'V[u+IFR ⶯!6 IJ2d.y 8=!iG39LWʓo =>QSDsOuAem>3853Z|kUxqJ?xFOOQ6M9f8đ_qm,yj;B;+ <̌dk[G671~g=FE%Ƨ Wr@Xze[Zh*"Fc=O{&W{6CpZ\aXMsXK (~E(@Kna[N6\,zS|dJI=jH`E_"RVG=I0]*k1Ir%:tck% (kHI $R{U+?H :Ep#>rdj dx#+:cT$pEsm;y|эLul33/w]eYcP&'FGjs0 K|[gvE@~FG#ڤihC1ϖqwj ̙% 2@U68 `=86pqӏsOŤ{3C[[In"ȳ4 gP,3WJzFסCp;f}? k^I̮7 ueMGH)Y}$C^V!FU)Jp9;DU˳`0;}kaJ˟+,sK_5|G;hT,mXQ2BmCSO֦^ZYdp&@ ` w䚎II׈1*7 jڊ CGpUAbq+*|om+qnSfhY${%u(KƌRU$?Q<=*/1 ȨaK2iSr\lU2tMnN gq]"YD*@ƳHFX# ݳlI0Sg"*Z \P+mEp0~a1\*0a8)km*)ԟ-}+ֺ"3N̛Iaċx»}KVٔ'kӋ%$9uv^,6qbיOBm̫7( z98wM"YvἳcWTsXfrk~jF(qQx㞵p3po!uۅ~2bMohx05[w%}cyr*}ýz7vr6Inz0?B~KLwq={?QVfv_Ҋ,O?5xS{?5xSݺĪնgoNW=GNvb$L|>-%V;zr:t8jAFB}Rl d~4ˑik$KRGSÎI"$3, jTQv [9qzJmZ9. Ks7ά^ʥ-Mܤy8N:>$h3/0 QC2t\ $YAtQ$hf1O] vm#" yjweϠ9v;pc˴ dzt isjsu lqsFmI\}ǞgA:G $XeV~?t'׈o-zuϑF{ɬox?U}Nf˱ ~wn 3t8F~Z}M -d2tH}x?,bPjuZ8c2g֙ ,;XJ׺5TQ}3JO$'7[o9,IY*"嘓u'=+~ԦdtNA={*  m~ >xs=$e6✏4Kۈ~Kǝ!{Q-*[AgfI=kJyu8%\J^KF̹N3"(8>sk#8֔De#DCD8Ao^z׭uV/||U^ӌʵW~sn7b ^8Yp?^\ 0q{V ,0[FsVY^:\Y7PHJ>5o k7]ŎGʔtbT9pQ7/*ɤxjQɂ$|*6PĜ8rH dؖ>x@ sy5r [`416鮧',$b8-f8,pk Z[@ZEYwn.x1+,aN{t@. \sXr\H9Nп1'U Ji;h[D@x/׏W&D6\+s.q"A?1|t̹,t7WIPO9?pq-ͻiT1zI}1C!=>Zqag1\uIY$ܟǞ>nN޾{F5u) d`;{ד~(՜G1t.@#zEtzP۳"(*! p}O5ijjBDk-ܷ zwf}9Ge*kV:ֽ4JXQ9<&&) c7*ngj6sA[P6eZ|8 qHK, ,Ae,gH-ߌУYd)@?{bG"6KqwT0F^r;zױ6?Hl1ɴ&,n$WiK$-I Y1 czj{ePfXs8SG8"K_"=A.S#wOOnZ͉nQP1'Or02d$mN3X\XiZ\05\AX$h냖ss덭{= tO"^)'ܱ7򫫣iyQ؀6aӒx~U7<9cim Jw<Z98~EsLvz\ik޳~D*0squkXE0^F9$׋^,t{ srpk;lu/u\]evj8q!e?{x>ՁL[i1he cqœrK*ݿx|r?*#[繎2v#"@t;{T5tE7\ls( Dϒ0d)inS F v׵sZ;&PE+<,#xuXlgGܩI?tm@dy,BI If[_\\ˤP8ے~#R+mU$PNoF1{h,nsZ Ko]ْU'\+u=.K'.\ZcΕ K,OĂv0p1鋪_ 4;Xc*LzytY[D!sBr3%O?~{89Ln|KHK6cq^U, 'w&s2)VPsN縨t땺x3R9.H {cS2M"XU 6c^y]Xgk/m Kv>PAZaHF~x^vZS^܁%Hͷ6qוc5X+tksyY)P3x=ݓ&<8?0< QȀYVf6yYe;Xq˷Oý)AX)AI k3$8ߵ1{u]kKO\Lv!XOVf4rd9QK8ǘsѴ7 : \8={V+uPrsП]y BO֕L{Rm MKן|x Y2|HcҺ *đ"^֨8 cj!sI|5jc p$8_@sVe2]9r09JǸ۫b;ssj_+/HU` sei#50_}"1/PUlJv{f`p #=)mCǽvt?nZ#p+ v]oi6 AϯLq\|FpdSz}+ҝHI9 sOםvN~"T%w?Zj c?c;RW\SQ7/Ĥ#ak|l.F1mF~#F)|$ˑwLGsч_fC;[/CE_Ҋb'U뽟UnUjzYJ3+ޣCKKWѭ,#0¯'p`_ZޖRǷ#nMY&*9iC랿ҹ12QH֚&mFA=kr es ֔ Kyf2EpƵHJӌ$ R)25GάK'IK5ؒ!'2WzA/xxi_CT<5^YDAuGl2ATv?JkIu!]A3Y"M!dt8cg yfm&q+_Gpf<,pˌTkj54h߾:%yl'<נ yZ)7"_q& c'X鑏ҦhyqM( p==Ԫ\'4W'6/ Oqsa<'=,˿d ă>vwl=kg}kV 67 XC{eƼn-VHT9VU*I͎:\ VWc-e6hQ.R 70*ngs&Igql=z~uv[D͸7wW?lt˹mIT! 0H/#ݸʢK[[he3fIO~x'Zi$he;HR%}ó8n 0R$OVOC過Ʒ_IEk];q$N;syJMW-x+LOvE5{ib3.>{z5hFr"1ڼZV𼰱$9<5ySd]L  !qs'"F.XӨ>j:9M%fHH|+%Ti$AD(7"X%%;I/Cַ-ⶍpdv\s;gZM.WZAĊYG;FsMhkRif,w;;nWVF|!5Iha@@9' R1g* ;+ٮu)/$>h;G =sӦ+`6yhcIYFA.0ATmKCNs&'' /N2p1fyiRK}t]:HI u=J[@bO*4QWY%+շcpnkAΡsS8r2@UܞD(B;AXx>#y$eD@YrKK"("'=Eyo ɇ$Nsq?Vu ]vC: b0;=svy y(ٲF==3?P+cs+r;E;+Y~L\`O=)rsZV٤ 㞟ګ^,wqB?{UM;քdd7JpJ޶bfNzfiA{쑂؞3֎4$P2:8b+{ng15uM\LUBnG'kdhF$H<} P#'/ӳ E6 $݌=}ɭkQBYfhr{hq5j["eݹd @^mH$EU!^k.F1mF~#F)|$ˑwLGsч_fE/CE1 p^*T p^*Tn*m,ӕoQӡG%R K"d.:VQ9^:dxܼڂ &Mcg} 펓Ac7NJ *S4V\g2ULON+e.o Ó\֢RT?o0g }3\P+ڝV\& H1F$It\!͐5Z>q.j̛H T$smjwb_v'Iv9+ Jr$HAy?N$/ =O=?^+a[HS#1-n`Nr+ކST;|j:Ǖ O9ں &UY y?_ּGKkKG?8>*K-۬ cߞ+N~Eds 1x֋vW'~p:=d_R+yeD9 <ұ=>lH&V 'C>^K%G9%QFT=kun&$d ~?&[ue ; ?U3J7Qae4dkg$.3}ik'RP]\}p[,12I_ V۟~²|AℵHgrQYy$3ۖThJj}KhWvze{]߾@[ dwsEN.nps\\jv z}.g!Po 1=FONxWEIPQ摱kahUӌ`chbXZZpTy=q{gSޡL+$y #ʫI>znLsd$py TI~VۮRH5bV7[=O޴l KhiG%s;g}],DFwd8Y Nc+Hq*D .@FӻJ1U.v^' ۡ")8D8~QvCWlxOrr p8Œwrƙ&/u<|.I 1Ͽ] KKwTYӓѮ5VL$`nIcSbaae.#'*\7$t8+#vǺu{QNW֬VѶ|q?~ՃNΣ#֪:Nq#zt)q XPɑ}1?!Tv"TJcgTK%ͼ$"H<-~,$^bg_dsG1i\K,mHI؜d\ .ce`@xfشj$~[G Tҥ^F,^,jFE-l4Xc4Kԏ\kFJd")e߷ 8ߍW;n isvK" {Xʕ`qۯL~o $QdLuX- .>΃ qM !ʂ{@5:=l~zRp`À}UŤd?,AD=~>CG 뀷Q#neν6Oi8P>ﷷeVI+8hIA?V9m8@8*6&0c*H+A}*o`DN>^rN{qX)NER.bYݪAT7}gU9*rYr8@:~#8+ΫB BnD6I)WmAB`He#,sOZ cC=>\ZҪ{%ܪԕ>$2?:B\Lgۃt5ihgr]bIVuɷvHiֲG8u4T)IPZ6Tn6i=w̪*NG?ΥsϽT^KP@=Jp6\te.ZVm z.T`Py2d3 P\dq\}n"ɴ˦9ecNr%ܱӯӥ[#ꣂsDZ馧Uyla58> e" ;gcc3k33wcc\|GC9~3W4G!O6 U;(Vf9 :zk@17b1㞽Eu ?-Jf{^vývp6te܆H2m68#v1&1)d[9fSvg?jBXc5 (%uI6$?,LGM~z|hOqk@՛:W#WZ sF޹uGlIir?*O4WKLwq={Fk.F1mF~#F)v_Ҋ,O?5xS{?5xSݺĪնgoNW=GNWwYv@"Q$x/"gT_ZޖRǷ#X< ePޥutLl+A=]JUm 9w{uҳ.<[mY fM^-`HV2ORg_=4o!PB9*>>ЛO{{ [^XK`DrYaFdbʨ$QKR֡O$nIxRk*,m_  ˟γ%wE''6V;3(Ņ9"(vЙ@=[[,^^8nNNb1ºcˍ94m &i(-vqʃӠ`?7Ol4kXc_8sn 8mtDby'Ӝu+sRWq`1T'2$6#/K𭔒]ʯqrA8;WIB#iU|=fԦ̶ʭP  ̅~Eei>(uoM|6A?;nrsTevrJrx}i". 2m]* J'&EItX w`ў}Ҽũ9\/jC)o -~zV[xr2^ݹY vrIz6g,}#n{~=k#_׭PGpmwzɰD XԀIrFJ:pWl}eVh0ag ϖ2͎Ӑk[D%̖1U#!BOʻ[Tc!ámOArO2i $"'`v1N3WS )SvgR.yFw5a2kFr -n?u>\ 3dq<qQKm^ΐYR̠9?Lh=cc 5E HY"aׂ;tX;xO@Zjor֖Y2H.H݁Z_gk:TУY|uHǾjM檵ؾYB8J ga8WF/>XĈH9ܧ8 `d_jSx{}ŕԬӌ )F}9.O=tar0z9xFRWl !?Ez<$1pAt1Y[6V#,4ϯz~|K$hfGqr};qMq[0u3cX9[w"̬n4+-}ӂ@M8>bqڄ'2:K\OL㟭fEuxqe*OLxZKS)'{Jh*kopLX\~uMy]uƩoC崇%\n> +h;nqS5 >Vޯ!YX882/̀9'zwg [4\!!{zNTđqϭoϦ<o.˴/r׷\7Ќl`wR34YP&o]*,G}ɪb߸ca0'&UW\NTgO,c۞C=:8`ǿT!P|\gqI'v[?)gҴd3糺6D2v[xݜS/1.Ӟ;W/< b>ճ<]_daTzWg\8;SI F8p <ҍfO9+N-ʰ}{U[(~e,qZGCb=+D*9r sҶ6QI(oOޤ:W6D$%s=O#he;vFfd02  2n%Z?%,[ Bpzt쾓0RY{qV)/FUBy3?to[r$fQV#D W&Ӳ.WPpA#Em4ܤNN*7c$:V{ZΤtQkf>12–I6ӯOܽз`OA\}jխ41°k[2p߽!RgFc-g'lɏaz I2zWEtX,%f `m|s7!{DFZ*x$N2r7Z չ`Do֪HؙE)K{!hd'ܖך-oC[)`^64GkO*JpSuGZY6Q%[Fr]yS6&d%ח$+HZ(suϹ|2kzҵK[P#wVgu_^BS&0I_ls注5Ův\)|¾0 ~@p3$cӾ!6бNF>f\1*{ 7@@@8* KIGsм?ANA=8z1-O#B1?r{vsAxCRy9R<*0 1U@>hvzI :*3ZZMhm;d*X( s{jLj{7yŠ_֙0i"$mEF&#LB{ ׳ ?%bf;?ZӮm`9 ry2AP> t1f9cN=* Fد``^I80ةi3ԩJG==]*2~[yQ%zTM.XDe%NH tWK^3MTJhLvX37m,w+&ԓIpkWE%6UG_[[iI8 MoiEt=8ݜgUSPu 9uKoY^R9A\;epq߁l _S d*xs$hʜx?\+AE{E?dujaFu[ٕ[]p:|~8Zg2\U{zr;Z LexiSgB՝$՘od-*]B~?+Y?&kiEgۯZhe:ۂH Ivp˸zwwSӂܠx$M79UK[v6[Xe8'φ3m.&ж #B/VTHQpY?НMgj"@:#'<#SGC*MQUHa^N P@=qS.se5~ӵZ[VvPl" G=3U9 VVWsc#8*GQD7>P9Jj%{ؖSZ¬mD?`NiڷXJm㞝*E{y@9 n}9Yבi~s`2oquO$ jfCt1~C 3$ږ_9'l2 mۻ?Z"7l1bd!sE]ɰ.9!]On80 ԞΨE ;d=⚒ $1~\;{] Acwp˔8#?K%ɹhqrkV반Q0I}N7Rn-7̫4XvrӠ@e #RVe>Vau5ȏa!Rn=z~[|H$8MU/]%Ӥ ƒ5 2xG]5iR,=iR= vCoڴxV{R# _5&kIwn(9=+>[AўqV4ˉ',1lq 3br,Yd_$EˆOUsܕM- ]9+pQFv|kw.oK6vά̿LݻW1F\Rn1#N_ծ4nOG5,+I,13I?Z#[Jҋm$qѿ A幅$aBlje#NvsEiY@J95 xVFXXΛ{3hMu;{K%S 28 vGIPWm #zWAi&0 \W,VNg_2F#쒱 w3y'w -O>ڇSbESYzHdx2 XWi$!V;TcU!mJX$zVOr+Ѧ2spA4s5 ѵa*ota1 < !)ƵkTod|{w<9qVQdZh{3"7c۲SޕkZids;ve]hYp@VCXZz\n>V2;^XYn,%w@K`Pz8*HYr1vSBKd^k=#'mjVa1;V Ƕq[~?m)ц RDg-n&ҥ28eQ3TetȥsB}WI֛qqvs .NsڼN9v7e}my )dt%X0϶Ed-N[ hdw`峲ĨKb^H_#N}eqV'Hf}OJzS Ƹ;J/8cRǧIci*YEry8c\jjLFU+ijB`Ecw|cݷ!UM ȐG]܍Q咺7htκ [CǮHB-Bedp9]sޜ>#[-i7V/D?QчFFU,,q/ :[%nkYO5İM !n@ſPgkos)N?\u<I㡮/ɥ0Esor)>L3ᵈAmgJmQƵ%7-Ɛ86,$>zZ۷KɖRBNV3u\e:f ռryU|d1P͠hZ%&V1glq|'tΧpAϠ#PqIYH$ /nޘ-/!(6{8W~ n:ո' [_H#1$H8p#R}'*zϸdYm2?.ڮ2MS/["䧖NTߘTt FO歇GH_̊#_aKFmщ'pHbީRq_dWP4ȲʈpW<~wy`sY:vXܮ܇fO!ߎcEp,ʩpx2V쌛]ӥr!O'MQ29R+d= :vVr. Psu=h~((=l^3"ZGcik d1̙#cl;k[m,+ uJ|Ctdo'HdIfmE4˘d`VW)9%F' tqҢ)*m A;t0B$t9rzU*zU b+PxMM3qJ뤴XcXc=ycǥr\SO[[**|2:I*C[mQ:ڹ+i8%g=M)bp@U YFAVYzXy Kĕ֩ڼJVX\ VrѢf(ZJw9 zW9㟒,Jߋ2ZFFN[v:t;jy#Zg$ISp N3G>Ҙ<׬y^]eۻ&#/uqxIwi#n6c #5Tv_Ҋ,O?5xS{?5xSݺĪնgoNW=GN$G_[[J[oK)Fv{tqsTI7jInK+ƣY5&쏕E-4#I?.i\v#֓]6EbrQaPFqZE%ԦG4GBACVA*^OG欦#QTfI1ݚuo ኟqrT`}k3!ʒ1f֮Gd9si}2`Sú-T}GZ2g |pkK`8^*@\kzkR}rs[֞/?(ccNKNplP&Q,@=G#]41m9!hrIp[mb z,݉IK :iU <~ZE_:!QH@`dx=UmY旒KulUj\-N|y\⼌LưeQd21wdN[“Џ P~\Z/!=7.3Y8JaѐDOdw ?վCs^.xVliV܄PzVњ0ZS+ i:H*GZ_kHԄKFTGO ͧmg|Uх Hj2Bp9;Ͻ]Zb`[ٌ*6eq鎕.YJz]7v8fU}?l_ _bb͗ =kēxB8=TVSʍwĨ]ISUWGyq}W~VhH4\|ӌQI!cyoab+_Or]$\$y~@ [h#ÝSӞcGuXոsv1գKjUB?\SsWQj`ԼIeE!eRU ԦK>k~ e!"s݃d885yQr*Y y-hN 1á溉cԢti4PZXʸ]:-g_v`IU6)$cTs+46RW-D |!]x> `M5Wi A=^$74JgFoT ;9͙Wu(8qן`c⚕q(Y# 294'q>ǝ^+"픳Be X'p!QR=N9^%RVG <[X:a*z`᱌ޭeܻЩ1ߎO/RBHe|q~ˠxJF-DeF8+jjVqճ~5Kmi-$IrHo>y-,KulPŔdA6m!}m\gm86;P]BX\M#\)] M%ɮ/d`˺}-?1 p8#'FUE3Bv q\XkQ,$BOW<.285ia(REH 85G-E$'ak {[ຮ@~}}Dkv wr8'89T֬1GbG8r1Xo9b}3^<(fr34x%(R A-rE.A\8zgy3Ɵ6@P۸\3f,W^F}feYV{m㐭֦QPHQ\*GDR%BvuMܲg)w>\cElF =1X>6n qV崣uӷX630L~)%L${FIQpO8CKLwq={o> .2ma:fPQE/zg/z۷_ZޖRǷ#0Hm%V;zr:t8=i `PM&i=iee/Μ.XcsRJM +CftTM+uW.#qZ#& E/AK`6Q@ SF{Kޒ~V#hXK铂CqVQR0GӚ#֊N(jLY'G*V&i,]jy{mnGΦh_=59!.pGQx|Z\BA(G PrS [>Y}Jt9tW]OS%1^Vc1ޯYfXkPKXytfDz{:*Ք|7>\q\UZx^lxHݓֲtѥ-w % a\χ,vo^r tV^0_/+]zL(_0tWVԣaJq(cb~$ՓSr6q3VatQrq)Bf-pϭ^Xq DLOlف?i^CCa7w@6yU\ +wFk8<꣙${ᅙ$Vm~-cT^ 2}5#nwqsQ4ar@ϥ gq|`vV9ݹ>q?kxMό9Xq-w峚Z-O0PA+:՟.Ҥ0w*5PvHpҳ } wjn9PpV998*#xqp}b۝9h.ch 66iq.4g?.)Ѓ8Ug~`b"q.w\PE KxGTrOaڴu]b G\#yj}1y'ޠWkXn K~0yUiHKW\Y-Hݾ2pz)}+myqbux#szYt 4s<^h+b?| *kWjR gbywxVw$r #קxѷInc\Sz p}1O*j&zs^IIwi#n6c #5Q%ݦ\b8۞=GP7QRYYJ(T>S<pO]pO@vVQ9^:d|u_bۯJ[oK)Fv{tqs$ C֔uMi=i Lނ)B@ƑLfC@{Ru>B)Ɠ%INh=(@ {RKۥ{P ){Q,!i) IN0:j1_qgQާ+so @6VV)VG˟CKc}ZXRG5:jWQ<8$'^0e585{QZxhX ~~o¡C86c)]r1Xh?#h&o0t~jÆ+y nJNyړ$hZ=M0O>px߽Is69Z;>07QfkZMH#q\'Ѫt:OK6XN?B[w>SdUH{/Adq~? o< a{r V]%U-$TkAI cO`O:q@swEZC:s?U+e]cwUFltV'樈 #ۀ s묧aUxkQ3E+cqT&/ mY͞T,?1z|DQٌa;9#oBBQ|­Z\tX}6)ՃF iΌ>ʁw1U_TNBA.ϓu2d` ]]υm&Hl*'PAyAqA&;ݞVf`PԌJhϰdRsڌhSG N 柅 (2)֐N8RwIZic sNR@ 4SF(rE/ZNԔLPQ1E'=>h)*̿CJ(wHa¬G),zQJwf]ɌI!Ub˔p\)̇*H)r|;,kPAդ2%?T8n70_ҴmQ} $|9̮k'RS*Y ⲕ=Ѭku;?&\_ yKqMNFA,bo c9c47s$! }*d[YyT7{O%ʍkjxbWe`g88kϧ5Dfǂ 1'klu[?[*]F3z~Al'g(S}$Ev s=nAhdǥ{6rNdvW𶗨hnPxRlZ9CR4L3ק4@ti5_x"ضA煕{}E>p>yZ9 ,Sp,t[a4v#<0qi/[ mQ dX%uG5ҧ+3Tѵk%O_^Z4@ vetZw Z/c8!iN?z҅>HՕ8L~]q18vL 'ao-`tL~]q18vL i. 8}~CN _;B}o˺t&'w?ߐ铁t7a`:got>O}Aƕ}WL~]q18vL i. 8}~CN ƅg&):O𯬗L~]q18vL i. 8}~CNo@?o˺t&'w?ߐ铁t7a`:got>N;ݟ)¾]3MwXX}2p.,Lbqs>8@՛_^cW_Y,Lbqs>8L~]q18vLc`*) WL~]q18vL i. 8}~CN q"(:@WL~]q18vL i. 8}~CNO#o c _[.,Lbqs>8L~]q18vL $`k'a K"+e4ߗuLN>ݿ!'o˺t&'w?ߐ铂csg7 G#/¾]3MwXX}2p.,Lbqs>8.3G_3'#/¾]3MwXX}2p.,Lbqs>8coG_3?g t7a`:gotf3:dϑs YE?W+i. 8}~CN4ߗuLN>ݿ!'g G#/¾]3MwXX}2p.,Lbqs>8.ȿ?g ?o˺t&'w?ߐ铁t7a`:gotp>EZE?Q@𯮗L~]q18vL i. 8}~CN /#/“h#Pg t7a`:gotf3:d%s*uׇo[WL~]q18vL i. 8}~CN >X];S|ѵ?*Satq+54ߗuLN>ݿ!'o˺t&'w?ߐ铅d;.bq^߆ I׮x~7Wki. 8}~CN4ߗuLN>ݿ!' 1%i醷c*Qk,/¾]3MwXX}2p.,Lbqs>8J/rY--Escz{`Um~yԬ.3W.,Lbqs>8L~]q18vLd٢WimPFCݏf¶,ιQds]o˺t&'w?ߐ铁t7a`:gotkm!C{N3T)7]tŞuz"o˺t&'w?ߐ铁t7a`:gotXx!}&={yx;^s(70M{o˺t&'w?ߐ铁t7a`:gotuэW>vC"8k)嚀n+4ߗuLN>ݿ!'o˺t&'w?ߐ铆.|cs~[*)4}Mѧ\xϔUo˺t&'w?ߐ铁t7a`:got*Iu%ovvn- 9hy -:4ߗuLN>ݿ!'o˺t&'w?ߐ铃"9Q"#w1IϱY]3MwXX}2p.,Lbqs>8^wgLQWcO#xt-'s2q U4ߗuLN>ݿ!'o˺t&'w?ߐ铄JھW#j?. {0tK}6f3:d]3MwXX}2qsS3KLwq={gق x"gGpnJ?<ro 9(,c)+X:bC$!"ڢ Q@ EP1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P( (? endstream endobj 50 0 obj << /Length 2674 /Filter /FlateDecode >> stream xZKs8WHՎ`HsN&3s%Hb"=$iQer`߇?#m稊0K2,$OQM+ qoQe(Kin!x$Ret~ͯo?-41Ee? "}za/ Fe-ct[UqOݨdL1y]󊘯 GJ9V~0b}LWFy"%\$V ď\ϷVE{_XoUw 1_EU*@՛UW\O233'΃7Lΐdg.a/![Hn0P&}^(}ZC׮ׇ1.N5I6@9z~C%Y6˘HZM͏?^(?ZQa@99Et:}8T,AӡipuyK鮛bwUSU*EC 8uѨ3φYHz6H.1ɐna}gټZjC^A# Y5JUCy13f 1Uό6O\,cQ'|Mb}=j[ώM?a>K@B"I3]2&6,Rde&N Ey,tgX5;.D\˘@K*xaT9+hi_=r Aģ `;A\P$9χ Pa=<<3L,A} )UF p~G}|`ŠN2s)_,=% ٸ0x }YLBG+<ܳ1I}(*3fR1svIxG\c0F$'Oz KuS}F3g Ԭ Un-+ɳܝYܕA68) H<;HB4?!+Xu`ov@]=4Œ]?yTeyQEK)cd,Yɢ.Bb)83hw*UY`ty򺹨roq#0ytafAA.s3ig&nm窮*>=iI\Y"Jau6F&RKVJմn4N)lZN'[(E.`bZ}eoCdW~m|ʝ@ѣzLFkWɤq SѹJ&}kvEߚ~--|h wm&I(4ᩋzz/E׎[!&zD` n#}*&AgZ5pj7 %C``Iԧ^wDvӺļ[w$Iy^v8: T ֖&a a 쏱LOC YTCwF7tA/v4aH )DG<"N A{eP< 1lFN D% endstream endobj 46 0 obj << /Type /XObject /Subtype /Image /Width 887 /Height 803 /BitsPerComponent 8 /Length 150736 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100w#C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222#w" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(;mSL;6ZV\̱BXOpWwf ?f=K_Z<%?,g>]_ZOZ{G R}/(.G,g>]ּ_Z_ZvyG N}/?E=}hּ^?.Zvy.yG?!tӴKp=k_Z<%i>^?.^z篭y/-;O]?!tyG?!tӴKӸ篭zגӴK J}/?Jzמy^K J}/?G-+O]ּ_Z_ZVy?iZϥC篭zגҴKҴKp=g_Z<&i>]?.>z篭y7-+O]?zϞy^M J}.8?hϥE=}hּ]qtѴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-_篭zדѵK?.Zwp=g_Z<'k>_]-zǞy^O B}.8?hZϥE=}hּ]~qtеK/.z篭y?- _k>__]<_ZZu}E B}.憎.yG-]~qt\X֏=}khZϥG- _篭zדеK/.Zwp=c_Z<&k>]mzϞy^M F}.8?hϥE=}hּ]qtѴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-+O篭zדҴK?.ZVw.G?!tҴKp=g_Z<&i>i>zמy^K J}/?G-+O]ּ_Z_ZVy?iZϥC篭zגҴK N}/?E=}hּ^?.Zvywּ_Z_Zvy?iϥC\Z֏=}kiϥCi>p=k_Z<%i>^?.^z篭y/-;O]!t\Z֏=}kiϥCg>]ּ_Z_ZyGԳK?.~z篭y'-K?g>]_ZOZ{Gӗ⭐g{Gp=lH 8כ?4뤷>LOA8k@("Zy&&6"j7K-cG+6|Ck$kRKXꗉicOp@@ IUxZ+}7zw9Y\ZB(c=G =8,cԷu2ClQӜfg,vs{KHеq0vf/=C+h OS~/y>n+z_ϧquuqmp"0=ycZvܛsO_g=ܖ[J@)'JҒm:;7ق.}1p8py&x_^E*pї;WAjĚm.[KIˈr\G&Kv9 }& ʶ@$U1(ٍ3d`73J5jE$Rpk-@KOhvncFd7 Q}N?#Q%yVYG1N\𦽦YIy{46{ldpWYwXE]Tsorڅ^R۷2|(`Ǎ6vxgC;?(0HH;aA''AG=MO=gFn~֝ͺ+kavo0nvqJ}Bz^^Dlo&Hr}H=C n>`_yڌ%0C3j=: N][NL'in\r rgk]]~\g?0;+Ⱦ{5-RGp{o[Sp֒C5GηƘ֬A!(`^EUB0)8 W83_܄hlj$8 BkGP k[76+ Bs֦_㶶{Vzޛa6Xm˱S#s=5_jm-dkYu֕v^B(''?9 vz, ZV< |vZޝb/n٢8S56K_ҭB;9 ㍻Cӽ.[Aͭ-v.x. EX}Akc޷X6Xm˱S#[IsewtۢZmw;exwW3=ܽI5 וBPNxPn47{<袷ݱXt9*@iL }3^ . lGwlρhfLM9ΈtR9>si7do? [y3HdR=Hc/=}dnݏV:_|:S`OX y$myqXxoZgӥaseB:ZZewi*=.<J/Wŗzcg^\u%9].rua+G2IQIjw0YK{K>s|b7RO]iF{X/48 9VN4(a[me± gsu߽MV7Uu-nQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuKk <=OVZz$̫'?Ҁ.7o2tV$4S4.%VS9K8!";ՙqq2a@ b\#eΟ76FUאڵ[5=6\-FMU$bEF[Ҽ5uۭ)ms0~5\(&2Ź82 S+fV#fv9aPc1?QľVqიIgݹB>^>yeM^cu{߂.t[&9wԜuW BtALz"9QE21E0'=+VRJ=+VRJ'e7uv̪2IDqFRm;t1h&OCHg8@2~gi+Lbibh\nתYS.!ԻRTu'.G tiP4zesRZ-.XvÅq$UpEMhx/v}*WpՐGr\qJo-D %D:.z~x-7h\,*H98(Oj7ELӶ8=q=)RJ=o\xm2klt(P=َMsPE'VH/G>!AֹPFPGZM-bR ҤX\͞@>ՑEik:D2',Ӎ/$m9|sQ<: 7S(' 6y #9ϭ2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(,It".Br^j1H9R{P&E#ՆO}t,Uh (5I-ؘ 梺&ǘ~JKڛ^WxAV J bF[QmQL c[[c[@ ?-PdFK-i:%Ӑ22W!eN{37&:&(G4PtI?ͪj":FI' )8v'Ү6k^= Dr3*1@X/͓+L gNʜdsj-wRKi#*јmO09& o3GHѣ A3G<15hdOKF+6йX&4f0Z[CFPΥw-\Ν^i7wc9uLai3N k{DFec 7$X,pr@Y\rsS9\ܬL\!PҊF?xW>5Dȉn"GeS+YG#5 KX&3#s-,KąeKhXqY-חR9i\OSQQQ4|}= qEl%\~_\ kmeB餍tCo,/@qָo'I3 )p>]'ޭůp5\X\4jȠHq 2e؛FKKnPX@9#8izC]岶iY݋mPHubFq9sW-v|BΫ`:|`ccxTH%h6]0##&]N~( ((((((((((((((((((((((((((((((((((((((((((((j O+kھ&hG[QmQL c[[c[@6YCe?d}뻃ʝˉ#PN21xJrBonOy` >$$dRn;?&(a1m*Oaak-Ƌ끏W|0,W^]>KHV ̙$9N^+y:foP0$m/:NŸf;w;g4Ci7@݅krW &Mb-m$GeJG \)P^xۼFVx#6r;m, 9on1s&pf9%ĬDX(UԚζнiC BɰyRu?!muoO  8"a1<'mgr\1o  QKh7=qm&wBӌCAa1Qx~T a<+amV[Xom&-TiCAG͐pSm}-em I &)LiS5 ,:]٘ϙlAz4ѧͧ]i.,]D0T7{Ǔa>L_ 7;]acn2  Fj3 R)hĖK( ff-/4oh2k`mxd"8+O*+pPU[~\C\qȩ*29ߐu+jh#U2-Rf@gYY,]@c7699qXR[7!lo-yiob iN (`mc؜>_]Z,]#"fr3~RYaim6Tb;`gy0Ogy0Ogy0Ogy0Ogy0Ok{_,?ѩH[=pBqIoy.>4geۑtk$K#p4X6FGnG\ӯmƚChErU@,pSTu7Wo܍ÀI%UB 2VܩBi7fLi(0(mwVOܒH~ETbHKEQEQETbHKEQE ڐ@pKEQEQEQE U X( zrih ( ( (č#,H)̄(1(cXAQ@J}QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVR;'ʄ~fqsZZ]8I)K2ztֹ&i|tua(  e-ޙy7qu*?bO kV^G?n#[ K?%Darʖs j=I^5_񩠏vޒ?RvLr+KWk[ElgRGJ%K=KWH[Rp|]#mẀAqKCx"W1/ebBfU#nA#wǸvPhK `l+zT^D" 1즹TT- 'i! sK[ &Y؃q(< $Ӿm|#<덹|zWB-կ 2[!TD8  8Lkڕvc kkEp/oΕwXon=jeogeF!E]NXobzV>zV>h SŒmQrEu1‘j3_%2*I8mǯ8sT}"#f$UT !}O(Tq|UO=GxڤK⏵I>M9ހ:{/ K(Z2r(U&aIj}.?z߃Q=G~?I>j}.?z߃Q=G~?I>V$QYQc,NgzrsV&Y(UG& VTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?!M0UQN>tcDnd ~'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*!'rRs?RϥJjdxX)gRĜgGb)c*#Tq|Q?>Ǩݿ?Uc*#Tq|Q?>Ǩݿ?UcGKcPj}.?>'\,a F%XzH?5%VTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?7p]F̣@20e<A j}.?>'\f?RϥVh j}.?>'\f?RϥVh j}.?ɸҾx&U(Z(09qk~?RϥVh j}.?>'\f?RϥVh j}.?>'\f?RϥVh v|ӌrZ/Ff\VƧu]-Պ(V("XVXP+g`2ywN49ٻv.3\wfkY(B7+223!sèoF[c88mR2pxQ߯ՅA2ȃ<}hI.!+ೕیrxϮM11O SxjK+?\yH3 Aө'>l\#oV4z¿ʥ|9cܤi4u&V~ؐ_}#2 ~:i'NH-9b |g׎/uGk=,lv;7 `cn ^_Wru[* ﱺyf@sA։|U'-$cu;7̀nWSq>b}cx6zQ/u7k=,lv;7 `cn (ﭿW:}SA7Uoad-=I$&j wk [F$e=e{ip6? ]Qtgi>W__][KD7??&_*9q]=|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|14n_U@K$*~lm'?_K. FdS[  OqY6,H2KsOZt- /W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _nn_YDGBs<E1SS7V֡*Kbe*:FSKqYYk0٨-{slm#hGkZ|U.I3 ]]8rAd#.VIN <зq?/o%SV՟[}+E͂\%bI )'i緡-TMkDԑ b0 ~5y뉩I{5b0n21ȭmKMDQ̂0'4[ EPURm7jX";kz?nZo՚]" 9"jͯӇt~7S|憎?3+/.%ϛLUh/Xr⻯t?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.KV)#! ţœpxlDO `Al1Sjj8FWϴl۪@u:ҨGr` wDTV#Ij憍]V 5yej?zV>kFiFxȲ̎ppA=wY]Cm3ܖBl~B7^ϭ7F*[[1m=o?&hIg+HFp3ߩ9BVЬ0<% ?Ex ~g'w1>&hϙ?]e[;u[zo&[D[otzbX/̿oo.hC3X?!Ih}|@JWSp$zdU5S4c^M/D=|nh{7G٣M\ hmn@W?8dptP* >ȟ߻P*#<ې} cQH-#lJEU"~?G EU$[wyQD€-QU~ȟ߻QH6Bj֑"iw2f׿4rh}|J--ͺV=1\b-U !nP[4޾[ o98==F:M/٠ϴO@f׿4}?_-*6X s !nP[ tU?G>׿4rh<3R}?^M*٣M(6X sET6І*%fBl~Bzo&.QT׿4f>>_0[?^Mh}|@("|ۥc3(6І*%fBl~B-Th4c^MB2}"-Ny=ğjU{"F@V9G!Inq0?̿oo.7'" /̿oo.7'" /̿oo.SPfc ?XhqII9'&Uj>jEV[Qk֣Qk֠ 4UoG=?ZG=?Z,Uj>jEV뺵~~S)g9ǨNOjYJ8Y=Nyӗ,fwW ։[⫮kHK4;?V>rWVŪ*٣Mf5rh{|G٣M\?^-h{|@i;Df4xGޒGd̊EV>UVAhYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?i7?J \fu$0Ox.p;V(Xc[[c[@fk 5"+3tvI!_/JcK ʱQ#ʧ@H+tb7336rkODKּ<G4|6$swc~n|ֱ`$ Ŷo_gDT>$:%h[Fldz zn}W la15->9&X^ge}Iŷ^Ny B9 sA-+&IRw'w<`E++닧Q-"" ǻfynggH4hpxQُ?Tx͌WN)qۻe+gh*}4@y ƍዾќg؏Γ̻0M흒EA6۶"v֢ݥ,f2Wkcsmkʲ٬`T`S)SO?TK.q$_" (#k:IN~\ #s4Ƥ20(CE̿Yv@\*z TY4rJ1N^>fxF;y&OjӨ1-QIz1/f^{_dq/ʇqO5~#ݏŰ= Ac*k=.?5m#8I죹 jD'K^5Ҽ2IJd)(9#Siu oynʒ'??y!1RMZyⳑp`0 qw#G#&u‡-K'GGo{M7>n4ũm^wMF8y6)ֲnWP@}:U5y +4jWG{R̈p[i8|hl>jtt+{mb0I=jЭZߊC,Ӥ{+o00 19*k_Z\^Am-塸%ak q-Ľx(-'nY2Usө Y2Rog Ahdi#S)r+}D-H,%CFOaUy˝&Dp"lv 7?^iT6'Ͱ xYCo#?7kD 5}&n$RIG=ֶ<+pU`mݺwEvcGOgSj4n7ϡio?B.umʆ[#}x yrN;ki^Ie|f 9 1{ 5vcGOg\w5N=nL{Y2NX8=I]nЩN4/5",` 3yɮ_iBYId;o!1$U?֍"4kY$(i2rp j]Q-6+kiU`T@c)%h8+!J#6Qcsmu;KEy5xEJ0pns[W:u59X@.]V1)v ;qSZ^W%_cP-nⴸ_p*IɤSҠK)|lPE'&_ZO-:\"%I*(Sr1֮ $N" J #c>Ryy ccdxѕ"ݤv$DV6հF@8=EbƳ2Dll?'zˎwao=(EHT(e9uku?կRC ؟_ʝE1 ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@H B9l g1θB?ٿvKG\^!KΐEzV>zV>kFiF-g<ڰ|)R GKTO>7?eGqet.D" 2pz Y?<<5/G?熣B[:jܧB? q Z^3BqS4U @ȋ"qi 4^Q_CϽF>Jʱ@ޠ?Jd#j%rEBۛ !f-KOR?L#QDXj ϽF>Iyv3lF8#`^oOe7y{ƀ%OJREn@ y{ƕ\%aж@\6ۋ2H#_薺]]y@Ioݶ 9#_\թ%3FRK)OPRUX20AQ^?:yi@o( GSUA g M'f&o'L𶟥44 )cAG~EYV=Le?]fREQ |S|2A ;(ׇoZ Ѽ &9o~*|/nUA qǖ?熣UXmy2é@[R6Pï_ Z^3BqD9sixz˦~HX11N(`cmP8q~P_vom^3l1jz|:m֌`òUVֶ%Λ eDnLܻ'椱y'ۿ>_( GSUA g M╺'of&eK uUa&w}j9sixz˦~H7QTA&$M'*a0y;8<玦~Fߵ?ϊoQU&SMJm3ƗI E"tak/K֏ܽƛAk+ RGTXQTYu\EͿјȚPGj$㡐鸜Q"\^+2韮3@1x'D76mn#ǯ>rIT(*?熣xj?_*-[r EOxn."A,l j8cX㲝Qz> RF)"kVfU-PGk8Ғ՛sB09+94}_ 8>/m;dm7O0Mj9!Xpc֝4}_ ZmV)+yp $:{H++xa%V o[}O(Eqn1>U>Tq|Q? X]I9 u82{OzUTPP0U'\}O([RϥGڤK,U'\}O([RϥGڤK,U'\}O(0kWׯ->/ݷgv3+-/;חTU;7/Z #+-ř$\ Z_uowILєvSt'K S:NM텭_g_LI+x籶RB`T^XQUzciK;uA *Ġ_~Yy}M @( GQkimcgkyc3Qi:C{aktS;|U2*?( GQEҤM*>\mlS=p1jgkgkmokK j (x{[ݒIO@<" L(^ZIu8 }AU>'\k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4g X՝FX}~S\~!Kκǻ||ӌrG.:wv[SXVXP+gVKHW䃟p69 ?s?[dl-nDql.?!) 6ݖߏOEvW̐ď$&PsяOA1rM"^3-S '(lndޝ>qхkB۳s]H:?1^]+nmΖ) Dau'sscop˴mpօg<8u}t`kB۳s]H:?1jօg<8u}t`kB۳s]H:?0 > K* 0gߚ@ZжR/O h[vss]ߗ?F-Q@ZжR/O h[vss]ߗ?Foyq `ֲ#J+jUkB۳s]H:?05m9.w~_xEUkB۳s]H:?05m9.w~_xr^F@7QĎrc?X h[vss]ߗ?F-99ԃ h[vss]ߗ?F-99ԃ{PȆ%ITPU nyqu օg<8u}tbtNcȹ;2cێF&kB۳s]H:?1S ?:ǘF]"}~UYg::\жR/O h[vss]ߗ?F8~ut%Q0^PGBH\5.@/>J  D{ t$ []M#kB۳s]H:?05m9.w~_xuz~s{(cM+$($ߊ@ʭh[vss]ߗ?F-99ԃ h[vss]ߗ?F-99ԃzm{e%35 nyqu օg<8u}tbU nyqu օg<8u}tbW{0kYDO%Ï4ִ-99ԃZݜAwыTPV-99ԃZݜAwыU]/#}Bk ̊(bG9p1Ҁօg<8u}t`kB۳s]H:?1jօg<8u}tb?9L"eA(1F4+&1MR}.5m9.w~_xжR/OseK^6qSGg皭yw{᥆XΝ<.$2*(`럺9<:Q~v h[vss]ߗ?F-99ԃ}b7:t8~8V#ú_^^EUO3EW\ї1ڝ}/t3kB۳s]H:?05m9.w~_xE!ZжR/O h[vss]ߗ?F-U{>PM+$($ߊkZݜAwс nyqu Ū(ZݜAwс nyqu Ūq2[;#Fw(] nyqu օg<8u}tat=6bdQ"`#J@ZжR/O h[vss]ߗ?F-Q@ZжR/O h[vss]ߗ?Foyq `ֲ#J+jUkB۳s]H:?05m9.w~_xEgKC9du2+9:5m9.w~_xRiZжR/O h[vss]ߗ?F-Q@ZжR/OCs%h/̣kݎN?1\_kWHem -99ԃZݜAwюJ)u/ 7CQ)9 ר֘w_"LDd)r14}+_ZݜAwс nyqu w_"LDd)r15Uty.&[#h6;KN={KfZݜAwс nyqu Ū(ZݜAwс nyqu Ū K9@ kB۳s]H:?05m9.w~_xEUkB۳s]H:?05m9.w~_xU/#e1V8]m9.w~_xжR/OZ*m9.w~_xжR/OZב}졚;xW2HPIǿִ-99ԃ$1rAwOOO[(6ŒV'o~3R7݌ϸ~1R7Xobb,olorv[.ݸF6\~C:W%gIĖv!$s1RzmAҐΞYǨi6RX"h+hz|Ώ}鷘K:|1*vFGִc]Dv\%XpYԓހ3|\K+pF sVn8^{pGUN~?5y2\usY[@u5+ /\k(kKܒ3Tf4+V4~? ǧXz柧YEXX䐠u7?)yGۯoxWtBEfƐ Te?+zK6z^eE`USO|ݜncSӿ^z#F5gb+"I֢K[-F?OcnK-5k2_:{~~?ټAAM;ǫ<)~ڿT yXVG34-r{SV-s(aSӿ^z om-1ES,-|<.j= izj^Z͖(a#ҧ7?)y/-{2Pw98nʏCG)该돨Czuk6(G{P?Z ,[_zu;W/٠,TN+mmrz!:RD=(N}OoSN{U?:\,u iv.4r{I_V m)1 (aSӿ^zٹRJnG35hqjOK5Ԍ1/+k\K/\bV (ۧr?L-^,>#xQ2=yAJ ;V% g4;[W#, 3nMrMlM4A\G#8y'iεn"iZ'ZQ<8j.[?;p}3\r%ơ,c/\4)ukMqf4Ʃ1_/4'?8>_j9>7?)Ac~me`bbB{B}׊͵qf }ƨj^!ס[Ԃ@o_f4,tsOլ V,H[OrHP_,OgwSnF>65Op>f4,r-ZK$v˻92ƾMo9Kk>}sT?[?ƙ֟f4-r{SV-s(a_25֣O4HcgRf4-r{SV-s(a_3k)ƯxYbg`ټAAM;Ǫ&,Q=.F?}?xJZ/?!ƣֵa+ރӿ/u\p}oSN{qoNa(|au_<\uk}E֭_].5 t/<6l}k](X}oSN{qoNa(|au^]%a'n0p%8ty|sJi9w=!4 Yf$mNA9Or ޕu}rGOf̩#!O7~x5 w$#=딗ZFQuKݻ;Cr;OV]jyG꫉G^99oSN{K5 >]ZEqDt~5#R[_]i:sяsؾ i/=GټAAM;ǫ~ߩ>shԁf_QQJ][?OV1[ı!m=!@?P<#u_]ilr-Zoą$ ?ټAAM;ǫF|O}_/8(}N]N((k,{.[t #P{Ө^˟O4iCrz[Ow*jet!8L jxw W?wDg5FV>f,-۔>.zr`ZQ+O|St֧7?)yMcwrQrZF{՘7}hyS(.&&5լo{/\4)ukMqf4!}J<_o5 G?>.}ӿ^z?OV1[ı!m=!@?y/p/koꚐtGO/>v&?gcSi^մi =1rxsc0gYo#ڗQ]{s~ i/=P>> լ<آ%9Bs k{WvqjZ?[Gb^kK}ӿ^z}/\}BӫXyE$J?r~A%":=tX^?2O.cÕ Ɨ\i+24%9L9+JE'xI5D_}ӿ^z)uk,r{([tʊ޿x{ū0Yn];ד^4f4/4r]Z*n:2Ŀ٣w?/h~ i/=P_iz桧KX"huĿ٣w?/h~ i/=GټAAM;ǫξs?fĿ٠gi/ize +C1W6{p:!Kδ<9+6h^BY[ӧG.:Պ(V("XVXP+gݛLT ;Y6\ m`}J3uV 5۷D1aqHe=3H{wy2,[/-U$=$桳YOhkfXh&,ԩ(N9*-SP2-V#1$&<] [O6b%pjlS>ku2鑱ԑ_5sf66THò?1Xi EhGn8QR;>|Ggf_HVny~f͟?vRi֝V[V=v3ܥG < λēK놙U[L_M]ƫck[XMpuu-/.qO-dŪk_zc j9n2 tAKG[n(w;_VqM׼ j{^9le!CXzl, 1y;Dx g@5r3+ڭ,LT!SVNǃ.\THNkw< ޹.ks2OXd ٍp) T : nl~W-wg\EtF#a7wjksdN*qe5NWrx(RMp:[5@a)c9dU\V7ڴI5NV眏(1hϻ'V<.o$nop{㠧x{6_g4w0>_Kg=j2x9xD6e'?ֹ)uf<~fFHlM[)#8V#4y2j14-^Oմz^m:o/NoPnkO9Mm7r~UtO ̍>qXYwv,D;pHx)B4`NiqE8gW?Vo>hg c*{B+R4"Iҝ8"zL1"Dt}F&9ϧ?ʲUK}Ja㜜m>}Pel20>t--4H@5ȧd+ q8?Lf43N |ܿZq}+.⮟7dlbVA#4؆-ǿcnB~>RnA{u*3@2>}ɑ"oc8=0p)zi xɧQ jqPdb?Vug5T*nc98 TI BZĒ=hbB 4=K@֚ ||S 4¹뎽9;P!BF=6MBs3{$˖:f6$Ҫ>*֬f3wP*@;vŤy7åz1VF2FNaH6;H`?vVYbJ3Ehdv dFҽZWPEPEPEPuƉh7c71g?N⎑!KίxeZ Ìn~FӸR73V(Xc[[c[@fk]Ѯݸ! }J|5#4#]Uv m8n\~C:RjxҼ=A g8?Ur18v @Rj̐ʙ>N[x?2# Tp*.sP!tKIS հ=)߈ok[^#2R@$Y\ ,8=k>#Xy >^18dsҰ Dg@pG;Rc֬B00r٩5hɗjE*!*TJ&ק^*t.Zӏ7=?p3g+o!Z'ƌAIyqQ <2TrHtTe' +n ynǫ&STխc }RZbw{Ⴍ=moR剧gk"ue#s?ꄚ 3cxU[s'WZ%dDń9[hldlSXW7ԧ`X}ݣsA>KF𾣮B?R1 |ƚ61gmK@qoݷ#pF;*՜Iq׸7ܞ3!pՇ$OR/)4OOlsقc3W$rzq9}EM5R<ce#Aힴ.pzc@Dm(RF{~o'ғe$,#jE1LV)3s~[F?jqqOR3JaAˏLR23ޗ'84z~І0I{~JI~|SH$uڝQ&GGZq7M' Gi6fAGҤ^JhNXҗv~ 9ErvFv67l.?!) Xvk:{ p@y{p8<VϗP6t5ZN{;Rb%s, L:X9?֮L3~uZr2?0nUVj/$K@_Ϗ4`w [Kr-du Ut3 0#^;Y֔N>?m]:W<{Om^Y:uŤ1MFEr/Еr8Y쵠:lʼ#,nI_,R+׫?~7llapy _3~BEXDf),n%vX 9[<Ƚ3RAc9_ c㊸(2>N郟N+`0j!' 3bA‚}O4M@(1R!BF)\6:#ʫaH.q]J;~Ζ?2iFA$֌\Pчg_n[dP=6V?m*˔NmV9OJvV2T"_+XGdd&e[xwK ;t*Mbnt+hԨ* JP+K :եka97$t\:k<4F>L[n~)}2רW=F>CIK1ZBg#MvVyOiS^^ecT >~%= v5 `ݴgTKpZr-dSp\7xw1ﶕT#_)fA 8@H.w#`N㞤v?!fKwL*ƘemIN>֦+&gR( ]}k{y7#݄@cۓ՝ ԣu*WQАёI4GG#0 k{PymGc#؏^kYM #05R3P~aVdfwOPm[k*{hu㡧9 ?sw~x" r303ޜU8cy  lI_|TD8I捹d n3 TN]q֑ ؃A·dwEA J[`gדRSo?7\v4@?n~4$UO28|cӁVbP#i%Kzz/˝i'#9g4q{daҐǯj,"2JsNaӌM{NI>6p8N špyT&pxN-7sQU9@Mi?ʘH\HX{npqG0=4HE[2Mb>3~ptۏN=+u&n=uI ۷?x[N8!܉W]5ỵHii+ ;P)hg#%z7_ dFҽV ( ( (; 4KAq?wt \fu{-nncv37~#B?ٿ!ݷEX=+VRJ=+VRJ|5#4#]Uv m8n\~C:W+gmkn cn1vAҐUgğ֕w76c;v>î;Fx]K ⌢x)f#s@ 𛳭r 2GOR k[YAsmm VDzF#./rw]m9nL>OK`/ˑ"G_Ǟ*7 Z+Cܫޡ|ߍnQEGSjfY.}Q‚O,Jx\WUhnu#/"֍XWi>1L>Xc ɤgJ ё1I^;ᾔ aR?:`8:#Rv50(y`Uia``~ pžmļFjmGͮ:xlrJK?Γ_֯X 7Cx#l~P!_HU,ͼp .=!Gaz͙Y wtl=ʼɝU 2Bed[72Kn2Z²z՛V,J9Pze\ܩye#8 }G:G(?lf' -`r W뺜:k8ǚOG@8ZMRH D!Ǧ3&إzmƿgf[^9c~-P4s RyzظU8=1֕wuJ^8`Ke>Fu})4,Q`tm򬋋n3O4z?u(<5mi^VkJ#B:62Gyyr[Gʃ `S^iv|vrW=v]Njlnw3عXr@Mv9m:xL%H'Ҏ?Qk3E2HdxsV󵹔l0{>Eu(*z9Z?g$ʏ|Hjb9֣UݱpSf %DkO=.A ;h~4j

Ӆθfj!xF}) F[1`?Xw4Ьt.nnt8BDa =I},c7e;/Ų?kR-$e˲# <竉G mgQْx2½2泛`%7Oxφk%(T>Q+F.99q}w'sV^x`cU3stWJ56zϾkіF@#>к>aj"6΍o;)1YK7nv7N9)$0O0 ^io9oԁys֡j:q{<*]wHx`GBGN<?++Owƨ )1@\u#B|7nlwMp?sAo?8ǽt$?HYd*€35?`O~ ۶|wv1OD38*~#{YJg-T?7[>/؟3~tnݳ;b$;UI2F Yeoݿգ" iOvϛ@)P3GoE?b 'ST,4{o>bCӂIɢ3[>2؟3~ytnݳ۱ثJoc޹{6?c#tg#|q Ђ1WӼS40xr]!~#|swm^O -^K?eE.ـ~u=2oifp1W,q4Ŋy:FʋإGx7Ů0U$q\`T·#dtnc=1UOH6XplaOJ[n4<%ok}5Jiַ:c=|]hӝ=ZQ!LUx'ݏ|WYjIg dB FG56*^1G/S6y^o&bþSar[}F𥥩4Tb8Z{cڲ gpUˍ?Ӵ9;}o/j|O?xnݳ<#WFy{^͞FRUk۟`gf|Otnݳ۱ح,RH?c/< t86kp&1suy?_'_>oc+L][FP8NrO՛y|x egPdUPo^WL+\E=sKbf|Oytnݳ۱اiqysI!>[cm9yE=N{UMA61]#6L>7?n(HHr+-zq,$rZ3c. QF쑐>l] g ^}1W(rK))$g}嶆8H\e_AoY|AxWd#>5O#_3Hpp?%5Du@*<-omB;ǭIzGJYS?\Nƫp"hriڒgv|{v1ۭ]4*&FU"Y \YjGr$[?#nps_˾Gg'Ƙ$}Ĝw\c%q/㑵FEHhzLq,DWab[nޜm楒ͥxm 2PpAGzc<]񤚴ݮ@q^'u~k?_R_'ݻgcZFaf8U Y n+}+g[cޯwΑpt$>_'O>oc*W[6/dnz[Nk$֚O?j>s[P`|v/1F#??'ٿJ~1MX=kJ53ĻZ$Ů?#P˜M' ۶|w8|W&-_6r|Xeo=?8ǿXuO?7?' ۶|w8|V{;79ZFg3tutSP|Yϯ똾={T@_'|7nTg?5OC_/ox7c=ҫ|Gr{}4TEPEPEPuƉh7c71g?N⎑!KίxeZ Ìn~FӸR73V(Xc[[c[@fk]Ѯݸ! }J|5#4#]Uv m8n\~C:RjxҼ6}|pcFJҚvOctw$RQF*(M7R/B>ƽsúm%C/>4IVq\ʇ*?j.7=mu]?hg 3$C(O=+=)$6/7L"=}F{UΣ0sv=_ cc^^fݮg;q׽?Iu. lrW9(7 |=jǙ.}‚O$g5eVдȑFYpk|]@DX[۶o_V*QS*m~=Vfr??>O0~"ݴV θb+ǖALM*im#,OHthxv=a ƕo7=jFN[ A#ʺKmMѷT1%,R0χّX1OF'504aGE(v= n}*B.I>ǿ4 K@)vHE< A"6K±t[GI$F8ߞ:kꚮ$52t>0x䜟ֲ.4M Rb:וqI(-HSֆڥ]{zU)5G*yb~T/EO-Kf%׼`!pX@a)ǡiE<2p;Ȑddm]+hVG cFT~D5\@6FǠe9 ⺶݋C2 #'?97 9++1;^ qזi҈HP#yEXeIog1SWduyaiw;m),l91+=$qnV۴9gӒs\HcX0,?hYZOkB+q?( wsS9hg7O7,OUA GTn&KMDPt>¾vrOZ)4ĒHi@ZwauF~)7݈ TeT56:91drsN O^Kj L~$Ԇ, ~mb9늶WɨlO81lp:tI8wS{bbNr{u!8G#w ;rs*Hr/ n1cڞX UYYzdX6 Rb$g\ҩUPn*9K s8)BTgnE.aؔ1=HXARh@q?j<`*0۲TOZx`z.Oֆ6v1](P?C`B?J41W%r zUd ԑjqhq ue$OCV!*)~wc2S9'`.9**mMwCddlY ]ьVqoN^E]Gy6%*QJ'hhծ[_iGalG<Q@Q@Q@׆[%݌8goq;:Gn:Ɖh7c71g?N⎑![ΐXobb,olorvFv67l.?!+3uV 5۷D1aqHeóYOhkfWhwXFU$"c,}H> ҥyRIo%*Y봑Z,w2!r}^Ա<L}ãoÛ [Enp $|zGJWn:*Yi}1ԟR{v- [4y\.(Wsw8?,e_NɷP݊?\|Wtʌ ާW>1OR4}Vb3evZeʷKrx;CXU)+nua n<uS+nXY'#短w~ espB +4#dxmLK=~;fN #5Pch]qPFP+'Z1vlRmhv@jO4f|;Wq;`:5jFn*N*k y+FXRSu8+5>2Ux?MT -i+ZjS[1II9p|/+*N<+џzAN\'zQIFhR .v#d!N .~a?P22 Q^/H9kѼcZr.?i//H$/ z~9&˥+C-GXW^$u2@SvBۍ{dsQ1ON Vzޡgb #-?CHf)Y6a\i21iYPK9ZT)8?zT\D \*YWvvml@ۓ*u}DK5M$:E^[OkNp|e} L=v /USa@6_w93ޥOF ͬ30H k[q6~NVfY.|;MLlHh} _4S>u;hN2K7nf,H@#%y G[,w'A+oOw?Kt9qQHk0:͉Դ[5@,L#RxߌU{8ėW@4gkz5RMrܧ[}3[QVrNli7<[-ćE`w']y$ӵy/tXC3q}c]xUϛ5B6Oz׭GOV9,=$yy"rP_J ekFO?rjS>xc>hC̬?S?J0ֳ_yx'!>7ծ19BGʹF"bP3aXzb+($hT\;q^KGGRrVzi~As 3$U=ca@$ȨtTΛp\eVoAO>)>\ Lqʏ+;:םv{ \iˉd9YiYjpGmkgh*2?ֻ`qʲc/Nq,! 9YBAip R 2sEA {q֥)9c~])E$ab({6LJ@YC>yKH1  U=T>Q8cjT9xѶw5E#8j_꼚亄se[^|/f&@>p[[j0s6OڗYb&]y18';rF0ZA qi\z|GM>Bs㚏}i6'$Z7iG'␤I9?C x#==qS+*BN: fw2j9lgT Sg 09'q {֩˲aܞy''޳56eb>lWꑄقғ%zv3V,u=WZ6l| vЖ|!ݿ%QE ((2-f7c?#{GQ?+s] 4KAq?wt Vtwv[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC-VCZWsZtϐэ]}Ҳ4^t[n)J_x$~F5ܑLRh@2]BUd@EWeh1PYdkq>>~ՙ#[R(1\kQýWVn>{orWۺTS G"2ϲ}l"vzC7F)k/ڔ7MJ[kY$7BN=7zn)6}1KB= c-lg`ۚѹ;{,ܓܚu L^]\Zkn\QRHֽ1cy_-gqfZ]ٟ6s+ Ez66d|Çz` 9 y<?뚵583zrg`R/8n~MZH`B Nt.}F;kt.}+ԡЗL= >>aiZ/FAY7wr0RRTql\F_J_Ǝv*Oʞ7g]7LJ![k& $|W+z:|oIjޗC*g) ) ;^3m(K=z?iz*5u"ۡAx7<ʹ3b V7).ʣ;x5+UWRqW?F7a%z`\jУIzP>n9F:1cMGi8pI?Jǩi'cCԗE h! 8q*Co4V>XUߥ3ĞÐټ 3\o  ㌞:̮ȩ%u[ $>UbOkX8۵lx~uix-ѝV%lsק>8V2|5=msPNl֡w!uWc3w?_]i^ $ǿ;G[vJiGOB/q^(㵞'a]rcWj̋"d:q.dS?.?2?*|%Tdy|+.Zt|_TmR+f{'ÇZ,y6pOo=[d-Z/7I\6n?OR|_e͏MGL|61q\uK~W:-ѳma}mҡ̟.J5,?KJUjOg-M=6z:ڹ%n''\ipH\^Su4{#PacMW償kq{M:=e'r;SS%_$j2Z&R+k)clK{bfIɄK3r>}S~sӏB+FQ#?Sdac4"swG<8vtH% by¿ʡC\niM$.e-͒: p]4\"i"3ҩџK}打n揘7={ۍ+RT1ɟVQQGg2ȩtl;ǹ d0݃) ?N*äɓ$.*]Ƌ ZktRHr=;֥qu\jqA `<1@Ty"ILX9x2}lWRed=HN@ַIz1w)xNY$9 6 -00$< R#T H落m" -K? zAfFUI%48Uq𽔗LfI88^Ag#g@R ~ԽjT##|zk%mV-,@cV ܟZ¶:鸣ZxZ9 gښTvʥu' \_+ÚҮ=J|GAgUr~JX(U\cGc.#`k+`vXuSD%׵t^,.5YnaE“'ߡ'=s\H"ovJ#'*O La}>ƢPOl[UxnL4Џ-jC {fuil巑Xm# λ{FP[ m#rswz4Yc͘ts< DCSi#љU2ǴH A;g2<%kixVc2(WN2A# JA?XAmJӥ?0(xg3C5rnB$fpls< ֽG:Nߤk FXA B8w$Nܵ>tʏant9i] ͡#*EWxzչGop8?z|6qG\=h/SF8;גvq2A~YF}'²|Ii|^.NS|캷_֧>*(v",W ORGbYzzO$ 'mQGW>coH Ҳ3>iy'Ȟx }7ֽN1WDa)E\ތA=т!G??f\9Ӟ?J⫘G)Tז޿̹Q.$2@CzkIc9#bIAWpn$iY;I]'ICm/1vq_Kߏs Iocc9cH5HH~S} ׭2X`'5=D[,}HKrFZd?̯ԏOnc⡉Cl2U{I0Km\ ׁU=͠w3͕22O56 AG4DNo#~B3%/FkM4o.K7,ZL_ޫ8ǸP?g '8FoƧ[˔8ϡ5rRtgcrI>HG w`ίr2a׹_9kp~,HxoQI\F74rEmh3aB{J*r!jOsH%npO+޻;W8g-t+ LO9)8Pu8MpXM+N$֪9mIaRt;2i$092PH|87JޣH rFG?{:99C\!iXdg Zt{偈:9;WYi$zs56"M=r1\I`sbhT{``ЄEwϡV皑I^qZ khtVE֋d`H!\VFG,[3Hi`oz90/F̟}x .?:ՅơY~'z=:Ŀ{\'#1 H8A?2wVHQEQEQExeZ Ìn~FӸVlhv3p#(? Պ(V("XVXP+gmkn cn1vAҹ_ ?s?E힛ci3pr: C4g?m&?9\T/S$NN-ZR rV4d>|EJҺ5 mB+7\g}GM4ք4&Mo$Ly#ۨ hk:WĒI)ī` :'$f>T!??:UvR{ҞVqddyUXpαF ;x.mRQ†S3#Pi`-/GX'Ixd)E'-MOoej f#?;z! p@}5 ;1 k{^z~3+ٜͻܽC T BI@?*?Ih9Hqֈe=+`<;%,LOn0'i<AĘg3NG=*Ē-nϼRӢ5=xH!dܾKR✚GwQ|/U<@q6_m̨ m¼yanIe F ־GU^;a$A\wz/EՅgS{y"(rW?)<zW>kju`#7N0{w]X|k^K8~ϕ:3]Z0qc) d(X܊ :܃XD"F+ j_<׋#->ع2>IqN4!i2H+T)^f_}OB19\5]«mr>[@"㚵޳4PAViVV?[ꪸX5s%%dzp*zk'r"@Ο0?@gYWַIJV?U)j3~'ҽ8_e EAv#hl%xR7eԞM5"Fw`% n`@Zb?!o1qN/?JkbON?4|S'#h鱲 CCmAxR( `GӚa@iq7{6<> HI_J>RpAqUAcHH#i!`ISEeazNsӏ Rǯ)\,! T瞹梎/)JnzRF(fqcW4=qƝ5@n <[R5頰)z hraTB0i1$Cq*@%Ii0n=?E*AjFppîӌ ACr=2F>lLd9s)V.}uJxP&l r Mp0( GYٵ8hsW^kWlP bҰFnם7u$2kmKMI 7d*)p 8Zє 㯯_LLA>?QkIsß}zy4IK* 1#5Vyn8H;&@ ܢ+3U݀]J\R:H4yIˁN~{!^=&j8Q0l~ Qu${zGT8>]Us^jZVEUQEQEw^lhv3p#(?[%݌8goq;:On:C;ob-Պ)zV>zV>kFiF `f!8]\z 3m] {H㷇/󀠨 mz/beZԢ!sRY=juCU|?-3M%wȊ/WX%O=RW0^'9{H2[8#Lyž%DJ9,Gjݍ6{ }}Q2O'&Œ 6GM:׆2N}*ʸg%wkm4׃J™1Jµ9鸐O[c_1yvw#9ێ_MboW;#8S:=sUk{{rCHs *:g V1rWr]7xP7g! Mowʼd--"38]LsxnՙP>e.x-So|?0̅cJ7#jpFTS߶r%̴;IN!rqpr+~1hH3#  1SIm$q&,'="?@zt>5'VC_C2A8 s埕c}H<9j|+Z Jy0}wGeJHnD c4װƻW Mt1f?ش^ds}  {eYkٴ}FWY#(W,Fߌҵ͟bG8t\_Otv1fVDS&6W{gֈ 1=xneŒ3 vIzSf2@>07"} :?_WAG+n td@7Ӷ^jS_tsǹi:Xyv8f9 `t A]׭ɃR#=OjRM F-M|fs^z3V9tzN1zb|#A;fG_+~SR|#A;fG_(26:7=qU [>.oup |Py'דL@m `=m:nQL̃Qtgץz#O7Ht*m~S:PZ/~jdJwCM|Epw \&sfŋpJޫ{%wA*4Zz3PW '#~V4 ћX( 2ƝX#˷}?8y&<~ϰsiU@,yP˒?d=&A@&?:i6CX>O`.=sLF-Ic<_OZjNTIw.t4N1'a硦: (d2i;}Jǿ$V2鳱ݝ zk]wْ NYarzGzHn\ps*5ɯ]++1I*hpMRr!0UT]ҁVG3ψӑڐ1 <ԏHl_XҼ&X͹'ro\v6n >WWNRVaEUQEQEw^lhv3p#(?[%݌8goq;:On:C;ob-Պ)zV>zV>kFiFu)|5B^XRQKlm@t 3h3k:[@. {i m H}5]jen#;n,N@֥YOhj(MxI]ͱK7qR7pp>5CO͛DV,nύ9'#v(-J+*#|Lm7VcxO12#cw^ZͫjwRzn-kfF;VFﯵU+i'En'(.[C4< 8{W5h[W" b%84N}[9%mÜmn=+5&MjJ$a(B~Ss_4XȲȤXqצxo]{xm/鿌c#ɯS䞻38U0e煵9%|toZtc#LXx?}D_tho1Pn5"f"O#5ҡў?,R۴R #!׃Һ? d(gn%PsۿNx$u 6nw?-|r+>t)H&w2:%z/%Yv7q$@v\VQ#H%d8E^ůj3\NJ[[fc٤ `r?Pڏk.`MߋVTCzy}ioM&X$$^c`:w$d~5Z^,-dc߅:5+m7rUz ];LL^ w?;8jQ,w.u0:ӖDS_Ja 2^g]r\d{B"b(z$jT8GdtV֬RM}ý2y,oЀ|?KT}1?S5o*sD م)Ĩ?#d?usXVϴDTB2@vn>g]TW۟~*aIG8 L$/?Sy!6Ϟ+PIn~8y|nA ÓOr(0e :Kf9%~R϶*|!sFiT8_'yb:?<?u zZw4{BTZmjKHO%  O*.yUSbO=ڋ٭4.U>汚{O.@5J3gt'Թv5=]9rwy\FO;We&~4Ȳ[JC!Nœ ǥx[YJd1-O?vx"{kY$[#*ZGl)ݸ|RP#hnΟU|/YmtkvfʞP8LXo~[k48>߇DyDrR՝4iDzaojo5Z4 N1#ԆIYtbcQ^@U$t[Pqӿhi U6ۄJy服t:!-9*\.s#8ݪ60mbD\}Ղ*i؅6D=V>3lEH?Yra8uo0`alscӨ>=k҄ZVDs"3A=It)L}p{5>)ң̎>X㿦+XFH>KHotLßCA~`?ҢVc¯rk|C&l+܌ukU'k.[:YV Hb,pxyIӣ5k2%E};qԞ#Z=QFiv\,-3}=cI}P!2wSSxOEDcA'{VޛXV'<$##=z=J.>Y\1C1K(m*!SMH=T$MKӆa[oy|OBVgn^h\ #%8'X:Ԯ/TM#:[I2胠5ɠP6W)YSܹu]\Db}wo>4Qe[ |ϼ؎sIKmHe]GV&:frwy*AtyyY~An̑€þu~{FJ7YFHnz$]?ĐCx8J^rj1,ԡDU8{7֦[y 岏j[:KI |wZeٺu22ΌOO'NkT=9ޭxت|b+K`:1A<'ӎxvs7d喸yX Q\gO?OlVJRzNӏo{ք%H;BNFNKs?,{Ujo:x~Uϊ4^آ$b)$jI vUoz:CcA *4?VgGYaq*4jҗUR .ğIVR[ZUBIliO)o8.OGR4v^H&se$~;цAMzn2jړx&+e3d t hZ) aA76Hf'yO |ɦds&A<U6!OT"7:S@=^\_3k\g*?+RƷ.Z{g@e@Bg55rW݈k+G*~`O@v`:)|yc I*^E$giL6s^t$ @vz5մwsMRcגZIm5_.GR97u+њuXY'pTtu y;()$o$w7@mA݌9Q6;'o\- 2Q,Õ@Sh~Z[zY{BNb1&=OC]=! 6zdW.P.ɑ6ߜvydF:},sMpCΔ81~.pW.tSo{#\B֎<Hp0ںGMyS BAd$0Tt)ReFȇ 9†9Z,Ҿ)51y9¨lxf\qu3W5v!<<(zǰLQZ2hsʴ3 Yᝇ+?MKRse8d2}z$4<(G+Od +6~q OV麔N-JqW q_?I QyrLAe6=U ;M!5 3F,c}.霅 9gftylrG\veVt,J8US'4DR-ǵBt0>R>`P`s=4ϧ I֭xH-%f; %;'޻b:*8z4bWØC1I=n6_ZdIi& '9FSӨȭH[d+:s^գU/h8gElLE%[Cڽ -=B\.^Ja=ZԳZU[uSn>Y/4#"$<ec-5ˈnIF$֥Cbq5Xb-n_LfmA?ڤe~TǍ/ݓ`#=p<{n1쎨ylY(Tݐ=+5ϱƑ uPJ~6zԝpUVz҃Q'itg^^m'ƽ&;-Š($((2-f7c?#{GR+s][ 4KAq?w VtwV[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC'5'u*J1SG kJKT1tpeoI?xBN-K,(#¢78/#<1]E $Oqy<z$-:{5Ewu >gv ԚօMLk>Dl4v@{awzl^u㴓|9WT|S~]J ƿ@y?[;_P]^IK>oN~J0~E*񼕌xnocPI4jj]w t_ &Ž"}" O>wc ?Z/u8w:q9 #'Ӯyҹ(*;:?٤7:ltEsדҹOZp[ H0Fzgvk< Xƶꦩ7[٭JhBF=n׺3<#ֆ>j=V8Գޣ՝ kTZd Hņ1gҽEuXX`nKy8${(Q tE1,qFƣ 0hGmB{`Sv ^k[vTڧ.9:7O40Uip~"nqz^@}QT#7i0bUl+*P>lnzGj%4Qn,参7Bj` ~~.J0ve_~>IlJcv?Zќ%ǣJfAگ6l:2[m*ծ.]O/~]r#F=OB{n*#wz9|).Ro[2B[FVl1ֺ*'4c#;4h#i"339=t^ċː<={Wk$#sw^j%ԯrw2R}|agv`/_6ƺ'\𶣧XIg~d711q<+c܆_Q2GA/m"M $HgFK1$.8ϰ+|QwiA}KNx A'ԷLN3 u+h,bد+4>\1 L4Ga'<`sĿv_$?l\ƠzmzjWHE{Z(+1@0Vvg~~ 1QaK2Fx r*f`@?\u/١C5S9/9W{kQl5ĺڣU@G" L1`Xd7JzՎ[@X.S *|yRxqv{JRӱƴ0K!P%HnjKTٕ :V0CP40'az_]-nfIxWs8OLJ%ۦK?;q*HBs`J2˸qxqH As(d:KMX˶@~H P[RwTkytۑ3BOC^qpN*&QI?z/T|AkOmV[h?.OߙQ)*9-@t6Zd W1N+1Wܺj9{0.m+Cm=GlF,0L)mS8G\vq+%i#G ֱV5fjn슌ܝ<3϶ gZ둥ђo2BFЁF{=*d\y3''>ꯔKgBc=Ysymy-6=8>v{NpԪ򜎕G > thgE@@'[qP1n9_~8kl%i`Q//3p;^ƶIO 5bhr'*}#+\I5O"HYc#ӧ=+P_cQ6>f|%x~H|3x# Drq;(q3n54s۳4h˓k _"SMnr ,fV8< u`<X^=uq<ʀ c5NdG,Xï\qսBr|w]7W$kEr{:L%V\+DX~χ[ pDdLU5[F͵cr2=+\xReR`2#s]U=$ULlФ91OSZhDc"eE NNwk&2Y2mAlײixLQ1* ;kq_WIEb"-%Uc.'FSR%o^m瓒8TdMNy޺IF).]6dճ!+&AHr9j܏iQ= 9L 娜U5jmU jU;CdpFy+T 9{X;GXSLι^/k1ux8cqz#V!"{#Wך<VВ*;-Š( ((cD݌3qKIuoW|2-f7c?#{GR+s][[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) /4oyr3"Hza#JKT1tpeoI?x}J]&9,<kPiȟT9c|A{ Y~c)>~GjtңKgV'0?rY﹐:Tpe1xy͟iȉ&FrGֶ޷Ps9͍545Yo[i`OJG~'WbYF5;kۧ*@c/5="M[Ak9 ˹hr 85?4MF;kXd~%NO[aS5H#}==Ӿ'[HkXg?(yoo濟̐tUz >ց@g>EltIi=<$iM1w94:ьzg=rK"9#$G=}~0oy08~$K &9hʣ.rg n$#٧X9gIWU7)^6ۮTLׇ귗$`4 }I83q^Z(5pҠ!I]r̤dsޤM'uu;p ;n.UA"?:.mxՉV|3?u /n̟= ߉dEJ''c]NO*Φ4ixl$W|<8Ku2Pګ*QxAz4")fnןy_ΩrFSԲ۩jpMGgq$M) )+) ՘4wHlAbRi ,CoOsޅ\7` K+g'5)BMxUmsYI>讃MԱ(Xշnj=z]K^|~9gMdY.NA5W '+5l#0surImda R>LEE${VZ~Ynyׇ5hd<sb.0Z<8^|Ѱ^Ύr{֕9cU@:n?F8μBvGi+{_"[ ` OHyC*9ǹ]N[YU€'8g#aYJM9W6p:w6 NgwӮ!ԒU hrőcHRFI' ޲u./ee/~]cY naխ Q=yQsSQ84-xRT*Ia=GG"3+Ԏv0?}-3 fňPT`m85an) g*? .6.^ۥ˘sE.+*=bHcu[b'Mjזnjh:|G;f{v 1~Yk~j~.n|3.Ӹ|}WxJw1wKTkyo `8E׵ᲳUA,: +b\g[Gd;ʧmId`kgMN,oj4 $䁜w5kVk.9{2u8ϊ/Ѵ9ֆ؍v`q h#VB$uiYxG-g<929Ct髵,6%T%Gdv/mm.*2֮[pUTݟJ|/Gr/$lN}ftUbG_%ViY{ѡF>;',wO+kTX-쀍iϯ\{{XCZPj视N rRRqB֤',8o\$giUOw 枣lL@9] $*N\˕SqjXs@+DY8}$Re3Nk Ԟ8]teӒԢL9ݞFkH.IOlT\& REtr޸"2rA"]*jgy=<#,gMk+6xdt`G519zqַUrXIMR2bk(ˆəBRsse a[UDn n늨[*?:7gt.sՀ PNO޵-4{IQmjp]$=u:[qje+]ѝi^ΊjSо@ވpC~MOy,yNkM!UOYj7i\*K;LY:]mT c.N1Z)QQ62Fj%}X);hRд ޓzk)8g WVIN1Գ=ݳ%<+`q+{jCI\EsSXC^ѭWa6d0 0@ZE4˙yAU+M[TMt~e,rdgl~ ,, b~R/ֱtw5UV*K2!x`#c*1{'f;F{qh 8[}Q[b?Y/!⭛!usWm՝&va,.HE8;W5  [zQCM3k8NH?V14RXd6W5qԘɧ1Ժ}@Sv{%ep^<-_jD2].'%8 s\c3J/Πpso¹~!nXې +@v2޺QA#+AaʐUOJfe\(\~A>7On1򯷱> 4 7u9-1|F`'S8#ܖaR;\}:X:x:ȼI#VK r_#afQ)fFrg[YYoN5Af5 8!9N o$k5ƒ9*2tlD boAFN̹RUD OC~ōBS1\@osʟ>:"uc8v8|5;}V(d_xm8xz4:?R,o1\%l880N}RYj VB sQjUY{|rq={BSKASHOCF?9b?*RNb5إ ?Z}~"{PY䑆 Hs5 b961Gf>Q,go5ʢH"bJq]wK H>T@ zqob |>o~y^ >Ym.PV.J(-w[ӦӼ5Z9+ܜt8?\t(|O>pnLT,Hd-#iQ"0!?t7נt"Y p28R}\57M"dpg?dKS4K13\bm._qY>1=,фp5~9$;-2᱅,j?HRhTr>jZ#6߼Qٮm\J+u6䫂8 Je #S V0 l=I)4tVMHK?P͐Gp c )5 *#SH"CO+>_PId/ajb*ytJp}+~[/jApI9U\\<^NAz<5EiܢˌEi: I2 *MɦN,~\ؙIGC)S!%4yQX~YJ,m(AtrEJAfQRs *]]c6z~Y G^1 J :͏G@}3>,r,q0j1O'quMBseku(dp2? ed58Rmٴ5ja)3}Zn!O#tG^g.U=;ic~"%B2r?Vagh5Pqn%PƀFvp?J]n06\?ҸsUuNЈ4^5Suh2q}?۪n\LnޕiCla H3rq:N^R %pq[=r"~& JJ.KLNYf0[H\P7;tQI8+[9&*Ob?$œړXW+8[S؂ONT9:u̗M,zɬYr0wcpL>Z͌|ݽű72onw(mT3H0xǵhXb0u|4gK^\Q_W٭#{vtE!^EeOZ=,vG+4W` Xs7rW?. u)2:OX/%F~R8ۊ[xv -Y$1{_ԖX8s1'#8i- AvxNi TxοIJW4QYOPO5Z[y}SkʫOGN9ɠ]mg V%P H2{s[zdK.ͅnnWIcIւvq]F _ѐnDsJ2@Pr*04 -;Ͱ1z'z htis~ ץ`<7\yW,o©~m _ӟofpy)V=i[K$exsǷf| {vŴC4nzgG?#LWb0]ACԕ#u/iZ2s>⹋o\$'>LȽXStHkr}Lg݆{x%@?YQYZw$1{:.4B3:#+v!W=edX2\7>V (?t{*Iycwb ^j^,5>8oqopg9mN˅,  nFDAV\]=Ho")(ѶӵJ $,8g_?ʙxLUӬe.f ,.̀A9/BeIJ6)7 \Tʈ2$njWA{v'Q0R1޼w^Jg.rS3ܞ# :+Iub)TU)X/үq]F?0z1霎6,k8`*sZ&ܓ9"s@iV´~T˽#TݡRBVuFNSQjGjw78Œ-ڵ$-O66o$d-7(NAc]^m6mr ;I# dk-d(r ҼM%KmsWiygU <@϶yQyT˻=jIo䴴u1f,Ov3T q2uQ fZ\,L@^1ڒ[h-nZѶc!rלgW%Uu}@GT,w6q=9I] SI $_xKQ"l[wܙ~8$汰"#[aѬR1 cJlOcUUe `F},S̸XWi tB:qag)]%c"]@F:|ɌF?5I5rn`@(;MKXLW9 >sZslhiEdl8FYd|B㯽s2 \NkkE渘|/^UedxkE\vy~')v&mG#g-ߛ>mͳS {UHPXg/SKݸWD6cW>v _ljO;]yΥ.[?ËסXg_J]IqҺday#zYʼ hM 65 ں=G8}+r L.E0H֗-#fd >Uat܇@I%bxsZvpK 3ye:z2FpW:r;qu3ށq4Iⴁ0B~fxQSE; {nd!uR6 x;r$`88:&gXc/"KcQI>$o8䓺8?GnʩY.w431U3HHǯDyx\tK.2&!$.'޽;rYI;('!`Wמ+6#u2~~Wi?k+8J#mpg&g E9>=atc,\Vl`IoX|?>E?Ʒ_ltxhr~֋iq@B$yǧo˧Q%)msU6E<̹79sL #䙙FC:t-U`YIc @``wx nbZ{qxPs~Ra.GNnk8DR! dD9o,0{RmJ#U`XƻCҰ\‚pIj2ݤ-_azWتu(~=\)SC,ؐ"<6WsXtdc!L0;~.-'8$ `.G@FExmiz30Fp{Bt%?ˌzjI`/=oʪj6>ʲFd;089?wr *ltZ-g!P?x񏟽q̆i.$%|Dl?S]ww߼m'}דBœ?ϽE:r{NIsuEq$n 1'5h`cq̻ΝҥYvFp+MKyt_!G5rI<;39#Doqv8<7@2K?h{3P&rF;gִϔß x=\*ھY(=yQe-ӟ:/ӽhYZ|s-Nʯ3TVRj^huX'}*Kb2;V [%98A̎fbr+Uy- TʎƜgR-c.&m#9G5z:6ZF>d2QI&r+xP8VV4cnAZ\r,lǂAPIa#ιʎ52VCďf,|ՃZ%eQƲ.GkN9h2k8Ud+r9+GGPR-Y"`GNyL :}j,]lrO<@I1Y:*nw C-Wͬj:=Ϯ+'Qm }~I-Y2zUw7\fb}.Kuo10zgs֡:%r+:LLK#q .VF4Ee1T_?g[އѣpĘ?wxYrM}%8F7YV=anXU,ҖрxRu> iݭdy_LUkI%+Aۓ#Bk^H_)"dU2'nwu 5ec7?lS$E ʾxGf?}&wRGar+ p3(T@ް/oy3G| frmkzZUPE¨tm$VYiR6"& '\cY9wY~ͦI.@gohgS5b&gG`t>:2-Igsg'?B? ۖבާr"Pyܣg-m$ $zJCތbrGOYդ_qR tjw6Fhr0Aߵpzb2Ł =jMrH&ganѭ#厹kI|]hs Jg&ILLs@w[0Y%l~F}/ýM@*p\^% 0P[K}q5ܣ71>"y.gUqq˨@K<(8JҒoo"#dSthUT`_]K{o׭A-i#:Ƥc%fim!G|I >Ԛ{x#gU in$LH$sקN~ qoA+]p+?_aJ-"P:7?ª=ܓtQdvx&+p`ߴ5i."ZXzzgZJK8kNTEG.Z0^fpg' `tZ6i`fLG,xA5/Oϩ!d$ qo*2)@H8ӏ] Otg{*Kֶ ,Fj}Նg,]&YT: <j/#N ?7_åS; YNݪw9=O^Mj}E-# oi>NIמ4bzvr*e =i9cBEEYRhA=5ww-7O,eY?8zM'M˰>tҳ|6rızwűKh% }=WU+1\yC#bFʹ|V,RKpAHG=q߮kԯ# }z. DO*_ j{oj^ǮYDYJ RFݤ!'[\)5=w/[j epFq5g4tsSITꕞefva1#S=*NJm;V[8D-鵏B 7Ka.le7)q֟=Pynp8P)cT%h&EW珩jhzqZ^2 6 A-%2+8598nA N-!$Iun>dp:SDG]p#55tyrUw4vG=i`8ɪ0'ک5f.fzrjmkwuQ[]+ ;s=jXWz yvRdri DHJq?wF@m93۷+ӵ/H/bq7mA';>{-BkI@Ybb93qBŜ@SUMC@ᣘt}zҷTCH=sV-ޕDr%5pI\R#ӡW].0+ *64퐫Ԋ4@I?(VwC+)<ʲhس c5(> w ghe>}}6N@,`m2Zv>y?)<7Za19 '9?8MVô xX߈r+ݔ,Ȓ>V+=K:O 4s0ϯtmIR3/J~<I歰#Mѓ p qbᰖM"*/>ƳȞe?d?ϭP6ѫ8RUҳz׶1Fաs qY}(O?u\"x?j]>!& Jg!0N~MD4ȣO H sl{UdҴpڸhG֡8FҸܛfsWP1?FA)u#jzzpd|cl¢E"4(zC\"BxsӭH?p>T?Һ}(#3\OSAӘVGB1 t:=7mӃ KF/K 0\a$u\ΦwVb#^{RW qI~mnrx== \kReb=5fHfP9}6cջ?Hz]VFO1L0Ckr d+5|JIyǸUhW>0FĀ硦3[[Y?+/ѫ*m*FA=k6:?0\׫I^^i?Oo +ĽŠ( ((cD݌3qKJu5w-nncv37~-+B?[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) WhwXFU$"c,}H> ҥyRIo%*Y봑kg?m II-QSۊcGjF$/GM;XY3>R:mO?Rb֨614 :m.2Dy篾k+^3<Tzsz?ЏFcG.g:INg!hU 3mo,^+{měШv8#`2p1Ұ.'\ЌzczΒ擱0R>{fbLzp;RGuqmaC2$zQ/`֒XHIcGCx2|DR{3DGϧR~i$2f"_-0~P@8OkFQxRkMI$#'?]úm:[; H}|d3g/sv!y~lʤ5Rs3YۙkE[Ts`>X;w_Z!)m%%bjJӷk-qE.:u >/_fgi0sTTΘb#dBm&4?0x }VNC{I(c2Z]PqRFOƺ @< aXדI@$`{#Xxiq[+U3vY-ΫkcyH?OV/$FH@qֳ%٤1bK?L֜1\c-d=sV3$o%''bŲ! ~]$<.ىYW5-KhҰs`qbsXF.)AĬH%YK[6`^'*3\'h}j"1HS~Ղ 3CP\ZVWk07&9w<,czuZ懴QqJU^%gnT4Ƹ9EpMoݳnU/0PX9"8Tm:`]毭ǭʢEi#uP6QwSb [+(RfخT>Z1Q\m4{%=Lc3OWN?JNYVy\I| r>%}kY:z"$,#d$g88*gNjiJm^\#$:ޙL뚫-ح.f*$<~5^ۗyAe ::wqR4yыVklm;gG5ƅdF%\S +"-%JV<$63khYđBg^z\8L[ւwmp@9 _%\(MII\\Y@Z#RH9-?!Wn-3{ְ?RkZ1\vuaI~xz=B+,g!69ymX#tL7R>0N35I-g bcw*Ht[^3$ ;f?5GbMŘ]iCb.Z۸lmu k .c ~5bB]R+̱heN>0O#z֧p۴׷j*ǡKdwC.O }U:v8BzrGO*-YNszz[ l-#+͋-N$jȜ:z}Gzn%K($q+E$WwEwzdi3Hw⸷W)Ӆّd8@NʱdxH +:MC"1<RV9M?'׫I^\,[ٔn9]\v3EUQEQEw^lhv3p#)i_eZ Ìn~FӸVC;ob-Պ)zV>zV>kFiF(#-DT;s(A۝3tZq}daČJ`R?!) =³C_1I :J󧈤Kw7G1JTi#4x>!EH.F g?mض٦_Pբhh%+ uYf~ A [<{$ծXF_|胯3URюް[JXʨ€xC|./ao/#`pGZyZ(I+,傁Y$SxZ8ڣ =8J%RV[ KVgY4X[,r`1T`tZą9l^yJ < I^}:˖gFRI<CZ-3S. ff]ǿgUm+$'\FO{HԊ2%fgi ^[P\u>up$y9 ' ĞtiKrn@!@$Ϸ?9(4M,$FIU7pO]>=f$)x?`hO*2.vFzVKo#CqV}v[9}58P'VHmn;ʱƒ}qW|83PA=8=Tڠ]rc*?>3gnjp:,8n,rsIo'#OǸ=G? Y'h򧟭z޷ ^kcH#%݀Ba^;|2ݞ Yarx`o^V;wt?L2jpE`}S+ρbjA$QrǞO8GӬ/NҮn#1)Ž2IL¿ lIxT_-ڡ@ivF@϶kzKT.gF,rzޯymߞ͔:pO$vES##xznT0F+Jnrh.\D`{k1Cwv'zqhF9HeP $q=+:kn[#bmB{p:ք#OG2ȡ$HPb3G'kAYevzfh:Xi͉6;}O&] Z(A?9ggУ۪\;|#лɴx]ťf219?*4.)HQǽz Pe98Kf2ۓ>4K4iʤȬ\ c~U \m,(r1MHpٝȹ!aG$*S8G }+A(%pƣ*;EghlKk!ѯ^#y_k ^dbw1+֙|R&ec PĎG#ֺiǞVG=YGN׺D)FLrS-כU+韲E,KcwS1kq[+[Eq2orB?tFt1UZW WaحEsӯ{ H~og-gn۷uG<[bƥGcMtmr@NPoF9nocBWWE9xI hAZ[K !uc[5XdA,sk,U8NW>~U>d>k7p]F4kFy%%Lp iwũViIBe2A+pGZ4_BF,ȻK#~FeG7{՝݈, XElC*3CnI81׃5&6D1VpY218CD7y2~yG9rv/\/psV&:7͸ro'Nx1N]J:o lK)O>?4 L7s8,H(L -6Ĉȣ%AnIϯj^v[U"5$g9?k(B4:տ;UOc^Uህ>f~ϥl閒&w 8$瑅 QCCu4̓[4*O˼=+3vo(Ҳb b1`tFџ5k,6,Dk t1͸ĺrAZ%)j-ry$yi/@'=eXdAUdw^[[" *eKUvu:o".D7pc)lx?>N=K˕ܰ@qzNn !<̧CooҮ_xMgk;,zM9u"̷T~cN1W-#ɶ!#U|,}.3՝;ڭeP \aʬkizg}&{fVl 0y' :fX͎X$PAU,m4*)ul2=Amz5Z0țvO5-_m˧lZن(B'!ݶMsqjeek8ڻrۻ[*t뭨~Qg*ߕ2F1v8SU`[}: @+oTSl?،D;2FJتzBm&o"HSMR7D*|ߜÞN6YåBXva:{a%̰L `1h&avhևWe x˹;IdWUaKv86[/%$ ʣ?kEk툍h،CzG:zMic$A}j[k uK}GQݾL6 w/W='E3\$HޒKjtb33ZzStmḕ B轎huD'L<~xk{- _15>c]OF'dL/nS[?a5ʍVy }i ]G%/Rf,^^[_oz>'Vҽ.*ȉ;)((2-f7c?#{GRҿ+s]M]cD݌3qKJu4wV[S`}[K}+`}[K}(3lj ?h򈠎( *':V7fkbN[ $GeK .G<IwwvojGc ";NIl'"JKѬtp%orAKFYy%E̍I'-I'ӎ*[?$Ks$K&MՐyېNxojߺ|olF0Xj(VO>p U rI\wyPI[m08vZ˱R$k;$pbВ#6E*Σt9b~ R斁-[>yL)1b1tCơMB!["BUPr;q(Mc䞹?jN5[3#F O?LXh4)nE83m'PN8MQsMվ PIpDh{Mj R).e7#A`s$ s:e[N}N?*Ӷǐ#FwZpEK ڳ5X4Xs4Oʻj>!|DQּCg,qܩSA_ǿֹ#~Ye gyFq׏Lvp@.z%Ω$9 lz9ZiJ5V?\ {P3H <tHT*-:6νq )H{ZGI(˹SAҟW"Âs2\Ȓ\}kV(#cTE_8 5Sӄ9^)](ڪ #%kx]?Z?qmى& N;w׽ww 6vcI iʹ(XF c,SQKTһhHr3qvΠPxzIi$M"8ϯzUE+7kRW8-tyn =}x^3KjtX'{DKuӡbvz}MRyЅ.OLFc'{ZZB:桔qWKOifqoͅjUd/vڦI]r{=+1(A=\J<-xn/"b" f`9' & gsn-r|,|1I#/X->" Ypq5xS6DR_’\JL A 9R#O"A#~>⺭+Tu=-oEfe c-3泂8 8T ?ٴ>SSYC.9=\+-<&jHE9~_5l1|Y< ~ۑ8ºΫ(]>$Iw;{ds7[_IrHDl=ѵgQ--ⱸK5b'9ӌ-ވ[}ӈB]އh/⦵ͽNq+=d WY5ƪQHxRj>xCuǖUc(%5N3'Tgo4MIdR g=H&$1W \^bgmjs:}kYŠKr721a76׳v5!/^&$]~@~;Ou |M\LpX/K}\YٝL{Lc_"8U%vJ1P~G<9T##)l(t>PJ(H#} I,edT#$9fXSex&+skcr"9>&ܤfi$su<=,V/S!FS+=69qܞ|]WF̗ɨ̒Y2Ȍ,eUE`2s9xubY Q+N`8o]mʧpF{ߌyg 1T$zdqԑϡĩI\0/*]mbe^?㊻nUQBl4s[}NFWVR˼׊K0ZF )Ez>ދ18L~5{jЙ.s"DTQNVT] I,9">[p$IJFO՞+3lV#sʬj)d q)YDaOS}NEӲg1Zok^vJT`t'&BNBq}{WED[`re3c?*IU0>SӎGq]46}k#ۃ՘nI2c$[7:SmpsƢyG,KKw>m 3{hVu> _amL}vy׿5KTEIf@;6ҧv9@w`''c?ol0 >m!%H`69rFg$Eo ~bO|1T rzn\S%xg$÷%G'ǿLiͪGy?GU] F3$^ngEp$g=+!,FֺQlF#䤋͟Yӣ3Vl `>Z'Ka¡o9EYV1Dn^^Ro\-jZ[d קsJ{t#[IoVp|G)#z031o'xdGjܯKё &U >aNF3HI28t!_1cשnd@#q6NaTP8֮": k_>;ᩝu-A2ܤϥuayUr~er#:n[$9w\ΏjS9ڧ<~MA^edɏ 3*D[U0qW,FP0k:Z:}񁞼 9yna cZUo1_ f`)i9*2]8w <.1J iėWEPEPEPuƉh7c71g?N▕![j[%݌8goq;ZWn멤3V(Xc[[c[@fj߈oYYJN60xv*fkb+(Y_ɂ$fbT6 ~Q)1zF[^Ieʈ f9;H1W/S$NN-Z4$.tkK y5FˍՉ+؂=y⥳YOhim;Gc-Wog RιAU/jy+',/װ9? mޝ+[0ϳ#{Q]5; M+tFz]YkэR0;~5iplllg9]R)9iJLВ4r@13<Q49cW +)Z7f*M۶@w#?wkB7c%, -4;"$d5T0zA>^jby[9Ϡ ֶRi7q+yWrRGQ\bf[WS߈a9E\Ҝ 'bCʻ ̸@! ^}(PvT˯G4dԌT ֈ4T@윈|5ۮJ3qެ*EGD);&˵#ò,>Ps*:S (b0OqW%tE~H*g‚IՁ;@V8geT$d*.*ǙGՒ8L-xRsj4t%ib,#+1f$0 } aV[ h%;!#0FxqZxQiVw$p}ͣ*0%W) 4~d<\3XVg,+X$>V"*S]N'hSE}Y;`5N-TE \q[0=am qrı.ۋ[6gb6:ZVJVTnFXb ]1{rz2n stA32?J-VI0>?BO 3tݨݑ-ZGQ3KȬ|1O-F_KcذE{lʹIXN\~Az/ћ/r;{6Ku#fI['~ry$HF%0pݵspqӨ#DKM%KA nFzgy:"Qw;yWmw^VVG=EnYnʌK$<ܓ9UdXL%c,8a9$v98#ﵨMJC[ chrɍfLVgݯL7oyf9zZU7_6 r9G1v9ӌ7I:7&vȕߌy$3`2~Egw=vX)þ wRiIvU#$A,r{0|A4Iqi[ mv~kIkh(a%\d|푁5xz{>u ?vMە!iVhw"Rd)'kmwOAooq.G~lLH8=֥))=ASh<KۃXeuYDg}ΫIp1N!Vw}1ʳ- Tկn#f$HK :#Vd, st:e,r##sH,VBrO {Ri6\ySj%0H!u#rOZ3=, ڢGyhݺCl^1ҴVH6 $I'R;JJ~8+^G HPK(l\r}N]V2`w+=\"{7aҹ14]N7"Ў8w%c?S޶~M!$+d~8/i=ʜkW!1nd''CY>|#nXC'ڐsWc)I5k"nˆv*;Ǟҹv&0$̜Ki_ƒ g?=9P[uN]VpT07Y[)ʞQ8v1U}/RfpQO5_ʬ:Hq95-w<%^xgߦq+Y/ F 8k}F@_%~P?5ضdcYQ\t cǯe 2'Ԛ؀?6}r sM4- %.H9 {ҬEq".܎^z[k')ҨbҒ$g;S.DI;Xs96[ ?jJqZx h+pl*sf$G}0=zun[r6$FWxgDd52!_*xqe<d}0I[MV6pC} U#_$G>`):ǿoWTg̎IF&x/]C1sr!##۹0Op`}_WKpQ| ȎnL^&x,c+1+~c-(o^s덵%v$8x>%cO!wrp=F{;6t3Fsk7(FONsk%㕔>"]Rv%y43_s?UO8+U#R qGO`7]F’z} tJ׹:l^'25=kܥ|Hv^+qqтoHP1=)R9`QMudqҽ&KoN 83*Q@Q@Q@׆[%݌8goq;ZW멫lhv3p#)i_Xobb,olor-=qQ e:V7fk]Ѯݸ! }JC3l, kY)<\qƹbŘTZU)gx^' t5gğmVH.xp?(~t`2U'#;T%&+簏h!:\&ye؊)?k:h{S^0 =)5뚯mYI&3t?֚P݅n~gkJIMN¾$79̨H ]Z]},ogN Gjy`{+&p۔ޮ|LR$&i%u3nc ǕZEl_dD?Ҫ۵&[9.I`y_ZӬѴ湚u><#394z42OAk9٤/cc]#?V4sUC7-GWݢNndŗQ3]p >3N0Ո鯃 "_bA^O?1]$(!ֹN/Ŭr!60#5RZXQv$$+1Qx$Wбڇf žmm20e3@{޹KaH bs+%?xV'< 0(FgUr==75]qXk( d'v5c¹ڳs+ st, jw<*a[r3֢mgj[ mؘGwf)`?z\ns֪Db1IYzWx+DL<)A<ѤmVu֣h"q6?@=L.Gc,OE^留3#}yFsrNPhv ±@`6#aFhܻV2Ļ򵩼pɮd#TEg &}[WgOW5T(Z1g^vvNsֳm]YeJg}=aYwpF=ǡ\ZZ8v+G83Dmղk o\g_]d ~{th$ٴ p#Ҝ q,~Sݹ=J*wԴR[8Kq$cl])6kU^'Ngz+]>`021K)U?gd8=njadNv6/5{k$n"8 ?^p;8}.tSivn\[;*A8볉t *#@W +@y4g|B=Ml|sA&L`gE,xcjz VSo6]=zq ڼ1^j BybsMyuoL11=k\"q( >xf3N4s=@u^A(((cD݌3qKJu5w-nncv37~-+B?[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) XvBl≕rO PƶMiisS71 yv GE? 꺅y66TLvKۙ^qq+6±=? -@|SFH-aD #v z+n"D-('?ӯֳE[0MiYir KRqu6 Ixqӌgs]MFJ 5Fkw%{נi]Y#ğ(ПZ௵8 B2zU9uXtP1]9osqVFN<lI'&P"GE֯Kp@Sc~sP궢=hDכ!v/9!Qo}ͮs eI',!a\5=Ȳuec>$htKxa3,; u9@ fƔ&K˳jbSI_ӟ*-F_HUiy0b]@y*孹9o-`2HuK!!͑AE@C@^UVcЊ`heˋ @<zqm9[+t`ç[=x 2+C_IL5 OH[rɳӁJThtpuI缝bHI(S/`"oFI s+(F9e9vn%6\-eYU\';BxMP dRD;ozDzR0Oq;k׮#B6fX uEw4x  4^Cpŕf1HJJ'Ne)VIoB +js5?0`'ic>*`Vc4Dz3zu5OY-QYq39< z 5 ajf$Ӷ}N[an) UbGsKa8F/g?mkoinRP{+wL]pC)ʰA漣ƾM Ӯ6&b||6!<ǒxܪֹΧ%6ruReGT`.Kn{ڸ.$Ҧh .g ǔ,rv1Uo6d׏ SJ(XpÓ }0XًYwj䟙<,&.PLBRqOv\d]y.#`8NzV K?*m=Џ1n1c^'v\;"&=7r)*ص5,W}:݌N;I VoBN@0= j?eas'“9ox8',zszQ=*CG-B-wMY'gN)є|U-Hې7>8Qߥ4BFgZFyF6 sO}~5Ax`vTf8'?^5 ?,k@-CP+++$9=)tM*{p巂A5uMӡ~UHO**/{K1Z$;q*@?SZ5⣨IpIlhdQ]g5kZm$wSN<،cs(wwoNN:w-+SGq<(yH P1ʭ]lq)d 29OL+1- U*y$ڣn {j9&rJ?bKFxc}*FIL&HknGؼlKT;@V6vkK9jxԧ+K>d@󭛈"z"ݖ%3goT4иJSFTce" J6ċGEZjWD3|L#jS::Le$rj5)e/pB@B}Kiͅ*3_µ%XݙXURz9kxFi{V"XĞ S6r0~k{5.8 nt饃Puv1`n0}鰬 Qu"WٷhqִU@ ÀJvZB1o`bBK1pG] z =ǚc=Fd&TDMÌPqK;s8밖SD+1[$[Il `{c;W35׌-U@eV=V#?nZKui;b`bsi\8=XT6kjtVde[3lW4H+a&#Et`b`rrf_.ryp+ҕd^@)`;E|cz!#ABڵM%blrXeHx{W~qN6\'91ԏL.9z3ůq8F8i0IqxqM^-z p@QE ((2-f7c?#{GR-s]M]cD݌3qKKu4wV[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC-VC[2ƳD1`IF*p}q`Vj"6n Y'4Q"i|^NߨiۙfڋxaQZQ"8M:$/oΒk+K#5X?ڜ&\3奎h ټqj%2vf<)ZE#$eõn^QIhz.^?#9ǽRCg]M!sU ;n[ɱ5rzv hR2e0duێ`6I!A~j]h&?дf`F*>UaV]Y2͂YExq'ҩj6gH`~~Wr^yJUN3VMܒ\yVJgivzg'齌.ח)jp8>Kq+0Olzv+O%R,3Ҹ=b4 *rf{Fݚ,4EG18#z@ڸPi^"hU$1@= <~tQ ,$t+Xd2GB yY$}\ }28,/6I ?t9l%b2:&O;zO\ڳ/2n,.CC. sҭ!gC$B6TNyϯOaDPDe2>f-g h́q:/ Xiz}~~rP|s~Xlj^%(Tr?y/$^28c.+uyez`T7i[REdeg1)w=J2ͻ"ig= %w??6:Z?hk4Xb0TϠުz^YŎ"e$ƶ>cGued #,@#'?OӓOF(nhk3G=eڀt\yr$y QyOM灟]z\\@M;=]$bĉObOXva#Ϡ+©Q/fy~:DHx,=llU1Ƕo7E'\?#޽5ẏ|,[ix``0?֨ܺbcR2݀E:j~Fʤ獵\w\eѰ 8;?t=Bmq@ ȯXMhI MvRt& uH+H<?^j*eh+ŭ8yIKWhY3B>xUm|#$l\qZK TdwvJʄ-~ {B:oUHZ;\߇oՕ홗pPǥSѪZu9:RpZᬮ/3&_L}/Kr!=-B=kRV ,KMZOؖzd,y=E]6¶Mڼ/eGPT;FhWϯjbt'?#Uʅ?V.wW"PZš l+KaJ%1Ϧ:Ɲ]K~Y3ZLKpî{U猁VS٣%J T5Sۻ&byGҩxXF(oY ?*[ >t(a:{ T42".NUI)uw7ar}3Ҫ ʊ^;OW!.;cf=4`19*ZFSlUݔOj;idf'?21+Ǜî rd={"dnF?kͷEwo#26˂ ʏC*\’?z@rx(mHVn- $ߐi$id_u ~5EºH|(ak˹UVA~}Es$I)gld@֌$dJ$㌌~~SǹrY U1c#k.pXpm!@AcOYe#NVD h@khg5 5(`^ K"17Pw{z4{YݽoEzckG?W\s[V++_E&Kѩ<(\^}pkWEӄ)(-2H2f$\c\+PWrCn?v`O'RP5;:MY"ֿɺ6`Ay%gમ>Dr~lX ;E[+c 叿'kN>~FX # @g]%Ɨg Wح 1j'Zwm= Elb.N 63>sskI$yg=3םmˊ#!Y,ÃϠҳdmAnE79=>kQ׏#>gG\ ʠlmKoCtH\S7:aUlۈH\3z {՛j6cpoL9ޕ;XQׂ;OD;'ZҴ..fuh F܇r {nϦszg$p^m''r+K~(Ӡbd+yE%Q\pIWU;ŝͭw20Bk5/ڮ,gi#3)c?.3Мz\<Ҿgtɟp\g^fwe5P#S! ߓZapuD Xi>3nE @*`eI#wry M  ""=鏥hk7veAL1  W{UhX[DY'_}IԭkWNޚIı\o$FA9]|T4jTcSc~̂A?qij E+=r|N1UW:p_/#_''rT1E|TDgT/SJfFtIB;'#pG57^F"C@ӿ+ŷ4RRFGt2#O>`r s'㯩銂KJqFÀ&@CWMcjl[m@#89o@H<:Xn.%A"G8axL qPc(_țU4mD+pޣ\8#IdTe;g_fM0yז<`1LsیB,zEմ$=`FV1"R<寅vP؀ $Îdd㊳i.>Ԁu1Ds"K`Ic;GoZWcY=NR ]w亨Nv@cڝ5>K8I{\,-ŵYrxI9}2`cL:f@i]''Ii#9_rc?q)c $q2v֮eS ,1KO9(\w5^$::G-*/Sd׵POz)*z*Gi'!Ӛ[fԢ~{FU#  REqm/dcpMIF*זe$gI͉ispQFϥe]YHTOq{[.2ێ8zcĤ4dn-\doƄ<͇>I4ǰhQ29$ǵha@P JT)M{V{:I8S%Iq26Aq[:)%&fco#Uu]8[,M8?ikF2۲eIi$Kw~ GaofOxpc ojx+;!9cUJKJ8 :4UXu68DTA%INYW?6:thB4MD0TsbXhά#a7##366r?5D 6MeRMDR #3ҟ++J*fXg kNiETsg`o>5B쥊(olWMRfS0sk#+f$tN"Qf3:O ksqfЖ֧ kh(QEQEw^lhv3p#)ieZ Ìn~FӸZC;ob-Պ)zV>zV>kFiFmۈ"یpݰtW_3O\5X.hnAc>!iLQ@'5gğxvvʱ(Y%8$$qM,WLlyXn6g#c$ӧ@a}"O"+2S,Z_98`^d=yS&$Ĺ@&2j J۔F"gP?w5f-,9a ߭fA-.vv4ʫs#PԣK(!zZn -PEqpT 0p22GsRԴ4)ƮYr0@ZQ|BF/nH,S&rǨITIsjdVQ$[&7}yy)6]}Rm N՜Ifa U=W Fx!6zJaCt=:Y3g O>}EBډWILcI[cy=6Oz[B裛oFLl$:di:H+~J>4z[Hw'P^FCasϧ}MY<;c .p GI6"NsҢ>ݑ" W/Y:=2{? v{7zg!Zn˷lۙ L72)B@ɤD*N*zƅi[w1fUJ ik&zP_ 08Z2G֎t[w#$q-I9m-U$`kg`W&L4eXg){XW,fT 'M\F)hTz؇FKR9ݓa<-zl9+/g7wtK3̛ULQl=ٖtIcr9zK B8Q H-ڴ-:R6sx8?vڅ堏$gqQ?we y1ONIoM$f#ڭ[_\[9x&91#1Tc#֕gF5%-|e[&nsq! dRs NU?JĊz0{qY-IۋźX:r@8ǥ6}o=:^%*R\KZŖ%U$§;'kkKy?f*\:,zJWK{ 4"{rîGz|}Y.Ɉ7 zj7 aH%YWx6sp:m&gYJ,3˧xCB)%%݉n]ҹ~g^4ug4h_ys8o0*` #=6XkS\pp<׈aO!Tg[0>7}kLʶhIwkRmoOҤY_0~D'@W$a.H#Dwߵˋe+†-3U RޤdSG!sLݔDXn19Tż- >pூ*ޖ79Dr==.kmmR)V_aOOzU4j<НozQq&p>f̀1sslB f6eӴ]JĘr%mU2x'ի5Re6I{m8 picr`wʁRBf!NMN(Q# _Iܷ^I97x۵fiwna潉ei8ʧ<æMMN/dl&l\ f Oҡդ*=0Nֳu3>,M1UdbĖ,F۫a<`ch6cPE,4V]F۳J-G›~9?Ҩ\=եܐ)`ʑA= 5b1G?WOq{t-<@K ($8A=N:?#Z(\G~n=p\)}ɺ%8`{#cYqћب3039#䏧8R=+ jQًHcI!U?P PbXX{曎1֠p?icUËyԫx)J,tHyw?D!Ԃ0FG,iv@}\ n:em?ZrS5 )4e|{+Z8*q\q]q*C)ГҹEUkWW ԕ=?+ӵmǖ_gVT ckP ,4Mn!󧾗-X!Uw6\zgVHy=8=΄Gک\Hϵu8Q~5^}>+gBN053pw8i85zvz`7`=A~HM8p}GɔYOO=o[ʎ FsMU:ֺQ3PfY.?ov$=TNSFT֭M̿6d=s:d$@6X#v r/Z+f!$\|1aǩSmZOL5 jصϹ"iw^Wk7̗7@oUUPB '4FSkLF`S[tFaQV%]] ?(\1Ԝwx9UݜeNG#޵.O zJ qhM=km[PM0'bַnSuZHFAKWܵ&wVf3Ѻ5j}.1hLҼAXqz6}}LZı$쥕F#'jU-4{??^vYp;`]GzKIn3kZ⿄n0'<`(xGѐ-3!~:!p1ЌMhPpWx5[k8%¥U!?{$!gQqckr4]ޡ@+^55U`:ˍOXm9#$uǵte}Iʁ"y4xfIuq4f=S[DH-]q ?z`j5ΓB"zd-Јݕ=sj;du{oJn'5Q VooXbBHϠVTX٢lr.#c :i%9] <ƬЇva۟VO@2zUV8c+-kY7IlF&=ʪ FFOq۾=n=-= QЈ[Jk Svz]*VWdFޅy.ͼ*c2]B<)Rw#]sN:cV~M=jň_Qz26$IT=x΢l i4f$pq1zV1FPV[ғZf ND8M:k}ͼHH0p? ֳ3w 0U'֠OIdUQpxSߧV%Ջ%uH2FN8aysOMv,B6}rxnmS y g54Eu$մ!RW9Su\FVT(p8 瞧8Lb1HbWGʩ>:ݔ>a)7O@Tq} ]YPq^XQ޳[V`ѓگǪDUTs|guњ*zuvo$!S}qJ̒+&@!QqcYxd:X<ҦťvkY#an' {Uƴur%lO.%HW:&cۖ i *[=Z V8;P}=jf d[u+!uS#Ҕ^Ot`R$rNTlW%Pe6=^1^{[;P*]˩[[jݗ :u%4kn1h0{[G2ay}?՞x͟Wu=X"IU*@\Z#T%S(#ڤ#"; 2~(+Nⱝ"`j4}j 360WOSqILE~ *wk6O*cRhGO;i858Xҗ'bq$Ҟ.3 +2=BE?:XKqRٚjǴ5k)L668:r fAiw'T~Z0xךNKAHg8[ Ls鳺JHU?N{+c^3p}E][ 69#4U= v@jRI?jmK*,N:a80Ҳt>6 ;?*B09J[x'C¬KmD,1RDiS6T 3Tf!˴-m,AKa c„좵Vg:g@Go~i ]L7NzlqwЌ֊3lNԋAL7wO)eϯҴR!b2G N=U`o,+](f`}*6`~Ts*99B ?:]۔ֶy{}}*ڀ0s"ёCVnqYHnr1T&Y"ʡ':%L,q9 ک .m*11I'~~F ngiΐ@38Զ팞eFءoR ;9n%*O$ PnX-{~\SWzj J %(qN}I^\\$-T@?Vy%Wg71@F?+s4iN-f j篻w+.y8G"W\뷎ǿckH8K2)U隗Mt-U= ~'LᄑXZҴ2k,f2[WAj6+p=?JыsK4?nJFQm߭CZ~"hE, WďW}lm4iUnM s03WKu 5mS.s/2aO+xtX+ + 'i.?K@pb+7ΝnoPٷ-b y=IЮY#+'(899~0y 7+o-G6f|xaddwo \Žuȥ*1siMzHn*6r[#[vm Om%~LgtXerpuZ&731Bu$~VPGuk8K[^^xb1$Ux,${S{wwz^<@rwP:gȭ0=Fsyɪ,B cj駡NG=\N?!CF,3'=0Y!Ac5Ryvh)Oұ?*a@h1r3w-eǡIUE_D%~VBwlsPٔ Xd~ `AS_s?LݬȪ ǜ:}AhjvڂAo)VNY% WE1rDr2Ng֩3w,-X!H(p=W۱Q^.EHU-ā{g a-pp2 W,5]F& "223I{ck RMgxn68rzֺc{ٜL Ȳ;ES$qh-lG Jv@ܹ铀GbA3"\csNddqۮN23ZRPE4o U$Z( k=3Đ]y\8==\`9b(gAl=@OM՜)7̙$ }KN35i y&uw9JQoA:I>bwH-R5qr:?`NzsSEio%mH\dfrsXwuazD*D+$LU<3"T6˦K`OMݦ>mĤ/BRH9vǩqi#$*]l" @NA#?z *`]@g?졃(G&74F|1FI'G݀ᕕzWq֛sJ!imY^I e>5Q3ms{i~dqʲ =I ֆ4sʪKTqR c30žJ1%ũk} rz^]$7"0 }Azt\\:¨$dg=?_yuQ#ލ^xs.~ת[iL$q:o4]y1U緡}~ktý)X"hr9 V{&ѲN1Y(G\zF#'%!py4Hg wɧDd9ܮ.ݍ[yNH)Ey:К-b B%p%'rǽ,/E?=NeB ;v8#^bGٛ-wx$[wo k4QE ( (; 4KAq?w \CW<2-f7c?#{GS-s] !ͷEX=+VRJ=+VRJ|5#4#]Uv m8n\~C:W+g6tmk2C帔6ND|c6ҐJóYOhi~K7& q~)SN#uqLnB?T=|ɥr@@#44hL?n7KR]U|1L|Ekj+ٵFs{<299iqk(<2]wD8PI䎂+\=l_1gF3O4]lb 8 h9269*yn\0籪Ү,H"=i"-e(cKLb NsK֌PA52]L5OZ_{>[țֳO%O*)I!PcXr 2]L.^]MJE'Q5>}EXK_m>⥧ԤFYy+}i$*T) #PF8u@`F9a5|y{֕"`YHkc*[fMaݟf\i?-H m?9?Rk 9X_ʶlHUI[u7$^[Ao8de<3m v$Ue r3hkvJnⶣe#2ܷ[Jx5BX!e^צ`輎 uB\-x>ƘmqxڻthdmDFI\:?ǎgp[8gi `aZϗORŔ8T aZ&=%I?.,GсXWOyhۻwCT6C=Eu%9' ӑ"U{]h/9r[+cA֜CL_7^&F"#Z)'[%թ ߵHQpyP z4-Ǩ#TJ[)`08ޘOOxhJCp3 =!sП«:; \z TW:-H2(b+t$pj<`FLSrH<h(]zՈgr 9#ӨJ;ۑ1RO1Qҏ(Ӻ!aB ثclOǖ#"g#=)1:Ӹ:8um.;=X>:8ۗ He~bb~sr)嶒j/Ԛ:̏ l+mKĂ|Iq,[D0Sʁ>z M"UԆ`ִ3Kk2v{gxRJNPJoDcrji"@ZqRX ;q/#223l_C] k^[_xjofR$z%5z^oKWhu$[P+:Trڥż23,.d7Rŧ]6u* )z#e95R`:֓ZǓ_Fcv})wGOjܧLo$T}̣#2{(+n\Ǭj8n?ҳ=")%kW=mm,6nM Q85~>-J*1M66kj/Wih@Pgu1RZ)F,K+iRU@>k6Z p=O g,1bG<|}LʮG;m$̺wn]E>cy|==3Z)K3>wVw+*cϾ}S"W3t4iJi_B'I xBR0/'=+XU7:Se@PFx]MkIRCH^=vIyzwEJ<\oҳekFӽIwHHRу#Xy*y-n,C@aYG4:Ԑf \{f7^:YD9Pe탊n85h5RN(昄(f(RE6wzJmv1SOS=% D85KRRf~T)'gR:M^NȆj@' Ac3R\} ː}k(s֥ޝQ> .F{Y74RE( p>q1lH]P˃?íL\ -8֗;/c6% ROZw>cbmV?ָ>Lq%Br?^˺\cOYM()<9Bӧr&Ii7=EKY-ٸ% ??޴ 2#S`V;M"2I]%X$k'yb:.WdzKttlr>E%"IDKEuCǒ͟ڂF<bWGOUc :m s]17f.l{V+hȷ!ǒ#1\: uA$ܐWssK;x5#h\@8Php#10P'`Zۿ" WLXDRd`rx=EJM]NiP2\[[0/I|fK1GFۑMcV^Mlz5r-$- cG_-;L,h<{T$Tɨj1;z`)ډ:=b{?)YOk>9U;QKI$èU_\n,?i-5-%(E Zǔ&tZvK:4`x=TlPHav\;V]-?H' ZVY#IbǷsJ7Ӱ+>+GJpzۭQy0mW]s궏 l`Hv?*m޹HÇ1RU)讫Wi׃A6;c= Ǯ;+֑ 1?&v]1S 9-G5`yǒJ2 H>e]QؒHHIIAk7hmg1x?8U`1w?謠 S\& GNƕc 14ֽS:?ja~}^p?&=נR (Q@Q@׆[%݌8goq;z_롫lhv3p#)Xobb,olorh ʶ+W :VfjRa$JW G`x:t)1O {CO׎9?Ϳ%F眓֧YOhk2T~+t;Bq™3uv\j+Ξ"Ky-)R]%4(.sԙ4fqH~j7g[ҵCÚZq{7yrW۸<0##U1[~&>)~?olڌw#9ێE';Rbi!<@) ;E!R`q@ h1Hi{b(c4iqK4@ (1Gz1h=hvn)M%%/Q@ QE@fSH>:^N=5(&}=2/Xxsܵ=)`bx  G+}sv^>l@ݼ㕐t_rjjH%l~< d- Z1dvF5Tyb# UcghX䔂VQ~j]bKYUc0&t.)#magLV|b&@:m|~me'+Oi A8= ghR2YU^64mu-jve}>'UʎyJ[O-]zګe%fz\6[`k¶)T%_UƮA2boEtl:dx_QVq A?DdrM(|E;Z~+ KDZ>k)?x0mHpw ϵuќZʭt.ܴa?޴bpFzedħj&OMh`_o>4[orHkО2*?JF( *OTRzMcfRC]bܯs#?ZLG(/+WL݃Ni0y"G晑޽3:/r|>נsGo k4QE ( (; 4KAq?w \CW<2-f7c?#{GS-s] !ͷEX=+VRJ=+VRJ|5#4#Z_eU1Vv ^ӠY^ٴMZCpceRЁt2 .]/>ًtfQIR.QzuCRXZxחOBە P$II*pI)YKFX?OhJn}ɤ)@B>zw> iq{<2]wD8PIҹ1O'N.&aMfM"'SKv 7n &9ԣSjFN21Q4wҗPbf{PF)9ϵ8(ǽ7E.=h@ bPá鸧@鸠F){ъAGzQF3PO&8(րSM8@ JE'4")%.(4P jd>=( QbG88)c%+"\wfysrM<+:F{/'dn;1 (?8:纟jʏVpr85f=N EKJF9lPƬ˘PܶzJώ{y~S XCzERKf^X&.ٍiiF3.NsΝèSS;ⱖ5X-@!L?6sݳy~?1?OL2ǝSY<+_ 4X+&a!*3a`R9x\Z>zrX{?:N/hMR$bdžR8ntn'0 ?^;}k̠dGWL;1NJI po|93uCqYRA]qF$g~ԺwSHӆ>[N]$Ҏh#vcHg,JQɺʙmXvܙ8%n#xۊhKYA剥5&瀐%pv:m.$E{{wME(-uۯ F"7';IZs˪'U<|/ 7\7œz K+$3Ԩp=ɬ+ ȠD%G |oǶS%T7*]gthG>q!5JH W +Lt&MPyޟYS*km/^^iQ"]TrמʒbBii߾`BD2G9ڶ8s=&a_*#cwn|Pӧpr[ Q^*R\Ҥl2?\m҈nd#o&煎۳GvZօ06ڌF?JX\g8D# Z3E=3;m=* &My]>RF+רBA ?u]5T~5Aе-nI.~'ޤg7Zf0\1V^ p2~?zf ٭䑲w6\O <:P?{0 :rE HaJI=Mc1G4's@r{zq9MǭI@ۃb#idQЁF0h0qҀ{ѹh1J\sNHLSM?oS@ 0E9cE&8KތPc:Rb\vGJ)R~N);QǵQKAF-%RI2@j*(j3.g|lCȥ.T>fo iqUϿΟ< s)+r}*yGn?fp"]L⦗+kp?J.$UuIF*](KRkfZKGZ4`μ.gYkMm]8{]"gZd *UpUʷY<4Y=nrkf ʠ~u {& d2y> {#(wۥ^*F~SBjW{3ןDѮca=B_²<j6:2qkz]kfUCIg8sSxa>Q%fo'a9e brGQޒvTK\`ELc 4ǎjbHu r$e SݰX܌/ [ 2Oj.c6HSɧn.fOyGv/ >÷^A岨¯9vYZ%w8>|8VTsǿҌTUe);1hj&tDG\Hzy=Kk +* 5a00z{sEB)^py%P˖خ3Ϻⳤۮ*$3`s?sJJ< rq k+9ι72Q cck9?cG, kVk&D]`Ano>艻w ۜ7} 7@5'hEL]`An47}snsn4X4ֿ7}7n:*s cv-|CC6@`ؠ Oֿ@=Ic\0 7g47}wn:(ۜ7} 3@5'hE]ۿF0'ݟi[ᾌmsq> ZrƏX4o.EscvOo2tQ;q> ZrƏX4o.Escv-|CC|7W;698[> ZrƏX4mأnsn屿ho2ntUۜ[> ZrƏX4owmsq>oEscvOֿ@9hw(ۜ7} EMۿF0'ݟi5'h9?c@o*698 |CC|6WvQ9 7g@oo, k?`k_Oᶊ698[>ɻqWnsclog, k?`k_Oᶊmsq7} E\:(ۜ7} 7@5'hE]ۿF0'ݟc' Uݻmsq> ZrƏX4mأnsn47]7nscv-|CM9?cG, ks|5vA9 7g@oᮈb`N1?'`k_O Zrƀ tEݻmsq>k.؃nsn屿i5'h9?c@o"n698 |CC|5vQ9 7g@oo, k?`k_Oᮈb `N1?'7]wn ۜloOX4ֿ7]7nscvO苝DscvOֿ@+|5v `N1=oᮈ msq'ֿ@9艻w ۜ7} #|5;698ai?`k_O Zrƀhp0'ݞ7} D]ۆ698ai?`k_O Zrƀ苻p0'ݞ7} D]ۆ698i?`k_O Zrƀhkp0'ݞ7} C]ۆ698ai?`k_O Zrƀhp0'ݞݶ7} C]ۆ698i?`k_O Zrƀhp0'ݞ7} D]ۆ698ai?`k_O Zrƀhp0'ݞ7} C]ۆ698i?`k_O Zrƀhkp0'ݞ7} C]ۆ698ai?`k_O Zrƀhkp0'ݞݶ7} C]ۆ698ai?`k_O Zrƀhkp0'ݞ7} )kFI?تW9 cv-|CM9?cG, kiKinsn47ý%wnGsĜcvO`k_O Zrƀ$oZB8ۜlo֐>698 |CQֿ@Hݹuۜ[>u.w>698 |CQֿ@JݺMmsq>ywIbN1?O`k_O ZrƋɛ.69x[>|iK9j17} W9?cG, kVp"0AT.r6n屿i'Pns |CT`k_O ZrƎU9sK4fsqn~>|.PuU 7gm|CY5'h9?cG*Ϲ|;,a-ns1c'ҟΛ@sF1=o9?cG, kv9<,7WsOxLkmw85S@5'ir} 9wo҆1ݟiOc^1?O?`k_O ZrƎU9rv#ns׌n4dlXϤ&N|q?O?`k_O ZrƋul_9ݟí^.sGݞ>ֿ@ˣVN.rݟi;+98|CT?`k_O ZrƝmQsn屿i$V+sn屿k?@5'iX.h7V#ݜqc'xOنwE$cvs>ֿ@]vJ4ݺ] c;c'ҟRn.ģݜ |CPֿ@=Iеlli! pfDU8$ E]۵k19tak7@5'hUݻVsLn>ڵۜcv{5 ZrƏX4UݻVsLn>ڵۜcv{5 ZrƏX4UݻVsLn>ڵۜcv{5 ZrƔxZ'A?촫eӭ->[nջ7> stream JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJUs}}謽=syy#k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZzV>sFt-V|m.?e? Uˏk: "r]*!s $KU42U^ Nuny;[ۖH,zUufW1r nyȪگEU~S˔vN)LKާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ9#K>6ioN2WVՏ"uU8,q^Gv2r {3Ȩ\n:SL7?]=W2yZʣFgh$<ā '?J^=UKa|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|ͯ٫{6ViecX+QL(((((((((((((((5O[)^^jR_=cƉ~:V~:WA-Q@XVXP'_w)޸oNsφo5mM/ cQnI;9·HmY\< ʻA;N2qPMv43VqJ2<>h"'Y#war 1)f ($uߴDCF2rAcĶ׷,V*|˖X].k*= P5>ɯYE?.,eHګ0([__,Z\Ӿ<+ BEaz㎧3Ē4=G3E `F)b.I|ЊS%w;y6/V2ʗD_KꚎzE 7`rKc z L"ִxX wAO]9NsiVD-N#evn두F2'hb-'Y#K8,_ c`ʨ#pA1S|bcjCe 5-Iޢ4IyD/<``GM zV%Ԡ}X$Ǚ漁c79 Đ3u{X[e /,,w$};sqV/"dIvD9=6%ڮ:RXi&].1ù[[2]VP EyY# H ןҴ࿋Q)۲8t Ar2x9Ηtzy{S7 9]N6@㩮iKugFTcYCtn8NVNrW养.O#*MK6ݟx3k]E< TG|yzoᐋd^3ZR[K4#Mfy69cx2rw_Ƿz\$ٕ3Gz>-gm! vz\m@0%՝vu 1Z+i_h1Ỏ:ݷ!có/)]}}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^lR&? o_oa?CTz;}J+|t J+|tZ(ұo-ұo-Oß4AjSp? Wr ռ1kj]xtQG@}>וBDA tOSh<Ua$÷Pqάr~|Vk7WK!k&vNdqC <㯥 <'La%,HTgcq#;^76uZ0P7@Ko.h4hLW⩃ 2@c<ǧPf{(Q$C?;2;An_Zr9>_)_C>>: [;-8y Cب_R0 -tNOqopH~H7܆$rT# 9}Bi"ٷq^\"(|qNrxZw>dv<ۙM,B ?0BNIr2uƴN*oO˫N4ۏmo%n#Q#+xĈBrޏe"{G3Lwl9^LwUHԌdܐyu_ }Ki5g6Tq6쏗$J$?Jpvt2(Rifh!0 yIjiE"EX&n,[ <9 b}:L) EHPp7IoLs Ər~=dgE(:2m[chS k|!3A\A5zLR^$(qbVP۵7RtGpqL``~ϧ^N*Fv㜜u*p\D+ʫCz67D!Qd1 9ҺzQ簢)((((((((((((((( ȳgڵ#,6zC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( d5}5 k+ ?S?W[`hW[tEolor~? Wr/ZHc9DЅIQS')iҞiҀ*ֲɥZheXJ#0B #Zu/-7w1UaVޓ.S & | >Pݎ~=Kqٹ{{1Py,X9(p:N-h¬jFNۿmA/d~ [؝^ESQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^fkGYmZQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE k+k͓@ V4>KާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ9#K; _w)ސTs} tOSh<*ֹx3T?uK'Zm⺵K{HeiDaa}Rݕƕύ9 zI @':W [դiD(*9I|u)Mf.c\ҸO~W|},xc+R . mrH?qW1xS3=Zf$P:.kX' x/G)Y݅]CIc1#׵K^#VR,󜍤Ǩ=zW=綴 A9,4ݝNׄU "ڭ$ œqnj~M;E5V:-CH׭ZYFrtҶ Kt-;Ep!U %m/# Fq7A?1ӏF˘㷳2Lc+ssV^}ge?wzИtbGFI Tx:v) MI{#srALvw~8<;?_skm e-P7gnF@=;4,]*h^/5$QqsޙG,,1`' = ^O薗Vn-m@?C_bO{ZiVOcOyd ,sqwD֚Jjp ܎R;^1^9+[}k?>m"X Xry~} Py 3EuLю,Gs\LyaQDZϙIm/3&ˍ }sh4ko<.LtO+qJ9dIZ80O?_b -u\qDZ 6q+ܑVO_=i5|k2ǥXK=Ky;[\cFsCW%E-EtV?Ь!A}پn XAnex#pB<|طh%D\?/~f>OwnsG?=rWOYi|>qg,'u'sҙ{ki~-CD>ZV\`2y Madn ڌf'o>݊$OI-4ծp\|!_trWEŢi,0f 33­Es\Io$rY~9}~{{\讲O6}ɇyy}O5A[G3m2!ͿmH猑Mc?N[ |) }.c.I?"7qw8մsq嶙ty\3|8rG}η,6zA0vI"{ժꌔg`*(((((((((((((((+͓@ Wכ''h|COXo_o_or EPzV>zV>sFt-]wß4AjS!v J{x'#Dycer!FzdZbomq0Q[w_KUqM6?4_F uc#q\OjH?\h28{9Hp@?L 9"_SMm\#~gp GiB$B#,ʎ[o^+ ֿ//5~[;nɅdcg9z~X%9I5a 9(?kx,O"(-${ e  kjSuE; KHJ= zxrfF$X]@ኩ۴t@&\~{?s4QkUt.^M9@'H$}y[ѵxʼ z W 8=#??GƛŦtjw=1 , B1m8Ϲǥ$mq}>KHJ= zx{??Gơ`fdή iww2|4c@ϴ[KhĒEsHaXo>{?s4, =74.HDP '#=Ses.|f% =k}U2kZsUk mo "#pQGs y\A"}&!;Hdu8VokQm$'V/XKy=YnaDQGF}84 #_5Ƴ0vp>oKQ$ѽiI]N oΛl9Z"kiYSϒTrpX g vc??GƉ`IYU6"Kx y0Kq봫wg/8isY#u Iم}=+/??GƟw_/MċmsI3 eV ~Î9mٵ.ZV4KDHd n_??GƩa'mDj_is<-¤F0ZK-dKԼBcpJdgWPm};@̙ߺB/R}KY5unXiEtlxqa7])`G+Arvߥc~h}ft:-n $Vp$zV>sFt-]wß4AjS!Z-uk滸W *2w*H瞵Po B.|Ó } mn$IbyKhf%eܥN ǑLEKx$V jYkwql[u\?'' `:V^ 4gfb qcx_욵 ]&XtR {R?s[{;xcϐJ{gtA8r?&Mƙs%d95LxFMcLmBH#e]zVW$Ҿk7hQԩ;Ty)0@!pzǷsM^)ѼĒ.o-ʅ=y^Es>=w6VOe#FrN9݀A?tVVRW2(A{om  @;x?xGpW*|?jy<X-XoDt%.We&E'T`H(>-q:yvi"K$|f gn%NNH!EczijsݶƨF`/]*ǚ+C&7[j|*F$ &I I ' 4[=-YTb6G׿L֥rKsER(((((((((((((((((( ȳgڵ#,6zC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ~ \kw!L |=IEo8̙}@}0qɬ@V(Q,i߉+ח;VhTeW-wyiN^+<=xozPԝV2ƒG|W-5]yP2z.y_ũ6yhɐǡ 9=zUSƛtU;v%F- G q8Zs[M /vw0i#H.$, $d58 ㍹Glt^g(ǖ;qnfZGE+Pg^ÎB5̘M0}+*~u&u (5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (=+,6z6? ^Š((((((((((((((((// ]J+|t J+|t!hJտԷҶJտԷҀ9?NxsFt-]w1u?B]BZ4O4@dY— $Zru_hs5ch ;Խ}O գ[Mc퉚ONN@ ydunPI9AUbU =3*K.n47$4 29 wst=FA#5ޥ.c1-h:'mJ#ڥ6s<;}Xb,FNґ9sN9uxגKŌ~dg'^2wjXZ@T6:3V=r4>D^KFI,oL <ITbR쭮hgXLpNH;HiA'+{kw;yᐴjT)Q=z޸*4e$93J۞Mʍy_1T|s5h#n^8D]x%AO8H02`NI 4 RTU (Š(((((((((((((((((J6? ^<-"͟Cjפ0((((((((((((((((cv+cv(WDRJ+DRJ)Z(ұo-ұo-Oß4AjSp? Wr uG7O*9DЅ11S1k+\tLg)E pdMkH98e28 <*$4|9%h.Ky=p{=D޳pu&59nm )Zk4{G*%xrpz'b[W3\y0 :xG+3Ǚ.vA3aPpyZZWOs*if6yHyݾӢ߲,P-]ds5_hZ[It-KVnU}v!Vp׾֯4i

fouq-ƙk I"lhړR6Re$Ty#QO˯=]>qgBϦ[q!Œ͜tȢ[8k ib yc"pXp=uCi[]G:Oej'f8R :VҢ[Cm;VذPz azTh+ە>Et^ ohn MEb[郴NjM|l+s6JK60Hi}9+;ox㳵"3Lg ז<][b64QdR3hߊ=5~P:9EohBޮe q>Woe=HG+*3Q,zQSо0 gwp]8Ǩb&g,q;Xӥ?/P{3s=ͰѴ<`xR6/'Z}ݤ7ATϥ)cUTo⨮_G,?§J?`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`-"͟Cjת|i F7aT`MXK*]̚QEB ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( |_l?Һj|_l?Ҁ54O+Ұ4O+Ҙ(=+VRJ=+VRJ9#K; _w)ސTs)1$2=pANZo-ne%axGz M\cNP}2@LCXL=?ҘװzO~)b?5?q5^lܕ)8HS@?ş¬#?"O*|IY r΅]>S u.<˗[k+ *aH>}h} Ve%yRgSw*le ~TWxbXmOe$v tK0q ǹk1xXi}=?]E!@Z n 99]A9j-Zdfm/7<}k;F[^ٲGoāGFxI\?6>Ovǭ4ڪ=WRMݝ>w=.HS7"h  gSVBW+n#YE`y9PG {krb1~S[Pϖm EK!еf7ky:Ju$FCezV,|m:J[lw8 O\-ܿ'/VSkP^I )9D(  ie, $)fNҸTz~QRչ#GIiiBnd 67>8,sn*mqu °!?qSxܿ [dt7^[-Fq8(Nvl`9IҤn亙RHZxy*2m99OQOSu?lYx^^?Sh>ĕIϪCqj"iP3(9(P = 6p:whRZ[UCu.TODgno'"_Y4ڻVCIT*I냌?%}O{47"r0%l 娥ks~GcNig2D0ӓz Ԛ]朶EchJ:b/\<j_GWiWfE*H.70 A סQw nc 1n‘ sQB+)~AOfӭ5;_:yic ֭Kc%B}pTno{#<3߇c:+(3߇ǑtWQGg!#<~CG^yEٟ?, xn =7WKy0b 8׿v7S7mF<@ƼnQ3rVtP mceݲ e%Q^Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\ϋWM\ϋP~:V~:SQEc[[c[@?iOܧz9#K;^N$ٷDO@]B%G7O"Ѧ7Jy7J'Z-̖zLHbDb3 ҶT5 %&Vcy4:XjWKAL vJ R89]QA +wEe'-t)t4* ݝu̷v̻_,Ut=y&fRt+tjx.b?t]8Z}^k[OuXYH{,Q*_Mlg]dg=8jWP+ż*A-=ֈK2 F0t? Tc6z-GRkdYdhxJ35̅e W!r@yV5K.{ВII=I^vm!6n=B#0@D8ǖc 8Ebu ~kInnǮ+Ѯ_0^x&[ f^PJs׃>Is4\qҽ# ^Z/Fvģߚ؎IRYf @Hռx@iqȩtf I mVҋQElsQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\ϋWM\ϋP~:V~:SQEc[[c[@?iOܧz9#K;o?!RTs} b-ctcPY:Vq1KgXZ {7NJya%B =IӁ*-Jksrx֞MB$GjAHnԗ[aE$ʣdn“EsC4 XHIݳn8*X#VA'9ǵt\-˨$qU1@.y]c\` gW1WyS.u ԵvCO#U@_x튘j\\ywi Pktb\4J\(Sg|sbRK)"A= 1'z.OJߘÏUxqӛX 932j$EGy"w5\F@]æsbSѝ~dU1\7DpN霵R:p8NU&bcsrpkVwMyd2Ur㎞mnm6LIJNfܟcNXc;m&fN}jާu4vLSL@%3 ~WI?+]$VWl@-Dnyo95b-R%@ֈ(3I>Z:K~?QM+EuZ.ӆxQB%$8 ^ZZ=ŴHXϯIڗ+qWIy/oնYyby{9@GZZc,z[,H\;?I}Ƿ=qWiK*;v0O?*Y5$]K)H;m$NH' O?gEu]Z] 0X}T6F'ŭ[zF'*ytQ}_+OWG2 ȳgڵ?u5zPzV>sFt-]wß4AjS!J ?ҟE1 7OmfϱO*n|?4Z(O!?*)c D`J`Ѫڍt۫M\FNr\̋-ĉ,N"9@z늍,Vk"̎ ;n=kvXcH`ܧ7rx?طP+[7vm~?qp躸mM: .5X7$[mk#lӱݽFpW}~b~CQ}AM[^72Od\CRYGNAg_z}Os իJh UFGp9ob~CQ}AS7{zw(9d@.&.Z"H9b_%U]A,ΰ۾X+9 [ߨ?o?y~)Q4~?sv5k 9F+w?*&;N'T 1ž"cRK#7Vٖ*y6E#T)=hjzuֲqm2KwzpN9"[ߨoۻbRƻSK˧yDK ULdwq'IgmKw5B aH{"[ߨ_S~?̿9d[w%u'dF-GYk^ \-H݉8WA}AG-??E?;[W#ۻ'[$:nW$%{)$U djž"ߟa_Ŧ mU𧊒A!e`EFHF+ž"a_+9+e`Uю'^? -MC#H7Y9KdI>8u?طPb~CSxY> F u;~SOӖE햔D$ %r:[ߨ?o?y~*~?9̿9q᫱?~;fq=6>5X;yx+0 Z迱o?y~(žsGG3q˙eDX$̘<sڮ*_mG?s[?طPb~CR}h25Xk&`h`8<9NV5oj"cT+["[ߨ 2E?5"[ߨ?ןaο~?P<Oy猟ɫطPb~CQu"2&yKgpдc *zTPIt9QEdQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>.@'VX'VLBEolor~? Wr/ZHcb ( zѬȹ׬ )|qC4eVbʾ#'ӭ\r@>r=kj؉nŠ( (((((((((((((((((((( N_~hVtjQVdQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEYtYjhW[`hW[1 EPzV>zV>sFt-]+/ZjCڍ(Lڙ*.]5s>.@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3iW5i_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s^.]-s^.(ODRJ+DRJ)Z(ұo-ұo-Oß4Aj/ZjC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ]-??WK\׋?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O5ib4O+Ұ4O+Ҙ(=+VRJ=+VRJtu-]CGe +O.OT[\5}.?k?]tTTV]}o.OG\5}.O*O*OSG7' rG.O]''?G'?Gթ_kw_r#˓?' rGʓ~_ʓ~_~/뵻eC\˓?HU[1Оڥ~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG{Hm⑑.2jpkέzU"Y?أ_*z+CY?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?خ2$ ߥt_ [?ԯҷJ?ԯҷJb(}[K}+`}[K}(?tֺB q3,؅''_ι?֎뫘&2ܼe{pt,N3Ku]bK'm7}Ew8T8r+NIRݞDҁ_nՃ{&}:PŲHK'wpXt1Z\mٌDJ&L1yu(vwfc͑8gЭH8Zv5WeMO1Y p;䖚[ͤyۉ;rv5[OϪ^Z\GH$GSҟ| ]\Ei;wIJ\uUZzv6trmet,5 k[I&XDhC#3T.{#SfH$g"ܵ֒ATBі jts"+*,v)v/Q[-. ^ټade-ěJM.t,4H,pB?>wt״hYD]WrGRT @\mD܂&O1llŐV-'ێi4Ro&]`G, q\=PykwÂN*O\ͧK{ r|ƕXYO8;/BfZjZU 2C8Кѷ8kM 98<5ګz5Ⱥ,hLpGPp2q}lմ9`6r9Lu9S<],HY slWf^Xiyh cr#q`q8imKXŝi9\ pgiC.ŧi(ɖ430+na񓎹֏@^eI,z^גjn(dgrǞ=^x(4=B;V0n?ΣTՎef=u$NpGA=;fn=\a-$Vl:VWZ_#GZt >;x2Jr# N>>:@/8b8<u$)trȂ7gcfizǁ}PcWmo`W'' }QnFu%юHrhϹ-|AGrܜ['('Bwa$pyhcomuȏs]fgԯZ,q*[4o뱯L'm.KKxI"x/ G:U4IJ\PF#ؚVMyMJe-P)wOe-x͉@2m&;iOe6q>rgBޜf}ZL@c hϹOmCzg\ǽ{JqުxHֵ ˈ3j]C '8=a}=ƻl7&Oך:N/"sIp"R㪯8I[xVHѮOU]HJ-[A -'{tFB%X1yw-3O`ϰ<DA =*][j7A"PMuϖq6z 1nWUE!-*䁌MKDhF6bmg{fٍ_z5!.xR9[ =zT^ pO2! 4 'IjBK 3`2FO9֧ki<;zV*OX tz~nH=ɫ]|KCoo;];O=ȭ8fHPrWz-ҵM9!hoM?yC) ]f2Z]GAdmfec,H}zsE]A>BͦcPvFw_xJn~wtPfB{V`]V-{.;)_`{WVzư-t"-!W3'WS^:^2up?4y0;A4]KHKhO2!4PN=U?F,<"Ғ[ӯJ4_C[+6 k4)2+Aݏj/&HCS,@ fsUA'U-Q1[%XUz8it4syQYXv*@ E[.Xg=\r#PNNAZԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]ݬ/./J+|t J+|t!hJ17ҵ[Њ))8OWmj6v򼶒 `W9qsecU?Rrzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_OYgWh8| {Ե?l_O+FȊ* B"ƊQFT`+ ~G ~E",haUF^C^ > ~@^+}?EyM _#϶x_Q^ :Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Ey> stream xڝZY~_LD9*,9r\S hj j5{B-^DfIh$Mad\jm-~cˇ" $R"Be"qIha%SYaO[PWULJi +燥J߾{pqa:c/E-}BGy\.qx[_!Sa¦&LRZ081񕟿=W Gdd~ft:83d0M?gb* ~z/|PCYbzb #D6fil4G yJXE N34o]LU͹mZ]i V?J0W>_#@ʌK(%#~m&eU1NEJ,L:if(_9̠c''ýۢK.Z|/_p#Nr](:NKe=me#'\TŮfwdPtlQu,4}џ[O6{ncoXў 4yqג`ppoLcQݤ"eQwcԩ*骠 n6N{]!}!$m:4Iʣ]NIc5I#V>.aΦ}$"()r!$1+d+ wBqBxUMFپCF6c*2Kʧ<+*M[˚G$PoU5]*EGFp쀪 |tr8Ly6?m:U@=v0*Х ;n[M˟:n~6XAڿX^lJiAP;N]=sO=cCzk~8{me,yߡ0[ӬT)y'MMf1csgIp_F#M :;LhSwlh ž;B qNS2ܴ8"F\zIm|zW(!_Z ˹K;w(Ao]zu@ y3?IO4LA5اHJz RB|: 6HZZjНںA1}"+{̲/F k,){K2`g&F)8=صC*Y?`д̾P[_x-Oo/\ +>+@~jZƋ@lQƪ"8Afߜ(x& 0}^r@ ]'nh"Wuj^(FY箞Z0 Yļ皜+- KE`~'0AjtU")zcMn6w"((xo4,W7"mc #Ν1D$WCp]XphqEvikbѺ"yad<;Fz=u x FUsR,#stn햑1b[81Wf*^0B?|Q2Эu5b,șrKI#^.T>?p^dʀ WM|W>²IO@ vSIo냲N$c 9c,7=%X *"6lpkF88!Jgu#ׯ9K?PRyWlf5n[YU#9Aosy[!c*!4=-9yham2Y%7sV2j29+퀃6a\\O9_EZP' X3(%l|Lr,6»x~٨S_dQgLqJ#UT ȹ:uQ7%X+/W$ VK$8L S@ ]o{$~q;.P̗X%gj{ Uvd<,SpX'2nLSOseJ\co?{3ff{p}!VI!<r UI/?]bP6mC)P?&y&EZrHR)3ErHzo)"縁ś #nr#ͦ4Lp)؟hvP9]P:kɫ;`hL ݥ1Z0:T3 BUן}T &; T)ЙtƎV!,4\y Qʰ;φuCF?8' ]X%W;l$Pk=ԂB>q/8ZŲk`*@p0,Q6Xhw$e1T1JF W>?pS.n|kDlKoArYQ Pf􊻞f#>7|^U3mR9@s24#uCXc$jeQ r ڇ@| Ōt.ԗ!&)c&2ȿ%ԒM}_ S\ҋ%Q@-ɲl\pc$N7>U D9S8Ӿ|\yYh;sh qLjꗵϑPP~D8 ʉJٰ{Mtyn; y1"KĴCOLgCSu UyH<#4+;]lVAbWs3d:J64KruNW> stream JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJ:?S@ Ã*}:k?{빇ďEFT دJw,k|cUvBI%P6!=woһX> OH@FҜc9M٠Σ?_ZV pe1IW7⏉Na_G  w;{׊KPk !i`odd䑁5mXɕ?:i Ey=#+ ֬\spGO|lo-ܥRq$nPh @pA3v}Ң{kKdy$P2895R=H}i,)c6"'s]==j&gK`|7>^\![kQ~c@2}ץjX0Kin]])'sӏΰz?;獯Uo*+Q?'z[Wx-W1Eto*N_k|\w_?;獯UsPO ޫjumD ss*r$}Kyx|7y.0ۑ )s?5M[^mر HG''?J=xdn AquN8<4P63M.@Æݒ5rp.NTϟQ(fIIEΎUH?x F0\F"XPIv9~ě)R,dbcm=rWc_]\[Bzg߭Is[p0D c,F@ޘ?gEvZ.6Cs=Ί;vGU f6vMq1O t<+=RJr^Z0(SԭR51pC=jψ% &!%6>u-qҖ KvsW<+ydQD,:VN4o.Y6 $BWP[Q]=1AtmoQ0N9b FWӤLsu&(,HXO_J}rWu}jg]@1:iH.fgXCk\ -8Yj u9+O-;UQz9県T]ZT_$N@\+ۓ/bu]jYYDo$w3?mq}RF?EfШ# N^/]RmJ{e\nBٶHY$AI,r0=XofYa(eT/$eIcqWRdy3o,1<Cq閗Oj"ۨp9=:TKQ]7ssclc`x Ьeg? T/+}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>yj [+ǵvo+jm>N[|ɝ.U{~:V~:WyQEc[[c[@koO v:c%;pV=4jG2y/", 眑T}ZbncR"'&6UmIdb$p? St9S\~qU1iPed?/R&Yʯ-+&}k[\ꖖg">٤P[' tahGPe>|_w3Xf8aJO riM[;^[Kl. ŰhX \g ,{co"qZ8q"،-R@֗÷o21v噗bNNrA95WZt{xam @ߦO5QMU u(Z} > rF;^6,#'qvw4l[devq<ʹFK%łR3&sG=? XjTH]o5p˙W!{YX薫bk \6ޭ-'q_f'ޘ(nA tUI-鶷Zh.c-$3Uvz )Jȏ9f4C}\f'#l=GZὤ9.Ir4fjE 0Tv'qڙc=NB^-O13 z[AjܷF^:ఉК>UTgRX 93-O>nmau B.:lkKX-?6vy 6!p1TgQถo/&$0I9stP m ϱmѬtncYLI`l & DHRLdU+` >f+w{_#4v]4j&iBȌ{A4H"ĀF@Rn3k KA~mKy }EN8\AWM HLaQw) 03ȮZ_Q=Mc^K e>$ cASj\\G(R |q=Z>Y7xu9oVثldojиWVTQ8U2RX:娦7_=\A}y-dQ*򋓞ʴ>e?p5QR迴?n?ƏpR͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_YMifH(QRt[qOo],(OV7) Dw:'VX'V]8QEc[[c[@koO]YZ#,u:>lʡ2lڿrYw~7y1ݎ6>\kV\dG~iЍp *[)G37;|mR1 ix$6KuຜAy$hǂB$A[6-S2<0%@Xh6CgtӘw%RwإnuY[<ѠS,Yk _:G ##W'{+2*{ZVvCj1v%Αq<0# _?ueyV9M6#a=;sY\9N|v=ɭIkcibWxdf2|8eC H"icbWnSVl*$J0K''D$xceN1nJ]WBKW\lqĖ _(}8ǧ^T]Ji%~5fXb0ΜOڸ\W\z5mn \G*Flc$9c~+$Y1n R?ӂ1OH4fze/?!*֐Y oZ? jrѲ3E9y8׽<_(Ә(((((((((((((((((((((((((((((((((+a? o_ocAJh|COXo_o_or EPzV>zV>oFt-]A 5AjE$Q"0i?h=t5?y6={A 1IFZ2(8ag5)}kO40dU٭Ыߞ##'ygEws?Chzve-* cO8\tjA)^)鑟u~كFGa@NO1oH9'g?~TT1ds66iA $PX| H zrǎH4BNO棭RnraEUQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQERa? o_os4>KާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ7#[O O?h=桔RX>wE%ͽ~,[Csnk~}k%`1D[ eI'.0Rfeܺլ}U +> F%a6h'ˑ@; {i817=rG҇++@T!1P*T` )`I ۋ5=F caƱ zm,X[+n ǎQE{g7 ??]Fuyw^a%`/ԍ)66_hw|ℑ1ۨWj]-앯s;??G/¶ΥMc#W/vewP3~w,F"&VvUdvTnBQd}'g(O~Wq*DrVv\wyuKK-BQ3_r6Ҳ*v!Hp Gr"`I >{>߳3'\K\䚑.gh +0ʕsbc?)WקZ#O~Q T:m܈ͥF m$ 3qYgDH Lsx|$qS}FK ??[Ry`ZE{q^#\UL}hJ5 \Uڪ׊@Qs`I >{>߳u:r<ùeb@7J$Z.MnX.nV</fۜ8j>;]%ߨ{`}}'g(O~V}ru2 #A,Nqץ[֯Q$HTR@ū{>߳}}'g+jPUlkؙnDd,#ݹ[ԽZ? ??]MHΘIs6ALҨc45A> ??]?SQ>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳R@ V1.euk\SP~o_o_oxQEc[[c[@koO uZޱ8Ǡ=F3Lv,<6`db#dFGj״UL| wʀ*Lzj&+ kXG# 2\7)#p.w]?p)mutKV{{9,A#`cnHBk%EC r7?ũ_Zr1&*ʭUrTdz <Ѝ`}9#Pj_'*[5ٮb HG* @TaWu Ps}%Oyy!=;Ocuy?U{<P\ko,Q%듟¥DE&x7tVmE)ߠsWycc{ʡc`\#T%rs|^iOCto..VϷp(F8OFU!>Fp0)SN6yyIU$F=}sT{Ӆmyv`qE??^ٝL<[o"Ȋ NVcMtBcEHNu s#O ut_gm>+4&dUm$`ҡF҆23AB)i+9zV}Fw{g !reE;#oe`Tmwccq۴@3?EQ:X 5mZq2"T%؎SިM j7(U]yl;? 9,r1jȢٿھC$tmb\Ÿ- *Fͤp;vo*KAz|£dgpzkSW}-KM7k}-(V*_*!qM4QH$d8‚x$rMsR> 6vip"w .ƒu$W/t"F7*)ެ3ʐx'=kle>LnK;;ًn$>Է:fSHvkq"(/{>Ki}yu-FGj??qTݿI??ۺoK:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq7~ h:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq7~ h:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq±S@ V=l'hQ^:#QR~:V~:WpEPzV>zV>oFt-]p? WQj6k\ Fw:HE{B5OSk"G)eoϽmZǹ}#@}&sFFME#L*2Oj/5xƜe&ňdRx,ykӭ,ͥ!`%RŲX'Mdx_Gx`쮫^Le'XGG&[wVmMu3sz_[iWְEkPA`*"|[J-phM{ gJ_÷>DžOӤoD0Iw.H,F88xc/dgr_!\X=Ƞ{mcPN1xnJ`229=y1⢡Qmmc[jiK5d4,1VSi,u}B|Ԃ`CI v;K 2O^9/o% ΪXb2I^sSk omla?J9}j/bq5*x_}jQWL&Gv0'u5Zm^BJA# py53b8i11 ڝCuȸ!d3C?.kXF+CiI|E~Y!f* '}־ioO |K<ohD0ODw'@pAsxj_NFgߴ0e=zȗo4Fsb#Oo I`nY/7r?׀4,@#u3H|xS*om)Y3.NwRtٶVI(@8#؜k?Ο ?2R#pzrr;㞇D?ƯW/]Gu|QEAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPZ+&$ Ps_o_oQEc[[c[@koO wtQi?h=t5?|[J-phX>'o(Ig#os==C2lV8#ڽGРb+Eu9G7lfm]Y*}9#G>]]sR 0kYbL 8r9] "a \|S~u3V~ Ar?Z4a?֭g)o&XKįp`ʞGz%柨q k^ll{e8z`c*emwTԿ_ Ro}Ʈxk{E3!HZ1'k Y-DN謉+Iڏ;/= =G}?/juԬnu'>KncL@q:ֺhemddr +qڔգcTbK Ro}Ə-K}}Χyumk[[@JGP@8]MaoZGFR;Zn Ro}Ə-K}4vUڌ^"̋ra6 ,8hzid)pXt\'֥ji|F1/hԿ_ʊFe~'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ5m'-69f =>^տFRNY$EJJ1: J+|t J+|tH(}[K}+`}[K}(mZ<7#[ -?GЍZǹ栖'xq}ga3>\qX0LgX>M.͏X%dMDсYե*2q؁217eYQc?UUq3I z֭ -'e;Vxє?Q$ڧ4k#o -n`M Fѐ<Ҫ]F s-ݰd1 |%\ҺњoMD[hcp@COI>_[aCҺ\7wqYu6|ci'dJco -'ݶLc)xz&UBI!s{n~SmrV\Gu\RJz,IZF3]9>wqZm5Mr3+6wmVfc5$-p,G4-d)CS{0m<+m"R])9ƒbp_\q3e8`0rzJ;+9ϗ m#`d >M>k=H$3$!+# A#1R\xqn`WHCAmΗV\Gu\RP4}<īHm/ ˆ A“#-zɨDŽm&˜=H>OoG,QF./ zn6ʭshD?, Y5m&܌%~U-^Ioi}gq<~8Wer)$x{GG5w#z۟|S-m"\Aslib]N>».y`[DX`::*m}Jwڳ:vn|=űcm8`*yt.3͸25?URH'EUw94[v5 719m#J00;DB?(xX `š0Ȳ-ճH<'144}*XIYnI =ۢ{w_1;ye>2 ݻ#Z;k5 ۘԓOֵbm";`?(W1v?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯S^yj<?#SX*lNi+6?Q®\@A$hKo0 O|< 4mR1v?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glgd 4R4Ѷۊ+4)ϙw_o_os EPzV>zV>oFt-]p? Ww@F-?GЍHj jsPKH`tE9?R]_gCC AfCjؖ+ ۳:1 #E$8=zV-Wx}r/o?|Ci?PGUE3Go>i?PGm?(?ʿȾqپ!7(]m?(mCW?>W?7?eپ!7+mCmg*"fxol7?evm}^__s8 fxol}~\gw }~?Qx3}|Cx}r/o?|Ci?PGUE3Go>i?PGm?(?ʿȾqپ!7(]m?(mCW?>W?7?eپ!7+mCmg*"fxol7?evm}^__s8 fxol}~\gw }~?Qx3}|Cխ*p.noZhr%良؝1bw4ulEﹿ7<VUmF\0~Hp}O=jm?+yN/ sKb/=[zz}~=b/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տGa-qlNK[m_KZ4R+FTvWάZ?ԯҷJ?ԯҷJ(}[K}+`}[K}(mZ<7#[ -?GЍZǹ栖' rZ7!tmFҒNP3Rn30β~k'Zf mB3qqEeU'MkK-Ԭwm:lNhV7f `S(e9dk)olM̛<1v(C'֌ZJg}o~5оF0pEZ'֒(݋ :񐸂&8qPݵb]Arh5ns/ΤxcLWm$sVvwW,PZJ|hzwcƧ0(Ѧw= 35%EvDSbހ.IpѶyY>)56UywhAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAy\A~gW_kؿ?Ґ'VX'VL(=+VRJ=+VRJ7#[O O?#EF$59%I}igl"֩ >Uw+9-{`q@Zmߺ@Z1^MP1z˵oڟ]Q-1aw7%-'q<^ۻsr%($tm^f}kmFI8,22u93. ֪r;][1B94fI|QdUD".[󃓊tgl}#g9`֖+k{5S+n'vсAǥY. g6OYw+9!Q &?om s]rٱ-vWYM 8KIO%8zl]ǟUأ?5)W4-q!nV6V.cx:LIm^qnJ J 8 2u93u_i- |nVaB$b[H?"8SĆkO*A뎘VV:eAn,/l;/54DiwVRh#5N nk}ErKV0+hXcEDPaNj hy4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@xŷ 3mC\ߋA ggP3WDRJ+DRJ)Z(ұo-ұo-O5AjmZ(s]B4Qi?hCPKSZ@D֛&')}igl"SnaҘEPu &Fumnj|m A?[OmqO)a97Om]m29x涂<1@Eύ_𥿾Mk+R@$?R*UQύ_TP_?|mٚߕ Tnu%լl EHCs@eNC,J*fX_AXylše Ҁ,EQP^\էM> s㚞 *.eb1NwWk}m{MD )\u@(wMnSq(< $՚(* l'}Z#y=Qu(,W(O?|mٚߕ +;IbBG g t3%HB2(?|mٚߕ U؉kq@ ύ_3OoV ٚߕ ?4+j_[iR]˶&ύ_3OoTIw,FiX^7:VPH o]\E3n[qrc':`ύ_3OoMUieN#Zg֝.۶U_?|mٚߕ u].[9d" dHenFFJbXKV8w1@fim~W(TZc y$Ӓ#Xy2x@MKVzq,aayύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ _Pg͏8)l% M~%ݲ˝#jP:wE;_ZtKsjFY#8Aiki. (U[3aս}i%+w66w}ea¨=Ijב:ePq r3-|idMmlg߹w8kRVGo|0xѝ6}o{Ίj Mӝ-?$W$dO@~~u;&Ԭwk<[Nv.Aێ+Ҩh@xGo\+y?z$]$|LVDn6>tSOk<[9bA03tq#Cs}9kmRMƝlk;e Jj)tX?a[xRLo/ aÀs1cNa:Iǟ83^T:9n, n`t}wc5lؿٟ{8Ǔߜ㞝i/.LO{OI.ֻ*z]G~_yi5}:K cHf0Ѳ̓Mo Gj'L$j?Zz)_~9ZvM5Q ~I,M8k,ptvsUۜ:WAa-jWv{s7ruqKuxX5̯ګ@lqB=Nm5! U3i6jn-<u\g=tPl2IJI ZOӡӖB|p8fJק_zZ0YKu * O[~,o jks\$B#i%Ny=뭢9.u+m5g֓2%@r0P1*ΟZ֑-VѶJA;M;^-t#.a.-Ia:VNg>[~hHe܇xl`5tP6Pz^I~q{oiMk w-~?S֝~>)o+E+`;lһ)o[ Ũc2Ukc߽kC~uOMo *JAֺj)ߨX(@QEQEQEQEQEQEQEQEQEQEQEQEQEQExǥWS\zYihW[`hW[-Q@XVXP'wuxoFt-]Zǹ(s]B4!%A- "OM?g\AX>3A6?@U ֐0|cr;!ǦA丆I%b+ɞRSW>TU~W>TU~W>TU'usdOSGs M rK E$dgh(_eˈXxOyldo*(* ,-ZDKu8z;%XcZHH(<##?K@Q@GkJaӲPm=wns@a7FJxO0ǞBǦjZ(9UF6*sGTQP^^Aaj7.R%  [sӣY9U"23PQEQYh\i5k6\`ޘs@QEQP\AhaS4(ANMOEE7!71S0>()KҺqgf8 RhUiu X_8R >E@]/$7uZ,gwL T6ޓ?g\K]hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@r1g-@Z'VX'V@ EPzV>zV>oFt-]p? Ww@E{B4!%RX>3A6?OQ44?gO5׋$i! CXg:ph]-_U edVrU|䓖 uK 9LKHͷ;޸힔洶w&iG!( u>ǹ\uVVΗv%[  9Sެܚmoi#Q,İ 08zt}2b[:qmdp*ɪQ%pFBO`>x4[[_!/gkjڒivtm5fVmAZG,AmX089HkZ cDFr}AP14M:{Hn@q)#KtȐS}DM[[$kpȮ @rjPծu z4FN#9M2G%\S}Y1kوǓ単җK RѼCl3FEov9\)^--"T m#Q!.Һt}2lB Ɛ*А IqX76VPĭA#40qwizmZA0i'l#ZxiW:坔BXݲPU[;{CD)_nq֗7^n  L1+iк[+M&ܰQph Ha@hM{+Iaapt` ޼z:Jclإۙ_yU5eW@bfEZVٛx/ Y \=U`db,Jd >[0@|gL̓q-"T fnmkPQ7i# 9ACۜm.e5wrsܙRldSWKޥݜq 9k oO&gQX@|0 6? yvW7|W'6?+e,m#XU-`U,`%}:}ϏH8I{߭ =__|A k)uI#G,m89Z.5s\6 }c`# $#9ً;QыhDsҨA XwϽC&L4}KB^8)t+nPMƣ,ֳ chr U_3l$_yŒu]iW]4G1bW(}FG4{ӧZߟ]UO o''ea;imByS#|=e[9Jv8!J }uޛgn.DaD4Ug眜TΒ*y7s,R#2(躝wI2B& tgɕNzc5mo \*m/OH,-`I,P9 o CwrgGx핹cn*ψ 4qďܤ6AaiM ,t`ÞϾimloKU gK?>]iYXxiP{/8|⠱}^=:/խMF?Mprك>ۍ:oM賷d`"_0MG@4:um2 KyX;,jڶA3 :t w4/nU䉎v $E 񧖌eWÁǰagi,}3MorRqZ>w.\筞"Pk*F#>ڕŔlFru?ꥵWh$c6} J*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[Gl45xxn9T1 -J+|t J+|t(=+VRJ=+VRJ9#S'_vԆ.O'Q@ h4P7SIE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :|^IKLkwܴx1@z'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW5ibZ]-??P~:V~:SQEc[[c[@GYn,}g"eC\ꗇ\]рHR+*ӥ~NIg7' rG.O]''?G'?Qj}f]}o.OG\5}.O*O*OSG7' rG.O]''?G'?Gթ_kw_r#˓?' rGʓ~_ʓ~_~/뵻eC\˓?II?|QI?|Qj}aܿOteC\*-OaRj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]t_nSW QeV۟_۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬W?xmDGYNFOoҺz_F-W[`hW[1 EPzV>zV>{FIֺ k]M!QVEllBwۓǯ\dkG\wYn^2=R:\'} w"l cgq$n"i@c/?jQVA>s{elb$J%,:vyI.o6uM%&f|x<:{ bY#dda?*]/Tk{Qū*I<9lä-"d$w7]GS|wW/Y˷˴aw63"Fn."4urK$%.:s‹^=F;m:9f6h2`^qsU WI]q$C,S"4e!sowa=OXd $ds~r3ߑI_sGnZIuɪYi!hdKM:wu9;I;F-{l0JM%`vT:}Ԗ$K^x^a|TߟŸ_} SuQI,΢U.m*@ Su6"ynA'Z4Ҳ*Ϸoss Kki網{o, {I>_ΠK[YNA[kѬXZG6y蠟¬GgaeoF#-geiZ1r.dF#s#960}mf^ ./H~F[DZtQ!t[}o&To\shJ{c{gm|$dDkʹt=8JZ:TrzcGkqx [=–-OZj]_q+}4ź{KՔa݆qT8[c0cVaB ' & *+lN;tyWO_6{wmb uGJ5?9c*qj?iIoovL#GP GYky ,BǴ\ޅz%0[\vҩ T=9;j_i0ߛ)/8Q\R9mg]W[K?f1l b&OykV:~b J/ ϸ~`c5=%^C,r3º~OzKo}K׾(Dlɟ$rFYH5nOiZGs,J#VHum*S@ԥ=$] ]x$qW5{KTӵ?۸̎KHDRlaѱۡ4tw]ZJu~ک,sSڐ\'h8ZM ;MX/h#E`GFխ=.Qd'[[޴RхB~qۊ<n[KpU+{Lk ;K$Q$RkVeӯ$k6-h2H82j}jUFe7^to# -E'cq%& 3X`0? ?#z2$g4-OWmoTtxfa%f"'c`1vVa2xI6rnH2rNw8_W] '6bq]sܯ@?#^^geGrJ#ז͸g H܊ӯ{: ƹ ]jچ<\(D.V`puV ϩtJʚMMfr$aZ cҀ{\)QEQEQEQEQEQEQEQEQEQEQEVw_kvW #@O+Ұ4O+Ҙ(=+'T\J֪WoB(Pb6dڻ9=_W!]K$2pq\ωV C=KOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=e] r06QRא?x_PQ^C^ > ~@Ey ~@Ey ~@6+Xc =Fޕ*"ƊQFT`+ ~G> stream JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH ENC[sy%b{d AG]HC".IJiԈ]b*2Tw>l4M.~ШGiRMc< 3,PRGpݷW:²F{%٥X 1q>(AmpO迾j#"r3]C8|ϔ8+oLAwi,WP11NN0G}h΋|'S H.ǚkKl]>?) d`dOm{X~Ȓ5 P,H<k? O&{%R+WMiM"AhD UbpǖH7~3[yuyPa;X+:=]l_o?bAqP62Җ WC[5'³Go&qv[p=j^^$vMG *|Hܿw7C5gx|> kOQɦT{ 5;DӒkj>U4ɵ6gGY %ԔQ.ヌG=}(X*[_qW0i1Yڴ/b-ŕ<}qXLԞ-ŔڇB#;{^x?ȣM`&־CϮw$[f9xWVzf%;DW36%JMzw1"]mf,AP9'4#9dn6`rF܂ Bih2$Sl[@a*G Cֽ:K!rj?n筗*T]O>.KO[T${ 7tZVsȺPDϑ0i9(~<]_mcQw=lU/QO>üm6 MCph85%xWB/*7/mn筗*mx-YIUhۂ8 4RmË-UH[o/iնX#p27g#үtڬUh&)BЅBxm?Z~]s]1"fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮ`LQ;[|zy'g~fۮU #Kx?ȣ6v0(࢈>ࢺL]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_?m5&Q[ 2):K O\"ФRFwKD[/٥8lv\ZS5[&N߿>)kS}VES8uj[ ˸X›Y" 2 tk[{(qq$oø.ܪcu5u\1xsoc2EwǦq-/.{+R)(ԤAA?6zs5|AXQq8su'ݳ8j>{<^!T8V9}3/Oǻ&bLF =I#S\hj}儲۪XOݨS LVDŽ`ay X"e  z8J5#,N n0f0)W8 u<`szv}=Y^S|9Jc Dzx1Vꦥ] (xX-~owCw㝉~wķZvZ٫jڵ'l*t$qg^/cJXwʓNФ0Ǹ۟[ˡnxbY6 TzNV5uZ8xKH:nid]fynqWjngb#{+S]c]zTXsޤh;ɝ c'q߽emg>W_]mjMyTe#R PCC7樱^V;(T|憎?6+/.!ϛLUh/Qˊ>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eLQxl ƄLm,2FEtF g t_OLi<-[ٖ'WBg0X@?Ivݝw6s8[UG-wI)̚,q\9> 7OMFc;F-fmO+CϤߚ->~k5wj8Fq"[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6KEoƏI5?ȣj8@w[+6&bop} s]n4ۜ"7!Gr^@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*tWOf#Mo!)_JY6~TsOၥw" “#?Bj4DžV(!]8J(?͛|.8<ٿ[ϼ?)>_]luև-QKo?mc-ɱ*dgo*%Qđ/ r1SJ+Y6~TsOVQጒG`㍤J_[ϼ_((%| >m>\EW(%| 7mћvUDW2Dp*ӊ![;tf~-7mdT/%FPF2rNx'((((QftnDE!OBI=*((-E| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>;{Տ[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_( ۟ʹ }Q4ۖHcV6PJ|1Gր;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?JiRS_C$}*ŝffBI' O\"Ф;_,h>F=tIJ\ZC5gxUMt˿QF #گO-3?Rjt:ZE4pe uꃣ9&\ޔm:QĻwv3bjZ\OWL"(_ka9f6fI 2x|:eGGXo\]k52Xcw?\Ro| [?j" ).UxV'Q 6}F:tRF;:QD.5u',F=E^Ag=jzֲXFc;s=I5֟YY4ʖQUH =;~Z_ mZmRNRwfP-DpJ $#&?Iګiz<WfM=wU! 7G$iJgbYВ}IYUƌp\,cDoSѾLdL. g[̱In9wj1ߟa9{VSxWoJXo}]n 1[ZZY٧Ya,3xR}nm w_krd>tʊ?JlF)-nDQ)-=,]Nڤ,VKIXFB3H0Ҵmqqrm˴lbb q)mj[K@"Ea@&O>2 uv #NNkBx\$jO#~XzѵKˋ;QHݙBdI rA2k7[&+7R"ң"zZmf6w2{(9Y14UO4o~.p]6gm.Rm?0\3Reoί>)_m?s\̳OzLv5ZVaswҳ!lCx^fB?k:կmc6+{:*Ivsºlj/q#Wb0a]ƌyl.ZWaq&gs a s8>nVR#0O#CKg{‹o Aj \am<WϮXT[oûi8' އM|_愖dxH 8kȞ9Ƞ\6ziG"/^Hxԛ!uuχb[(眴VrZ:pꠜ珻֣B}2N{im RG"198> _/%j ^,3_G,+Q"Ʃ?#<ۚWPkdMOr7ʷ%Lkc8(ן/&7U_0@ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0_ɿq]MOɿr@pQDpQL]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%]2ͧu?Uj6跩RLњu\њu\\coRAΥ7qBzy#:cC*P~`QN2Q`FԑЂMOE0)}>E&/[P^ϵF/[P^ϵF/[PkX$Gi`ay 8Ԝ՚((((((( C03 FG;A$q}>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^2خA˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB+ O\"Фrqqg]z{75/[1KdPᩱS'K Υ7pB)xifg2|F'#*I \en fޙ#kj_wk~sz <5L^>}_& 9:v4ow;R7{Ey/Y#GMy'5Nۿ_ܯ\˧j}دOxM+$68z.DJc ; D26pAVÓNsjzڮ'6"X=p5]yp\\ɩk2OsuN9ǽW5y4cC!0){mPx$WG|F%I sږM=kQ] *8c;HsBcw+j0m:HmbTRH cަ<ڍ͔Zf-Ū3K? mSW7 :7{Q 0I]˸|?x}+J %WR;mD{A! _JZ-RmwmLz}*⫛c%Ɩ v yvgiMk^kմ;gϓnw]s?o#N->׻:1>J@3=um^%gb@ ۜXsY߹{DZ,Ѹv>p8 ^hj^e,dܤHlaSO^76724 kn9=.uRKS@fLD/>ET~o%!u tl\ J9 M>s$04b}ӴTLa)GƠfXS:mNk^x{TZI5xΤ2AW #;F 7q0ZI<,6]K (2x'r^mԡH^9.Znb|mh[,Y:Vy wsEUӼukj6,v8Y.Ax*=Olqqm|ou6Fߕ6cvs ~&mՊA= ;|4Ã4u5[Hñ H5i_kJ$[X| ʱR1zMRX]5u8"XMAek3SiwϨ\=S  9ph 2x[i%>Z;N9$cۭ,1ILtli%x sU9=Bv3䷎:eM젒#xP9cs]ߵ̧tێ1~-vo/'83 d`xQmZenVk[NJcb`M!_SYZGg5'5:Ee3,bqc붎ח2j0G&/ՠڪ7q}[~(Ӽ5wwi'>k^JᎃXQzGV%%v_՝pQDpQ[.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pBR8O)8R3cP%?s(?|uѾ_B/\qto|.8Т3ĒpkHebЮ՚_wV_)}qOT5~s`OҪZ*iRTޥ64 hp֧Bs)* oMRx_pU@MnP'JN^( F8>lxU=v;{n-l%|NAoݵdՅ;6 `ozMK×o4SŸmx5,0 3myיv?Y}+F`C2 mRAF0j4]]=K)I]̬vЬrIb7I%:vD-4Q4d[*xUc^K"kb]dg,p:G_밺]Mbn&k[KU]Pkg 0H#ߵAVIM=ik ƀe* xMSӡRv&$+jCN e_˚[oEnt=F.Brb# qGTrxG{/XyKmMI6ŕ+4TW,; Tv}.Υ;6yn2V7/'zhd!1d:PW {;Z|Yh.&Xvc_(I`c$ իr=FX1n>mxYvA$eƥ%y)toKPO*Ee#)aGόq܊IfQ' n6a5=sF"+-Ac];H m)pOJxdw%sOˬEa0MJ]8SK)1]B5Z(Ð 'i5Яn-XKks(A~K{m,o>ӧ LdBVkh EsEA$rs)_5.3`Qu&n`1$Vψchο$Fx8|zI8ⳛͤէ]U73lu=jQTHkq EjA$26{sGEt0w".O$Z^ެujvǜd`Si&ԮmnLFky'F2W*+} Xu/"ZhEp1yTv:ݯ#6ĠQFG|S?~_E.q^iZH{J&teӭ#>l RT|1Xm-!pMHV{_3%n-N}3dfT-͘>峌cз(6mnwXǒ=HD(6mnwXǒ=H3޲"muyd.3 D9 |6CIɫM)Ӵ{i.M. w>RȤ_>5KMʎQKi6J࣯k't dXlZG;UDOnoRE{WO7W``v 25lREeg9;sE}; P FՒ0 '@k>“K\gk-lBiʜt8W [aH &qf4r-F[Ckuiq,]Y 0#Zvd潅*VԜ?5ZM255fxą$Z|5 *zA?U֬n5iK1==?_.3ysY)Sd~{š2E,zc֞l?m{'y?Ieg?aRW{c@,s{ݝ4lΩq1A{ExMWןM_(j+(j+OkM&171d0!V9+ӡZrIsH yu=ffB0`&iߎt-]{ŪCQʗ)#q zѷҧH8Q}Q:g4iG|\5l̡FEU2x__e]BLl c!?]=?J>r-a  8!YԾӅ߮y1I5;s[N;2$T #gP:unzZ\eE!.A#$/ҸKŚ`+D+|GOQ[c)l8駐r@ꭵfVU<40kWxcN"P(er9P0W8g^Q7adЩӔ-so{RK8Fc}v#8AcXXjWZi8r}&54;Ni`ligܼ;7VHlt _PSDi21z O#$18e s\xڅz JYo;co>>\twƒf^srgO#mwöՍ F7|r#y-׊ 6BJ8$བ{E*ʍx4 ]Fsj[8OZWj:ȳל?)4nPY{Ǿ@V:Wy ԍEspiQEdQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Z'sEoxgX:'sEoxg\7莼WO?;>࢈>ࢺA_y/ν Y=|]ue _GYŨKS(Wu J}"~\X5]?jUniUVH8t,4+eXv 󳜑qs=ydaqh`;+0kW[yye3F>`O$OOnUD:ޕk y~Bh ?c^qoy;7.h[C &4vPȻZpC;2=OnZ:|nUl 9׿5ZV3X\ oU9ۃ?Zmjl6@;A.?ȣECf' Utgqesm{BaK{}+O]>U7Q-VԳZuEJNb}T?>܁nAz2\,l<ǔMb'p >h䃑pq㑚mK UK6ᷨ{0dzSգ(C7VZV6$ ~\p'MM5މarCm%A⼛>$:ު݈U 1O^t@{8sKvyXTQEvEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!\m[@9[Vs~:_ ? 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@q=Վ 35 m&[ y*-@Go K)(I sjcy*B0r' yNؠ>s(3`S6e;4KRѴkA Nv!L۾ ywBWi9FzZ񥪲 W/nl"o63XPv}r>`1=]X\Gjm{_yZ?,O(lL{>Ay8߉2DHȍ+#R6Akԣ̫![He[9v'?Z򯉿 %V7XT(*J׸ ZcOk;Lk8NHF[ Iփ%͢ODTO"6mCWxW/kRi0U88;O99W1kf{NAme܉ v>LIAm4x1P:gYto7 F Ťo\HkAԎZ<練*yޥIEGr3cy}k׊X4gmp<2:^vzDnfV]@A9c{۹nd2O+w=ɬ/u/Rȳל?~:Wy 4(((((((((((((((((((((((((((((((LKں ZO /rEt6 buמ>bЮ՚_wV_)}qOT5~\X4֭?Ji0'tZO"O/rXV>R\4K8G"b)rncO^ I֏"O3Km Ys ]yc!n795oNngR2vV!{$ъJpDkׇu]g`3qGiMaQKm?6y=X#6̨$ :YOF'E'W]ϗ7?<U?*7-~be?lk "`ɭ$k%4ʱ `{p2NOO%?s渼&Ix千#aA7;AWq V dSD7 s2Mw[o Ǔs%YGq*lstJгԦ/-Ma*λvࢶ[9)cf?)o`[ [c$уǖ g85oxSTR@vڣ9?Tuy8nb$?w=?{ ms@|M@^[iӮb7\ \7ەKÃݓpxO'=w>tĐ&1}09x<쿓OVj_^(-WoL\cWKR;B%q1(Wvr^+]?bkY]zc W0SvXn&[?8r3wGևk?QS]/Γyybm!1-70'aO#~5|44j0ȸz=ivwk/d{G/(fI6c,ѓxY/#+VV$0*^` QOQ]KbIV6r6 |zfu&;Bw;cޟק+]l3*4q2*F|`:Ӣ`@m#FI.t@zҗk~?خ!EuxEgx/%Id@X׫. =6SZ&{xVcTK7=S?WsCwy#8Q`ikMs,Pۼm*7tߓw9J+6rwxbZtTdzuH ,k[5G "JH(w9:+:B ~tgm9i# |Rj}O?Q+,2Q#ޡӵi ;=9SKUɷ{beY0F3 f Ԋ_\H]2p(>QvpS;vhPrNs^u,b9yxFG^_]]jk,LT"<0.0y5^u"*4##=2>j<ܺzkMtVgQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ딿-5O5ۆkT#AA@˯f_t_^uמ>b}qOT"~\X5]?jUniUVH H]Jg̯I]29mW`DT Gs]RU)MgcsQE?_#׎j^y^ #R07, lxW8=s4K^Ih\gF{ ALzn}exGU G<72tg[{<bY GU.=NO[D*T,3CAҽ (-| kom|/tcA+:.m @lS>ڛl% Ιr$ vohYT P oh`Eww/n75r@&^2PX r%'r(-| psxVA<$mq"DIʞH=}I|5;ܾǑ,9fLc ʹ=;We,I v(ʣKU/~D^8Y<-kN|3o^ǿEi'1L-V'U'sqE/{A?d4RF4HbA|{wUatQźQe3)>G/eh,g>FXgU}S[nXyPy~RW瞵rT6p!FK gѦ "\s/E!ơkl^H{)Bp=j͉nVR$*ؒ29v"?GE!Ɵu7y 9ttvH.wqWu GpnxX! ϧZ-s5ibhdb#+X?7mj\2Ҽ'fl3#ך҂Sk c;3fr;AQISVr*wYRKyIx)nR<8Q\SO_ E q*ZnXehK, 9+_y~='5xW ٖF1.m5iB,^KN9]]Vr*2&bЮ՚_wV_)}qOT5~\X4֭?JiRS_C$}*ŝffBI' O\"Ф;_,h>F=tIG)ŧu?U©\'_4跧H ;UFz3 QR2FGQچ3\|=֑ζRH&<6pcu=;F;+.4%G\lA|CAė7׷Rl־dΙHۨ]sR\h61ۣ8ZhXrIDWY J fk[Ѱ_- <45; ݜuܭT cgom=ݬR;sy%vyȤ*y,&?ޑQROs}~Z]gjRX3M\`SREūuOR?;Z@fxUHE1 8%P`qԊ9?:\ZJx] iӧNo罏?rNo罏?r'֌Zxs=s=>dz[ϕ<c~Oc~OD'֏|{{z&O>}^?};{ߓ({ߓ+2}h>+y'79G'79^FOW??!?_9??9?LZ2}how 'Q 'WdѓG}o>WNo罏?rNo罏?r'֌Z>[~~Cxs=s=>dz[ϕ<c~Oǟc~OD9#4}^?} KI3gvV_Ck}{ǻ([Њ)I0$LE>δtY!/q1ҨR2@kRO3z?UhdѓLF~u/T:߃VO>K?ΥUFOgRO3z?Uhdѓ@ԽS*^~Z>d~u/T:߃VO>K?ΥUFOdݛ߱y|){ u?unyMS((]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%axS!#/MoI sAgژk$@2\v=?~5[gZO*ñ^0Xa9`n&X#3?Q_4fUUkF.'F.'W/(4n{F~cgۃVL ]X O*^X O*Fio=ȒycE{IWiXm0}L(cKHI> ( ( (*e9E%̒Ȩ1>((2Pih 0:-Ā cz\LUX+/s2T}/s2Ub8S$pf^d榢 ( ( ( ( ( ( ( ( ( ( ( ( f(((((((( ڏn*5ks\W%ᮧ@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*R/ JG$"EY1;~=r0:yN.m?f<:DO3­D ^[7l\fkkL7vE~T3T{-JimHh7$sftB+QQKY qiIezc%1 X{+(nڌc ANI$[]ֆ%>{K{6ȄÒϽQ+ŧ32H납擑Ԝgi[j68ǖlԿzoؾiL<ٟ] 9q{$ֺzt[k.dl#H|Sn jZծc-lGV3Fܼ"{UkXq#(1ޭ۵𳘔63M?/s4KlR T珘Ό_[-ʉncʃ[7O$tVrBEX(bUO| 4Mt߼@zY,Vmxilgw/Nk-v?-궫ǪOiqYK*0sHHhnL{+01"29rp`;Uo^]0yP@u +yPIrhDlowlmApR6i#HsZ=۹7bc~_z[1|COjzat >Φ4bB1;G#$ ֹԵxtőԮRƫg,~`:_jlW7ʠ;Ā1t&ⱋSиx."YbC9|\``x^:,[dr!w֭]k:j";#Mϰ9 4gs|n% Zy q fyyn.T%vY A;]yמTXlww<Cj,iy',X 08s[7 |{VQC0>;zdLVC#`9N~_V"Եm Iu;\p7(R;xvtχvҩaol2|p*Nm[h|<.< *y ME]$+Kj#1)e9qZW1ukk?9t$HEp ẁ;T5JC4A U!$Gu I A5<)[y5-FH*] 8Ii׶Mu3\brb[VY՞SdV~F.7n!H /rAYk,QƂM6;;ČqKw{keEƱ,R e2/|;ms4Assc,0 1t`}*z]/&VtP}-]^'l嶕\0Nfo淕W;^[wmVC#`l5rk0Ed&f}s+裰_e(_#=E3FvI_Lu5noHT٦(ҹ#cI[7֑\YYc6`ߚϿW˧{wnl4%9;vR3nW9uX4QI%> nX$1rGZ~Iy| @Wh N:;wpKdmnFͤp?]44?8.<6wcU]QE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@&Uxox:u&Uxox: e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRV׍lB,KEU>\d ]BҢ28Y"mXqЃnfݲU@y-цQRs8@h_>/l,3H _K/ ?Eh_ _K/ ?Eh_UmKx.ap7`\0(}_Y(DݲVh 2In'IdhBEc$v'wː{w PQ)(4H;T[p;((((((( TR2&=0(M}{}t4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@w}ʤ0'r?λ-PĪ77}OuQP.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pB_qxiqAd|#<6 VKZpH=|ޞsH ǭǭUhhHҪ#36FI[yAd3$^ͧ_+FPEFTϛx-|-(2?g*;kgI" #yP7][hImrC%Ɓhv! ӠO[=[X=TSsrln9ϭNyz%Τnan -QAR6Zm&۶y` *uoŤEogA`]7<+]~v+ioEa-?l!#2 +-w?-閺MYndipqGb{f~]'W:FaZAqwf@(7n$;k3 )90HrCPEoM-qĒn}1SlHWogg[dr8]E-^KtinaGxBpJ w7/!P`o1jm-oaI'2E4(f&SoObZ#d}V?ek'pN~f-c1m&iCmg`un'm$m %3`,ƈ?V׶$tѺNI).7ojK&ӭAKxMc9a*MWXxnm^5HRtr|`w-im?qw!CLjv8/$/<1HU`\g oyD~~;h<ݎqq/"lP9fOsRS{ (Q@Q@C)ͧu?TZ cKѠ+6I퐪z5;Db[iX7o%Ǘ$e<Ҵ5m.VH,R$m ;*~9 7ZÉXEv.(ui,'Xue'xF!1j CWծdim-xi"WV%wg3ۭmc+l7ח-or.RIYw(Ңܗ2cyF4nwZk?QN\O+@7ϴ_Ě>2Q֢KXa[IFPYĀl98s[6\vz7 qn^VSw=8I%󤶍wH*H|B][ZooWyy֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@#7G}OO|\dʹ tAe^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWqjRU`Eqtmñ?Ƚoo.Q@{?]g_o.@{?]g_o.@{?]g_o.@{?]/{?]\*k/\LbmPOS9=ժ(((((kȑ껎O: ( ( ( =(ۑc$~5-OȽoo.k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(2i&D ){?ʹ uj? M?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UWVVq "/ J5.${(Q1q{VEIFé a3HgK@/@r:S[T>3qu~qeMG ` `}jZ6ZP\2(c)W^>ki`2OKzNc~kI)1xW4-/!cx;SyakYb"Id\˂y(6}s RhAiĀFxگObu {y*#wi@#T4 ^j2 y\AS6mُ#O4u]Wڍ͵9X].hWl`r9C*Fc~#G= ѭ٢mKXw`6I,Ay MfMGѧn$ynF''"UGg&ךPZ*hwꭵs vLg%խ [,s=ZSxRk\vMf&GrF3Mu;2I&k:V~ɶ.Y)13$sٶMm, YjF>S9ԚZ=/2K5ݥm$=ݙO&L(roÜ[ھk~d 9ǶEhܫ^ڠ$`?Zep]]c2 nsޕN]ԫ+fK' `рP۳3 KA-6UMfHCՔLֿ]?kgArL#;, Ro]ZK{&mZ8ZH. ]D7y洮3gw%Ԧ{;$nE"(PWA=M5Eַ hԪ $~fvDOeH'k0&Bۛ%~?ޡ='P03@ /ӠH o~QB:+ziyumwQZG{舸hYw:vAokutӫmx*zVxmFٚ+%Px]t"&yVR_](^`aXxYi7X8Uã˻q8#+湨6H0A+D3B>cömm} a噰x?Iqc﯄r1N%bڹm#:^_CɶUޓPG*~`6y;PmmuyhN%ȅ.2ƴcNkGw7&\U ?,sNËqT>l݇A 0WGjk-/rk,kN'oZONQKI."{dVT``I=qyj',K_ĥ `}ixjϻn]c9W=:jJVcm 7KSq #!B6xaJv+ioEa-?l!#2 +GO<`h"`玿(umkqyq[|\pQ@7bcnsaVڬ嵣F$Qk1,[ЍmV#-+HF2H}@}xFʴ uIgarx!83W~Ӣͦ\_]̳)G !@JOga9_OV=X>A8cjT~]ɜ37K!W]QaKb22#^wTH d7?H<}۳v33jku=S7h@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVs\W'ῼ?κGA?ɿr~ ( (_y/ν Y=|]ue _ /EO@ pE=AsTi,M31ῼ?΀;>࢈>ࢀuמ>bЮ՚_wV_)}qOTQEQEV?t:̺?N ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( () M?] ʸ}x:` e^{//BVk|E1EtY*mګǍqOTԆ;yy@}}PH2uuAt?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*)^@cp$Dzwa'xs7Q ʹ}x:` buמ>bЮ՚_v֟m\SA5Ci6?SRQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@ I m!GCcC2]i,jse<&:aQ\jW-2]iSVoOK?>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? z>)A>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? zrٖ8u%;?>~fWڼU@_t}_ Z$Hn}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗ϰ^Ʒ6[ta[;OV?ޛ(7!UkƥNwt,>m>[PzoGءƬ̳QUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCb]@6ruԭ!` +0[ß}?΀;>࢈>࢘]5":+f_t_@ i$MS]K{%x<dFb;OPjv׷U̾zI)zw kX}G& #|y= aF:voNQ%GKX,VSCtrFI}RFΆRuI[dIK}y O}rks=Kjcg'kO]aiiZʱȲ8RDLmbnl[\}l^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U{ VT+A)L69}*}-[ʐ[Y sV&ށYGqcݸW]%Iʮ |I_[ti防+{Zu$+v. w az>n]>f`8Y3PM}:K<#N2qsՊHf>77} ;P/X̞, 6DKѣ"<4=jz yp:4 b:HkX1ǩdn5efg}(ȱʋ.N2 o@IOVEM.|ҙLWix>QOkY[b.-mt2vi_}?/;4Fb)U$ H"|+v e Է@k"k]S+[(m&ܓJŗBnnOnE. {fk1jSZ[]:B9.B\ 9'y(vn^blԔ+lzu=tFhK p6 8zvxzx5;'7NC I8^@:m}o˯w3n%-.{S]}.wi۬2#vKi$"鞙VʰYhc9Ƕiy{8l- FMb@1F9#GOa~Gow}[ACrjy"O Z-ICzUlXͩڃ>lkYݸ۵0*pw蕟sf.)ݑL+qגh<-OuG1ڹv/5|X eIhΠgKqYKTwWmȚWt|zDЗmqukq7gSst>^M \.wOQ-4tFDwc k+m=_lfK4[]éX-+GHn >RZt6'5nKJYS}J'Cp PN$ -lFK]h! )Wk6mvWRdb{FZ; hW}lc'֎GW2xuXĉcN hW]l=hQzU9olI;PgӠ mq <vK\ovz%"QPuD:(h`FNch6Yxb徲0'3oSNB/;+P=.VG[B&1\ ep'+:X|6ۗ|D&Lf@qlg_@u& ~б ㍤~ӭ~%>Dr4\nU=qҏ',KO5-C^EA.?~ѿ;v_~?vS .wW\s[}_3g=:qA^-`k80 s@E7ma5¥ d:Ƣ,t|pYTֿ[+(%_5~;\t1sduִ}&݈MbDWD[]7: ;/⻶rLъ=y4TE 0- K(QEQEQEQEQEQEQEQEsa\>w0}E}E1 VkDh?z(kldU~Roʼŷ@," ?HgoʍW}?G'ڗl[ktUj_Q @?z~?y'ڗl}?@*6O^a @?j_PoʕU_JO/G(R €=*=p*|EhHK X=oJ6@{G,mc€=*_X𱵏 lDp#r޼6@{G,mc€;k-;K{5cGu;HTp9^m$ٛہy,mcXw6ZdjK<_kF6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ˭*MkQV"ڼv?q𱵏 ?ckDL0d 6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€;{*MkQV"ڼv?_&fQ$W?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckU.s,"ڜa_a X=o6@{@jX=M-y,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )h endstream endobj 61 0 obj << /Length 4362 /Filter /FlateDecode >> stream xڭZ[㶱~_7sNh 2ol8>u*#B#z(QKRO~xP;I&K |ި#as$g n6N,O77y@dwwltoSn\๹6>V$fItʣ~q'hFo\\Da3iXLS}Rkޙ4T<]wf!8KoH6&MoqZg~l~z7Ms!6֩85]lcr0++4+غ 1|ByVxئ04DJ/w?hhCi=#^OvMX%n56ֹ,n3KI|]S.w=L띲^;kqCYCG|abRw xY֩P6}%iJEـB}ڇ_nA Ǧ=MшC8^˽WLiFw:.GU6/T>ۓž\XǺ=]NC燵 Rʟj86[~m]~< kK0Tj^aF.M"9ca]D}ZH lYh80Epفs38@JW~x;)jfLKP36 ˄eEaU? ꤧeG\cRɖ㣨} :]vvI1QҠ%"VBUySUʸe` = >c0WxSs-V/1,Nӑ:4lZ) XˑAߗ;܁Os;0\m<;JcM;lZ QNUAv(=ږ GO= }U5?=oG5[t MGl#M|ന@6<)?1zG")P8guhș tKWn$^0c ͱ 4n!09g̬عD٭ /mѱbiWt%&Kd 36Xb44pY|T\f@ u3S^r~h..&.VA^/_[xr_\bMXRa S 9QˡCGnXiF\k7R`9J֙H)3/ 9KWsʺgr&P?YKTߚ,rݲZm\V>P#Ο}yNƯO(&.. :dwH^w!0= Y TN|YI1AR:pm( r)gO͙k 4>ez!M=ۘjKB Xz7s9ٗ F b&Gq8l QXN>Yˉ(cBbe=Z6fdd@=N~zɾiȈ1;^cKئabD\yXS>{rɰJ/K*(o ]2ԡ8T1XIa 41M,S~+^eSvM / iR NYy%--@D!Q`;0=0M%5KTߊ`nGȁÅ ~S%T(%ٵGyOZ63tjΈ};|8s\9@χD4 NZ)~ZU~(!<>gnjo$s0_vT:[ ~Drd͒D氚Θ) V}c~W:4!Jйi/}z}{vP C !Ebt{CïߐXh9c-Tù Z5P/fygŲ[4RIlM{yho SZ,OX5y` kB1`.Y#,_X$vvD6u^SD6q@NS\\VSfͪpsM'M~ <% &zR hڲ敳F_7Hv<GE`^4 1p#x=RIǃHJkS0Me@ &>\C.n>| N\s7z5= ̉(CxRMtG,w‰$R -$ -C~]!M׎;^``SGzR ;,DPZ)?eoa4l X3 Eܣ(9Q  P7Ng`!@ܧTǔڵә۳@ zׇ$˞^ޙoqwsw:y*G:2jv%ӄ?\8}ͨh9AP 3 .{D$Vh{J*FE2R0(?3@ݒuGgdSc`łȏ ɾ.q+P= xҙS,L:X= jN9"G1iNTRB:f8~ xEaXht,E32}^>`1JrJuSź,ṘJ`]@-^zy!7\E>zƩ󣉵xHڕFr3+ėz5qSǛ)%]a"ΏR:ngM/'ǖ(:UE15%慪Z-3.㍦< K+׺8)&v> stream JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVk)i9'GYe]G9Ep  Sq^_, %8?URAu=5C*"r;pG" 0'K@.I$Iޓu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Sh xbXzM/}EEH&`0 *S_ʢ,-܈IBPXFiKIQJ3jvǤ?zCDpQDpQL]5<]rk՚.?4]թlp d~E}Q ř!ti G+_!OƠ>2*iױç^M Fdmdcºw?5?]xw+i`O[ox,gx ,zV]x_ᯋ@OӞ\˥E71f0zF~ɣ s?*S0Q+#&ac?]q+Kꏢjiq.3\%|e q5±?f.V>0GLQ۹A46;r uǑc^j̀D(L?隋?0t±?f.XKGsFChYYB:0>`@mLiY{+K,B9]qTX3G+#&a70Z/9mMmZ0[Y,]o+#&ac?]LJP>-Ys[wcީ±?f.V>0GL..SD:Ћ_˛F3}zi=.'IMEu418ݟwcTc?]|a@_}։ W{aטY0qPf ,LVGP,E9UI|a@?0t~!\񮩨Ky>$ q1_ڪ±?f.A%Eu|a@?0t䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@J?0u^HЏ@ ( )˯fǟ Oz}^a㱝6zX4\$BaR<~ xّOb/5I5 7V^j+<5#+lY鏥 :gXe]hO?>]j֑̋^E7X(l6ӆJ]KK{hu Pn!ʸ%[a94a$Qk/R\xWRI=qZuEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE2iImƥݱ2MVn#3 6 $@ 7][PmCOW ǒrYѩ';#۵Wtv0:+bHßWW0*tMWnӒyyC+}=kzCB2RJK@ ( *e^gQq?J˯ftRPEwuEo2[eG_PWGb@u=EdMJ~\G ֽ" E--{ }ryobizD_,pv @hQ@4:69vNH)b?UTr,0aB@ hw<by[) 7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"3}"K!`4kv/ ѴKrqln%q'%Q9kIhxWq+3Pȋ3RRr_bu"Xϡ5[ :r߁*(QmԓXL/b7myAj΁p^jilV7zc9 \c{zD "Eih%?:/?*kHLPED#Gc3==N? t}K) :k0[gikK^0IDT0^+NW$q;VΡqcX>r$18#L쓖PCEr6rT6ܣ!s֫$XL~h6ש@y_Q\⋆ӯuY-`id'h ;d*56I{T i:PgEfj7:|w:ڳL" x39>V6$QE!Q@Q@Q@Q@Q@Q@Q@`<͞ls  ۟ʸ  5&Ux_AA˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pBƤڃj7p +GԷ/ J/4hgxdHS1i!ŧu?Uj3)oR9H ::͍ىUkU1!cw\v,쯥)(Ւ wNx5 ^W'F\\;mʨ F8=SZZ5Adi±Ò~R#q>CŖ\*Z^-b[E+ 988AkWsl90I($=Ms:ܲiז2n&ya>@ݐ+Z7j0"e  z8%_K[.ŨOlַV0Cr1Vm$VI'zt3ɥVR8 þr7>V'fぜ3C1Lj>&!?![w}.zmQR,›JDdg<Y,4on?7Ry?h3nW}NHcaӞ:go2U?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_Zuj61Ǝ&p;;zu6N8fD3밁CGJ TBvbz{.m >]C6Sqr.c*͐ON28xvXf(|)#qZUdlbo̰gv7P  =v^{)-$F>Q;_@'#+j>[+ x.-m>[ϼ?7]~qtyυZdxG-P0 ?.S,&pHQgg,z{U[ϼ?DWDp*L (YMgcsQE?_#׍YF2HY 6(Z)~m>ϴ?(%| JqI^C;r*oϴ?( ŷFoU\zg#N*Z7mћvj(ŷH"IKQ @ 9Χ ( ( ( ( *%EA= $o[ϼ?(%| J)~m>[ϼ_(%| J)~m>[ϼ_(%| J(ةQEQEQEQEQEAyw wP~ 7rK=;O"[B$:;Vǽu,5O ZZ 2m~5xgNcC:]ۆ_CWM(^ ]O[6z?hF7lFAA+NEjf+GfPX MFm"ZZ¬ZL.B2r2>´`{H DcnUaK eS. V1"/WZM[n?ei%6Gx?ȣRQJ9r?}?1G֢i[# ( +C!_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%5="IGҬYؖfkt$RqN/ JùUt#\Qo'+qk]՝9V)4}G.F%70G?\j!?h_0 Ii-jfiӭl e8#4-ת[ĚmszRŴ}GoGpmXqnj6zqS9Ԛ]>_%u4:w}9u 2!pc$Q#ou #CsŤlPqjM[iw+f6IxHrҧ>"Ԅ7Q\Nl%J8=T,(k%+:7/6-˛fkKKpa6*.KX^:\!!w.ьؚ״>ɩ7n͸ٵv9sÞIm38cssн?kVӘ%`A=ooxe1`*&O}h: /-RdҮg3kē>xR{c{C"6ʟΒS6œ^wRɊhSuuw%:DwЛyeYH.EPrh"iGw#M~c>dZc)c@WSF;mDÇc1|Qh"e˦4Ze+{8$idrz[W)<>? mwl$w[xZXMKYJ%@`Fv|sK'闖koٿ:g=kYs2nm>VVT`}:?3ڬk8naY J̇ E={՚@E O(אk#V8ĩ'qqϫ U\%Ə^U^ãv;3潰i]Ě71v9,U]XYHy< .J#c}> -)4)s!dA_,_>c)SÒyn%g㌜67z6[_ɒ" ڮ,ͯ"xC"Xpa4T+Uy ioRn2`|qמ)>lr[hês>Z= ˍ:SY0)KaKdP+o#d G,6[;csxFw}P[8DnTnk \nkBiMy6PU=r*߳61{c8K^U|Gikuh X,e,<(S(ϨQOϨ>T4}.\sN:K$ ?3ZYygPak⨼Akyf@X31@8QG}Ec$E.r,6[|p'$V~yYK\^77R6 '5ygRoγm\R0Kmm6""烐852k~Q$wrH)PBOn?:67N!z]紽GÚLglT2qg}C} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu ?tfyg&jĩO }Xgd3Mnά9ڹ }*__oC ( *̆]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%]2ͧu?Uj6跩RLњu\њu\\coRAΥ7qBzy#:cC*P~`QN2Q`FԑЂMOE0)}>E&/[P^ϵF/[P^ϵF/[PkX$Gi`ay 8Ԝ՚((((((( C03 FG;A$q}>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^)|U~[p?X-UYngnHFE'p\'>ԟ>-t\O0}O-ٗT4NpK=M,ʦ@dȮrNմ}rBm巚/;gAPLlf6_ \hmũhV;$rq9C^#k[d@. Xw^mR/VmX 9K̒MR:Ym6'*ݕص-(Wjw7ho9L t]38k[yesY-}F+s'5sup%y{'խxPד2U_ }(o?_xVwp}E}Et.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pBşv?-woHǚ@;}.4fo}C3@sM\#О ,':/ J }MuPjx'Gt7c{q .zdiڂyWٮmc9T$2xM7wWیq~ןKm?tn8{m>o n:wQY ^ |W[$Ą*#`WÒ+j6|LiKc8|=(A]:TxdkxZuf!caZK7iu&hⷈ^dYqӦ ;xol@[x sPm4;K'c-#HW֦[漽df1c6N0y;knJrs.i_b]>I7  #hZ)D6&Q)qEZOM;ͩj+cO9j/.?ꐉ^ly,E i .ן%gDQXErRY| rq8&ݤZۥȵf7j&ݝ]J9wV:$6i/$E9|i֋mY,Yo%vW0 8=/Do3x+]Y\ib |gK1$.1;WV8Y꠱ iӁ t+[ki dm䁜%׾muqss&%>׆#@8_XT[0 ]Bdc_ AGsa>[7'$j[ 6m]Ew,Xp#? oܭx!փϖ+QI (b>f8<zj76Qiz̷t,^- rGM_ C,70$?gYDX%w. y(4Y]JK5e[O֚'~Hu+hI 7Aݵ299:n͌X8&[p @e15{Vӯc>M߽vj;H^;w3x)|K{kյxch0RU癋m'nricmg~Y7 kxFhc1xRQKMy#`r!}M>}{PҔ+$V^ݬ8Ki,mN_]1P;)C5ѳp1(6vzψtWщNQ2G_ۧݛ߶ycOc=;MyR{cg}i$HMk:å_P4KԎhP7b1DD|}i$jIw/oXl Tcלj \]yR#x i(QsMngoZˊ[ ]b0N)ϩWNծۈnhdW 8=5Zϴۼ~Vۑƫ5΂-MV)L(pr^'@n rm#) eu+(oa/S*lH=y5K=btֵ[hIa4jNmO>rʫdeLn(X@k{| ⛩nKIxb2\j,nl8䑏nx }'3[nѳkyTTrs!.9T K Xc97K sU@tvo~c2n8zwC߇nJK-\Lh1;'}]FݵiUYo(mh 0MoS\blu4}N/1g+EhI> d 6),@d-:^_FzdKVj9nkOMo!QC/P qY>Im5Kho<1nCݜ{S-;TBSDbE d!sT%iBB}Iy$mgbIsW  ?.x[EOթ_5Z'N<ӏ+iۻȷυFw4VVݦQ!.sP]j t{33\F~=z֦o ?.q}GՋ-JSa{owUk6ź=ܗI}mm5E$SΊ!lgz,q}GѾ|.?n J#ӃW}kJۉ5;$7 4QЯ?7@ ?.q}GԺitIR2ebS_ǥ%ƷZ]KNC%«IG|.?7υSjurgkpq#C2O,uM?SWk [C0L>]?m.u+9;uf\u"Voe-'0L@ ?.q}GՋ-NSG{ kC V@YZG,/,. [xH']?մ/]B;wD\gִ[ųlI\{?}\Qu IR`yaiR NO#OgZX,n/?rweuPwυF5=f ?6)-e^8He0bMWN,eK2ɢr q}GѾ|.?M=/VV̢B=9t|.?7υZTPnq>]iQ@?}\QuEf ?.q}G֕|.?7υZTP >(̅?cMCᎃW|G#my?xc= #((e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`WG<@'*F~j$\.8Eg|.87>?]hQ@ ?.υZPxQ._]Mil'2 3OjEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEOV5{To_׼ )|qE? ȹiڙZo-?UtNQb"S!sҞJ[ɯV<Ic#,$N=Q'{}yݥuiF &4:Z}Pr,ޟ)~Wwj>ҞMz)Y[GVBԍ͍84UicP"kngJcdsؓݠl'$t)}=C< cYm#ɪ#y .1uSѨJz5%H:ܚ)}=&Jz5iOF ~ҞGSѨj*Qj)}=9/o^O^>o_Ir3N9vJសs~:_ ? 9]5":+f_t_@՗",k\SA=5?j\X4֭?J@Eo!)_M<±/b}+g$`/ J[fԆ!h\>FUs0:[T> ckҩӵ;k$jQ6<2@z]㲼[F-r@#6Ӑx泛÷maq5a|㍂EltޓRM^K0 #r>@lch[^_C]_bѬ,̃x'psnʑAHXdw"OZ1c&s'H,H6=##SXh+xdpB)oUo<;wqc@'8 y_jzsy'[/N7V+^ѣ1" ڟ0+V_h6<3kI,lUѦPTYf[MjӮڄ: zIo~Wq?ѹ v_4^sDgoo\ 'TIfQ' BK-DQd}Ĝ }~wk 'Mx?1(m㑑_|K\iWm76tAzEϛT<;LE=rKH{R>^跗ivӹpAL&"x1sf-yl>-A',h[1䬄i9R@{',h[1䬄i9Rq]^Y?yn}‘--7\QZ\F'rBH 0HG֝k1ayq y%U`u', VLMfMF٭g1!ly}ֲ j:O$ZuKf!)po'9xVsux& {k馈N#@Jz1,@sYwZZ3ʁt[s4]SNӚYEvp̊vte` x"K9{Ⱦ 6Xʝ`p:J_~x ȹiکX}>p"".vs9\? o.!ӥkv]Ts Y>_+=e44ŵml GCK+UW)Ga?sך.kwod {q,ܞzUw[Cqp$rAovm!+:m3՜KM><[LHG $!Ts*κں)qM+ ONf5 {{Ԓș^D,kC4a 7Sިu 3ۛXzĂ~pHr(T] ]NUy ,rMWnTe6Kn& vNϮ)eMGP6k%ԩm83<==F9d-Iާ^=/tt&='T5י)O1A:`zu:baxpJ6=X6\!H%lcP^yҨ:.ޛq[ `eeٗƁQGjo{ ltqxG,/3bR"}9POj}eiز+\G&>΅5/ٮ[gGYB îN@X׮lKA $co43T[mbky-K ~jxLkL[ZȊH"r7(PkM֭O HkhzY^OV/""Xҧ # Pyzg/yӛjxNF]Jy$"| Am^ӵ[-Zo1Q8*QXW8֕;i&+*hEΝ1+yv 9B;%n:sM_}m.5VmyM7ܲ2Jw#f] sauxҭe;@ `xitymm }:hnaK{#τ)0 O[5Z+2=j $C*6H@Ջɍf ( Jd ֻS (Š(_YJ=?YJ=?硼DuYAr Vk|E1EuW_y/΀;/EOPY>*Սƭ6rF8'go.tk2*vsœoaSX&HRSq͔>`#'P5?ݸi?'P5?޸?@s5#"h`q~r-.#tf9 20O~Tuݨ =ڊ %}mE|E}E|_ iZ$xF7fT19|9%rzt+\ow{ipd_> 0ۀ'V%D7N,&؃j+ȳל?xfj+hffj+hffj+hffj+hffj+hffj+hffj+hfzOגҏ>3Y/> ȹiڶ~Xr[ W?)~PqsQCp^HWeo?l ZC0b'9 {gZmλ53b`JBfs#c_J>TtzRѭ.]E IpG^ՏgX.uD ͑1c}ҏVt'bԮ,Y͂|cT+ =Eo+.H] ?R}ҳMm6ćdCe SS񕞗wy 77Ƭ==\V( eob_J>V( eobu3'?W=??mK=?硼DuYAr Vk|E1EuW_y/΀;!:Ef];mYc}iyjѳ8ӭwEb;(;cG\w?5>"+& }w*ے3c ~y?k?T\_-mu[Y#ܥ؏{1]z?OpFi/ٮِ+Ivw4 Wk^jjrlH*v|޴m:4%+@}rG".a`cn% sypG3(QUG =_~,P"[.H7y= Wm-OO҃ϩ\xXB'-=nmk)/qGoRMmqӹ3{ ?#h$imHYrq[޵`3DdF@ːH=#Rf{! "zsCV[#N-:i+:mgYx89+>&/ӵ \NT ה|M_))&*t \/p]H*>nN:dqX7vg`$@ M{;NӭtkX-##BfnY7/UR5[+-L#gޠH-f {2Yq''^$am$Җ{ĴX}>3]F:\ܼ?]crQğ1t}܅$'Ku~M6R  pk/egJ`9Q1\ijڳV 9S־n9ڼt=oi<,_+|A <ۮmc1q+ռ="Ε^p*u#QsE%iTQEY!EPEPEPEPEPEPEPEPEPEPEPEPEPJ>R>3Y/> ȹiڠM3j?#0,#Pr;z.Z6oP/j͜DžgѢh-;ۼW}q6FSj~[p5hw3|=q3]_hK-j0*EΞ,KGIePNw:nVs-EL[{ JیZ>E_ÏiE&]Fjڊ}3kb@ F-yhh9]_hK-]ixyrhvR 11H#)Zj/,r$cwq>ZPZlbj^.-+I"$N9cx.H%[O5wLG8kK-iEקyj'nouasoqo%֞wP[ c5^MP'Vu1$1<|gʤutiE/_+_c#%%\}b+iH;+.o ksiFK/^I#0%B۞1߅uiE/u7^UJi s$O Ԏ&Uە@|x;wp+ˍ㸉c-)Wqٍt_iE/m-Z~Gm ͻ)mgM/^{m5\" ͸HlWmU>G_h`rS/}-U>G_hS/}-U>G_hS/}9o^O~ՍvC''d= #((e^{//BVk|E1EtY>)qj-H~Cҟe _7kV W_Zh'U[Z~U>/ ? <m,|$`mAs^}jmE.м2<ݏ{zO]MgwZyNc< s׌ׇk$DvqB!9$m$w'#T5Ueʠߺt=qE/nVZle1r <pFs/'^Ӭf-ZD c39 O,9sNcl3(ff)VX `HLu(禮.YTqnɎ5k9tX1dn\r&/^A}~LхlO'۰!FjĠCi<1;_,Oףyj[N~v8MyK*I ou.2.ֆ<(#dž#SꖯΨ[9AsVլi?pNv֮Z,y?ˏ(QP٭n\|?2Y\^.$olßjOMRXW ^ٝ@Zaȓr Wq 籪 a= -e).J)Jwu돭qT~Kcա*u,"֝;{;$S_U=Ϸ l#Fېd;zW?1X%O> st88fARU{Ra m'h.z>P ՖͨI"lA3$vISh wX\PG# Px&ωbC82 vLiK㏪=7.Z6ж}(fq7^:qo-?Vw[SFwhIDGDPN:Q>E⿍S_,/ݦϤN` GT2^eLj.6noq1p1uiNY~h&s9kO$$Q&xR{`O5-ϗߜ_c/Xnt4GF$#{-{X[;k;B.`4͞ U[%fsLv:ō}:Y&{W ~}31O_^_G\d;w :OPW{$Rm4i Ix>́ +5]|-P;1)̐/yTg8 u}%lP.BJm[5N#CӘd:4NC2 ST]֟stqk5ĿieʻyQ^xxhID#mݴ!qU{ }=u~׳V5LysC`Kۙ,ot\Hm9T %ŋZϴ`u+Vxe  1 ~C4?%mjS_j hѰc6^xahOE麌wX9'<*5O]_]s^. cAnO'RKۉ9`ےRBg98Jռ0v}8*d# מHۭ>vkIw-kx')Eo*Ul"%w3d8|M?έR ( ( ( ( (9}gF?* ZYJ?ֹo?_xVwP}E}Et.՚_z^{//A?S_)s`u5"~UէU[ 8GsI6-`Aq`H|}|b᣷V[p 9z90s.#ص6KOCVo{x'[6_&=cyxP\[,|̳G8H{Pfg"[ٷ3q+m.gO1|uu=ܷW2't[l Ǘ {YҿW׿x{E+lrTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEzo?Zm[DM`OEOLIn)wq 7|B[ nl#h#kNVGGh&纣w prZe&q⛻;[aqڅw |/vlP#h#kH6XZ*zjՃU?co֬UVVUn|pQ\''ZE+]\].DRR%Xܑ\unTo^汧̯s$G'Z,⹆żO@j73\Km)XW;+o~g%~_^^8_"OúZWu#״y ֍jq<ҬXЛyT@, "+~?خ?*@|M@_D1y250PAU֒5veX0=8''K\^T$&gG_ѭid[GAz.uG{hZ%ڸ0HikKx 6Jc:g `t=@K?WsؼCg"sӤ ,k՗a{MA=+l̪ %uzZ+Q]Jk! w45Ԗ(m[Guvr`q:zob9;<1y-:K*FYpI:y_@c5 Ws%Wh y$c}zbz!?d3g6]c洉܃dry[5A>]n_IyǖZ bh(đP4SrU WƩ㥪1EuA,wqR#`3mpE/I&\ m_3~7c߻s__~?خ#Etz~C[5KMSS`$O2ܠ!qӏ? k9Gwe_υ2xl7qYԀ9Ԟc}:<~tZÖv\Z70SNlVf%I4p,X_%222;dSb*=KbCGo΀/T<~ty$C´cE|RywEal7SRbO8?o΀9o^O~։oI' %Ck׊i~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@PFUE,|=e|-~J7l NX8cm%?pBOk85ʎz)sTϚiVo`KaCCq石YJ!\c'z՘t}R7o"'pP WQ(I #qMKo"M뙧Z^bNB[no8Ṕ+:%ܤI3Fy?ZwvO|7o!Rdm!zrn_exGmSX+}Gk{ YItlDHReOj]Va)tG @kk{DR d([{GP d(x+~[t9.'I2-*džV(d[,V68 dp vexGmT-c·  $[k2 BNTFyRKUڻ)bH%ġFU'8*Z{'i{iėi$w,#?:g`/rK17 Wآ֊_Q72@J>Tp "8;wwZTw[KFC @IuK U4;{nnO,1U8Aqˋ2]HK;У;Gj(o Zx継Tf%6`s¬7\;Ab8#ֻ)}G߂my%Ϳ٢7Crޠú.Ϋ -.r[,Hz=A{+Ac<2>«\w+3g1!֔:XKٟk4[TOV’[ΒKnaKrŒ*/Nzzn(m|Vr+BXygg9] A| <1$srhWݞ̲7wco-3HMdgfXpAJ,2U++%+{ĐIF$mȭ #9[MԵ=7i,mg[bgP(9qQk~Rw0.u`iڎ$wmT>`OVok"E,/j82ƒ>nߗZDځˉF)}N_oKmn5 i7zmSzr펵]>i6W_cJK,5vcPUW/lkPG Gj |)>Ɨtl}C)~dfsy7W9][CskH+FF1[>+4/3L#*oޯ8P+Z= L;UXmeġÌ$z5fQ!,:FGr)_9YIn!{o/liiP[3c8qT[SӴdSk7h9}۷##z[@ӝ. F5y`0cz#5 m_8Wd[ߠt2ukSJj7iQĻ"I~U9P^kGWVɧYLK}t}76$?.}i[HFA4R`F WMNBH;I :G Q@Vw|'t˿s媳,>Vm#o-+r2%Xp #-IA;,']Km:T(2`OTzAkk[=L*hw>q+ѵ}P\^hmgDTdH5GX0 ËqjT:/_׭6-OX,c1[v):橽[_ Kk[93k`K}>}DPE!F1Je.JkY)sZ謼1iqZ:Ia3nTUbJqZmei8[k_{G`:4XofVur߈.^豕8Ѓ ? _Iy%wr5//{Z,`ge2$ZҷixVXI&[ h'>?AӴˆO9g,+p (@wUolZȑKڬN"Lࠓ׾qT|G> ] vW #邐vq]s:w 4; 1)n]:K.mVA.8d19$sGo{&҉.VY̛SEB뎂{RKVY,nivw`p;3eHٮ$2# p햟iY  s$I>9M'^V(&MW1ccs^l5xFX3D* w95e#NHFXuڥ*K麥%lWϐ#r7 m;s5k6;RGq,*r]b|5ΓneE̎yG@XnsGaw2FwHرepvɑL5.#D aG⟯OO+guQV ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB$#V,K35O8[J%a hcFF.17s2O 0:9N.-?J=zE=@Y=h=j7֑JVHJ2:1zޫeofuD4i{C1\AqI,>R:b rrE$kf&tFBP?AIKEÔu IP_bƬ *iivDmu9tw7WےM"mI!=@*:=7 :ŖYHs)-K[ScE0*㓁MuJZ%tk]7-?=TOmjZvPOg9Xa\ 90{WO;f[?[~a>i%QEgY7G)*M 5ⷷ3 m-R22PQ1N>Z՞k[,vY&<=;{{[n-[fP O#i/j:RZM]%ҳ;T#9Wzd#05!!e,7vkOwki-,n&u ۔҉7ir$#+n\%dw~bgdZ·_PXM3\:lf9]FIXmYj[;{iewxy۟;,;E$ _WNgy5B{`[OJ}>;;PZŤmNY$jSz/wF-[zEA?3ZF.!XY*>W% 'W=ZU'+v:WN6>gs=s=>dW??&[ϕ<c~Oc~OD'֏|_Ihrlnɍp1 OZҺ0 Dž'.sIY>'MC4Q#rSںJ-dpM$fW) MlTJH۸drFך5]`QֺADxH]rgZ5 Ţ;ˈOfl`w9=)UO[h6%o.-> VF,p͓qXvw-sإ,,>F sBե\5;{mJMus@ RX[6qڹx$V*W88@=Z`6f)tOSxr9u+ ڄSu wo<7 H:_= ]@o >#3LG SƶMwu 2hS0n2z֟&yuL{+ LM#Sxucu+M*^D.v$Ok6) NI$KCua2nW ,zex[Av%+$;It*4N,nQhe3I"''GZ_^uy$-T L'XnYc_9L9>橩$Պ"iWW Ar2?SpQ^mejlڸ4{o^ 28{q=Η^j3O\ܸʯ"`OJoMmt3:Ѣ׮-W84&YuFlJr|!tt/8) zStco!q JרsS'#3H#1=5թkY|J.~@: ig@- Q3psi-m?oK Wv"KϬZiih;Fg-=F*=Ƥeo# Еޕh {MxNSK͸]*3 ]+_#IT5jm'RU? u?硼Dvb_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%Y0DgYheU*o3EIXw^!Hc>[B\pqzwEu-!nWOǩVrrs=dc)׺NX8@qw=c)?1w=c)?F.'F.'Z4IQIUJ =۳s:џռ#??|њ@f[r$`b1${Umo;Ͷxn0$3DH)>&Am $`*Y࿶v"{\gSA4Epȧ`sN0Y( ?(QϧV oizzt;RH`Eg=#FZvqqbm-/Afl1,Vyh$-;E+1Xy #SYXdF+ [[X`\ |^Q-Ǚ1n1WoiּMݯ֒k 6'I-%K HKhk6a%?xP0? +ߗx=1TYiZF#aach0)a@'CC6_m%];KKyW2Iĥ]V U/4kvNN-Y0 `9Q@lt is*zjՃU?co֬UVVUnBS)*R/ JG$"EY1;~=r0:yN.m?f<:DO3­D ^[7l\fkkL7vE~T3T{-JimHh7$sftB+QQKY qiIezc%1 X{+(nڌc ANI$[]ֆ%>{K{6ȄÒϽQ+ŧ32H납擑Ԝgi[j68ǖlԿzoؾiL<ٟ] 9q{$ֺzt[k.dl#H|Sn jZծc-lGV3Fܼ"{UkXq#(1ޭ۵𳘔63M?/s4KlR T珘Ό_[-ʉncʃ[7O$tVrBEX(bUO| 4Mt߼@zY,Vmxilgw/Nk-v?-궫ǪOiqYK*0sHHhnL{+01"29rp`;Uo^]0yP@u +yPIrhDlowlmApR6i#HsZ=۹7bc~_z[1|COjzat >Φ4bB1;G#$ ֹԵxtőԮRƫg,~`:_jlW7ʠ;Ā1t&ⱋSиx."YbC9|\``x^:,[dr!w֭]k:j";#Mϰ9 4gs|n% Zy q fyyn.T%vY A;]yמTXlww<Cj,iy',X 08s[7 |{VQC0>;zdLVC#`9N~_V"Եm Iu;\p7(R;xvtχvҩaol2|p*Nm[h|<.< *y ME]$+Kj#1)e9qZW1ukk?9t$HEp ẁ;T5JC4A U!$Gu I A5<)[y5-FH*] 8Ii׶Mu3\brb[VY՞SdV~F.7n!H /rAYk,QƂM6;;ČqKw{keEƱ,R e2/|;ms4Assc,0 1t`}*z]/&VtP}-]^'l嶕\0Nfo淕W;^[wmVC#`l5rk0Ed&f}s+裰_e(_#=E3FvI_Lu5noHT٦(ҹ#cI[7֑\YYc6`ߚϿW˧{wnl4%9;vR3nW9uX4QI%> nX$1rGZ~Iy| @Wh N:;wpKdmnFͤp?]44?8.<6wcU]QE!Q@Q@Q@r)YR/V]/+K圭o:2{څaў}}lj>o gۏ>x={u[FS%;o"O"O:{+m'7-C98@I@sR^?.c]>WɒхGʖv r9Q$($(Z4ŷce{Zl# >c#cjԑnhnw,2zc~DEDE @-(1]v~DEDEjHk`ۼ#|[>"'gbaIQIQ_m&+iź@B$ OJkte]-',V"sWwyw_JP$h_P3e~\)HT_bmGO(%b0`eu Cg#8W$($*ܕ_N)ۅѬ໊hc{C#QiKw$ |$ɮȓȓ}8 06yf~lbGn$xs{yڽȓȓ3CfY{q*]-o Q^̷ BRLX3^IU;u3ykMYssۚu@{qGI "In2c2v0g5xP~chGOfT|аux'j/"O"O/l,}oY+k4fP$4!"TMb1p;;e =g(OO`SXDPO-QEQEQEQEQEQEQEPNOJ*)@i`FVR}{}>o=\:Q(Us4f){}>o=\ jb[xW3Fhڭ_أV/Uњ(Us4f++d`zr)Y5X>a>ds<}ɩo-B/5G͗4VVݦQ!.sP]j t{33\F~=zy\UΏu&u4_,ǃ dvxխsM|Xy+NM].mv]^V/  2 4=?륁kju#$t9$x+3UEfk<2X lIu{ 0y[v {?$Rf*i݂F|z_ Ti6Vvl[C 6q۴- G<߅qu]ʶ:3@0#85d]F-[GN, ٦Y+1as ;- yfPerzUSiK`/Χf,3Oqcy{i[%M:[ƲI2 qұCe=zȟZ{yf!#Am铎ON5]9 _ڵ7e1qT4]~-kR!x&x98rn<8+>$D+`u3]*kz hZjHo50P(9慭ޗu+ 5QmU3ʨ j;kJ5ANXzk>u `G2؈ln%t8u k[c{yݎԺ__?3t>$$VLdU;=JH6 C9#WiCL{ۘ[IKT j=1ed+;bMg2Tk/$V+QE!Q@Q@Q@Q@Q@gm'RU? ?W࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%]VEI\֯8@4>cnCbwQLSO%S$OeioOg9֍֪4o4kxiU $ [ 2QCiz fӯ㕣k"|*Sg͌xzU]Bxn[F Zܳaw͵<-~t9!c@4_;qvF-KIR֋ l 67dm֍'V<R707  ( P{6m^Iogk 0[{_{G`:l" Vry.z_ZSFyi]xYhբٖ]& ,r48 C1fQ3{SHBjݝ#E Y3 sHIkb Y5kKp$9d_zh"NO&̸{iIP7PwH>)$Auiw-2H9Oܜd.yӢz}YCy40#a8%@`p}Y ;q(_07cH`g5zö$"y3 )g1_-L{2 >+5 tpYwn'ezcZ]FOZ¶40rq:ömm} a噰x?D~P{[t_:Kh|~䂤K[d?xi %ۼ&۱&̫<76\):9`\oöcshd˸[!T5|;W[Gv]P0]~\߮3څ X<"??gy^v88IQqoy6(]`u')QH((jrqqg]zƱ]Iiߛ$BvUT=zT"v1-WR\,Qp2`Zo$Bf)a} 6~M?Bċ,s"BTAW:H tjm,q#cn2[Y4ڼp+R+FXyֶK˖)$ sQ]xvKL1< #p7E ;5~E~ɨ']J[j.'rB/Mf_KkQ%wf0#(m@6 z].;kk/+)ܻdr~ zvZۤ[F;$$gn?7Z7ZѼFUw7zѼz],=s3\یDYju.v3VPR$G$'V;Ѹxj>Ҟ\%!MNF~F(z)|m؜_\Ukۨǝ?Ə0:?Qju?W2 Dx7\ʰi'YmŔңGMqp\g9)}=VK-D\#ӵRź#%,NB}|@/SѨJz5s%gӼ=5Z0 hmr [SVofbT}tn0ē_@SѨJz5rm,"i  ׂIWqfOiqKM,lcҖ N`(3PCj>ҞU+_&+0%pgw>٠)}=5:-.xr}n/>mrKUn[k#vFp.0rOhJz5iOF+M{N!YJ,FJGBGP\xNɎ,\#[;X$2W}=W8b}qOT"~\X5]?jUniUVH%?pB+ O\"Ф=(ۑc$~5{?]\)}~->{?]])}~->{?]])}~->{?]])}~-_"~-EU_=fd(Dڠr{uTQ@Q@Q@Q@Q@ב#۽wJuQEQEQEz(Qѷ#HjZ({?]'P/ůGP/ůGP/ůGP/ůGP/ůGP"WX:R$:ˇrF:"66մ=yk*+'bݞH~G(EA%sȈ5 .qiS~s_tSNXRE*HGs޻Q_Jct[:6aUm =OLUҮ&\Ix9*$6Ⴇt_Q_Jm 4IgK% h@#k8KrO_ƥ-k*Sh|ucJ9<yq_J>KưԞQmLR?46DP1c#285-V\a% zҠHI۝ČqץңM8c{}=IR}h[-u<Z6]_E^$Gc4Ia8ns oZ:6xZG(ZxJ/ҕMEl\E"cϡȋ—[$*lm'LPiXucuD/eom} KbŴ 8as*@O<f룭Ra{il$ZP0=q^_J>TJ8XaHaQBNp>ҏRЭEY/eo UQ_JEY/eo UQ_JEY/eo UQ_J㵟 7d7Սz?/p ;%W?\7莼WO+gsQWA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U_Z~Y4BS)+?@O,ԡGnRNAQZ0N%-".a,MnPLjuE }5*/E;w w {]rI'WxfGi^8u5ׇ,?<'oh]8{s[kl>4GP:֗W(RtYU*xU.F570G?\jݬmo.em(@PY|w>T~\ܐ}Me剃>._O24F]n'[[c/x`mOjl" 9.x'Qdlt[qr;&Mf̦.0?\Sm8Yfږ54)dVNRikoʃW,vvf9<0msohzj#y,E[wgr){[cjo'(i::|vQuv"WU6ɻ;zU;kwJR–3I,,1f ;w>²_WmP֗lFĴ4+UB60g޵ +H5}EbEeI$8tť کbfE1.{v9f[U XY-V 3}0WYہ},O2c!B5ݡ@3̿UmԵaw>ߠy57*iv&8\HH߷ 1-y`nm[fz~I<[Vhמ9WFCnHT5-(VW7a#)VR0s֖Z=v3Sծveqʑ0%K֥uk-Kxohi#WV%wg3ڮhQVVKIQhTmۚһ͝ܗRc{D A^=|4֛[ׯZN.^7RO$۩4At8:\"Xo_ Y9ܛr\ VS@:-vMSPU3Gv0_`fMy̶=JTn8ݽjv5=:[]E-$!YQU$9=/vQ|#`(V9EdK>k O;u\\4?1u*Zƪڍ,/M/lJf9#+?GPG~HH 6G=;>pﱁ0U:)ֺMYndipqG]ڙ͆[j7֍E6/NxoB7mZC!#qo*8/i&Fѝ `d_IN6q}w2̥v($*z)=\|?1?"MZ+`-፩SAw&sPϨ.,]uE.VC5#(8䏼za{YS"Kd(r1~CT–o3Zh{1 nM8=ח Oݢ)QEU-nL q,>}p.%}G5v\ޅA2ycaԨmZ0G&@9Hޛ?nuٮfR7CI{ jk}E=.Zwyi8lҦ-{x5jlfD{wnیfCkWiwewn(m0H#:{?Ζv Xl[حŗh, ݹ]cGMu;JeHioa0:]q}o-}6-Jŝ,큷9ImbaLܴP2n@!Rm2 k7q(T8QOsl^hZ%3@mG=~_6jMV}[V_$.r+O+.#(L(L(yp#rxv\2 -^i!u d;TH04=cMY7.fHeeR{5\$0f!e;\J=[T\F0'A~DK]>,ǝBf@8]ڋl.LncfiBH|A&oD-,YL(\⋻+IaEŮ2++]{zDf{c>"cpp8K-iE^oR{[5TrRI]?qQM8")RG48񎤓F1G_o_hK-`i麍$TtqCU]֟stqk5Ŀiav(K-iEwOng;qs[":G-`se厳b+[KKN8"-N/}%KMOMK"[,ͳO}`3IG, /3FH9n>mY]$ocK-iE?Q5%'hJC:H_29)ώmBcY3#8ː>cK-iEjr_kiQl/$;$*rǴ^zwkkO99%ն-=K-iE^ėq\^GiMۋI]P9D$ }#MK-n{+cr~/},O]JKv?w*[;J<+힋̦عf۹1'`;﴿Zd}4}&s~p m\d+խ侊]?2!=[GA 8ֺy+T#"-}4PiE/ 7_hK-CE3PNR M?]5x\&Uo((]5":+f_t_@՗",k\SA=QEQEU?N.O@jӠ((((((((((((((((((((($O,zg%̒鞜u溹>w4uL:X'56M&s<֞H,Im̢Lo,mÜ.r>`0zyw4yw4Oaiz=[ |y $I5a+tEŅt0%KJm ]o  E?6i73AbKneg' WWE^PXn- ŊknxcҺo"?"?8#w m a8 O Isa%֣߼M-jAUTȏ2[ڥlurAMޫ?vmvyJҲLKc8+SȏȏhDMDMRw4-c"o`Z*SGS@wq\W3ῼ?κN$].򛿵rtA˯f_t_^uמ>bb,-G1OTϵWo vFMQShVe9 Q}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUME:% PXݘ5i)4ME.N$f0r=U~謭zQtx ?f[E 6q'#=ת3.:Zk1[xwꏱ6vsiԚ]NJnmj1 =Z:{\ޭ VP L1H@'My{+?2[4Y~S6㎃9 m#S[5ahEwjŗX+ް~ 3Wن vrUbMj]T4|nTj`q,{[?a^,W4ZS v6\{Q05/5 F1k^r]J Wmo+iICYLaSwsV:*i#/>֤n ).=j>n.PQ[J. q [|y_U ߀&tUl Fvxϯjx\$O6BF 6>=CEtc>mpHB@U{ YݦK8*Ox\.F]--fKw0"*3 vybɹޤPH+Ls] /'{/nLyzgajK鰜riu?[}|tGnvِ~n$`cGqEΞu ]~۸n ?ڭ˿ X^TLӑ~n Si+n<'d%;TtN]Gk^x~ZN)Z6 <5ƝrNn"YmF2ObVxvt1-dIC9tSX[׉,MuB(A\>CA˯f_t_^uמ>boO)Š(((((((((((((((((((((((( -@c\,~cMzڬxH$l6V[.oΣKĒi!ZX"JdddvȮ*ZߢAgvЋ%J#!n=F:qNkF<$R+(98jo?Ygl紛B7M^[GqT[cM֟Mywqo yRq~W/3?_Oe:silWۜz85`^ǩma@`B')'n;T [[xn.(2>2p9>'oι}oSo&I4pI8]̙`AYާG?n,CzTqpySsn$nn ]Goιu['Q7M<^W@t#"TTBxӍ"rA#iקoΏ1ߝp:<:m:{DEtU )Q|ɧ,nq`%NO懧BNקǘoΑf-k7ܥwWΆTXT:f=Y.;{eSa`Ivhz_Zu?\ci^jK_%SeMBW9=9:vŧƦn[y-^P(T3N/;SG~f=o1ߝq^#Ԇ ^i. ,m=;]45).KtHL@|xx_ח^gjee&@Rek.u8ߣܤR(3Q_Y].Uw8ۅp@е?os?.[jY5䮐lnfp0q㡤TյkP}=[I[ >\p'LRo _woΏ1ߝq%VyZ# «|FHsR֡jWL7]YUf߰yzo@ZuS%&[! OiA@# rz֟ifL6HB8;O sC:1ߝG-@c\,~cMzڱK wlE& m 8'5ګMeOdcyl,g+#@֝Q_KoΏ1ߝpji{Lگ~aM?6sԗZ-֯C-aBD2Y-x#%6d^׾D`̉G#ß}?ΫikwD#wj*χ>$Ojߏw0}E}E1 Vk|E1EuW_y/΀:֒AC4?fs9#j^*e?X<,$ p?!/[y=a*M?t"3>ZC^*e?+7<+K}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_ufI{nsцG{Z+7-c>RSTZwR&̻QUHa$|7qӾ5Y}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC\Q\fp ánn}Mh?ޛNgncZUJ|mQ :1Ԓx*I|3UwwDOWvtb>5թ_vu/0DŽvPMqPrwg'zd^ ^XwIDAf=I;5(7PzoGթ_kw_r#E!"O9[w ֬YnmJ᯷ 2M7?)>4}MiƄ"ɞ*&kdw1m@J w@epP?30ߎ=1S}Mh?ޛ9M4 #ogI sk? iz{J$^I3K$gpxb>4c;b+؝D1ۼ?gòvp19lTXXlMOeUCbb;BҌ6W##펙f$zf4ص ͟4 c0ILV~4}MhOO𾕥gQYbuC{ 'Mђ7Pn+3ʡbpq[?b>4+ Դk=^`Fċ AR<6#Cm9&e2ݙ$V~4}Mi c3NIz#:KqNCFM=Evep<_T+CPzoGءƁ7Daќ9OA|Zƻ}$~9ی;PzoGءƁC[ʇo#1|v)מ}ޏe}siss 5 czӾ4}MiV*3 [aj+ɼ3 srtӥRh]t6:nP@l{V>4}Mi ?YۤO6wןzGxcKէv3G3Y?drx5oPzoGءƀ>kqu @^e gK(cp.TqbrMZ?ޛ(7}n+t ok5Ag2.vsJi}] y j}+nn*ksPzoGءƕI{++{! $~Iʑp 3X^uԭ!` +0[ß}?΁pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5ޟdg+9m4lb6횣i` ̷w$I,_23`qJ_[+m@t#h$q> f״~,1`s횱{k[s,Q('>IϫXj{o Wlm 4çnuΕ+( #$D v.}K˯e=ߞ  W=>R2*}aN[r4m\05i5]#[X8JM9%nzqRi*RmY~$W0Pxڲi&tȷtI^ lmnij~yݜ/J)u+"lEŭ18]0=M;kygc}}h7,V%*I~U^on:: dMkzke cbGX*fgkEynaҹ}ݜto21@ j汧]xhC\AѢ"-ȣocmf;JkK{KH\%U+'$bO>.֚ MڒezNV,4:c7I 6?K[y;Z+tۼxs{yUc#linssO(4Ozvz%a4OKr2&Y}ʽ=+y)db#1=QIju!̊W]=S"Y>W/6$Zyc.KFu?( [5lgIǠH {a.Y'@}.oY\d| ' MumijEEOq?*v/밯Q4uFDwcM?Wc{D@3*VoSPΟ:btUI#@?dލ@IF:C T(?ь E%~ y_3kP& <HB3\"Eg;xmwiϥȰ3g8548/g aHIPwH9$rh~l?ku7cX@ Y3[_eC20p@ poS;PgӠ mq <vO.=ux,k; jmJΓOA(\ ²N3Nn&jvNn0ۀ@pɡ+:nHȎ59,z\>amem[Dz]ۉf|~U[u;Kehxi9 0ЊK[[Rԣw`xf#iK6YjwDhr.W ޱd흈Is "m6s?0=mfͮCVvlYuhBvr0O^Š€͌dHFPO.1  ˸G?\o\#-)5c6j t!ͮ!gvnPt_KD1[^1ZE p㜃s֍ ; ]@\Rb[-s}_gyEq#tJ8yD5+ #g[K/[rO(Ɍ#YblgN34;}+ŷV1,gCpH_CfU-&Ta_aW厙/tnۿ1"U#r7qjeek8ڻrۻ[֏۱ H<~CoKuu{?AgwWv^ :1R5=""ƊUFyQ@Š((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@M<ȝnn^{כ?o(7Pmei|/fXh.b *=xp=ͳD3[3c÷rp#;7Q X=oL2M^pG??hך?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckUu\\ܼj6P[Wۣ'#6@{G,mc€=6IF cs{?!RW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7Pou\\ܼj6P[Wۣ'DL0d X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*eѮe]{S3<38ck?o(TmP  c'57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ckXc{qm(kꭟu[LƠ:x>࢝Š)2*՘Ѥ 4$Tj2~j<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*Q_J<nCHŠٶVڜE- endstream endobj 67 0 obj << /Length 3011 /Filter /FlateDecode >> stream xڭYY6~_ Ue1^:e'lj+%Qmyd* ~ @c*GWϝoiĸROCDzD7Ωb)odF:uۛVIpJ8OF&p.֌<\Kpt> ESMvz#!NFc~N\fK*+LPR07]c6 l8[II>L+b6Ԗ Z 骬n@zX*bA(DzpoY7r˳na=%N3i2ƨH>>5؊Jͤ9e"vB*^mXwW2D}ːA >aYYnW)Á{\IPE埉itaܦc [u  6|l8ϙ5 /BPȢIIȂKK.a~5TF6dm 5yq=dP.K̞̗gVG@S࿭*cel(`Uː@>z !rl(#AeRf.RM~ka? "<WQ]kaN%7w2_̉#H-ЀIwmCZ϶w#-0pdMɘ.cq֭~~ 7t8E@IU'݁ Klc +}X2Y_kpc[W|A E9JB& fnӐsD!R094Z%sXꆰ涓!ܓ)p sC1n#)eaujA+ :f[K#"BNbgKPr51w~Ԅ3ho*a1XDٵb@r0KB&7j?&We>=zbL e8ɥqhFy6p8kz(;aaI.a;#z jsQ!%wB4"Bsa}I[1lu湝ʀ2`{8nNda X,כ_ EλY|,sj,*%#,I(Fxb$g<\pXjWcؑl*]eƜ]rZʴ{2#?4P…IzuU}Z% 噫B%\IbeH7;e UKY+P̖b)솙ܦNsvSW&+/%&jGEQnzy1%@|>Ǿ!MWS8Ѷ$A-nX FR2>,h1S5l۫`TqQwx m-'L,V@FȾĔh䴚'p%sٮB񬯳~i-jH 6D?m'G^vA!A6P6dx%W| yO^pbbuyy^OKV2omF5blcDD1N'ORsxlRDZ6L󣾴/ǟtjoFk̀H tRT:bHn}/MkvWH6 r"q]eE)])Y1qץp|%m< 0 5#2o==ZXj\sa7D7۹sOa NÚcs M63Jw8U, {?T%؄x)e.>.\@I+ mJ`hwPV:VjLJ%WZVvW}3{8Pd#IV:&^hs+` N@6u:Cd!fʀC{F(+7yO,&3iNR0-خXN>ܒE ,F~pT*yɏZ> +;bBq endstream endobj 58 0 obj << /Type /XObject /Subtype /Image /Width 712 /Height 557 /BitsPerComponent 8 /Length 53711 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH;Ǘ[YY#VxRN}^c6c<4 |Dl.Ȟ qּeb>?)݊K \ynu55{°;`Q@g:Z:-S|d^u dTCїs(}O*K(oh<+Fc10bI>VD\p%04\p~Yndb\PQzt^֖&3 <YTw^yDw =LR-W=8vv`wc? SSِ ː,\/AКնWDbU!ܴeRNޠƵuא*bq،ts\8tD{ڊ((((((((((((((((((((((((((((((((( B\m[$Q딿-{ ((]5":+f_t_@՗",k\SA=5?j6Ղ('U_[pqҫ;-5uU"W=ֹuo|y]>uLX?Q:KppX߄ y؊cQNΈF.7hs= A'P 5rpijA}0]s CO]Fx7-帟z1K<sϵkY\iz~ L2c'a/B`դO8d70isBՋ2v F&sr|w(`qӵ7[9a؜xv3p *#8I>/fi%0-L!E]ՎsOdڅ̶mk"]9%|qޟkmE!9;}8Ի+8d˴nmR[ݴ*@'89&I2`h)۹~ץ #O{Cbh(㉈ }xwᤊ6KDQfRsW.(eGd2qyNp?*H:<`\\\"I+IpTq8~ !#" //"{y`W/u}>"'ˀdMԯ&ơEw)ԣsImK[g@6!{z9 Zk|_z?׬y-fNRHfEAPI'I5k?!YY e@OCێIo$; _?^E!롢~{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_[=SwOrzZm_ }OVuiMdwp}E}Ev Vk|E1EuW_y/΀;/EOPYg:|Es:_j3fvy}Go^}h rrcڣ6?§_OiM{q ܓ>֗?¢kkBodVO.գ IA7Zw[K#O0g#>6Ah,^E=BDFtcǿ[gyg.m`o\"$gt۞b sw)NKDΑg|VgcBƚaV麅Vp}zs@o~VOڝrHķ[Z;l%T`yC?CZ0 M̘OӀ+9B,מYQPܐ[8\GթZܡ%ЗƚGkCjN rzeM~,?|* ]"2BI*q Ps֗h({I'~%m.C2n#V"z$VVp\mF 3=rZs#@(ϯҵ;y#if6#8ޔ}V򇴟syA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}YZ)#+u]C)̶QpA ۘvf>$5E?RCK -?G$cQK=?(?4K{<O5}V򇴟sg[ƪ]o|!Gc`EFFk I;sg[o|>q$3FK!*~Sg5E/PlK{<O -?XQZ?}͟Io?%P'k>GCO|IxA܂0~VHCs IP[$hUB:EU%yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCO -?G$cQGh({I6%P'hyA|j(i>$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCO -?G$cQGh({I6%P'hyA|j(i>$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCOтHIcW<1Gְ4O /rEock qb\ Vk|E1EuW_y/΀;/EOUm:0 EsV>숚3Aߘ?N@:Cc @>X"QuM6U#ܳO b,Qc +2O=Bâo~ !:?QM0dx.2^j5&$ޅ{5,-([yFG#Mk^: U1C?!p=s@"U'DY°(x+K@ݑ@xH-1m#:ϻ/qn[vP85㒦>TS<',$O3 zvwqȯ,e'c}0y?Z~E}jT9H 'c((((((((((((((((((((((((((((((((( B\m[X'Kڷ1Gր;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?JiQI47Xݗ愝?ʼF5rפK4s陫SŃasL  !FpG?WiVl70FWp$ b2 {nq 38sJZ|lr^#ۡ7c&r~{P6_>2Wa)? IdEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ딿-t}kD)[V>wQP.՚_z^{//A?S_)s`u5"~UէU[ 8oy: D<뫃X؆-〸CK2xj-ɪ@~-'O(uۋ&8c`gv#8zsYz VMvV7e}ϜzzuI`I>!eJ ۞> 5h;K> Nt>-4P|x&+5J}(((((((((((((((((((((((((((((((((KDD\-wְO/jA(LRT췏((Q_y/ν Y=|]ue _ /EO@ _Zj!o",@A>^?CVHU~qU6J@`kvj.LX*,69ְ̣zlm|b}y'ZZIQTWҴw6WI F(nG^~y:.Z+{ilTT+I.f!/>hߟzZnҸ8t6OA"BGR5g<یn\Au{iaز<}gkcg}:cevlJܬnH)խu;(4'cm ) QJ)d[i!1ޭגh,d9dt4kukA P6߻✫IfVƃsiŐ&FDU|ZN< p70\Z9coo_)R+eYt|!@ q1qE[{I l!3g(=*U,{LJEPa+<:ԟYY`W{x PP2 pQ(ᷱ?`*HnQ*+G՗PhV\%"Fv ˒VMŅȆ) sc(#{W/H8ۜqOttAnVP$V9^OZJ{4@ʕoƝqֶ\M<j] OAS^C+.7&9Ծ;G'Ӓ+ =XRL.B-מZֿ 1Chxnɔ0|jz}{DXtWBsc>nCۭQ{M5Vfl9w֚UbQc{/??F ɒ]tь5!\6G~$|$n/fI̻$ S*Rc؎I-&%Igp!a>-΋Il$K. vM^-̭b]2̫T"93=ź]#'˱*$dQTv"AC(jz}k}ӽh<##bS' NײZHo.ÿnn~ү{t]>. pO[pc5e=gQ՗[4QoF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZjz}/??¶hU=;YY5e=gV}jc/??F ٢V`pc5e=gQ՗[4QoF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZjz}/??¶hU=;YY5e=gV}jc/??F ٢V`pc5e=gQ՗[4QoF ?C+f>[ñGcLF';JᎃL/Azz~5`$M1܉/((e^{//BVk|E1EtY>*Q,fV: ʢu:)1ij6JLy:c:)raTV. ;:gmUo֠u1FgXGcP}WTڴږ5Ì5ᔶ TtbQ`$WUg#%yU gOƫi +cpHWkFQ 7NW5/w]bQ=3zwVJ ⼵ekems`qk9R'yE?JMlA1iF2ž(yi'kS4 PY=y~Xm#:70YH6? ^—<5ω+w8J$Yc:qکؙ@ٍ~ BqeC#64{_ʾsiu_Rm2k+-P۲#O=:\v}Z|v6^W#,0Y@´{ʾsZOjї?j:/OE)=a1089'yVTUftTnsվm3' (}9ڽnl7vprW+|qjzM}c, MpTs/-W18La x—<8G??gQGA.??ۺE—_Z4[Vi-m-\5{z"`{9#ӽk~\X4i:n]3Iwo6.a)iH!ԅs95&a.Cp`dsr:kyUVHZi@!p|>$'5s)eo c5>4D Гgt c AF𘮥3@KkB)*wV3܃ӎ,Ir˾yWK <2B[fgu`:Y`Y_c,x;}jE%ԁeh"2BB=r)13pO8'54q l 5hC8PRͽT2E瞛R~P媟uA]~ I?@X,iU}RLY3}Iyi <2s\7#FFv}?@v6^"pV-^e "DvcOۦF, 9 QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEih_ջសah_ջសs~:_ ? 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@r>:æ?5yPݒ[#pAzL: 6ܘɭeTiEW=vq oCS;'q^޵<к&I`s giv$k)~a6ӷj<7l$G"c@AjS:$*<=x[\3$pG %7mA'{f!ʳ?@qi/iJ1 zԩ#cx#\Iሴ}NKv̩i9Ǹ[(((((((((((((((((((((((((((((((((KDr趭 kDr趭 k׊iguQWA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~UesiD$&h p#hy*yw6k)dc4!`c,X {cLOm>h;X" (*VA?AfYw00TڶfT@8קF4v5lxgyf6󃪑C:q~29)ɦzzqӂImKˍ <^V*rUZRknM4v!\kQZ}`8:ջk-"M[m$h n3֡ j2O<]ʧdz\Ջ4*("#*s'sʬNZ-Eu_}$go4$of FA'8y[|i\}Gj~6vs=^y&%ؑ8U8i[sCh׉+^d\7@)mN޾BmlYh6 $K<Ձd[]kk9-).t"8U1']Ēh FOA'8*jJU(fKm:$="bPdi$*q ltn RBK mcsO%MBۭu>l^5W /˷e?0’x{Q*I{iopY #9^ Cwh/eٰ 2nE?>O>d/.<;m2i  0zJ s`E:ȁmn;= 5R\}:upv$J)V'9㱧2i;v_o\a}\i6̌pxQUCk< 4k\Oߦ $p~lc*Onv G{ ѱ"$Xzuf *~?MdSXsӑϽG{x#-U~vf 3R{$kSoOjB \Ҥk쒼mogtWn ddu⛜Y)4vz<9DkuJ&[r #8|6m-EȑRHSv7B -Zo5Ea3|gaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGa(+c$õ'Hj ZoR'Mfk׭ʛrwj ( +e^{//BVk|E1EtY>)[ltk;*O=E-:u8skkMI/Pi˒OP' yR$`bOS4]*(ď_5S^ԥ4֒K]a4p3ϰ43Zq'Q42~+%G8ڡSyogjH~_]%Bugn<ס(5-). ,_|+.5+Do=kҼK+<"G>n,ַE}i&r<2=EK^ӷnĬ{tс}1.|#3%4nPED5Yq"|4nl){8v e)V]NZoeIv.s'+*vu~nµ~%- (ʑ3{8v MmǺ@w翸؁99.p{VZ[LlOqoǽ˼OG$s93>88$3Y_x.)nbe2QZ'y&G\+#`}KT v1Ufr9Y1vKK䷝IXӞ[4&@P@\屟gvi}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(pfys.K RYm[^B\m]I-;>࢈>࢘]5":+f_t_@͙ƝlNx: Q˧IwrPdy9xM:."2[KYcon2r:{TvLnbt- D:a@EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ딿-5_/j<5h ( (_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐YAu~&.1r}}\ԋʟXri#!GSif vUPGQZ ; z殭4E/¹#Q~-CPNkymx28'T^eTM!rq3W{|<{j{16(+T5]XL6Xul`~ռ$ۤʈ\df>Nhƶ#1YĦf S=Oi}F6%XUݖHcay yJRԯzO/byV^wѠo.3y#h(((((((((((((((((((((((((((((((((CD)[WAᮧ\!ER趮]Oƀ;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?Ji<#J2#Q`tk1Ψ_˒Uz\QD 7˨BbN a\ΫԀwyhxQtǝ!\|+ Po0aRv"GҀ6X-Y>lp~z宼A}9:Too$:-Υ0RrXR> K@$=ΧZ5iS`A,ޕoerf渐|SZvsRach(((((((((((((((((((((((((((((((((CD)[WAᮧ\!ER趮]Oƀ;>࢈>ࢀuמ>bЮ՚_wV_)}qOTo֬ΒfPNђ3qS>ߗ {9tj 'H FE4Dq::X+w3L#ɇHmS>S fdVFDlK@s{a4DmG|o*qq #zM{-F1ɷR56bTa9$p*-/[M2XXvJus<7sffAh!6s9zU"NX'?(\1ׯ59+hӯikMFs4[^4&+vfUQ 79=*6V^~S<&`g3{hu%; " >fq{GȐ2~h1ۙ>O{6Ld~ruk%fK?! 0R|#溋&-:OF!# $9*Jof9PYKK&1  .qi}ݥol݂d89*[}:5/0J h!f"V$\1zY{w{v I/Q<@9)j_,Wn,-nn,7,QQ0 j hgO>N>D+uQO} k &gD\I'n.G\㟭-Նw"ؔhI6]0zjQ ; zMa$s#B$'np=i{cfeuvP1mxg#k1ݻ)+sc<', ?ZukkfvFٝr9<@U4yiIiv҈aXǎv皱M;M7kgoA8&t[Bmd6kfywtsV/X䴔nߡy_!p$mۻ=*=V\\\ fH++8,0@384K}<+o'ۆPC_P*|y%W8 rfrq qޠ8mۙ n\ 8R{T2zzM#Ȓ|s$ |F"q] l{5xw*%x8I8?zbhb ;cUWF)Zpncޣ^GZsa,N (w<~$Vi,@a-$8piFQ{WZE9XęڍfI۷v1EhҤ^?4̟'p=^InE\@Gܱ)*gsagڬVV >?;Fͥj{;hĬT'&:Ul~B>%yYVkydV u,{B+}FqWmDkdNسNswm[I;_~W6)$ʱj3{jMY߱,[y<@ji%صʏ*%mǨqLmnn>%+ 6 zRF㽻CK40`ljͷwa~\w(k nű0~ve*7ےި\hZ۰Yc9n$0APK0x9 ܭyS1=]%ߢL]B{&Sc|rfn,p 9'2y"JhcgkH._s ncuV淼ԴHe+0"J K֖B/{є%@Rƈc3n),J ii8xOP~SQ&x%ݞEtJ0K#\G4gԖB$,fRd(  (->\[A 2JÃ>*Y,kXm#)'`#G}*^}\@ Dg% ~]Mjx+.}} c(A~U+i>e>߱}} c*{I ",?YϤXi>dWA~Q /Q',`H? >e>߱b=__G,?¬QGp+} c(A~U(EYϤ`H? E}ȯ /_V(OYe>߱}} c*{I ",?YϤXi>dWA~Q /Q',`H? >e>߱b=__G,?¬QGp+} c(A~U(EYϤ`H? E}ȯ /_V(OYe>߱}} c*{I ",?YϤXi>d@v,('*Gj&U/roc/mwG-uipQDpQ]#.՚_z^{//A?U֬n5iK1==?_, +6 1Cm*VL P$Tq?ZyoH_\Zimձh @[k(?IT k?&O*eׯt TjVMGm~:sMеvl QG*\̍Ăg釩5[M :=1$e?#\ Υ]3#Aw1Rx|9{Kɕ,v`a _Y٣~q>\Nƫ2? 4մW?xXm.ON;UmOċ&;l(9i]_3ǹ;gpF70$Qk{r0i cojsKh[0?tĽSOrNuU"W#9Ƿ[v2 8?9x+N؊HLmx۽eϫX[Cosjs} kiq j\%n''ɬ]h_M4I@=r1h *ޛ w t+}Ve`aOJֲ褖RXX>2?z࢈>ࢀuמ>bЮ՚_w6gu@([_Ze~'y {YcH럟 e _GYŨKS(Wu Js浟x~X/w񺭬RGI=kA?j=oѥO}&,6q\99ptht..&k˂<ٙB8d[ҪZaAG8?ΫZ,^(*pH<zS_m{$U8$G4EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!ER趮}O?Q딿-?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUn!D,2uGH,h=:VK*D<*GV,lbI=L b}qOT"~\X5]?jUniUWHgvǶ}PwL;X Wϩv RM=2av&p>B0=zSB<C~OK!3+' OU2LAEm/ʣ}1~6 X|3}!UC2kk[Ė3Hݏm ݭIMG*TsYLIyr1@-2yQ$\N&pÁqǭt\[MdˤjywOU0G=hWdf2+A\F4/2{vIlXN1^tk@`K2ѕXjv`}"ka4qGMo|ʮs:I])$.TVt{khgGP? c@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEhh_/j|7=Q딿-?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃUrJ :~T?{*ir\?4&C.7?] (^.%$r밵k|*?}l'@]ͬ,Ds!THP;s v-faow᱁Wu]o'U7hVg-J$P[I6@@ʒ9$U2Ds"\TqxfY$mAwJ &6z{Z:rY\̊h'zwyA5Ni&yw=сͻ*`RČ'Pb1 ,*"6sV-t}VN6")',9-'5x6pʤ8 STmOе7-40\)GӞ[qVB2+ީmZp\8HS|, ץtVvzop'W1P==rjjQVF^]_6U q +܌QꗷI|SMnP*43ʾJ~z&}BRԪ$HwqR3];Oq0U% 1U>9CGe u=1+WgZuomky*C1_O n9 rN~j|5$\tGG-*FI$}qI6Ob2^[I>c۰0 kۯg XeΥk Z2\I@ە1m:H5BZ)b'B`18s!zVfd!`Q 7XDΠȠ; Ժn㑢K+A'9O'׷jFO6ѫCnU 3֚tޥC[iǕ$.NJ3 F=>ͨq]\Z,ѫv|pLO U # P2p>l&izEf-%v(HR;)r];=u*zZpR`ڽFB(_S?!aHܸ]ͼH!}HwI{hR[XGوdW,w|* Ԓ"m̖Rkc"wSṕW[}I *NXg=ߌ!N'yMcޫ?.,qqUFq͌ =ZNеId^lX^F3'߷h!xf]Dag$_j]:Wy6^4H;Yxx\xAcyRY}LHۈHq5%׆nm$kam2\Q> 41ǦE3PwpsqڨQxslppyYy#/dF\{}/Ek;kgyJi%""  7{coNzҌ#~7ּ,.* u_h[9LVB%ØT~3Нz:M[=т{ ilwq u5WVuP2ҕD@ p+@Q֟ѡ&mוN#yFݱO9:zdu'd_ne8 `篨SB5Cx >G+v<՘tBmu$ӓ2܎}%I[ZƤwVw6I 3N##'75BI\x Y8qү_is qDgYՓyx-a g?)\ZQ_ϡQnDB2*J 4 as. n*;vU|=@4I2O12F1rxKቖha>I1׾5~r} g SZ_-*9Q֥iq";UBXwck\& wdoLՖo4h-Yy=1R,VUKp=9gW ! pǯzԉ[؇ɜFҘVA9b3duy%|7%<Уo_ziụ!vH<9$I?=_GGo;Y2I ŴfGW#i>Z#6̨$ :YOF'EWUVI-X6ߛ}͎{]]yB+*9$>(8?v?G2&s]'2&tGEIy猟ɣ?G`#<Oy猟ɣϰ]R}'h<O.>?4}'hsDtTgx|>?4{9 :*OtGEIy猟ɣ?G`#<Oy猟ɣϰ]R}'h<O.>?4}'hsDtTgx|>?4{9 :*OtDO?ZC*A34n*k+x{zj9k` 1uמ>bЮ՚_wV_)}qOTQEQE\MqSDwlYsjk ؚX7_ß}?κ&UssQS˯f_t_^uמ>b}i!m3Ch3lr>~ZC%Q"@np RSۿ3GL1 1K/33^*e?>ZC? z>){"~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoON[2}n?֗Wk}.x^;Xd3 y4C;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qunYu8aa!%8ǶkWib>5#ʭ{T࢈>࢘]5":+f_t_@ i$MS]K{%x<dFb;OPjv׷U̾zI)zw kX}G& #|y= aF:voNQ%GKX,VSCtrFI}RFͿ?Vrh)o@m'5=o̱G9'W;_[+m@t#h$q[XZk:Vpl2,0Xۂ34^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U}?UfJa:JKa2G¯wk1YAikwt V9E#p)-cz/:u[Fk.RK4;8ϷZ\69H"$:r6P&W❭>Y#?;VL=~ltAգzIY]R4;Y>#+w0Hz1Pk?]LwS\aHTȡe!>\kIۚtP˫A IȰ3g8K;+5KMA-y-[W' ;T:oqoB`vӶן _gSq\GAi3+Sb ryrQKY<_;[i y e?Q5`cJm/ky Onl-!8-z%zm}o˯w3n%-.{Tr^G?n#[ K?%Darʖs hZEy~/Gx]?OxuԬAf#,@xK[]zMc.ymÄI5ğ6Tn\8~W[ipxXRk|UgHOz;m3R]Inc)\JfiT5k$lʱ6JU 'P]5մe ʨ,wе_woGyxOYMo P%ü ŀO?))'Ӯ-E|Ջ3/nק<❭XGEe"PҰoZj,z¾Fp)e /gi6r"P ztu5BOi1[[\;. B=+#÷3kԮd:|eiL(MctRC6їQgAi؟iOwW<n״mfqt 2yYiwٮ"$ p>l泮gMF #! "%𭑐N;(Zz~;w;&FҪ`@'=;Op![%Y67[I5隇7KJI(8أtj-OϘc+< o׮fjΦ8ĭB} Fu7#ͲKpIԂA:kwo\j:oِf_+ HdneoY7Gn\#_βv*Gh ]w+5ze56hI }r4M&Ģdٟ(lڀ6n#Q]XBR{y*^ l~G| 9+7umΤڥ]`x]WkHuɼ0Gjsb2F@8㡪/< æ]KQV8>#2z OMzMmz[+'̭VQݬdZUOO![ӷ;h!mJѰFAt=R+d@76~>+ E{ Rs9 zI =wWh7I?.-?)ŭ2g\H=;V- R/Ll|bdGocK [jV!S\ k./iKHܨ+lWL)*;ƸA!wOj+iP_,f5Gdiv66@f.7;x`~Q"\wN3V՛^d'{zyt63Ȭm#$z_ibM p:CʬNN zxj8??ltSa'v76XӐ.t+9KХbIjwM 98ѷT`~jΩegqO6|Rq8r-ws\l"MpP9N8Z5/]X-Z `Dr- [iui[qm*$RgOI cN֖_iܛxsH3A{xdsOcp/5fMt]k-EZiB\S玵RVĵ-bfTF[h7:e pI< 7W߆yvVxcz:wuM6Al.'f-:$b95,}?Wi};x/3$$u߁5vR^kV 2`ҹ}kX m;IϾkn>LG5F}FcHλDSa4~u --nM0\2z,5=JGKonAIf[(|nBĖ\f ncHmAkmm]NEY!,q(lY-q\X:f͋8};.[qީ]&O9<{G?ugkEy]^hQ}9c]^4#ll 8 WvQn4_4gk徴BU)Ul#H<"9?8Lj'[JTb2h((WNyOc{8).Gry|y%M[dc,O6Clq\#ּ{m.0E7 H]VvM>!AwۧZv3j}x: ,nL-®38$~ko((\5"S4νq5e`2Atve?tvvO^wf ioTug}3OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OJۇy'ڗl}?@o?I^h>"4kp@$o7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ck藖{e=sFѱ^[ht$HKu6@{G,mc€;%f!)ͮa _X𱵏 <+ck?o(Ms}4"Q(g_(09qk\=+ck?o(`;4nRUsy8>z_X𱵏 +ck?o(Ҫ KH,mɲ rO$z^y X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@E="!] Cjy,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@T.uGd}q\',mcXwt:p;8fJKH}BmdF?.{ck?o(6( qQcib8bPW?o(7PQ^k X=o6@{@Yh]_]16 2pH5?o(7Pdx)dm&%}oQT/ָX𱵏 +ck?o(ҩF8*X𱵏 ,=+Kh]DrN6@{G,mc˜Ey,mcX =*_X𱵏 +ck?o(Ҫm},F8@N~W X=o6@{@Ey,mcXzU𱵏 ?ck$d=Utt>+8 GY9$RI5?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )h endstream endobj 63 0 obj << /Type /XObject /Subtype /Image /Width 1137 /Height 465 /BitsPerComponent 8 /Length 78025 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100qC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222q" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BqJxRF@@L7 ;ךxe}% u,d~S°1"'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=IGړּSQ FI(I^) FI(u@$\kRzu@$Ѻ|.=hRz׊Ѻ|?h>? ?EھԞ}=kh>? ?En"_jOZ>Ԟn"Z7?OE'jOZ_Z7?G- [{Wړ֏'x- [E-Qp=IGړּWE-Q B|"(I^- B|"(s>K.=hRz׋й%./ o7E'jOZoZ?-I^- B|atϹ%~Ԟ}=kſgό?nY?7{Oړ֏'x, >|at\iRzs>0K?gό?n?jOZ>Ԟ./ o7G- [p=IGړּ[-s>1K.=hRz׋й%./ o"?jOZ>Ԟ./ o"Z?E'jOZ_Z?G- [{Wړ֏'x- [E-Qp=IGړּWQ FI(I^+ FI(u@$\jRzu@$Ѻ|.}=hRz׊Ѻ|?h>? ?EԞ}=k?h>? ?En"jOZ>Ԟn"ZW_OE'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=\=fS޼H|S O ?E^zN 6=TQp=04q^42E :kUNE0Eex^>xOW9<=ɯӮg/?L2t\|??̟]|G>g{hx._϶~d??̟]3Fkr}'G._϶~d3^ ߙ??r}'Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2.fׁiO9G._϶~d\|??̟r\#m7(3^ ߙ?|G>oQp=4f/M2?r}'{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2t\|??̟]|G>g{hx._϶~d??̟]3Fkr}'G._϶~d3^ ߙ??r}'Eњ?\$m3 ğߙ?.fׁ'iO.\$m3p=4f/?L2t'iO.5|I>g/?LRt\|O?ԟ]|I>g{hx._϶~O?ԟ]3Fkr}'G.oϮ~dEy>*mQ隭vE,Df$Nkӕ hl \ιyFI1 p(O@ 3r>uB.ꑒ{6z 2Y pXcqqYt^jV Y%.y$D\Ω}`:I;ƶ僰G<'xbVIm$V\4sz A{WaKKڶ1dCwvd9c{ϖQsf+Lipц9ג?iI'8bBHWpt7whdeH+g,ONV,w &rǦ,1v#<+U ~t쒫&.Ewr?]ޢуmB^F_%.`4Dj3㸨Ɖv$+op8+յ,7:ͭ_:vB7Eb:@odž|/ Kd tk;v愵uie{v0.4|VR*滼RTPh.s:ǿkxvp:an^*mAn jQV5 ,4uMPHqeqf/>_|tk_1?H< q׶j~-53b$%s]&v=#YH#<#>j]޷6MF""6負pXq{_ޫ&;ǖ`̏w8jԴb.ޠh|[$9~}kNt?hj !#%\s/PjqLGhϦGzy=dq~#> W]:;f%V:ƳuM3/Υ^y7f1xluI^ϩX} G32;_Ӷ֬:_VkH fhCt)ƣ W2\CwvK9:WCk Oxm!Ll=Q5 nysH2ݗ=OCBh/9{;˹+[;OqK WRߎ8Y~ IoSKxͱkAB7u4l:)4$p 6N;dc%dP`ZkoO,7:.29?^GKi4[;[5q>>o$3Zd|[@(oܴP8*H\u)[jPiWgQ,LaUPS?55Kuc2_2qބn:f@4GRgAXP:Aaw)G:kլnAgZMy ?*)l!~ܷ3/oZ5Z+C3 #붳d<2nr=Z~!M}ޗ-Ũ[{ x Ar1҇K[4E5By v_-6WB'0XvQ4#[ Hٗ["lT-GlU+"rCjil_#IQ-/wcM3R4օEr8=wBRBаs\f\+[ 0R+eic}%6XH̀9}\Vͷ5J*|*e^xu#5tSZH&1OMU4[[閖>M֘&#,9]v_#Iiz}-$^<%m8oåDe[Oq"'3}+5]:|'^B WG6+\\8hþ#n*чZPF:+ j~ڽvTiP 2r=i t"Oop.-8yfZs|=xk~2Z^3Lb榵c 3W{H$obG=y)կn/((@a(=R]}911%͝孲n6¼=]Bt[$t+c<vjݍܳg8ReC{vx}j݈֓$li`pl(Ϸґlf)_-nx黭Ymɖٗd\ [}I Ғ43%Ѝ-sfC% z/\R.oΥ(`{Pta$qr:F en~^\X9Ya.]dq ;bSœ;{fp NMI 6*\ s.ʓGh)oOu&{ [+RU# k<8?t0ΰ W~L%trDB=?:rjֲ$nGntJJ w0bG  'y.de#rfPioE;̢L2zc{w`x%_^mMt!r% I>Ҫ0dvFe$Zyi5΢1Hv'Z4I)e$+g =i4:}>t03G?sL*'sU{mNIC((r?BK&S[ .e]MU\<wVB}scޤe]ni޸sYc<~7S)-īI,¤hYM8K4daܶ=,ϲNб'i^zlcYS*zNnQ@Fe>(UFc7QY8unvT$ 2Oa>~7T3i\mb8m#zj~c]+44.A%Q8jԻPQE?uZKŶC"?3RXwzksyM4M hmG }jnT^Wih]Jq*(۩wS(u26w>oa,ٵ,F' d9PQE?uXn,"#5R.ŘzM(ڝ}fسEP䜁Q@[xrо nX}!xsPCSoo:v Q@FeL/ks!m0¦|Gij7BuD=~ʢ(L[wvwVM :8 gTPQE?uPT`ZEL%J/n=375"^O"ǩVUJ)4dSMq2Flt* (TU9MIݞNu6GҼwc}{ b'-o#͞SMszjL(4[yK,LG`gz:W:{ZW"݇!@[o&S?JZ(SXśdF|A 1I(|8sOk=PK<{t"b\A@VVUQmnӜ=˜n-Q@2;";_>6(($te8#@Q@29EBQ~ mPȨW<M(UfV U 1f'$i(((y{fscE4vePYade♚( ???WZo{ҾU?5a_B~ЋQE0"U뽟USORUI"bU(IV,z4I,ZM]m܆A"D aꒆP>Aq+K6#H`2/Guj G#m@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6 جԏyy-0 tr)Vdj?#T#2@z_<[27#W|SӮk;L2v#ry'8m#0E[Ym:<$$}߻nٿJķA ybr$J GQ GR{O!Fr Aש^V/,?*V/,?*Gn.&`QL0;?Y/TL-: %z4[HU?[x?[x).c{xo]&RJ9QiagΪSNdгd}p'Y_@YU_@YUW_o@4h]ezV/,?*V/,?*5ŌWu H+Q9-f$C1p.I7i7|݌۵c¶eT¶eT], O挒Ow{o5ݽ$OV ®N3V]H.:t7BLy#9>ϜcqX_@YU[//͹Ca@.eT`gR֟ןz^_qGWU GQ GSV/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*0t X_|i/_iO0ʲHTTIF])pO]pO@4 Ep8M[Ccx׶͘HΫ`g {5\M AmEo+ y#?V'ko uO2 7prOJ-ΥkGpb|[qSmnFYL͹ą86#[$V>RPқ{~13H̊w(qp2qTrcۉWa%q$X<lZoi )]q*EcxEb2[x&V`IeX].EdbK}Rc|]:opU@;sF1K~g]esu%GI:@9KRͷIZ)gbH+ ~i-IJӦI +1X?0uBOEK,N:̽>?-%ͦm")@wo4\x[Dn@?_j{t!99CvA$]Lѡs[O &Gt3XۂWqnyDy;zU5=ŷ//4B3"i"+6].J'x.<3vRwjK:lRBVd.&Ca  y;!ݷ#]3PYvb܀r3NHvJIK0S!fa~Ynm#+Es XkoQMiWiww%W:zڤΧc|.ۈGow^")},Pn /Rcߗ6zc޵n"n "q=x\Fgr.VٮdPҨ73<:V ˦[ڴZ : )#w8"ΝjJȭ$꠰8 dOTxaii>9?snyYn&/LW͔2A=3U촽Vig.Vnݤd\ۆN K΍uH7 C])Rn7}ELukz,n.HmAbWzvRRUS'ݐTi-ΑukxWP2 ˺0:VP̬ W!څOo30$;Xq 3^Դ;ɮnd 6,

kx`hmf$q(~y[OcoMQ{y,M###$=$֢ҳ+\m!*2b}OaYzM݄6A d%A<)*8#yj8tMV_M"IŹW$s8 @kqoo^o-f 20O~Emeb@ J졀^}$5SBK漞Rna~i]hAcMN9H=SDinD"mb_[+=?_ծ֡Xp3=5n,ѝh]I 9tAe֒76DY4෷ s09ҏQzitKk-"#&a6>S ]ے=ɮij.3>K5Z%մ';b:IԷ`qu tO-lt3{wC$FDq { O6\Eb>!8djzZ{K[{Gtѩɬb:kZrum9##>=]xR[kp9R{vq5n~cNk=MbҴn䐪~^;sS]6.[EI#gC׽,GLkM/py3Nh_cRǮ |0ȷ#d)uFLt^ .Ź7,tQh%C$|x+VWkixR8-d;PZLj;{_6ݤi| ^9Bݏ4fP v5Cj9ʩOƩ;umi2¶WVK2Ss;GZijAO;F-ٙn$i~O4%{/oLӥ[YnYx<v]J-h#h8#=:U$'Dɓ1V&FNilWVq3z9sK}ֱZX-]3 Taw`>1SŖ%Ԓ1Uƒ29577w!M#>z$t}RYfT\ y|`ESsa*8w>a(~Pw ~~/)t5-NT1#.{d[_Cme0iY vۂ8zk_4/LW7pgS۟kmB#84\}Llƽcܺ3U),CUZI$7p0|ۏzu?_oqy,j,\#svӡQI O=I,$c;S]>b{2[sB飇Ma(H?ǻZ٩M~I.VEv޺]3PUa$HHlg}E AksrDv鹉H{+9|QdAu曃j-^k6Z#8@Bd u&F1D#ܪv?'r9_i4cN=Aʩ;Wc}#k 2MK_K߳PK1&x=Zx8k{MRKJv| d<&틿:foqh(((((((((((((((+?Zmt?`8ӽhV-dT+i@R I>Pu]vHKfS$1%ww5fMNų.aiT;g92ú:UMaR0] |?W']Nݡe%tARYJww\bաjvwz`藗tM2oO4u}2 Qw؞u s9CL} 2*Kiq%CQ߷Oqc PQKU!*qqưm<>m͔nb*-3FUE'Z~RdrSM_'_qERQEQE3#K_T}EOeUIW+dlV-ݞ G0#Pho--?[Z3 Nx0ti^=V oss$PPO=GfAOua Mi"yQʹT$ sSx{Eՠ)rd#i'Jk) ((((((((((((((((_ SO +D6ILc>#[tY c6r$9!F>zp-irA"`8cQ`j|̺Y F%0}G\I( r\ӵ`¡YbxTÀq^)Ѯ]+vh]U~+`5 u<>[9 A pҡKOP:xx¤*128݊/3_vFD[O 6@,^x=GOkeo0laU9Q彪-CE'OXiSò U=*Vö$f$ :*y&Mm`iﮡ9HKb6bc|C ̑J!}[ X6F]+U RWʺq Wo5R/*S>gW*:"sbAo$r4r[,Q,`|ZZ^]_][xF1#,{VlZG`Ht%ʊbe9FG'zT'Eԣ#Y&W iyG89Zn/tfXLl#p<1ޥӵT,fxhs*kMBYk?"{ڙXe'ŗ7<[=qñ#zG@mw#IS ڤ :^LձI8#%pG8{WWJHN>GX.8zk-O1ރq>=:n׌~YOahm.']7=TKbQH/zg/z" ڽMn30#Cu*-PhVmFt8 g+A>FFpܬ5PHmͷ9s=oC;2}<_+d [H;;۾ZN"쎠o>;rl6A"bđEeq (Ŵ6s;;̃s=o2}<_+0YUhg9FsGҿ'~fwgvG\n>;2}Xexf6Lld)#¸9G\o>`2[9s=o<_(/?OGl9{;xk8} ͳmh|_(/? ?%eFv{5/%!;Cso>;2}<_+>0W,H%ݞ}M<6*rwgm}S@y>Ee/I$ٶ#wgm}SO>-[vfsumh/?̼eO8bt2Nrs=o|_(/?8 $O\n>,I/Y 9ݟ h/?̼ef1mEg9s=okV-6AG\o>;2}<_+ͥY 趍{v{5'#o:v_/?̼e/res?GӛNGs>=?̼e2}ef8oݖs?GձC*%-s=o_(/? '9wgm}SWSıλ,vwe34Q^ϲ\kJӬvsv6:ʾu9g9ݟ h/?̼eO%;o_e;,y?GG^ϲGy>EsRG5'w4I_v31um}S@y>Ee/ᕋXٝb}MF,l1g9ݟ h/?̼eu oӬ9ٜv=}SJup۬,vs4yQ^ϲ\֒]۬,19ݟ jfcf۳;oyè\<Sv2V.sjl9}s?G6fwg99m}S@y>Ee/ζ6m1{>-ٜ99m}S@/y>Ee/Kvf۳;}M#kY1m}S@Gy>Ee/˶gvfwǜv6cvtGݜ:v6̼e2}ě6);}M)}۴299ݟ h/?vM$);Y+;-#Q--hi9N]dž _RM.KdPLOxH.(HW3E ԏY:ޝ\֭# :6ŗ;XN*ιc0Fծ|6nx֐;o祿=mVZj--Hj?_ ] 6K{+ꗙ#RN#_  6K{+K?u†oGI hJ#y)V;P<~ύfv 7Z?mQz[\j3W>$@: 6K{+>$qRmQz[\.GOSڸcv;o祿=mW|I ??-\dP]z[For'ĚcĚ4: 6K{+>$ԀDT~;#Psz[Fop'zv3\'ϛumQz[^ wA~R?w^=/mǿ 9~'x3m?)l 6K{+Ǔ⧈N7~(d`?^=omǿ 8>!IJEϖeܘmQz[^a/.6R^ xZGhK{({=-- I6Lu@ ^=3mǿ 7_'H_=mǿ ?@|Am 6K{+Ǜ⟈TEGjH>)q/#4o祿=mW[T=)'Ĥ-܈lH$Uk=)tbӭ&6|Cr)l=|h7ut,nmQz[^u:tW{z[FoymFqˬG-߻:ݷ 6K{+G?_|He,}"?U{.oo祿=)#, ?dGj9>&Zdƀ=kmǿ x&k?iU!+S9r*栺w:ϘJb)sZo{ҲeRw<#12Hm7=UuqIr2QL) _ꞻ _Ꞁ6%VzyڽbݿUjJq+>Q(RCd/!GSRRbϜ՗R)s1۴u4X{ԫn0Y4َhXP9*(c`S14@岧9'2$II Z(PGz7bȀ2jy76BL@V+^~\g4/yک zqV ҩOgKKjT/݄ʧlq@VAZüO#1AֲuQZGNx :z ZVgvu8k'@q5u7X\)ڰo@؎2kjy.R"`}"U=XnZ&Ϩܲo~A,! P)jrLvY6CW]̜ʹUIwzS%r#qgJu(X`9Tz0=MLv㹠Ts֤2:u>"q~{uXatm]]yߝˑe;~R=*ʃ9CTc@RL[4N|Ē*l _ZcMx9X|IZ|r0 @5 ɂI94{fyM! p=Ne\ C tTK qDWY( 8F3@S[;wcGC.bGL֗jߝ}qϸy?Chx!]+f{J9 { a3VW~B73 hW'@DZxᓞEeMn#2S)-ȬH m' ew.j)eN M2c4 vg;V]wA0*BR6@ MVPXO4OSqUoAZ=Ug`s@c\IWhUb!8#ڀ,"\ d 3iHR?KI9I@@FI [i0ӓ4^"Zt*$)4JQ< -4ߍո0XqVV5(N,\dWoy sՁ1e<>-ɮcebp{5j4j(+&ݍNZvo-Qɫ}Aaɠ||dUk0j574~r*z=ؤ\pցg!A iRx5X"G5t Z܋R}3@[I.TGzET@EcYwHOh ڀ)iW0 f-͓to*O"$hp(hEʮ=1Sr՟5P 5~1ۊ來\BL¸e*3><+ u5E1jp7oA5KћU2{G~2{G~TE_QVfE?5xS{?5xSݻĪwuw^W}^8>Mvw6YoZRnϿgq~tؖ8*'֖SLCp1U_sҴ*(hdF` Tnܞ*9]ڀ, yZJdV6 Bs⣱-<f5Zdr}*ⅷ<{թ$>Y=)2qAĨ4fUP?w0ZIAIu'&s@<$?ZgB*A5"K (NM2W/ H4d-'$fH+B;UKvۓP? V@TȬ 2(涘 cv$qg֬!IWi$'uP gVь cZ49uYSLPc1%9 (SciG͜Pg`⣓)X4sր)֗Noݏ#?5vp@~m;-y?C?gx!]+f{J9 { a[Cv_#O՗tFgڠGHU<}*l ☊NzgZsYwnZ`; (M瑚HB T6#w'ˌ?w/-3d^gkVնqY5 #pa܊]ïUdRR0WoCYcpB@*(yY"S.:v+"87) P\Nu5N\HoWp(qm2[0wKlJTb hBЬUYoӌRidm$TdV3s5VVI_85$nȮbfʮ( m),2k/JʹS5w;)pil;aV0ۦ@ěT+Tbbu0zgie y<%= r 5 `Q j9B{ktmZ2k*—7=ekAǺ+ekAǺ*(e(̊kWkW vUe)lFp|~USy^=zcҒ.^.%[C,*sڪ3mn iҘ@psQMp"'@jptwesҀ,HuS6Iҵ:}۳ZA4ᴊV%cqD3@y!P2<$nP8 ,qWű vx Ux'cdɩ#godc#Ҁ?зLj(^QG{L$^OJ' G"K"n`Yy8T8ZO7Z'J06 15 հNljOpC!'ozтu T ʶkyq>9/B(iG; M3t9sJd<2gs֬[d$8( [LftYV= c(,Vs@JP%1@o"[X3\֣4;FK̤ޙ!pA&t!J=+]Q gڣ >qp 3H<-*zVF6`qyNv1֜ y959ȩ7~}XsJNUxm9׊:SsM`p񻨩Bf0Ijq4=ڝ!>ؗr@ٲT6kBB?/M42di)b{ ,V䞘>jXF1R8}LGA략:әc@ x2q b)3ޱ/k{ N1ҫϧҫPQJS zAFc.vEH rKrhI'>v4&Nxc1PUG=*+#E;xzbHi@+"?5g܀QSE2TwJ)hI˰XaMd\\oShĮpf ٫ێ[x.O~㩧6?y[[$uZ  IՆ*ȅVXhj:u7|;@u|>I; g5I9X[UtCL7#4H[Is:UB[֮<*s a}QpFj5sRpYcBT0 HR`UaL[,"Lۉdzq]n*8(x@sWsp9Tf]jqZjU7T*Xv-L%'i l5UU{q@֢zc<֍m,x ͹rj5+o,N܊Ηk="D' {#:,n1ޮGdLp G>2հ#$EJF_#P6>ЩI4w9gr.ֵ4ȁ]A0!FUmdXi8L54:3 RNA=1J'5\K*L(e3OU ʒ$I-)Wq@ oZzz;Xu y=iBNԊC=!qtVf>#8Oeb;c{х$K|Z~H@ ҢJp @.TҦV}(Wqǥ!^@4/z}CWG]_3= lԏq_3?vGҺCCv_#Rjz[Tw~pR?:V\S#i4`8qrZ7pF\4~J$VT*`$P3߁ދhۜSV|S-۱?hJZejf##oNSy}i̿+61L䷠ ׈K 6EfnTMY$?+@"e#ʓ[n*Tc9x^5*Qo0Ji.ư}@"&ֵ-pIPS {VLYOP گ:֔RfS(/qkNYm8<ۜWcLF8"<RYR9z":֥|YZ;֟B=)/ %sT:1/sKj4, WpW ^k*Op{sۚ.<$NHpN2TTPJ&(݁5_&GWַ*B>u_WZx=ǽ cJýV C5}R>ʻ[?#]!{!/?[mCv_#M׎>V\Ricvi6)Ͻ1h {ZqQԓe?ך0@O3ʛڧR `MHqPܜ~㩪ۉ㠧7˸ e^] 1 &zO5u7;3JN({,͹YsU.b)03ձqE݄_/Jg 1kb9tA u|qLR[` =*KȒtQ3@ 6Z02⧶&S.q@a1v~Zn꒰WfZZ;6>jm6ݣT5+T(] L8ZZ9 K4b[ץkN(H%.2w ; #Z`EA ~^c̍Кu* bSP}ѷB\I)n|5$y'ehj '$G޳OZ)&Ta Es]˱6ȮB|t wMH$9&;ⷬ4d1fUgqtTҰnach3zZ`'AP2gRCOc@>1n1 c5pR=6$ېaaP; 9?уxt库ԏʣc 5vCcI*p5Af0bhp=h9x}vpD@w`foΤx>$Oas}^QIXx@n*$)Jsɧ\PJR'^(,<5.}k[6qk[@/)z3|/3Uh[:o{ұUh[:o{ҪˆV]*ȧ/zg/z۷oZRnϿgǙpq^n*]l8וCר"Cc>Gjb,nGj{,84w4A6,jzS!vƶaA*2DocH\I֕|GJ+I!V0pqҘѴjGVc$\TEgĨ#=)q@be x<y0Ҁ&T$u5u <`H,ۃpyWbvOZk;623ZkQq@3qR;yc- *zw%'ڀ,C t$TI#D8&(6n Ќ@UqkIqP22Ĉ|܈<`8xAV\ւB-eM XIXTH#5Jī_npn>AS,!m8#~R{sڪ.]^(m@ۖjgkI;%Qq@w.~y5e xP.q&-[Å|*c;gv:p0+ *m[~wcq$>C5}uUJ_]ǽݗvӵ [nj'!|a 6TN.H-hۇ8Ive[b-;2N{P[ åV`?=AŚp_?*R8݃ KC0ր'R@BNj$eFk!FmaW-#2L\'BG&AÌu %E^Xtvq$eTT |ǥT H]gҠhOր#Ӣ/7ZRE[M].{ҽAQ><Q6tyǃ*RB(ekmTu5чEV :r{qZK&jC: |;}!-E_2v=(=Ne>ǜ:<[UV6ˎxٞ XqߺC=rW֭>MXV4>o=1K1: CY*k>8g b+"DI.`*kze&tǥFѯ=E[q;rrSjo0|UA8)kV[LXB'2>@++WCk(g5<+[Bs[ ^ xz3"+gMuV1VAǺ*(e(̊kWkW vUe)lFp|Ч\cMh ˃X6;Ud(v5fXߺ1Y;XkjEMsμ[NߖG5CP̏1@bZcү1O^+?I6'K,'(n~^OsQfRy z "` [ + Sf3^Sⵡ\ rjRzʐ=jNLXe,pۀgڲ+43V 3 +y;bZ$%T=j̬ȁ5cMs( NnҨXڙNZ:x*#c4%k$S4YBsT]ۚ1F 7-nx]vrط\lss@J^{uPFXb6|U`HȮOb8N,Tʫ7s@ɒ*m&il(qmiڒJ:kGX=2+uqu ڀ.c5Vʦ(=w !W::}<Gx_E[ۆ:Wq}H<;F!ֲds]Kl-oc+2nV#=ʴDgVtx[+:ݣP5B(:( yj"v[]wdt_ 6-voqGCWG]_gx*lԏqGF{HWAcnk?Ƙ%h^nj}l*C89Ht*[-E5$8#< E*m?ѦcW2s%H<'ڠC.]t(ր:e :w<-¸y pe(+qlMwcͽ涮sg (M3\ľ!Z<2`~fLrmvFysDC@{WH1%LGnMc>Z ʞj]OJ`Yw)q E^\NDU]m7篵hXZ${I :]@cMY)mJ4|ƫpU ]+f\w+2M'ֶn|@(,Q8 $Rj=O(+\=jq`D8!A@bu$UiL r3Uv1ko12dm"9ַadwlґ@)YZݖvǥ3WIP^ł8CCU 43jBSͧ\|\U g]iAڮh fߟ&Ա5[R nMe_Rf_~g`h[:o{ұ״7=UODU߫.EfdS\=w\=m۷JWw[)N7u{g3MrEoZRnϿgg#i!NKYa3ySZS4WPGj95|X; -_ P6SN܃ZfR(m^GFN[""[c\ZlQ(cCVH8TH0Hh?E+V>C0oOZPrpOLUȇSqTdKzUX@ot^Ezrs(c'zf͞tWKV~p0:TWfXNW2I":.pC=/?1Dz!8t׵R+iPZJcSwA(X;4%ݐOlcֲ|;mͧi!dɀB``]/jA>O+ajk0zV'"Ifc6RxBpұhXq(2:# 0([epQ˦ۯJ$qheYc5C+ߛomwc=)kz]_\yWh2\ϡy?BʻK?#\YR>r6{GW7e]5 il;L!@[wnqVlfk9Okw$S\n8ػ+&h1]kNeROJcbE^TNW3XqRPü5iܛJ| 7&|W-KD ;HS6OB{Yz6qk3A$؈m2 Ho.CDpPn uѕB]SAB9n]ġ_eH=z{I.RxuF~`KKF$cᱎ;Oӡӣ!ga4;o 䁁ҟ =iiuu-̑_O) 6+5K e;]CG:BivA1q$S^G`1"`TNr=q9iA$P]ϭg5[pY}h{$֮11-i$k!b9y'5 1pk6`[Vv/^E@c8,}hګ95dc~+>;(6,y85nU&UjkXc+}i|8P@Mk&Wװ漐H$UH˺Nր')-Q3l*v @iY@xk-L]b=h1/ٹ:w(6Pڀ2n ȩH5 b/A5q%HV}i`0k^쨅F;Pp{ U0]Q_Bw*8I"?gjʻ_߀zԁe%A"r5YGp=8RD t-x hJ\k - HQV[Z3QS|zdW4d88Z:Lk h<O \z֞r%"SF)z3|/3״7=XEX??VΛ*o՗h2) _ꞻ _Ꞁ6%Vz0ȯ_oZRnϿg68̛k ub8"(XidlnHAo(/JD!Q&ݳ@'Қ!l:ǥ(g 4L~}8jLP3cs@mX ~w~b@pqI1ƻ ̈9i䤻Ivzʼ{y8phaRϻ`A,{(9'=3Nq1PI<>]&@#iZMv(2빇$X==+LD+U+bP=Px cZbt vE0sFrV1݁w,Ri 85mbG5*Z5Sm5 q8@iͷ=*;7=x⩖ & ݣk"n&Tkv->[ɿzNinP5Ɲ[@[rCJICҧUm8 sN#8e˳uћtsVmk!Sn5Z7lW)-yXjݛX lYm;?JO$(v6bI+l [fs'a؆BlN7L1v'zxJ|b }Q}ǎd D_*OΉNOZ[,֥ v4.uܰ݁TeXVf=יcq}>/TSu#P--|w*xP1r+4q^Z[\K 8Zh|Gyogwp[oOAd+e`<-sڊIk#Ѹꎸ#5w/$xZy9v%dVykaگ޽;r۱v:?<,6sl x4nke=G<u _ES#=Wig}+?3?vGҺCCv_#X_e9MnnkllbJC9= nVR̅9=+dmTiĊ3-Z֋:VM7\浬/pMg`mgzU[<.z&)qV5^m5ܷV"* }֨[iI+qZ;13ɠ zvy wEAY'r~ojkZU$.*qEA m[ wx9']NQgP[vVG*OEK=.96:%1o8t|Aԥ\,V]췓W8=2:-@*\8a彄g\M@nݎ3ZmMeRF>و@wAҮ^G, d+Ffi+ @O Ս@F{`VuZ(siOxzgӸE=jEI>o$+ VUx$s3裎i z9JK[hM6lyF8VD}v**MH|O“RNN1$Z=+ZS zk*{2*>bYFk5O34xEr9p(X&YRAiƻMM,aY(]ER1[M H{gjvuڀ+_) *DX4 ج'4Q^-]t#AbM-szIKg(dbZēF[4h Sj@0 2B>ڃf@J~sjپ_`GP+&vl\dŌvGZn(qڟ kX@-&Wzf{Uy.^FӊmMX:ktơu]<*Ż[ۮ*FqҀ:+ddEszeaگjl`{W#$\P!A 9e#4˘#C2P? @e֫\۷JWw[)N7u{g38$Ce8Q2.: $$)`W sW1C O4Q\LvV<׏u.o,".0qU*jY(Ps@ E‚rMG!A&vdtrhXYBp3OciTgp:5`9AUb<s'Fr!}*y^D2285H+n ycֳ5$9POZƺ )\Տjnէq0XZ k˟\ 4&JԱ$]n^VS1޸yHkEzs@=1z8j7('Ҁ92D pFje|yX60k&F,&i5 u:\"+e'ӥr+ C~ Xo>fœɻU>Vt$c 'ZdAeGjѱahu4Mi)e*. VF@@1g =kF&޸yWNq[Yy|8т]Ѯ JhzsޒYҀ+HnpZˇA3Wm|w0p Jq֢^V8@#|D\݉uܝEtrk=~lހ0#ҥ2ح-;GH:~y3SqPIDˉny) x~`9';nsZp `WʖFj ?*Jf,pEtp.#Kkk)s@V,zF8fh_z`'io,m(l3?fj#]سRk5Yw.(r䞔FCdQEjWC5}?QR>ş~Wig}+17e]5SŊ lf?w ;g=݇Hgu*~kQ,::N=*8{~!`sRnm.1Z7A`8J{n0p(RXԃگlR:cIf9SZ)Ƞ Ra7 Cg$Q= cJӸbKԟS\y3*ӉzVKPHjm*qW9.jx J㊱cl$; >(!+ cE7 =WۜPR $A"4HebZYy`95G6>_4XzL?n[3O 2B/e'>r\+6RJ|A I2yaqGkL\QKg7Teoz$D>lT7Oހ-H'5MsYo#*VOIXz7G(hbt =4j|wbOJʇ$hf aldUQ'ju(}xmGM6}:c4Md(nz(@&+,k3Vksǭnyb}qGJy&&7{+NQY&dEgtkؒz;f^K{goS*E'9c'N&RxxzڲNFҵm4QYFy'ok('@{WyQ71Mg$>6Ul2J;bjB8P~TjmaG'xWhʛO"0K.FO,L N&4X2=h[wF'U6#VMNvW{ĖAoӭgQ֋ oϾkfd8==-ZogH95 Һ}ND Ԏk@-I{H}kZ2lBBhXppsހ8 B@r.a"x64o TqUA䄍I8tye +zIKp QWIӖHqa" 'ya@ pڎrq+wooX玣zGo-w^q^[q2=GCWG]_sʻK?#\Y+R>r'N2|[Z>aTygtZn#6ߛjK/: Vņ< LG1"yNb'm Yɋv9R#]b紒Lp+ӧFb(Ib K4x.@ )y\z_6Y0kI/Li$(0(l&8ł ҴuU 0+InRv+CHyGQrj@Я:Sd-HJXM2T=EHwPLX(!88?R9xy=S+sX1<@la.eV]?*DZ\XG4IIL!>T8@LY"4v< ޞ &㠩b# @QҀ(l 3YU۫Ggaӽ!F2k5H9k3kI$@呤'"qUڜ3 hƣ1}ULc5jD4v/19KGRaJY-b.}5n^01qM[ Yeğ{4${eRMUkW],A #XdP=>э dsҩmV$0P]ƬNETW[*HSZD֚$|PfK3萗h=}bL qE8F9&im.(M֜Ҁ1ub&VT:@"\ Ս=ϥfu`9|XPY:К傩>=W3 *9X8=sRƀ5DBJGe 8+,B=N̑Ҁ{l ] pz+b8>UP#ya%xAb&K|㫟q֢yNE\B=G<u _EFkHW3\EvGҺCCv_#I vgݗvѿ!<#U+WyV1b1,TN:֍߳6{ ϶wI\yT"h'\sKkPBR.zJWTS1V-.M%鑶F2iS4IGGkycQ] [P`LxɠZW` o -A3Lcpjb8Dr2{xj$j2e tǭߒ{zTP xHq@/ڸbDFS֟!dub @Op7RKGAˍ/W\㰠 EL"6ۦ ;wBWd9\ΕwLl X>5녵b4Y2y}6 m v@fH~ZU ϥU-Rҫ mNB5F`MY2{`J ;%{/5gԚڄA1Ҁ&z⹍^;ڴK(ݕrNsP!){ pMjX>ϸ@XNw+rɇoJҐf*P74 ӑKeJ]פ:柧ߔ Ϸt82 * qSkX˓MֲSj];@`gqlbY @ Ӂi z=wҳBIZSWb(~٘,SK9L6΀4܈ڣ4^ 8U^Z1:S@s P~BkOmvG^3D+p٬s(+J}._+%*皪H>ncVGSVR4}4a:ҕBzaXb#\VU/Fo<=Wz+ȩ{'+kMuV+ȩ{'+kMuUSQ~7˴QEYpO]pO@vUSy^=z4@-W۷JWw[)N7u{g3qۼc8$6fprkFUW,1?ZJDxR7GJ6?Ú/4H'Zp晜?4.Ҁ8`IMǗ 2ww=iF>cȠ 34֧(fBW#8DxUkxs}jYumNim),z犊Q@< |q@(MD+V̉  !ֲc9>̪dəͳ2H\4֗WwՏ"q U[p|cw.2.F. S|$.2U݂GlG$bY3Z0 bqI S!(Ze&QU-4}y銰@nn#dy8ޅ@{IHb PX(ңzҳhEn 栝^?Q&XSd =((TLc?AQ=3R+f>h܂NnJjd4gwR8=;ѷ֥LF8Uku1q]3#d*BG'Ҁ1aakX!vłFNF(W۷Z!sR}E#B }8<in tv>^ 6KEZ@F3ҥp(( jޓҟ}SL#;-= sS<ؗS;!ϟC$>C5}FkHW3\}EvGҺCCv_#Oտ[S/7e]5.2 7386FhdsOLdV q1TES $a{O,+ Z#G֮#>nX t7Wꍁ4jiV8-ֱgIjΚkFs=+ZDs@,v:ր#h23Rcy|cFM.2栠?tj#x?I"=~ !@2aHDF<Z݉TN-.W> n'TI^iZ PhyY'UGCojh !ҀI;| ~aoQQh1MjC&-gkmT~5.-@ʠVVK&kc;۫JdpMiIT'ҏt#uZ| e/u6WcT[7Er ܂~oAɠV6lrЋM6j#p i!O ߟZ@ MNGҵ dJ>Fx8$  }hl(MYG {}mu5FC@b,9=rr5g6[?tֲ*5;E6h#t@^pj=qקyր$7Ϧ*aE sGuy'@f-rbj &R>Oq-`T֖9lBܴ8  F֟ sր% Ɨ`8`ziobDM y21M^s:RxS3ЏQ=(b}PۛFwc?<u _E6+R>ŷQ]ǽݗvv a5`?JC31|{"`"sb'.8zF"1TGU ^bQI-]桷y{sS[Yl$b5 Gml欐HPlu}aWFڱchfj\vDTpyҬ;Lb>@]JR/J_2S6 ~֐lOTZX3@Ce$(CKr/&xF>Z݊y(a^).(=@}O9W9'@,Nsln>j*p1gd<Ⱥqګɏ0h Ѹ2Y#yjn:Vqɠ e5308k.f+^*VrkBACTZCҀ)|y{vƨKIcw#(s;c㰦y}*lHp4k1*[wGjGe,85; q@JzuBi >=+IrrN~Y`]w>daSPנxr#̽KT!`T5 na֋93 \s@4Y jV 1@ozvWހHPc5[Y,(wI\t&t(.zbA ~FDq\CG@%rni4@0qiuȠ>Y-g]:P{t櫥zVTr&6y+2/8oj?qޮiSрG 9g";]dtxf?/zQ!>=hMlGiE׊jh@==R#V\E:A .ڧbIuOAOFSpڀ.ZYNoj܄&MegʿLJao dEmiJodEmiJ "Yv(3"U뽟UnݿUjJq+>QjC7S]-Īwuw^W}^8<@zRCbzTYlM<Zb#8 > jC&~U`!cz#<ܞMkF \tt! <7 -VUsOa!"to(KRJR|܁TЄץhG5ЄPP%?2b`iFQI. >nX+F>8b#X?)N r'7P~bNy_ծvprT(ƗJAzU隐`)H8VV-rMp#I.,:Vy2r~m}E@:zPTr}8=3:$#=wsho TmjGvFwc?5l@gÍMHۛFwc?<u _E#5Wig}+o>K?#]!{!/?JuF0_| C1 G$2y^yUUX|93Ňz8d$G(2+Uu*0ZnQ(fFqڣYT*Fu,A f_ by5T7S8w; T23HbWZP[ ӵeݐ< t,&QO@#^)zI-5F.wFkb&O/G5z*kxHT:@eaTvN˶'8,:֍i 7\|¹$rjʠ:{S\n'G&,z;EVryeWiQ U;I OJgJcր7t8‹c"z hƕ V| j[l$#J&u:4#~ nOletv۱jn'ހ'Qrqݱq2']E"+NWր2bgS屝E%OZt=jơj:q@{e4su@b=pՔW.%s$7IiaNli̢UF$޺v Ֆ{a2%`8ZTHET̏׌(S95$ƥTmoĥN {G@W6{T{ ;V8؊y&X**2n%5MP沯)z3|/3E8??[Zw{ұ[E8?[Zw{ҪˆV]*ȧ/zg/z۷oZRnϿg$OJm%Vz9I JTeFOrxb^)a*EsFs֦pQu@F ɴzVݼf(b* ;Py$A7 i\*&P;RwNZgkȠ em# )M)ڀިyx-Fyp8uk.?- opz ]éssNY bHSLN?*$}iQS֘dĨq4|71+Q@r\ƧL7j!jȵfB>ڡU;@ L 1(y!Jkm^LQҬokMV)XqҦϞqQ.&28힕rt*Y.p mM*n#\mZ͝ǘFsQ' ,vNy&3eCgޡTZM3@3]rl»mڱt 6 4/s](ǿJr8VWg4ҪYL&lĞkfO@&TG'ȵd(e}ϭg &J$UovھCPK*+<M5+=ylnT'p')bZY\ q@Z{S@8$~.%$15SN{ԑb{棽ޝչHЃ@XO ̢'rz/jV {U5:Չ}*4zBېOjkGL]>^:!7M0hK0Y,=ͽߌ\C3zWYvlր9}{O;G5ͧ+}{׫S̋@US=ZRpc<\hee r|Vր4т?J"dQA7>M`G^DK$Y lHF=*n.{jt6 DŽk: &e@k4b=kQ_F:se_Rf_~g7pײ"_bpת"_U?W~EUO p^*T p^*Tn*]l8וCר+:6wwUSy^=z`pi!oz̅R]&*nnjkUR#SR1%t^w;[u0}*B{u ȩ\_Jm"@  Ž"]I>X>8D8y@#1VX eJqqj/;1s)v۞*JqTe#AGuAmS15WmjpsWKq[Tvl}'ΤUNj`ݔ?J$SYח ],S8}FhAY>(ن</[jz,6>қj6$bNHXu8*fHd@lJ֤P_άN $8Ƞ|Ua8T D,yLqT^v=hi$ ;O>'IHגJPSV0&vdb9SC&$|#L~Qԋl/JFhK!ŧ P_}j`/{Ԙ:Pq["0 +Km#oD9>-U65#nn!ݎq$>C5}憷Q]1fԏt=F/MݗvoGe6Y?RTvr =k. j@s Ri)#)niyf2AȦn ̇oZŁ1O!$㊡-A zROZWʫb R rj0(G,n5)/^*c?FQ" }J(P9暀9Px<ʩRv',*n@A@UUmf_5ƀ* WEWR$1 qڠ\s]vX-V?"E%&YZ8d1nzW9j @prM[A*v5,~`(Â[]>A$-ٱ+x X3҆@1[^Ymb<:[fŠ1_,r:V}Vv?nP1-ߓ),(#+ I\3K6k#P; Ò ][q=j7.18ΎJՎF:PU9gX"XՕN+E1zB mcV|1\)ݝh dpŠif-㈟ր:  ڞW<<$f1pI kgPzQܨk#֒J瞔ajosלT 0|@ x_K_spb'֘JDץui\M5sh!NI1ێ+2&;,dpZf@@lT~bW56EzK*.wFydY<{?i!,:4kZ_Lx:JUQ;CcUی`b܂: jLsLDֱKttQ^(qjz^sK#dduVzKP[# o :퀋j v "_2PǧJ3ڒԄ\:%ت*%;ՒZFTSH8 :L <#W8_Ymk: I9Qןw3ZM{x!zg5;[D"6X c֔ÌюiA*{l77<Uk+@W~*GZI@XsU%B3ֳm-cD8ր5# 3z MtlE]Pd>8!uo` TND R#U@u6Q&Ǯi^?1]uF"S 8@\̬_,ɑ9=qWm-]GҀ9Sp)R3qךd21|쭦|#$P9$j Em.`˂N*熭fEQPIF,O5b?}q]l$/TCOs@4f/G{/&1^k~9E#閚 ӆN~ul\)W2:JK+ɬ<[s mrH9o-d]-r1cxi I"ϖ7ާmmDwc?9o9Z^|%nf>}CWG]_fԏq#5Wgg}+17e]5Z2ÝiU{!/?y`pO!"׷.r9fkk8yJ\zb1.ulޤ-P[ڳr fuNJ۳5~?n ShV նμm636h=gCj>5p>E]GZ8 iT_ךOZ]'2^_-NA=kF"k*X*}GVp'ζCut\zT\n>5kl6=(|wzbwtXWjOP/3^Mi`Dk>O$#5ɠ&v@4RL~Mdf-91ex<\USj}L@etZ}c;m$;p08f*xEd(Î=j݌\PJ;W9dS[׍r7 Aր(XD:pkv+Wm q?Y' *f)|@XחkN S۲80oxUOsK"h>zZ*.?wڬΪo4mK268t%+98Z m^4c+_005x}VUf<@r|Mՙ5[ 7;F(}5L_o* 4rAϵS1U3jn湽2atn@<܈~FMʷ 0p1Nbis5:,Ђ#+؞%o!sftГ$KGNIH'ҵ`3[6& ff:'BQ-`&"?&A*=8mc' ={n!VQ׮([8ɞ0AasNl5`fj'Ufɭ5S$t}.r-*c# DYW_߿pת"_bpת"_U?W~EUO p^*T p^*Tn*]l8וCר6`+%Vza9!ZdMy8 ZٷQLDf'UsS$H:lR+6\aҥDm#Jr¹ZQ^5X[zP4jRh;M`̣4|wfF4%WB((XUJpy qȪ8RzI68Sֶ$;Imdeq֝, y8@%@AM8AGpk9$!q-/8+e`8{Uk$6:QO*=i!ӟ41@\L̻YZLIZi$U@X (q]ą\e8m@dfm6H𥵽]5z~-Z52G-x=jgz#r7Cֻm lCO<($wVLbq5c >]Υ >g?`DZ6c nYo kMtop8Y0_!Ṅڵ.v v.`fOj "[Mx\oε0E!PTHNޔq"3ȫ˃z}(8X)&9#_DBucy@&@ݑS.+T 8)oo:1Ҁ0%:fq08VL'$1޳NZs|Zdq ('5^zzi ls3PfC `O\P"I!KxarG;?#\cqJ17e]5gdgVF#scHg5ʪ2yP mXHp&nbQq1ߖ>r&#EF ։q&*=4n ʾ U$ SI#. Y)v鏝quWE O@c#ڨKN[kŬEcpMhE,G4gR&7b}"cƒPt4w%+o0?Z{]( `]IfP>O>)IFk#.+"M2$lx@ͥK ~ Y!Ϯ+muJ Ű8:1iI$o aqLac`i%Ԗa{C 2 3N0;չU7Փ<^\گۉ}(sU^MI954 slzƭ<;jLP2j̶;զ@[5\1PJ>@ ScSOj۸3E5t&P[9 n`@4p[wV9J<c-d1"1JޫmQTџZ~UPJvU.Wdǃ֬iC8 n*'5-ʤGm,ƀܘnjqUVkEYDDG(2٦Q4/ֵ|+]4.@zњPdDUlb#hǹ5XS]S5% M~g?Pת"_c'ᄏ9n\(;=UhɨӓhEUE?5xS{?5xSݻĪwuw^W}^8>E*cW۷JWw[)N7u{g3kġi! ֺb ǂLCLCrAcҜPR^Y)vigH:ՋCU) T1 VDYKgꚉb&S5FNVnOl#w0RF}h9^KjWPhẼ;x8 n"p@Yrsq[j.8R7r%bu p_U[P+ֲiKc2+@wvb1=0ªG,:w>ڀ7c "/5 fA5mvU5g,S}PuflLJNx* l۱ZD `ӂRC] d U dP`\(n"kyPUyl؎NڠC dUtfv1Cȇ~1@oʸfsk}^@"2⼺8X3VtLwR}6.*.pzw໅IX =}y=.qv6-W7ulu*1? [Fi;?#\c?Wgg}(Cv_#TZ {!Wo7e]5[aX*C8ǴrĎ2#Mn4X<Ι-b3ad .Ȑn^Tv55=)ʌ).* 28Xր!-lmN].NV,EDy )SҔO[eVnDw3cށ]pT맚71G\ջF 5.r5ZM)na  #Ҳe6cVc %ƋRj̻ʧ55.H4|$PyrOՋ}B[,JlbBk9X?Zڶ֑E`\{񊣙M٠ SPL Vt8WvNrk*ٮ [Y :Pӌ&`b|[;~)t-j| rZø3ס3=}{;LV(v2$W0QVvq$P M1Za(-|#lqY:"(ur\tz+O5E W/NE6f+Rlqk&r{ֵ! 93V[?9 V$zg5V ^8kͅY@_P.sZ7AT k0q[vaְHŒwmnr={s@*3m= IޑA M#88;Eă-kWUFǥdBwphaztT5IAmf)`zV}nkfiNW~=z0x3V2~RBd*z kRIZ)ύ2*PK/AWWÚ\qJgbcx 9=:T> > #OTSWSTw^M;ryHG]46RX#WlȐ̔<$t⸝^.AtX^qTH#!}R1Y>'yy5]`Bv7ҽn?Z3cz+_ZűzK֠%|Tz߳qұ'ڽ=< [OM1%p1D>ib.;b?ҥ3V m-B;kh,:u&x7YU/;b'JûA>'KGh;"ae p@>G))83 j~oM$V_ҺKqgLojRJ=tUi,TWwx/ViCx/Ucᤵxy4ܴ;[&Y|:`$U_@[|OAjU˒3ޛimz(%U<':|VxʐXdjh>aUǂ<@ ;Z!@nT ͗ 5vDH|-}| *5:> Ռpu$^ԕtaRp:)m]?"|U;y`¹xP?J;YZ<7z%ylRKD.(/{TrÁҺƪ)\?[$aF>ZE:})>qC?4 3tۭ&dڅ爩W>Р(EvvGҸ,Wei}){!/?&mv鹇gtY5 9V?-!jX!xbǦLE+rJZ? d̄4Β8Zw8@ql}­=8OP7F8̓mǡGsqo2}P.,02x#HcX7޺ ?w*OPTsqfAOYdOǙOR?%dDs * F~PsW-KRncQ~F1')Y{VxrBVNvWipF*3Ҳfx#iJ }To$3B夘WLS[ yqB$5_lf9هkam+ƱN ۺ"9+Cު+x$Y>xX21TnZ;w?b_dƹ뿂7wnY*<2?4q^ 25臿ُM_W ӱʬ/~Zx@z_'q⪭˛ע_oPZvRV$$!OW%-u5Ȳ;T627ۉ#،K WُW5q8b3Jc"滨Ok0ڰskq<t/p18hGQ=+_\w/JIϷD}>U[f^ uMC.crm@3j^$̏|n#@ic"(ZZ+ WCnaXi> `M I KF?fgPHs9AkWo CUe̒o\C<ŶeۭsvR~^Ǩ6Q&?Փk! ܳوKBa{WQo܂5x;y'j|;LPx"ϭtnQ{ygj~CП*NUFG= ̟j8|l;K5FrzWmm˗$4lA=itZ~=k OD=}n-N~wRvKb0zV=qW]x"6%P[|?}nPQ{"ʵt_fj(bО6V ´_$2QLDrK_20ȬA(g/?LRt\|O?ԟ]|I>g{hx._϶~O?̟]3Fkr}'G._϶~d3^ ğߙ??r}'Eњ?\$m3 ğߙ?.fׁiO.\#m3p=4f/L2tiO.5|G>g/L2t\|??̟]|G>g{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2.fׁiO9G._϶~d\|?̟r\#m7(3^ ߙ?|G>gQp=4f/L2?r}'{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?.fׁiO.\#m3p=4f/L2tiO.5|G>g/L2t\|??̟]|I>g{hx._϶~dO?̟]3Fkr}'G._϶~d3^ ğߙ??r}'Eњ?\$m3 ğߩ?.fׁ'iO.\$m3Ip=4f/?LRt'iO.5|I>g7?L2t\|(V;{""v3t5ۆiQER_*5nsfPʏ##H䳹,'74T\թ,g; ?LG"‹,31n5s5Ϳ",r1t6N0L;cU:԰(m Z6P< z|MS:!: B\: FY^K'  8UU^+o7>B}IJ4yź^gx֘K״ʼn18`+3isxZW7K_Ʊx4COӓMpY}(iW L}b|F6}>[h-`1y8ϵYԢY / n݅>vK)M͜xOlRL-eɂxϯ" y%/m*\"-9;YpC+w@Ӣ-ݒ+;Jsc5K+4RDN>ϥ%ōů(>pm9>Չ6L)(U\ʬVU+ەoیdPyҮEKB$,v늂-ݟ2n׊؆-{rlwݞ__!m?ioYÓ54H2"S=Y,^tY_,ƨIg>zϾvVGBSEv_ ˁ}EeRcGa*GJ#HdfUP>ĖQ.#Jy747 5G:DZX=ɘ#9MpͰsRZ4(˳m[ Fm"9,[]&~^>Ѵ :=z QO2?:KGO$GV1&Ռֵnc]A>ҍ[,oozu,Ј@˧,:P*[ӈJn{Kc}՜&vMN:W<'t  n=M:[qu}ms[568B$q@6<#'f}i.l[hVIxPAZ?nαݥxg} Jf}FdHve1 :\6sG;Fq0w TkdӆڄVԗ0wWqDҬ{%0~jLxaVf _Qƀ3la 9%;mg'O!BkM QB)";rqUf[vHix'@h'6La=~y3 _JYڣA|,3Z`ȷ1kb tx0F08RM1Jyf);*چ]*3?teJćvXpqa[y>2d`:y84[^Koڹ'´Ha{nA>h1 aU#7dndS򩭭$[fMb~PrEh-Y̳琬=‰6^3Krۻ|Pap,h)-`N[̃IDZKrp{ Ypy;4hfBH#d9uphkC- OԷߖݎZ-fdio;$-6?ސ lgT,)`!o>8^6`$RN+RM3tǔ,sTfZ|9lO}@qm59PH 6;F3'zIؔ &Ўi33UCw Kc1zH o:3A*@_JjE,w Ԫ%Jf}%vC02cYsE$KcXfh̋ $Ƶ.a* 11EZ[ [yYil}Iv^NJXUe#?L֭մ1iGLFnLE%,u;VKtsژ,;!YXKw8B$|MfX΋v/7p#j7QhBI#2cssŴDXgA<*F֛*G P3c$YC:38$1LdA1R=1֮ 9v#n* 'Qxr~ z1$=~dO &9#Y[8>pFv\;[D]QYF }2ĢD}2wrzzeq{4~I^O#fдn[o%OZՅ 2H89/ݾ&>Srx.(Ϧ]j);'kݪ'Ö\^%_$׌`kCǯj :;$eؑ2^GJ@Guk[ JO|TveuGmhg=EIssgykl۴M/wP=m7  4ch,,;x2>y*lݳ4yqC7b +&Zb,Ct\$ 8e=["m gE۞:nV~ke@e.$hRA$M5Lqt#Kln,."lF2 B<ԋsJ6-] UnQ(q2B`v"+x.ċ'^Sb2e$_{O;90|83]++_A@&幻K4ebGK/<nnz7[wXPFq`zc?Jo#( $]*k,#09=Mcdby%CV֐kL;pZ Y؟$ (ڥ& G|graY;qCmu25̞R>ݻvZIO:XVObj:\nm9 u[7fH8ݸ^P{Y Y){aܡO$.{^4+0ccisg4ˋKMhǻH Uu5"u pzY[`C#mq2 diXJ5nc H=Ni3m@GOL8i-]-BCvH2a[]G  ?\gKq-E$&*r@^GE*[ @?ME-ݝw6NЫ\VO,aGZkj,HP4)$;r2s֦-Hw Aӏ~dYi.`1{k6Kk Nlabk(f$2r=ԗR.f󌄘cޙ$Z4D{)A?@mFUŴ*[[A:rBg)gs [nCr9.[yY!88hOyVJ٧BZR\;TSs.xF@=(H3kw1UIV7L.ܝDZR[89TIl-Zsoe9g](`gQP2Al.?in }Sg&Tz9݇| NuSB.E+/XfVeJ>WSGd)j]U_\K4f&zϖgsc㑌CTh 2JA*F3Ngv  z Xg RJ'lhX 4Y|=6y=Z4f(R* RK#}ԍ 134fK";ʄI2@֙@hYMom93֫P倱Rt5Q(4f(%YbG#]0Q@jH'YJ7*Hg'YJtPFh њ( y^gqUp8Z4Q@hP䷙eȽQ@ I$f(H >cztPW[Wd*n2`-z~UJy幔3sNUh њ( mfr1O 'x^G?!U4f(3R$$8fE4Q@jqyph3PI'$4wSDQ(Hbޖ96+L$Y9 v*ɥq7BҖ :gp/zf$+HgdT[[#; `~uOr}3@ EPȨW<M()#vFNiPEPQP_>E#*3UO;Sh (Y+`r8"ff,Y$J(((c~^ٜ6(Ve`X3brI9&Dۢlc(~(fos9ǏΡ(*TGq2(!~YI'$QEQEQE9wf07z mPEPJ  GqIE9O9E<)]G+EDYG8f(!BVt X_4"QLojV^gM?IIV'LaV?T'ߑX:$i7eurA]3ltNM7[vjk{] حN"<<$aXiMlE>%ޚz4'ߑc cat%K]dD2m vGGYKgV9B6zqIa-t_awRw İȲ)5ooڇQ@mC_*5smMZmTQI|,=g1r|ey 8'w`>)a4Q>Z4L qNOVh~%2n@:q6Oo"k,l,dmvASɩ-/M`Z5A tM]zdU5^Kgt3E)uL62*#`:fa/6E3"|K?j@mC_*HtOʲqHuE#@&;_CE7?Ss\N y*/5sPz_X-~쮚zS3% +4?D$z^"u[yaOS 'Zt)A(cGAGj>&0\ [~}[ xowhۭ5  kB;+SN|JJ%BxgʗCĭ,V$rO"ʢ +?˜V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇP|#N'kOݯ:Wo=!d}ȥXd}Oݪ? m_k=yH-_>)z&koH<ל¶eTt"ͭωͶ ]T>ݷ]ߥh lb[n<Db%HSm#m#Xc|W=C}#9[UuQr/]W+o_G+o_BCl]h0 NџmVͬ*& O-̇$}_@YU_@YU \KCWC{NOPd7Z̊ۏ)F%vEgU)hYHv>GV/,?*V/,?* _شUush2 W=]W+o_G+o_B@Gcqomy+:$wP(圖\iGj!8a $4lnsڱ[x?[x}sFI''[MpwW'pJYտ:j&<g18?V/,?*xƗˡ Hl203ukO=/8׊+m#m#⩁]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@:G?Wzo{Ҿw/neY$c*|$#MuSB.E+/XfVeJ6~ѦV-#Qrjާ7L{ƽl@u_;8S>٬6oxV o}({}Y\);_O}[ya~RzT)nn.nu+]??3;݂3Ÿkv5rfmV$,O }W-QR$>^OP-jFdSC6s3k4.J .%u=w#HԼmLV2HmGY_)$I<+":z,\`U*qe_x!o5,m6niLe|L pt,zVCޟ çi :'b 7 *Ɵ|f >x^y7u>f?5 ɚkp#ߌڨn-}Qyٙ8H|GYwe-V;Yvu᝸?JLߛPYb!t&y7HgI @-y隂k|DKCrrGU7USyYhIpzA k-Łw2e#,v.^+ kqhLojX0H/u8i!RHR،<uK.mmuq RHY 3 w pܢksiZ+,vc\8z*mSJK/b%u;3vG@';]ÿ׺9Kb#p Y|“q#wpLq>s'5+;rv`P"Eҵn]6եL1Hq1gtTWԭbVfEi'U'<|3$ LI+tϴug1zdGdbl隯eCK=rv$M " 2pWZ]tkZEem=PJq*cXdu qtzA.~s^~hkZ]AwZBZ?27IX}+F/[#Zܹڂ ǯ]ΉuWk5nhDs5iutkgvISEv@J°Z?m:4Wϻnp#KRM,-de'n i<֒n\۫khF${%A8y26y31Dm;1Yri70IgY~ٜgcAimi4qv(@Q$27$ `tJO3]Fo!k(.\eqs%7OL$Y1 4 ȵB.~۶;thAu =,N2FkCwkkrZ%)_(3דtwOq=FĖhA$ q~Gkv6ofUft*#?.y#ޛ-0C*m0.Q[!z;xuROymmRJӲPʗ,j8삧wIn6tXºL&]с԰$ʹ6Gee_ '^.n{yq!C L|Mss$a>Y`̇f֗ūOzG$6*,JdʆGUZtPWXU{yM6KMNy$j7c΄ƫ,vW{k=H'ŕU~݇T{/3T2:䃁QkN[5mNZma>w,Cn=`o,d96-&}V;|Ln->S򅴖7y3H$g`R C}bxY-4- ;\nٷrzfjlNИ`[rq}wQH}WzͻA]$b0)U#-ǽTtGA{=lm\Hc8#j{q]z^< Uhc۳ۧoZK]i= !Bnz Söݣ}NjAMz։pPΟ4NY~ FFCڳt]FKnmM.;+@HlZzhWJ a'`IG0:u]?/#-mvֆ|G4^f|Ql$~sQtZPMyK\!E[`=oj 4>cAS;F6K[#2$2lB0s_b4=B)"X]:\09ni|condȎ!oaX9&눬Go1 mU#q;O@kWO{ty/cH52tV#95=^Mk]>Ucnbbs$dqև˯"jKmn3*Ot#!ԐUNӼ:fq}|pcG^ ZVq3\sT2OnjcKåtV 4Dyy{sin/&im Lpp}=jX/Yl0ֳZx&Η-dxjX]jmm4 GLjZ_Rg{{okZ[/8[q&\afbR9U /Gn:XVv8RqNrGcU4MCH3_ZXihѥ3-Ĝm/林įevt:itKk-"#^W[Aft1[;eʕWf;elKkmy & 2K78.pG>S=?_x-F爴>@,eܱ;8 YAw5bSCk#1m)FU=+O^=dRXz_I;E4=%SzإXpa8vZi$@MCǽ6bW0 0!8&5s'ODm;Kyqjz忡6!t'?BA]r:ω4Cy%\KS>حqo=  < &/?RK<|P@8*Gr jZ|bc] ;Cgv8hg}5?d{ S#in=Y9gѭ^9b6sՇxj[iQK[skn/;O͖TR{^mԚw1^d? kή5wAs*g#liHAZ\]Ϥ_,r <䎔ofGx=cTkةhնBw12p=:[ֵ= 4@]c3` r}}ꗈ<3wu7&k"fm² zkJ^@ZY4WW wc 1~rx:*O`ȭjK|kj݌ oQP((!b gVFi-Y2g8bwn+\\`,mZ dFm<ҵ4+}oY=\Dp~Z^5C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (10T"McSg%=!`H͜H`;jށ{{\# ih%pȘ$9`s3.B4 p9~$s?ܲ4AX'`yX&U=qץAtke읱Ud_p{f4 B]DϦ5N|sC/gS-l!-*0ll.-R{o0?>ľ%Ү<S :s|%۶e/yW>e'1\3ch/?訥Yi,ci $A0H+E_٤D;2}<_+o*G&]..? _(/?&wGm<'<@y>Ee/gb?x?/]^ϲGy>Eq81\Тue/yW ;Pآ@{8G_^ϲGy>Eqwgr,m ۓ"ve/yW>'* [B& hH̼e2}3ii k|_(/?&%ҩc]3ƢON sӚ_(/?RoDO$Go&&2#[^ϲGy>EpG:l_IIdpy̼e2}pJ13%@M@ۍue/yW|}p B48R~O|_(/?=⤑+)6N&1Ah_(/?5b?O?Bl€=̼e2}x숆 s>a _(/?+y]sʡ.}ue/yW? E?/֔x0B8 2}<_+ KEQ;C׏ր7<_(/?q >isϙy>Ee/u>T_yQgƀ6_(/?}Ot,zҏNG_ 2}<_+LC/?̼eSƛ U̼e2}*ޢKx@7y>Ee/˟"3?0(̼e-6[W\?#Zn5vEvzT_RM.KdYsF ?A[ՙzvns;Z7L\bF}8W:叴Vٻ9OZC,Qz[Yi\?#ݫc8u€5vK{({=-S^d?TJu;€6vK{({=-F/T U&W(omǿ Ƴ}`~? Xn; 98d{=-y˵?«^q ?@Noo祿=ɟj8]OP|K | 6K{({=-DxT#')m\t1; 6K{+>$zΟ 2EF({=-mǿ¹MLMPg@voo祿=j@s"sV({=-mǿ¸=`GtuWgٺ6K{({=-?Z;_zqvc@z[FoyCDFضG?{oo祿=S'LupE@z[FoyS$ۃ\U%kOLGhնK{({=-0EwDb%Πo> J Czoo祿=O*H"#5$8ݷ 6K{+-O@bRDyzwDdvea~Z\ _>!| W^ƺGx7z6K{({=-?ƺ̝Z :{V~{=-mǿ¼vh 8#aex{noo祿=#ȎUf/$r2C>*=mǿ ߣ5|@-?@z[Foy<_5o{DƴuXugbNsP]t;L]g%19m7=Y2r)d;H$ ֶ]v(HV^J?پNEݿy}I^i"ּJI ,MJJ݋>sV_%H"nmb*Rff;U c=@rJxO` ʞȐ!'&3gKrɽ ]*@( )2)d ^v(2s{֎6VV&QޭNdhUҤ`QA*ta?R;@ 50Uێ!SZ@֗`Ċ1 P֡aqҧ-wzvo~w.Gҡ`H+* QgQK93l;E#H(}h7@9awm$giÂ0h)+& $\ɠ0>>K*еet5Vx\LQzBɹT=klR.8Sk@Xk RV3P <,ou#ctnE>͙ jrɤ*FXS#= A"HH?]$GҴcYNqSVZMq@S3[ɺBqO@'W484"WRjϚ(ZNk\?utr_CLKtwRE! Ea\j2YC*]d@5LŘiȻD WbE$0o5?~b_vii MtҬyE&oдڸsnsBVdMUE:8ʿLJnZElJZElJ "Yv(3 ?پYz{7Ҁ)ȷ{;װZȷ{CbZtg' ocZ[HP}M1 qTe|MJpD 1T3ʨ R2=rxwjn)犱i*ɒX؁ 3ĴSqkq׊:qVdlWAҶګLU@:PÞjI$Ue'ԞhHB D)&l>CnI tFhk`~yRmU r}hxvK#Jvָ1|DsPLXkkd֕NӀ?ZAi.@УGFqY+vh""9+*#4194|1;V[yNћnEiJ9}ZBn6VT51ں-.9bJ€:RFUHqWs3@<ԇ!@3M'#P83FqE1 $f+A>5Ju4>Rva c0+;zPn}:ߒ1ND $fHzwgIT!:9RHgި@fK֭^x&YlGXwүF01zUheN8=1@PĔ(OA6q@N`|iZr3[> mH5glZ^Om\u _EgLkLk9 a[Cv_#O՗tFgڠGHU<}*l ☊NzgZsYwnZ`; (M瑚HB T6#w'ˌ?w/-3d^gkVնqY5 #pa܊]ïUdRR0WoCYcpB@*(yY"S.:v+"87) P\Nu5N\HoWp(qm2[0wKlJTb hBЬUYoӌRidm$TdV3s5VVI_85$nȮbfʮ( m),2k/JʹS5w;)pil;aV0ۦ@ěT+Tbbu0zgie y<%= r 5 `Q j9B{ktmZ2k*—7=ekAǺ+ekAǺ*(e(+/XfVeJi"ּ~떟-^krv~*RaSQe'CkpcLj k8N{U S+bFU-QWL x5S&ݚv TDY R+ j&G1Z?*\wOy#w59fd͌-S\ J9=h$MI?w[x#Ui,<օg$U!Bu=83ހdQ"zzT8m9J\ r6Pq]RBc>L6QAiiW5!KΟwP^Oɨ!ϖ3EI@ sT$7?7%Jr n~T'cҜshOENO4O^;S9݀< Ļ͗*y) ͑-TRֆN3LE"{=p oaI:Uy:Uu<=Jz~`DQB#86lbQTNInM)$һҕ昄 #8Vyv2,#ߩ} Urs5}[qtҀ2u4կ+kdKPQ@!I:YY\KxmQ1PNȼ&BMWBMRg&㞴rGsڠ03ۜ<O"[ #gai'+ky=*iFf) i#nrGJhKpzDžNqҡL;/RS8jN ! hJ{ B*, ˵y]"#@-S ꒁKb @ nO2(@p3ަ"WPZ2I"3[vAfRj]OC&gr(*d&-׃+Jx̗`"`41u⹋T^$[u=DP-#;|͒)КXTSG(~du0=4KIc Fh qϥWPI]jL#'4T\(N h]']JJ*X #RU_ڳX@s:Ӣ* Tq7<{ȭvǚ'^:`,#<ʴ4'/qʿLJuZElJVElJ "Yv(3 ?پYz{7Ҁ)ȷ{`K潲EݿyI y=⧄nNGndcQq)tL`ʦqQ8F(hAQȸ:DH֥hPBV\*xbI4𱃒jެ\ it.kR 𪮅Te,1ґ@IG0 Ww&`A'h*`<Lv(Ŭ,dU{midqD,I9^HB:``˰ qS%hhsN,Us}))$KpFNF}|Kc~}T7rXz҂EA,߃R)٨ejIlMcL2v1EyzuTs@ƥв69wndFcePNi;SZRJ>v-L%'i l5UU{q@֢zc<֍m,x ͹rj5+o,N܊Ηk="D' {#:,n1ޮGdLp G>2հ#$EJF_#P6>ЩI4w9gr.ֵ4ȁ]A0!FUmdXi8L54:3 RNA=1J'5\K*L(e3OU ʒ$I-)Wq@ oZzz;Xu y=iBNԊC=!qtVf>#8Oeb;c{х$K|Z~H@ ҢJp @.TҦV}(Wqǥ!^@4/z*`$P3߁ދhۜSV|S-۱?hJZejf##oNSy}i̿+61L䷠ ׈K 6EfnTMY$?+@"e#ʓ[n*Tc9x^5*Qo0Ji.ư}@"&ֵ-pIPS {VLYOP گ:֔RfS(/qkNYm8<ۜWcLF8"<RYR9z":֥|YZ;֟B=)/ %sT:1/sKj4, WpW ^k*Op{sۚ.<$NHpN2TTPJ&(݁5_&GWַsZZ欥F9rgQF)`A^:TLwg#(vRz**=nATWSUz,|r?Z OSҚdO= fAҢAɩFGҀ2.*=WNV @=8Hb& |c$Z]ͫo٘Df/=\u _EwLoX:gO+x9nCv_#FLEF}) p(bmSzb!u'<A9'4 w&)Y'5]`3ڀҞ3g?6?ӵNUOz993aIJSU'AOop#ʼc@DM^ *k nwf'( lPBYUr\4R`gSgv$4bf;֋^b s@7u8j☤zT$QC fegmҴ.`dOmL8]$0/`c8\S%` 3̴vm|mF1ިjVP3M0qjq"s@hJ֝P=0gJ\3V. eA@vG&/Q94UV>=ħqozS+F8rk.IO5~"uPOcZIgZRL'J@A+P珚c,m\w@'ڛ)I;sEMrwoY[i9 dcBҪc.+Z銩`H2nj;f$jnNds֤2.ƀ:|bcFlj}{VmtI 53T5 vjs* \<@;Au'GZј=krZ<zaҀ+4 /Nz<ZF8G5$s4K{P|],qX\֍@wh$ XqIsJo(<(Մ@o'ڶ3wtF!Iuw$ڙmwVa+ٮBcgW?X1$Ljgj%,dҸט}?@!Rv'dbRMAutIY26qvM>%ڸ` QӵL)s}~pHqf_i~sSL8 AavB2UuShuN;,Nk> ddʑVDH[~4䓚= C@/sV\cު[W#9LOJ S {q\|Y6Zռ!#=q-9789ۏ;֍5߈#cZ.K0I7mN3Vem%<涤PT;qhydah$sT5|oF%=*cChr{Բ͜~ 5ve w(AzŹP6c5<+ZEɠ n@&q(Q'\ܩsۚ殴ʼn[VR F}+RH5oOʃ< *KUN3֬,sV4؀79" 6}}*$O@gXNm1:@_Ȗ~E3E,5Jo}.C$`x۱4ԥ跷Ue*ck7IZfM#[x<Ȋ5O) z4Jh̙*yܶaVˆzw{P֝$~Ճ" w[G_ށ0UnLbpE<3ݳ?UUawxx4úP9/Do?Q"}k!K5N-f19=Or&b8 3ܫDFy5gGҳ-5 Z: , -^ z=5rz;:]oVjH|#j/_O+xA[Asw>kZ$kj??ʐd?3Qd|1 I8*1+&?-)#+JzƱi".|~R9<.-˗n*6vA+s]~O p1h?>5YnJ+#to[]xoG&0qL$z)jaF=kz/V7/٭.2܀7s[f/ݑkP6v5rzx,85o;۵t:SXOր,BD2ZҘ>VbFJ\HF(;6%oW[MyZ}=(Ηd'Ve d[R<{T24z([qT!RL#Ԣ1OXs0.TU{p#f"hpE>b[gcj '\H 0dp=*I4䌝 st 7>гǂ3e Þ( NN8I:{S+œUh.Gb4LY3H@gA:4`PJEfjkַi2GweEqi UT8$סAF`+'Pd¨rL|Zii.W;H@ZPc9gY u,G=Mmx~ԂB8YW_EX??VΛc"+gMuUSQ~7˴QEYV^J?پNEݿy\k-?[׋OxGLCfNJÓQgdɂ2i%̠iIlsjvZoA (l1[i Q ڼjED0ƹ^آPǎqר`р~:WWn}iyanx~VɖP)U$ր*ߨM7N$PV-O5=鶯jyQU`ι9 %p $㧥=TaJfHAҀ!V[Ji Gn*I4QC)WF;T{]J\*=hV&_29p:\y(TMak5aOY1\8F\yA@l]D]Mr7`oAr)@ rT({UT(#h S[$*Dm9VVE3EhDӊnQ[V&,'tg@L~'ŷSZ܁Ij~_PG59FLI|Eo;uZq 220*tHr+ iCݰRvzY AZk)VwM8O-$dU)lRBI5:\FGozyR\J;RKz3oVɠ5=#OO㊍Y~krRFBk鶫N\$0{{e1H]L;UON./ #j_:`*[s Xi F{D'Y Hbq9Rr3[n`g4݁ kc=bkno?JkvhT@@K*A +1$u˭RYῷKyvź~h*潧Ϫmc ,Ϋ33|`u#ƨ͖caq;y[ndtDt] {R^c{_l|Cwcwi[; rqӟjc-JVo.];R 6du*G`Q۠=˲3[M^H XʲkH_\mKv^ `C ?F_ ?vtVrFxa U ab|CmuHg<j ۸#Uie>[N9.J3ɮZ9LWlZәnԓҀ:WӄUz dV:E-ԥw;sEqA ?)(-&Ҩ{D_1(w/ KcEoijQ͓ЅV^\h孵I#",p0}@L}RK"$x&4exsPTfP[Wkct1(l}R^Æm&K$w;xX4{mRI÷8lc8NtHYM;8f9 `tB33p}]]Ks$WrH >R;w2 nzLJPA@P^&r`cS"?J ;JNqZŁL'CZ/%7'=]wCpHJnYXBS4 wZ~גsYYyo}aT֥>ko#[ֶ2*(6!f  @:WIr| +o5؁ހ"e7Etv䭋}5DvXZ Knk5F&lJ&ͳT#v0̢F2r*R?z*MHn@}igRjGX ׻*!QA6HnFTWНh;e;rqxNzHڲu Y`Pk%ȸܪp tVQjpw3@5=E!=k8yqq4Z#\ӽ\$栁p5nϯzAe8&AȪB1=E6B3KkXLFkR4 3@"FnJY2NkH1c#өWH>@Ug<֤p f0Ry@o|Nrk>tqV߈5&(cs 9 |z C g8ʤ]DV 4`wGcrR]ֈQ;c=Me^[= 84)Psgݰ =WNM8Sր$SJ Q4cIy;EuÃR,`"D•*`(<X{V f1Yq:ze" d #mqiޫ\BRA)TcaԶY#kKrUrGOifU6sjMZJ~TҠr4ێOݛHqTL@jnт5o I5-߽'ִoc (N--T\9!X$bSq6PۜqY2ٺj_:b{7q@ݿڭH^+OC1>U>Ze{{/^{D'Y-kR;aޗ:XnEt}P^+}3kxd18l >x@w *WE \j־z[ ^<(9aԯno--%IXX|w4W>#|̭僷'zSƌXψ㕲0 珖9E$ThuG\u;\xC5}掃KoX:_O+x9nCv_#X_e9MnnkllbJC9= nVR̅9=+dmTiĊ3-Z֋:VM7\浬/pMg`mgzU[<.z&)qV5^m5ܷV"* }֨[iI+qZ;13ɠ zvy wEAY'r~ojkZU$.*qEA m[ wx9']NQgP[vVG*OEK=.96:%1o8t|Aԥ\,V]췓W8=2:-@*\8a彄g\M@nݎ3ZmMeRF>و@wAҮ^G, d+Ffi+ @O Ս@F{`VuZ(siOxzgӸE=jEI>o$+ VUx$s3裎i z9JK[hM6lyF8VD}v**MH|O“RNN1$Z=+ZS zk*{2*>bYFk5O34xEr9p(X&YRAiƻMM,aY(]ER1[M H{gjvuڀ+_) *DX4 ج'4Q^-]t#AbM-szIKg(dbZēF[4h Sj@0 2B>ڃf@J~sjپ_`GP+&vl\dŌvGZn(qڟ kX@-&Wzf{Uy.^FӊmMX:ktơu]<*Ż[ۮ*FqҀ:+ddEszeaگjl`{W#$\P!A 9e#4˘#C2P? @e֫\Zȷ{'֒-YJ59vU $ 1LDSV=iJWHTy 5bsxcұ{v|aȔp1*ĹVR!Eb.j9-=3C#'#@#{OZ=[V&$?9Uj Dv < 3INsVC!qǵ,_WY@ة[wXPNι )4>zz5iJ~{Vvv;}^,c^\I6T |&Cu5.b򲜁F]'/Z+_ÚFfQV/m s֩0TַA> c3T#-5Ϊ1Xv 26&1g3Lpk[)>+XZV Ļ}(6VM¯H(# d]=zջ"Wk-\*;V s@㩧oM!K.HQppZ2?eDHAZ16@`ʼ*sx3d\C%9֌vnzTc@G֧{0>ZE[u7\<okù8 [^6P:U^;( 'ܹ'.K+'#Ykg,ii>ߚA1Jnc$H$f\Nl t1HSsg;=hg7#sӇOhcS?jT0sW``'aPzS4lac+w. \[],88]YLcGZh±c֒5Ǧk3DzA;O=(}/ghC`dk3P8yŘYz͝w-@s'$20$+Wt7G4h#8D#nDGB94-}k"}CBzć:ѿtݬ/?~t7{!/?,P[g1[ݗv'Y9?JC8U;XdQ=iחEbqU.SޘZ[so0qѽ#2U3q@Ƥ{bָBK71ȿ.z]YHEj@IU0MbC9 KzPX 1VHsҲ^*F{Plo8S uUWUa$m@IE ]cj)nRxF2I iF-rɭ4B8TQ6Кd{rw4%H$xVqEOFxC)8Yr zP,B jIȳ 8\N^N@e*h[8vA3({է&*!bɼ}hG9l<Üjy1P*x NrץO9FEK8\\$yֱ}VsۻzVT9'w@ 4GuK c G">ST'Fv8 aDlǥCm:8i k&Cs֧yG5YYc]́j^#=hs;)u#WYSIC7c@RUU,DfjָV&pu)c(FԕԆ8sR`"@j´PsrkKPn P;1lE2_YL3*÷nZ h>Gs:;ol]-(NLs[B+K#= lPR\g/X ,ԳohPZui#8+8eAֳa#/s\DWl[\܎9kK}죧#uph{HZ<)EUkRkc,Jap}=iZȡqTPȓ|^ +wj$TbIL\/'8aof@c.ɴUF7NQڀ&ѐ*֛n#ĝj䜃[#*—7= ȩ{'+kMuV)ROV֛*o՗h0c=Zdz}(q׻Z +n?o^{qqۓI &fD'^RD95^OnL sY`ym)拉U`%e gzlFH'eڣd\e~cWd9I&4Q63ָv#q޴u2VL+6I+zu[TQRO5oP [ݫ=yZWn֦.Ͻf2"6qnhl p>ar)CgprE]yZWqޥyPqhFzS`GXgyjrcq{r`I$PMLֽ se'z> ]¤Rs*nF9|Pbe'ׇ$a+Vف@ u*nWvf.y4}7E}7zT6rOYnuP*#$qZKf&Z#GF&nOޠ  ry/ N]W{H^֌,( n;Tπ1`d*jE#ր%tayYb95d?7nzUwId6:|iN}hy`I#Zܳ dcXaH+HڽHL\n/OTǼا>&)$!e=0-]D/+bF.WXiF h UGTnHHԚӇGR )"4@t9`t7j~1[" qY:y[\ 'Ono_,URaTygtZn#6ߛjK/: Vņ< LG1"yNb'm Yɋv9R#]b紒Lp+ӧFb(Ib K4x.@ )y\z_6Y0kI/Li$(0(l&8ł ҴuU 0+InRv+CHyGQrj@Я:Sd-HJXM2T=EHwPLX(!88?R9xy=S+sX1<@la.eV]?*DZ\X33[ 1k?Kbbx"?tNy NFMJe "ǚGJgA n~I7K R@^FK`d$qθE\R?;$ 7^yjE]s]GuTFy\JI'z,$<֏j>0Ns@5ݐ*c魸XR 硠 ymZZ@dg'UXle֧.wI[ĩ9 -g Ur+O#tWAzć:ѱuݬ /?~t7{!/?;[3Rni߃ҐX*m Hq@1* 'kFoٛ=g~;.Y`*irqqoG\W9xy5(!Fz[H =qN¥E+)+Huw|pQ &#m)$#ޣ<Ϩ-(0{t<d-og+ ^HSG Sc1XƜv9 =P ~5^BzIێ2FC:c֌o=*E(g< 8 m\s1T"#)O2M:1Z '@%#ٌfܗXK.qPňPB"LDH z m`T;ZtvMgJͻM6,BZڱXFlv^i<€`Wֶ΄; N3W?-*gҪ YU|6!XYsekn&{0FV%=rɳljMmBp@Jy=q\ƯuZZnkڹ'9(8&,agO t';h÷lH3c(݉u i楁2GsҮksO[ogt{CFY8{],eɦY)ӵS.03f1IɆtc_HYdc$S)+ljpj)Db@vDNqQ?[yی\ut\-JShv UK݌(_hq?!G5'ƻ#qXb8Il9ϥC>/]sUx@AJǷI㱫a|) H@ q@Zdl0ߝiJJcW[RJ}x+*—7=TAǺ+TAǺ*(e(+/XfVeJi"ּ~V +-?[גGn4[!ɭ+UV_Ʀxj nS+H*Xj\@I icfpлJ'6W_84Jq"3od$oZ34:Ś \6uU#qfPS@MPA9p*)G):2FoG4 |PZ9y3 PS,I⋹'<ec߅qy6W6NNjls@93ilX#ZlV?j#LBIR@HZ {P18$ )b`I`ր.EIh'UKiGמ|A@nn#dy8tG3PZNCEi:e0<-*HA;~4PXSd`@OJF@90STNc5*1@ $*pJ'5:`'<Ӻޓ*OJc WaaqX4cVS}*bG'Ҁ1aakX! vFy۷Z!sR}I#M ό}8<q4R:U;/՛k5rG"{djRg8PߚQZE'[?7V|$j/zH|#j/__+|>u]F9rCv_#Oտ[TwmaK0!Ґ=$x8☎~Q*g"y0=릖$`W[ʀ#H{gޓzG[Q4DX$sLfQvkZsu v;~fk@G`TqFB72h*~j Nh@ZO|=~;z3&TIcBNOwah_T7-qRҴa (Oy =(4 49Uk$V Bx Eeoć9j[Ҷ$o.UM: SR7 6P7zc71B\ ۳4J+5zո*$z{9H F#5'(*oMSC Y.͎ i N G8Va3tG5:A b]7@c\UA0Ayd$H9Y|h=F]\>*0?ZKqҸYÁ fA{[c.j$r uvfTN xa+b ـv,V*1Vb zU;չ^U/F>GCojj@N/X@TZ;GZMfS&-gkmT~5.-@ʠVVK&kc;۫JdpMiIT'ҏt#uZ| e/u6WcT[7Er ܂~#Ry h,sp/cBlGnrzVlm 0.|]A5ƴ1 SMq?JtҭANW%"|.k.2~q6'J>O'(?Ȣm]]$鴚HK"gY'|OQp:è&Ҩ|H`OQq?EuFj^Eq?GfH5z+ ɮc| .jt9oޮ#+Kvj`ey#yWy| 2?Qp=$j1ϒKךᲿ?Qqq꫸|Lu$#We+<Qp=5IiSM@58e .iF@*eP/We 7/zqԓvr?*uH¼r8 7/=SZi`^a_?‹3nn=E1We 2?|0›Dw,+8euKw[h^oq\RGL*k8FWy| .V͍Z S+It_ڪ<5 خҥ. 7>,B9OQq?EW`\i< >_'(?sH]F W@޹rԱM,cεḣn1E3Pt՗=k`dƟ)/5c ⋁7 sQԗ#5M !TY ,'+ EIM5K6UW d8 YܴW jwIl'W=88޷lfBخwQ`^L ^k7UmDPqVgp 8ZD4:Pe, Ob=sUQdb+*9DSt<Uh7SG8W4hp|m#hdT.2:zҼ3ZJCq(6yڣ5y }h䈩Z}b.sFQ" PMBomSS$:v')q@f-Iv'U{5~B& }UOP3e_Rf_~gײ"_bpײ"_U?W~EUeJԬc=@?['!Eݿq)o9I xSQeA4þ:T[i\(Ơ2r٪wQ4SUsYry5m%q$lx6zԷcZfTP>V̆< Q,H=( IrSB^ WQlSBB@*tɈQyd!UF-$PbvH \bkژH8'4xTA 95VM^P{_Δ)WjAHm tҭYX`4Ez=Fk^ASZRB[vx~!$/ҝ uHsTҽWxj1`| rdP{{WX_>[GrIe#@#ֵ55I/Mo3Cwvo4|1u1˧ oaq+Tظׯ7[)QѴӥ[}xɕjg 5iƖ/EBE[zsZ6~/Lnb.I>?iך4vb *oU;G Snmfu'h ppRA4C1m0šBwv$V go},(2:Q?Rz3^JBא 6[+&,Eޭ\4䖚e14o$``$#UCzilIGGsOO_饏CIHԒm*evxǧiw5;+;+!G`ฝ(6NX\CY,ZAI-f?'& ثq;_~CH>ةb|ޙs^J$*zW>WuOjj$KK QB" I=RjM7SmnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ:] idnv,K0{f; aȒ&Qֹ{-@/)vrۗ#RtkxQv{ҵQ6sh/8"LSigPk l(4f{Z6CN.|5{ 1A&5g4fK}.[:?iLH|Į7=PR[KF1nׯ3+4fiZϩ[C{$I Y2('ҚWMRhlCay#M̍gjzhD[hM\+Nq˹#r8F*oC3Zx~(e'+$R1_a+1K/5%!Blݒ,g>lz_p_efVǫ떶 Rx>3[Pj4JPeWb; ^_}|o H$ )NjH<>Y T,biBg<明Hdj9&glWn8ț챑kE99#vYp}kMMp=hI8hv2~(9$Pw%TXq)aľlR]ia}gUEyWMZʿLJRTEmiJTEmiJ "Yv(3 ?پYz{7Ҁ)ȷ{{ OvzHl{ ;q UGAWI@i6irz:?VPZ idlaZiJpq5AmoS]cD~$KJR2`{RZ׵:GP23@5EUzKHJiGRɁ#'j 0gP'*?ZN^\x Isz/LkvHTRFazҀXq1(%Ozm#85fC' ew YP1="U߫s]Jd^zmyxlp(gz@e=q-l;t#,Eju亗n{PnUar5$xmXixgI$ðw ]>-wD #\д;1URRwEuSl{lf# s[΀0bq #t  ~cx +=ǒ$C#j1V8X+T{LiWI9GۆѸ$&kq" _SB,귏a^D*H;6Z5љ8fd.DrF\#s[?`ԮQ FIbfR1iV&,g`'"aTɠ vn"63dRJcx;Su{qme21%ߵX߽.0N+^}N*`WPv yXeF) oˎ&役涂L|·(FAOgΡ%܏c,sU=*Ȑe$$I۷Nvaţns =:S nc18K,Nn;#k`O4OY \o/e3]ZF+EY"V2\ ĩ9 :C 4sv,s(re{i!7ޮw?f6&ECp_;um]ih IMNU+492̓ܺcih6^f$C»Iۥ?/!~&Xßٟjq\w, 1Ϫmnj/l "Ocpwvc?1^iomP((U?aު*8KRV*3譃fV V̷6ݼ6rR~k# Т_I avG99 .yn yK6<ȹ;Pq@[m"C#H C<6G,$cC,6Hbrc_jM綽e-`zFGh~a0hSP~U0KmZX.SB00@zZc3]WS.'ifN#%xN=jH5"}G$r_xBH9qڴ/<7g^00;*ĺ=l +;XăKO÷ԯTci&v2D( $.wViI?,_;N8e4pmL0g܁P/!#gE`Cx4.%j r@deQg#ޱ!;ETS}$Fbvt&rq KB+mtV6W wSnt8cےDP r8Sh!뚼(%:=_pluOuR{%[C+#H'%A{ qֶ",H$KFe!W9bIa)<ۆ|={^ϧڄ?8ZF`%Fr@ gֺkq:y4*I韺F?#_޿F gSOW{k[(8ڒYgsk:q$/WsǾ-c54楨Gh 2/P<8LᢙCP2khm݂BXRWF]-yeZxHm-.~wHI 9k_\m-] #nHQM@Ӥ1TD+o>^v=H`ҭѡH`%+##=Ԃ? u9VԵ.ovjr^m V9SougmB9˛hVه*6=Iq[3V ^"TzI X,VByS=sGz}hXv%Nr1x;/lĈ?Ҟ@p\qݼ<eEv,œ~\x44[ {zH6IgąϰzD΢a$ P{, 30e@ǽ?ÿi5;tm 8T`@"FJtӭc#+ c9GқaiO #H펙f$΄3s;a$9㨨om,omXL,j@`Pmiֻ pd $nܒē6oiwhEW,ۛr{HoTAcEgo+w#I"3&ԗo bH':Gĺ_k,!c7}۲C|/pz֖!;7dH\s"9j|d1m٘8y-uRxѤxt[Y]0R[Qvz⡖RҮeGF2"q؛ȓ1  pi@WP,C(Įy-;s յ)5[k Aj,Oߙ:㏭Vuilo :$oHqq5\iVWS`mʳ3$(P qHoƗzdΊxT YÌ898zS_୰[e#@@1mֿ%KUvy>сYx\.5'O-%yn`F[.TPI O3X^50Kfce>A~٣^792h?1 7ϐ*@RX/eU,Gi΃Qh彖X^HNG:sR-|I]X ӣD8'?J>~ٳ#֩h:vsܠ3H $AK~L'N`x7nn\O!FwʓIyJX9Þ:t4־aĻĘY!p0;I|Tie)-om;GZ?%}IlH:2ߎIZmUi#gf(_MD ʙxLecmʣq8+N[+yRH*#F0({i57+yİ+!6IQ]kmp,"8bFC)lg9ϵmǣFlR쪬K+N0wK'-1/+$vO 5LJtⶇPgلE+ݷvs1zѯ濵 \nP:WO\YHE p2qۚ't|N<eԫœ79=sVm4{;.!A *"n?}?$rY ߁<*-WV$6m!A9usV]5!# p8>v]o@XrO.ulS̲Y&II,b95xe>{l [T1 9=xҺk8,<;W$'=l%8İ;lAuU,Bn~u`U-msٹʐ0 yҟ%-Xuh6XcIeo-sy849# ~U\qBmv-MQz~y[0f5F36"ZG lȎH˝`}Si3İnƑIܪIQ׌dbAERQEQEQEQEV/ROcxE=SMx?iɹjP7[ztm2iX[ːSx'CcwH9ڝhASctOj7`hIVL%#JK$V$ZE׊͉w0֭Ls@O33mj!\ԖhR ӓU Doޜ Os61k+(-d ksҹ' ۈsҀ35YTPZF@ݎ ӳIp{֚: ξt iT|뱑ki" w ^ xzE8?[Zw{ұ_E8?[Zw{ҪˆV]*²ojV^ v-^k[֟-^kywNgj6`b3kf2G1嘟V5N\XI}:;vE8qއ ctj\b9\җA&ixMuxE'\\zp:]cRKιb(r ؁Һ Yl \wxh07w@I.$R1FN 9/6udK4papcjm\FNFo=moyrn.Q?y+9my"@_kP}Wijne_Jc-#3 :Nkܿejzr?kFai- ] ӐxGK_M>}YI<l_vuku%U; _"dO(mn_Ω֢BI?:7/HbI?:7/@ E&ܿsXKKĈƻCeXp>_Ķ>mݬ7S쪑 Eo^%#k86F& VQi- .FN1 Aywojj:Eymo*ܑɘ9 Wwnpl;{[ۋ v$ VkQiQU>Mѹ?:-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-qv^5[ʌCm*3|U8Srx~u-j&uP+G!~U :ѵuF˲\$5fP{1_(}@]WY$X7Wg=Gw;˻k3 哟m]]/%]9B_SGOu$׵G`5H+E)b7ֵ5h8fM/%ڠ`XA뻭A~/ಎ[e[q <:'ohW1ۣ0ZjXrI5~GnZ8 @-f~;2;Bpe<"fteHyudx/nmB![ <[oom?V\EcknW:ݳ=K9<R\Qb+V,L[]Y9#=FOk4>td7k*<5dVn=ĎG*A^q1(^~_vjW5!l N+*#XW֫|krQvy< [VR7$ \T=McH[eu@C9 dU7c+yRȋ w{V-Ɩy^Y^I#nf8=ImReTy4Ms+裰}V3v6\`)-<6\uF̍qں>2!z #}*;,?5)Lր3|y*#j82hk}4ȉުFяsQ]O^+c;sk:r$kBJc)lPTEmiJǸO+ sW>Q[w{Ҫ IQ&v( +/XfVeJi"ּnU8dn?o^8J`k,9x-|t01 qJ*NT=)U 8 'a֙(0zP}ācX=ϥQo.~:b݅@ .|*dIt~+rh5;/s^{^ dk\mr7s %$gր c ҕ:Hm*Y0H?Hty$' OruZ7\=?L_iAȣ_L@ey?+ b<#w) wf(*vrxF8iM\_ʦs]j@Mhe@B*-<+9mb#6,PĺMxV.L(lyl7mY v_v*wc6Rzyu36ج\f~;{/zdob=q쿙끟.Biz:,==mngcgF?Ͷ+#a R\sދbob=q쿙끑mngcg|/E=9\&?Ͷ+#a6ج\f~;{/zgSkIӁҋSob=q쿙끑mngcg|gOqE紷mY v_gdz7l33>AdW*sҋRob=q쿙끑mngcg|?=S+8`lVG3v?{=p27mY v_ϔFỊ0`lVG3v?{=p27mY v_ϗˀڡk gdz7l33#}ݰoe\ 4[ʭPS(\?Ͷ+#a6ج\f~;{/zgO-Yr\?Ͷ+#a6ج\f~;{/zg(֧eՏ&mngcgF?Ͷ+#ad8F7uvEpgdz7l33#}ݰoe\ N)n{`-lVG3v?{=p27mY v_ϑ]Z8;*w)'ҋeob=q쿙끑mngcg|AUoW99HN1E秷mY v_gdz7l33>V`[8ҹU 8s[6ج\f~;{/zdob=q쿙끟xsag$`}ݰoe\ lVG3v?{=p3$]Nشēҋvob=q쿙끑mngcg|Z7'jЎ Q`-lVG3v?{=p27mY v_ϒ1).浬f3(RyX.z+}ݰoe\ lVG3v?{=p3m=c8$cҋαmngcgF?Ͷ+#aaGE*8sob=q쿙끑mngcgyb@{R`7mY v_gdz7l338$ Ҡe;w +}ݰoe\ lVG3v?{=p3ɼ;1jH̿ }ݰoe\ lVG3v?{=p3pC`W|ᷓENgdz7l33#}ݰoe\ Fz5Y[=h\6ج\f~;{/zdob=q쿙끞c#i$HG ƋαmngcgF?Ͷ+#a ZIsob=q쿙끑mngcgy8($R#j`շmY v_gdz7l33<{S $J,;&?Ͷ+#a6ج\f~;{/zghJ_#pX.vlVG3v?{=p27mY v_ ɂzN$j#"mngcgF?Ͷ+#a|^ژW- }ݰoe\ lVG3v?{=p3v A;6Ӂ\6ج\f~;{/zdob=q쿙끟0x &ޕN;Yob=q쿙끑mngcg|u,q\TUQ` lVG3v?{=p27mY v_φF gڳ^7G`#}ݰoe\ lVG3v?{=p3󗕒HsҧS*g,>ob=q쿙끑mngcg~޴g߂Kvs6ج\f~;{/zdob=q쿙끟 ӓ9VlX.{k}ݰoe\ lVG3v?{=p37F9q4X.{k}ݰoe\ lVG3v?{=p3\HpN XKTOE7mY v_gdz7l33>MHvJ `R=jR( ^0Ō~gikt-E$U+2:;0`wc1=~΃:R$3&⓸mtv[=O^99{S߂<縈z m6Ҹ//r3]}j`I 93V[?9 V$zg5V ^8kͅY@_P.sZ7AT k0q[vaְHŒwmnr={s@*3m= IޑA M#88;Eă-kWUFǥdBwphaztT5IAmf)`zV}nkf ``o@< (%PM`g/uE9/!\P3il7[@dө4<,}]!>PPj`0y=LZ8 SG50()t5~ R9/E5"9HO>ԱiRygwS\}Ѽ1(;?W7Pۣ(-%Vzy USy^=zERCb GITZlLEGVJB .1UYthXvI\ |QGNw7TS?\S;^0f,݀+^ zZd^d>=kqce^Nq0G*\aGjuYFeL?v3ڪd@$ .q@ |Xq"5~OIVq(}2}qN.'5]J=hfUyW(d'Zsl׊)!d0TټVeT |Q@ hYGEe_.nTnب@nFppa/:8FaYz$ڰ.Z`sjvcO[y fS>!bԖ.N:V@钦7Gn\xN#n=z 6j3r7"+.y6%ݷSנO?~g_¯?C!k#z/X™ Nq ة_&mAcZ10?JC \»|H'.d4-S(u^kk=G֠҉01Y n7@H X>ںq?WgG?'mu? }ksuo#?V# qW2wB29^'ndU&fƀ9:]֠17'uÓһkoVE5\'8b K]=h}!<qjs؛Es[ұTW)/ŻtL":UǺ+3QC28Ǻ)!hb #/Z4#0hMfO;oAG$M&x($ =cGϟ]ϟ]ϟ]ϟ]ϟ]9J|H 롘H毁 P%A銱Osr!RFXw&[\P}!0+HyTknUX"UɎ{PDp=ǥGA;AO!}Ki1m#ڀ6<TT?*UH@SU->g9_^Vx{U¿'z{Qy$]u@rN+NH<(ݸu+TzzӞprsI Ą @99& j.jE2˞+rT!DB܎jP%yMɮ?Zc&E@!BN[BGST% 'y +$E> m\ K¬ o>d LÐbuvJմ+OeiiKBX={Uk jO͜SQ]!l?*?u柕vٰtQEq:Oʏcy]l?f@α_PbͰub[hY"D^jke1*&}(/UE.V54'rVjҀ3րe||L 9,fV'S\ -I44Y*JЅ5#SZ,N?dM:S$?ussU.W jřD8>ٛg#ұnHaCjGZ˸g*F^yTkbK@:Еx\ډsڜ)=[o$(d(P98bϦj VGNv N} [.9 R@">6s=Z `aPh^3 uOYN1@ lRyEH`{$`H杝Ãڀ!*59')&9@"JZ7ɧƥ^[⵶vTjS8# P6sǭ%D603Z T'8T'jIcڀN7qFp֑9#zSd1{2S|ҕp .XR9V:P-aPXZFڧ梈,zn1.cZR =@r _CY2$+켅T眚RHLZdrFrjY-׊D۽gn@7r:Utyv4c慰*YJ`k-$to`@+*0.\{%`;;==i@li8^j9 kJ8r_5|I>wR:toNJҖ[SZnlӣy҅u G&岺 YKsOkM[8FM <vc4LʼҀ.EsZf4ǵVe`OZxWrfzU-Y[#?Zɞoܳg[v#'(fҮ$Qsr+ jW-pCzZX`c*ӌl7Ɍ6j8p1YCZ 3 4,13Ϧ(;N%,85|s.K6JT*< RFO^9.z6٩ zMCВNJ3P':WOh} s:$p*q1bzT35.Bd!'qVu+穨 vZxp(S$Ʋ c%zۻx⁏8r gf2rnAk^`Edjv$F@~Oǥfd2dtf%Fa]Fw7H29$i :zg%2NEAod7sVnH9 w%lE)[r8=q*~er:boݪ }f8zrO@\UlqڮάT*hLPRT"f#f+sUcC$s@qFz>&p&Xd{ZmFswvnJjO8滉!\~m*@V[W)mtFv3cObUuo]>xn=z 6u*ԧһ(7_S]_tWA>(((((((((((((((((((((((/zg/z۷oZRnϿg ^n*]l8וCר](oI &xr5Ā -RgY(srAaS e1,p\g%419Kl 6iF"\y-M(ڧBKےxf5HkA4xG KoKVS$ju((P=}d秽IҸ=*cH l6O9Pޔ*35}cL@ %HzX31U;@< tCL_lz@P BHQǂs}jgm(aZiuˋlv.RZDuM9_*F'4ه}1M4 =*+3~@NLLzM+p+ֹTv_S[$яP\W<`Ȕ߽kHA5u_񚺐NHpȑ'u[ 3L!p+= yd3IOJ!wV|U q4rJ\϶n쟭Za<e<Ĥ׊0x!9Upx%sJ0JU2}hE`tq3۾*E( =ZwEcA m8:yRI`T>{paKb1Y+򱾓H1y9@],㎝*Btu`X8a@d5m8eZg).jp4{ +nJ؁{WUiA`3@ ;[u36' նaDfܪsЛFw]%|pkj4q].\$[o\At69Q@j&JE{pU<|$DA@r8XJaw9Wh}H;f\1E!eθր+T8[Wy$ǖjŴb=(ݫ3 ĎZŰ mC^sh랕[!=bDfQTԢ&(m*yW)mtFv3jgs)mtFv3/ߢ0OD~RJ OvQ}] ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ("U뽟UnݿUjJq+>Q#oF\oZRnϿgL89cI 4h#_jZl *Z g֬JĠsMH' #R}˹2fpŀ'ڀ=Z1ǏAEn+E@})=*v`ڢyq,9\"A)'֛E'5Vi7"ր ?2ROLֈ)JUSPN$ ;S& rpfjJ?գrhArs=cx9@1@YAN @ǯ\ىNgXmbAMM4ao֨\_tDT~{8խob@f Z(4a7$1RI@mʟB:na'ڸT҉ *Kp@5Bl\@MqVZews2:.yϭX{I (a.1kH*HS<{~DTQxϵWa.I#Ҭ!U'z^jlBLH!z !p㊟q a1ְ!i Wh\\FTmaT]JƝ޵QuGk@V5usHu;$Ԛ`gҀ.^\`fKt$.d)ݏAYwFy a@P"ݷhqd[ނL/Z%Gֹg{y v~=$tLS\0y'N:֘Mb*<՘ T1QhK-N+d l.Zrs@ ,mw"smڸisZi-KHM4sZR.&YIoO4,-:ŔR8ݝj`?Dӑӊ,/nMPɶ :\PyS~Mǀiۛ5-@Ӻ=p1YNg5 1@lˎ8~4<ڪN`8 P$n j[k YҤ.Ek鱪FIeHO>92}i.$E+kKNOPyPv"z{S4 ֕ "oLVI"14rۊD,sڠK9.$[P-cU53tpѶ{n7m`}뙲ViCb7 øTNkON,3ޠ#m-!8#uFFc5 υ8Rܾѓ{UU$#ͻ"@TxKph^%q U{pݴd*%v%T2\yvw -4dUe*8odpր.Kq׽d0j7"Qg҇$ –ႄ9+kFP0'fj*DNùjމr6T$(Ӛ׼ɼiȏ9NyRkӜ=Xr+h]c*x Eq:cͮǵr7ZRs2늲 ֙g$jGgTY$ET]kFfq0  ~iifR@ǽt MNcU*ȣgh.Nsy.ȉYiBր/:#+jrIZ, Vm ز`cF @1? N718X*A@]`}j>*\ɻ(ʨxP[v,# v?8ZV(Sϭ\`y-%VRZzZEz\ zTրl`:+~wqgt@Z$DYқ4#}RwfmݱZWRr[qq:y|4y;\\rrx( Xp+ @]=Mtq8 ߚ#h8 +3XLtn0:Մ\B)Mǖƀ6,ry54h3JQ[ W);ރ:V8P$;zf\8sTopb|3ހ5E.qY?)uRͪB9YVMik[^ڀ4MdZǓjqF2h(k+Po/<ҹny99up;x ;#sUVЄsji qր7ʥFR.(n ̄1t卶3p2+9Ȏ=ѶH9xm N\܆d#hC'W^>R=z O6@OauXWA;Y%@8'z˷s3$<}Miɛ{O0ǧ5e+GzR͜AI:f9ZCfLsYtL' a Z ^m56y$q\Y[L*z`PKS\@5x@r[<\:QT6{ǶQloZ9$L'TmUfwǥrʩk a^zִj+hCPZwf}MT>S;O56+Ӡ3PӂGjO1jڹ#ڲbgmTlRjlBxPNьK "+l*8M=t"#M={R^\GD 4۩6D/c$HOWv`ISHp-HqjRq@ KeAcӊBj%΀2[!G8{Y1ްoOO>lvIPt^G$N Pn;N=3UUG5#(9%d0+9v &ɨ")mtFv3D/Q#5R/Szwǿg'_EaW5>EEqRJAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{?5xSݻĪwuw^W}^8>g vUe)lFpxӁI YT"s'1xByt樱(8*EjHT󩐨"/A֑aRH=mߚlI 8uUf@'%^;P9:IR1OGnp7zVO-QPޮŅU8-1UЯ}*BA&h.q*z[!*Qm޵SV;chz{FXw?AUڠw+>cej72G%EizݶR j;띲NҀ*jD8Ia*;/<֮G| @^Kvei*I!nތ:b 7@'4x V`Gֹٖ .I\RYIpqt"Omf-~oZ&$u }vE|y'3b>j.1E"؆ldB3]yG"B294x pAo:K R *3qV1FUbOu`9#ӎ3+ {U{E0(Sju=d] mj3/֪Ag/4q@ڽ$@Jnej UR$@ x$ g֪CkqPIqq)P2_zU;M楲P]-#6'ڲn"(uAZ&+׊]C|2EL41WX=2h0*&Y7F-biVȩ.r HP%$w Q7<էp!+ҢlŌr*yc?3=dRG=(ؕ>7-ZU}OL:89TFeJsRCRt4b#1RI@ JcYEFV$.@Hc'S] hO8{&W4Er)C;FH`R<~A 2Qs$w;K}kǭlr_.94&Sڴci̒kqrPsڀ3n6у?sc$Fq]|J"\$ǻ8++p8VZ߫=+o.}(iJι~dJgl@@;}m3'i؟hAdbL *8@ oբ1YMƵ ^N}<y(7Jy z|C'ր-8pҡzO&,OA{xG&Qm77>٭)b8(=`#8tXx!, !q@al{u2Z p }֫6ph6D [x( tѷ _Q~u:u{lw⋋Pd0`ji6wzeWo |ёOѭ #m۩ZdR>Vg*h Bjr~Pxڀ qLqJyh9p8ccڬ*oJ6R©${K(LIQޢms*ǃGT#μbd=Pba+jf!9n_OTKpz#Fqjw G!~Osڪ /J϶($)5 ?tzԶ?Usz'\FCoPjtBz!$%H4E$2`ڬۄ\8ϥYK2O@jéOlQ =9(,+>QO^a!7AO|ҽ=)mtFv3Z<&]fOgo^=O^9</͝ $E)/+Wer((((((((((((((((((((((() _ꞻ _Ꞁ6%VzF2Oqn*]l8וCר+ $6h IlX:BYT)572 U!oϥ1^Ktrҋ{pK, o}:H=]>Ҷz dQ:s@U$`f%;G Dx!%}x ˰Py:%=&kFŌPpLF*EB}AySɥO) 9 ÒyV@"!ϧzeb⢑ r V/㜚)qƳ8Z $^ct/_AP{=+,xzP7 ri0;ꢱWGD993}3tAw CdIo.X߮?Jѱ#mmU\MY!d<-R٥xʎ2^ ${U]93=Ur;R:cNgʨ t qL$'޷,/5i9f=kn28#4$TA0#XMZ:kAʃYl/OƯZ4nU Y:6@9qp4z] .AmA@j#^Iհ~*u^R,MXYr) Ǹ" c?Ҁ9T}j\6E],VU$(Z:LϭZ4F@U%TiЭivdܑ@59˷`8mvYi!5lP@R[[n8i!i.]zus׀)u $z\50*K.)gP_[]+/h%§h6RZBU#uKr `fHV9y[5t AOZ"Xv J#QYZr܃ֺ#95|dvLIYIek9HNjqݳ@6qc"@`}*]J>PY@qRq_j{s@ ɥu j"GNN@quRMS²;} ZJ*~A$Ur58\ְKt ;9Mi2}(1֠2c@U$|9'OZ!6; jqI39Ö8#4$d $-dիɼ+݆* rKO1쏦*rp# ~S{Vض2m"㟭sȪ h6[$sK3pFq[ְQ~j_׆SנOFb1]ïSŶ׆SנO?~g_¯?xkJ}+|5>EEt袊((((((((((((((((((((((kWkW vUe)lFp|nhdbI W[JWw[)N7u{g3BA)k4X =* Ð3N3 b!v·"GI\ hZzj#!,;w'j`M͓ɩf;S8 2ر#4ʢ<Mv بu .?Ji9i _'x 2p^i$;QJ3K&OA@VNE,tI^S->VWU VSfy7Zu\ƽG&٤3Ҁ"nԩ#漷Y+'zݜ ,&椆_)u ً =9AEsӢ,ナ#XWa<^ v'E*: iz8^\TZBVY@"Ypj{mML]"M`Y.ޝ - 9Z1 ˓ S͞Lگ-U'ڮY8$sNW1֮1 *ʃ|jyXn r*CTo ]% E]J<OAsOĚm!+E2hQ?jq"155`w]07S|9wI phLG[Ұ)cج乸f H'ַtVH7 {U^9^'[vFq1eGJ{x#JXOPfh%̙`*ֆ8bb^zӒ`\ibb5r`Z۸I&(J8|N [Cis 8Gf\ @84rqC8YA:R1׏5Y{ve"6~d+(i@ tHc~5'*՝\$~v8NN1RM AT1=3@&lgT%8' YjH# ."<'@^xB[P~'ry5mXG!\{֍Z ƙ4#+}슂LPWyyfr&GJ."f=sf,FNhll V= +[ [l\ml!׆SנO+~n -#;zz~lU'"/ OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCר7 <^n*]l8וCרZ|RCdaGN*G4 2㰦"ċsUC&UP@aM'^;80< i=zP][`QK0wd4ˈǰ I%T !g'@Y0Ҁ4-\WmXweNF&e]2Tis&3dq)I +[:WB(dX[ ݻf/;m(דPjE@qV?C58^饜VW5$ҙ$,{tu4ήBu8 p:TF9IwhaV8/Whm#:Uǟl=> # F8J)9J95^òVjb{^ l3޳7< DžuK:l{b,$(ާ8*Hk)Kc޵{W6=aڲ-͑[r]xwefZ|AcaW #waY~3b., ]Sgo^=O^9>r85οOxn=z 6u*ԧһ(7_S]_tWA>(((((((((((((((((((((((/zg/z۷oZRnϿg溛vUe)lFpy8\.xl*F;S|LDre qZL Jq8l5]#ڧ$rEsX>)v$Ǟ8~ ly j{m#0BEdG tnN9*8dDC&[=hq\q։G`:L S$w2T`PK:;nNy4CXFynxFjwl䁞J׊[iwk2x5@X;pq5L 2jF0.9P oT3Qy+(s}HYJ8=) $(J{ӷMTܑT&bS4vPDPsIn'$f#3ekZŠ 4kn ֨G v@YۖI(j=|:\F=Evo֞̓@d>#90$HYS;|w&'׊`=}3+v"l1dbcVl,jlG5 L:s,ZhQVn_uzc#nU2H ]$kRyHTl-85rSGSR 0j̤OTs rcbSh;՗?)DqJ(G4Zyx|O=*Քch+>U=kAr=j 8g EeoU鑊g2w /mrwyE*sts&r\*0>#H20]hRJxF5,Oxn=z |Wԭ-nk-#;zz~lU'"/ OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCר06I%Vz]˶@z*~PNOC<ٓe\Fisڀn=4ض`OQW d [ڀ9o&gUT 4RJ? ^@٤a>o*$ @)%3zTjᛧi0Eɠ'޵Xʱ9݂j)Qy>EVk3ր,M44 g֝Jۘc@ rlEj䊪*wXR QN:LFK>; qK֠*X:ր'!CԊULa3 MvA@9}3b=;ӥl& M>,IH[o[Fv3;OBN@/5}ml!׆SנO?~g_¯?xkJ}+|5>EEt袊((((((((((((((((((((((kWkW vUe)lFpx{Wkn*]l8וCר'X;TnX2jܳ(42v|?TAqKj98e٤qpAM,cɩ; f=q@st1&Ʀ{u _,GY9 gޭ `Vw| H1k:kYO$1׭e^ʥ >BMV1r*Kq '3@n:o,1]^xXHX3&r3h<}h}iH%$cj0I8Af !T`#Lr&T9w^;(չQJqb*ziwM Fxӊ3zn[,/ Rshx1X K1l\p!rHCn2x (wiB$sgZl%ֆ/ 2ma |nzX`ÚH8!N3ր: 0-7̓Nء8)oie^JbFs\3#ߜF$dg &ր>9+đT-j*po^2qޮqjYJ3oztۥ׸ ePzX+ր3USZY.rsVev1@%$V,ŇjHrɬ#4moVHczTۘ?EpcIl fBFҤI Tf#`U#}4*dP^G5JkLUcG[kAzmfd;u+=Ԫ s@ ƌ)ǽEEqRJAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{?5xSݻĪwuw^W}^8<,Y#ݿUjJq+>Q/nFWZKXu>6T˵<☆m(ă֮naEP?:׉v ր$A_+֬2yJƀ0ㄫtT9Ks֦d،ǩi]:k5 O;T$3֔Y6%b܏J͕IZ :Q^{q@B#p+/X qR:U멶#q\u< 8 =bvP})$t]9Ȫ'LFiҞ|@ ۶>s4ċ(^jMz%<(sfК P(vg#ڙs~V֯ۀ'9-x6Gau^gMḶۇ# /Z+ v@4mgUӪEߊ܂#Ŭ}0et69_F9N@ϭu0ϵS`L=*բάUzS3ր$ҕTnj{v\I$@ I~xFPaH\]e'jۭtvw?:4WoԂBJkԂX7 uT(\cZ奻ԙpY.4Lj#wa^=Φ#LvWbLP\MNVi 2XcZ5 TGg՗.|#Id Huȹ%k[x(tf _Ej$1}_4#Iֽ9yw%NW<0?Hz*q66AO"ր;Wx۞\<^3ۓƴ]~4җ 9 *$9?H8 fQ" Yq%MFJ=B U'ڀ-^FK *p+>Y5nq('ҭAnqs0P¬gn=S)`sҙn|0r@_҉$Fe#\Ny@yWuqR[Ci8PN}2w+qKn7$iHIFS3Dž2$38jNy"[ ;xE4ˢYz deAJ{ӊ8O-9 =*vzgjruL<*^?5Z QR6ƽݿUjJq+>Qkޒr mgJq׮x=wN\cn^;IV#\(tRsפci֣c@ # gtw.3ޣ'lAyEw~9Æ=j(ƃI-̂R~\GZ`“g_\y(đݍR'vAϩ}kS\?χ1i1949bhW`j a_$g@NLt9+Jc#hsM F@yZ[3M@q۸=FnvN=hӭZ+b9XPB|b?S=Oɮ_ENzⷤP1ߚø0w`'us `)W%H.q%cvKl[(F1@ MxH6?rI¯Bhk8a5cd@&]`Sd*BXԪƹ$7I,5%tΤe Jt"9_U;[vbGsU+&溶UBqڨj6߻@ֽ8[*]9ZtfLqW&Tl@N=+/Ox)KppI@9)M)06*U( x*WLZ63NL٨m<\bUG*GsY ɍҬ/*H"]wG" @ao\=FEr'%ɩ35^I=hE'#)t 5ÒT[X<|5YHD#o(-(;9V*{V鑲եL1@/v5Zm2n޻Ȯ$l>ŵZq}<#@ wYڈFLQ U<(߻ gBᘒka<9n[%kJ? ڈ8SlGmkYBB>}:Pceimx5W?W^Z cS$e])w!ZQ+cխρV` @u=vt @b  }quO'"X0O^jmR%dj,Axɷp͎[Ԧ)S f2mi|cO'ڍIأ*(u$g+UpXjv#vEWYw&Hhf!OczXx5418 ˻u ڳmk=K|K;UhwZNbl`ֳSق8&7]sT.ЏAV>lA`kw<sMmiVfSl,bGq涢U\ b-{5mF-7dcWR<%#cy'Rk22+`w'!249#lޭ[:\T /_@j-$go^=O^9?:exWL -#;zz~lU'" OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCרlk-%Vz,~ؒǿױbݎqYiJ݆/8!FH@B**A: (7 iISO$Ԁ(#ޜ mi.q;fP[9@ w{RY)|) nLvh/%)'#ZԱXu=Vldnku z MJ!aΩFprsFGLo-N\` S QSL7z*<.nm$^MsE0xXKV'ڀ=i1_&yp1\X^FŢ\;׏q@gpYܟzk5HOҀ3b{rp);)^kL@ M'l(q;֚i ad[`XKF@O,P*V閪"IZVG# A0qaKmǎGXw$ā >sj4X@qۺS] k$;P뀡@zBVԢ?FBA5f2,oJȯzXgެ8x4henMtH']֭#4ӟ!F b H**dȘ`GNbBf(:$Z/T?)fJ>q(GwjيD!W!$N7UH=*(-J˼敭g#q_[XJI'ڀ2 џJ$jČCu<@3)eђåu/8 /3yOhnLEkX xN}#<@PҞTxUP ©ɥOp&F#k=?:JܨYU6 zvK,c&zʱp95i;M\IYT+& Te98;r7B*zqUwb ֻ̣$Sq,5  O^&+m)Bɬ{&'"=&&W7JGu[9mG\ּ ǽTU>}j"=9%HFpKʯ$ʬ:[ n:ր;;aPEEqRJ0EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS\=w\=m۷JWw[)N7u{g3qu\oZRnϿgɼ%tB򀬻h27V'bWǽ=˃Rri+:1|jIH#fzP\|ͬj2Sq=j$v⫬^3Ҁ.2~已#5x2:Ⰺ׊U0*79@pYE)4d w4y$vh`1ZʲұGzڎԶVD0oZhsL_.xN=W7(3Zf'ԋuY>^* )8V$qTghʧ6.!Ag+"MA ;XO/ I2s@eܲ>^.V%ҰpyiAI \:ڝH QDȄ1@6 +2'ڹdn5"К{>Zoўl*H}*݌ $rM#؆BqONI@c<7㊜E"(a{b8NEWYNOyfH8+d NJm5J8FS!%I?($ztRڸ4%r݌xsfɢE t#cuH{T C#ሠ:K{FQmmёӥv2۴d9NALBꠌ>EW9C0=kV}@8T2)4LȘXvWTe=Fr2Ih/tf:?OZsbY@Z[E\&AH WjgA@}e[22G85R!$9Us*ۡoOuPT:Tlx*[l9.VG`1\IbsXb{te\MϯJ{a[IaP0+@D VKM$u[+u< cm!sQxPv| [Qiܨ`I=kڹveW$\1;~sҀ!HZ=vՉXռc 65"70 rs+NY" 1ڢ%j%x\_NzD3SנOTھ_NzD3SנJcEO OvQ}\oԧһ(!QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{75x?mpإ$B93P'̤q^nUTxIY3#>mK[܃?{=p3Oo5E7Q!$U @uNնl\fAEmVǮ3w oe\ _{#Ka{_r*?Z'q:[EmVǮ3w oe\ 6+cgcgKAl/y}UMnW8 Wd.m=q~;{/zdmK[܃?{=p2^e a{_yR !}F\xb-]/elz7r v_.m=q~;{/zd~ܿĔD^X5; 16+cgcgFtm33%_{ g̣ú?_t;o֞> ?э6+cgcgFtm33%_{ gRfv>MkGlk՛EmVǮ3w oe\ 6+cgcgKAl/y}/K93? -P^.m=q~;{/zdmK[܃?{=p2^e a{_y(b#F=b ޺tm33#h_Ͷn쿙끒/[ _r3W ~5Y]/elz7r v_.m=q~;{/zd~ܿ"V \zftm33#h_Ͷn쿙끒/[ _r3=#?]+h_Ͷn쿙끑]/elz7r v_z-/$f#} mK[܃?{=p26l\fA/_/9rUz.?t͢6+cgcgFtm33%_{ gvUl'ڸNGf 65M6+cgcgFtm33%_{ g}f,d*AMzh_Ͷn쿙끑]/elz7r v_z-/ RFQ^.m=q~;{/zdmK[܃?{=p2^e a{_y2qIvic5 6+cgcgFtm33%_{ gZ 6;,txWM6+cgcgFtm33%_{ gͶF?_z[vY\& Vtm33#h_Ͷn쿙끒/[ _r3ⷻ7A6˰ԟL=׮6l\fAEmVǮ3w oe\ }^g`ҧ0k[EmVǮ3w oe\ 6+cgcgKAl/y}96N{R.^.m=q~;{/zdmK[܃?{=p2^e a{_yٍCSݲpGmK[܃?{=p26l\fA/_/VMn~3/zdw͵qiJNJt,cӴyH/ze0VMn~?3%Ďb_ZF Mzch8fe'c}=p2iv;O=q/zd,8S81]n`z3_^wcOnǟ_p8k k5q*7㞕iGwKtҞ~?31K @ChTon{쿙끒|wp7'Zu_L7<5W)<8e\ SDaE; 浬Aw'־o x`#ú#u@c==p2_ FI(vq3%V'qRzzWwkɛo[Hvzɣ'84g(((((((((((((((((((((((8e!PqȠ-t[˚duȬg,ywk**#FPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLzo.f4k͒WyiQ> stream xڝZYs6~[xdkf'3ɤrNJ@KTx3}Hl'r _\իl%iJSjǫ:F/y}ҫLdW׷+f _֯zZL߿o_0j,$c"#Px<)k2 w6nWo~ 9MIؘxoj^EBgzW*g\jZ 2^*Q~*3n҅o|(^n5/#)lV6MT)my«^7[-msh㱬(Qvc-إsJnGvUuE;wgkB돧躲C,zwrkS5t8UVJY˓OX>mm>U}؀VCi70(8|qZqɻr"-Ůn7 goG|0}T}˚7{.G|p0wVr튖-qB#tY5Ty}CA¨ 8+5hi2z:MS}(.xrLoeo6aZ&24O,EzEr"[d!&;rjN+׃ ƅk(xҜ2لCF<$:%c)'֣z_yYu|Ah0It6l%p[Cj-ޭ@[ޢ St3L+0Rq2g}/78,`[FP-q8@;!vH3r# w߳'i簰.׍հoF wNr#׮qȱaDd,$EKGwk] H,lqB_=^5|H2ñEȩa 9N2.6Ehnjt'|HB aq0cq6[7]EͫXtK}^#ߕ;.HH( E'')|]9趨2iXt;a% +bŕTMc LVelߖU25% ǸkWt[2I?j3@e8D$*{D=խS֟)/8a.eOaZrxŽ8]QEB$DqzaU|8/F$ Nv'&94@GMpT@E=8ε}_bZ P?r)BP6a [&hˠ.; u_U8VXHCikuC d̂ lSNv ^@lkK e_YRF=#aICMv09_ ,c3tz+>jPz 34yZ\#-X/OC0ԛw=uf4Y+kG|># HedN ncBDHj8e}m%jg8z<1 ?jGhc>˨P9 =:Fh FܽAp,zWŭ3i،4KWE3̎p}V˒QMsi ^0Ozu.߹ BYٷc>C"jh̼&n P3KT!&>?iwϑҁaH6>*0S QG( Ab|~,zT~#^PQ5FI)" քW? bD[j<u[w1,6INxhP=C/r^ n* ЉZ "9c,AǤʀ"JFtyݣ̜K'I6,޽4TdQ ["IũQJݴxm_zU4~/+* MHS*:Ҥh5V"m2\ K@YU^,*W6bJnlz)d<v=S*O=NPe-S !{*mGSlm) C[hp4% o |ɭ}ÿePBb>8mޥ P1o=RS-HF ̥3,JDJSU.x]$\$HٟL1Z`a]ƥ -F`}Mdhb3ؗt涼-Ӓvp5I[ r1r>.7]KGQPpQE)i<\F2},|$mLO}(}CnK-4:[_*9h ߍQ:Ib>1qшTqgt9I@ (̝TVS0kHĽUVq~ԡ̺#)Z1T>>*@FSGQ[']pzψͼE/pa8xXH'k2ha ؿ=L24B= )(D<˧*grOr|z(5 oD"Giv]nmh,˳3`N0";pǺ[@Z(ɓQr?xPɤ0ʍ5RrYXΎN`'(^7<0C!-9L$iH/w] ئBuߟ *]K:3:%lH2$sevgf'~׾b0؎и5E)1#$iM$8lC$h΍5K#!`%𻂼u<tkOBAST; 3kZΔ L\ڐe@quj )@~>JEU9h z!j.8 LZvutFDB"a&*Ha&^]`8`}KL4%q̦[ y J3g4nlI W?=p 2ϸiOwK'9}UCM>^)N*('>`[+(l<i3)N$A#(aVmʱ J9|bd;x˽awĪعLw + @z^C6H"ϑ_gN0,U؃zOCCr̶4~?782gW ~0ٴKMIű"CXfWl* L2AÞ.yvQU =)d{-R~&aŗ#fB׻ &=Tot|X˵{7恱BYCI`d KWiedaX&1nJc"ڐI?Ǒ \HqGoG/Kh,&:IFCj-YS !D3&kzJP+YzxmJ'wEͧk,BI$6` l?>Q6c'X ;щ5x9btJ fbNG29ȁ endstream endobj 68 0 obj << /Type /XObject /Subtype /Image /Width 815 /Height 456 /BitsPerComponent 8 /Length 29832 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100/C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222/" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?qQ{LT|kGUQ%̭%nԟaEvozB::XLG5&Z?&F? ?c1'/r߸.1xQ| A9Mp>я+Lu ~h^?&7h_<cN_G&:q4\cF? {r߸?1׿%/} 1xW?Q A)Eo(я¾y^E} 1xW_k-{R\cF? -wReJ_?"/h_=eJ_?"L K|GQp>я+L K|GQ A).п1xQ| A)?2%7EF? ?c𯞿2%7G&Z#(BhG&Z#(]E_(я¾z\Ek} 1xW_k-s3\cF? -s3eFo/"'h_=eFo/"L|EQp>я+L|Q A.П1xQ| A?2?#7EF? ?c2?#7G&Zgb(BhG&Zgb([_EO(я¾{[_Ek} 1xWk-o31\?cF? -o31eF/"'h_=eF/"L|Qp>я+L|Q A.П1xQ| A?2?#7EF? ?c2?#7G&Zfb(BhG&Zf"(\_EO(я¾{\_Ek} 1xW_k-s3\cF? -sSeJo?"/h_=eJo?"L M|GQp>я+L M|GQ A).п1xQ| A)?2%7EF? ?c𯞿2%7G&Z#(BhG&Z#(]E_(я¾z]Ek} 1xW_k-{R\cF? {RcJ_?"7h_<cJ_G&:q\cF? {R߸?1׿'/} 1xW? A9Mo(я¾y^?&=w4\cF? =w4gRO?&?h_<gROG&z}5 .x_I~kKKY]#]L.ά@E \5>4N;hG"Sȭ9&xĻ-:}+~ L-`rQnu!W/ey;^UQQ N(犱4餸<|/(#`,W!ı#Dr9vεMjLӵyȌ)s4><-6>զK39KEԧTr!B }*F\3=vI{7gɫ_Ӵu[KǟJkfP݇N@D^(ӵ [Mz5齌ٲV<;wEO'tj!9YHUO&m?Lt.&b\ ,{*)ck}sI N$H, FS>wu׶/`) DޓGO#VƭMÖZѼ_oe9f )^2? jtTFy.1FlpGqkLumI&,6@Lz{⠲մ=7 {c6oo2y>n cicA+ E~MFx8{-+I]JGEf7fl$DmU9\KM_Zиa r>կqG_UT1Kb6mn dr6ĶwQ-[YN6΍6:=KY?W.gkzqj };\2|0;֯ԵU;EW` i_ |3}kv; A?@Ls֝WQ줺K9 :O4 z$R]VIivFPvC0O𫺗4ciyΩ*r, O$Ċ>mlev2C[D3ğd^MoŤsIo4fn3ۯr5ֿf{_'WYҵ]$=R-O!OSYzw|&T}j\jr{w0\gi4=i9Dhێ1@5=2KkqnҬD gL ֡q6mn[TF  2wq᚞O \_[Og{r}o1A ۵^O΁5Ң32 t8EgX hᕮ-53{`#/P3fxbSOk}m,.t !Uʷk ۧuhYmς 1㿭H#ЭgmZé`$1#?3)fLIu&Qiװ-գM7瞾:2ƫ ej>{a9%>Fw_fd;|䳛_3`ք1/ci}e,6Ig-B1$w:z+[.v\|=ii o,(895x@.-ضtgR.>},Mxo#ٓx;psi$..ӼU}iiAe3X5h0F1R&7 (Y{#{+Зu-n.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@Z]_]1",oAk-1͌!}B>iעgp'Ў֟dAnr"~4ϟN17ʹ {[qCqia$#׵aI|_QK|ԎshEtIHgkhxzPMV2A0ϖ;3t:~V5O<yWr!=7w:6ۖ1{񭸯aԡTkqUq%([nS9J]/}֞t"ֹտ_mc%J3L3d9?NyouVR 8STs< tNdHPWxUiPV+L[K}+!_Z[K}+!eu\uY)B<U^uIR6<5.p4Q@eWhrKkS?uGPZ{-[G0E]͹pTgf `z*af7RV%}ckny9i-fuY]6{.KF.=~ }@uާg"`$>0?ա%CwCafG'Xk:uztsј`crwuڧѥ+9˂q|9}(;uhlo.ak{Kd̩ `~4kr YHQeן r8<847RXVnHW*BF~@ եeI{^Zsr 63n޵ޑ{g{BeU *8?@RF˛Y`٦Hv .3j7\K;|g&!Fw)dlWvq=#zO+mwυw f+u%ZO3!1!ぁy[uio{4W1_rhcw0ٙl,0t⇠[Vbu  m;HcX UZ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(ۨ )P/)Pf^~TtPIE{W+ԭՊ߇ bJXox7?:Wk^w9cI.;(`qQG`]\7 N&$Ip,FI ܤ (’/i?O7G)/du-_cZ}ͳ[wiϣ-fI R2X"i`;$O\fR^%'%_nu0NO<ֺVo oQpsg/{%_nR^%'%FM/ZUKEe]\)SkWLwP9+V)/dt’/i?O7JC9_*j0mry:"R^%'%_n8·XJmw8T's`5x#=r[[=>g$"?Ix'IwjQǢOd4ub4wxbŃU *='\mY^/X3od@ "Ix'I}@LkX\ŭ6%CXȨzW)/dt’/i?O7I+g/an;8[)K񑸌[j`Ҿm<.]"20\ewqҴ?Ix'I`Z^w3!領]:Kޙ,S+;s׿/ltkf'I#1#Y P3%_nR^%'0W.$ub-9+|?gxJ..vp&q?ƺ>)IĈr~F2 XMKZ! FU \i3kBCmZgXDq\" WW KĿ?K?ObL3]1^(Z+V%tjcDմ[l3,8Rfv ǧsZ_K?O KĿ? \i̴-3÷ ٥YB y*?kԥT6A$Ѯ1$?*i~kh-t0|w|yIx'y?|Ekk5e"Fv , UkeWzjpx$sڕzy_K?O KĿ?Q'^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?OAA6 +ob2 [Wh\%K) =IV)տԷҼYu#n+_-[i;-ӂ^op4t$,XDp,8z-36-< aqH4oYDY)'Y (RMh-tXrBXYl$kKr"GZ,.SFkMkaq/89'iS<)~UJ1 8v"77^o;9,o#hKH5[r[ ꓫ~ +vCJ4D* 1$ԞC˦n],@[;0'lq[Uh7VkuqkumG4r۵ G0[57H  ;O95JUѮ|Wwu=H"ʪ22{[xB9s^ո2,s+!ԙy&u@ Wj`Ÿן?JnWSkWii푑HXs޺qֱcKI{ww$kLm#U@[%nտdr:kxZT&4ep0bR߆暾8 Sv5Hv{f\u܁ƷDHu;{ۨ}xRHti7S]K!sw'>dwhO=-Zz.7Yϝ!M쩆iש閷ѩTeU=@`?Z|-k] _#KiVu RGR+fcP$QDQ01v9˩[m>-ss 0u`qVZ1:P[[[}4QZ]2 cM上P2ѶH  .6^_ܵ\ya)j>~'GSVӮoU'&:nRPx#w>7mJɶY$B6Č3޵j7Vw\_l"l%6 M?+aiwkqot% rO|sғ Z:W5WѿŪZ4LK1UmMMݬIGb ݂H_Az"-!IubtZA#RN98+7gYӢPӬoZV&W ?gzsi'^_?"IJX5Α·VnR%%@rHWWXP/u_leYt)dحEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPԿ[Կ[or]L},d:o->MZCu J8+u@giq X^M,&X[dVq?P).4=:kim!iづr 1@Ǯ\=],ڄvM.}6;GUcn*xx[O,`:_`ûI~tϳy1w2*ŗ$[6=_JfoS3]-6$_ԵHuy孄ݖhԆ$4o5hRk_,v[D\9cc(ZmWv ( ( ( ( ( ( ( ( ( ( ()ki?Xvlki?XvsG/ɓ77jv.vm%K$"t#j]}>}mjvo*|< g޹3iutڕkhaIFH Fy銽w`gvAa0YJeQ˦93U?jϬv֑]ϩYm7Uu+;EٱieUCbq\a<>+#}>. o n@`G v梋MM1;rƛj.$扜XƋaxt@t&SGCu%}œnBYc&i8eԓ\-K e-I$PBWGM-{(c87@=n_[Ԭ58K kSh%Y>VC9f}=Svb3Nڻj&{n/Cy&O=Z@q^gVǣ^[ê'ՑV1#+9+(pz;jP'q#gu֘HxAʺm:i`So?84-%ͽ =A rJU~Y]]SIJ]mB 8eVT|Um+K;;%&BAj.[úYZMO4v+`GjNe]B95Aͽ$zjvm%)4} B;->E uf6*$c *mp|[{;NM0![`u@Dq}*4ȍSg]k[j6Guv_"/͂j6x3uL-e-bJٗ̾ͼFߞszb\XkZ_IfRqP@q.` P3kVL6Q[ڭǑhE"11#Ft븨lr((((((((((((((((((((((((}ՊlaOmmP~jwZzQ_:.m|fӭy4 PvONz~4mR=kGbF'M^Jm;Afݹ'ִi_@AER((((((( KA5mVƱ KA5mW;::Er/mdg{XJnj8a0H)twbLD~p#=hZQ^sH#SI]ž SNBk' q{sr'-nϔ$b@p8qBUyigd!\xoI[mRt"0T6+O1ߕ {]Ewk{Ė̛S`²Rz{еv=&+io-aMհѹ&U ?)Nz@MV<4)9v)lZ+y9)=>båKC[[iA=uK~`ή|;$k֛VVKFehݔMz)e<+4)5uHnea,R -$ $3'ҏ k{uk{eHc9vF jh(((((((((( KA5mVƱ KA5mW;::k w%uUXHp~Sj/ˣ )ibi$ YFH#qK] kl\tL.}<+&ߦG:m\+(NY*E,V6фs"F#  @\" aS@Q@PCn.^}.Y߇љEAR@Csgm{ ,:5^O,`$pFs1PM%brI,O&Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@:}ImՊaOkmP~D% º-[K}+fUKJUw~r)^9P+xbɭe2l_ܹzK X>p|H̎N8#ۢ.<+:^$kZ{ІA$S`T'·7Z^+t[ˈqnCj#&pY0%zl-RU 3ס:Xi S݌BTM?\օPEPEPEPEPEPEPEPEPEPEP-c@'k.6c@'k.6wu4uW%2ӯfbsxmU$fwK0*n0 ԾX4ْX67׎\T PkVcŠ((((((((((((((((((((((((((((((((( FGЍvqV0?'kV(?VRJ..,bYH.qqFտԷҹ}\?a@WJT_Gq}ɪ?k&OI!HWM]Z=ŽE <֎]sXtжK0J/Z//g習;b1o Yg >qu]ťͺ473*K9$`U 躅ܗWed"W,1AM=UVmq/cnܞˠij˪4 /PdIc{Kmem"ͷ]7#9?xZKSF((((((((((( Z/O??]m[/O??]m\h_KgKEWAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEpV0?'kV+Q?#]@W3km|A}-ĩb]FKO ~5j[^{>uAYY'Dd cxZ.`Is41QdRISolqҚ_3"i)倁*oGr)ld8W+[?u)ܲ+ 7 k5-E owr|8^8-m\oآnIHM;_9A&tx]%uQEQEQEQEQEQEQEQEQEQEKX%{I? cX%{I? z?k~Lh9((((((((((((((((((((((((((((((((( FCЍvqV0'kV(?VRJ#-pمt:W'j6NL$*#"=ȠD巂v9 O223yX%D7с =Aj;m:K1C(@\CиG"VU.tM&nn)e:`xHnM3"'}T8hkZEML $`(Yt>;٬mxT}_/ /t]sq]16J6/'htbR%ѣYHYZRvMwW=o(k¾2CJ,v迩=ɨ&t$&r]"RV0*ض@Z:Rh ^9!`v+FeHG&7.{3-sub^uK/Hce&v۲d~];Sխ;s}5f-ח3!N_57ÖMK4JGBOsUFGDRU$< 6hL˱u͒^G.k*C.$QF9뎵ui6]IfTWpkRAC{Bܽ$!B'olqTa J=Z sN&>\prٝp/M<^cmj֕my_hþu_4ry+kTm/֗ 6%Op4qA]%uu}&QmFkhițGd} ?$ JZC ( ( ( ( ( ( ( ( ( ( 7֫UVo@(((((((((((((((((((((((((((((((((b?OimWk#_2FKob3o-{2WCoqfs^j֖_m m3ae 388J? xW  NF@XP /nO.L-1rI"`0N?Pc6:-L!U՟ ˻k DGr . OV۟x֣ykyF'6d"Xb:柨Zկu k/8&oyBTS2,!zunZ?_Bvg;yZ}pfnVIJYS*9muGWѤL&Upks}jom-qqm{Z~)qR2E9F"5  ,sRxBBX+s}j@v+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}svnZ {@^)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEŨFKob_imP~xx^CWor: ƻy\un2bWkR[} ZGp1}$w~uo /pY!k˒>f$r@= aKoZ\ijOg}c)<bI'))[YIhc{+)P^|/,MhDx22;? 1 -lKqot!GN:us:e|C. $-hʖ; ['rut_QuDM7R67T;@nuC67T;@nuC67T;@nuC67T;@nuC67T;@n1*ns?΀4袊b ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8;_imWk#_/-ՊտԷҹ ۭψoQ! o-?SﬥX!  WOos€;h`y0c. 3iQCW--ɸC";8'k cy9kBM6]~hR/mGг:6 Ԍמ*{ i~T tՕb.>n91BQ{Wԯ-K :FqG'v7QEQEQEQEQEQEQEQEQEQEVoVZ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEŨ:-Պb?vg[\?e0VRJ..,bYH.qq^[xL+ |%*/>E@Qmlln5<H̋Ky(ƴjXq,P11`dеv$JS=7-dVym'J5Cr=)-ZCxcI^TX=\:J{ {A Ə1o0>2x0z]A/mᓸw8}/mmo9XH]VSAAWk{jZ]ipI$PF+>F`T(w+PU3n `Tՙ)Z(Š(((((((UkP( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8Ko]\ez|X [K}+f[\υ!QUw.>}T55d|ϵ\omXH[ϻbqNOnn3дۑ~&YQrm6mC KZI䐮rs^\HP(<)9s'm\ľ^۶N7ʽB^_p~`A-lI,c4.qlPA b8.McoRK,xZuM~"m?s8qG`2[ZKjRΗLFht,XAo i wurmXIvEG6(nHֽy"-{Vʹ~T/wrb8MjFkd*'< uQEQEQEQEQEQEQEQEUYֵZjEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP m#_/볶V+Puoyu֭egy`'I VRJ#-pمkCA40] #uX}p=MfZ;S6LahUW~*3Om[ds}pu64Vٖ['u/+j[1*3?>U{/= ioc}wtZNkE:CyTON'Iu͐;2b\.m4 PB HA* .+8T:' GRӤ1{bPՐcXU{Y7&f<5n=SOb{,d_"^oX%mĖf=$Ud"yM帍$¾qr@\#մo=B;e2 u4r((((((((((UkP( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8K]\ez|?X [K}+ћ_4ո98ۻnɑkտԷҹo(<5r㱉pfCIHIij7?&XzaĐZMa=̲G FV.9=p8Qh j-֟>!4gxX1,2ۚ.K3v|&9.ď®Q`8 7JԴ?>q-nK0AiAғF/V[ƀxa/G@I瞕SCo"PN~ͬRlFfG008]'l^IZ)$tgid$`z] z^QEQEQEQEQEQEQEQEQEQEVoVZ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE[Ǩ:ՊmTz|?X znԿ<1,[ˮpO.O=q\EHcShxíP1~e8/'ͷ¸ ;?Jr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;hfՏ6/-v89h<h֬ۻ<5wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ /65l\G!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3mS58[W/i`D(ZV}Z39&fS+AYuۍp(fhQEDlbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('E9mPvc ڤ endstream endobj 69 0 obj << /Type /XObject /Subtype /Image /Width 712 /Height 557 /BitsPerComponent 8 /Length 28145 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qquMe6pΐǒe5 ZήwQa*MN7_Te$/k#N7_TeH=-;x+Q ԑE. sD0vbrriZm Xôo?He7}~ntF$d{ЭpMu)ۙ|KI#Kd *:a dDL۝2q Lw]JC͚HY(ýaBܱq"oR֮5'r2:{A3 %is"]c,wGz}̖oMN8VR$F@ OHDf= =?WAtWy9%!#?I{El.㍠p98ҭhJ:ʻnnO'օ (IRXgG2 -ٚ5 z*-$6~xrZvʡ#BRI֣p,F0aOJ.J.9 8H^f=k/nzU*y<Ƙ.;ӹqC*¬;3"Xh jͤ-olŽzӖ J :|q$IAIt6 PO2==wLr@,xRƅ%9D*`ߵL"T8 o w^N҇$7$PwHE,6Y  ?ld6fsšl(w AjeT( &*jɋɳi vX :V'pчh?tV^@beO &g$Bc!c<8''ުIY ˑ#P`u gW"TP0u gR Ď(((((((((((((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>bum9!ف5AV=?k}qOVe4mcGyG?g[{O? Կ罧Mv[BzΞl?(q{O? Կ罧MvceK]쬿/Q'#V=?h+R5Ř%6+F~*@֟-Q* !pj_o&B/i}]mQKo{8{O? Կ罧MwexQ\ VKkƥAQ'V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?ko%ΏoqèJ]&8 lc9)F]S[è-ݣ>>~l\I#zC\:v.5 `Ӯd{ ?U<{S[C(((((((ju5P(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9]oF?*>ՍoF?*>7莬WO+gwQWA2Y=|]ס]5":k\SA%XJ+8^X,k\SA=5?j7kV D*uOҪZ@T7-w:3Gl~)<=٤?qM V} qִ~?fwڢs5H}e4}/Y3n_&4i/*BI`:V!w<ѳ9`@ɠ (`QEQEQEQEQEQEQENjeQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WZy%WZ†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Uc?ݶѭ[4}-sVIK3U<4zJ]Z{6*r.>x`8LrG» u-sᛉMݳ6Knv8t7ۿh_A4/=fRMUȊd N=N+rMNQE60\)31)aNd`sBFutQEQEQEQEQEQEQENjeQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WA0כ2U tZ†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@S1)$*V,FA4+0ϩw>>k3@T }Z>e?ֿƴ~o>7M3e?ֿƙqw̆5X1@:>odѽM0 r;s@(b ( ( ( ( ( ( ( kS_2(0((((((((((((((((((((((((((iAcՍoF?*z~5 # Ar Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnN/vF\uH42T 31IJC>5}^).` cuԊ+7{lrpcК6OٮU%ݗpۖ=XSH1sv4$Q'qZfWԢtFe%FO)/"?2iڔ10ydB! lEo^&F[$5O,pDy_j/_%B:+%u3T 6aR@nj֮:{MZCpd[i9BcEPEPEPEPEPEPEPM~kQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U jƷ#L _=?†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@R;n&s+ jˍ<*?%?pBtbelILKFٚߕ ?4+P_6>t?zT1fTٚߕ |V6>m`$`Ҁ')QEQEQEQEQEQEQES_:QE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@#L _=? xZy 'g=?Μ9\ͫUSQKwp}E}Ej`2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФԵK=&'k6rX(& O\"ФFi13BE<~bd>ՆmmmC8uŦgw&jqr)#J-Y)f] nPn_~6=k?N#Xy2yg9?qa~%[ӐZO<>ݸ5I%Ĥ0۴H蠓{7uFiCgpZX;#Ѐd{)/uA쨤BJ)eHzREPEPEPEPEPEPM~kQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\z~5>7[=? buמ>bЮ՚_wV_)}qOTj]Y :j3n4aJsҐF?MGZ\LU #R!O˜~D~uvI%l;,Q$ΩCcq9k٫EeCc^M/kaW_jY_rh7Gt¯բ!M /? o&k=_qEeCc^M{ V7G$6?ܼ)=;ƭ /? o&HlyS4{XwA*+Z++^MrhUWVW$6?ܼ)?!Ma5hHlyS4CcúaW_jY_rh7Gt¯զjúM]tg ?#MN2ٓ*sM)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\u7M((!_y/ν Y=|]ue _ /EO@Q@Q@z÷oBO[yu8IEz*UMWB/~)*_ *_Tk??Sb(2 ( ( ( ( ( ( ( ( ( ӿVqMng/ԿEUQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s\W-]M*5h ( )e^{//BVk|E1EtY>*zi6?SR-KEEERգ̰HEdX۱*+NOxbYZif%e't4=2եEftTdb$6MϞ5b->sS__o_&HmS E9/ /G$6MXOW|?o_&QEj+Cm>zK /V(5?!=O%h|?Qi? Ϟ4Cm>zKՊ(OHmS ?!=O%jZ}$6MϞ5b->sS__o_&HmS E9/ /Ps$oiaUۜ{(Qw`5kQVfQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr;>࢈>࢘]5":+f_t_@xEMPǍqOTԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr4AA2Y=|]ס]5":?*j7[}OS ʹo ?@pQDpQLC.՚_z^{//7[}OS ʹo ?@pQDpQLC.՚_z^{//7[}OS ʹ tA2Y=|]ס]5":?*jbЮ՚_v֟m\SA5Ci6?SRQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@xEMPǍqOTԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\>uMo((!_y/ν Y=|]Mq.0c !U>ZC%Q"@np RStºyyjW-2]iSVoOK?>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? z>)A>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? zrٖ8u%;?>~fWڼU@_t}_ Z$Hn}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?+RjvCy~Y=sVU4}MkXǕZ9.ysZޅҍҫ}Mh?ޛY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC.?ҹo}x:Vs~D-Ͼ@pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5\ki_is0R R4K0WQ[$/Zfp08ϥTV5յ,@iN;('>_Qtiv/6ݍNXPOR}+4خ %p@tFX@dY)"&`6gi-kYOw\|jȆ]p,].+^ K[ @J. |Ik__1C3XAr]@9 '}m`+ QğQB\Y#tJ8yD5+ #VΊ7-Ğq$8[K1)twPQtыiXc}._cyK.PU[lUIڹEjW#cOԟA#ݼi?F$wRH#Ғ{Z( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( 9밮?ß}?΀;>࢈>࢘\5"S4νq5e`2Atve?tvvO^wf ioTug}3OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OJۇy'ڗl}?@o?I^h>"4kp@$o7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 U1=5upuV:[}ևhcPH<pQNaEVBJEh r rv |5?p~UZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZP(`Wc寥ZP7mDaElZaN endstream endobj 79 0 obj << /Length 3254 /Filter /FlateDecode >> stream xڥZY~_A%Tbqn҆|F;IF@I(ԎA{IӚY wU~Mxr_'DŽ.lm+1ertUr|` Kk!.ɋkXc3%]czOb70R&EVap$յeܠs٬֢B_n>5KEZkܮx~Û|u{ wg23J%͏?d}$,EkTkhCiHdҨ` ᓗZ n5A'TKj4OVfjIZTla_oNSϧ[,2 <ݎHNs0OWEgLEg|w]>PĕB@[FjQ*24-Մ@*L_p&TaaS?t>>:{h?gW[tn|8"rdqƑ6 {/,V\>}P6UӨf!v} ݎ %Lgy)HV΀!x+7?7gܜF5ѡr^ebE6zdd`4UL@pMd8/0 34;-`S'Q,LP2'ByAlJ>U7CMl:ƛ7tߞ<,M,|_27 €4hܢF@ γny{=mϴi-5ʟ|>(0Z%Q$r`ܱ#`T 0s+aG r}da |kU=BQwΫBd(q97,fc3UXSZxX(46?7b+I Ў%F$tz[ylTZ@W31Ӹ͚`-7y`X U]u]O6{hw+ $l Fz f )g"_+<{4H8L~M;uP1!4clG1j0V_qsFNo]y3 Rp lҺRGlETl=FhcTcv[#08KBΆ% P{EîrT?:Oafbeb"|Ԕ]T@a>swJuYopXf-1rh xiwaw1.A1] MU78#PR\8py85 kvN؆xV0-*a yG>6Pxp1NcO ;d]ل&}DDHQ,5۹(}̣& 6z4\`x6;*kʍ>MJ!ʸ$Px lQ.K(+nc;PGHk)]4o[ps#ǡf/PL> 8Z͍܂T瞦YeBLq𠃚tT qxwbg≠L$E )!2a Lᑚzpۡ0X;Z򰬫wξ`Cf ,_3("y<"ջ-u nq`Z`P~s kH3(ڦڗH-/)>+@k&_v(S5dܗit`~!i*A I>ފ&U{PJ!0Ff ݔ#&xb /$0H2z6Sz=bi5E9>;E%d,MkZ;>_`L ^(?6Dznޒ܂X +2%iȒaG*k?ϳo].vu/Vw4Mu7PӡEF.]~Ʀi?ltg~ f:1'$PFqkN5'XT ή J&RwX36wEV),"j)Pr}#΃C"TĻQ\ȰAIr!47JohM `k<+T|R]Al<<:'Am47V !F5R2$LLo9#O]&-qSv{wUlZ ^,/(馗l k/mrLQV!~2`p%&j(i b%5Mj ~i{v>z|M|\-qXA H5)ܽY܀Qȣ8((nxQ|&`'b&$ΤC7ۂL|ɾ|&^a:zuMۇܗ޴ظ{>k_ WSA}2*8c>ef~ݼfC6yaOLGwueʕgf0S$+?/rzЇ挲/@3g0r$..LEe^HxU!\ c?U\ Dr}]h O> stream JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qquMe6pΐǒe5 ZήwQa*MN7_Te$/k#N7_TeH=-;x+Q \wWfwQEEQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@#L W¼Dk4^oU/ †Պi~l 9]5":+f_t_@ Z˙875LRurK9%2\T$Oz !¬c?aV LyKi͹'MuԤ<٤b;8--.LV-jYۻhp,pq#;32YvqO2)-2t{nw,fd@(P$e-Dd J :hFcJ tEw_,/R:dV]b8}*ٶL}h[x r%~s ݙ^@۾aBCg%l0 ^H4($}j1gcvpXI4H^_0*9㊉di]@Yc6篥[RIii3m;t;\\*#2,e݀&Bʯ!l(ǭ9maX0 ODCkE#`t* ǎ,hZYH8=Ti(UC,NN P{u(rCrEtRnPCnl98) pPB`Pbm1hQ@Q@Q@Q@Q@Q@Q@Q@S fN31ޮT7V^@beO igY z00z0j srirA&23S}r}ꪢP@sJ[w%~5u?ޟ‚(,((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>bum9!ف5AV=?k}qOVe4mcGyG?g[{O? Կ罧Mv[BzΞl?(q{O? Կ罧MvceK]쬿/Q'#V=?h+R5Ř%6+F~*@֟-Q* !pj_o&B/i}]mQKo{8{O? Կ罧MwexQ\ VKkƥAQ'V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!s.to7n,=rmߵ2++#H+ )((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b "ǡ1HG$C+-AOglO+U޲4ãLD$j::tǮEt\cS[6+o҈ )' =ȭ5gҭ5Xu KG`A-g<ץ 1<;˪x~kxuv7c~͕ gk ĹH͔}okGH6c8PYi:BivA1; /vFlX^IZM'44fyy9si:,-n-g]S]t#\moӬqr:Ҷo_%B:;TWB!?88$cZkNơ,uw rᡇYO| kptQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE5S)ڙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WZy%WZ†Պi~l 9]5":+f_t_@՗"D \g e"~\X5]?jUniUVH ]OXpvҥ7q甹4.)OP}23֏"_54 T_ݹY>n_&~ƏE/oFڢ&6[Rh]0I,J$>6pcRg,4%QL(((((((((((((((((je=S) (((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH q}'5`ƔOji9 sFjG@^K\O`fcY.E, @Waz.?ſa3q)}Tf]m ߻[w &Et,ֻ{cA֓{mYJs[*kRe&ˉ:/Ǟޅ=(((((((((((((((((je=S) (((((((((((((((((u`7d>c[JᎃXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH s73R#rd98Jڅ<[Ҩ#&r.:gs&{(ʁo_G/֏ُ/Gٛ~fFw/..[{yYƫ9#8\ُ֧/L73\G|`h%QLAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U tZy%WOưDub_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐I֫`wF@ʁ#ff ="Hq{'FO%ޝ,Zܗ1]#as cEf6Wvur-9BnV NpzP^xI5r\Jrc+?qF.`V&5^7c3Җ= S5JWH̡=5_4bM;R8O,(X$$ 㑑ȭ3yXp$I%;]Ķh[Rez~g=ӄUr9cw8>\NkP_ŵǝ,ˠt-;j( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (L0(((((((((((((((((,.dcͼvkVz~5_>7W=?AEuҥG5+pQDpQVd2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~Uq3 XW\n^AP!)_سk+bORb_l6?OMQύ_liҡ0Sⱴkn?#=QL(((((((((((((((((je=S) ((((((((((((((((( ʹ_ k}ro\z~4A2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФԵK=&'k6rX(& O\"ФFi13BE<~bd>ՆmmmC8uŦgw&jqr)#J-Y)f] nPn_~6=k?N#Xy2yg9?qa~%[ӐZO<>ݸ5I%Ĥ0۴H蠓{7uFiCgpZX;#Ѐd{)/uA쨤BJ)eHzREPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\z~5>7[=? buמ>bЮ՚_wV_)}qOTjRl1Hrrcژm'=iJsҘl?iO R!O˜~D~uvD4V%"ب d c\ݕΫ5kVU`prFI&|3$X"K-$9֘?$oQ u$lL$HyOsFwjazRiש>vg6m H;~s۹ mBy2 zsY+эJKIt'oץbTiqc"\vitBgwڡ+GoVb6͇0sjuQ)+YUcE .4vj(;djj^źerz4a6pGzcI ! UDr~Wۗ{.c{mcl*9'WCՆos:~\wRBnp>E.t{մkxO!7qp_°4zU{Yy#1<|QŶay4O,_)U>)i,욕 qΧ{?l-͆i] ?[whmCM 85oVuku q$'\21!$Co˩[ݪ:(d:X)Oh\j663K9%Ugy X^ͥxq,Fgdn aO5&qjif#kd6Fh9=0;ԸY9y")ڤ?Kc9#2D/7`p}+BSj3Ha{5$˝nMג`8P>ƦNqWz\CMbͼrƊnc|#*y k*M'QL"8(팞5Rkmzɭ; j2, B`A[KTHn ćdcUvɾAERVuƭδAMэ@KPH˩ZFpUPGo$7ls̤} $rdB.2?u1?_? ѿ+ehF_ ?rB.2?='?8/GA A[/I  "#?2.iO= ~nSYsz!y'A&fFp%6Wr0X¬svsľ&xTad ᇥOjRlXMp.HG]g\ѲGC}"?/h?ة> > F~6_*O'?'?€#ѲGC}lQe?Pb,>~c(,>~c(? ?aX2R<*?'?žEڙO~C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (+>7[_ֺ&UxkuQS˯f_t_^uמ>b`@ X"_k"k8ϙ[~`v=9鬿k\SA}k-I:5J#q 3tf줕#>P0wVjk٢a`Υ8@Gb(ۥ}Gۥ}Q}Ro>˩շ?UKs}Gs}G_eԿ*_m~@_Qth(7glt?Zoٵ!/6aS3B=$((( -.YRC}0KJ`O ( ( ( *˻/ϷTK7 4( (L0(((((((((((((((((*5Mu7M4AA2Y=|]ס]5":ӭS[_ZjI~N\hrz9l4bs gEfxFG؃ҌO@!LWu)41DWXm~# w>Ԯԡ2IY:&ټ#i|С^aze8MFO. TeN>S5}NFaL#О?Ma\\0uj@/kdwGtYm5<x=@Y&7Vr)n_v+By /asJCÏ0늮?Bv0TA0wHxОj mnOZsYM,MmnDɸ@g  ohhuޝcr.[1(q?!K߲[$fUT#0)l{k-zVz"nбXk{)]ѝ)sj{/_Ӯ Ibm WCz55LJK+YbI#tF=hj&']ζX# 3dӜxX#x4fO{օݙC'ho2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2Thx_2Tr⻯.Y^$U0]\^ڬ萻ƒ 1, 䎡GT}Fò28r4x<#DMÒcWYhM7WvmO)7W#q,jivA@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr&UxkxuQS˯f_t_^uמ>b}qOU84mbmR8ȞQ?*ԁ؞35rA?Y&Pb~Y}OӐ E_]l\.86X;U|!S,&pHQgg,z{Uf<П("Hܖo?] nxc$8i?Ҧ%| J)~m>[ϼ?춿*+cVXc`h 9J( ( ( !)ddO4q$e20ðb7mћvj(ŷFos?6]:'$2jJ(((((((( 8.yr3z{TQ@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr5>7[]Oƀ;>࢈>࢘]5":+f_t_@ՐNdSA^=IE=.$BYmGB*{<g[`|'\Rer%i'QՏӦ=r(_Okښ[},@ O)O.=PqEl/~\C>oqèJ]&8 lc9)i)w]a)3 A6p8ROҠnMZux c2 ݰ‚q4h5+Hv uj4-/.].06 qNX / JT%?pB2\S5[&\\YSޥi95[̣4Maksi-Jm(h؃\b oO0k\b.ooD-w$$~dͰšmr$ woÚΥm}1`XpFݴqd躭g{}mrgi&Hr zCF^Sv67l(9qߛ'=5N~זo:ꡱRGQPݾ..-`x`L0\c5T#s%Ϲևחh_]O"[fU'>*ƥ։0&' }w kWrew-{gqٽ7wRvTh9$0튒×Dn_,B`}:dvB:K]K LW6q̷dګvOk;#[{-` œ8n{}]-KlҤ#@ʒF=ꆉORDø-sϩ@ yvE~,S. s;V業G\j7W3:EnNI@;%WJy,^NYc3YgZ$ҮuXcR<fBO(uu.bK+˫#L襣NbX{QkɦHikcnFx?ōS\4LHpTrNF+7X𖡩^]iӵMbSӡ1?r,2Ò`0ڧ52 `IY# z M/JPl3ʏ˚H*^]z|-p3f(8M7WgiEh>M6('<0c5+$Դ˫\Dђ:f#T:ޭ- "ܱ[d pן{^_E-gIWla`i0),7QxVbïL^;Z_oH4xT Ht3`FxSN״cYNXճBwi#!vzAwiSA nVbïL^{:MR! $ |p6nGQTt_ULtʡ8N3Z%ͼ,XC>VWXkm!]s~`I$hXi5/nP(*[S^A_(}K#cn<ӥ.vdCyVS#xC 9:sx_PD@1wPnhA;ve֢m5fȚLw01sX%I --؎ﴺ?x91Y[-ޞ\)o:Ȍgv+>qG=*%? o|.1mjN|Vp]$23VI Dz_>j]5d9}~O}̻Ӧmc\wq=i:Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr5>7[]Oƀ;>࢈>࢘]5":+f_t_@՗"D \g e"~\X5]?jUniUVH%?pB+ O\"ФxQ Rn*:U?@n'4M\FWmP0O>ƀ3n_&E۟C/oz[is4!1rWwx`I8C'o[6|nUef,'%QL((((((((((((((((je=S) ((((((((((((((((( ʹo ?]M*7wP}E}E1 Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*R/ JL8@jMR8ELdf~SmLP<1^hR_XJ`KqmxMvX5b%֨'ΆKJm8']mvF-6Iق#1N+E/tNIgl^3铊bBN8Aɮ[Zhϣf7.؄峃iCz_nexnd|@|m$zUgƕɧjivK >]X7[p_,cfqq֩YZiykŜ3a/]kuv:Hl5 'e*3`esץX/n?ޒ3dI^MRWiaDCe9.;.Z>VvW*aԕ`IQ*0܈ixm"dBA#d8qRxPv˪隝6jIȨ\Xk3H(6©q{4dRc8c Ac/H=6@t4oYji\-)[a\6FrBkcP,t.pbGSA81kk[Tf"ӮfMd.wdq-A-ܗmn38აNFJ6_?_нt<.g`.HܯE%οYGoq4B@2}A>Eaê5%;{DFIH@*K7^uJ{k[ْWHbQnCsOo=S\[;;V`PS''4y>w au`R2Aejoc n22?ȹNdX}NnnRU@`iFmPU\]_Ak}&l|&n~؝OF B=MVXӮ f}_͑W -?뗺?pOW̟ L=ȧRi|(RWyXXFݪ:jw3h7zmׁ!Y$]8'oagJĺuƨGo7TAcC 뜃9@4u{IXiIdynXX`W绂5 5Ա&: VKݪlhc?w56Jǥ\*;ȬL4t$S6_9>lEe}s~={uop9mlnU~9R3TMH]6LiR F㸜֣{m~+mJԮc(匼ݒB du?jͫ[N[ih&xpqчQ*u{bOkkY)&{ʫa֛ k{] xLE2O-)*͸Nk;R.oeV;vhNܼ`sGUv:ֱwim۵=VU M,uKk{5V")3sS88KLaA[;ScS;r1;SuiM JyS#к\Rֻ{cA֓{mYJs[*kRe&ˉ:/Ǟ޺ (L0(((((((((((((((((*7u7MStAA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФJBS)*VKZtR!uJ`66`]ρȨM/YDBHA=' ٛ~e(;_kh}Z1%h1%i/4s ח3`Ĝtƴod_iV FN ( ((((((1GS$wtImK~_캗[߃Q]K~_캗[߃Q]K~^&ȹ12F~PEPEPEp f|gdh]MOEG Nt ((je=S) ((((((((((((((((( ʹo ?]M*7sQS˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pBƤڃj7pdV#'Ao!)_J_hs(e4 cRCO]^) q/ 0Y;~[ z]BA/KdЩU$Lhj@Ml=Tdm1,6724ФQ*n&#<SF㺂Vw`9f}k{auq%fUr c ;TY_ Ԇ d GLdu?1v o `q ?ƺͰť:NɧmKqp[nH^VW&Ζmj&kauДdW_][CC7?&_*q];9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕZz]6Hv;A qp{UD4? Bī,jXCK9'kIVO|+;KئvmH\R+?[}&jԺ 1# s3z֮q"9_->~k4hMݩ<ESy|b)hMK:]<E/`{P_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\x:/s\W/ῼ?΀;>࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_ z~Ћg'C/ JL qH)"O)8R3&3LOx\quz>_]lu(7]~qt=GëHW'iU(((((((()LlHz629&7mP9oo.ŷSQ@~-3?]MEBHg^@bmg'AߵMEQEQET76N9P* EP)h ( (L0(((((((((((((((((*7Q ʹ tA2Y=|]ס]5":k\SA=Ae _7kV W_OjU~iUg+ O\"Ф(Ѭ-#5Bc[9c1W/ Ji`Ą򫜁}ܣͧծe[xF#;N*Lj1G-E=HL-cxVg׉pys/}.zL[b.K2-ŝ@.-g61K/ass#I4K3:vuh1o ne>\r)g8LSumM_Uyh쭕fx2r zg:dh.vHy<^Ny*z_?KbU73\%>T dGCXz.yk_j)./in~bHcAV0 ( ( ( ( ( ( ( ( ( ( ( ( ( ( (L0(((((((((((((((((*7Q ʹ tA2Y=|]ס]5":k\SA=Ae _6o.tk2*vsœoaS:O5]CۏP;EwᑑYV4 0HR8JTmP*42pN="[ ũin Kw`I 3 *;Eg}+t}+ts~2FOO0k4hx.x.wه_̿Eg}+t}+ts=e|+; ;_ ;_a/hYdi ]di ]f_#F'?NW'?NW}{54Vwӿ9f2FOO0k4hx.x.wه_̿Eg}+t}+ts=e|+; ;_ ;_a/hYdi ]di ]f_#F'?NW'?NW}{54Vwӿ9f2FOO0k4hx.x.wه_̿Eg}+tdi ]d_#AS*ԗ1ʓe~R@#؂ YjEمQLAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UoA?ɿrtA2Y=|]ס]5":k\SA=Ae _((/U_JJ? U-ECE%KOa *?gGlQEfAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_w~jTu~V( ((((((((((((((((*9먿}ro\>w0}E}E1 Vk|E1EuW_y/΀;6EM{kO)o(ǽǽ2k$)͊Mw$~5o^7rRQV;5 l+k'U){5/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/^> K!Y6`jEI$''vQE1Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s\W/Ͼ]E*9 ( )e^{//BVk|E1Et\Ka`th+y®?{OxI`TH-(eo9;5z0^DofgڼU@_t}_ Zeo}SE}iϸϵxWk}.)+7?֗Wk}.xO< z=w}iϸϵxWk}.)+7?֗Wk}.xO<e60IG/2]jW-ּv>f8ib=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC*MZ_7N(q/ sj(7PzoUN.^κyyvJ6J(7PzoZ坧ҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛ>+ol 8iYMrtA2Y=|]ס]5":[H j[."3a2 SҭHFeIL{83X>5DͨIK|I 1ӵ%~u6Wi(<'GPAcPmoFrFKz#i>٪:=if 0wrD+L8ZαbjO 8.p26O'Sꐺ6m {M7?.cF [>٫uw2Bza\ep6L:qA?g]aiZ±Ȳ8RDLmbnlԼS0.s#'k6*1FHs[֓U5KH#[&:Oy-&՗JUqn8#_gkp{ͫ'gMlwMđЮvZI4-#(,'cڲ!v0>TR]OK*@SFoe!$6 3cy9+lN thP4q2"7?6 Ha\m/~c ͕ &\u>G[eeH-Ǭ_9+M@Z.TcpH;q:,#~" ;Gs~5r[KmV?,M. };֟S[,X&y6J: 6/ﭴ)/.9@ Pj[}(2|i"u?7bΨ$'˟'m|)|:ѽAbN|Uqh&!nV_Ij-tecwNL HղO>`2qҐ,yJfj'V:X_vgOíbx9-K`e[%`~_,>uTO7f͝<Q}B;iV7dUvT V3U$ w\5 jaR[%+HQ3'uM2 6,.!Uߴpp63֗AsRVtѨ\ m0 GN?[Ivic7l #Vs6_[jY[E)LY9ڽc֛]Eu絿ԆKRhž*c?/&Qt:(Š((((((((((((((((((((((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mc•~" qn?zMr>\;Ut@6v59GOSQE0EPZ4@ƃ FOv;G5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5J<5?p~UkGhiQ[6֢ 0*@;S0(? endstream endobj 75 0 obj << /Type /XObject /Subtype /Image /Width 712 /Height 557 /BitsPerComponent 8 /Length 34138 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH%?pB+ O\"ФZ/i]H"y*;CiP͂R)w>p "7YoW%f #m)fo_ __kkG~f~fw/=7^\dF>[ qӦ?1%i#5BX08`P2J(((((((gALpNO 'ٵ/ U_m~Gu/ U_m~Gu/ Ux+"]0@ A@Q@Q@Q@Q@Q@1@BǢ*c!rB1:)VPy h(kSߥ2Š((((((((((((((( M A?ɿrw}E}E1 Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)+.\jM6~A ehR:t1ZEITf 2_Jp>05$8@jUҒ <PO iӷϬEP׭e,]dv@= RAƋK Ym!$ ٌ<5FOڃc}s,M Eb8cNk54m^H;./0E0Hay AtGZٽ?sh7iaa ^1 pPpk|Z]v<6$uealnvrf[a HNXsARu! OL6lm7n 'U}÷Z]ū,.ih pӟ??,~&];Y,gP˹naAUw Ek}kk4S9BY <kZ\TtVwwSY$q Y鞕gkMXyVIxKp=M"oK+(d@wWI'WāMK ^ؓTm> ;c4!q$v'Mmgqey '*N$gYtVY͜׮JѰP@7/'zhd!1d:R[vK=Bkƞ%$QG>աmn c|&"hL@ Fw> qA=k7WV1 E`Y$ cf6Mmt"ɞݴǎ\bv( _s5e:Ht"xord1:$]]Տ/A=]KfU8҅tMwR.0ͦH$V.3lqE/uiedLqq2Akm-#v,$N8_u^M&(`꨷S$2n8;FIzmȍicUem61z*_v{EJBv_ :|CkΰIWyX ,@*ӸpBJ^[y(HqΧ?/MO ]Qtmg>W_][CC7?&_*q];9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/tR;.(2A xqԓ׽Kyv\ƅ1I+3uPz(FKYd1h (BK asf{.m>]->~k4hMݩ<ESy| _->~k5j D WE?j8K85S)ҙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UcuWMZ buמ>bЮ՚_wV_)}qOT5~\X4֭?JiRT263kQB.1G BS)*0+#>wHК1?s(7]~qtyυW luD-fHc!\R{W(((((((1#mwLŷSQ@~-3?]MECv[;u5 E!ΞEy]2}~5PEPEPEPEPEP&;Z)T20a%% 0@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr]U*|1Gր;>࢈>࢘]5":+f_t_@՗",k\SA=5?j\X4֭?J@Eo!)_C5ZfHZ[Lqg,pæ=jEIU2]Ql#8Us8U ʹ_ }((!_y/ν Y=|]ue _ /EVZզ#71.H#~ΒfPNђ3qS>ߗ k$Tq?Zyo@tj 'Su$'H]fddVU ;}ҮU;FtٝQUјۆ ʟήSFWmP0O>ƀ ($>>ƀ ($^>ƀ ($^>ƀ )v-WK4d`LczP袊((((((((((((((((kSߥ2Š((((((((((((((( MZs\W+ᏺ>A2Y=|]ס]5":taLSAt{k!e}SFN k [!k,)sހ:o֨OH-ܫonHn@-U5SƧmq~#mdrb>rIsH ]F:mb$q&e0\wz4rʛD'Je|!igmjp5v1 fO9mO1O*ݯ*E[TjB!`󁓁n?b+oRD"B zkY"DgiT,}N8-EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\:uWMA((!_y/ν Y=|]ue _GYŨKS(Wu J}"~\X5]?jUniUVH%?pB+ O\"ФzJyJE.V\dT&?mj!mpO7/Pw//5f%h3ߒ4}Z>e?ֿƴ~7Mfo_&3e?ֿƏ_7/Gُ/@V\+H }n&'ǨP;@QbI0i( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ()L0(((((((((((((((U|Ӧy98n1}{7:XiAgYR?7B0P ( +ce^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`E!ͯu?Uj6跩6hA|њͣ͠ \x];:\[_[- .̱<5y^iz/b ԕ|XM Sh!hϩ:mܩ HZxM:W]kb$3,'**2szSwv:f㨢(((((((((((((((kSߥ2Š(((((((((((((((W[JសXiAgXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB+ O\"ФfXĢ"$`X&y u8~tz9-dcYf=QH i Ph ض $4lʣŷ{G-(I*6?OQbϽ}I*6?MGo>? ?Ə[Q4#J-ѥE$bm:ġS %̺6=jeeXv0N? b%ɸߣRy7/u&{E~K\hhtʗi$nVQG~?RPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U jƷ#L _=?†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_sU&W1bv ϮMm[J%1"7d}V]NMZ`\o@jT؃= tOQ,R[J+D A$z X#7vp9wֳRB#pf`;)0.GK%k+ .՞xK8G\UYQۢ;ܹ,ŐIX&\[}L²"G' X:RҵMLKno*A6vOChjиf>(Ň~|7ǒğ)p>خn ji0:j gɍ۴Has&1k}6_8.ʪv^Aяз/ JL>-UI?h4x!hx>[=p{f3Fhkͱ.3ɵk*8ReXP#ÑFMGtf?5!d OݻR &?V-x7XrY ((((((((((((((ҙO~C ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9]oF?* Z[J?ְDub_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%]VEIWik]OhI٠J)RQ@ E%ֳ״?5_k7MlcaL3Q'(5VѴYerZgjeyorpU>a~^w%wx]J{+1f o: d 22Gzh:9lQ,4h 3P:OALo\iUTo,[u#Bz{ Koc2n4Bgo͜hR={1Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE4^oPxkbMm/V࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]͟u?-rj|YSަcHfFi4њfhJzI׬?5ZC 6?5 5[Mz;dtx~cp9[XI{D[+[+nc_K<њ NsB ե o/GOnk-mco6*zA?SW?co֬s`OҪZ*uvEIWjRU`W?[Qşv?-XHf14њ~h34f'³§y*#rV##O~\oyk}~-I=E{v|vųu-ʹwvo.-c~ViDm]daViaYE d!z=I'}Z(((((((((((((kSߥ2Š((((((((((((((( MSA?ɿr4AA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФJBS)*0*ŗv?-coLs!h34f3L3@4bn O4YE-Q\=MsZ\%b^<9bkfPeׯm"kd7[]Oƀ;>࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]K_跦?Z¼MK:sTYY) \0i|ݲQ/ ?E;o/l,yv@/ ?E|ܲP ]3AV?U3i7_pF:І%N*+[jWny68M̗ 6ю=*?06עKgSwcN v[[MhdS7=>]Vh7P]-ե*Ȳ۲U!p;v[hֺ:nbh3 6s'hGKxn?*Ъpɭ(QEQEQEQEQEQEQEQEQEQEQEQEQE5S)ҙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&Uxox:os\W-ᾧ ( )e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`E( ,*` Og*6 Y&O=@Ҫ+Rp=(hpޭkz\شUߔ@(r9qW!tXy ,^1ڛpv뎂:1^A5G*%QI+5:iD1)mzn隦77$-MsŠCƀ!oBGJקO<qk|Ajw[țo$rL׬Gmby}N=( ].vR"LeMUs%.%I?Kl$;‚ԅ~B92_(z+$ڭ[=P DOD# t#U}KR[[xtĬ'`q࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]{?[_e +EvJ G9ڵ.RDxxRqgMBf˅He8-.->[$ XǠSuiy-#+2PA<ٿ͛|.8t]0cM6i@wxlvs92B-nشW_IJ_]lu6F1i^]:{P<;} ^u|=ČUB[+b*7]~qtyυ@졊 #A I$4yΙj!PnVR#&pnom F=1L KR}z]RSBшI̾R Dxj{mUBP tTPcb#AE uPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr ( )e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*vEIWjRU`W1k^جҘE(&,I sSK-<+TarX[bbBt'J騪Z^gH*tu8*GeG|Mmeo gNL{gt3N3܃tTW=ksWu_)#*TuUGbЮ՚_wV_)}qOTo֬ΒfPNђ3qS>ߗ {9tj 'HBs)(N#v޷.1ATs5#"h`q~rƝỻ;*i'ݮd+v@䀶3)V8`mQ@ZF-Zs0e[=0k:?Aiiw6s\1䭌($pr8޺j(Zë\Pi[G[ B*֕bt&e6{ fQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr먿}ro\x:` buמ>bЮ՚_wV_)}qOTQEQEKQ[Os(=  $(мZv;>WB/~)*_ *_Tow0}E}E1 Vk|E1EuW_y/΀;kO)o ((((((((((((((((((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//]V; E>a_38qCު}_ ZKEnG8+7%Iߙu'3>ZC^*e?+7<+K}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo,qJ=w}iϸ̯xWk}.㵆H0ǞN?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/_JVӵc9ڴvJ(7PzoZ<׹9s˚,>m>[PzoGءƨFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhuFq\~xsRp4&o}x:` buמ>bЮ՚_v-d@I5Mu-~ؗA A0?A^iVZ$R#2$=܀zgk amP"f$%]$ڒ:+]FϴIJ# ?#9Yl`lLune"Iba gU-bX[kM 8A')H]6eߗ1-۟lՋ]:ϻb!A=IrO~}ZTV{x`ciy8젟utFX@dY)"&`6gitC^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U}?UfJa:JKa2G¯wk1YAikwt V9E#p)/_1[k}Z["FO٥rWoc޴ӯ-4mUgWdV8;࠯=i'ҵ { OSB#Eizc;GDlvWڝޒW IB}@"NIM  blOCƝ37chԑ#+/0h͏55)mM 9R!^#Wꢕ'%GPqȧ m'U}çvRVmtQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEsa\>w0}E}E1 VkDh?z(kldU~Roʼŷ@," ?HgoʍW}?G'ڗl[ktUj_Q @?z~?y'ڗl}?@*6O^a @?j_PoʕU_JO/G(R €=*=p*|EhHK X=oJ6@{G,mc€=* :Ks܍wnL>?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )h endstream endobj 83 0 obj << /Length 2158 /Filter /FlateDecode >> stream xڭXmo6_oq17nwѻáW,u%$'koCI-;HIjf8|f ?z[8Iőqګ~Ⱀ{o}-$wŴ^Fzw _r\ܗl6B~7~yH/bI\3rQ[V*``EL]Zಫ>^ 1Xm{ {q{+7$ ~y5L "XWLqbk"!A ޾݀+P??Ppy%"|:_jӹ^_Jg1fЫhnSuʫ<޳7W1J2U3Rߘd-ծ^۩S*)ϊ<{U>Zn˺iYsys{o.KLi;Y2 ,l,4&h;-t J,=(vTyLS&L༝0͓nl0)A1]4gA]˩,Q'Q'U.6ǃ|1~z_ @Ȇ9Wn]BQP:0!>@S^n qTO-nMZς-c3#:w[Mȅ΢NW4E(~[dcZ7ЯڦY^9|lǽi y Dq@{7 74Do*OmDwHPD>z4^vb)Чv B!P҅5 1:ՙ=CfA_-uÌeԊZC5k:>wH׵O#;[Ѓj|4v,}~r rvr vu,&`s!XDR~2KEAD B}Z5'yCa'!F"=%8U}PHaY%+ Z {&0|pbMqߑ\Q\v*` Xx8JmED^D`@Շ`,l5 ! (JoMCp1զ?pqU: ΦPHPn&ʶsb:::BA( D,sZĆd>oڛCsXdfIȪsi2+<}ۚ}].9Dx&TD:9: !0>LX[t|\"h"*w-#g?akF-d9l O!- ~KM\y-=J}O)ʓxUc}q3buwQY16;n\p_Ĺΰ=555ETq"çk__42Y ˪0,mQ ;O] Y^Z0:l)n0a ~ D*3":y8yHsFL}p!X|qH* i=,==tb@f`։C\]sN-3ORD]n:Gc}c:SyrҔ1jL3&]NN,jV=vU䅩 8"J0a}#℩I{}P!i< endstream endobj 76 0 obj << /Type /XObject /Subtype /Image /Width 712 /Height 557 /BitsPerComponent 8 /Length 42589 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq(merD1ޟ$L!uCN?QQxJ f&mjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5LIcwtI29+yͯH?'?ƕ5(^E@e bE4S$D 285b>b|:.߬X[\rZ7(HUAǭoWj?#S98$:Lu|G&ZwWH?2ӿUi_*z(k#N7_TeH=-;x+Q b|:^ab$Ѝz}y!B5][df^\=Tv0=zmF4"4^­R*(UT ;V:XK \ܰ;m);?~AZ*vn;s qN.FV$kE$p0pɌ"P`QIfş3lrI9sO1Y#>asՑgn1?JU%>l: dU\JafVy'CQo^[jೀIn1(z'3qJ.t᧘`p:V2N$* EY62)0})Z'ce%T| ztEyodZBHC,H +0Q3ҭh\APw{X]QJp ]NI#ne\y8R}*dYO)nO tI K+s.+*ċtGw,Y7v8o4[x Q%p㷩 rEx' o0!y $Muc<+97,>$$ܸ򰪫Crx 8#Cq#/N d>dMETQEQEQEQEQEQEQEQEQEQEQEN0>FUu*2B(3eW p?o~YL11MH bKV-mbEŽI=I5暲4VF!%R趭 }]#BK\m[^S^=å ( +uמ>bЮ՚_tM<JZsߋ?Zv_)ʌ_싏"~g+j,.Tbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/>-.xG/8'+^4X|7%C3g矖 y` I='-QR Կ罧Mj_o&-#ĖżJќ[ZMAƨ'dnDE!OBI=}zT(qj_o&B/i}]ѲX?ب|!q_j_o&]"a 毤JWpIv1ʻ<}#G"\|Ch2{RiW?^(qN'Ah[o$:}>?¥]7ގKyU4$3C{F~@* t@)Qv!%snO G#rOL)|_.~O?F@$_IZbQUpЂҕFƓ?j?4 V ?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&\f tGg׊Z? ?뜿-wt}k,:݉V5՝pQDpQ]'(˯f_t_^uמ>b}qOT"(((((((((((((4sBJ$ndqЊmڻURR2wLYk}:Wp**?7ڹZΠm,`Lsk>iژdڅզX<:!n?:UnK3.47V8feۻ8RS]B=Ba d9r,K.6ʹWg#$mnU[ݟNwbС$p+$(oA,_J&a(P@O\G&m]b9%QO'ں=aRD I @qX"Stvv֖ő%FSv93]}?kYuZLβRK$k mVf/(#aǭ.ZK By~U&$l< Ƶ%(۳7.*[B6,Nzz#di-r9'oi)ʂI$g%-Q\g@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE@9[V>!\m[\7莼WO?;>࢈>ࢺA_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARM#G#Hۜq2}NCs4mNs4mL C/J2s>+,Z+X 9Y'o?zSscĐ SJ7jYLйaYǥ\i^ z2<9 Yr zZ)RṌfwg VFGder#X\*C#+dpH#Aʖ2G\V[F7n=0Nj%w+̽N;覍kAyQ; BL**ǜ_zlǧZ ĀӠŊ((((((((((((((((((((KDr趭 }-Bڷ|1Gֹo?_xVwp}E}Et.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRL[?j3ž&)B=&-?HnrNje\³hE Ǧ;U}Vyʳʱ\ sVϷXKfPɀ1Fv1hmn GhݸN:? ۏ,bQ#SQGn9s[VZ1cQz܃=p*` ~zڇ#t*1P%M6EnQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEih_ջᎃY@63ïlV:cJ..W8C((q_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARi?S O2tE% +^[ kWvHHK򞿍z5s::{S3NGf3ƽG+;3WO0ُZ 8;7;Fs]ˤ\_bS!Ppڽ9֝6q-6ehc$pϯJXڗb_SOaے1nW>d.O2`v1QCbx(hEwmⴴ{6yчۜ#i0\PMÓK[6^"*K?յt9@?{|Pp{OPno=ͼ2T {4ZN(=#f?/^ϤtKLldO|#FsSOB[ܛn%h~B9?]{sO~Q akΫ%D 1eG'=17zTN-<6`qtMc*Qd}}'g(O~WO=Ǖc,Y ÎT+-w7^L@ 2T }G U*QS??G/º F[[4"IFټ̆$`u&E%6[ch# לv)}~7+sO~Q y:k{ՍR$Hn#,r2zw^Z$7!A\d}s1O볽/e\~{>߳}}'g+gK]n2Gq5-Յ^sr$`Q?'4Qo?b/^Ϥk%dR xZQ[Ã#9FŝP$M+MXP#mק:kw[1In&2Ŕ6Ntʑڶ*G}'g(O~V>%an./,0D.ʸ#M1 &+*PXz{C ??]=׺Qk)uQPEade+4%œ=H/eӯq(2~{>߳}}'g+y5{gէQ-N߳}}'g+ro5r-ݼ-y(%ʌ {u_-Gݺ [pNt\k={`I >{>߳,k ILpх-n?Z\.L"uo˜xP YhWW~{>߳}}'g+_EOkrNTdx<+. ki>а*tG([;F1ZសvѨAIZI$;>࢈>ࢵ$e^{//BVk|E1EtY>*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:YfEfnTR9c$m9MsJkFX于7|z}+U]s0 :sMX7jQސ?jɧ<FkFi4Z臚0v;PpwdW_#yx ^+$%RxYIU+)ITk3}\5@ "1#99\j fե'ͺ6V ӌm>p;yZ)G1dɌc>R좲iYˡöHTqtcd8bD$RQ9^}y ׃x"ۻ#~Lt壸{Y#GMf ԩ{.Sz3*ͩM#(AVܡp kǵ ;9G F?QC5̶-d9cn{'BhԮ#È&{ dƢPg^:K*᠑5 J$ݴ H#۵Cxt̓D+FʜB;@kK7%kVK'|P*VLM+-pBϩEWk]4,ƚ[Y!DbnrGO5}j'؝Њ(,@u {Y_,hB:c}j?NQw#R/E C;EJSlhkt᜻9wfyMk+_Lu)WI*F8AzQl!6ݵÖϘ#UlcF}9Goy5R*w?xs(;>K%ƈdzzܼp(JA7]fg$z)}Bw{gޏ;3j72 H~Ev$‚z۝"[gnc0İUI 6WZԡ j/j2;F$^LJNx9Sy<Ӟ]ESw(<ی|>A;E 3?=} WG3jw27 pAsU#0 a&h)u3>Y co'YSX(%klB=s#ۅe?263/_t;K[VVa*r A899\}K3gI32rpu@=*kk%dВ;~_`Ga ϱњ[7W h68*;[LjS1cBNA 玹 :(;ھƭ'YhP`DNڄn!`p+0}_@tjkEhdE pK:O_zucJy$Xڹz*^_Om#a-t!oKOƲJzŽ}jh"[5+YV] *@P a`TQi7hu&Y$q,k| Mۤ-ɂiH|vg9"Pg{Wb,KյiȊPb:O_z4UE̒,d!!fbxQ,}_Q}?=78hK!BQ$ZD>_{6B!&5urE?CA_c:嵃+x^*z~5%ORg]qFrww;>࢈>ࢴ˯f_t_^uמ>b}qOT"(((((((((((((4ATtO}c>YgaOhƽRwPےBCPK}sQ];[TL Em%̶ͭh[2?^H`0Ǡ5/麥]E)Sđ hED>LFT9Vi-n7M--.4k;cBqW|I $?ֶXClRH%iğּ4aI$~y[` ٩c pJzh[{PUvPwm \Ϯi0E7A^µ49UdLkYCA5nbCSZYٯfA=03{qWk*dT ͻ~8?j׫STB+WcO`+4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (: 7YKOƢu_ h ( (_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARqM>iڝM>iژ^1eH W|E\b鼵'W|E`jq߽|S7nELH83kroY9ʜUB&&f*p:k9e m=Nn/.cS2O\{RװDbgɆ\cA檔_VW7qtv3{ULZh1LH?1Nq j{JVs I( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (: 7YKOơuo h ( (_y/ν Y=|]ue _ꍷ۾mG JTvj_ϭ?MY}mh*%wghSU5QEQEQEQEQEQES%(|$kl ")|R$`E>((((4ATu )oͩoͩ9eS^~xQ~'oo-{ <[㌲ >|2p68#DҮs=w/Ӥѧ(3HBh2no,Yͻp<09?A [іZ$VR x{֫VWE 6X1߾O^ cSjE+tFqמƺ:İ9$jA7'Z. 5e#EWnQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEu^n\=MPKAr_7wP}E}E2Y=|]ס]5":wOϦ1[prހg'qS~(\{tyX7WЛ۶8&Vfe1t~:gӵQΙ]:?.n'@Z?EITu:< TqWgRVFKJ{|n21TYuwI;#z4YY_& G Q͊쎾LK"%GehH,MRO?"At(vAɀi~]H,Mi_}GQ.?Eخ90/i#z5K]?o?&w#z4YY_& G Qsb 4.YY_&K4?/At(O?"lWdF{o~EY<ɍڤHҟwSOcỏs,PEۙdIį̤NqZIpy(21-#.6^u%|} -K}?/jkRŲ$ȥs岎2N֦+/2 ţ\2D:#lC 8sj>_agaj_Ϸ>]{q'bmdZ!\m u5ul;cͬ"]1͑cݒ_@Ϸ>G>oi^iz`gXc^*lIgPP5&yA+f|㌬Z_1:p Ro}Ə-K}ۋ K$KGS:sQZ̚t!7-S;p6i${2?/h_ %I!LʊP\HÖ,r=*nw;M*#ʅ?n֟gaj_Ϸ>Z]]n[wVXtdHTn;2Kg]LVsn?(=2=j2^6L Ro}Ə-K}đF÷N֥x$GAYYEcϷ>G>Icj0\I"'4fp}`"^Om v G8֫kԿ_ Ro}ƺ'y-gT&88%ݱ2 <6pQ#2J _ Ro}Ʈ]ZyvWWB|R/#8[\O8 N|,8' RU{[)aj_Ϸ>V.>iznfg.Jz6kk$`,8!cŤjYaj_Ϸ>Z]\7vZ5\G.i=u{+NP F{Vg<}XqZ4aj_eEO^2N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?&w,nl_z}io5^MN[qQAA.՚_z^{//kXB-1SGmhkoo"e _?_ϵ7G/(bI O6#]I q=Oj(((((((X1J8Qkk(I=X(((()CKHzGK, wE-vu4$\[w9A5KJhu >%fu HںH@dqSI5]\$e{itij2<ʄP m>;XI$ʪBN *Ԡ^W'oKclOBcY9eUp*rOLjIXI@8QWݞ•G̈n5mk=f8mz]GPFKr#ͺRy㱮}JJg}cdq>s}ngd,7bE- 7rA|Dz[+Uf,~C/:W%lѷ鵎;ism)]nۿRԶwo 1ZY4Cw{ bPW6[QV !vuýKI`-L[#3S[H{As ?.y]#ߜ_nsJƢGK^Dv/vqU[@X:),%?k&tks,#Iq*Iv>S!lb{+;[660zuE?RHܸѮa-bH68h~m<?@` â{Vt6ͅR\;eW(P>MwMY ēmUQK4tlS2A8l8`TQӞXvG:DD?Z)%eoYlRWwvRK1c#j͠郫3HŘ67ehڱtWdmE6gh/=Ǚ3) |EX]kMK3k4EJy ,Ir xY-HM۞(>lREqVef[-. xb ]$v$qXTSx:mfxik:;H!w`܁KǥE1*v1|? ¢ԩdmEm0򒲱cԖ&/49m6w 9z{zĢ7mK/0D`5@G' -\U[/??ƏIlh !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgjp:n䬋37uo S]4ƜTc;>࢈>ࢴ$e^{//BVk|E1EtijiAk[x^K[rǴ9Yk7ZiXE3BO>Yxmr* eא4H߽R87t'|TՕR +J``C@2O xi2h5A^ΠZq?W1/%Ի[ے`L݊9Z6+E0Y^DdR<2U46M=.`4uD>YS=밾4FENtVr$T7zFsPi֒I.ۻ_4gic/Cn U,'${WU|Jf6*I!oHS%y'^JƊ 0[djkKW[:>9>~0id[ .=Md&8idj2VI#a}gkp#'V6qֲePA'OFJ|h=!Y4&V_X>láԬ^`) (((((((((((((((((((% g/z_>n\=Mᮧ@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*z((((((((((((()CKHzGR M>iڝM>iژ^1eH W_?Q5{_4-qo*|I|5V'dy1zVZÜUԚBڜ}3U9\ u4&oRE@֪ZD^F ~#Wk7uAERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQExKAr_7C/?4AA˯f_t_^uמ>b5nn#$Oͺ%bDVP>#PnK3mzO~ ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRk֫s+ yb(@yݟ^⻉#EU(ٲ;9 zbnfEO䷊;{g>Ґ\qSfp zTH)Z]}3F l^Kbx1L1 #*H'8.&xKk4&;O|i<.5{=`Q?]%X—S*%PrUӭ`iv|352Jn"PZE/ʸ#Vwo"-r/F kxzdH;j9luGbF6wfϿJ‘[z*[UN ';Xɭ>[bq/#W0zeXŨ*HHM$}XKNʌX8Ssp{q+I4qy2Wnl¬_7"y>4Xv ׯ?[}b#W^X?Swg[eR̀(l`ay{9FҚ3C(8݅ uҔuJ R?G#WE`t[VqOL'9fM-N.Y V$l =xTU"TW/#Ʒ9x5{=`V15gdfeW˴:٬厬g RG(jz}𮪊+G(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X= Z6sFdC =zz}O _'W RU))K'5H e^{//BVk|E1EtY>*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:tZcǹ+8rO?7M41m$n?P׺m‹+D"Epr>U]VMb]C(FFSTdӺ2I͙c K/\h$yۊCX'XWg?V+ EleYw8'ElD+61w'⤋M፣{fʨ bq*6')7va$s+rm1<PL=<?uQ?/k.2ik!oC XmAuҴ7K.#@uQ?S~/|3~kmۿ:9PϦwRM"}ב G=VCoǦ3Us,WnD @$& ؟_ʚ]?adrqiDVmgٙ`ʼn'9LF$p?6'bq*_Saet;sa* # =}7|;$1Lh0 ]TlO/Ma).094&駏Rf5m /e֭'bq*OEae6Nl?'?ƺ=؟_ʗԨ/= mG?Q*k>9p~chaA8?15O/FT}J/Ϲm6Nt{Q?R0sl?'?ƍ]TlO/GԨ/= mG?Q*k>9p~chaA8?15O/FT}J/Ϲm6Nt{Q?R0atƆ&V s?κmY6b-%/3}ι ?]G;z ( *2Y=|]ס]5":k\SA=Ae _(((((((((((((= -!h:tH: @-QL(jIҬI] 畂D#t.T jQU?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhפ+SujSt,qʬr2p3<7 ( )˯f_t_^uמ>buX}9 =@@U4#'D7r?UV(((((((((((((= -!h:\ZJ) \SFO'ѓi(4dJ(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒM?]E*7sQS˯f_t_^uמ>b}qOT"(((((((((((((4袊C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (+>7_xuM?@pQDpQLC.՚_z^{//A?Sמivww:ܓþH."bNca}Ƚ=+mr8M֠hk}2'>;koVMk+R@$?R+t$:X3ɥ=5f n*{ M%#G (˅u-~sU_p[.< |\`=q[kzپg bdieݤ}cm|qӷLQ s(:,-a" íKÅQvW[_?:QEQEQEQEQEQEQEQEQEQE= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr먿}ro\x:` buמ>bЮ՚_wV_)[O:Y*YO"Sp~Qj_\6O*-QU~s@۟?>s@۟?EE`pTQEQEQEQEQEQEQEQEQEQEQER4QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UoA?ɿrtA2Y=|]ס]5":`EZOkz򇐲:)U'9rdSx]R++>o"+|sw=SkKMƒM'>H,L_#k u&QZ@LpWN+?EP?EIQjvN# I R:V%`j}CRDe08;tue5]P9JedjAV A[/\!_ ]d11?~?_? ѿ+ehF_ ?rB.2?='?8/GA A[/G$7ls]d1uAQ1??:H4o ? ѿ+ek"# ?riO= ~AV A[/\!_ ]d1{LO~!p_ _ƏH4o c("#bcth4AV?EG9G!_ {s#F_ _ƹB.2??c(CYj[^E4aI6_):z,>~c+C"?/h?ة> > X!bɻ$cO= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@aly>e)Vt;/EO@ ttP $H{QQ$GV=z(((((((((M sJ5JKKYL!X}>EQEQE= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@Ӭ:tq[ hG/B|*.nu>0ż|q'Dy$XH ~C_ zWPݼ gTcd3c5K< zi^&JPPsȩ+3< zw:2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]l_-?ֿءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_u`o$bHw'lw?ޛ(77~fLVSVQKY}(}*ءƏChbY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC.?ҹo}x:Vs~D-Ͼ@pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5ޟdg+9m4lb6횣i` ̷w$I,_23`qJ_[+m@t#h$q> f״~,1`s횱{k[s,Q('>IϫXj{o Wlm 4çnuΕ+( #$D v.}K˯e=ߞ  W=>R2*}aN[r4m\05i5]#[X8JM9%nzqRi*RmY~$W0Pxڲi&tȷtI^ lmnTzU±t z;(--n2*($n%LoE_QcsaIu4`'W+ _\1Gg#E 2erNgxU(tF+#Ԯ2cԎtOZ;:+ܷxē< m.pHwNxTmAEkF-?kcϹֶ~ZU.nAUoݱU'fj#\u>R}0vH!qߎJ# JKkah(((((((((((((((((((((((((((((((+o¸}x:` bsןO#?:9Pٗ4ګ}/ڥ?yߋo혁YEP>=A O? O/G(OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O?*nj_Q @?zU{EU%yѭ—6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o)W.7P#÷[?Danc[ZA#t}E:!SXdU 1(9H@4\h1I*dWcyk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~TQ]yk@ݶmj"8(Z( endstream endobj 80 0 obj << /Type /XObject /Subtype /Image /Width 712 /Height 557 /BitsPerComponent 8 /Length 50425 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"(((((((((((((4ATt yJRQK1`SH *[q"Iۍ~sTԦPaR^kgQČ9Ϯ}J{0+䜟QF_ƙHj6*̨He֫akl[ErY%UVpiQ"oʸ8r,]C]\UWWVf$O]L )#?'Ble_`'TTE)8ꋣMiډF>\9S.d[%x?lTB cs;ri-7i$vI}KfH>[7mF A,"䤡Crͅ9P@ePNO'?joZLK;ߵq~P`]m l$oS!*Q lV=y^F֧^,Bk{2X֣/B nX!RS5E Mm=w785 9/}"D,A(޸=p+6Tkj[[_:KFBc+ZVo-ս̈; Ÿ~9z%'wpU:F4Ǹv̄2p>Pq7cG7x"Y1IU |EJR[_$RGk:L/wsoJIuki˞O6@T9l@X4S=7CZgPxK)n5 a{I!A``@j¢SeMp :c`t4-s3Գ1'sR+[_=4H\,ԅ-NO P$R[vH#abQOt^F{[m G)O2===ġg"YGem`QGԩ?k#hm+HnA̒3c   t-EFb2qdBPMPAuxVtTŜ!E<[2;;Ym~tJdB71Ģԩx{Y, ]˖8VbzTk}$ #x g{z}J?k#t6689]e&]-K7ʕ`IrÁvjj\~S$7[FHyKsu~rӖU7bԴن4TN8`GRk:]{{BKʼnI-}sRx*O{dk7GEexXˀ;G$%mv]\HIG,#+S=6%@ir6+#`r`gߴa mvi1An=Hj)}NwGçEPU4[\6smrr5ER%އ$0Dm.]29WU8j6@"0-o$~P 3.W$䞾E?ûڳQemh !Gxah_/j+ZTIZ$N[pQDpQZ2Y=|]ס]5":k\SA=Ae _(((((((((((((= -!h:tںE1FR@*{ %SͫĒrj]-FV0&nHPvt?SRt{[,"2)g`yp,t#n%N>Xq滋#LdY/KAiW zEAywPƛg4pD@{8)-oq]Rдt{k%K^IǠ⼷A_#X?׭-X-mIāT~2+ky[bl,f66_^k®HG9 p_?&-*}հHePv2|G6#ƶ TV-Rp}s)!Rbچ1?.xsU˳Ԥ~U߇cVz٬*B+WcO`+4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (44O /rEocah&ڷ|1Gֳv5IEwQVC.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRTBO_%ykOޯx 5+ʢ͸ncnq#jbN0A+{uJPɺ%!pӞkE$EǼ"1a$dY0xjTFi-drBQx̌]pӥUK.Usfr匮o!|afS\g[5i$w,;㡮 re)+h9mlQEyQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Z'sEncah_ջᏺ>Cy|4 ( +uמ>bЮ՚_wV_)ZzV 0$|RRoEW.?VT}RoEA$ T'Bp} ( ( ( ( ( ( *)bv%DU,4CscuVR>@EQEQEQER4H:  }\:}\0'5 *cPҐޯο\y2kޯ,Ο-޵9H?peXF!\m[\7莼WO?;>࢈>ࢺA_y/ν Y=|]ׯ5m#Om:+}}4)!;?8 z7kwF#I#!AMZ9ٷ[7c/\qU|5MxrNhh#%I(@L+?pBuY׏j4^eGOZ?EITo|;j&t,gHgUTqf%/ާo#3k?|憎>o2T!ϛLUs⻯u?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_w]6Pe*'z 3Hc!JWkg8QGČɾ2$c g9={3_^@Qsݘ'uF\ۜ3|[}&ho_Sy|6D[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6מLO8ls4(調ACu *:tZHo-$/ژN9d~qޑq]ưNPqA&2G(jz}OYȲXyv7yWVUXK>KDF@ rݑkhג+*n-D T.r@@Ǹ5{=`S?`Je/WfEn;u3R\j7ej_h/'c/ R 2N}cÒ5{=`Q?ZemByZ˵$*Vq_#;M?#\@ʹ5+nɯQ85{=`Q?Zzdiiqt*-]UҹwϲI'۷#:;UGY]}ĸBױF ЊatF2Y;ܐ>qAg%uG#1f[Ԭ]y4ZA^ ^X?Jѭű,Fzdcڴ<Ԍ ;v'W[uѵWk˔rʨ$v}rm7A?G#WXJ)(2G#<ҳ.Hq ӣ׀Ns@ zsUMg'6NşF ?G+xSzzõm$k=ˢ RKYmw}v+CKG)땑#kP\Tz}䖣Whkh;Zː0[i\uǠ1G<i sZb{ܞHZ^X?땕b7F9 u cWGu4 a,M:*1`T8kMG=f(>$D#<]\Y^]QNF ?G)^VmZIK۝vD$=TqրS\[┩;rq$g;Ӗ*Sv2ɾ+gL\Ojz}iwXBCI>p{}Gy<[[̖0,mӜ=**z?O$m{ ?G#WGh#wJGNsth%UKѽ;3QX=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=b]?VHdf0!$ccZ~L/Az>ס/YAq Vk|E1EuW_y/΀;kCwo*h-0b,b H=qhvvT ÐpkV]ffH݈Tܣ.8;ۚȢ]?c7$۷~qJ}bTGD&+%xj),_sn=v+.#IVv"kd 񴀮q~p~E?lMY\k>o(mL[ҡ9 PexJ(ߋ07!IK#wO@)HGtlt5E/P_Ňs}|I;(wcxˬA,)L@~^O5E5~,=1kVZr.ί&ʼn'9^y4Ѫ%]8dQG(_sY5M:;wM`PX5<~ qop8 <_%K7Ȋ)x.KkQdAV\{}*1YGۑXSxJOul'{Yv9]j,ŴĒ G 2 XRߋ1Yw6VmEkt9XҊ}S. X&`܂k>G=㽒]c03}MY/Z)<}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}ke&A"vhxc!\m[>aڦ 8]5":+f_t_@66tZۈ,>c|$`*ޛjz}2k4[9y0x] ;^gԏ~9zs7̸ZwgÃg1]eK7o;U;JP9k>#jw%sF` W8kt;+ޯ|Um~5T^V+m0;R5QnϽ(IŸ8|VFIiE&3FfY1$p>7G|"{Y+8^?<\?v8E4nyV_>lþ֥b5[QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!\m[>@9[Vz~5Cy|4 ( +uמ>bЮ՚_wV_)}qOTQEQEQEQEQEQEQEQEQEQEQEQEQER4H:  }\:}\0'5 *cPҐޯJ3Q5{?4bЮ՚_tWp̿n-nLJX{H9#mU9.(Ikv/*5Og-QEQEQEQEQEQEQEQEQEQEQEQEQER4H:  }\:}\0'5 *cPҐޮ_mOt"HaY<AWt~y'=FY'ϐ 7^˳"pbL~c?֘A3OÁj9?!ެN;jN9#5$z⌷c< guws֓v #e'B:;oB6fZ ǜxy2>rz=ED18_NCC|_zOE!7/j>rMu"*HC(3'5 ]\_&_*H297;S|DUd( c94='b3WPM,f٤-R|lOntǂLi-[xH}йN=9>t]81Aqُ oYo'ע!(E@ nڜk;e@fvMK>/S%Ze%\2.V!k8۩o?KWc& rqqisoȥNYE M&n+gl :wu]mb8@-Ee}oh __{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_[=SwOrz֓?k7=?UgVzQvGuQWa˯f_t_^uמ>b}qOT"(((((((((((((4ATtE4N'H|$e9WhU:^jSK{qm4ff;2LzcҺX_0+?z_%|z}ClvqJE)C[+6ݞ1K#L;9?p5ޑiOFS06LԢմ/I9rOH[P!|Oҝ8r\9>"'?,3ԯcmϽHG5ǒՊ\^FI ըFOXxbjk$'ܓ[x.Ȇr VzVc>abkZ*U(ݱN[T;MZ, BC31zUO^' #+ _ a&n3ϯ5Y E6QJO>GWn[aP{5Zާb4ȿ`~F3ׯҴfLkV:sЌ;S@Q'uIi6#{Սp^lʬ>uG 0dvA9.G"]^;GCK -?QKO4$3K' HqLuE5{Iw5 dVȹ-9'K{<O5GCK -?G$`o|j(i>楶qinC p8zT(?5E7qi.%)+r[i" 1$QAlU p:EGCK -?G$cQGh({I5\;nV$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}ΏO.o.GGL<#_j\!ER趮?ֵ8V.MwP}E}EX]5":+f_t_@՗",k\SA=QEQEQEQEQEQEQEQEQEQEQEQEQE= GR{x^tUa6c@|ZF-ܦ) P{]?^:xoͩ/ ]MI,gUt Wm6̤Zi࢈>ࢀuמ>bЮ՚_u:>5F$¢hՊw=ElU{U Z$' @Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARi?S?SsPҦ5 )\߈!8ϒZ#"鼴 X u:⢚K/,yc$ӏOi1- NI;ӽkF*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:tZl?7sOl?7sO2C/J@W?z{;ֶ#Z1I973zWЇWFvX]\F,K 83:(ħ4?fGF⩲xQk%\#G Yk?G N/n'm^8L`W~劦=Pg ڎ"r(Hs;]]Mp˰^**{[>=Pg ɶKT!ĠHpy##t2bI_* ^3+5O1p~*(dr= FAL6~P}=X;N1R[L\tm>?I|tL.c&)J9( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (44O /rEtB\m]wP}E}E2Y=|]ס]5":մ[[Xn5 He1ƻ$U`#&eU,$M\s`do+;#)'šVTicI 'g+fc+5ʡeW }jt;[2 70^yҹK;FTh >aY rp ֮6:-ݽZ)c*sNi5..[[.*@luDZ77Km3=32(l-yVc۽J㷌ɴrv3{j3\K՗YBkSr2EKè.OT6Z~ `dy_Eow;[fP4&)$dGFsJ~֯9cImt(bk˓ Y8S;YEҠ7R]L x`A092Um,,[y,Vt_%v3pHSVXX -DPÐ :vu]{V WKyX+m`k) htȤ7$xb%Xڝ]H..!CsK$*NW+/+>n -L%y`A4MW;X.u[F4R`2z՗Y=i{(cF-8-N>C늟]YRŵĢC&}UʦF6?C*9=g { TN3:+5stvL혌6~{uZHQ[Y*:H j >z2A]OQ#V_YYqǭZ _^v@~3:R[WV}-}6UJ/˷w_{֏iW|l5e=gUxt]>{[V\T7{l|M0G.0oUs8 )u&ITď E *bnF-YH~a - MYy$B+4&Y8^NzU-eFRƥ<{|Q3SxȦԻF:hh5e=gQ՗XJeB&K|obqP >ԥj d1| T uo?C*9>In/]qj&1hq2,d[%p2Np+h_>Uϓ4aƄ{.NyQ*M3-4}.5 %N~R*?Z[-O7TbV4^K̐4  rzVk%XS,ZH.HZ50 o9ZmQ)47C(jzC+ NiXdbבY<1| jqet}:.Qa4ݝ6u*nv$ؽePF*@#V_bڵi2)%!)XW',c@<V͉)H 2d9ҔRncE "{ O0*䌒@6-D]71zN=v:ёQ!#,nD+WHӯ b[(EXYn#vuj/]&Р+\|щxj2OOKȓ`A+fOrug#}о[{;x#]>ǤY<+ FҦjԟ[ _YY5e=gV֫1~oF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZ̶ib F9B==S&U/rozM;sVOC ( +e^{//BVk|E1EtY>*zm[y0@)ҕ'&m@h3[o?g>4f ]?.T#?M@Q@Q@Q@Q@Q@Q@Q@Q@I$C8O%2HH|N!B&*s˹{4}yƫwO]MtbY#i84nR:rNrk*D;GA.台[/x oʃpVW7H]n[yX>O=&=> xDfg=P 0r1—L%/^\'ƺj^•ʾ`Ms C>g,Mf t8#keǃDp=UTgRSnU<" 52F用o!P͍3J` T;Q &=&y?C%6-I47 &=&y?-CcWZh Koj v?H eo&Zm[5FXHީ,6Ze HO?3[<<ܿDݭ# 4*8\7M|>ߦ >§òu?kό?M[|aio_G7Qa}~%6->/oòo>0K4mo[}Io_Ge/ ߋ1[|ahL|>ߦ >c_]c-ѵ o&}%M}Iܿ.~/o[kό?M3K~(|>ߦ =;/]v_F%g7Q}%M{v_r u"lEYOb|5kfkIOcxkx*wP}E}Ejd2Y=|]ס]5":.tԷimKn?_&oUcuH3 j\޿qb͌C7NA֖FWnk\_ݸY>n?_&Bz^Um-fHrИp;G>hN@D3ח_ݹY|pȌ`qwg7mߝzEm!7^0CT Qt-ipoU!*' wmX`"~FT}Ikwͳ[Jj^>ؿgp[ >zZD:usbsMm5ԓ-r\GE Eo_Þu߱p'-zsUu "Q6)Έ9\2qېHoU4E/UNTO"SܖA67RI/8,8Q*F 0@VշpY%As!Yv qUŚ=qne}m,oJ<9y&Gq ?1@#;01Z~}>Ehkoo"OVSOr7bab噉9RE[C}}!:X<˵@V%;m SbI O6#]I q=OjO渍$#e;@ e?w5}>*Tzph/畿o"WOS>~?h>˵MtEQ_+EW y ce*?J|D]pWt~Zƭ'\w7L@pJp?'JרV ``3qWC`mfGp3_luKKGo%mU۷KiiIm孥(Ea#AzPͪNih&xpq09>2^\Y+;i᜕ɏ@G4r_3lM#mPOSTMmascwn,;G;@q\Eb!Shh.$b'(Bg~ݹ>j1 X(kAwwiV\eCu[~ZFbdaFeFpIb9(#SQmro\mKX(,DS_G6!n|ӭdox:AA˯f_t_^uמ>bPhgmHUfGGcS?d?oZ#vY`о́xfPǦj񳺹4Wp(\²KeЛM+5TrllddlF(>t[:;vbiƽnկMB1K}C@.qf;{4AD7IZ#wB641#;``8rI':i$ 2ź`)W/l汒8rbF#={V8u4I獧φT2<[Jg_xH?L|Lߕ :;|bIKduPK,I,cT֨ꫭjg7}VH&H,:U4=JÛmVxJtliy߃ZU9,0W++:w!p/pU~r\2O@Ov{m6LLw_$co5ֻ{cA֓{mYJsPIK$s.+hh|r3¢U%#_hSE ,Mt2_%=UEZC[E6Sjc2 ۳Goֻ{cA֓{mYJsW5I;1e$ v 28X꺤${hINB @w.nvr٥Ĉ:I`~GE_`6Wswuۋ4qG ]VA.PcSWCۛSo be͞wƂoL2?vNu^E&[j̇Ɉe^H'h8gj[ko(E+շ UVmZvo;A,[ÀˎG#Ұ tabadfib9տE}8[2{i*͒NrIh:7WV?p$9QM?JIݗOKXc͘U uF՞TѮԥf3Bc9 9b23zѵë_l+7 p%NN!o!8TH2t)GaުŤ\M{hnǔ9*1\[OGTޱA3˵g;cwL5ii-XmhK*U0NPu7e¥%8L*9{U[Cyq{˻%pX.vd-/ȋOֵvM2L/*,ve ~CY=wwRJ8\AZ= u#AQԃa6Sa6桗LjzRԚ{?wF5)Ԛ{?wF5-Utlj?b*[_I$#HC‚ 15-nW\ђ U/zZ[˛P_HLj]u pA[f'/Z νͪdPH(ALmps8PI䚞'I!Vɭ__khྵ}pmi[:? 갿oRZ8k"f $z4ChI**J`RaAV[mf×iL?'9q[Rs,^l"Y4Q| U'pި}mbW1r^UB!K{2: )?./|:,D0K(IXݑ>If˓Ki]OiSIftFDʿqʐþpG!ӼCh[}mІH9~Gc㊴ZlZ5լhBhZ@'5@u`>Κl2B#bU$Nk<9Q![+pA'i1(åZH5=2NcdY.8ު ӎ"/&i U]d_M H0F3;(;;[04H5 :k6]pk*mW;ۦ+;Yӵd^NkXRD``q(C9'/͟#8-ykp ixO mX_kF`L:uwKdM&ȍY yU|`@':UK(5V+B=f $C*6H@RZ]Cz]gwQeW1ƗSLʶs)W mq7rkOj쨡iz_`6z #1#$uuߦg_G?7_ӯuSNO㯴mLjwh]J *Qb9':QzαtID2[[_D!° ]ski<9zV NX tI=\7$՗藦IRthoMA,PCzywi$u\БZ_KSj`LX@iC`劓+KMԦtu+,>qZ4Qp9}MRǥd DeF3XP1=Nj+M^-K][]+1HdTLG-UK4巈Z݈B]iERkڸbK8gPÜr@k:TL[Kui]5LT0=-ωᴊ +i!m9UCܖ#a@XۢuK- ̖Y30  Sݽ֗"&"5̊:*=3bد爐{;;J#E8 :5@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@&UoQmro\x:` e^{//BVk|E1Et2V&2!TS[n'm'Z|I:llp0#+,ׇ Lp*&ôcXr|.4ž nIP~F My\j663K9%UgyֹgYO$VrC,ZB ¹-OMY VQXFelkѐr{uZS{'.^[K=Xvp9K;/c:\7/(,UDzM{ڮs:ʥ?++PoAmy9$G]9ƐjwE|i%1!Hb=qnqU/LoʙԶ]>d1@} uS#ԕ̀PF;sկ.motyP`yl9nvzEZK[ "pKg`rZEyo%c/ ʥȬ]X͓&\cgzD\_V;)mCd %[n+8kVS$=H3ޯjZ{l/o󅵌6I &)/<,.jFe+27.wiWC,VK{gr@P~cg}Վoڝ:^c(C31皖]%ikLQ(y OZ˸G]O;W!-yNXry<PiM:I#!16MKkq XARr~}mfx.m$pV1Ն ֛Mm>̷3 $ u}k4PAz<9b2{aCa7,Okz>} K4<OQqRWbww+Fg'n 楧eB]rI VyTyh?G*Mt:XQcyFXN}ƞckQFyoh7wsΏ"NH̿wZ@4.biD1 ]ݗBk7_kKwօɂK8vSUmA i Zjͬ}9d\J@n*vJ6 t$izyFG}7Q3M6pGq o*y$dVF\rWդkei nU#Xyeޠlt&8V1.BOaӭ7]D]+h`mJѽA,F"&$mB5=7[QHaEPHzZCu *:tZHo-6" E۞-)9dȨIH Rio]pOS4lG\? ]E5>\oKqVe\kp_Bk$Py@.qE TnG,R ERʃuvZ|χѣۧIìxxV8}몢MTI]m,dA)9ԣP&䶖!ۜ)#:uE\K q hGC/q@10; MaE{V?3{+KR[r'}B6SvUS͌+:X:((((((((((((((((((67Oxun*7sQP.՚_z^{//A?S_) ( (M* Xa@j.dM/L&,Ug>4}mh[&mIx6`v ~(Q@Q@Q@Q@Q@RHu&{D3!B88j()CKHzGR MxE=fE0 6v?R 3?¬Q@dYۂ:>{ DHudT[cVOjmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@7 SƦ&˱\=s~u\Wῼ?΀;>࢈>ࢀuמ>bЮ՚_uRkVMd0#n;Y)T2ؗO9FsXz֝ĩ76ri1ݬ!%*r\]}z*I?L,,sayCH=GR{fomA'x>Xb3hsˑujC4wG^!Э5m;L6QuwX8ǭ^>\Y C6Y#ogluX?ؚ pΥUUmLql-v*"U:U:j_nj_C{}mR$@&?,? /Wu]*WX.E 2Бӽb \]u/ݥcp?m?"%GehH,MRO?"At+>lWdmɀi~]H,Mi_}GQ.?Eخ90/i#z5K]?o?&w#z4YY_& G Qsb 4.YY_&mkp^H㍤e&@X SUAt)hz\-đIRiʑ8?]7ұXnfƣ,oa4$C"3FTq 8jV7oˉ&\qFFIlAbѮJoG¬y!}<1 +BnJ:4hriOC@ԃ@F4Z)2=E E&G#Po[ ?UQU"#!E qiQT'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}Ou_]&UoӮPM17̘{15xs7 ( )˯f_t_^uמ>b}qOT"(\[K $ #jZ(T/l}}!m Q*J(?_ϵ7Q4p!rvʌrX ( ( ( ( ( FUu*HpE-RNɝ YJAV袀 ( C#) (((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#) (((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//ăx*zX<,$ p?!/[y=!tVg[y=eo\ :+3< z.VoOG[y=mR]B+em6x <Ym_-?֏[y=eo;5zӬ8'3ZC+e?+7-c>RT"~fg|W@Ot} Z$Hn}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏gi}.4}Mh/A>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?2[PzoGءƴ9zcV^ҍҫ}Mh?ޛՙvJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@ 4[ß}?κ0?lf5xssQS˯f_t_^uמ>b!m#$Ikocĺb Y`* NJ"I%1O\|jȆ]pd1 Kg5_B}E%iJ~s?^+2Zu-}:qA?Bٺ5;\#`Ҳކ״񨽀y#X@,h]_c7F\ޠӊ+Y]˅8⋫,u^{˛:qEpz+7 p9'RZ7Ί(((((((((((((((((((((((((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mc•~" qn?zMr>\;Ut@6v59GOSQE0EPZ4@ƃ FOv;G5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5J<5?p~UkGhiQ[6֢ 0*@;S0(? endstream endobj 86 0 obj << /Length 2975 /Filter /FlateDecode >> stream xڕYY~@ C> x!'gسCǘVќk#Vꮚ_w]iiHR?H" vw/~wq?ˢtp.3C\';QxUBZI,x;=6u(kYh-u<+wӕ268JhN kcjRY\}zOJ,]y&&9RUXQh܆7ô,\SL~& }xN0K=Kz$Փ tc&uي,'`x8H=E+qK`(B'k b?|TdZh 8V(&ь0SOD(Ad poƼI#M rzD8<NU8<(ɢմ[u`飪^Zi{/Il'VQB]eg;hd@fw4sӓe$)ӫ*$UMCI}zr8 !,ETئzUem]+z!AJ-O%hI2h G d2/ E1(|_#D9|6Į6^XSίӓLPeJ;n1izoZ\_D"dYj(E& ,3סmL=qFHxV`E7v4\”!¬KfqQr%6`)oQ(@Y3X`Ū f3E$'Kβ+Ďߣݥ('NLZ.]ŃѺ JNJA+IK1+5_L8vwUnF<7uI! O(AVfGk>EntL2D!X3ɘwazQWbmqy4=N(e!׆%pJ4:_Oe#Xxq1 Rs3; h3 sLV󠄅x2͇f6!mkpzt;Ҽ;Rʱǥg1Ltb#k/~\4q`4w",ΈRv%Z XGBUP1ľQS5Iȍ.T!XH.L Q"@ˌ@RQneoAOi)­smN7w꒾?˴T=#~T0/}U##z?qe#™ PWxRaQuc ՎdԸ2@$[.5<=me2*iv(? yOr|ɑf[VV'.BƝΈhpq.=ZjTk%JzjI5@:޸m Bk@+B:J_ Qκm+kWI4Zy9u~rI}\-=fmqil'iym(C~_ړ<+!;?1!cQ~SV,gou/_$OH4ϳl.BOwm0eyS"ٮwpqy4)g7[Œ%T8.[uޙOI8"e8?J8r&ukxF9'*IEZ,߯M?(|P̀q Lyi"wRu' =8CJ.\Q* endstream endobj 91 0 obj << /Length 4553 /Filter /FlateDecode >> stream xڕZ[۶~_N/C/yl\;NN:II)RkHJK9wFmæg7A&42~i~:m7ayo#m8û7 ?zۏ?xx|a&$P8~D>TPz-g`&r~hkv;ES\G&?`S@6tL=OȄ~wscO) <=zl4^nؕ+kHa0j:Sp,Wv%Lv}u~&/GJ?WMnC=oc㽂|#~W&D(8@{gs,}YP5Y+FObzSTÚ,c?雕q,GSezOD:`> {߾+`)c=0/ܾĢWzo ѾGEWjAN!JB# gvL GՎ'^?2U^)4c;4 >m0mϮmi9 #)# „Q}iG&vާ24^!<©#khI՞*~\SVxҲ7^eܸ#aE 0xlNk?_6(~^ޕv *2)YG' {N" ]⹪ko󹴝[PcGңՉIT\cX Y4p<5`bq4얨po0x.:Gg{.g?֓iiīǧG P$jsU>CwXTM߁ ,`~ݐԪ|S<9U5w='/m5Tz/A`Eop ~"vKtx߂U~~he>%5@d<8Ax-$vL]m=spj+_M3ܚBDk>/^zc;VXBOB~ڱP4Y$,;k;YQAx;+D%m׎ oނFФBM8]Na;df #٥A_<~S̬(||?`cZ+y '=CW~FU4q,[ONNC'sJ3C=w+@cBn hE{5~S37b;tc JQ5EBmjiE+`%NT#r5CDsALc DWt:du'] q~x+F1gMRޖx/TvHB!i@_0RpOZnSiYH% 79l!Ǫ*8=77w| s(0glld .2W[+B A} y\,$(Ȭ=,+=[r< }ˊ*va.J*UC3+bUѪL&P)dx#Vr0w9]=g߁s (2Y写S߀2NsuOߢ^]P|x&$N Bd-%3IDBQ&֗yrD$ʏw,/}uXuPٜ1 A)<ŻKA"`R^ '꾕r2\M끃%!3DGsSo`,́5AP-?|_\Hb m?2E&_cko2qԔ}Ab`!! aԴ`)nr#'av ?.UY 98u^3{@0YZx+ MHR[P#x-XEiZA{E/7oʰ]|>KZ\~ V 2K\BoQs1L2SLO "©~r}wKMIX䙴!lP ] NS ,vl_ GG]YrCq$tIRxi.@#lx,+_ZJ[!tV{UQ|׶f&:HAjn`u6V 7S(^(RetY-$X9%`K0 ǐxoWk5@EaS:?*?Q/C (.8 ڶӬ ⻝<_.=l }+걨hZ{2 D.^M{ŝQbH/]Q*10ǹ(<{ۏSW 'fE`ImJt㞛P+_Cp1IkJE%e+熢 H&iuo&ѵNLE FhIV~q<.y0-"B<{+PPY5s) 0\r^aX[y aпS_Cʎ6.x? s,8) i0H~ԯVv8Ϧ3G~㣰@ҏǩ-}=& XDTv0)ñ 4#lFڶ̨]˯p1PT<Ez2X OʎXqg J oM-{0EkQ4j0funGWX&. \f*3,2$ W) ,;|Eƥ )> BA(v@( #j,F :!oVs!8*?RG~%|֛WGdJǹo$N DC,$6O74a xYE8U3<<|ThRFA$#s]r&>܁@r M&AB+ڦ86tS#baP9MHjϘ/ ,E'S:v&vl)V%#%%Ow|K'PGLx:ói:_VC8rA*:1wXxtuG<oy>Y Ǿzd^1\)1piaqa"BQVw)H]Re@e(pq LsDU{bjzwGx="G Vr]oPRIl96 'p[gO/r&)%oR$\qGJr"NE2{#")`nWйC[Ow!R sBw1X:xwCc@9(1%ܴLΰtȃcw=, =ZtʼnyY3@Mj;:ﵴcݖab+q@:Ҝ\uSW3rh^Xȑ">&R/Jӡ竟 ;$hṤ|ƸXInBBūuZm†>%hJdx}5 &vxf\+ zF\! f#ZsOphۂ=[kk Rmt͉֝%h!8T^ªcj=gT؃^HnEST}\WrZ Ҽ4L> stream xڽَ}y #}plEgA^%1+4SG7EIlwUmP, MIjF:Nu`t(ճ7RI%6Aˆ PnF.F X8RF24m^ ~H__xr%MPrehۗ[|݋w᯷?ܾyu]p%x"Z_` }Q4x@W[>d d)[|MЈ H]B%}H{쳛Hoj V~d RP:cF0aߔۡrDxgpڮc5Mk7Ufujiia$TRjk\; (Q.;-{npȼ=8Ѐ h,^ y٪-N:dEy3T.궵]SW#d6f&EGBn27v1DDA}ɶ ~&xgA4ATa/r7t?Mq{ЖK@:q zhr}F RzM|?@|7)V^P-|mC6JO6IRgdnM?MwΘ<\ 9t!YqCY-cvM]Ffކ-Ktu3JfT]bfZ/-dZi?HhD&bfˤ{A '';KYvL?bmnp=wKu(MA]ٳ$'bvGZ%ؕ,$Ո Wx7%L͇vN_'Svu hWsv-&)/ӈn(ښ(87aH.@3~SMw,ݼlj*CeCz(nLn #)?95W/( MqN#=fiw֩Z/0*$,5U܏LA$2[ZؙߓLz:;7dXC#iOk[9wfFFd= nT(J[5ru)<"/v%m,\Y9݁gctQ.v5XT~fRvV:9!{O]{wm|x+|ȫ4yFL{^N{gSN$!u zC[EY.`&nia9TD595'ye̱6ߣI5;[YNʙ̎1$o_#U#*e(u\ÚTvL 9VLrCo~βW'B0&J7 FU!Q/憞{J,Z*,q ` ݮ69֌g Sx7?/7W,~c97[F 0_r$Q Ѭ {bp]^wU5J1qajr}+7,Tvsڀ~"x.>fp0wG&>áPf!k&Q9 ($b 0B;RMm[wZhBcaՑJ(+(.t ]3bö?E5uו>;% e Qwڊ=pR e8*ܖhP 37Q9hgxr8}Ljwg3>ÌTl,/R1QjtjMmmlR^ev4͐o{';WT2◺ 0vCXA(C O L:@`G!D"44jƘV+%q"qGFM5uh;.0w{?XLqOP~Y'RO"m= ,#kT/,x:B:07v$Yaf8/ P$$eIm P=d8]&Kn ymH~syӼt|lz),&:&.N\%nblQ& /)( Q4F h!rpir@b/-:.m&@r&/Ugqlkld*I2KW-z͔PqDdrYtu5'zc\fbl4<1\Ʌ0d3Tř'J6Z1kut' jMK(O=a$G\1qm̹i PT򧠌S"Iϣ4p/uR2i y9BN6#)1HPag<`rƱ(¿DU;;Cl0:JD ~$J* DNc!z ȍSo> YlU_X@#.c!"&5%~t,e٤He̾_C*3LC-b?"d< TpeG0rv3ݴx̱aոA :~rz&U.s'Aaw7u+ꃝ`,Ah#}]cc/ހNT:Q%$Mg0]D`wp-X :,?FwO(TFXp"N ~/=BTdD}AW9fR\x*9/H)?EDƎ9T>n<`I5ze@SDEإFr3*8l j+8دDյtJC-5?U -/*$6(d i槑 (Ȏh=n2|G "ws>! 9-^qYL<UI&t0 Sf@ v]]VʼA$*b̑CB<¡ qSPfq2v5H) {̀/nW}DwB _YHoݘ9?:FrjNBȌ/zO%%~T̈́/QD`"cG@yR~ORD/A@@$&OÔ ZJeO0OMz10f"T'LJ K3]X`7i_e  K@dZ1`$-eO @*@S?cғ`)e0S eC"u}c HKZK4RB7S endstream endobj 88 0 obj << /Type /XObject /Subtype /Image /Width 1370 /Height 304 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 30883 /Filter/FlateDecode /DecodeParms<> >> stream xw\'do{c[qj-8PAUjhXօ[hօ (2d! %ysOx&{i '5!@ua343[vjNῷ,^u !OAtwo|U([\j߾R&$-ǿHe)z !{]->?o!H=6HE >o5!54n_m徽2yHR"*}z%`W.DwinIAQ*6Fn ۺ7o-:n^VNnfF"ci>WR'nגv͛ԷqVn\ӣu&NӻY@ }GԿ)@@:> GnN`dIIsE˗u9rtoQ[}jiGl?K~'zoa[˿<[?*(UR8Wa~%z޺6S=O"!i93ըu'Foϣ[|uęu?MKMZ!AugLz>M(g_>dK<|3v)OpY.!D ke''v2 ӭZL:=;Lz$/Kqǔ#ϕԼP[iSqIIMqiƃKObu޽}؂ z'ѯ'є ;m/=,/?rKGJrrB:{gVB!!dʮ5!PBҴS1!GW鹪rjRKa !4-93Ϭöײn_E#&B>sjτ*X  nmgK$矝*yN2!<|/"?&zdl*`Xф"|7}A<(`Å֝#/V}am׭I%6^!-?4[ߠ^}Oo>\iXY4L%.& ̭4z9H9H9H9H9H9H9H9ښ[?)Uh@Kq ^\Wfh6q[$يT2 *y-ܴޭGر&ELx]t,Sݲd;اo΃^=d9n:0%k]Y~Yf棉Y&B^614n/jM*fQn_9^<6B9roHhLdl_bׯ -L]\%AZtlk~yѡC,?krE۸a[KU]TmCHؖCY Z*G@⡊?LP{Ny%3-Ӂ0XԷjݮlt3o!SU_uC;tDLi,zK71O|Ya[{!VΦ̓=8DUH\=MmGǦ,2Z~ى牝ut+!yl. {o=J{_&}_a=nK۟1uP{3]/(#t0֕=&Ȅ"!!i=.!D^cBHY*,#t1TzQrQ| ì'Pdgf:Plː-Q^.t/^\LJj^OQ ~ΕK׷m1Dq[7B߆1u^\/(+_p#2Љ/,{^eL5Vuq|\J/J.*]vbѴ&,"|ʟHeP[4asb!Ӂ0}Tl}}]"GxEzrӞV@ "aW~߽>,MB8_Vq ;u_^L;T쎄;R7C~dxBfoD5k!wIK05.MSWEeyGVTcVcX4EaÆ 6)*sxNeX7pgdĻI'?zv%D߬Y.A1ޑ?#¾YuZ6._N_IȨ묞ݼcXCB: Q6_L}? V٪:3F36SC?&6Esbo*6;ZnN Q4qQulYuܨ=KnU넥{&xHʷtn  ݼz?5?}h5E4MSL0X _UN%5OU۳}mU²R`XaAO `y,,̫ght(&P45|gغ 8=iƦUh ,4*P#e/!0F:4ku?W~nv3c:.Ul6MK a+``sS:hKi>P,*}'I (*}ȹM@,,@Sw-³a3ƩjJF, 3T\IbLRB VMlkeebb'e/Τcϯ7BVOlcmn9tچ1P-X;4PanY="K 74pS'J?;dzgGZrkٰum]JHsyvUME?J `96kL?Ϥ%vM6͕ǖ]WJVXy^ŏ2ij}wN5K}U/[Xh6؅-Bhewo!]?m#J'/>~˧?Mh n'c]iS\?oVaҦ@ܻub@V)yw{Q/džav1B|mm=Lk#a͌墒y !X/x~NMiSgVXPpqS%;4BY=dv𚧛iEyλmk R}Vt20"a6u" 堅g*-nVJ՝y_3ɟwʺL|7ʮ8HaX/M{ >;[YnU@'ֆ:ru7lwg1 ^:nR:+ @5jwlkцi/8MB u/<ϻ$-1ЍxP&Iӄf:2/4/-|~ 0w0ITV8~۲! 6')nMP1%L{r{yIE]vo16rM-1{B"aq_o`*AX4 ͋|#'i_7-ufDͥJKK?^FP\:fܼjA@0>;#(>Y X,BȒC9992eʲyj_V*'''o~ԩ.]RSRƷlr (__˧P}ѷˢtԧ޿u>{5G M 0Fx/k.fD(**244Ϟ=ɓ'sΕ&'6h#ac$/ݼ*ٷ\'6)0+=察3uĸ VO6$p:0]R.!*}٬ߟ;82%ɍVNp'o[ -<|C[{|!DU$jJW23238lE}:;˖t/:99]reݽz?\5EڶIU㋞Kp0'\]]Z ;\l/6/ͻ$c[VWesoOzHJe2l4;@o_V?}oM4RZ~gm^Jp5.aI>o^\tߗ.E4n*&=s.gk -g3jiM8k/^>|?CIeYLS|kB,_&y6>}[RwιՖ'd)>~˧?Mh n'c]^n m$]ėJ'W @19?c$8;x4E40[q~#%58X&B&O,IHwdt>QdtOw)+kDϢ+:V_$iv𚧛Hdgf:Plː-N L4X3-O$wSr&^gq:M. ʟ\5hxm>w?\!wLW:w6H4asb!Ӂ|n]he@p59CV5`gdDۑd턁-Io[l q:eɭIڠ.6H͙sTnBQϵh2K^mxG '=1oyˤ)~:ٚdlPZ" (UeizInnnC!~UMF@|~?(J ts{}#ZbV _2 آAC[i5FzU8dcBaV-LInNNCrr:MP}ѷ ^S~b3Zl6&Dn{-|*'S2N(Vc|#U:00jbÆM7R搓͚ݻpnBf\6BQA ӝoyu a{;z7j}  =ɥGa! א+}5;4?a[X1< }];<~;12v^<{/IѢS;Xx@\r̢vM=̬=Zs3Wv47{kRo9ؚZ9FzfSҳu3 3KF}Mڈ쟒B˾_4I}Ǟ_-I+S u 7j䈭[6r\.uQ#GxzJ+w0iYK:::37޾zK#"%>#to_ܚ2u'WU~g/%~7i AcvM|NJ;ן_~pYҎsJ{Nfl;-CwΎS2^nk?BZ-miޞovWW~.+?BHqANqAy߿VXy^ŏ2ijt'fK36lتce=}S'fO\O_Or通[hj.4ȷvHKO(;d*]KEZ{(W4pKOAS6BDvғ,PܻubD"'?[/a g#4]vb`lwF~/ÝLFEijG_+9=tsޜUl]V B$ ݑcg3AqQ K瀼.\\5ݹֺˀzbaAbMw(w}Σbʣz84U&{8X۵&v͂oo;J fY}bҁ_$<Ӟ}!!K#Z\*Mze7{gv ̺Q_HEem MmD%OՏ.f|36lتc#lڲMLQbڴe[qIs%wjT02D'?r~ɫ>JO|OT@LT.=jQ얖&)I@bnd4As:*}Iȅ_5hYCv㗯/ X=K1=mQ~d+{WIwbƻ4cÆ:6_ JJ~fBP8uڌ~YPR\L3eȈ3 (aIݸ%AԟR( e<_巎nMP1%L{r{y:JQ:k Z~όB%,yqc 43hcR$7iٮ#|;O&GOX}݂"_d(Es9q.K_0vWbK133xisN733SZ`eKgf٫߹Эf}W??mҲ奈˪ޡ?)4γF}"h 6KBz{_m:ڸ |:ɡNԿխ]>َcM'i\κJ_B[vn ˀ?":ovMw#:YX:91ֶN3Bgމt>>¨_&&;6cÆnDdjfvqSSSS':ͪTN%PekL- {@Ͻ (ϖ+%@),(=0@i B`D @]t-bXiQ|{/˪pit,)3TE;j4tf4tnsTDXl^xv匷iLc̓X4͡bJtu"Ȗ uʫKgX㺺<;G8R^Y0 rL˖hW.2q3o`Gt,ǣ7jcjQEN*/;+-;Ȗ#-+#֞(f蜕t’ߨEOR4b5j’/[th70Fk#GFLGٗڍF?Bp?PM/HhG ~%]g&50vŕ3,h}:Rk's]z Ӂ@`/!CD՛(J ts{j};fh@_iW:,_ֿ)C51P}ѷ ^S~bW۩#'Ks,M4M3 0X>I5b9.;6;ߘww! iޤ! kWQ[ Ĵ!^֎MN(-WӨ!ߡq + |{&ݗSgH~ %j@j\Y`Y;:˱S}BՅ~ߥ>ӚNojmN޼kM2N1`ImU5xgm^Jp5.aI陝jHԑ݇O$p?^xv匷iLas,y0z՘x^"nb]k;{t鱤f8q{ŶV+IdPIӜZE'T5d?54bYih; !WΟɅaf]mX㺺<;GFbPGŢ*2^2及ELx}I7a$!_iq 5owHxM6& ~ j̛0-MLN8_5ho3/3R%ҕ#}w !TVFFe蜕tUc:`ȗa##^,,%wSZsS% J^E-t@zh-yA^ʺI ]G-PzDDpo)aړ˃(qq.--Tce$p?i1r8.MSLG\5,{\:6^Gn5JiNQXi3Nb#:HE|3m3}oY.S9 !;6yڨOb{o@m86Œ<"XY@J9hT07ojmnrfs7QI }C ]->49tf8oy".H PK( 4FOo^^>8lN}>]Ǯ=0ЈnTU$jj4*;QԼԔWq B<Ѱ=y԰qsBX,JJ|z菺<={,h7 EC dvu0ZFҚU```Ǫ{rn^Lu,{H()x*Ưs3C#g)Т!~6zz6fKre5јP4EMSbHFӔ2vqo4cǝ/*,djjP)tЮSEiȿϢWw2"r~;{_|E#Gv Ϻ2|ݍbwmi-9=wٹ7B^|+9TRh.~*+ "VO@sdef;ԇ95iDOGhMѲ9def:d_C5܂@DmYCVvUn6'J%!(Cwi%.Y"I:/ԷPxIDD-??xoۨ1݌dF!]xSnkmt8s;ÿ2˗mPr@޶68d!J ɕ|.VR>X| SBH޳E=)QU(X4dPg^M2i =硓+!BbNDFMeZdViiu@ ʕhtJ[XeKG:VLGQtqNLEKp0՗wa ^wdl:B[p5g_w"3R+V#Y="aۣ\KXimbzBF|X'/$䘪BLj:d\4&W(.+8g|CY%W$F3;Ur7 u+eBht),V+ؑ#Hvk:Y===['6t85߾Iv>֫ukk \/w` dѤMr40cKdC6MvB[Wւ%+ d?54bI1氲S^δrk9}M~c5ώzj:܎&-ڊҪV>ƼO,D-b!^|\.}%wh;fs9\.>'@YZ4o3y9T "@]fM͛za:O -(|wi RB.X٤ϸ!ɗ|BcHSeQiEkxKt|5 2%|省 A3)]h#.zu=rE%c,}b~S&vq!7Z&BP'cThӹ7iHw y!Mٽ{ʫv%LxF}G-!djM WMyAJ:w6pibB?~9/*ͤ ϑ.o~ӿb}ـi1s@~] %sUKIO-W]5hlv4EBBHa~DqhJ>>~gy!M?Ń茶ҡNS%OglfxKo}m Wn㪉M2ٳ!<,&kJt䬱-M,B-`*A$7\#wly.J:qgA+}_0Z:yߕ7V4B?huDB!GfT/M,߭;yCV:\yKMZDPӤs7jŞؕw<:rjPfMu>D}{m4Dw& ML/r&|ށUty/%xϏj A3lٗg# p6u[ڣ7zv{p#\r+,q++ a1Vil윤%MIhթddxjie-()r;sB.4qi/!upրyJy[tIO{}ҙ}8p8lBH'suoHqguafa_OI;?n a&L2}LM}Ш`ju{J^N!ǫdF@@x!foٮ.&̐-06R=vLM&Ө`abjVʧX,`Y Ù} Ҩ`bhdTy%qSh5KLGA!Xh(V1~tŠ(C:j^㯜}`J,~wצ^@=t^&2@#XZ4o3y9EU~B5`ƦM[[Z0@XL|ƵoӘ6ǒo߱ VvUn<'u`1!TPR\tJwh).?۫ gsbQj˳@#7'nׯ\7dTfL3sKS'=X@k`*AnY6LG0;G GhK̗Z n,6~>vcXLp?Ҵu(h&@! Ou+]q՛(J [F-̟6} }vFm-7!+N_@7bNJq ),MXciE/RJzt{dPu}WEsے,fY0Tl5 4db,  Hؘ|cGGͫk\4oRځBׅ|յЭbZZ/OOkǦCmKY%Jv֔\FrSg6NODklxn rPW`*A)Y&ƏZ2IEO]%dB..鄇Ǜ&覴ڼx_nM2Kn5"&*/P@K= [|cy!KDLP;@Js!"ɪ1D@xךǒwp67w{E+͜xq87BSz@MhSsO3 0>m P0 FuѨ`dUc]X\EFKQ O3&,$=+-7RVT~Ʀ@++Ne9y>)[ 5LbIZ= fOQe4*Fϟ޼v9JKp؜|~]]=Vc:`enlb/e# t H]./kdU!)Frcd X?`+;@J9hT0uRS^]87h'CyG&zQ !b()ɣ?V9KvF qbfa%,I$ҚK8Ξ-9OP*:h˰Cs&oIRMZ:jN<Υ)L%2Qfx/(+x3ϦkLjzYƷlLGܺOunf14b9Is{GjekdakGE+s6{}LuLl/{|q燌 phfs(h)X~iJRf75^,{\:6larlORZS1Sz4.$F}Az(m'۾iNH҇4Hn<~ 72}^<T`5L'c)bnrٱn̟kK nA}}[/<9ڷSxճ}|+WJ!jV̰w-!7/jۏ,eOs l,M bamupրy&L-Q MQ,7r9CD*Ѓ(NHϙbyȄ]'sXDJ+HH_Z.Y(Y ,QsybQ\9%s+ݭ#޴3%kwbֵ#{۪/ziȄɡr5.<uSoˤɖ<硓+!BbNDFMeZdF @>7mCW}tNk:=:pDE>W#REKgu3Ⲃ{XWZt?T?"/ŔviZT{:&8g7vvv՛OWvd-KPX,$HJwh;RVM-I-c vdY;a`GK=qңV-;!dǩS:ٚ Z2lܹ*LJ̸N✗þQJ.,>`-=KnhY>GcG<=|f'#wf"[kȌ`zsvW !DύU:Sb- 9%h|egnݹW~;X,r5th^㯜ӳub##(kcZwfPWq\ճr55e^hu7 0=ݵGoqF}Қobk]6!d1kVzJ+ RR\P :=핍):#CєoS-%\ ^hc<}t /G? @]fM=x[7pPZAnE@>FzktcaB?17ސ"Si)7ζR_$)Mٽ{ʫvx QnjT0uصWrE< :mj^eΦf溺3" }@FQ6sp15_Y,qV#FQ24PҜukPkZE1Qm@]t*uߤ$2Gߤ$ƝWkbPVi޲+g\XhS֖V6P)VvF*1@u19?c$5F*BH;j|;AnA)!h O@k ڍ{ٍk3ަ1 8l%߾cW7cmth).?۫ gsbQj˳>v~B!7f:Ƙ[>qxqL4m,!fB:[VF=Q09+#(4&%@|Hvi c8.MSLG)4a,!(n,6 C2y@ŏ|}U&cXLp?Ҝ6.`/!C3y@Uo:(9.$͍oٺdg|A-bW˪HGA?"rCLhT01oZ}ѷˢtԧ޿u>{#Arci?ηGj9E>>`)QYϟ޼v9Jp؜|~]]=?{`̪t@l;#U{[{x/ o? 2NMHWZoR=?Z(W] Naam"7vɹ{255f"ay5Uci?c==cav }j`];?dTGc6CES4M"MS,6ŽwwqZ3ߣK%E5ٔG+ZI"c%wHʝ*8!H͹G:<X4;. yemCjKN&i'4&bʵ^m%t8!rt X3(t♨._'GU~J>Ѣ'NM.;}[/<9ڷSxD-OOe59EUdd3&,$=+-7RV\?!}7 ܸ+9DBlEBv:Y<*ǐ*F`[Y=k.+YKKf Z3dWGeZGP3Nf@}F#]:gѯF:s;ÿ2˗mt! j/3mY.[Ano/OiT!MMr챋B`!<?%-)6MQ2}zhJ,BuKhZ,)4%{ "ڻc.X*WR這ޖ'UZr)"(10Rwy]r'u&%}v4ov7Mtze1Ѫb:2_k_$H)K\ShْrYh-OmY;)=tuwiO'촦ӣG[s5[p5g_w"3R/zr,.T3bMu߻ LJBF|X'/$Ҧ@{;q=c\ܘCY%W'2r |ٙ*]U4vJD!?4%w?pV>D&tJoƅĨàob#:HE|3mRc)qⰈv'sNNccf6$g=$xI=ǶoS"KZ]c-k$a/YpEκjT'"Tp"Z[jk՟Jb]u/%"(#81$~>Q{<6?rR7 HN(eg#]?}=zbUE{S3DeJTrL4 sg '[r&pA+-J6«|Ѳ[`!'Elq ,&de=aWwtoɜsJ*4x)mMQ7~ܼ4l;gCu“KJ# x; K~BL'2Zou~-Lu(n7nfƟB?/`\5EO]&$ha"K|z[.kbL)}EbT%C۱eSj5ؖS7(>`א vț - W*t=2PAFrFzZo m_6I{Jl̬qm,B%(LT]"sgN782;d3[Gy'Iݖg-1B&/Iܪ*#H7 ܻyۯ" <OSCcFC#eGtjkHsBRJ?H}C II#kWɑdfx`k9,].,Ej;cNBg#AJ^JM$t.&/I )c y3}lm$HS|z{o)yO-*ޕipT mFMmȸ 0hj! ~BD {dž• q开SZ}z6Z8p8lBwLMkD7#xܜi};413Փ~ Pm >Ws>q4ЦTS3J zՋ%y|>!J[+*Ξ$plc|ML"ufjf(Lс(RaSS3 EG,jR\Mpb hͣwfqk['v >,#mkf>WS @.& fnaݺcKE^lcP3y@MWCс(+)\BLePm0y@;eK<X/ (:S :[\3FPotG0F@oY7ttt,% JEECC`Pm(9h:;\Eas--;vDQ1HPm(9=yzxC\8x'ُmਐCw6ehΥ7ddV Լ_8^06%i"[+: Bst~^(ڔP P`@=7?uZ:4ս^0QD B @@L*P9Or:1?ɭGr&ZJ?ޝZ&xܬw?ؒjK%7(hbh*t=dl@gbƟICZhk~9b :Ή724=z7UՇLSAP)zxj6m`P+N9֥I 6ç|OQ|+?әYl{w.R;:MvEk^Rqhn씹SkT_1j@94"wE1khWBM5b/I Q'r/@@dI3xצ>>__O{f yr  9եDroGߡWo IGڱJ%EN"Ӥg RQQ9k [{Ga O\BH?vG(ŧsx^XPQYa@ cw@z\uOGwFPCMp̘(N?5,Mb{~Vh.~~h3Y@GjkzVn;p릹֚CDҸsrMӷcKzBȭO,XB HN wk1囐;φ r$sD+1Bu>|6)!]"q7(/|"-R;F_ʭmר-]m3K *,}Cq_ Ikb7d–UFmWĖMܹv.̶} 6ds`7CB$4ܒӂYk58(rw# Cv,v:yI's7#ʃ{n!W!LkK ^Y5| \^4jz):(PRzxOnb5W|W&SE>./PRYzշ;vvՐ_z0e3vr B3nP_(k^~''I{u9vXr&b>]Jc'LLG:[xWHA,M[#^Ԍ ƻw5eW 7 tk,H |QIAkS!cgH;3f '-#Tkt@V X̽͌ 14i^ B[v4 q) :QSd]?ݼQ* # ݷw[hz4o- %`!DgHwq !2:t[EQ"G~6cww߲{{̊w6!s.~99BL;%GolM/jϺ`w BHe M4T@Vܿ q eXū|ri9fm/[ΫjU5h*eBK 6o60K ʹEQw/J4K{k-9JO8?Ϻ,?h+H\?^W)~ 5#dR!;jVfI(+0:Z$w]2nk =moq7 j7^U6Y ݨKeYtbq (~%]MÍ2߇;X ('ƿ,G53HҙuJ6«|ѲA#Jy!E?{kF]m@eH-505u!/2!%\F@ ̋ =+2RO`!,c˦@۲"|^;U1"A)hw@iu8@@ UEocmBH4M/QL}Uѧ:=]Ko%񦡥ƙW= ?[cB9IsaSWx;=ޖǥ˚BJoѳ%(S-lOOߙWhѓڌ e- ]ٶ6jaRXBL"sg:]?oRVϳ$`ܴzSk 뵌N"%<~@;[#ĉ+{ CFK !DW \;P+Iܪ* (n^H|>z3)\c}FD ;nfqEd2Ûq V$?.(e؇[aM7X#~v)7 %_;LM#q%U.$9yeݬ)P"Mq&uhnSs-~: <@eO<Tk)X5~bˢ\= !PuGg辨t{뻙Sʚ f={󙎩]>O{Il$șWbBH. 8Rq+Ř1BȻus vN>ŧh߹ Pª]G=r1z3K1_ψ@Pg"eڍszl/'S̔6fϷ %gVn}l86!`QS:G9ӎv*_sٙ{oO= >;6nXс(Xy㧈Zչ§5gP>8:hl\ͷTӜG]PRB**kXIGf6nѶ}:“\G(aK~Y:ܤ*7qbAkEY: z T?+U0\MpbEw̰;C'o5; -W@]z TKi(U0 EW<,;@3&F]%Sz xB<GC@̲CP {H[/j -[~uI1ϯ9`FƦ FJAYܽyE=яM[zZ80fA ):+{;T ȁ`PXJ@;@;@;@;@UT+:IAw4p:;\EP8leN]]ܚEw4pOs<޻P{'7.xp4(/b ,_<13; W5$%QoF~P0@c5ˠܻnu{щ?'\sv~iQ~,XlK!(ePw6 :|vտ_,Qt b0O܄k+c:( /}|zq#Ss6.Q)DWYt8_B0-G5;s4#B]KsY}Zkr!E3g8bf)]0pۑ9W-8tkFs\PS ՚Ͻ&F~C&lY\_JC4|&cQ1VV(g<-*,_tE^["_>{ͽEO*$y gFj!TIJ?, @$6}j_wF4[z{Zۺbѕ_WecҺ[oٶiS+G&꣪vE{5ofТyU~MUF[BƢtqr1ol׆[%؛eu*)@MJ5D%"$](ǀW1n/sBHyOu6Ғ~R$a F7lӈC!(r8$暵;CݎAӇ˯ŏ33 74Zws :$ƺS j!x0ၒ͉82QJI ^ҠKI!2QcM(sBrsz@ty_7陷2hs+I Lo1~-Lu(n7WQ=\]ݻ:N9ž>ǗXi*+rcEb(ft͉nRN*R *ܶEٜb+2Hi튩ˌ(gyDsM-\fqO 5j@4gs3ADgg5 P763gѽMc{ϢDsDb[t:]t;{{/]cNIӥ˯*q*{$oqb@O_7S_I"şnw>OE(~f^.]lUoU=]]{g)J*nv$8} ”PqQ'I/ Ny:G@nӹSb}X,BȇKpXpbvIEEINבIm SW޹t:=2 w T^6Nta)o`tI%,8{쒊DZA."ݹӂՔʊXwYۥd  &}RN*BRHzwdk@P0{{=:ɷJdO?6BX"22W.V!D8YJ!DY*%)xG#֪F~0CIտQI_!2bcAPoAyuO:nHAI5k2$Тm2llO+6_]0 8C'zznvMʰo,˱̀KfAtbBp=dQos6.\:R.+SFgj5͘#_iuE'K*菌ՔʊXwٰEw\2l͘5T2':=7) ƅisbG`t {{7yPk##ajLW V ,~F?09\*}?[Ŧn+^k鷦=5=|DQD҈Ba-5PT~:C 1;xU[>ͬr7m3p޾wbC`qHRF>s!d#=0lqCޢg1Jz~P]~.M)2(>$Eiwߵ79u&{.Q>f\x-#GA˻%ϻmY᭹IݖO@i@ ǫ9@C8 CTxrv|m̈́ࢪڽI MQg#{|B_ww11uGt7Y@L,^+: (jjf!2>+҃cZuM=>&Θ(+-6!4~X[~iEEi~ʚ ?P&, G[rb>,aCmbϯ"e2HD-`,R[Xns1b>@]l#cSOos k8;3br͎&\;͈Z٣p]C,زSOڿ=43ۢ/xkۼI `o2ऱmFF"g5 " (x"6sMȁ"g5;x$YiJ5G;O+kҥm9V(WydH494Nഅ߄H-$5Vuj `4bfIҦO-oIüV,%wd]ۨ7"|' 3tԷlA(J}w`Q=@ ;@;@h|ʂ{)Aq2ёk$jx,6;yM#,UH'(9tX,BIRDORxlٞd(",dzCvg:uР;OƟ%e,">?ӧo]8p|K?|t2ݓHv"8D/toa6loO_O{,Nкec+BHiN.t6Zi36mjԄn2o7jJA* rwy6g*ocd,bCw.zˠF Ptyśջ*BKiF]*˂c !,!~?RrzfFݫ&U8?Rzkoz6/@J!"Ք,UlS7!x@Ãx,-_xsWe޸%W_>3abEU}u-퐤BJ|]}#=7 ]RQQ?9uZUA!l.(/y2$ l2{B읂7Uek "'.(zN1_{Iju8(?td, )qgw^={M: 6 ak#wllO+6_]0 8SZt^28Yc̘'/|DxznvMʰot凥Y}.%gzix,[Z4xfo$cwe @PϰvAwAwAwAwAwAwAwAwAw?:+! endstream endobj 97 0 obj << /Length 4360 /Filter /FlateDecode >> stream xڵZ[sƱ~ׯؗSYMq$˩8 ._ TT4fڗ{JUϖyfE^LWU_nWJ@C_}NUNh]z}۟6ʊή6։[ӻ\޼_*\H!)9)j> 3&4jz{+I˓\uYmWV"eǕ*s%C_t\(KFku_#f]qЍ\n;g!ԡ?vv}_oG7C`;\jCsZmJky"ǺjqK VqNM{agݕm5և+gׯZ?tgn {om$rX0[%y1J&~(wh7ɰkc=;{NL[Ýxj㄀ǿSC]_?d0F,e <,~~O_,@᧏#Ai(cMqQ`';T*3b (}|G_v0V=dbZgԳ)4YgЦjwisY '}ߌĈJdJD\T̏2cH`+M+)AkP RZHdv6C( 5(r`ڑh+S zC#n-Ӵz.;H]87iQB+7JI]Sq1PR[(]L]Ye:t58~ e}/M˥LWEZb-kR"W+#xmpR3@"R]Pӵ~O۷'qe̦IV!%LIVMJI?Yj21<ϙMF9H8 ƚ[F ĕ,x48droھg6 7.ܲ@.ZHl /!"+h"xAtɸؼo0S& @d$(R5|Rn7*љ=Mu}//>wjDkQvi.E4`Rgzd niv@x+$ yaX4W#d 䚜/q@GR &{dƬtY/;NƮ|`.|DҌkP)h/=w?2 ̽N}ٕ ;HL̍Sj) a_4z6"ZM+aUmjD?(Q0(+RN#r)3ȉI)9ɬŠVTzLh~MࠊN-'6kaIzM/@5yJc;m9e+c :Bk7c*~.(T7I(Q(Z /;H AeQȄ4ZX/F  RB++"p$ xh\Bidm|ž0"ȳ6r!πs!F:vA,Oxsi,@tfWRz<]Tʘv<=0|THKs :@BtqgSzL;7;}0"X!fU؃:ġ\jɘmCӶXcL%qu6P )P/zʕ<8/: LWi S)(u@AL1UKlE8ĢۀޥFF}(`Zu䎱Ɖ!MQ[ v5K@%ԺKN(7$xq8U[rGxeʽ&{"P7GP4p*:LZ[p kr{|+#`qRg[FO$nd!m tnv@f&<@+lqRO|gXU UҙQB\]W:sdnv@KEbT08Oqkq/rX.УA6B`>M}1{-]sMD^uCiu©5"c8lNͯ4F;T>sjļ!&}4Y  B誔"A R|'h%/K|J٩ŗS=% ˜3`PV7j'oHE%6*`Ms#CN{ 22$ "Hgr.X= `jbJj B-uP;>0}]!Ф;7IҰS}b1 a3}`H3_!l=XOd)rn}$XG&&-0Nv+dݠ ‰4K-Z>QCÈ,ÉQoU% /uE)_,\&oty DBPP3O[$7qNIx42ۘV!Sp@)9>Ur͓ _΀uX6{A~iT E:Ap ǁ_@G>n[.y$S^=V+|~ k<<-<xL+zh=~e2_GsYuH6)?> U_;c4?n4>%Qb9˃hK=*:mOn,Zmxg0SD^>wcvz<u|tJ9!W\b=IeMQdB'q$ A'MŇ5sm'm%hxܱ(P{Н o_ 5 endstream endobj 100 0 obj << /Length 4538 /Filter /FlateDecode >> stream xڵ;ے6ڧ, [lv*{쮩J!ؽ_n\:8q98B-f$l$LEgn"-~ysw8^daEjq]E,4zqY4!^~ԋ",8ő fO LC~)cY/W*WY}Z$ t\%i/o~돌O?[|g\ͿnBM;ajbhQ|F&ô盳SjP&&QAEQf]5agط}Y=8B(seʂ~\I P8u˃gtv[v_8.TX$ /W6d?US۾, T:ؗl]{@M=jg,.YlcSEj| Jݷo?<'G7)eUfr#mەNkxZd <-b UUJfQ *r Ɛ3(XGnӬ"$9 `=7TjCaft2چe%~uV?d CNC;o#OrcnAVf鞒KK-KO`B˫ N0CfZWL׀Ys6?F>eWlW 2@*#c?wR9fzd&#`kqҗlyol\L/9Q(f:&dHN$0q1;˘ۭI;@%lGݱYt$0qa{cQJ31"uy!DkC'fT]?5`g[EIVEgDs1֑aHŘ_]4{>L6&z#-]@aaek,k̋\1պ6LTEh>j@ktJw!A 1JoF,K*0}TGn̬ǟc9yph{0h* .Y{Ќ vX|Ҁ=;^9ѯ0>*u":C` olYΕ8ȹ"Bn9Pby1Bmx]+!󌣰s(b6V<ڲk?R:Z1z4RxğrĬK6 ezN-)֒rЀO.m!"5=Ѵo0NXk"%B `DID Y2l $j'dx%Fkɺ1|ZP؆u6f XǞϋ6v]PYi/(3g.UK)H30' le̒S\y&ޮm-f8 &, t#t%yJ=g6|އ%|o_Qq59oXuy9ޖZ ،='2 @eڊ̙3԰5WgW|KnU]!hi޺\siQ`D15x*CkI]VL yj0ϊݞ-ZÉ/-gObB8LQa*0O/}iSml)oN6&VAn )GFF1q̀8t*:ڎAу + :Ο2!(ً-qrU|\bjiKN~z &Ty(A"e_D̴xjU >iRMdjg1m ??LGe#ͱZDa䌗v( .@G#Wv2FMQ{nba&"Q- ;7CclbZ=yӳO9kM>̧/~>֔ʹ`e@]o%k@<_72\A_ryLpPꚥShI>>4L}s!'U&8`(cnU")P`V(Kب$VTo'#Djf10TKGSx:h{۹~D+9|iX.ʹAwb#54)h`>:LcBDBloSo'>b-_.Oll򸇶ĩĠƹO3\A3ZGʤr ATNI moĜqe8HQ:rǒ E&ɌD] `׍$W2牦h{@ݾWPOK(WƒR>~.@"D EE!rYd47ͩyd'REuR00&3n Spf[b u b9xt9݃8"D]vK0|_2MT .7Ԥh1 x=*I@|lyjG+;kp k]>a"w(dyŧ7}wR09载F& x2B\4x `>\sm<\]Y$Rgk_JeW) Wfg CW}cXC86R wokD\"Nhzrm(Oĕ=-ܝ=r0}y`{Nޮ[dc"(B&#b;lʡ?2ӣMS<տ2SJEHr_ c]Q2[¤V }IN P2;=Z| ;~3|x-N^ gt"&LtUb [<ۚKj1,sF*ni,'f)L}pngpd1:IAg3j⛺#?%c5SFA~-d>\S޺0 yp x3_h;^3zSSzA$jըwN+{2y쪸8f Z69:LJ:;EAz`9|!yB0ֽռ \Q%R f8Xr]|ˢ\U> #5j|9 yA` c&ϛD!ljy! zߗ:'Jv:H5eA<6O_:H5Ǧ8aQCJ!!«/BKX#ΡDXU%@`Gp˚ ( Wd P $ IuꡕH9t2<[KE,ˡBaشKrv|CsCt@8b_gA> stream xuMo@+)X {3bDH5i@f7;WvPXYd H$ n QlJHp0Ϡ%**sYτHb<ӆrRlجʖ|bQ{,:KW?}~? ȵD>\z<2>wVF)8l'85JϠlAi}=p.\pfG8Mشm n9]h endstream endobj 108 0 obj << /Length 3576 /Filter /FlateDecode >> stream xڝZY~[8YyrIWDHv= $l4@>nyo7F/ԫ7rY6C9lj_|޺Qi?l2^ocg3v5Lp7жkt{mؚ,XIq\=\3}=9К'>b1<-sVL _3͔)|x.p1Mnϕ庠qǒw5DbIۦ!C8T'/vS=q Uxa~@+\̕[q: X<2CSw,pC즦Y(Kˌ p)X+NcSڧ(.",@ڕ/xe+D@, P\~k|i\>ՠr]s6aAz}ն\a1 C5Һ jօݼ?ФEY`ug•Ps{`[Y53_U?2>2K3GXc}u&_oOjs]F "O]T.L0"鷾?1 -RH1MP? _q utdSMdbV %$it2:TJGc}haw17,pNpTmuuI@{뺕ΞKנFGDw(׹VOYΞ˳XQ2THgeϊDq,T-,;t1"(Rs[ h) P qڞjJJ-H|h  r`'4 v=$XLj@@d8UU?TWzŬCW8X+DNdxn'z [;[h0IZmr@.-,1N(7x@uتCتa-XXl}_/_/1AES>l[>a(7 ;oD"Z뷠DL2dss(XH-*Fp IúgufUa@f^ "Hcpa,W-Std:96.6_Q6& D@ {wU9͞iP"(&FZ(Sq DɴJz.I $ti6laDu}x&C φ-^f0 bϰ&cD[,!+95WǶ!Giu8VE&^XB@j&.1uuIے[3+%F@Cߏ'cˀkQlǯ~_ $7x׾զ֬|&3" )773Js kpm.U5 ^gD!P/dmx2 $ {ž=anbtaٴae !sYF_<*4_%NT4=`*3\<77?wU[s8IM_307/t(|m=#:3J2rH*ppCԊ <P3\1]!_QI0 g8Ľ w,-#&ǂ8d(6Y3*ӌڍY&Tlg=L|=$v25oM6{T mdSgs a:2*.fZw01Yn:/ endstream endobj 114 0 obj << /Length 3769 /Filter /FlateDecode >> stream xڝZYs6~ׯ7<4L8UqKV`$r#/N\.6>nJU_^IJ( V]V?]0_ūkmVF:ZV(nuon_ntrFw.ЫKc_xH2?i5^I !+aWw/A 1^_I#b3$G6M_Gw:!fot_*l0@9nk /q3`0$<΅NX=:V9nmgt ȋ9YGtY.HZ<4Rb]{ręm葔5QN5C(:8h䜀y8%P7k~  Pn 0n+/'U ~륕فZĝRe}AL8\i! _Җͮԣ1w&ernco7;> .O}0pr>O;<X N2`l廯ma7x)cg ?x hR¾\܈&Q )<:~%'7/هH HN8Ӱ5D%dh/bBW7ڏ`\\_Q!F>쒐{tM,(,8eG?2C?%}0.DM{AbF1[Eu%:3fk3 bD.Òr4\ͼ@G.2tn{%)V_`T| CJK]NӐ[{v.m$2^0$y`*SA {7{-@a"XE܆IY]M=qȰMH2N =dIL@ȋxDb (U}-DoG%g<ߞ|^VjQ$l&oBČ8_EYM9DQ$#)=V!+(qt/<5`=XX O$a.@v80I ]-,l/r~D1YDSɚR fɾcowFs򻳾/QN>Gp' iJ%|)g'3Ed]Mq,õ3JD0x&ș bpʇ$F8I *~,1{T!RZ|A%A>=lHJ7`@WKHꘕ``MV w(/KoqcF Ze6 j @ detZq2qg$31\x vECP>y/vgXbbE[5HTQipLpjQ9yPh#`!^U!UVJZ xq_MjdsSøC8 (21BxpgcWuwE?]Q5rqnwO_ȵ,?st8E0J(쎽 ɹ-u.C47Hw|,6`ߴAۃ;x<f0<)p@<˳9Mـ榐MǓdt: Q_&Iݘ  r\q&*C9U/C/ WvmxTӗ17/e:c1]6@+'׽'?iX€G`/oon4q04kz#\. u,}M "^0a/lwSUӳ8'USHiO9` wo/=@7B޼sw߾/S: w:GB DtWG07-m ,C|T"ehFLziƷvg> stream JFIFExifII*JR(iZ)( )( 02100100 4C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222224 " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? _ꞻ _Ꞁ4-ⴾq#Mar9V_iK0یZfNg 5Ad9Te m\ߙaɤ= ;f]EOLvwʣ`QǿA@4%ey4iKӠw@XdsWeHaS$ 'cU4j1sb. W+ɳ+=qg \Y*mKy`; >ť#9fܒOZ煿?M煿?MEm|?-SC4c1 Ѓʥ?TжM?ɫ{sxtSB4h[|&o΍ .lf1U\вgkzCkS tGޯno΍ .lf1U\вgkzCжM[? s`K""+Ax/ߎ*Dݟ0-w7Fl|>2l8\gAx>֖[3π>G:77@* 3g 1ڰ ho웑 D?g~:77@?-Gj?TжM?ɫ{^sʀ"жM?ɫ{sxtSB4h[|&o΍O om|:77@?-Gj?TжM?ɫ{sxtSB4h[|&o΍O om|:77@?-Gj?TжM?ɫ{sxtSB4h[|&3y`:'iHsn}ʀ#жM?ɩq 1 B4h[|&ƫ<-hƫ<-h/ om|3ȭks 4hжM[? ?ɣB5osxtno΀*h[|& oսѹ:m|?-V7FhжM[? ?ɣB5osxtno΀*h[|& oսѹ:m|?-V7FhжM[? ?ɣB5/`󼟴ټg7@?-Gj?TжMF61$de=o΍{Osƍ.[iCXOE#̊/3ѹ:tQ{۹-&sEcqac~+qK x!`cPQ8-ѹ:IGi"2ǂt\㧵E"[9vKH3:77@h3sir$#ljB@⤝4{U@w#µw7F4 ZD1 ORF9&Hkg>Ju:֦?P6"s8Udb3(k&eV0B9Lp*?P80]Gz Z[Eյ$hX6=V3w€25>GqRJ p^*T p^*ThX`W0EUd08,}3}QYhv`jڈAo%wn!~{`R&t{a,úAf]Ji#SbcmXFʀ9'zշg 98d9?1CVOx>,#}A @ -<iCVO,cu7 +i`xNpzPMkHl7W3,۽O- 'ڲ-M1kg!0!ewo9c;WյocB\麁+s:D\褆$[Z̷RxJ1%rbX[K}z ?/񃥴I0l&4c8xMYmP]qjm/l 0!2 ̾u'>ī}X&%ŴA': locuKqm62cD@2pOy[?+?pBku o4 HzO \"Ф}CZ<1H"e c<~UW4wI;'z4UYO&G!_Q͊LK"%ZOdhI,MS#O?"B4(vAɀi~\I,Mi?i}}GQF?Eخ90/i?'z5O?/?&s'z4UYO&G!_Qsb 4.UYO&J??B4(#O?"lWdEJ? V=gY?F?Ei}}GQ͊샓?ȹ V=gY??* 'T?/9]r`?_xN6l;3m %q[-<ݖܜc?ZUA#Aux%0O`~No!꫕ǮFG[u_#-K V\bMIڅ STvoQ%77G@I#*W?5wˇy֦o7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇywDu9S-]Z蓀 F 0/I!伹ytMdhɏ0SO+CY֦lwKU3`rCɮwOu+CnV+]4݉Qw ch^E{kɤfnW ’ T~6tMY54]Z Gh\cIV\Xnt2SzWW2K6vmSbAYw购:OE!"-xdˡyp}2'z5׃.ndqTu 98ʓ'EF?ErJXF.U)\ V=gY??* 'T?/lWdW&s'z4UYO&G!_Qsb 4.UYO&J??B4(#O?"lWdEJ? V=gY?F?Ei}}GQ͊샓?ȹ V=gY??* 'T?/9]r`?_?* 'G%ZOdj!_QG6+LK"%ZOdhI,MS#O?"B4(vAɀi~\I,M1Cay[740:pXfH|)o`Ow,ȏ 0'5Q&+8_,~Վs4kx#c@dgv?YӡԙüI ᜑQ;B~[(Їߖ \?F4;dkJ}+ |5>G1 U뽟UmDdo e[#?K#y4]vtOit/e".pN?rR*;.\яMߟ?P q>1Lk,B@UB zbsc;.\яMߟ?Fv]ٺ9ţ?O Ztn#:+.$;qv~{>EPgeݛ3Z1˻7WGqRJ p^*TQ@l𵤬y=CNעC K&lmbb)aEwOG4y)Ɗ(SJz?o<Gh%=7䧣(OG4y)Ɗ(SR&/b][I*%TzqE䧣<E <Gh%=7䧣(OG4y)Ɗ(SJz?o<Gh)E6nȯⶆU"G.҃z|Jz?oJz?oOG4Q@OG4y)Ɗ(SJz?o<Gh%=7䧣( Z%KK{i%@93N*hhSP0SJz?o<Gh%=7䧣(OG4y)Ɗ(SRmՑ_m D]<E䧣<E <Gh%=7䧣(OG4y)Ɗ(SJz?o<TKؗtJr U$gQE.)Ə%=7E%=7䧣(OG4y)Ɗ(SJz?o<Gh%=7䧣( QM[+HK瞟 jhhSP0SJz?o<Gh%=7䧣(OG4y)Ɗ(7~{IPGS endstream endobj 105 0 obj << /Type /XObject /Subtype /Image /Width 251 /Height 204 /BitsPerComponent 8 /Length 11192 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIF``C  !"$"$C" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?_J8cEcn^/yM?Nr`0GsgS X6k/Ib'`;m3!R #jͦnͷP[g$95|3bܩo{? nXEe0܅H? Zi6Zޭo=.tk@|`U'~g{&e;NpGEp1φc=7.e[!۫rqu<qL}Y]Bɴ3~@ w7k־'ִEkrpD qӵrʷ"֞`{` @`M\ߢ2n?//)  Zrȗz|V]:KwP~Mr Ԛ<^+&?5";-,> q4%KO+{ѽ?Uӿ?_Ɓz}:Ϣo4eZޟ_ΫjZs^msE*na2='^>}Ϣo45};. P5=g˵{8Rde':$ l'<^ KQ{[smfGTŽTepnezo/NVVkz}:6eIgpV7.mwi"aR5/MEhC06Mkƚ"y$ky2\<.F⵼9`bM#gf=XIzo/G^>}kz}:͵lE{=@ "FX.I=^>}Ϣo4Tִ=3U[n?/h#>Zޟ_Ϊezo/GKkz}:7zo/G^>}ޟ_Ϊezo/@=^QP+E)XO( r23-&~96;OO^r=K-+& Wո=;xXH28 :zFiwc<~[\wA# X3tW:vz +j2de+aEA<$q;$jh%PЯ㾴Y4`. G#dƩró^Cuo-y+si^5 NeķіXقؠ*z:S//R'oWAՓJյteFeu1™T`|)jɥ꺺[20%s2:X= Oj6:=VGHt|f l"GQԮa ;kZՄ E{l|dVOK}Kuv=g_υ4-Y4WWK{TfSĮpGU+'r3]t*2RÚG<7kV&YɳHBǁ[#s^{MNm9˅vVn)7m72"[CَIkz}:ʷZ[5iLccӭy|0 1%<8grOԘIpbkեogOz,% 麵T-^oOFuA<5?痆65O/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AKz: b[_JmKh;W8Y>Zlaȋ+ eg$ۇ^k6oMjóO9pAcyMFu-e[Mp(`|{6?"O*GOnF&ߎ534{Y@Q8M槮t) ڌ[x[f pv~*_}K;6 -"CW{3/8 ]-~J5[Xg=B r88ʁYZ^-7X4'.jI%TXkWP 'Y:'^-D%JqN6Ib[|淇Sk:ҟ\YYC p<]/u]v+*o&0AA6re30pC2\8/.4ohD˹Ҳc`QI={Q%ӻ) ((((((((+7]% oiLኞsZU_U|/,Z8`L:0:1ҁ35Hl康yUC! +8`H V`Pѵo u߶j6|4(!AZt|Ct@Z#{?ҼAc?Wx=^Q>''lH}䵩Y~ ?o)Q^_PSxZmi:݂] bHG8HG[Ws㑦ױ-ڤjhA4PHA8ⱴ/TۥԷ~)yI$>\IKo=Bۂ3zESjXܖ ɝ@w_B\/(Š(((((BvMZ"ZR7(ԀqPj__/k|s..zl/!kY㳶AfbGUu_ iZ-҉$ସCm=^O".'G =A dz+t*?S6J=G ěn$Z՗{_o)ji~0X/&ТmdJT0-ryU#ڊ`y먵iZtucy4FX 8<%ZnfݴW`Up'1Ӛ(V8H>EFQ̶$NŸa30ہucҵ`3D\py)"A2qSZtSz-5G#kZJX-֏mH'Ӕ835WMͳi { J6V&,uRxAdWqEwc61Վa/كYD9#/zsNIwkY(B/+ )䜒yҊ]-t$> uMMu9usu}omn%N|I$]S(0(((((,-kh|v6C޶+֝]YYۑ{ EG8<Nv/B?UWօq]yj*Y\JA=x\_JJ1^/yN%B{_o/gKomWQK ;5sq#s s}<+Kg.e'nf\? 83yxMx.4.Xi{|0`m_^'[&:ik˳Cmb'+뉸Khc3[j&IO@29oxկ#ƿxt}sBԧMF;k$d!VR lZJ'}RΑ.e(,#g;}mu._YGg @9 Cl$p8nյkoYHoyыd6  tOxSMN5 .gäd7r=}O^1hP$MKE0WUfH<7iyu1|(n]05XicR-`#?X޵-6@Ͷb${G*?J?uɾ u3bmMy۽NSԣg["s+۸v3ڷt^}_ (Š((((((\{K BkmZ[[F^Iw(pj/xg\n^"fsmF'@j:h"ծQCqw2ŷq'n~6]][J׭#ޫlAje_ o&PjpHdz+t*?Sz: b$z?}ZԬ}䵩HVָ- \}1`3A =(nJQ^FڿKޣsukCsqwGm;#p w~/m.ē^:oآ7p"A6C&6'&ߟj3+eGּ~#/ ALQчJœlg$Z.$xWV*ٴ(2HMX`J*ERQEQEQEQEQEQEQEQEW?JoFzEy$mbyE;Ts: b[_JJ1Z2QkR=/֥"9<;zUM)xEo8$*ҺԵMQ;) FEb }Ĵ6eG,|m3qlQ H K^{iq2DD>{{KX.#{Rxղc,2昌_u!]H.i`:w٩n<1MךET(2q$anV BOk{Kt 4NI@B` *۫[+Y.nanY" $J AE!ECowkq,[4̨mv8=uK=kO%}PvW['QZ4(@QET^_]Akm̓M DAX*»i[/i8 (ĺ6}qg\p僸DJ,B1עii2wg"l}XP^ ب5l }29+?h%woU{_61i=|M&h#4} ~"gW?T,~odz+t*?StkR=/֥"űmS_T2z%l/6(q/^f:|9HjW:=!̖qhpymwŚ u+HЈL 1Z𭝼IqOl!H␛ud2JM Dg}SFӯS$,? }΍\PwU Cs%4d~]j7WZ%El-kFX2Bt뜪Y7z.Դiڽ.V58Q*߃9P+ⶆ;‰Xy6.'T=jo=2ΐI/h9 qڒ[B穅 |-s[JeXnCwWko%m|+ooo}$yۼa^kovְEԎ4 =PŦiOgi;O ¡%/.0ZwI_Ցvw+;@_ϦrMwyxܸ 8wmQz=3Lo&K[ֺi&e&NH݌ת4ǰk1lf1lTP<:g\:Mvn,9ٌuBӧ馟ISީ߷jQ|g{J&_1FHL!#xwBԴsP8-$#IX͘Q;^-PKm a {i3qֳ|/ᛨúDƲYFY#O$4y_ҳ_~w.X'm7Jñyz1fsn`슥5 o 7%z$q>#:X*B=+Լ~+֧ic}X-v"X8-:k_StmR;]OI/q\[$cMKG~KhΣi>ֵmB宮0q,L#F-dڴ/ޝLlaVkg}~K7BUGiJ)8'9ICgғJH-^ +B0?*þB糷Qo-m_ Z/~ .']j \M nIL8^6~okng巘$9ی+(5mi p6 o RX6<²;tLmX!&} H~xX5>th.o\01,Lg9'9<&l?vfIuyMRXZI)B[l#$e צšhqjEiɨw] x9|g0OJo%| 1~xg_]uc,Lon{?ҼAc?Wx=^SP+?.o3kGl?;r-jR(fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣWѹUy Eq]]|Ť|EdfVV."gW?T,~odz+t*?Sn̑kR=/֥".ܒFl|A࿈!a^OKf6wd#)(@<G){OS;k4ltcw𖇬bm+XB!c.csօko[::(Š((((((((8WxF-z=ywK$oRo=[#}GwZs_JJ1^/yN%BY(Rnn.wέF9ҳ_j:D wDA?xGvg?S|s_ ZE~̷H̡Lr1 +)Pw4"ԺΖw̋4MW}@wMôFc*pڦ :BqλQP>?Y?A?BιHVY?K г/.OJhb :B?Y?^(D, '@? ڞ'*s5g^#/.쐴wj?S\?|= kA4;װ:\ŏuYhI|'=#w%0r>^.j)*D endstream endobj 118 0 obj << /Length 2731 /Filter /FlateDecode >> stream xڝYݓ۶ofN0IͱRgMb_y$Z"}w)Jx.뷻?<:3<˳$׆qmseM~ᰑ'?p^$cEEM #fLaQ.x v`w n4/2r_>f?qm.7\{@Oy^^42ʺns.Q!6սgИ=EV%i.xLh0 v@r {5|9\t8kXj$agښrݗpIma.4 NU=#(1\-$O?J!?w E~[G`sƷxu[RQzmoqr[`T: Rt'"= !;?LVM]I68^nۗ]99Fi3~dάߎ mT}y85S W!$Z [$ΘhOH*GI~tw8-iL} )e♞v=e}r}"0\3JRIŝ$噺\7*1ٷdrf 㩧CiWY&G!a弰eFHw(RPVǹ/ c3O<.ԕ>ж4z_OEʺʀn-#ut. kP"<,,s~Gͺ캪~$SUoӌL"04Bfli@i^CYHDlMDA.T镂| @~ P爊űۼSwtkٺ_@6.Te<@֮  GziޥaS[e@M[W}rer~q'R!ICޕss&G*WSCuj< =~M2t}Lվ -B`zC,cwl2/=pS#o',cGD*@0ߧ/̚AڇFVu1W>SG3YńӺ] :g^?\Pm6H<44]o갿[ `=U]2z6GZv4 x8>|rՄLcۜ-B= CԢ2ivĈ6F?d+@a6s\0<0F n=$;\&9x,6PQI5T "QqZ㳩_ʄkճc<;wT⁜ bbu4s,{[ǼvLs׻Kl^ [WlDSlKμM2 "uB(lC$_^!+{']x?sQ@na& ]=fG< aC</ǐ(:'{$^H .c;["˿Cۆ8$VeTReJPlZ&D*tn`M}AWGAFM.Zkݻ/sA&ᮂ9K"Ֆ۲-5=PBL~һH!h,6BA_' .BDA_EDHCH^7۞ ghw5r|qXmAU~^t6Z7ӡ_?ӮZhZ8[i Dlk_ Ѭ{ ~*0Y|BGm䆴-GajiP}Ŋ a]Ux7{DFaUƗUKhE~jS,kpw;Cf[_v5Tq$F0N8a1VI?_|WZ"jz*4@h[/H;ƈ5݀4ƗՃʨcŹLS— rof7uGBd+n?}w3Ӌ^ǙL-4 u +F3b#`ѫZMH|L!9(fSԺo`gKEAʟkhnJabw,U/e mrk9b3o=P"GFO./$a :bT7lDy AW2n+s4-5G\ԤMVE:Ԅ4MFޡpyK7΋ # > stream JFIFExifII*JR(iZ)( )( 02100100p4C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222224p" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?GSWa#M\El 7ddu(9s4dspI u=I LFp'o{|Hdۯ)>}BDF,r@8T5"["o[>gO4Iql-c,[l aޟ_ŷUDd=>hϙ?]e[;u[-ړq+R*|p@<vJ#.W4޾[zo&-Fi *(USBXO>\Ɍ~"2ЀH?\?_-xrI鸕([Q5R HȒPOP* >@2܌cP*y$T}?w TU_'3 Hϟq֠ TUQi] >ȟ߻P*#[lJSgw?f-#!=h}|@(g nԞ\bV\l ES4޾[zo&%gt -,u̘H-#!=*٣Mgp['W? UF[or[ )>hOzo&me,'d?JESAh4޾[ U?Ð jOMĮ1JЫmKu¶O[?_-h}|@(m )a<s&1R x{B rh}|G['W? UF[or[ )>hOzo&8pGj8`#QK<*;(Vޛqj[λ<(Ңt?€4<v/7M(t?€4<v/7M)Dq8' e[;tFcY;lc'N? YFDj>jEV[Qk֣Qk֠ 4UoG=?ZG=?Z,Uj>jEV[Qk֮w^%écRnVmYw1=(sσ?r_>O:+/KVѬH$H.u 3ՁoxA@$v.QTh4޽[ U?G>hCqi:0FOjzo&GES6z@/vi7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?¥;k|ewB{/c\Bxd0v_ҘM\M_+5q68[ yÁ5o+:'t ׍-EѴS?kC$C9 ksj B"+rXC`FHnAz>pH0QHeӱҮ 6tU5wsmA1š<a $-xVX!q#1ycj+Z\p `[a>bu^iwx7# $%Ew3nmӱ?Pon4Wn/` d>n:.獿?MGq/n]6k0_9 $RJ2 ?B¢ c2nSN?4 ^w%!nS:P鶭<=`?$+o6?S%.r"B[.{Y[kZkӲbB΅##*f~{_5J>G1v[=$իFo*FIy`Ӷ7g5SL+GhFX\ڽ׮ζfl$W%{aj4v<>;af\DjRp[Kxc.8o'#.GK$ï?s\y3% d6vi{K68^P)9$"1NrT0#moFp2 2xVlEq~6TAd Zg[: ]ƶtkXL-Xp܌JWmřO0uAM, +g=㞜ՋFo+{.fFqcqg\ZZ݄ikfvuQ8^qsyqMaˑr o۠DWے#o;u]=wѦE,QGSU \\yPbpGީ7Lb=L?!=8\'ԌzlҶ," x2 <ƕާ_c3ܞ`k2>:8^ְXm1,85 gН(8tfO?*<` qu^us[[K[&+nbQ%ٝve8o痡뺍c Kw% 7.X8'7`y;ۼ Ἔ\UGRlda`p2p:{viw1AuxHk b9Y~ *j,3 /]HH2EԏA"b|3G\. lW wWlJD*4&r{&h#EpUl=vOR[}fS{QQdh~]TnQp= dNL @1XAXRi.|[v\ 9e1O@ =a(PH 5=~ҭݥDv!\8Xz?/wyT6ϔ:{]U|=6%vJ/P g5Nӂ!چy7A7OXd8C4湋fԚ=h1 o0Tbpyc6^]CȁaaHTEQLG{z>D:x qcWӮba7ːr8tϽ!V֗0Eoî~p^\X=ۖvrbW+>`^QR`|Mg#͡.w2<gz>hrKq ggNN̗ST+ `{S=smM.^4kAʜ-_ΖOK{ud|DڅLBCfxxwP3$lVR8;LmCxhewCoZ&"pq p`GsKv_c Fq?jЄ묿SbDDijs:2M]؟_ʪ+7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*}%ŤYd$c~`~U~jlo@W+V>wBk/c@j?ꚸ-Wmj,o`lNSҀ:PؾSmY5֤om{Wac8eu nMqEE8?PTb&vWwkk!8Hw+ǽli6ic}5/S )a? =rO_ƀ.Hl-m溆8WUs'֢򗵾 G?熣MH0Gj6 <1cEusizN@>$Ͻrzd@-h8 %?RO o$udfS]: ?熣U:@nl'كOޒB -}x┠ıGdic+-ϱ2=rO_ƣ򗵾 @X;_T7dd+1Å{wQT+K*r$f.pO:BP TFl *=ǵ  ,^X_ih(*=}6msp:hH5!Fjm.AOIϽ@0#4VOMGϽNYJAeq(N~4)GSS<[kky{ƀ%uX%Ulld4^#DI=6ms{NΥZvR0AN+Ld[v_8߷b;ȣH"Hc`S򗵾 G?熣⨸X|nz{0KnؚsϜ='r H\FigwAɹ=2 /a&;3:$rXmI$U( GQuԃr6FI?]_RokYf/j0F D3l \o7P_'lRۀhz+bHŦ,ہ~PX]\^S;nؚsϜ='OAg6?>j)q3k;܇T~P jHwu 7r6FI?2-;!;$h[Xo7>CHЭ12M4cjo){[z,? yCxj?_*(Z0nE#+c'VŻbk>p8؟jƊʜ#}pIˉ{Y7&8"Vmu+Թ_4a%#砧j: ZM:FqLu㠫>PQTڸ&֨uԀO>$sT+-ϱ2=rO_ƣ򗵾 @~@_V] H ykRd$`ΫyCxj?_*cEusizN@>$v׋|q?,.渽7,A8x:ZgwAɹ=2<5/@-- !"T`NFݨώqj}\#P!6Gep9$$RO$Z\^ ̐2yp ~K4>zD{zwڤq|Q4\!yI(j}.?EVTq|Q? 4UoI>j}.?EVTq|Q? 5俴?EK^?w^ƏũE WZ*ସ;aoJ;緈_jP^#b; |2Ā$c+K yior,+TXJK{[tC*eUB){[z,? ԆKc/_/)M,-V)`:dcv<5/G?熣Ԗ)aM΀qQZiZxaeemmynsQyCxj?_*( GPvVm N*](Z*'ɳv1n1wQTyCxj?_*'tbߍD*84CrYH>`c C[ Pfn pȡVp`Puo P,qty@5gSOoU>'>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[quo4syrs 60)k}nH׎ZuSfYJGe+V>Ejl?pQE UYlX3liM1J) 5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm5l3)>t19ᤍOz9(ofYJ(# endstream endobj 111 0 obj << /Type /XObject /Subtype /Image /Width 663 /Height 556 /BitsPerComponent 8 /Length 57776 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFExifII*JR(iZ)( )( 02100100,C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222," }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?i`(cXƯg5(@(U{fq^'OSv6vCJ؏|0TO}p/Ҹ^ \- \-p=GS¼6N?ck~[{Sx/,]o?tut-p=GS¼.N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- ZO]~ڟ}?+b_~[.N.?(jxWֿG,]kEmO oX׭o.X׭o.?mO >ڟu[_]u[_]>ڟ}?+b>?b>.}?(jxW}mt}mt\xjxQ߆}m.}?(jxW}m?b>>ڟ}?+b>u[_rmO >ڟu[_rX.}?(jxW?k~Q Xo9EmO X?b޶ (^ Xo9G,]cڟ}?+?b޵ )?b޵ (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>>ڟ}?+b>u[_]>ڟ}?+b>?b>.}?(jxW}mtֽmt\xjxQz߆?b^.?(jxWֽm?tֽm?t\yjxQӧo.X:ߖ^ ZO]ut-p=GS¼.N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t>;Yߗ Pׇ_cEmh 4*T'?N+t$#AL Z)Q@65.#QՓCZÈyg?SBPuHmI5inȘS$Hpƴn7eip D?'p֭JczwVm7[ʴhڜ^6w [Kw=-j)J֌`YI+h;{TzZ4g P #wM9$i*g `TrzJѼO`[Owyc#5硸h&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumgO:ז\j7;Cu_Үir}Fƀ7[Dҙ6[z ?sX C;0.r9g?dXG)ɑsN=7HKWuY03юGko#Ik0;˫!ud#@Ҩ_M <: .?mi ZIo*WѬR4dD"-`V j1e@>lq=/Zli #;c%}o0tm~os| vϡة9J?JrtO{ԡ9AE2X՚/1I=,,ĸ:g^moLJEE@S ?uO+)Xg_://'WӴQ`>g@MOk2$bKi[bdp=E_N@1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NEjzIqoOH8] UQ-%ҕ|759O蓱LJJtQ[m%߉$$zi!'ʯq;Z1//'Wx) xv:ᔎ 55i??oЎXobb#V~[IV~[Gʈ RFO֐?MM!YfoX%Ͳy<㓐W"vF/NAS%ςmcrp}k1ܨ۠?wsi5 +3}?ʣ#R1?J= gZ&?MU!者'h0[B\o=قR|G8N)s.(~U"ʹ_4 [ui%n$X* f*iT?MU!Q2mQ&G0VL MWE 3MĎ)fl pjEbX_'i wu>]ϼ5g̨2'Sl#އG]ϼ4;9H9۠yZ=u?P( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ⴟ 7jk31V(X՟y!39+o՟y3i@QƣqBJcJ/'r|C:?$PK|Rtc:91Zr0Pw۩r4xșn.nnI`! 9 0Him >LyXlv?Ӫ~ٽX58c2IUMȚTyp]jV8bIR9 ,r9DI.;[jͣxѢ++FLSFr$L3YDYb@?\uhIoĩpX9o#Qƙ\&2gex?#on<ן[ RsrMMFqm/&=#-qnlb7)C}Gd]bԵSܦm|f&"< 689\Oɕc,˓Ʊ{ż{;vQĥѱ f3ԠsxP(ɝw,Yt4^wy o)Xռ)+kkw[Bxٌ0co^8揲~ٔ,cn9tT>IL79=K-T|G/vCjtB٪( ~j%_ [ *\kmZw6׿ekCnPdÓӽ"krjd`{qVf@8joZ7fYVh e?>7fWyf(r 5j<$ss> (?-- (?-m ֖Y c@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@qZWC5nwV[SgĚp<+V~ OtTqC דyG&#LoPqTN.iސɾg>߱MOwbםiw3X]kss|+lmLm9 L^"]AΈfwt3zS/#~bX?خVŷzLTFkB@$S}xumRMl>cM$hf'#)}`bYϬW +>e4C`4=մ%*@_e 9+_2z>r}QL.bX?أV&7R?YϬQ+?u?YϬQ+?u?YϬUh##EE *-]Tכ?c-;$2OjϬSlN-??׵;/\h^K"[\c9uS+?>g>߱\[+Lk{g[%H%g~:C5ֿ\GQVv-AVM_ ;v3 ~aX?خoI5ΖڂYSyDUCmbI U_wM@wFĴZ*)p3uEη6}}`bȣ"}}`bϬTdPaX?أ6>El( ~OFEA?>g>߱SQ@}}`bϬTdPaX?أ6>El( ~OA<`PaX?ب,R-a! ǥ`YxZYђ9Ȕ}-GV?'N眊nH,7}}`bV$fn#ݖ w I2fQ6g#e|\ P;oYϬQ+?5=fZRJ1kw #30|d>2Q֢KXa[IFPYĀl98sIjC~bX?ة7Q#~bX?ة7Q+gh-"B~g>߱Ipdko j[LP"HC)f GCFج(~p4n=jnBC"D7xVֵ;ۋ{-(ZwSMt¨ G<t_bX?ئAlISW78tt-ἼYZSq!c"u 7XU2g4%wotl}`bYϬWGX܈0&̥Upxq`֮]x Q8fb *_޿ٵ)fU$Pm,C-R2pk}STȬRKKb}X `u5 kA~g>߱Qgh-"B;FV<kj<kjiA]ZI$pE.<~֭l'dL 21\嶉zܗpOw: 8'l*<}htgoiqyq*'?~p=|wFdF@@}+7F;4n7hr:"lrʣcbxkWK[<6¶OSu.LWoV50I>E[}"J_ pn?Z;)㶟*"dc*w+_"I-.cc ~fOA޵p=|wFdF@@}+:m05f`"Ef8X%QMD#<4K˸-ψ2j.GE9,yۭ\]V;Vҩ!xoqߛvf: WwQ#؊ͷQo s͜vͫ*iVVpah ?m?&O*\LU&7Qo cg4agCіB=Hnu/m?&O*\LU&7RfzdͷPn#kc6'Ua4-H14 O kgNMIhC|FK8Ae*㓁;AJMکbfE1.{v9fs ?'wyۨY; ?'Ѳsknud{DF?I4Փs ?'7VN?I4l{D@ۨY; ?'Ѳsknud{DF?I4Փs ?'7VN?I4l{D@KK;α Vp,@Ohoi?ʳvA="OXOqz}hxE䜉 `0{dVA𵤐-AIKFܪ0@Ϸz%>g=.?"_*?ծ5u[de2"yB@sNAP{[t_:Kh|~䂤K?qT}z\DU @$F%%u?YK%q'T:αa=.2ĞZ%]]`U&YW2~J_ 2ژ//mfh$P*A_%6MJ.H1 #؁9ù/,M=Y î~$s AH-\bo컞Ns1`+[%%z3u2o*yN뷏9d?k76r:"Ky vdbRIY$Tkc;IK?qTn{V'rfO8# m<.z QK?qT}z\DUIq'QK?qT;"2\zKR;OOƱoZ%JrA=JvEs+1Aw|/OM7_UܮIv::+L7_T`7T{z}Ò]9?U''Z__tW1 ֗<.KT}b$=u?:?UX.OP^ռ3uYP0 :u _Ntw|/G)0rKy)<<ͣv4-AUolUNTM"9?U_*9%#8cXEHaUFSok_*4s!(؟ZԌݢq?#]q?#V#V(X՟pϧq](:xcZk|w㻫C]+A/N2`Տ?ud<_}[}s?*‹gԓ{=M~|g¯]|*O۩90 eITwv hd89[x9 G#*Bϖ ;4Kksv"ہ.b;Hf1`Pj>/ k T\kY 1'i%k7ԧ2.+&ƊD  Nl4c0dҪXڽR\ܣZ8A#S) H '$c֪_+R̚Nu+ihy.LQdm3)5S][Mk^ %Ii%vba!U gRn]7 3+[jZܮ3G1H ʜ jq{nitXe@DlNޚWן /JmehdO\֖^G.1]vb+֧cs}q.haVڽ9NO%oGyEPYu]Yu]-||*d~GlQO ;V$ʪ2WUAӴkߴZ2Zui3HR(0z)~PwteBVA-~Q]盧2a}Qr=3W.h(;H}V4-vC733Hn}F;x:M[S¸m\[ٟh3UzLZ z)|m NjKmsO{+yIX_`+o܏Lo?gZET3fUtPO?gZET3fUtPO?gZET3fUtPO?gZET3GqlfU=p*gZ>V fUngZ>V fUnsleTfUoTk y;0]0@,A ^M VXCc֮cWPXt(.8HmŰrv@TBj->ƞ\9FTvsZz?=_@֚K5Bmy$czW+fOӢL[EW?*}=_F𣥃̡CvM;=G߻o<zu/mƹ1N yt-LkbQK H}9;M/YCdv׉2ynd.wdqZ>GڿkksԮ-4ۻioOR .9SqZ:C\i$t\FHNpѨ%x_~}֒,QUGڿh__~}ր,QUGڿh__~}ր,QUGڿh__~}ր,QUGڿhGqG?Z_jޢ֏*ڿhWX֏*ڿhW>=fqeuvhKq,Ѳ+̻jsu7K?Z6,XRL;`vI\ͻOBYŬj[YC@iG;OߵL=\5fxԪH@ܠ dQ.k#U4~6kl 31V~csCYM[yvȾ]5L1F7',TRTJln5}P# _915FC$Em<ͺFPsdrp*__[[ܛioku,IVĥS;ra9Ϋ֏Z+CV`mVTW dZ_~}֔*$N<k!Z O{G$? V8H|HBIׄu&hԆ4 hBO78QԜ i%7OȁeI[ cH }P(HXc$dP1#XlØ<Ew<1kzOLY>wu,X28LḧLLdpHfڍluw=xϰ2xvay#^9w zu gYZ3**@Hw_O^9sHEGqަVbP>1@Npp=&SCVfOG`=+'evЖ3ҺV_o kGFUv=F?;_/LNXobb#V~O#>]wwҸIg븠\*C+5 *W- qBN3) 导Ei$ҭ&GlqNJ% ovEq` Npzg\EׅEw,Rˤ^P,Gypr2=σ|9Xx9wq#hđXWNx5tsکª-.kwGi>?/DZߝS47p;7lQ=888Y6$ni ȎBse3ZmƯ-L?e,L˳snhxQmwv_J~[Oڕt]#3$QXx̖Ƣ9YsbA t֞=fۙ4۳<3a /uz,1{oxv2i~|3a /uz}~:(Š((kBhvDݡ]&M 8Tr?h~K ȹ,Bc)!Ӯ^~.u%gF$^{$X`@ ŸzV~ gmDH̿jDA?6ڢjol6 O*hW^HNyo5 `t4罟rqН7k6vQ[m2IGd. F'R1ЌpixiF{{;OKg 0K~Uizk/iMl-K UPrFQPUЭm>=:m9;BG9Eu\:^_KZ}3O"XFzFPI(X#eQe4rsP)'۽ n d!zg/[7l"5hV̎ ;p}~ͼXtme7#s sM\֥ ΗU@RzKIl7QEOsLJ WGiP5Ux@P-XW.ܦ&dv{?ӌU]n!O9bi 6%sҸ[>[yTMK7qq]o-/{,k!Ϋ)vЖ0+z Xv_B5a!ר`v[S+V~O#>]w477Jꈱǖc9nxKO jwHUchIdRWvGM_g<8nEI?׵練ծ F59Aµ<9jxJPy3>>L=TѻQzr~2JեiP78Kv./L*[6'(H0zɸբˉCMDe+&oK::_'QdjܵQZ(°(X8U ']-bP6Ӭn<C„یc֝Hԏ2Υ9S+~̞Gٓիб[G-/Q|ӑמ)8#B-ot&V -c:.ufOV). {od"ȸ_XڢžnJy،cg`Z_fOVՇk8u-5l#-qawo8Q[xm>_쭚v?op9c ·}=Z~̞Gٓժj('Qdj}=Z!2zfOV~̞Gٓժj('TWiyo[?_ fOV5ٓը2zMECdj>̞SQ@=Z'TPKd,ܷ?ʥ2z-z*R؟7;Tw8֓v_'Qdj:?59.Mq$iuv4jAeL`cCS&<1S݋l- y(ygoK_-mufOVYǭhOKK+K47Ny*)|I{aj^^SI%buYAP%j?2zfOVw^#JiR57 @/ \@5>{bRnmS5˶,q-2zfOVWT 7z}jHw!ZkUHV"ݗ/q'һ ~̞Gٓժj(.<kq[z_르(?*>!+6ndk y3M,M5N<␃ppzZ5j,Ԡe[)O)ZbJ:@'iy8.sJ$8⣑4.쪊2K=ii8nq래r΍>^J f# 8 9=sN~Č(.B["ZsYU_xH7<qkSzjWRoXNL8gX]_J ePl;~ 6{,Q(y#5Y݈v@A8#xֹl :ݥV +nݑG 'pq/,& y㓓=OzTӸ՜Eې}%1}+`H+Ȯ^u=wX˿v$c$E;QE ? ? -ZOt7ܯIpƸgKBe7sQHڊmavQGii롍B.0 P:B^bDN[g@cԊڕ_W|ؓ=3JKC$+)|? ֝8ӏ$v1VUf-~ bsdf!of/_'ؽX&㓞q[||YKR]%VR7wnlJcwxK>}^^C['nѴ 2{v]G'AG'AI_!obhe.[?`WY;%vcXX_6[5}JOh| 0?iQU7y\{.T? O~>O~.T? /QP*'AG'A@h^||]y{y{b=fqHFTQY3Y~o=IP:Mèl$paܥ&yc=vپ\AaQ1^]O'AG'AEht OGMrf9`IJ?m[iFvq[ h%s V]9U$epE;ϓߠm,nahz9 QeGchҩa8gp{AkbJN~v߱*y{3~s1ӽ=$/$9,S'AUqX˽5N1}#ܭhVܪ_q:N+^||.vQPs_X>64? VyA\V |/ԆpTQE1Q@Q@Q@Q@Q@Q@t 7]'37{a!c\u#HgomQEE1?J'O⻻g\$3PsT5gX_͘ZYzͅtCvcyFP:V&1Fi9SŸa!s3#6b@+GC {!KqbT׎s׵1OhY2ymل1ujI[ gVw.dg[fAs޺?FO omٷv}+ PqflM)OlZVmW⛻.#YMy${r0C#kfX|t3Y3ƎQT[nu[FRmm0D$|Sf.tV_](DNsߊ;EZ'^Oe& ^jI$[ ˓铐Hj}SZ77b6QIDY{* A1W%Іo{:A}-D1 3z4 ˧xbMݵ$:wlr9N–1_̡}{k>m?Sy'TL(p~7z+]N9N]>q)r +֤O[Gsvݗi cgt8J{g.)u_7_e}Zo3$ڼѬVD!.0cJWծVXW7%*ͻdVlxcuƯ"(v*v#5ţGssws%Q,Һ~6=+~sԳ[Hd'- e,OXwV1Gأ:L>տ2JUQF7sJ.ӦNMݦ]Htp1CiK="muu*̒ 9 dvZmtm@X#(ITLJOajKk[!]QEQEQEQEQEQETsǼRTsǼ@QEQEQEQEGqCCsqf]S-Da9T/S#֓}?%UԒ,i7!DIʣuߨEMaer6v -]w5-B,JqK0HMIUfmi wQ5$q\;~`dxq5歬DHXjՃ>{ú~#(bRK~zW q-,qmOCPZ^[uk*(QIYj'Onw2gP[a@0E#2`~P2Gpy腔0R13ɥ:7^{,添419A(=*ψEaw֧OO/QY%vu/pLOM$7O/G_ʝE!QQ@ QQ@ QQ@ QQ@ QQ@ TW٥=GqiiSiSiSiS.cO/n/_ʙsʡԬ,^[}}Gz}}7epE-?Zq*tVᯆc_=$Vģ7aI'?wo9 ދ"O mUU!sc')t`].-/գ$+Zq*,.5ߧeixو0i?G=Tӯuhޝg$g$eX;Z-]wsXZG1v?qV~Ӭ"B<[@@R;|j[!oH77\>R0`*S}i[zWO/\?ش隤z|vBIP!$WuIj7iS O_z<kAjC8*(((((((Ofoo k?BZk|?5Wc!i Պ(V(";g\$3Ww{+F}?j5\qvO& !⤨yRgeHg0 ,uK:5C%ws!VBy= jn8McxGvښX(2kA;uK\e'aE-4,rN7!A/4Ym--1O$o=@u`?Z'5SLmm:R Pq𮃐/titKa& Hs8`i>irͳx[Udۍ0 F$%\l"0cdz{dTyQEQEQEV]A-hV[W;I"/ Ҁ3olHs#рOV_W@YE0̎4u£kdұJFzjH]öeyb 4qɠi_%O4y$vV1 #;SVbNsޤ6lTXXlMOeR&+KQj^;l#82IKm$B#8V_/mÄT}yӴVooBb/e eveH\[Ofb |>QI rI+\B %#,0H@ E[< !|tWBA+)!I5@JFX`::TEgQ@ (?*Z?ʰ|m h3)((((((+OfvЖ<!ݿ%_3]q?fXobb#V~O#>]wwҸIg븠~Fժdp%Hґ b#RMe#Dw48W7IxĮ\6w96W45Yȳ!YvF`*NJɞL^q]3;Vc}jwV6؉H. g,CxaiE%&p3,騵V˨%8B,58;kSYY>}JL/p'^K]O#C˪N$jrг2H9!ĺ\iOrLVUpCrN3Ww.em_LAgyeI$Fe1U}n+hhQEQEQEȯuseuoƝGr@S q-̸6 .1ךۥͬզqs }ؙo+U,V{xm+W2mc]ޗk"7**&8"}YM2I@:q(9S~TyoS~TyoS~TyoS~TyoS~TyoS~TyoS~Tyo/T[q*7<#}ڀ4yoPhyoPhyoPhyoP7/W?/>ӷ_)uݷtWeOhP<4N0ț=hͯ|ɡX[[q02nbw- TWS[`;U 9?:?<ME-QZسȶZFCq-۽ tu3t/i~HttO0{Hg?gݭRiKnJcePXߕn c'K nB&>28K+layVA2(ko`חu7]6x[E?"?wammI,Oq ɕ[09۵XԤvKZ(yۭ\kDyե(=p{g![K݅ &(=7&W,Ilk<I e=RyotNQ?ʰ|m hO_ ਢb ( ( ( ( ( ( <!ݿ%nOfoo h>Ca\}3V(X՟pϧq](DGqpH#ET1g6OVw-wڴikޛՎs zֿם3y\뼥RƹmgCOx/Z4kXyN#r0jwu5^^-w~fNvF1ր7<Rƹmuskoa6g>vgkq-ք[-f ѹpzJ[v:)}_?G}G[]ڬV ͽHd9hF\}:Է1}E4uc}cdߕB{:\:|Rƹ7X.|Q1i4$3MV7ʁ܊Ov%6|.Ēlol,+~RƨMYu] i,/&eff- jiYIG67Zѥ=s%N}MpnH`".H+ջVY$OXq W#{c1ϧ@;F2Q=_k'|McQ÷5NOr\u ^fiq1}k2/=0'%M'K3gc9[sw4QE!Q@Q@Q@Q@Q@Q@Q@GqIQǴ@QEQEQEQEEsʢu+=*ͮ¤ I'9$ =fqs0an-PYn Rϰ$sڀ/H}P]h!vrG5nT-2Ą3𑁓Àq\J~wu@ַhB4SK)ܽH+7ڗE]^^Y&sj:񞒚ej.EG(8\`3VOiVHyaŔ˛ xY Ac.%IFl=+޳^h,~hچMY0lV#hoF]b3JM»"BYSYӗWJ7qD2傎3hj%o-89Xv_A7ybiqӶ?W4%Fk\]3<.?9]ZxSZ[IB@ NXwt{(˴(?*Z?ʰ|m h3)((((((+OfvЖ<!ݿ%_3]q?tv[S+V~O#>]w5$N.属}*zdsGoqq$ I9, O&9'v5 j53^9K1%Hzmh4#6`3SAuosȞ)v6?* dt*󃃵\kڤVSl- ݑUσPZoMFo_ ~@p6%vw_z_#>M5 A羾hݮGb39ɩ.?zE{ qks/qݜ:EErFQ&mF;dاbl ;*{ Yn+gc?skG4SnG[k:BA~ ]ujQ q֢`YFw }φ<@>׷^WG=~o^տE{;o4YD%(AV6cW.-5u'${Aaw?ۛ淼+zݳ<wⶖ ? ?3:[{cDgT>Yb?Ÿ#c̱#]qU\ߺyT$QVS4X* Vn%6,"nO5kϏߡ[9tt!Ӓxt')EEqwVV 6|\Zk؉'nj{4y{5J/ B)#:_/$;u=.v~| | svݴVZImN2IGTӅMIǟ.8 >?~>?~+Rh%Ibqt`؊.{4y{5J*(CGCT | | R.{4y{5J*(CQ\O٥>^=p*<E]hjwϏߡϏߡTP>?~>?~Q@.g|ݏKu{KU} q(f`{Ā PǟCTnl.K-BYd2Y}̰q9k x mvLW(e,. c }Dc-͝ŊŒs;@?+0ڍ#kϏߡϏߡ6/}>[stxf\xNWy[i?~>?~EŅ),Dw/Llؑأ | | RiP5UoC_ oZǔ`@-HgESQEQEQEQEQEQEWI ^-sux'C3׻K@q_uWe!HgmmQEE1?J'O⻻g\$3PsUfmjC5ij8G avaǥ!DhKRO@?ޫ:~ $n #Og+ f ?@1jnt]f+N9ABW$:>SU{_TپYkn:~e@S}V?4TfU 7ٟh3CQZ3GqlfP*o?gZ}V!3fUhGٟh{KU-FM+igELp^zUp+b/+>@dQi#m:FcVP Wއ8C\Ck6Q$jR>Z`*Mj]k6 HK7*ޕ|e5 nw/`w(,ig\ )[fYjaX1WQ ̑o;.1$eAx=K]cOƍ=$knuKE6%(ѻqF[ t7p$OGmSӭ#Oƍ=$jndzIѽ礟C64oo'?PuM礟-9$u'?µ?eZ=2G%ˉ8#=^itfҖ #79\>5qݚ.xSrwllU჆<{Gđk6zlVpLM l,+RpN=9/t=OL/5+&k&BOKxRn$/.VXw`J'TjmZwzwZGe=ȶ\9cI@>Ǯ}Rk-YZ%ۀy`R?ʹ]V_u4Pc)4>\IA|<zL]>Aey-5{z [h)tYWw[ PWy~>Զ~#k.M6\\5~#;Exz>kkgv.r ojС4.=H muR3lL|>BGYn{跰ˡILYo&"!y f PWe q8TՔY;bw FӎqsM7R)K/Mͥ. ;/`dx+-_CL^ EٚI"O."I~Qx@S[?.nn5 %ڧ r:)$=*վxDࡌW$-\[C>&v>Bx R֯緊k-+YRʂ;Kk~K#u7WHlv5$/z :ҮKCQxwZ}vk,⸒fN9sZ7v/n-Za2*!ԃ\V?kB%[jnd$$7$nleosADG`FpT ؄Þײxr]4OIS<% qsOŚ=qne}m,oJ[u)G \Í g'#wJ: ~'Niopx%H.g{myu[(C*0zUeoc#MԠYxEI>̻ܒh|*wkO(66Co< (\g 22)SCcoľl}&%mz*R ab/'f (<}転A80\'2OK>Qqya`tv:䵴̙XN:OKj;zƟaYmvnC£o4Q$oH6!(!GVÞ׵w:[o?^UjohźMg'8=)/??6Ay?SF1\] Xʳo0>] r )PЮ Lv%'ʉ:H.@w=Š( O_z<kAjC8*(((((((Ofoo k?BZk|?¸/_:C;kob-Պ)YW ?w?J'O;̾Q+ pC:ӥ63A:W4 [i7x3:_n9=(VwQW:e(;wf [ğo텘*N##D"D6Hn#R A޻ +~9zc֑IHu!Cm Xt $ley2]3_6zƏLǷhf1} QTHT+wp71AT\kiy:?L?3ok&V.VE"Ti6^+<-ǘ OLqU?Ui3C6zƏLϋIGݧTy#ӽB6upd h 3ڇ_AL~/ӹ =cG&m@cchZ.$=pA ׊I\̈b#{ݿ/b?! ͟Ld/Yx7Yl#o"ˤC}8y&@&8 rG5KQ[l`z 1H$qבDe0x94w~T%pC hv $GBgҤő@\i1M4rKX{kim4[ڬWO=DMڠ6Q8-!懈3NĖ|F+-2rR3뀕g6zư.qqHDIQTTKN_qWQ_g&m@5u/o_f_ =c\7Q /?3oj9d=yR?\ltX!< ov7? ?>o/ZMߜPDOOer 9Gd&7&Fpqޟs~_O0ܼ3Q 1#h4ɬ..;c9Hi@ߩSt15(HRHD^!"r?>o/| _+KYt{]HaAX 1>p6%04 +] $g:Rk"eoO7? #9uc#7 3nj/bI 1#&FjͫZD@$OOX~_K˰~/ηbGaQb{mo/ wAe1F7by`H$U+k$I#F䞀qGq֖ &63~?  <ͺFY\'g'¤W5=xYʞ ?2?*p:,kp::+ \*=OO/-~ooNܝ3Q 1#~k|Ƒ'Fs5uo{"Jo7gi 1#bGa\^7Tv~//T(?*Z?ʰ|m htS)((((((+OfvЖ<!ݿ%/:+|?3V(X՟pϧq](662QLAEPEPEPEPEPYu]Yu]%W}v!e nx ?{ j73]M-$pH=?Bw}^ELg7$17_HۮT,nUGֶmC*pan#ߵo{? ӿMLpxBT5ךsqZ-[sHORwg Fwv>YL9SbGui_&Bw}M+{! 9ۨƻHaF#zG:S` kcʘ2=y뎧o{? ӿM?64? W|QEQEQEQEQEQEQEx'C3׻K\t {\uY~QmQLDwҸIg븮YW ?w?RR?Rv( (((((z@ZЬz@ZosVtyͿخZ/5?0G^k_j6jV 8{h7|KZdwjfݹ1\coZYH(uqSBMi5 [S/RxxEĆ8OONj:ՊH~9@LC qG$vI|\j!7t˷]ӥhj ѯnmK 8dO+ u&QT:(j7>cX$Z7W86g@668'sW;]B7ZD{cgUt WеK]f=Vվ(fYqo0`ԓԽx@n!vY =:]mS~ɯՄ`; 3 53ڃv[]j-usC4 YKa0#i$Z5\Mx/~" @ 0F1Ƨ HUFa,k .С7pO[\=n&K09O, UDʼyȈ*>84;LׯS@{t]5fgbu$ ]]i\,K t@ pךtE!1gPct~uNËyNmѮe1.Hb9[M?v ok-gOuPNぃ XH/lA'd=A\bԮ4l ghU5/}k~_)EV|Q? 4UoMoߗ EV|Q? 4UoMoߗ EV|Q? 5/W_ Sk~_*l$E nRTt?JC3ЍO5W?_teT{S>G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{*9w[IR0/=i{G} _(/QE} O=i{G} _(/QE} O=i{G} _(/QE} O=i{G} _(/QE} O=i{G} d5\IB =*O(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PZǔ`@-[i{G} >tW}(L?P#\L?Q?Р#s0hG`B<ϴ=i{G} :+>}(\L?Q?Р#s0hG`B]wwҸIg븠(0h 9 $s@QEQUcHǐ~4y[ʒ<bE h((([0Y܀Y\(>h?ռ+65۩ati%eU<8> .#0/n,,f՚WۋsZkK{j^|z5'%) j+|)0z^w5Z#ͩڥ26B5ͷ'jyn|@ !wusߵ _O3\f=bY,MG*>. vz+ًYW$鎹p:|њ|g(}D^#7$A\I)xV$MV;&[)v`SbuL?;<њtj:պ3Bd"! |dlҫ 9/qH,.!gt2| S1<ݻnE"x3n_&,adZ^+&s`.xI H0cJׯ槙]\VuiuKY$yorăV]suKCtm?0qzǯ|;,њ"҄Zc*rBqb[=rqhKYO)5.Fbmt0hr2xR]BHV9|ӄ<=G=)^!:ޘvOD9 INFk ģSHhv\H|;r3ӡP=uT)qpXܶof73\Qn&U3q<'Sʽ]UvjN:YoZkYK0nF]w4QUo`$}$2"m.N.K,qD (weί麄cpA"-QY6Rqc{k$-<`,zy$ MJ;m$1#dykX^&%+Xr9Ns2qIch\p鷢7,# c#(ZijEP$7Ios$`E3.r=2qOeƟjI$ ۄ<{{o.WJ9,o"!HfK{#)s9q3(n=CZ[f+. ynR[u[j̿z8Va.QU&t{+؞eW9NjVUtæވVGܰG$݌tu ROi$lH=Gn=RǶ31YKe}j0=AV]rH8 e, Ap\3,R JTps=@(n/$<_ö@|9%} o.WL˷0N8Pף{Fbʿ"`}pA%cj}I$&fF;q@V=Q[+W1" A8 Tt-V( %8rG~Þ:P6%[܌RiZŞkum,Z(b + HO:AkՐ 4I{V񨕂K@%ϩ[,=K*F# 9:,o~ɜyr[I- Wa*νgtWN7b8<ߟsESմˆ-g~qL>=FkS²ur(xk b $9ޯx#+8rY ˴ž[nynoisڅ %ef5[H {C$FU/x@UkmFxudK2#ڊmn#k1=|C"x7r|k#`0Zi umt%{,avdq]ƦڏM&v(' t5-i~\1rN9S4pZK>j( $fR89ObRIa;N =3P7׿O0oz-´"(d1kQ@'$$OSB ǵmi$kԹYN@s۱}U x{'ODm;K >[TP޷9=.-gzwve*y70s{iwV[MIn!WX[І 3NA>q9+d7(w1R(v}Ek\E`~p_5@w8]X<'Ζ -77n:H%4INF8Ϯ;VﰬrMԵ-5㴅XNX70sAm^ms̚-M-͓EllIʾN1gMvRc95Y<,<ۙ=:|QGw@w ]j:#6ٖY;ϧM_H,m4? \o\G4q\$KM6 i[[$Lɳ/RFE36Kav YP&e;-2:}ޚ^n^kfePHC.rq][B?9+e/?;Wş[j_U۳_? v)G$kY.Vإ!vrvI] 8pzo̐{Ē|뷥P _vC}:KlљwW:z%ӰNͩjkedm-jRRY3ж1) Se[I$dh㐣ٮҊ]-jG%jv^[ܽ [֞D;pP8$s֏k[i,3y`9$Q[2XE P@ 489|9,56H p cUJ 2Ik=֡cÑɜ # wSt]jWڴא[YGdtفY2$=8*Oh-ei}寖O&4ه t=^E Oꂊ(EPEPEPEPEPEPEPEPEPEP\:됳wo@EG{+F}?՟pϧq@QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\:됳wo@EG{+F}?՟pϧq@U[h%zM!bYz\UC"{hC9; I?(6vQx\()Wj󵪬^"fHd+;Rx&@w.᱗8sBCEdM}_j"o7' w~65z[xo LO8f6.3AP+&6.w(H$v, 0O*jV,pC@(((((((((((((((((h$\{As3szqx⩖6qLoVP"٧ߣQiUc5j=ơH_ۜp}igh4? +6>1vl3gZiWWc4䲧\PF#H f{G~G٧ߣV#uNiE9m BRK9h_8e`x4?7P7C"Y_e1#L' I^S5E9]c! i̱x4h4?˻׮%Ӵ; 󈣏w*3K/ t,?}]_\:<V(X՟pϧq](.ԴqKN?ʧ?`'U eU4h$y!R@.m$3r'ҙyӢ-XM@,,zz訦M j6oEkyO5[vsִukѪi6bIp9;ճ=GLw}5乒o,+G9ۜZ;csiow-k wOpaV 僀G^hx;,5%1QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPPzUdr$fUt ʤ$2@#M7ύ@7_]1.|1eoW:^moy!UB䎕KAf͛h2E Mu|u>7_]@?OimԞRLzN:_ZKv חOraV # G欱*Jd$yDYsύN.y j'~qtyύH /i]ۣ?/ j5."f"[*Yv'ޥ2 TeCq/{B?.2Z=KIol~mdI"u]@ ;T5msS20MfQ-1v|ϙC #ύG'~qtZw2t:VX4Y܌g?J_B}-f'ExYRǵt|u>7_]6u1[tK5}Bi]@#2[>HO++ 83[:]ņK pq6#9_?.>ONbOI2¨yύA*DVS+#&p>N??:ҧƮDh_y+C7J27H!Mr)ArRݴ2_2cjR|_]p{zYƍ/lsҴDB%X1g~EmjcN{mK]MHT Q'  Mxd+,mؕU#9,}ncj_R|_];Pf_^lѐ8EV<ʵ>o/.mKquU)+ЂV[l]{E%dcN9$hqrǧo8ԻG66)勻6+wo]}r9խ؁[ S?o) +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57R?5YOO7oTm> stream JFIFExifII*JR(iZ)( )( 02100100,C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222," }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?3EA40(\Oui2.2!=qZƖޏEjOZOZW_ O ?E𴮿"'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=IGړּSQ FI(I^) FI(u@$\kRzu@$Ѻ|.=hRz׊Ѻ|_Z7_OE'jOZ_Z7_OG-'{Wړ֏'x-'Qp=IGړּWQ FI(I^+ FI(s>K\jRzs>Kй%.}=hRz׊й%?h\τ_EھԞ}=kh\τ_E./ o"_jOZ>Ԟ./ o"E-Qp=IGړּ[-s>1K.=hRz׋й%./ o7E'jOZoZ?-I^- >|atϹ%~Ԟ}=kſgό?nY?7{Oړ֏'x, >|t\iRzs>0C?gό?n?jOZ>Ԟ o7G- [p=IGړּ[-s>1K.=hRz׋й%./ o7E'jOZoZ?-I^- B|")?h\τ_EھԞ}=kh\τ_E./ o"_jOZ>Ԟ./ o"Z?E'jOZ_Z?G- [{Wړ֏'x-[Qp=IGړּWQ FI(I^+ FI(u@$\jRzu@$Ѻ|.}=hRz׊Ѻ|OZ7_OE'jOZOZ7_OG-G'{_ړ֏'x-G'Qp=IGړּSQ JI(I^) JI(u@$\kRzu@$Һt.=hJ׊Һt;0Qp=N<05d~T:\լ|R 07#nCҲ5K.&9v\ּBJ\+vl࢏a5"T֯5Fal~l` w1wϷ " b s^pOBWWJЮU`c_VG>Z]lnُ]+/`iVa Ej%갭7q\,I 7ny_ן?ࢳ!Rd\uA[AvWBԌ-XuEݴ[2E%I?#8pִ쯴O :[ɥ̾qtBNAD-lpa@ מWxm}v8ܖt lzecA`< O쎘n0Ad ZZɚHp0GMqEֳCp`yV9'=?P\IqۤG;ā>G}+nF嶚,'vAֹ+H[x}JÈxO 7?(>Qkt@"/>Z4 ,.q(XgѸ x v:H$_bX?{qֳ4r; &u׭-QYLfpϻ|dcڒ} me{z֖WW x 8\tWLqw-2Gb8u@՛L6Ϭ4\"p;JחW/<3mũ[ZɥF>(\X?Q'K[q ̐&wʐ"X Sa~-~lnŶ3Ǯb*_-KU(0kII!Ãot|>mYI1>Pnq/<;魚++-;HYcX Sm/.uN]/ԁwl,4WS)PxyБgkK Y-nbn9RqOK9Dծ᭗L1Al`TҭAd ZZɚHp0G^u] /><=ܼMtI{{EDȱ)c  sV Quc=R#+blwN>a_k[譍wQ_-A'5]9FvH1rx=V%_ڟ;@1r8sև_g iav-81=3ڵKmu% b ۜ\C[.n{}:=%DRLwO b>۞W=k+=+=WHYF/.>ʜ#ױ ǒA 8 Lt.UއplԁuE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.U#q*SPX/ꓓG^F>y)|XILD(Zi7o̟Mf7[x Yݓ#TQ8e0RO7VWb8~A+ ^[$3˅ c%}H5KW$*^PZ.u0\\-p[ ۬,tZeAp`&dF}*Ś#I*0 :OWR3jt> ѝuÜ{^xK||Q-Ҩy滿@Az>~I&= UĵTHC+\??Ҁ>|!Lj._V^/7UET5 g.QNy>5# F~fZ/D?0Vx^y!bph7QE?uhڴ=+Px H1z}B-mLKueӯ--sB\r1֫PQOaeHètޅw/b3{/.$qg2 AnQ@V5;KŶCǚZ#@C S , ;L׊(WKۣd#_&wg:kk=n`H]z Inu rcb0^inSYwyQI&.IA@7P"҈1+i'juwPE2gX'$Q`Գ lQеN-o1m6AQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@Fe:]Jd`=)_rU)ƋZ:eJK:N2^GU?bN_eۻ1KٯplmÝmK&MR?ڮkcmk_B9!~[reےO׎Ն<9h>ehn:ՈAs%V:sHf S-C_f>m[T61Q0ʹy=*l?OE|E@ S 5uǵng:\{b{R~GZR OJӭy͸i,X:6WbX?cADrPA-l5T@Wo/χ M K ̄ 9Rig2KPUѦ! eXOݜy⋭;;HybR)*.xFfݵb W'J'*>DO#G#!Gk(ܧ8j`[Y$1`PLI8~=Lm r93Mz%߉'4]]cZcF9N?^Y>bRJ@m;/j\iP6FU;?\mNtQo#P \dcx]4m^ yAs?uO(MLaS33< Eein:O]MsiVڴk dВ9-Ӵå۾qdKxa̙(YKvF30G5&mM3\{d_|^mffrЈ%8M_3kDP_…^=6xMK;itƷv#cH~1s"[iZ^#UKy@RF pH/±ZVc[y@B8C@O}<5XY&#[.pWB( 0Xa6o$D-3Dr8ߦGsxL.uCpfϼFX VW_?OuxFk(ܧLB!y}0kĖv M)|T$¶/Ŧ5Z^V98*i'cFY-T9$IP$SwُEk+/j'QT#"W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O(" ?5O+{,7֗ q:Σ{CLMs^籭x/u2SJʬ2@'HڛV`5BbQdu U ^w7Nos! x|9\fK 5QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPU&4yS[E(25> ,,XYW;=̗0q\cT8Jc#CNozGl̷Khm h/JTz#H7u#RQGn>}4aim';1+7c$2Ouڭ]33A$ C}hۨϳq;ŔWj#$Vwc׭yu?񨥶}NGsZW,ZVYd8qF{K5KvY;Yf6Vo m$d!+C|E!h=QaKl^e{K:}ثZvX:n 8yUN9Q\.umu9l&smyܧzU3t-5C׶)no(uܬ'^u{]ξM>G Nfʰ 2292jRyMme ZBZFQ.sǷ_Š/\ B[;uLZy :ejVXny@ ڡNR(];_t}*+;I/FD 3ɷzS'|rEf~L$qޏ :J+[>ޥصx%%w2mGstvK-rOE+ $6*((x]犤i[yP"'dC߿Ӂ+cR[۟6G!` .rcQoQotW?g?iiy{VGQoQotQX{i F?Q F?WH$QXDH~(H~+Ȣk!{i F?Q F?Wdg 22:=dz/%GG%G^wHH^dGQoQot ==k#(?߷ ?(?߷ (^GQoQotQX{i F?Q F?WGaz'%GG%G^wEՏOJ4?J4?¼A{Yiiy{V/m#?(?߷ ?(?߷ (=DH~(H~+ڰ=##;jHOJ4?J4?¼=m#?(?߷ FwM̒ZyE$zs᫣WfvЖFgn|5_}o=Ϳo{-ϙ#zarzN__\jW7se"K` eP@ J2;Z+>(=xolI8MOjs.i_b]>I7  #7d4u4W 5UmO2[=-[RaFiD FH#zv_uVnsu-D1d Oʸ>a}EViRd#!r%ڣ81CVvw1V>#Σq-E<%ǟ%:6ZKo^5ż7IkȚKOʍ8K~GAEs.F*u(ZRwB@9!oPZx{k{}:%yϻF\(6$qh@:+.5!v,c1GRF%8=o_M~(!`zz)Ddj-jV om7nUH֙ҝD܋zLmzmJ*6èU-ʏ %6b)%[[ya6q^?JVk0ݷdg9mɿrroELM__ڷ7s}EPݷdg9N4{5 [qb+nxcҵ<97o --{`susVL;တ[g/4c?(\b<97o i+?Qt MnK]He2's* ;ԞЮ1RPEPEP{j)/QE7M;~^|#q᫻$he;bp6v׎)֟L~u ܎Cq#IP+ZjF0=ꬣl׊BMXH^BB ш~I gmB{U(٣SQ67dn1鎔] 4W{g yB+ 0O/$v/B69턉2ɹC3B#fa`yE]6kx%% :TϖR`n8残u݂Ƙ,A\t]h%ᅚLB,Ff2,.PF zM;t (((((?foo k_BZ|p3/?4w';KKGX# A򮆊 珅i~/kFk M7{yإ$u[tGC=f-"FB~cbEa_LY77\u{rx~tå}(Jy ,TI۩PX1_Z\jHl܌ca׊ܿ)7{}F8KH#-yOV_ ɨCw:|HP&Ӏ9rx~tn_΅Sh)\^ڂ[x1NჀ=jMSP}vmͫy_ܿrx~tn_΀Mѹ?:Z)7/Fhܿ h6Mo+a'rW %Ka_%\Q؎޽w/FD`#+Q$9f}տnUۂB qʀ; ;R֍giꖴhkWPvPnAgr+Qd4ɀİPsC\τ4k{WcH ^5$J@_K O#6a@Ȯ\_0˂r9bp=}խ&y8U)'9?~ӦZȑI,,p y')~Kj);+*"j2uKQN@ ]p>涱$dBJ x(9=*{oYu wqfYELYI!p;UIYؔzhpqjpiwG5g1dPӵkgq/~_wyupq[k8u(ESy6 J;ϟP->k^I&%|(#6a@ȥ}: $_As<FM %#,0HRW1wcmm*(57W,IljOJkzV5vSYLM#Sxu'(͛+5,D3<cSKZ閦_. BibII>¸`w(JdHv;Ջ;.KBB*5*r\+g<еm{#-/ey<(Kt!I ֥ծn\J@,S穮/_OSHⱶMó)i3֛w6cm^Bx[wm:f3 fV(HN~ $28 GLkm q+~y"T?"עhNKJwTr`CB9-ϟEOmg|*zE$hUb9N6PhH=O:[Y?G"Tw$.T"?HD~' >?ƏEȩ5MHAm< u+,ҸZj{">?ƹvw߯r cFJ2ak?Sh[Y?Ryt:]?">?Ʊ..eQ3tIk?Sh[Y?XRQemg|*k?Sk=CD[Y?G"TeQ7">?ư(D=MEȩ4-ϟEO (Qemg|*k?Sk=CD[Y?G"TeQ7">?ư(D=MEȩ4-ϟEO (Qemg|*k?Sk=CD[Y?G"TeQ7"֏-fͽl-8S\}u>U`(5gn *_4w~r-H3\IXsqtw6'I#K @fܧ>8BڽoC|_c?rJ~*Celddr3U:|}~[<1>pDW>4FZ,FOҰ4;FѴRi.oOrA2H\~ռm5n L9iEJSGD$JRF4/ߡQf,y###EsZ4K1W *菰lnztӵ]bɼW- =ܻ‚O7SjWa{z͋BӠŴ\7lf"L^1W?пi~sFQΕ_$sDJsӽwt{(vA3̟F4/ߡG#m?Эj(Pg?h_ BF4/ߡZQ2пi~h_ BCoWd1& ?пi~kQGdޯ?cBM1& ֢e=_yƅ@O(cBME{z' 6Qƅ@O+Z=; ?-i`-I"#Xه2 ~j6* '][Fu($KUYiꖴk;NTZ\??ҺC(7ntOBIOA+?.=k'j6.-{ȾNpHc'@C.o4cg,G)n-ɡE8jI-H{Kǒ9UI `G_Ze  p5%I dZZT3XZ\gR:@CFDPUWL8Gnyj.QvuA$:`Rܐ38?F>€*Z(Rdc)Vv+D JcTkƮdim~(:FM_rhlv[fJA5@GL`ҶZ>hw,&J) cmjv1^ZZ[Io(܏#5c#M oL WI,ƱFb4P$`+F-: $@Qj>#*'`9fXAelSn-0q9)*S寥Qյm3E,H8.QS܊bi1$[SB1IakQޮZIdsK/i#&Ҁ(KcipZ#:rXzyMcipZ#:bXzy-}(Ҁ)_j"F/7v2:SO"\ޠ~ܫ<2pA~iSpr:bfw1"j7˦Kv2D2GJZ+{Kf@Fz <ضeZMp]A]۵*|`F3ж-t6zX=6T@f)g>i ̚-lnTt'ץ\汶CxT@6%'16p1v]wb]Eo~5rIF qH6?%0$lIS̯a۩h-`XG8bNWܼ!1@$ R=+S)xɏ̍,38KݫG o޽bc6qjńjFmujeeP3zy10 ʤ 8}Z52g}w18=E2yEӰ-yҵݎQEQEQEQEQEQEQEQEQEQEQEB׻K\u>=}3 OfƉYG>ϸ*a?: Xd _-?ZMtrZ |/ѯ=3%)&OUuf]vi%gg-oDޔXy8^soO֏-?Zm݆rVW3ZEgbcR4ȁ͸N| @(֬G֫?Zyji@`arjzS\Ojc@UU#QgĖs7$2a+|)'x=*{/hk=vSX<2`|ҙ7;;ZG9h7s^qȫ26ؾ6&oBZ=IKIsv8lQmmoamssFkQ:兺촂<=ѫ=I8uK3Qnu %Q%Q%Q%Q%Q%Q%Q%pZ}wտmWPaZѬ;R֍0vukP>`W '-W4R?n[}?W@ԬL NB;Y鑑z${Z?uȿ {RM3'>%՛[-v~ >]7OJm-@=O>j?!ymq7kljY*Bv1Q'GPծ xYaH#\'oo-QM@VMDŽ$1ӨKQ֑ܛRr tW @q٥Ru{7ھ{͕mQ?PGzWIeo5{n|U;6]:y&^͋@A !*T8HU=݉[# 0I?O.k}yArbkv|.={Xyxxk4Q *E*!YoKJL{)@ Rt YQ`R]~EuOq[x}&PknQ$Cn*@GB3i{kOs{EHW člUJ}2K׼1x>dYO`qϽTޝ=ݷw9yc,1 /"m|[ KT_HufHћYWdPX6џA ɃzU^4̸*TzZ-8roh5kܕ'Lv}V!/5#tyGgo1gipl:=ak/-L:0pAށ_M/[DfOVfKwiw pTE$d 7wqj׳ lo +@qN heei26&LECg?COӭ4Ake KcqbI9$I'5]Xt_rQHKG֫?Z/ZhQE%޸*ơeZ2o2oUʈ~OWia(v?'&bIA,yu櫚PӖ( ;lNϥtz卒3++ .GǶ?QUR r3̨OɆ#WnnZUx[ 0A q,EU>U\b#R@R[ ?XjYY~zʤQ??I\3b(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@u>-]O//{_xzS/Gkqs,~X'V$Y>ƕqk0$+GC?}'y?O4}IO&v,4BB;FqR {DѬsdgC?}'y?d7F[>:y%G넓#?)8jE}'y?>'R@}IO&C?Եѳiż yp.9 p?'GۡjZլLLVQ`>PnO5-ۡht>a3vNt&z'i^Y;;R֍giꖴkvukP^Kjz]?W_@Q@Q@Q@Q@Q@Q@Q@Q@Q@ V~f_>Y袊Koq]?UEm?ʵ)eVd_5 <skM Ī:ă>SW>>$4e䞹^/:I:Fi@aUfMJKidU[hʐYFH珥pTͮ_-)[m+9LwcӏZ]2ᘲNaix^XSI*L XAicCQ~#ԓ(U]am~a;i<4^y2LqO],}OZ:;(n #aUWY3[pH^W߶8fsr~?HsvF:[qՖ(-.*Ѵ$zQV\k8a[gʃ#8GZ:V'Ew8+:%{P 0H&Δ3,!}nw=)}~_bj> Eӥ{ChnAqO-َ=4)@jc$be;Ic ŴMṂ"HOn}<LLnV`Co{讯Y%[[u@`N}{t5ƩKYXc,,p=:Mc|E.7EuʱF9lqXun.(f71# }}+]m}etLvEp(% uIکvlI2nݲ= ~^:Mۗw9+|F#3)t $1ZW[h_oV;0H93PZ8~?QOQ]^,חv`y(fGؓT{u=*-?[c+wuܰpU|C68~4DEDEUk|dxOFO;A;8b#ӣUDd~U^IQITؤ.5WvpEzt2uzdF+m`@9*ܶ_ؿ5iQ34|m _"O- QpWQ]Y-@{IM-y`Me N=/3q݂@|m hȆ'OY$) ǙclZa6ȻsF+[AKkFv LDzvDEDE%@,kR-ձ8Ɍzs\-̺jvPQsSdbp1^IQKPSfm,$>!73>vvI6{gNbhf :[BCBț#,B$zw?/W:x~gct_;;R֍giꖴkvukP+M'IpFcfaA<+Q꒴Vecih]>U8ox#\eqI~c2fǟ@ hZZռ-K Τ+(hg۽J{!:;i٭*]RX$w93Ie%yc-J)-@K0-YN8+ykMѵ_I4[٬KxR߉eT9gVnjnoAKY۝]b>vѳAU%ܖtdsy&Đg۵skfRA [f{O.tg9t)t_Aٟ{htEck6ysܢ6=pNjͥnW0ā$2S+?RѮuE8яWtY, npI2Ȉ(@ſ G]N1&F gizέxuk};7VN:+q{<,]1beVn{ {_ÿۺG_ U>TR\Efg' {Qяk7Zƕigy +8#3jrV2M+%T`J63k^Biwq^^\I XpB;P:օy[GوΘ(9ҟ&QHaEPEPEP%UYV~(#Wx$Es# zRIU>\˕Qe?v|сU(մw,0 &CXxgPye/3FjSiW y7s|aXW,rH?fMq '%- UM,\: n/'S U& j奭V6s H,_n㞵_ٳJO&ٿ%s|I`խ=XEuѯHaXgҜ.G6aLz$>q6o \)7j^^Uh7O%H[m8H~"xngEidk87 ylܒqƻٿ%s|GlS.߂kp;$۽4)k-#2+;l`vgS k' qk#x]lS6o \)'{~A|27n a5EP FQNJ?&YmJ$( $sbٿ%s|GlS.{_#& ZUEQd,9lǰ)Zgy)h[b.H H ?fMٳJO&/{^5 6&dGd+ g t }ini8HlE哜s3M7h͛W?5$WC:.5/XʰT %3"q[x~Q7IZiK}1Hx6o \)7jӛBG'.xl/Hc'䓴epGZ4Z=<[,1:`86o \)7i}AZ߂8F-5ydg54iy! Fw*A#]WlS6o \)/ks:~qhn$rPp Gp6Zm#HEЪ6G&֔`]NggMq]Xȶ q[ygtyepg'Qq\68ӥ7c^D'~9>u8۞GlJק-?_:WZ~YZ݉ ,zW$_[cqc)98A%tMMn`(]Wi2qk\oMfM=7UTyHWi%Gƕ]B&*-Np['py>K[qqgs -H\:q^z~{cW $s]Xyɍ kk6j1Mecvy0ps;_p8e&HhTOISi({ $R%'<f]Ưc9_Ir GW??Oң]/Kq+jMmɁG% #V`Ku H-e6zasI{k_j6qgP'\ޡl_Blđʠ,%H;14)ӿ.Lmkw[vs :ۍ-lwwi407eVO?, Xj-e7s^ssLkMBocb # TFd }/)O-͑1 ʳ@ªؔok!Fk-ය'@6G'sZ|6+}-vm\4#9g|hW7vxȶiPPOYE#=ͥ$(D[[@%q)tvϫX-YݸiF~R=KV&L1+ӴX֗G y6?;&ѴdK\Ū̚\ij=qq2y3"|9z~_ :]3zķVXtsss%i.Am9i27s5 2mV3X\Zqd&hYVTSI/#[Rі)7*I vå rW7ZZAC52ȫjl6 .ho 2=0qOm$Rh-di$ӹ'ȊPYڥݰfYdxوKc  ]Z]>:P)48ʺ0eaO_ CQ]G N 1$lmmS`_ȱyָ׬_ſ,^?57bv+?E/?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhQEQEQEWphunF ( ( ( ( ( ( ( ( ( ( ( ( ( ( -j_:딶׺(랾ׅڧ_-,䳺YLR})ti+[X|"Px?`[x-P*)A<*`zWAtiOF)M5sawn],;G;4ShvDo#\'v4=W5=TfFe%e0 9N 㵸dVҬ3G8 tj>ҞXWzb st#kpA7hɩVV岛Tm doFVj>Ҟ\xPb^y#%p1ItH#A"rp\)c@=)ՑڝٹW8܆ym6^Ӭ/RgG*ٖ3j=GĺN;AytVEMɱ}[h;Gy V~Ҟ\߉{+U\0En ?b:&w)H mSy4j>Ҟ\$,` ỴZu4eye_ݰW+X@MtiOF)6}&V(n+d psCͧi34мd`GK[iOF)˟[]Gg-ˆHI72J=ZKv|uǢTGGj>Ҟ\ni/, .u >\EywhK\KNPg~ݹ>jMΛ)}=Q@|U:\?/WKokbv+?E/?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhwQڙE!FjeoQ@ xK$ɍCE&ˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E>%1s4ucŠZru]cFw`W&^gh:K3r85:}nEз [ R%GTEUUSEjf+iT]h_ 0F3О㹧M/jVoՅKyFݜ'k/eoOrVefo$$Tl8 ={V[ZZ ]K5.2"2#ҏR}y }N95t[mUO,(n3g{귶dkp쪀W#'= G) <ךӯ-Mwn7ܠE׎UWs_J>Iiz=]y߈}sQ1K$FѢXCXd1Hn|PEwj+D|YXzdc9zG*n/k+I.f{u.1 ym,4I˵yKj#,C:ZSi"HC,bfFh -:rk/eo%++֯aw>A >ts1ۚ籖MsdwZ @eA xɯB/eo7îI*р&qV]?Zyϫ׷[_Io$IhFUX9}ҏPӳw!̖Yՙ~g@ ) ((((((((((((((((()֛NNb?fJmԮwQ,m'$mַ.om n'H-s;Wڗ;*."#OlK8.ۋYmEme1zu=1ҟ٭7oƾH;pHmdc6K=]5+ڜdc3JtDԬeΩ%<|:O^B^_ wMq$H q̣E׌4"7 o22ϴ0# ^Ɵifծ,1\" `vGj w,grK̨Ȭ8=yV|н]ͳGs,4Qd9[u5"Cqmsl&PFH ЂEs-i]n xemT/6cp}kkDүm SR{^nI4@BHI'N?gis4ms=QG j `Ă{c՛2iE8XT-9G5^lˮ6~fVsONt6{$ªzg%~jj!HU)dVDC8u#꾫M.!e}y8ėOmHY8'+P5+=6nd⹺ĶvP#)=G9>,}.oɪ Y.Cݪߐ .c[M,m\Z\Eos4Kua$*>#VDʒƩFYC Z$LQtP[2.<.![ 8ѽ!O c& \M$J9(V$Uu!6zwMq$H q̣KK6WK lrqחд%N5ۼjla w<-Ə/m=:eĈĒ5OAXWҵK^K vYc(N R+&afglX / kئ}y52XF[x9 xZeu{E\ !p~OڦaKu-:FD0 n#$W7$!5 =-bL:g'tl5b_JJX4n Z׬_[{?}BدBC(8_bV+ev_j$wzwӿ-h(C+\??Ҁ"z]?W_\ں(((((((((dt}j2րERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES6hf4iEW!UѴl&Y#UF+1_hK-r ={xR}H:g#+x'G҇t7b{s .zd%z}&j"̓n;OTSWާk5ySi7davsK-iE*W{]KhirQ%ʶ={]K_etA!x|+u1 SVv)]viE/赒u lH#0#I"C)<V}4d/QMmlsuΛ/}FwW@b׮~sT;Ul *w\07vPiqڭ77"A#=;Vugҁ368u6ΡrӌӶ'DR k{E څih1\fOА^_bV+S?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z$29.T~b!5 =C}M:(0((((((((((((((((('Zm5$\(-Fldh"c29()rE.F\.Gq+9! pΥ#icK{`׭%jy11:dǙ}if+_n3}W[GGНO@kچiZͲ^7y8Y~^mugK֞nUA_]_v [jax8nnrl!d&^Yye%=ۥ91e&wdeo>2>tʏzkKu4KkYn#;2z k .'FAyEjj Zݽ]]5(%[RXڝgZYx|hehsr@ŮNL/4nrǍ qgޠԵC YM)!hI2+1lYxbЫ}}-YK@ă~n}Wwwrߪ,:NSn`ҮN풕"Z?G[hV4f5`@ֵ̲5-6Wǩj]W~N3#lHdw7dkHh:wtnZ1[-ԡ x!p8dO_>76QbYHXNy,w:)k7vv C=ο%9\'j42KOi(A d 'TG|G̿xyޞ@{>'W7Qox)r1O l/89y#|6oqiCui~RT2dy61 ŕfIe6a|;Tx>>Nkl&% |ہB0 8u隦h{X5i$ʖw u5Dߋo21yau >F|u /H.[;Yՙ~g@ ) ((((((((((((((((()֛NN;)j.e&W jz柠iIfO,QqNv$158DǠ}O1ߝqW+8.dif+Tw`A2MWY/uQU/)>7gsښW?[y=;{4P#\O F4 Xd@3t+Ny8}:1ߝc}:5^5Xg{ynDdt:Ҷqs|u $(9U ;Z]ɇWP=٦ cBNX/_"gnqθxo>T7{y%PRv#S^\w5mZOVVb' gk?\^C0֏+DТ\*TdH5k1>q+E @995Va_KW'R#bVVk7 n&oj*l/k;W[ Cӿ-hvkFAkWPvE/x6ǥuQEQEQEQEQEQEQEQEQE~gVeU6(0((((((((((((((((('Zm9:mD i>Đߑfr V-nwW9VRu=WWOGc}owj%X\#= L;UXmeġÌ$z4k5[Li7ݜqҶnByD1I˜p8yl!$&(^FyխH 'V8z(tk]$DCA}n c51?@Z|["CZ#g^ \~lOGuZѬ;R֍t_/r PJ_wm]}rKj(((((((((֬G֫?ZmQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPNNru 5};R;n I+|g#O'mw7K<2iu}d U,t-6=C{o E+=I Ԛb9kmR,c[/ H|úx@<33jeQSEuܱl1c5ދK {a ػc#Q؏jCgRDmLrI ;s"'?QoosGuq5E.Bڄ Axc뷺楠H,d2BΠ8?wz~ w5u-hۉbCnw"|=_\cn-tB1*HWˍc%-!ۻxbyWִfx̹dylpyf,M`99?/Nӭ--Ž6HUE_1%԰a /⧎PF9;[5;ssq-}hKTdhrQ:Rlt3Lm- i^ivv6PɝG +zɥ~z[GI q'̊2DdkW:E@bkY)c3p$$sW[D[KӘM7s<ի[{+ u*G808 ϯjSڛ^>ეl t=h徶欺<OrF଄aIPtw)i1ߛ[n$lc۞Tv(o"C̊lB 4\ {v!HJXa#i=1Z;MI}$0[[ʇ=y^ջ>6RZH`tHnb# lE.:_և]m)lu,ldOOn*Mbj[o6c38 3NChKn2d EW -L4P]KkKLctbO]P41,l$'!uou1?b}:C1["CZ#g^ ]Oo`OCb6οNTYw9ݮ_]CAں<EPEPEPEPEPEPEPEPEP%UYV~(Š(((((((((((((((((i@ ~V햑&~w:u7y<5 ]yO33LGcfsnwc6e)]Fsj\/>$bW?ׯ_Y;=vq.3*r.M>-(1]c6˨^:vR-S ʡy"_4iέgwE[Ƅ|oN}ݫe|f۟/~l8iҴEؐlk3m ZfDnN& T@l)eyERVNon)t_DPz7uvz}cQ$c#8Vk4}-ӵ d%ICcOHE=oxma6 Fw'=xOwluTWƻ.v3Y?kH|2bx HSxf(`U\sKl36yes?uSGfXcZ{>b6dMii,Fo#.Ϡ8.ןWuqO$pdg9 yjkHf0? }:/i_GemK 0V|<_ :+nn~(OQKi#Let m.dtkgH8Uqhv1-Q@Š( Ƚush/]?1\l/k?E/?֝kFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@9:iր!Hckrl%Cp#%4> hȆ'OiGgvER&7Hу8zS?'QG'QL8e6]N >Ъ6G&֔`]NggM/'QG'QU_i.ek4vv$+4*"Is\`q}lao'U0PK[qqgs -H\:q@wywI%y\e\Tjl/}k%guL5\p(BlUVwe}Ǩ}~U}:%[wd@ :n>e"O"Oڦ`x+nfQ!˜К-XGj[dUhDEDEWoi-+!״ky<"X%Wdrދp$$($+^ (-縎ho_+ŗ!tɮB"c+\yǮ5`#$($*k(f3-bqhuη$wZwӿ-hA5r PJ/!/x6 ( ( ( ( ( ( ( ( (/Zj̿t}jEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEM'ZڼG<+c=텴w $pehݛ}a5Aoyg%bd8yH#cO6ZApv#VE%;(98"-QƝ)!;;fQji z^s$[xD4Is'rJ@s]SѨJz5 K_P C07+C:ز' ÐF3X:AMpоf[y `oQjV_OTxre_Oo-1BZ@ rH'ZgtCw0\q嘴- cCB)}=ܔ0uKOt'e8ȑE$p2k|+O[jj +l,$k~ҞYe~[Ln;Yfz /]QUkM |"O;o[>I2˝dWvvVVݕ?uGj>ҞNeEFNỵ'1 ?@Z6uE'#ӿ-hvkFAkWPvE/x6ǥuQEQEQEQEQEQEQEQEQE~gVeU6(0((((((((((((((((('Zm9:em;HKKBh>a[.;U c+Ggiϳ4onQ b:Y&l.tvs}O[[ZjQlK׵O"tR0Io\ zVLZbKuIօSc= N;Uߦׇ_'?7_~}%&jqe7*è*~tX:eIYc &T+qV mc\XCu\q.Io͂D2sd6:fԝN5$n]x8k5u+JvLWZTy'A r7cE6zK"6KFB7]7[f,-$X#x7\%X|W!_. ZvYG,FFI=o}rmBm6Q.Gۣ<sɣQ,ZO>{+%svV]AZC'UA'AXi֟Va{.-49-4OEE/fI{x 5e `|cdQvF;k >@Z5feXWiVɮEbySZ--re ulVQ5XRZ+]khJ Fݡv9jꫯǪ+͐%00rrr#=(}3\y݇Ulʰh.lk/ wb,{ׂe+ TNᜁ߭O1 ?@Z_~lOGuZѬ;R֍t_/r PJ_wm]}rKj(((((((((֬G֫?ZmQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPNNruiusB4runH)keQaUWASG7c☢д_*8EM @z}ҏV#MVX \?9Q)޼-c~ ksH9ׯeokz^[KwLda,14]xN!cp#*H# 0hZ_ 6>G+*v7W6̳@F$ e@Js`doI֠Љ ŵͳB##8$GB k}Ұ#sB~G+?T zE­ՅK""ͻU_ZiwQ +ϱ${hԬ F~b988 Q_JƼ񅍣ˋ[눭Y.f n27ӒXpjXZY^\R[<(aXG/eoRx|][̐L&Tګ2i.- d0!' s@8 /eo޻ m̾LRC`By8v˪3jv 4 Td+֍unb1\,rq>XO6. CN(͆&3) }OQO񝕵ĨWpI!`rX@8]?WZeo>+{ku+{VKh6)<9z֗Nm^M ](Alncz~__eo{7On.Vt[ vK6ۡԼEjisAb r8\FF:еw}mrh.ux5mhi ach۷qX<7SX-N䢓zCKfίޝkFKZ5C+\??Ҁ"z]?W_\ں(((((((((dt}j2րERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES6hnom>k x^G85h:6N@J ȲG#gHdfhzIZb9ȼ-|!Yq]mpF'qzS&d%.uO, ƺZioo@ٛifծ,1\" `vGj w,grK̨Ȭ8=yV/ZV 5K}"G[^[w! Y5Xk9YcU;/}:O5/Lu#" CN39kH4(2nD`zrNtiE/Web\zM S*L ITy:D94XywnHi#n7v'uu_iE/贆}|/v| @d1op⦹,.o2=nX$;K8\Qm}Ɲ };@Y!A,ryI%i>U1ev$q^Z>NeoDԬeΩ%<|:O\tSIԯ?cMde/ݸ3sV_hK-%Cz^sT!ycl*0퍮ZaF ;OWV_ǩ%ԠUJu;QZ>Bo[Kh:0kztmb:\K#t0 랝{gd*^R6+А?*>\^wx@?m?λNTYwkA?ݮ_@x =.ͫC_wm]}QEQEQEQEQEQEQEQEQE2_>Yՙ~g@ ) ((((((((((((((((()֛NNɺi!tm&+I/oFH.UQfy 8]Nrv\4sH~1rk|9y̗O#p rQ#۸D ={xR}H:g#+x'G҇t7b{s .zd<~ olM@_3F?| F0\c,4/c7l}+yϿJj7\5;_|q'I̐/. mxQj0e-͖&K6v=?ֆwe{gz-. wVW G5^^jW&V(sԿ;y[؛XlD |TO=zU#W{KO^byUU2=J̶p`MFC}ڒ ߍ+FߗOH$we|D~ZQU\s֟"=~K;[iuw'wmjx5[bmnؕQn_OPyWG13QU럓_ҋ }WnRw/hAμu_=3\P)x @骳2"#Ix]DX6=Rǔۻjq=:潹hu9fG8+=3wq[F~Ya{I]*qsyn]Լ}mcq4k x$R|ro}ɧE쐫(mӹyޢO ]]͆#Kl&Rʡw)6RԵkk,"Z*3wBzUWsP|Ci0'2C$Zи%'$;M$G`n\J*j^ދKBU+9Sݽmo[vCzlWQg%̷[j_ ls_#>SY>wgi+Cm-ȫ!l+w8mB/qxtf{o5s/G{$o$1$I&brׯl]%/e0%6Ɏ^o_E.a-# StV$6]j>mvdUL8=ZuU;~f|xu'VIIcA$>mb[nrAb3B"çGFmp0~7cjx$,P<`B-MemZѬ;R֍5r PJ/!/x6 ( ( ( ( ( ( ( ( (/Zj̿t}jEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEM'Z"Gayw4Gѵâ:vkeosyғ vFI,?֘ȏȏ6mn[侳7˂Htps}j6hLq67݌(Z^MmTG-ޟG=8OyۢvO𵕢Qo_a]IJZ*+-ch#h#k-qwv鋈up3v^!Jaq–OPW`ݑGG!=-uǧ5֡nAys=^(|N+!b9QY?z#f`p0zSr%w5iڞjާ?)bda0"kcOMupb,mA ϻ}Zcz}<]Foʪ U'Yiսҵ)wrB31;[@jQg)4* 19Pg<C:"?nK7(nW=3\/4ko"wX+::D  s޲%gu:YTWXv׭4z_z7SGS\-K$pįTſ}1Eo;|G̖V07$Pc}r #n 6:"?]`'&^[d]F6ݍk7YaGfZ:;R֍giꖴhkWPvC"H0m]~ΖYd[-ޝ[؟{^Q![rx~uQQp?:7/X{^Q{^Q x~uQQp?:7/X{^Q{^Q x~uQ{G\,mn_΍B31SuryjۏsFܿe_?>/Mjn_΍_ۏs9ܿe_?>/MhA^<],V\hP1xrxOW>/Mgn?&idiNQ%tbCнwCнwyh/MΧ=f/$: G$: [_gn?&?GmG}/ B=V\hӦٍf~l@֬_?>/MTa4&uiJ6}>CU/Mgn?&9>CU/Mgn?&,`0} WCU/Mgn?&,`0} WCU/Mgn?&,`0} WCU/Mgn?&,`U=*ۏs9mNrK:e ($O?tsxSY,V+hû@xd.H>5}_?>/Mc**Ny Kyyc#ºQG;)fbL<ȧ75ծ 3}EvvrJ/Mgn?&_t+m(Kݝ2R,$#&4j)b-"S9|v*ۏs9VV9eqDOԮo-//nkB9ozǵMyh/M; WzmdB+t :2pq,%$O(2ciwv7b_?>/M%XEO./m/V;Wަձ>*sz ~/MsZKl$rX'q:;R֍giꖴiC+\??Ҁ*3<&DM+a@\߃]6rߚjCmtc9\ *ʣ8ocPYƒex@wP۫,?aXk^E ,) @9JHC*Y1#<+A]Bn=seu 2A"m/>x-3lRn#<8پ<*?hݳ{-ZE=<}i<5wNlu Apof]sñ,t=- ̒(+]ZƼY4q`R4l`_8)V~?#Ryq8$z$ }wP$oPD+\ {adKw rSr +Z[jχAk!f#RۼɎsvsލXy5/8\FԗUPX-Zl ;Gvc"ȋm+n ]wWo>3Ctc&ȫ66`{'9jKdnS[tK%U 99Iko? ;+Zu[HP1PdU[ 0rwQ\Cpɖ961Gat>t DJEI\߃g|)je\&|ƬkŮ.q>yvZLwQZv;ڭ_ٽah Ԋ$8/u/|}_Xb1JtVRQ\:Z ʢ B/ɡko_G\^pksXmco-qvǖ#SֵkhmIRvl$A_ɯ5\6KjjNERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW-k\c]Mr6f4iꖴk;NTLC_1_]Ctb$L1@^ ChbyRVD+zq6IY).[trңptHg_[̳CY* UaNJӦ8e^(*A+m@Cm@C0B`0Wah۷1OUTP +m@Cm@CӾZ;%w8#ic\ӭ 2v}s渿Yv ?^Yv ?^;!mlh:Pv= L^姛gn ]ף]נM:[ehǡhNn{Z%.1q?e+Pz?e+Pz6͍6S>s -T4O3No@{h ]F;xc;s*y  |9cKʼn_,󟻌u7}北}北-H9#K$Ktr22)V }北}怒LٟbT-mGkrM)M۳{% > >ht&9ov3R3D,`rp+o@{ho@{hJӢ7ZL $Ic⍤>[S<ٮ}北}怒,m#XU-`UJu==jZ1Q݋Sf89 =湏YY;h,-mok 0s qPţC$0q! PG 5Ϸ=Ϸ=ܴ#Kv9PJlx46[\XUsgZ?gZ Y`8(,z\i``ӭs~}wc5Ϸ=Ϸ=GXxqۥ%VMXv0i7Dy +o@{ho@{hK[lm1fK:aǾԵUIJ%RS.I@+}北}怒M3Oo%{ٚ.1 açC,p>l3r7}北}怒 G[tSdKt  fN㳷K,JgZ?gZ퍍6S>s S:mi.6$*1 > >iqX6vKy"Vd8||?Sahݷ9}=o@{ho@{hH`"B`)Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@rψ-j?bMϫZ[uT {hӿ-h+$v UB(Vbrweyk@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@dD`vV햚kO $ib endstream endobj 122 0 obj << /Length 3735 /Filter /FlateDecode >> stream xڝZKܶﯘ%"W K+;q!e`vhq1j}]I)ՊM_7M6&&K|$iI#QFn00|w˷Jo2?U;n#m8{nmw^ow&woov0$~!bEɨBXܠW8換>!ף86߂~vM#*yGx,T2?RreBFлN? cW~\ۃOx^m|"O{l,t"L(Pm'MX K| [܌+QןC\yA% ˅@ ,/qzh M7gVK^&-h0D^s'bW/iYFLpjhOt@`61Q̯f Ibռ}J%(%^ ,C~:pOk (mpD2?m_+WynBrB0ɦHό =MHͽm `w7MyYSYgي\q뚳e]W7KNޭM fzn2rs:53bԌlѴD薅AOZVw͢r逆5ΉhTZZB\b긁c *i$Hb׵K 'OkXXVJ Az(K? C.k%+/ATl|-lv C8qn"Nr- A*K 2mzWP—ܘic04iFd RpM?X<۷]C~w%-x+K^J & @HFdx\W9~kx[mqZɾT esq_a"qs% 3z\W)8@^.W4hi#=_[7Dh Xozqq:f&8M¦KX9>ȋ_Dp8ª`4(0HO4msg#$ЖBO%YC@În4w:36%/,< p%U,d8 V!J}3/Jp5Hy Q܃Ty}{K~ Iafj;e Jtlsu2~C n᷑UES%m2`CǞ%x ZV/M˄nccyľ)g)+r $ =9* Z0@^0¡l!6jN?61pn:xbRer4&Yfz@[saWr,6NF6LyFa8xIe5ܧ9)!ɧr;i[oK,V0dB6D?E)0;@3i';* }cϭ=?~汖[ѴF+5oVONK&yxg,X.mvrwHOBLGF'ZR5EQ},e #3*z)J-H .Qc.3 ^Ģ>$V!f:( DŽn`(4e-Tot1=qUJ#П3Yil cș3k* O~w狀oud0q*Ȕv3u"lL$Ō}\)CQ6r/Zd(|9)Hn  fe誷H|pz{8z1O2iW6ۆ*E _mYuTb1ߓ?YVO#;Rd_ihHN>Z/g{ ;|@T/s22Wrӗ}e'O`Go,Z Ąc$=Q&? /|k6A.e52 oYKb ,w(v av4 oHw3Jjgz]ȲQ uLnllg*MG&cWc XMM$'\s :Ck<6#*E\f 'X  &Ƴ2ҳTIEOʙ-#*Pd\+DJEl.g(R6j&h4__K~f;1јb—wܔmpH#+ɲY=X0t t FѼsJ*r^jH_d#HB84PjE xfԭo 1+Y,.($,K!`|V{0Qy@b?uG 3h8OjqH+R^9Ho 4a'fptDZZ'^U5GWi?u'Stć =p)@uEV[ΛK>үb"-΁qU-Ӂ qNTICTmα؊>KT}e}Xm<1wz-V xLo|Qk* U-އ:kُ-"Dg}cXY~ 0931)dA _N zxiB'̔ eh%WT3:~\A\ #rCr_&X po}C4@h0xUξdȓ mWݮ+[lqm]qFZk'gٕ{WZ[¸ViPuŪ.p eC8Z9j-T:ƛE!Zr\r̜#}9aI> stream xڕZYsF~ׯۂU!<μ%dks٪J#k`05 YId4su< cf&PEImZrڼ[c6iJo7YXo$ #;n~ bzMIN?; ^w 8Q۷o|}qizՆIm_W#F66b&9~Wm>܌;yg M0&*U:Lc876oϦ9vIX3i*nXJD|΋+zZ]wg-iڏݥ8ȷm51@/% s2 ByaHESsE溯ܮrPnjן~&z[gaF׾oDeʥ` %RcYV<.$^QpR\FDzo>1&J`}4l(vX;~Ij'Qb7,䠍 #5sr$MI:WCGVb)$ H!" ̓:؞i{U4y<:cq|`dAY3% Lȴoqu8Yz$'crt ^m{x ,{x6 rLzwr@`w5*c'qJ^҉"'Q |8 3@ĵ׉oF)=ё @Tdx&2^V@ zTqRh[osWgۭtFfrz,32kfM p86SAI=3i> pK\3Y$ <2g5Ց4 _>z&͵!n4:I ﯕ|+έؾ\?=naJ $2l5bs ~m?ipkev=M㫷65071=S⻙;gZYp;f ~P-f}R//مr9ӳ-D'bDܯx<,c_r0% -L Ni1N+8M & #3Pj쑳,C vBEY#/;uV p(OI.~pk/E$م1\.8s ~vI>j8guI'*̭yA{w:KB8QtL)+S p$*7X- yfaqƂ*]̠g1Y:¤gEwS4Aobi)qͬ\h\g~ݴgZi╵oPDYh碛لG&3ϋ"L^ `pzthaK1FoYiHת#xYjwkaaD#RYjDW~{X;11!&mw&yڏqo޵qp EɔVCNoL˸qG  q$L M;B|e=F<위Nvtsc?*ĕalCǺ30 8hN%5rC#R1/`_>>/xJѸt Z&Kp8'hĥ,;Ѭ|6%_M ]y= B [ӟ1h ـ;*l`k߻CQ1ku<=,9Y,) DmYH}<)+!'QJHOTJ5'4Swk٫T Lr8aDܱcž]%c7:%#x_!yY ٺPVw*/Ex@#bI[En(#`Z:}񤖪QOq3@op5LgJ xJ.²g8]pcrW,o̕IJ&W.'wckH (%@r@,kXK}"EY;tR8bKsc9E(w/ь/۵U6}65Qxyu3 H齃PEz7t|pC rITvo 5B1m|EI TE{õa"W,9h^@?tqc(PƱXگJnMݺo_#Sb .R#K;F$鐐Uuyek{A"TG!; c ~j#Wܐ,͗m>i!^JoL{LE0Atϋ̂Ykj7zꈑt@,vkb X ]/jQ$K} eecB  ޳YjcF)薱zm:@)%*80_ ANm}q$wD&pXTNj2 B;0R$a m>S8̆L2\+|e ^4vcŻoXDi*vtk۠W AX ''^C/!r>:_2;@d dO4kM~9 dq5>e/=Ax$=x >.Ou>@Bf-UR{!8>!/CD|Jxek > stream JFIF``C  !"$"$C" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?)7'һ'ǤJ {Vq(ԫ~ {Vq(ԩ ]'&ITkfNwo$?AT遬UK'Q}><Z^K /\۠ =RI=%CX 4Z$\ ~= RGsYo'#3r:[YfyZI;8#f8j}۫Щ_$ʍvPěu^i^lmBHLrO*'֚z[ Lbl(䞨Nk{ޭn.[릞C3a;TA9S´C(´C*eǕk龚յ=jO]?HSA5˿>ݦ>al̙\ǂҨr^åi^[MqqwtRvcy{GGn%my?oN{oߵ4ind -@)[/bTXJnF uԠ|E^tGty.JɆ'(JǠtö3B;]J6BGU-#Z&ҽ<ɱI5M#ϖ95%օ楧%iE,7F R RFM&=&H[w<{!nN75VVg\k[y4 i-'fՈb<`=A Pؽj6PKrXw;p9#ac2=ˢ db6œ(#> zO} zO}O.S*czro_-o VͯI;7r((1n8v[R'ۇį*D~~~mێgqFTk+O??+O??ª~&:+yiU5 FRE[[ep['4aф%I~$ڔAEVĚMq6I>?5=$Ur_=u|H|Ci)YCgNȥQ=p1/_CڷG^I}vB2y&V1,YTx[ZQƓg\AcAԳ69'چ _C' !p| <<3`K`Cck;~4nK#Z6p 큷v0I,U W~X_oA|֟ufռFNk[$SȰiC̈Bqu-O~޾A_ݠjx9oΩcmsOdkx1é0oj,@#Yڳmc/iiI9%U TpH[|1grMJmȱY+HO|c޳/ZEK7Vʹbǖ[ cAj7aHu[ic 6ckqPY{6c[m~mu]Q;7R$zS]/@nƲi eM{02 d` ('[Vi!IQUeʱR'ڞחZ4MLItd$+ROZl֍7[]-.XZbd !]Ibx7|f蚼3u4``$L!<⟥h^*žm-J9dԣ4H;F޹ۙ_z W|I/os*Kq6O#5f9h:9[[!+ieR HV?Ľ6.tTT9{ n[+F 0wS[/# ]hGkr1UxC^n_jFWx6w;x`03"K]?]N/xZM:Iͣ[-@Bce'WK^ CJMCZv =G^ <{vHBpO5]"BT#,כZ5]CR5Ƶm㿂 َ A](͍jo4 vn5+{TE98RM[/ekRD)kϕ#UFwlu¨$U {"xšw]%[c*w+=; Th?j+bzJyk"RR#WE/?7.++FAmoCƨQ[[f_Οe<5ax_~o]qQ {"Th?jUf_d?_X^\UFAmoCƨ0Y/#WE/?7.++FAmoCƨQ[[=e=K?uA|qs{\ C!T: OoCƨ̿?ɿW-潅gr x ,wDGMeiEk!BBU~VP. !nE nIZB8z]۲mvd [Oeq}Z쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻w_D%3aieq}Ԉ*SɻTu$ݪ:Lh(C5_|m}+kzI$ {Vq(|Wb[uԭIki&\Tn}{ s_=uT 埅ER<v4E%. ?Tz֪W=iS9[VakoջBTS\A i=7Υhʆ '*<ǚ@܅vP?1-oZ{@oG֞[h帖,,`rKci\ ?oG֌<)4HѲAE?u03͘*ےz iHC+pA4)DrWef(ꖦW"27+j5Guj n@?Qc?>۬?OU-ݼ[@΋ !f*W$\z6(((((( _EIëd8.>VHFƊUzS((((((Qԓv1) kzI7'Ҩ/![УR-/![УR)tE%. ?Tz֪W=iS9[VakoջBT:+7|O&LX7?qކ#𖡭sg\ZEJB K$n8_ xYkz& ĖjvЩBb$ ]3x_@}i,+̑F7?Sh6N$8jig6zFWllt%'A$bܓԒqҥNm%?sa M'5o3]fJ iEWsi+Kbgsdw+kĞ/|Aki&DrŻpw 奰%}66I-ץOuI_N+mgȼ}fچXd:M_i?؝Zk)MK|B5[T𸹹frvqPt˩[latuk-N; E@<0FHYfGP]&E55M2k6xmmH8Q5rVöֵO/_io%LdankZeկ͆k=ۥ=ܬqc# 29|[kV5(t%?!W28rǾZ95{;}4&6ӄJ\ln8vքԚOW>'= /8,l6]\ 95GPi5վ] X U$F*J #q\m_K7N:(]wBT~8>[zlՖӇ X\Lw7? /xgXc[?4 u]o[;h籸&ks eCIT +2IZhdm\}XVD9<|ed {?\ ߜ;k~KKӻJ((((((((((((Qԓv1) kzI7'Ҩ/![УR-/![УR)tE%. ?Tz֪W=iS9[VakoջBV:呖a5M3`켂ǦxO.bI"0n ʀFwu@MGy_?mgk~W(/Qa P<?vKgk~( }u;Gu@MG~>?|-s7%ۤ !8 ^ҭ䵱XeiK<سc,qVN`Y[`;)#Ǹ;\OES(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doջXZu?EnІ _שj&,n?s#Ww4n&nhyqd q!yj1o>K $NӚMGŷ$:}I,7d pu~mc꺬RLf#2WMou5F i |zPP00([ |Y-V5t}]Rk$"q 3AkF9zm݄x]Ob3ϵ2߫ʑB'k qQvFyNv7F\V//yY\|Ϊ62H8Emx;EþӴH3 83!Y$D~_o/oX֢(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doջXZu?EnІKms>_Y؛XI| HJ3b9Pfnal#QRUD<1V:rEM=]~mycy!*F27d}k6Ú06>'XkAiy?xx1e"2#)c?ֺv|%x@-#(r `ڪD_u{=:?j~yisms&'$S2@Ao,t!d{_4Nq|0wk]q^OGVcXj7̒F(`o)4kD Wk'U\~,NX)l`"ܠvw4RWq6wP MQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ڣ&QcAERto]\oOQ'%_CڷG^^[_CڷG^IR_ J]+A6?L Z\Tz']^s趭ל-v0(/mlR[[m$[y#8*IaCmKvDXs $dki9ƝI4O4 Oϰ~Q}ùcN? i[a]~Q}!uGP0 iGA;ks/A ?"~QQ kX6;-1?@IwCIN ,mK,laP3}f55 ݷ*GZJ+d`:nRT"%)(((((((((((((((((nI7j (WǤJ|m}*9/տo :*߂տo :*HJMpORR_ `JJ]js֐:u?En Om[!G kԕOG _797US?=i<ćT]ރu-m'p݀Ot3xt;#V.fI^Gp# sx>> B%wollzx T)YZv2 n^ߧ/O9{R[GVEONz0ڴY?iܷh2B:rgKi{ KIdbq@ÎFoZu {岼%̛ Spe aU'y_?Zש>,Ad&D.S&"EiyFRu$cL4|b* G=q-xFۍIyV( {q G^)Oߡzqgk+`ƒ9%'p8U~,Z]^&kիB@}fK-6ln`2jt } jvsB-m VvK OY_X#oe,pxQ]RO6%'V3Zw4?YKYʳf9e @PU\wPZ<VFXp8Y"zlQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ڣ&QcAERto]\oOQ'%_CڷG^^[_CڷG^IR_ J]+A6?L Z\Tz']^s趭ל-qPI 'bNق{p{iYV+# RXP#Sii`QZJă遐G@?'/Q1c>:7 Wf|to/@ɼ*<*ѿ\Uώo._ʏ._ʡf|to/Kŏ._*'S$"(3p&7 4J<A5h:XhŇ }/?\~U~_:&ҧ$2 ( (((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doh&g.& N!x su?EhꚦĒznU&X@Xv:luƮۢv'v[5ꞗizAmplL' KI1[Zޯlr`3[@ $I 5"|9=DfF tve @ tE]Go&yXH<2>%j%nCn|Sv9ڈoQ^gZG ]~O57'>5"hƮe@Wi_~:ozoon`O.#i$|Tdz ?}6[*մBɫ-RD /98k{KoW^ZԡNt%VLq$~dK+ [~63kBdž5,5 <2[Ťe9O1J5 E><^6P 3 `qY mLwsv&i5 !g*j7'koWiHeAَQ]˹ _{N>m?5=$Ur_=uU=uT. ?ҿg\AZJ 2u7jm4e!$$_wu?EnІa+Öі) w2\vj})e" [=?|ժW:e4'FHc3!z2ކi=i=av[76F#smycFO"Ǵڏ gǴڏ g\v[і4{O.{O.cf 3Q Oi^?B4lJ9z_VhƱƊU uQLAYnkaj2LmLAU`I:(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uz@doջXZu?@5B WP\ù̆@$0 p^Cpcݙ I ּ~PKk4ڏYe ʿYҵO-֓ᯰ1RU!`PTsw=}_?ߖZ\ug Z#m#*FAqU=Y5`\\)hˮӀHWEq6izNKN_-ݮl_h 6H5;%׀|?>wiwRM=I䍆ȼт %6+DSj׶Ks\܆0[. ;#?Z(rhUTϭIldQ+$r:M_Kx.zJV>Cc3vSl:Bp `F( ŷ18ЮnMv}N{5FԠOo#eQA#M']GmmN5KBSeC8F|`#Io}iqwsirOjTOZ2*s}ses5$d0Hk Do-+ex-Hlۀ7F,9=">..}yH},Q]m޸`c[CXg9'9퇂'77kWߪꒀRW]11hw=F{cjV֮4Io'YQ77.)ھ׶2鳬$0!c\=9KmgMfOC\k}8+H,ch$qq q:Zɧ-G Q+A.,srK53X#YaYu)XBEV R=(vnׯuxmG7,$(t0]P)8+qu?xS51^67[lg!#89)_ٿvi~Q\MJW_Of, q誤%;QHaEPEPEPEPEPEPEPEPEPEPsvITtQEj5=$WdtoTI|QשWQשR@Wl"yB(BrSSR{v+v?Yݷ/?nu#AԸg0 msi~iQw}uwo.A gbF{*kKO}W1$O@ǭ-bGRz_ۺ/ۺ/jZZCguaI< ǥfx'S-7͵ޒP(\sִt_ Y?t_ Y2;Lx~T^yEŪGbĈFOt;-2]>^6OAޟZZnJT_Vg[hցW"V ]LP: DI İ4_Ə_ƋhE=c "gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOPaE>EQ5 WxDA681?Y!_cDCSQE endstream endobj 128 0 obj << /Length 4467 /Filter /FlateDecode >> stream xڭ[ݓ㶑BoV I 7Y_y'r@IЈqﯿ@hg|ښAWYE/-0<[: #mrϻF%jUIJU^e&~KOpzQ&5Qw??* ,qTDF]~)ե lƲawwŴx^ ֫D=\U siw xpSYU@aT>XóqZHE&ۓ%⃱P7õ g I~bhmsk¿Ll3`t0Mq&e;vJ\zP}VSl7SW>j8c 'NՒ3vĥ$_N@[DDG"Rzn|gv{2)j6˫6 *R=>! 6|ңluIYdHjGQb}=6pog˷}[,DTvv\bblΪh:_|8TC-m== ")ӤυT&LL-75#ljf탶R2e,:궷2cg{ ~ہQK|§$p2"wdD4L=9FA=6{RyaW=z>o%Q*lU/Fz Tv#*9"$ȃl#xIȽh<)B&dui)do&w∌JjQ6,b-??Of&TF/Yrb0bǸ QT[$M&?lgIruoL|>V# ]G؊jL(G $z薂 q*32;'ï<՞RGL?77A XyWvGW~NHT@5<{#Aħ[˿g~72oBfOxƐ3ւV)dX7#vxjV "mti"JK浥~V_x'_bZ1-yGpȮ*#vi&5bXk,:K=:· y)@0C8Ǯ<&ls{1& j!!x]X67bl$Jmi3{@" ψݾP:\@;Ϩ 8l' 6e|#:#GB\07SlAXA|@/YY42uFʻN$~M8 RD(f%bPm0ۑ-72vl% +Ŕ$lԕ]19̟sƥ@RiNb & 3Fo&2L|e@)dJޖC l{r)RyUϩ?[wx5z1 V_sZȝ<I(PRb$0E{URQ ̥R,<;1 dDbgD!F?12x@Lֳb# RDZj:xRzQ<_Ӛ pm -7 \p .!t9#&3 ka0SJ"zlAi*p6v%>-9z7B!I8WvqtT*N OU נl(ɨκ!4"J~%|e 6Zm@䍑2@*F9Cӑk-Ry:}{_y ܀.w4esCS,,▅CNe_S9:e[t$C0)iǖIc}S')wZ PϮ":cٕ;[:zGLYr ' nL%5c=P8VϿې/0=w[EЭ /:x&LۑЌspv~wqanȓT k'[Zқu bf} gj8 (<:< x{"$Ze /Hh2̀b*4tp\VQQQEG)GPffSAd@\ 1o{Zvq恉`# xb5/I_IBdQh `mչ+MXr.;9 ׈ޔ]r2ч>odMB'FN|̘jMu*>뙧sMLEW9E9ؤp9׶̒m}Son2s,=IB!trEIؑoΨC ح)HFozي&}Ӕ.!gγ}XOuq+%Ǚ+X:@49M0m7p۽76`hۚxrS.cu;/Z[_\콅`ReI+ >KrvR. zGi"ӫ@+G%\Pu.**˂^%^AxKI:{ZQVw{T^ s[u C%HHfW*Y'_b7 endstream endobj 131 0 obj << /Length 3482 /Filter /FlateDecode >> stream xڽZ~zP*9O&0="PuZ"(wfgQCygo_f|vΊY K̬,VƪY6_00}{񧛋%%1lf1,1 SrvFE7H9sap$ٵin a+W懛HB8{u]\\rFydFjwq>Y̤?r7SZ0S'q0'D:QDbۣܧ|*ː. jܕ묦rCM>&/ jT宝 f k99[pΜִ̪bEgI{$0@$i8۬HwR *X)ux'cd&!g:qc! B$}je΋;j8,֝|!jmtweESPj8:z|Viᗉ ,aZxһɘGsGeާ(@_*_ݠ,.q&:eR> jzhM臰L٧}յWYiu7(_(f( 8/h,re4ɚ*^x_|,9,B!) @t58Ce?IknEy=J2k:F~vĢ5Xg :Д$e&y Mxo/7A}/.QWچh>ddڸZVղ2oG %2,[-C: JxTeo1f|^Lh FO1eC;Y{Q2J^侎u9t*IPƕeRwr;:ީ7i,%&t p@',Ię[ i;H6IqN`o\ep1؛Oꌈ`N8)㎱rj p= ~ʒ:CTyh,E]*jJYQ*ӰE5Q )tu> ̦R!o`;I)&,[֮o:PhrK=x_O'S] #:[f)s`=zț{؁Txi:*$]ZldEY;p 2)÷Im:L] _4]M#qЖ0'Ҳ,&Td`5^L{Ǹ.h,ôTk.14!qGzf@|Jw7v(L7g$=r{˯[u{C71)pDq|EEcrvi3q bf$7\u {/I.D9NSpYwKر^c# qA-ڡ-&iI4ؖ赠Zcl׍:V)eI]DEA*tv9n9cy u!niɷ8YN_zᑇ) CC-:sN&QiqpB1eZ'=2ǒ>Tdž y;˼9;i@{y 0ؐq0 RKjX Йh=ch6 >Vܥ{|i;H*JƨII=fa>!`4G<"0l[TLCFtzQP_=^ X:HOOQ lfÉѧ&a>fBtt1%9;;u R'+;朣 f,PGo݉ Bvez^! q\k0r6dq=la'LiwqbFmц0 #?37Fhhԫ*Kk1 B+O`"j9ϠV!i 6Svw,@}M) Wq1 Pk b{q˼x1aI_҇-̱5T DFZR3M8\c^#k]2,.;&Bx8?Ԁ'_ wJ_h`2$gS|*z 6>ާU 7{ s\fu|^+.lFMe1= .UцL) yX 8MM7?ྶNa'"|էsP~ji|:QfmL.|C]aUrч"v)}V@ڀ]׺Bx :4)0V`J*OXgǠ? N L@>gֳ2_[SOdx پla5iLgz|i~Դ_Y_ݧ{9bȌ<Ȑ0$B>l8êbA9vAPG۴;RNI bG*;`6B'ʈ(ӧ:0I02:Z~Dum paEG 5K Ό A( M5R[h>z0 .|&lMMMREOe\CQwEF&.OaM),E9"7] C 䴮)&^(kzD1hi}'9 |^w'J Jo(qra%wׁ||C)m\7- S0{"y?H{-#\(*js m:{ ob>fnSp#9 h\gȯkBzD GԸ4qzJ4= Cel . rYy%.s!/'ORnOnrhCCX="XzuL sB Bƣ?z[zxߗuvPѼ9jn {3{=BPU'm'#0_>%wrBZP^p5>`x58Ø;d OV Y;ߦV0=qv0"mc}Ab|~]pG`މ$# EPr𲭥!/3V6I̔J.2J jʲWէ8oS &[Gt/P~2o!\ZJ/(%HiLY5|UJngPρK\0nK4c}̍l0#cp4B4la<<*ؤd 9ڸTa endstream endobj 136 0 obj << /Length 1014 /Filter /FlateDecode >> stream xڝVnF}W,b7{ʮGE⠠$b[H*N\mrΙ(zT!j,6!1fh~]p$fjqdULIH+ Oڢ~Y-I 'Rny[zX 4P!$~7lzBvRLNom\->.P=ñmmD0=%aeݾ[b+%{Z$'XXb'[۬ dOPB VoNXe7ݸ:vVӃU=i˗2C3loC6`RƌDKnHgeEuLeT:le(bL,}ퟏ1%QZatKC {I7?I;hZ${BXuxݡiAX u|Nĭ7Y׹1L3u|2}sȫ@@W4b- zmrhE]fϫ a{d?ڬ;"Nr+zy./2bf[g |u[yu&0%VS@6myr }E,u}f))3Ti{{"I ۨoNӳ1ĆϬH֡P5OUٻhn &;AKՂLqtzO\qQǹ ${z'Lk,Xn+-{|駛 xu.u'ׁـP #SsPpfbVy c2Bh0܉ ^Rm8pzD) A%0nE9C#O'& endstream endobj 139 0 obj << /Length 2975 /Filter /FlateDecode >> stream xڝYYsܸ~PU+oU9oU6Jv6!FXY>}pDKFqkhs7f¿8OEYt,BdzӛaW!L 77OwF"Id=l\DqIDdܖǢMqWp9,P㩸3<믢,hfy'Ln'6b-8npU* $JcS30׏};yd<>TiHǎDZ;W qϏ%s~6B6Hq4 Fp6v$(Tmux hF-2xPI?W2[>=0WhkmoigeɌSvh<gGi`H>` >d@^eNxY_P6%8pց5AoKi?80͗bߞNFG׳2U4~fCsH)4sƕKXu/ھM7ck@7x2:ɮ uWQ1'e^ᵳ]FR__PxwɔcX}3fU7Vd0bd yċC2#a\yA: (+/W\`jGhQVnEo0ax 7Q:(a+Ns%8p ?>p Br n-.2'W(O9q`MN L~ki;p+BD^ǭmh7z̋f֩[ZI>)dQ0pBs 5h!Iw6#H%b)bMOO fϔc;4iCԲL@<̷V@ۚeŁ e#0G_&]U } pꓵ\1}[;ÏH !ʞ[562jap|8!hڦI,-"7ܢd{$|aM&,3?;@ cv2Yu0B# zV-F^쀮C$|P M;27sfE^wC4)NVmV' %mP|e6GO{%H޾m Op)#ёך<='{d$g&FQKFQPOܾdmB endstream endobj 142 0 obj << /Length 3840 /Filter /FlateDecode >> stream x[[s۶~˙#X^8N3sr>mH⸿XhDϜi:A X|bA5g7Y1cCO0 gTA$gU:zE6{uǗ\b/x0)I!gauv6?%WlRlӅdW/śww/\",(B2aE歮">(}mR_;{qyיg /rڞO3873|vq֚k+g`=Bɼ cB=)'d`Dc+50F10u}1X%}ȏ!Vؗ _j4sx1#ȋyOIr.$[wǐ0-n'<LcBtϏPˢ߉bK]]%ŚZ8p=J\]ׄEu 2=1c\!Ǎ\@DJrl8Xc naҪJ_^ =cʻZ2/߇9e #‰w#TVʁt(v]}Wz- Ӂ g^OTxs]O$HXKI>sc2XK#>Q ;R'DGAk?xҙ' !z a5d0x#ǔ%O:G0NmlL&QIeZgE2Z˜ I2Uͣ&!~2O9V扸|e.8U~}u 2yJM$=_nf'JYW@{uк\۴ɶ:$A6F7a& 4z;~11H.yAuᮣf@m{^L .Vç`brZLJ&9>|X&D,"*Ow1S㫐F4PDCHz1\B8ؐ3rcX6s ܝzxs3o Z$\LB[VCc~qSҥ9e)VE\8?xB{<GɜY@k.Ci>u5/}¹np8 )fx,}@h\k$.-LG\ ov7+8yڰuŰ S%Ó6+HD,-TEdKd?0`}DYSc<4TH/W2Ǣִ H`Q ,rƝ`Ed KEt _HkmguS_;UZEAS2_}M3XQz֙5hs&F=؃A4}W7ćG*J$bJ)ł!x^ŒL[iOH<^&Ұ2D"CA, M2 ΍a~P^ Gz_ſ> 9b,zD{=@p[H u/Ǎa*X؃>SQPG VVpi5\  zCxF`NhKY67|ã endstream endobj 145 0 obj << /Length 4129 /Filter /FlateDecode >> stream xڥZYs6~ׯ<4q}q*>6*50_}!j$eK"b4߭Uaa'*ѡ(ѫ&_V> ``zw[)WƁX]VIP(Z]mWyUq_#*HF8R졆ihЇ|-Hc͏>_]a:W:]p_ӛq߇_.q?!M)?z9{·VduK#+J?JwlNdAqU'iT\s؈@6m/q:;W=ʢZnXySoM3mFack!4 y2pd7YWU:R5)oEewzMw.| 26,.W\pݾn<}@7Yō6Ϛ͞۶8d797izl oor8uJl>Yռnف]ih Ai?I&_3F)$A_ud٫up' sݫ[-1KEF^(ec6Rt u"DD\X&NPk} zF 3PA:ԆRlDig`Ƽ䅁SӨ\RBGﰙҝ˳-7?vFryk+8ʊ\^s0|F&Zx=aujlr|hkEϪM~R_N>}9wt{Н wޮ܅UH0Na#PqPv(KyfđNYۢ+-]JK!U/oV4T Z4A:`~}1|}ݛqXe@p g8XL#3ĻCUsGP P|<I{S7M^L$*+L}.Y/b>CVA?vC;:,2~ N`rX0`U`KN/<*] 4%6e%۾7CJ{77*M\0}:MF&V-RÎNSǰПp,ǮF?Ek5 {U];MͫҨ3|{^ej)n]IF~#j? bwWe]n!opP9vG*@t aA1}! 7h]Z4fF4 d8dkѻs/qK``usAxnx8; hPk` TXTvB0aOutwþX5h zum @h&4 #LGf{h;_ bg:ۄ`8d%™0}ƌ}(a1E:tZg rHޑޙI h ͗ CbmM~BtEGչy}eW.CS0c%yw dbSAO$&~yC,!iю9'bLX7ʚ=j1I# Lsokv)+]L-S]}|y]w%|g:&7l"oON$"=`%HllG_Rbp2^uUod)*&qEb'9 21)KTҒET8"ҬKyAtcM-J,6!rۚ*7{8U?Ϭe_ёq'X Bb'_Ȕ*zX(u7~_3r)V` cc  ]2^iʿu$&hD3W19㫄_@B9*45:Hni@nj*`̤p]:+䖇;[T%ᐵ K5 &; {Ə `oy`bt= m8pZQ !X qLT//$ Bnr1JT7 c{@Pk!8RDX[ CaGTbBкihzG3*n2VS6>Cb ΐ8.^L/YևJ{6CrɏMUaa^0 #=s%H}zit$>r;Q{ȸ~Spw\20KDf$anZx$ۉ甜TpH@փJ9* /ۓgom$NoZT?CAȺYEZPá7_)M*tM׃?7df}lx0b\^fz\Y{oPXU6*?J3T0,L1(q/@=ilqЃď42Uȓhh1nt Ll+-`*JB9 w9|<ʀk9$^ijRILXQ&_U %r<$+%h~_OKDY "ĶA9c|MVbES"B q)Kf `/=V~fP|a)]{d)I$4U;[PcD'l̢:%`3K(~MD4b4b"A'DeoHata8 “SvC뾃m<_/"u2xn cxݔ5c6G7dsb|A͢~# R4+̂Q$ ؔ65?5̀tU XCo `$b(bdr2A&!~sC!vCeƿC0eg۳f9G1\t{1E%Xc9(e $k\]21\<ȉh(ď> stream xڭZ[s6~>h @3INvcnh PK$EJ8A8U7j?ƾ $^%H'Ѫ1_L Vo.|-*S-zRҏdu z{틟__o <7Jw/QyǗi^` 4B\" "*Κn$ͫMzU}VⴋW^tpܮuo-&늺}﹛彝U^Wczaz\W C?UWm>ȝu&J_hf*nəD(a z7Y d D"ݗޛ[89 +6JR+P~9k谸sxE&^45gi}5U^`zKlkvJy-?T@vY l?k +$! iS2&|,Tn"m虝Fp-^vMn*& *2aMнA?NxЂPh9G=X +A#fݺlg7w'G{]7;i K]ѡg1ݝ!i|DieMQ-ɋMB=>5~n{?%(, h}V!Uf |EeX>cw+ӋEeMJAN̓ޡ jf2YG& ˳|O լ5@sZ];{?_ϐBfkF>;,ScDޘ/;{~Kh3nʺ^^}G&= )۳I}e(WgЄtgmԏYPG beeeGHAt8"bZJG+14$D3)۲uNGv3v'boMwm Ai.5x&$s Q~L%H& 8 h=ÈNmf=\Ձ#eY4dI)C5˅@Uא3*n'`XVthX;mեTAgўjz T@qc0?#H(ͮc?'3rê!zEp)kP6)5= 3tET֓u7ɱA'/wjAf1x-gd/*I(K>gS[ЏR)By_vs$,@F. ١νdbMQ (:QK~f5$d |;dcR׍X>u j[ S[؟=.& (crzv[9:tn7zۊñnv !#Afc]T1>`=e.ߙ?EmuQv-IÄ9FLAl Q~髩4_e܇ȋ]oEL$I| sqpTJt T5 (T;2 0Oyr ScŐ:T-Z{2̩Y #ҍ+ 0>I!#Yہ]Q-x!ƍg {n6w1UnxJa2g0[ZwRa ]r,6m]X[T $j #0C]ܣLFQFC9@x7T$)|/_D„ `ͲO ) '*RL^S"sЄ `DUëŗ#IkCL@^}eQ.rb vf7C9ܜ}SL圍*,$]0%BñNd"w!wiL"\ l=ᣌYKcVXJ'+p9؞}f k Y@#9s8ph9,]}s{Zt^-:[=''թO bvq0 N&Pxne} t$9(v_ J @޵{u$Nuiڝ̄3]:mv?N>mZg[K&Q\jPm-2:s):\)b9, YPZ;)@[ns Cv=A? ȡ8 cCPKRt;XwFz|yrSǖ5Xt#9ĶxtE2 0tZ3shK,}k Kg.X[q`U: [CFwEkېG,`a%vANpj)H/ȣh>(qY"CM$>W:vsNOK* t`Dr1u+/F-] |įѤXwh{&bOB |`5bD-1U{Q-Nh+b~@BqeWpK18"Td`(,yuG*"vj[&&õ7O覨`{ɻxX*b6zt0XFm{P&T'1#o1pLuq[ A:B <%mt Zl +쳿 ؕ_4E?nLj`^<BM[}g~AXϻc@|wr Y3 3Ft\> stream xڝZ[sF~ׯev 7YlRJ0HCʯs&_{D^ZLl}'s+*n"`uxTf'Reyo ܄hgzLJ]~hy X2pdDa[>bG+iY>zFrzFغ=N&튺jiv?=Q|qHzZB#iĜ%BŎ%wtXyh>йO SVHGزn Fz&=t $=F9K;KW_^ɝ*pJE~YA֯NEmʼzp_#mq8C~5ޞxwgwxz[]ޜ;J|M] YweeAl<*sA}{""%y@y8$~c((l5vxdA55PDo'ܡyP(ҎڏP@?[@M *NxivD+blq]wxܧ;jn-{_Z(#2X:Z}PۖnU(,ewIH=ϫ EL[~7x#pm;)l$. `2 deڶ{o`bGI6 Pr11!\; =2{SS/{@:8L$^V\}.rɞ!ŭ1Ύk S;$Apg-'C0ٛ,+gK+S.uJؑHE,n(R%Gz!|U3n _K|L oi0R Vkט/,*8{w,qCJ&61q0q$\\Tn1 3].7^vzRaF߃"I m nvK4u/OW9dl"JPY\19;zzje-0['\s'լ7!V}d8O "wNR#6AekӦ!0nk;< ,=ʮl9N 6JyJ-YІ8QՅX)&=, 1SB_ҟ8u9+-:7ݛeU0^0FejelI?LܭTcF'>cq=UjI >S@aU2S = g8ʎJHCTmf&mȱ`™!m͞AO%b*;Hv 7iAns.YQƻTc)&J8O t>,y]>_%N&/?yEPdc~J7!.>K#8xvkҪB j.-]̘%2SBr@b?E mZTs'R] {Hi^F?q_E8w$\+&^+U2U7<2Tr3e8jQ˄qlR$v?Ǧe% 7p֏U2#)%M Ge%$+n/1,iiKF@6;-Vg@ҲXY|Q.׏C}r*9}Hr$@aeQ ~@LDV 5u"u}wo endstream endobj 157 0 obj << /Length 2361 /Filter /FlateDecode >> stream xڝX[s۶~y*5NN2mNL,ƼU%+X{ xo&O)SQA&dɠ36UՏoD,ODe&)|&-R(TlTI^(|{KߒO?V,O#GH2lF}S5WJIwuӮnWW^q{C~T7fAQ_Gl`}8ς';,q]_Mpb fzeyNz\m V'`qtX,pxZpX,,k`zvXvn~ќ/05ɟacq,9gRt^,c}Y+mnJe۠"piMXIېbG=0:=kK2xgl{voA[؁/Y>SlZ'*|$ oZZk\:gfy |m_M|& ; ڥlQ.K" G?/5WF$Y] m=L- ۹Ei{3iW>}KC;vNb*SnSuMC<=EmZlij4^˂Аdpg]_شe2Ct[:lAes*^HaAX+k•x#x8"=z`az@'[-Θ5˙ɲ,З< :<]l ηu/@!շ*4=&ߡC kQ9#2ӓ&87EK83'\؆/c3[/twQ h{sbAtcP d #{<tg&_NI ǽvvR+jW%х'Jx81z2Uc@UxX O(e/M(~ :<= >bsPTmEHIœΊO!bb*=GՆ}5$a{jM:ff+;͋e N𧥗XL²dy~dЅiTܻ9)_KyNg7'ߔ@{H?^H1xg VAo*%3M?5@=F0|Q$@>W)&Iahbg( p xmkGe 耺m}O="‰/jP NHħ; !*K얎yb%N/ oCYCWOc5! 0S4lI%։?Cz(ϑ#G81Nqq|=d c+xzf] endstream endobj 160 0 obj << /Length 2946 /Filter /FlateDecode >> stream xڝYݏ۸} \"wKm"Mٕ%$g;lllH)r83͇[=h2VE(dYtn]; ⧫nަf2mEQ e"3Q(,>&?J[dO富~%+S)["ij=~1yVE.\/4E)LgJRXL|/Wi  Y*<1zc|T5;t'fG.VᔕRϺ?VN,WVgL#|gT; C}} 3zc"pv}*a0ώEw#n۶ݞs[C6H(z8J̝} R%[5++-ȯ*",ڶ~@{{>BFap S}a:NPd"M-JqsW)u<]{tu'xSdàJS9Y %ek:Iˌ0 `6iў$0Tco>|PbX3e~b̒Glڥ2`+]3#W%۾3!O7xӣ}>{T3D7Ev6C8k]w7Z%ܦZ7Ue6L־yg'mapp}jF<ZSkG+O=llO;@]PRZY>w@{b Ź@]?!>kSV^-ٖ34oacƞI:kB7ːR&?UBwh?f G4PgkfsދJ*vâ~m,ۂ153B0EJ 2qP)"奝*Wie\y vqoF ^on"v 8ŻfCKn;&L"fmǻd0yygw$s!u.հC-'1{܋cu ۂ7ѹ2gPdzx~?tiz{Wo-Ax]xM<'Txf@4Acr|ꁞO>Kf/'۵{Է6t-³&t{g=H옗y֥\0p 8}moh~P3Pu\Bsc 7nQb܄`&?靨g֌6 >|ߌ,\d|RC &R)vǘfZ&qJ!d$a\s?n)Vam)/>|`bu8%o`mTvZ2BJݶso sL>eInn| vԖ (=8'L<^z6PϪ0‡̗35zbeٓyܵdg#Kc2Km;髰pU ޕ%%^*G-:;H k{Cz-{PAYa.rLvdba^E! (OJ\9Jb % G5v*HOuKcy 8z!)|^Fc\18-~_Aa|VmW tj7@OAΩ(&Hɱ` q:TŀO`ɹAc;C,$1vhg Ӽ:(Sؒo4:ʡA(ſC)bn;p*ScU}'&x^jp*D?X ^3U&Q0O/ fS~ x׽51O$+?<<}9Afb3|:# yV|J ?vZȏw@T>PZpFqC~ϫRB񶩚,ww endstream endobj 163 0 obj << /Length 3225 /Filter /FlateDecode >> stream xڵZ[۸~_!r+m $4(vA6e'$˓iv yHԹ| U*b{:T #zM]1XȼWWzRH/ HDS2eQ wVk*dWyՏN‹$fw Y`.Uqv<wT[&eW/~CV2Wȼ-}@&ڻ5+^D%xuߗ^2X@' >QK?8s&=]޴0Wug06]o-x#E=z {kQ9y#:b;(0k sx8S* 5f@lӄɜ%Y3˃vg`LT"1K2.aĩyÀZ5"ӶNG5]-opq insO [BSf35p@¥'qFE~̨e ܊2[_(av,;7L/b]%gWU y# ">]  m)p0( @!6;[m͑u~6Йd1O73T:eoh"M6[x&o[8HFD( 5R#v4tM⪽ش ܥKPXE[$) 2D5 +'8|Am>?d\S;,?Pc!aANisq<˜w4[ZVav( [0 .1DZ Ee'AQLLw@,&ox0W 4xrS][R:|-VSjN(8q>,`\8zp 8=Q#d']rARYsA2 )P񎖑f\T䒤:/^,{Ʌ_rimuCM4( AvC`odGDȰDQhP441^NHFe2SICU &L;p=  Yߐɉ˲Fޢk03vEzEU pmYgY].QFҹkEEm7v*4[L?.awɭk7). NHg>tw@:sy|9n[wh,j=u( yشXguix$Ȟk.#Ӧg9֥I!)+ri;M3A[k(ݾnRTÌij|4T6nV0Utm^r_+*bZqB[cv)q SUH4Yݦۉ"YBdQ8~5ь=:X#ѹ:?ECCT/:v5u0f]iy(f`Ȅ;_ #\`e0ėOH$eVե(KJ@! )&`?i[ЂZ D?t;Mݞls1y'$[cY'&0nf`#2&jBےMA dH- BcSgQՍumn sTf>/D[1VW{cmA`Adkp"JqJbe+L R2֨Ha4+ dSapp5ėBƦhhȇn3 2t"]J:/o#eIϸ6J bA}87p씸.|r;-Vֽͬ<dzLE᷵1 Otu7Xt&AwpQ̌&~X5FKmj5l^1$em@ј"TXTش`ԬC:~YbvB.cc,f "SqM&!eA~~߫h͍&N,p'.bm\)B(>KAn! xߌ܆PK*b> [6:I+T (9qbuEMPu lq3֛_dDEQ b$RYlxp݃> εs7M.K9y H8;>)We1H-h0axmrh;qAE^POhc뀭8Uoi. ?Ȩ{.Xo~d:6[.6rm]_c `3\OCʧ E'c6\,`h; ;\g35uLqEc.-piA9!l2a`LoY8_Pf>#A=dim^R&Y;W) p[nӡwGwo޿oУ+\n2‡B0H5eaѥ Kg˂rs`Rߟ@*uz-:&)Jtt\H*U5}kkS'Zb•4w+2o=zm䃧?00K,Cw\ N 8aWK6aEΎZtPW/}qS1̅l_JZSG"܊-茅6_`Dru`1B JI $YNO^bA`]pW endstream endobj 166 0 obj << /Length 2725 /Filter /FlateDecode >> stream xݜ]s6+x)]ޥiN&KsA˲t(9i 1 8xN}tpR{YTJBs0ͺ-s큸_)-2 A %⬸)>-]~ =0A._QiX?~ hJHÒſ/?~_/ېo.\.]r<7Cb7V`Č.uG .({zbs{aR3ą_@ARЭ\Rvr0< 0= Hg֮q8AӠ=98󺮷^z 4fj1x]Ɵc@(q XВcAiFgl+{m|Φ4R@T#8hMpjj ` p K gV 3{|t &FrӵL5S03Cg C [/v/9F2l?B[GϹӘOj!8^2n'!qcz9qcq,lrm(>Et^EIb†|Rq b1Y0Q)y*69=l݄jxy\Q338.0q=r `sR"`ȥl_/ T0(K+qSxBāpc#[)"30[_ 4C0fAzpޟiXKN]e1$yn2 7V[^Vw*>B܁q)ܾ .5D;UY.O vc^7~zNh]r8xZied5'_dGXdՙ`K$`kCkW~ aL^6{y+;pMAq1n&}Er8{LwT.sE^^AƂ/0߫FgD}SÖLjG?~+!eWLɂ5St!! $V[1 8)^o‡LɂN5 rBDS$5I1@bi ÕuϾ\قPua*aH9*Ddz(t;Sכmxs'fr 8VC8'`'#Oq4&Ljܫb:!:W }cFݸ ⾇DPR۩LjC(F=n%䴱'XɌ-{r ?}fau>{җjo-lLllH#^/t"NV޾uy2;ߜ1=צ⟩Jqz%#w6c 1Եބ9K#7 ^%> gv}89A`4i.ټpO?_"Ygћ;怷g0}g8\݊m\\vҽv+1eb "QEc^&u endstream endobj 169 0 obj << /Length 3972 /Filter /FlateDecode >> stream xڭZ۶~ [0|zI]qi4L'PBRo|wts2X킿-Y ,aOdaV/6_qoq}kb/7HP$Nwq^_\Ɉ1[? y͏/,(E² aK;k>{B7黼>Nz}}ە0pQ~/g*K"$3\W-]=䤊4ʪZQkRDǞzL<3s,䩛4N/xwۦ"m /VeQDq 14қ~tSC[Ӵ}VvaЩi=zfv`5׸iIi@W)Mݕkm۲Z#Eύ8g_Ʉ+n j z&/-6{mtT f%Xf>]8?G~ >!L<ی( l*/kPJVeTf)#РS͌ce{LlD?yu{M"1g* UĎf@ Ld.>$ g2d\%4ƮOeꋳ:[3 QL?uVԩwޕ:\q%=5Dӕ /, )䧱ϊ1U(]"?.,iISuxB3?L5;0,ˮPue2?re}1|!yq|s heX’$k¡Ks4NaOyizU']Onfw[ߍt 9,b.܁sDb1ҞIOD6XSWx ]B]Dc0K.`";z K1`/4^5}G-|v3ycdc皖̍}M#p 5d]]O 27I,gCCF#3b #4bؖ@OӚOd fb#͎Z8n806ç ll)=zX!(y1Ykm˜aSq4 =n/pc̃~3JchO\ٸdHɌ/ogBfl~l $iE81K?zȄ,Y"JBi1bsNpf΋ֽNayUPw)D6y#WD5R'Ww%11H%$n bTuWԋ$1jF5CA1<=>.;Y KFi:0|lhhU[I}(^ki|oXzP˲*C-ZQ8i77np bBO&xԼ+qo8nWv]XU x*)4ƻ.BЌ?ZRۜQ)U$:4+,r0+!ͣVnzj̈́v0 xeGF; n-` vL]pʻF\$TD:?擊54/Ӡ݌0oD2LqԂW#:3*`V> !ymzzlaYcQrdpH"3PLyeb7$8s!"y)mFjY$ 5r+m+E{H,:?& T 1 H0_#Qhr؞ 9l1]ԧ1~Y|9g|u.М])'tvf#``j;С]IHBT/}Ɖ̼u R7 >B"f\<\D>213 @\EU`jw*0)_};E gB%5fx8tsR90{p])D"qT:Dr/ǜ,_IX<7¤jjnؚ8 }U'nA%%Zȉ=qvnzU 6FR*:֚_t᭯li]QތwDc5V~)wƦE<-{ (1vNד݌fwŴ9MĴ8{9/I kd"6 1wެjuajHl*;;OC܋8{řob! zln, a 2UƩe86jGUXŇxruímǛ>t8h͝_ha!4f[,qSS ozp2XjnЬ92Ȣ;LJN7ꨊs >bgZ6ŨrytOK [*ʪJM%[<W^1anLn m[<Uf`ih.N|;D(xi> ˬ1L gs V"ffGq){jCW ^ '%{xw)g0 ›no5뱗:lw|IAPEjOA=/Ba#HZ<Csxg˱l7dcnAw͉Z]E+3 ̎J^jOt#ω"S} )wAZ\ eVO! 3"LjE<ҿTīi=o+4 ?-5~40(;۩[DF='#Hˁy= Gxd"sRp1Qg&L-̖`ݶܠ5eP8MBqFZF3:Jgr؄C4CgpDS͘rÖ6~ ٰ2{17r*S{Up$|e& +{ALmdm]@1}>@gJLi|d8k>r\>n?Iz3ьҿĹb*p*gN7{0p~ŏ Y]&{c>wOR;.+ec]O@ V2*|YAi><8-&^?) Ϧ*4RJ&@Y^__a`A endstream endobj 172 0 obj << /Length 2501 /Filter /FlateDecode >> stream xڽ[s6)؇vv34o3eSFȔ"M3P` }-2ߝn^f">ﯼˤD-wgTAh!2ml@"qSӉDhEP{9#RchFhF8ֳºEuOn+YWr~=Ut[U%#a͵Q8~GdU)乿NvCܭ성B х@ <@U%l8=ܩB50ڍԌ&\&udwk?F;alP{llx[1N,X$?nxș@#' g YON(#j̗FcBᡲE1NpR0wSQBD=I1 &SJi n*=#@H(}}SzB~C8i\pSz #A02(AޯW;7=D[ = BX3 ®MTW? w,S\]<n6PD%= m*&wܣNLA i7$n4!2ω]YbRz ^ꗛ-P`@A0v)"9DT*w$=JBCFU D$HGylHRCiI7! ˌTez\f U={ۏ8ч0s#sk Gq¬9]wL? BڣH@4á1`AY&\ʦY~p;"j)d=|쓛>qA%xz nHy Dޝ#nSGnp?9?SwM-Hh5PrWᗣ㸧7ȪcߕEMH*uU;G <hl8]6Da+ܽi0y{UuW͍_Wn}(40;գn(\mHSB[|1R364eYOSO6<@Sݞq13d"Krg9mnCE0wLK=DǹR@񲺫`mic.퓤҄ w}k1w8LH,ϚD%Jw^+bDhҎs^Ey5Dvzʓ>0Cy9YےcMp9܂72(ram͗wus@411C,Ǹ3w!8%\][D㲎f^oawJb8$9?a:Ǘ쾬])K<[J/K>`Q>>ma\nwT֛j;4G4QAa NAQ4dNGV/;R30ib YR_>[ jG+Ma w!=@Pngݢ?!hw0_j_Lynprl39tcN$GcS7Hpv.uFKW )N"Y eG/׏x`AC~B yh8=P4%'H(@@Szz]kt'O>eSC``ŀa1XM0`5u Yk(tY|7ĪFV;" qb0 P5Igg/(,v՘ ,ʿYgGEsٸȟ`GMUn֣PͫFfkΩafPb'E4ʿ,q^}L#Bb[SԽ endstream endobj 176 0 obj << /Length 3291 /Filter /FlateDecode >> stream xڥZsBLsT"1ă/rM/ɫ9CdHINCl:b,vXLnߛY58O8Jt8tYcf?"`foξ8R0Od2bjgib= ^o~/eI8_I\GOo~yo|3$Yi$PtdRVZ|kCQ}sqLFİ*&ZV˫hfQlvGe8n7{wNAʓY0s_s!>̗*P5ߚhkИbׂf)o빌;m.4pfQm ,q%-k"ײ/J CZHEWV7}[UEB)c˖rgz+oo:鬯as,\vk߹j:{b-o*Avy:NBnmS+Lv*rݶ3 UHB7MʺYR4SۢeژPQMS/̂Zsݶ\m}"Tk:?_̾v6&C pdq#qהac6r갿AuvE*:yNgc$Ry!3HI˜,9T K$s0(EZ]j0y?s=ӡ&P iЎa; v:59hZn.DS1`A[mK4F3{Su'b@T$nLebGrjmY6d@41-HfgƚUW"qX kk]7`%E6bݒ;fLc7]ZA[a75~hG٩OF6`c ck)c O>M;[n)K}5%e,%.Vԇ)Tºh5*d,Vȃ2J  >,2,<2 ɈzϹA~LR,R5UQ* #WޥH8Љ@ ek]au,O-}L·R@&<gU3Yq܃{ۺ.rH,l4LQ<<\HyDPQl+ c|SjZ9(hg/qa{+K(3pc `GzFILA G2F"lCAz$Ȁ r"}}4nuD1E&`dMk0 A8'Hn#$҇C a6dq/aUp:"p^J0喅 Awag V@1싛C{9CNFO @d m/GX+{2ey"UNa *) c" xp"%Cr$gϐL `4hzBF_䄔z[Hav  y0dYhp! R}g㶲l~#exw qMK-> %  An(J7>d1R?[KnشQ4iy- @ro i88pLa *)[P>i=g{-ʍ:n_#o,y"P:M1\RHYHm~]O ,SXi?Hp`\Ɛk15eWu&OY!z ʪūShLSh3o2 2}cח?| 1TnWVh5ՋP~t(];Wb٬G/ysty|ρ2U"w  mr)ȂÞA Z(aT+O WGu?9Dw?s i.N~+z27$;w-kn*v/bH5,q)/'뵱")Ny Z2c?.UMC=T ?K 3UW`G+.c5^gMdQi*.=n =`_T֢PF}dݵd1r\Ǯ{'q/=QtnX̱id旣'ʷ`\$ |R,AyVdaP Wyėŗray zpsuNR^_>| ,w/@+%VMT6TڙT6^cPӓ}}sa(ǰ /]ċd.E@ON`p,Ef-Yc]*ĕ?=}:u[Ʋ9T6t@sFd oЌupy8}=+t-by\oSK m"O1d (k|v`'6Ev/)|%Z-of֗*U.R3~WZ2M1ph ؕJUnv~>-qes3a uJe1rJHE*C72'49t"ݵ endstream endobj 179 0 obj << /Length 3192 /Filter /FlateDecode >> stream xڭZsIdC;<Ӻ&3q:td}# #}wo@lx;.^9ÿ0ЏI( F;[_>LWR:ƾpNz"N^s\\3zi$#)`0e̤7Yů+Tc/"o醑2|͛xK^|wuBʋY7SiܙҋR|p~8vM{IYyGXl,n51%kp=5֗EAs^p'b:nWrW vky7+jsWt\!4 iO 'EWTa/BO)]]`(ձMa$?K!` bXgvb-k Ӻ4c2_E]>dMi拹x;ߗpp:Bg=Jɜ )L9pJÞuc۽CȣRʋвDO.C%+L8v`aaz5Ϋb< +#;ɳB0M$⇬t<Ulj' t'a zY7Mv(*۬) g4vh&_lOc0$FR9tqQUTtFZsWsk'zyQaYЄ&hp`Y}V!OqM&;ah*mM#ۚ2^>+Y9㻭ӵ(94X@7f1wy{:9S^Ő.gskT9/Ր>e^1/OH䢰Si#lf6hFeddNLAAjɺzmݱ]>QKxt)z&/C9 ZvBouϵ.0ބ. }2L'Yu;t=X9:2{|)'4SWvLNX'Bg3EQ` pF^ &!A:L|k)YDP(M_n5fA uO$K_"U+Dr]5)=5C B]V/Vo81GWXwi>nQy|ϧ'v2e˔ihQئ ˪3}R6 s`]"0E1CJE=Ԇn#A*J#v;VQm` e [jo}/ ZDZ*j3Ol"T=jBy 5d= PZ FD<_0{X3>0/F*]o;Coԫc]^W̦ZX*(~ @ccM_`OQ!rj[x'xғU[{yXia>GfVd #?=p3^+8SyWȬ$!Fz>Kz0lkZ Izzm?-.Sv㑱ˬ69Q-u|YN c[XWЗ+u3`xB[o{ @1CQ9ShMUZǂN7 7}LM1x_cvL<|; eee =)fBhVg{!תG/}5,L[vU%1*t+6mS#U0bGNqXk859З2rb쥝6z <.A)G9YbЕL:Y'1ӜUź<ӱ~hiTgi<ڸ]B} Q5(pݜE3sCBȢ,YTd_H[t[`nAfycS9u@ڸKRC1𒳂a9\dY]W*j#/ci u?-xb恴 &Ym-o0눥=b>>:NA-}LpK-0ox %Se;8K j:qJ'C!doT;W&s!^gI-9R+Qrbi:}%bVY[" .O|hC}N`(B@R{Vn24ߨ7T2;jxQAqq~[ ?c1H#." efUrw؋zyl;3SL~f E*+x䥩XSV4= 49 ,@T}۩{q0@4ӀaeVY9[pg"HwRؓ~oI٧U"q Y$eEA=)ZQ-5$W|L(sTz.1S  ~=gс&bGMD N_ddLw"HY/}P`#Uh~wNxPf)i5#/^}*_]Mr4RM zJ93W"5?%=7Ԡ0-T"T4ƻIR l:B\GKS_ =c^J44h9'<ENNh&>WeOv;>^ᡬs`^)/RgP|sT"c ;xhTz?1 6”x`XIl40@<0j=Ǩӭ&f6M}탦>!$g' Jӑҏt1!?H7T> S*v@fFZ6B endstream endobj 182 0 obj << /Length 3094 /Filter /FlateDecode >> stream xZ~U*|@Pil'[7(V>|p_jha\3͓-}?AGq:`\*_qȽWzF*/aI(Czi(Gw?\b%l Bq?~]\+I/bIfHrZȎ'&O6qwW^ ˈNX9\}~8SIۙO ~{?]p K͔UY$tE&bKDo6mUge1 VR2cZM[l cUVyZܶ魩i|[RwQ6ԱO" }ZOl~B$htz Gpn)`)Ʌ_VfR<ܣLeK@>3{uhwD?ٙM'"K[7DsVd<T}K(_fuee7rGm>(+b P  ʞbY ?s.+IvBf0!=QQa{@a;Ryf)i[@VqlWޒCE,I<ЦԠ? Gn 0fe>'ҝ̢՝8ݧkc *-]Y"}FGgbwz|:t9> _n)@ٔm:\^%Q(wvE<͂Ihz|;(3( )b$ e"emV"L1n:un&_ʬ4ܺ %5`m*u5{g/؈ѺI+h"n5[CQ( :!O3x:j]롫[t< '<ًvGO4 yԃofzlwt3Spָm+tGq=R[eƙ1 TMͮAu3 ZtmeGQ2VT|n>n¨IV !܎}dVޒƖyA+kc@6 3; H9ݒ^ C_֚p꼴v*$ Á}^7H1 Sf[ KKf.l @j &Dv9c5购-ßYb^۴IGzp&tl_=ǘ3)/-p?,X=X@qرTJvPzw9Q,.ڼ,S'|3oo%<hz?:T.O`[z8fþs͜!gwhV?lBk04Ʌ(n 4(RK 2Z7q,G=AĢ@d )JGr.g0~|Ks 2)@[۝Q";hBSĦ)13ٔ]y^ 6QϷ.^{/\i(pD SA4S 0\{X@DLTH!' euZg"P:сJ'i'SȿȘO3`cCM$S CϒDd؟at2 5a&WXkg*^I2_M{#<, 'gLo&Xn*HحgѤnӺLYЯ=3#~V^rTM_C&2ljAmI[C)JJE6Kճ{\H:S鱿oZL hJW |Z`0ߛΊed1{"LI]8whTϴZٮ+D'f7'jUD]֜[D*#Լ*oYV&ʹ;\!^;CXpb XzhV&O*佖pVA!bч9wu2'1}t+.[ 1ӇD Q!7VK[P!C~YuGn6I v.h6TUyѼ'i*LIR%}26KcϪ"7[:Ǜ}9|9^(c4s\jz[*`BS5TBRjH||qv?mxqM Ë\>QY.!m$K3HZ m 2m4b%&} :=k$޹b(J4P.s)lYGV'>Z&Wb<cp`|N{Y=j#f. wߘ!`+H5lԀw ,'6* 1E,>K9C2cG ŷ?WNeˡ3;&,R.!Dsy%"ztŕ8ɔmbbRnR{/2Q9˞7{g q/9|\@s&nWfeήk't ޭ{Z%cL+TfGWcfe}$թjɃ[wMASlL]d'CxDCqdܶ_LA@o"U}a > @H8EƖۢr")ȋ- W0>Q[mxUL; V?*.CJ2ɧ6HLBawn0Hߵ} Z~N'^"]8y*SS*D gW5w6_Eqt'.`l tA!m6uS8L"# Z>r)5Ezj|h 8h=̊Y Rua5ZL**+p`jl6.OrMւ|? endstream endobj 185 0 obj << /Length 3170 /Filter /FlateDecode >> stream x՝]sܶ+x)T(Kmf\w)k2.A\a|EE*UNK aNoa{^lDy}÷oے*rw_*z;Io7?t!o}xN鲱mAr{XϾ/()>޹-dɉ?ϥױ V *4㤬P# ROJ,HU%Ѵʈы6B1L$^5AU\lulևz{ٺ%!I yG8 1] =[wn XlRer0o|-8>ֻc_7hfɨ&Bk67khF?Nr:A;V~Of^| W`AA)oQ04zhλn8^'}/<_,>:^bq(Pp!!O}g&Uޓ/~7^s*{E* <6mzef<BBaP)$%1u=ZeE<^>ÈKhգ,+#j'}'(-'pN#}'csh? <( >zP#_iX]H)x!u``1EDp`%!]/9MdfEj_ael8k'QB]5=iYz;PX(ih12@;C븙FTי)y鄝Gݦ~<5O룏?tgHю\WhYq(%qƘ2ee(\|dr٬?t&c*ܶww>[<cƛPtў=.x N1T tȲtJd:$TM}t6;|we0(,@%@5'g`xɜl>A|AEq")TݪOǣi&mh`HrMɉ':؍]&r8.ֻw^!p,b8(JI/q,&( |qigpzSo&uhzb&1r8*PZ,Zy("p9H^*^B44V/{:KOfb,ק4Hz:\o@(_:GF} 8 :݀@f^j7ٝ8yX|!%łeyjCa;'QEbvWz {g ǧ(5=-QEȟٝzeH*QO_* rIRVN(,NvN18iuZ/g< tzr1m]I?c2}b}GLyU<++ 4 HKUGa_E̴О$~¸q3Fq/Ɇ "=7=Y˽4&#}0A#Yx1dqcWu #\R&^'G$kvETb,, HGM KR`ޣ#+{6]=6 ZU %(5-$T 1Dptۗ0~M`#3/Dյ}%>uݤoI_A<0Tb9 Q#00&c FjC_=/#L'3/XΥ 苸N_6V_SHIЗJj*%y //vZifl}=O+NXe3:U#C%w0T8KHqXW#3}?u'7=L>4ћúm2`uWD̝%{UJRrQ`.C%E@A>wcPc4o]lLϻy~%7|?㾑 Re&Ӟv7_-Y MWMxPlzeׅXWV%VȳNXιn@o.aUjLɈ@ؑ#w e`n.^nr: [F4ZEn3CCas=cPvG;'t~DLn2^ΒyM= 7}utAX((,XLX\1`T;Ws\*Ș EKUD!'IK ^^C2I^pHTf^^6NOVO ISV`>=%8Līy"r1i'c1:PX"HLy-sp:_tFFxW6c`}3 OOPhDdi lyIpS1Oc%, ܧ}FIe1epE x5?fsϿNpXʰ3d e cA=lP}3vn5ҟ&vXTynh&G9}p&>vTv_(39ŽDR5K fzN01qQbr߄ endstream endobj 188 0 obj << /Length 3345 /Filter /FlateDecode >> stream xڭZqr2rfHPI\ @Q\lk%'ɷ1 M,(rH7CX^T 6q/ FIhn W7}"inaM]w_r "\Ho.C?^(E,X*P`So_6w6Z6Xm̢gGDjs.cХN,G,>s ,KF 4;g"M3>mqW] :~s8N;~llܒ׿~%JD(B#ԥO1)@圔IJؠX1W63z`.)`GBamW"I<5)iiq)59@bX$*]Qei .FOjQ%"fδaR16-{ӂ/=ؖsYԓWwir[au2Y 4yL!=o_eD`ҹ!ı%ud H* A+)QJKGr"r (- 8#'6DҢ9r*Q͈Gidrt<0)4kg/3A@WN|F(#~>gՆӜ 8L $[۔Rz%J:MӡXO:ZܭHE}IE϶M:׍|P%R7oq{L Zl9>Bc_ 8F]Y;>C!!5YbfRDfPc}^8 p"JŏsNbݳFϭ"9̕$jH(;3'/ ; ֡Tbv0 - #hs I%6YD"T|c1qقo ئK.Rϖ2lެwGiVf96MR5ApJ>UUgE(Jv30lui} U0!,K\$3MIPx9ha۬zsZ7YSkWz4Ha^LNa$+2zuG WqxcW^<1H,m&~0Y-뾩Br?d _;^<$u5W!4: k7p_7?jL8͚F6TA=[*\1&+ĨQXh\8HucAO2-53TLl0NxKAI0A B}3u}&Y ~--v!NL4ShUT[JT QiQh!5: (F1jڨ:ѽ*ѯ x^7ҋ8mz Cs^ Yrcũ( ENחgV*+c \W7X C\^&qqچZďixkR$*uu0z acr֌rΊ8 9'`FK!0zhlSz,"Br5'x-dEY `mpf+_̀wԜ4c E#ZqP^mJD$"M|bCZڵduRN~RAA ]ai]zW0#5S)zF$xRgՁ//>RwB/ 0 :9$i4wH\X"O!a.gThќ\rn|бLفI GM51r> 1#92 #T 88mH}M?_U'FC &}@!ܵ ZkaPbP:@+|S Â*ЂTRJ endstream endobj 193 0 obj << /Length 2956 /Filter /FlateDecode >> stream xڭ[s)hdQą[dft>%yef= AP?.w.hQ'&DG ʢm 7o#M,F!LH+MD?FG3 1+{'u)@S?L,o?Jzϟo?}_7ܰTvLfwo4zQ$ziEBr"ͩ=SS)X!3g"ɾfNngHHzFg3SpAY.eY|ɛ]͔$I_tH 7iߖ̍$UJ)#BT%D3$DiAq`Z(h}_bsma֐\RZΠ0$6>@#zqKpDkqH: k8t J ;+67Eur[B0'r-D[6L{ʞ z`Y5]z&~єu=dU=F{EJoøFqXbsIBug;[uB 44&* #KzX`'+Y_[AԇU__|Qv4@<(L&\I bIإ$}*c eJȠ bRob*.@oL1PQ=5w \v+ ~5/Y8۶CfF |oT)\:(5d" 9>a4\:(aPF_#R5S:i4py Cư|>e3 cX>)K]stavklT{(78`ǡ@w΢87wBix\kL~p*}yΛ3sep/a6#G~X01^.OǬ/ϾL O (+HH2(ùFûbiWdXo`0n˥9<䯯=+qz?cuRgOLۜ5aW+N  E 3^US%v%(-5@ .g8]yF{Bt -\]mcZ=:΋ex8~Z=7v7f=j1FӄX1-h3721L4%,_h)F@I n4?􃹐3 z'e)71B(ŽFL P*1Js|3αasPrhbNccN-rhRr(JyVl6xy|XX0(Kg>naVyytwx@rTVGsmy&" (GY834Ka4ek۫'CO Hp=JãXc=.zvvjNjV9ݰu6yݴcd$gt!lb%8wvZ1͗D5:cr'@@kN]4ǙK…y`U6Ψ Cʾ sn]} v}˚ ,fK|Q(OؕK 5}"I"\\b.DCt}°AbMoܗ߻N&3\"lsbqi2X\.֘%q:(IMjbHBWvgaB|(CgG:S:U$/֘fbۃ ܭ ,/f¤ZMN:7xUy?ۓs¾=(:VcY( rIVccemK!k]<04Hp4%.ӄ4-֘)Q#yCibRS7:^PA\ST{xQ9xS3hxxkLëJ¼/#d~qFeq<ۿ1]zP|8dB$GHgl4cuVSsR 9D ~2ygeڣpɫ s+>Xiz+|ap9K}+<+fv0@΅r \BkƴsI w$ufK8jH ӳ4`pAf2zc4<`5avmw<T"w| iiBh( W Obi84M8/own|oQje< -a`p1 Z( bi{x9CoIE{Hp@$j!ifAgzewYTϜ0@`&K@i8kLlO.s{%A`nF)bp/Vo˯ nx3)9X  GLc18QD#CixkLb XjB!YD7Jciq˴9UcBEEL8]BOJm=^2zQ(fKgy~vLeBNFL̿R;A86y7 ѭjp ecFu> stream xڵZo6_yU_j^w[Ό1cOmOӠHQ؎&6-,QI?RK$5X³҉diO٩,/ Z<1ħS> &|؉fZ~@ʄ`rV<Y|(o h ZL1L@ *%vR%ulJ<of l(`E~莛>D%/_y|[ ;vroq-ट *M]K4yhf2rZCHkgu$$h+EN_DØy )hMe ~/){PGqyum[\f v e]+ķԿ?hniPj*\6cWh>RʸDjR9@Q+ 5-7n-Z@KSfpL6bSnv!5lG%1/U]Sk‰vW֛c]fO'y[?s{^O2dƤ )W_s5!g3/ZTδwo3J2G JY3Q!""aY6ΫLj+W; POI_Q3e}4tZ'@c96%:.9MM۝_֘Ƒ3k3uP0]ūlgzv`wˌcb_aLټ=Μo"R^tزOmGs 6? t YK< ixpZ@tf3,S?|90X!+'U²\ڈA8]I)}: ]䐎rܓ́2b`4&@m PPҩou$BԊ)&ÔZĥl: =Pz5Nlܐ;88 0}Ec0QZb^tr@< e|rLZRIr &$y{`Zյ7t=^!{tcΚ_-uc#aK+`6ߪH`B\eky @Rr'|nKO4d>ҜIQ% 3b<]TΏ s8CK2zsN{necmr@:LEJyab7 àŤ2_JjTD^LLr? 8wa❍3?8AwRcp2Cy3ðQP-xo(vU7͜et겻q1c2+2gZW^P?7,cJsyCX_Rt~vX"%rJPxřeO;A`xFJX'צ/y` B@V=}8'"͞"8Rt=G<`y[RJX)xruJ[`J] qtHOr!5֜-F5P 2`PWo((oVNkmJ&""G),͞i`3t<"izJłtoR^YkNIznd 7w|!5{}쫺^N `o~{>+DNJS\> avU(`Sr>2Xˣpt]( \KDX2_$W AJxKb]eTKi |&=)8z2'*~*૽;IA.ez![.2珠ks:Ӹ^$L^ wD:8v4<G2tUU@5'w)V^KfIbc/1<%<9cH M\g ~ slf&0>cs\$陳½}s`L>Jaf>a4{ ~CGl* -rva\O0ޟA_j`aOSm0J/]2}/^VPSށ?5O<~ZG*̍||%Zӝ]?n6ː];\=eHPho>쫐,EF5^6.h3˙8q Λ`9 gZ<[.'SF;$;z1[j&?-Wu)岧u[‰bel#`?'$W"AĚ,hQ]e&`bTߨv? ^o_c5Gڽ9ÀTJ$٣z /80(M`Ivqv~@4w/1g> stream xZ]k\7}b~AV3CS y( i !ۅuwݵ{u),kqΜh4k!GL%wF$)'/L,BĉbL(2H S,c1Hk0{,.cx ^cylR XE-qLA_td;qbD#W\$Am}e,$?@LJ 99GD2aTM g/(~}_Va, #3@ьqlD`,檄aPa0a0,qT3Y*M,R(BL ۈ ad8AG0X 3tI0FaHG@ =+{ )'s("gsY:60 ԁC.e1SdIԛ}  3kqƬ` UfqaqXh(iLBSv걚).`zփ*&8pq1l6o>6?m?ݒz;lno⤍?lw_CG,JBˇ`:8qKI>&5!͛뫟wͻ;[j*XK;sQʂ)'l\ZM=8_e>$}vX߀J%4/VԌ>UBw3NPDx_' qN \ET GBu҂?K2Q?!_Jnj# ĦsKp^jvHAz!/WrXG'*. ٥v״}z Ws>8IEΙ Rq(?<ݞ=zJK]QG!x[¯k55+U8́^tdd|vbC*%Pz*=Pz0U4 >G]q8A5 ewg(Oxڊ<'O;ew&w&aw#mw8jז)U~y[mЯNVwjy}%)nI%$q#V.\</<;>B}%SeۇPN3|}}.蟺zdhC:fW[o8TGj m%bK:یM&[[(s$arÑj/}Cl=*:.OgڳW] +_vKi\t~^A\;T}X5^ۺmeF}&SNө[Qrt3-3etpxye zUܫciK,uJV'>ᛲ=6 endstream endobj 200 0 obj << /Length 3750 /Filter /FlateDecode >> stream xڭZmܶ~bnMCުJ^r7J=]ԁq&9p8pل{{i6ԏ4K7YAdѦ7/7 6/ox{JmR?Ops{d&MR?қrT|ԛAf*N%ۯfxI6 _W%旛.sk?t6l@#O(V~wͲ˒U9tgyk7U3E7aK{C77Ϙ\dp+0. Y*M3sE^ᡨ85f#R7L*v&[XX?ǶBpe,n~ft28<R^є-| Q?ERƓ`_o&-dqH:ӝD$ދm{mϣ 6ݙ礨uV^f8)N^;Wco۷] ?]ǡGƠP#8V@9Pv@0j/d0_8'XpBRNT5h4czۆPB1g ʉj;jlڑ<*Nnn|Ы"t/)RTX_k(˪}eXaduxEړUsM vUϗgF6Kb;%4fbWlo57m{C,a v5Hf24fj@ki'e~ko#ekD[ImfV*ljz7 j]U⍃+68IPpz ĞYbM#h4W }10i, B=ۆhE|CrYqC_t]0NMՈ-H l2 o?%vإqhQzXص@U,Q3`I2A|F 0 !P,]ϛU)_~*ޛN#120'ʶ~[L/4I8h(J1?\{|AC6Vo鼗hB6#+JLJL1O|]cxU5U2D> WCQLP%ZPT(oQ<}- ;:=.ٰwOWI R&W[E5gu,co@NRj,+:-CsG?3k7}1pY9Wjvo:M=K)DY{Z`O7<zC{},:_ހ5s%wM"z1Sq0Mkh`)TTAE䃵V>?"O,ĂO0޴s[fuWix~qw-ѥ:wP….Z C@>Ϲ j}6'8\~9l){Y%e_ie}trq1zϒBZgt P e:(Ћm{9Y h>OG:I ˘2S^`=Fm&krI]FdeI5zb T4u~J?ʴFd9RJ< Mk:+;Rv}[HS(Կpttu:C<q $<2̈́a~L萕J; >ͮ`+DXbRp[x/$fۢ,?0Wbc(L>T8`("%$ivM@`/teї2N;pXz ¢aJ!e8wLफ़)E@ʴy\*ѦN84VuiZN/'$ Di6 $V]).DýoAE)0b-rB]ze%:\ Ⱥ&[N]%b]jsĻs#%uu؃0flbtCo><[o7V11(L7I '~12b92tzHYUtu,>_զ&Y>b:~ GVUQЮS)?g=G;HSUvY?YT3R׳ϨJÄS<ɚ(?YaƋr5I- bXΊ/<{=pɄ`dJ SA rﵑ~g;ʨ&<@<]q/qORĦ 4x4*I@|6#IkvZ__M(ƝE\f|fͩDs1r95Nr8qR0of;G_iIcs!}X@7[1UD1q F" .r.EKO{CۏIe5tuGN޽Rp0;N ajޓLO>tI2#t>$\u'Ё&H瞄CaC+J'aT&jRmygzi[HO>Z-}i( `935|SMh-aSXas4~݆`s/D=0NF*XVU:.2`֦| .X;O[zf<y6e0.bǎ`1`σ^p]k.>̧Wע <Ł:?UgEY+kZ,;Z75' Pai0}`<;ƣeal4ٻ7 PiIOdIۓ@`X#e9 *x4uǔ!t !ҍ3’?E0_&޷m*~ȳl3Ljc`OiWu6' +W0G<,뫎eɔV -l٪)Iql9DžY8"4~Ͽi7g]ŵ.`|@C.ωpgX~rMc?HxzVPS. Rp!&jYӟAP[gɞ`\t> stream xڵYm۶~/FҞ~pθMtpkI*],H:4o|bwx!J-L4KLiƕT&D=3!F&Ғ)ԤFכo/|b)4 [,ox/|+$)Oa<?k*/&.cQᴫW䬕dFhm`Uę̳f#39WRŒDF+>\1״._k@w/=]%JGFdzr{l`b)hBǧM|P:nmM2aY2N>UEy\9=| eˁJ2-|[Xcu!QBdC $ ˵&t ,0RHvCo*>s ZC/Oz۹ܯ[zUgY]l5cg'Cei-dشL$Qhdf.EѶD̔?9pΞHTu.嚢go#@ܡ-2Pb--1]$M$ou\|i-MݷME -w6SqpM\СKM[ S-RK'-[ QZ{= Fȳx3Z>ȌC3^GmAo7Rw}Q-}Zs2@ZүqGX (|P_¨xID@ GG]k}wo+vJ% VUU1,b R9wRdI[T# oMwXm_hiFYu`gw~QMc]/CЭ]T huQdЖ\Dbm&CA5}T}yL$LusEABm$4"dM >ɇ0M\L,hZjѢžg/{Zjl9KH I3EJ9eSx!i\9%V{Sv[ȭ=)%o8=SNv3vRIݝgI6  n{H9ִ+Px\.v]TA@ϳigqqŐ̀YդT 7,`[ iF/2@l%(u箃1|Đd;"X@25g'Ņ9KtbQ]8JLWE2;rah{!{Vj0cuypCW⪡ g4z$0G]UB"^qH"CGrMUy(u v>є2_oAx3 u8VU[nw= =wG/ >!gPt: ͔Dn >&5BD-\v'~~NГK/rO$'xJ5K.$]0`2!Fq!;b-/ +3_K]%ߡ}z=>%$to3$BJЌI I B `9pc&F w~\ >C+-(1(MOg5 )>+! 0Lq]t_0 "e\fs,Y)&PH%2Cqs!-%t2q39 ȑi(n׌y,wC3L忻u.`ԕ<pͧ ek+om LK \lfE3P`Ք/;!WDE,.9FP #Hnlwbme]*;E9Mu%3'Gs7$v&7ʘL*B2K|K&l{ xpӇÅfv;rMMsl/DOAr(^V=-'҆˛=K=918ծUo8r_9Q`qvQ9M4QQ =ׄ id NAEHօy~NyClo _c֓wu { Tn>u.\$)ťHW.P]r7VC1DqZ|jhHdhM I2t|<> lM!_ڇیؚiB>rL"sp+*nOGa/Fÿ\)r.^Ղ'`־ endstream endobj 202 0 obj << /Type /XObject /Subtype /Image /Width 405 /Height 194 /BitsPerComponent 8 /Length 12236 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFJExifMM*2:(&&C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?LUpOT> ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oE2 Hu #*uQEQEQEQEQEQEQEQEڻcY רהkn#/8nֶvG۝ǕEL0 (BG>TH9ڀp3P"խ{gY$aiyx~YF$ V9꫷u57$:,efD1<JdS-}w!l<Pr?,Zuāx=UvSMf #a_jJ(2yF?tI)dyn g(I:+g/X窮iPqy$l1c+Mf2$&~錓TP$yn goeƭzȷycTQE(((((((+<{Ia=veU WeS ֕YS4LSHWzӿ»׿綝o}a__f?闙v? 4"kwxCv64I *26~Tt8Tn?Ԩ8oWzӿ»׿綝f,g9RDk /.ۋhݍ®VYO/|37wgڏVR?]NQ ^w"kv-w- vXqX]Ja.+f}]"߷i}A,rQT{G+{{i?]NWl|as}-ܐCk$q.-20T܎$c<C=ߝgyʿ1mջ8Wzӿ»׿綝N+h-Ya"R2>T}zpǖ»׿綝޽=Ez}zpǖ»׿綝޽=Ez}zpǖ»׿綝-jNysf#3m*^w$Y%y G }wl]Zl>h6hdGRxZX:IM*'+ʹ?j2:޵u{5C},6mȌp ö ٯI?g\Aaळeuk>`TQ ?*}3AV?Mn H{me}dOn{=CWsk]M/!In%PJon@?)~:*rvcs=\\/icpU#"ۻ"|9١?ѽhm۾s]}utzYQxjMI|"{n_{qr݌.fajxRO nnRTvQKi`2m,*NFp+-< As.7Eі@dg<a 6XU3FaE ͞1Ju( h4Fy2JD H( ( (!ylqcG =*hVeV;44;O+BmSvVW&+h"RV4bƭǥQ_"-j?Du42š-AdP2Nr@qӵ{4iSTVǑVGRIKJu M~a)_F_UIB8# U>>ϱ}93:g\eyi˿#g1z+)kx/rrɝmg5%:&05iJ%J+QF>qڣҭ'Y%-bq'_1)(ѵWUe OY8Y؅UX!$ NA?E?ECGyex0 IdJk}ZIWKU$ NA?EV7}^}_f%:&0SboX{G*oW NA?EV7z_ʃfnSboG%:&0V[F$`WpcG=_f~1-\K~g:M28Ʀ;]&fN_h_ӿ)?ƏIt/ G#)V_-gJ&*$ǛmffBޝI4KoN9`]K]>Zja oU]_Mi\Ius5JAw,QE# ( ( ( LUpOT> ?q%ޝ_6cyh]B1o-5Iد&V9v@ O/JߟoNse៲i^-??mtw~I-Jj6֓zݖ[YcEI)}.jê֞3ӭMVR㳽xɛlo&eFrd'53RkW947!x}>\ :SNu(IqKw&\JUeӚB b3+).8nhXxP,b,wJfʫ0ܫ tY{S-$AkBɥFX*W >rPOrrsPEPEPEPEP7ic1 )n8ϥgxw_ʱ46ӽ sL 0#=Vkq4Sͅdc*{zNӭ4llaXmD_ԓԒy$IyG˹H <#Z7F>u*"@P\ ?ZA{ IxAUb!3/| "(7S)MJ<5VU嘲bR g=3kw0)刲#P.gt5ikP5ϝAUhSB>?<͵ 7I2$Q.ݣؿ>UʊE +5rIb'/| "F(?0 y͞}`*mZ5bؐH:ikP5ϝAP-T$r<}?(kK;_|oTkK;_/| "8(g+FOF(??(ӏ|utvWSpARkK;_/| "8(g)tѴH I ڪ9,OV#66NȠEaI?w5P*׎a!+5Ʒp?؃DGUGVV5$=DѼ}JӮz1o;}RH5##br+5ѥ[:?ڼCl A=v:W\g'm?NiB*ZOդb(aDYOq1O̭SVv,}V()%dBUA#K}r_+4η}F-z!^6eH_?RQ^qQEQEQE> ?*}3AV?Mn+tW>+ci?z\GK 1ϓ_V>im=̳:vBWd -q_`GDx-·6e{yȕqݰG%/Ibzg{G 6 u˭p^=*W;(Š((((9+{o3Xlp<zVGu&IG4[< Hꇷ#f&ycT ݗQEQEQEQEQEQY>)Ӽ#_ZIXO4Ov u?5/gݢ5/g`j_7k_v=[n+407 (ʊ!|Cv~CETy6|]Z5eJ\3J5##^'WM.Fw%Y$?~w?/._k=:zѩQݜ?!$K?'_qߛ/G#WZ6_G_!}BO%_]w:z?5uehS9}֬漴,L3IEw6Kgdj8_;Eƞ-ւ g\ʴFi+Dߢ5/g`j_7k_SvԿnֿ՟#ݭ߫?G + RZVT5k]WFO3kK`v­\":(O*'* LUpOS[[L4.M+tM:m-fEi5P݁3Y*;+Cka^tǝ!M:j*ai~簒EaAv9R'*[oYX69Db2`xF9\1;q[PEPEPEPEPEP7vkp r(bR0FG"[ADCHpIEd[뼿1j]эST (((((^"]jb].@wh&w,bi#H>d8w3Uȅ/覨MsYhGNm"If3y 9Uu EmGŗRkŢ:+{IXl9 ?B@s}&f۽͹K4FE`hNaמ*[Z]Yk$=gw !;8@y9U4&g1-D*!eT~@2I''$y/5;gR#?WK; k*@jĚ/l೵$7%yyf)C T[|2~& .B21*>c{.6V) +Цʥnʒ6u##sbNm"i[8. BD)cyZ>w`w7sg˝S[ ?,OvhKaQvǁNN9Vk/~ y۷o͍wsz_-HK: n'1 \.Dn@n*!Zu/^Ŧ%Ņ\;(,v]NUŤyOoz6Cë)ʻAPz\y';UWt) *yҁ^#QZMYlvUIϿv(Tz$^eLq82>\u*=ڂڃ]^VWWdyyI c9N : ~AVݤt]ZAfgَuTQE LUpOT> ?<9M/Ó_]˩ֶ_I#4 ;<@=B;֍8<)ņ'F̰&Ky@HN8缰4k HkhSq;Q@ 2y8uvEYc-#Xt)Xy9ums&^Asɡvd|3hml(۸ǥ:ޣSPԓH2j+ڹ6xc'$GaY'9-fX^-!q _)A 7r9枺u@mMv; =@402|?⋝{Umn$s pyLn2oQT Ѵgx-R&+Q89U((((~ɧ\mDIC'Os{Oc2!"t/j̼G#ִ5 i3Hߙbp#o㏙V%fLa ,òi7?UM>7?U2.ύU7eTBMEQE ( ( ( LUpOQE5 4. 'ē,*+39 *zT?h`O̞[0A+E00VOgoEȕ|b U8GV P6=ZyϥU+4Q@Q@Q@Q@Q@v_/j*QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE endstream endobj 203 0 obj << /Type /XObject /Subtype /Image /Width 357 /Height 194 /BitsPerComponent 8 /Length 13382 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFJExifMM*2:(&&C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222e" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?LUpOT> ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEG7I,0lުvIzZ( ( ( ( ]sk5Ʒq\~]oX|7zk[Ns ;#Xmʁ"xVD۔rF8HVnL2n8LPܖ~5UӍgY4K~f3ٿû>}zp ^w"Wzӿ\xCEn&7 kmh ,~`]Ìu8V u![7xYO,K c@"VR?]NQ ^w"c tnY#qqm,Ou $`y?>Ufco^>G»׿綝޽=Ezu][Eqo" 92A"ջ<޽=E+ԨջԨ<޽=E+ԨջԨ<޽=EIoUtK˛4')opP?Z'i-ΈZ8Kpg֪զaFaSC Đȼ28jObm3AV?V ?Uȶ:7zhwZy,-ELȹœz /ZF,ogD3ڈ2H#vwEnfPH7K>,xyA b5H-lo洏u%Aq0q&*@9jn-o/./"K1"\AB" ğNsIm=F{wviр@,p@CL]Um®(R8<եy'W(l$yce ?a½ϲ'|y[|7}wc=֞᫹m쮍֦UV(r%@Z77 eB9; \{Xm|4* b mԑL>?ڿhy{6Yw::X=U(5oq$`yt/ڹcnn3]0еH<)}׷7)*;(%˴RQ'#8QG@p ՄN Lt¢ 2J3ʞgW,^*0Y[[wf%\s:P_ i]#Oge %K"$dAZQ@Q@Q@4ԣPlMz]բрL[I 1NTqSk(/?鴙mw)ͻa3;:( ( ( ( ǗF-axJ:uޗ+˩1i[b7?.x8O&d`qmQR0(((YEAS kp9/]h:5>kN10nt(.I#8TOZ hc/7o*4xg'/=7^펧<^&{?xIL7w$ĩ6mi>٭e4Tbv:Ozi;[:4Em)^;;׍ Tg FH~3[5&%wN sr'%@ӡ47RĚri%ĥV]9 (1bB恝55 h+{gy*(,va ʹޮ7@;ybD,Tiup-z''=QEQEQEQECw3|8sVwuAa,Asm;>TpB:ۥhnK<[kF2:J!EI=I'O$*'*yF^r}  Z?dIFOT/-e92ηp6 JRJ?civzy:+FI7FVRN #Gg\!p[]RyQz,Go)lUk 挕P|=2? W;{<&W2;O##!k{%t~gVrfbN@yԄbCa pHFw{So)lU_|> @:>Z+ƿo)lUI5ާRU >}}~4WhSQ?o)lUekFQAMGeϟt_f{-_76_* j?/G|;3L49 ʥBpS@=pp?!UOů&ѿUVklgxYQH]h+:)Ӄ{RBsQHh;(((?g\AO*')EyjWwB__Elm'oKv6F9ګ^m- }GRJ쀰A0 "5b/9;$R ,@}oP׃t᳽nu. ǴVX؂<; {ERQEQEQEQEQP4sEopmt+ymJ.<Kg>a=PsxĶuu_l_%zZұO qW-uS,!hٺ0"~YM %EĻTl'{}QZ0p֍:SikG\y\kO>\fݔ/#G5gCWQe9NjVwj#6o3tianO#EʭP$q9˞@<砮=)B"gUJ=Ί$hyL]p+(?1 =YL-[thv"O- V o͈ D/ª*#@$q=j`Z*>a"Z`X\ğn\L7 #MrO3\ƭ->|`ps]]vA7YI1eo'{r y*ٱ.w6r8Izg'r'~|6n9۷n>xǧ#k=Fݙ^ʗzj>u`d8ah略 8y뚧\p[@rbLI~u֮[(bc`r 95&(qdF&Bgx5+)I8"22/УQTktef\(*ڢ} >OQte2(۵qgQTt YoT&#H g覹{ TOH+p(((*}3AV?PTg" fivzl[i֫ios2+L d`J̏VحZ[{< Y-m<1QT#:cF $ȗW rlQy;g|qMiMf-I7s 3XdއFir=?wi?zԵ;IEu$Mc,LQ9"p}* hw RI+[[{y',X+~_q xZw*VG',R,y"yuv#8 s2gm߽1j_ ӿsnW=]._}褣n"vH/LEI>[jI3 .ꛎ{(*=7i?z7xZwCP[I派Hȓ2g<ݻ7dvsZTүu R9eIZXjH.BdRvhU@;?HO7icCa2GֵtbWY~$ Iм2&FFQ`ctZ̊ URe@ŗ#BE?~,.y/ juNjt[h?Go$,lQ؅RU7/-km-̏1.B[9)~Sn3dkgt_}şo/#T>)ѵ+.̍8&\E6HI rI IVw[i:MvjSG$4k,b 9 N=E\_? _Fm#HԮ4=!$Xi E,@͸xGSSi#"])SpXڎ>v;G,NY,BU޿6ڀ;:(§?g\AO*')OjxSKrzH(h;"PmЎcmN xqaѭe,. fAP>-9,,>?.%NPNk)6}X㵶KH+c pbx|>GkzŽ>Yqiw(-q*$ĎX 1K;G*7=ٺMIg{{;Z/9ZdcGuw$DE# #ݏן?ԞQ֓T&}8]ֱ7̄SZigOh5.uh\±SE0I< j3h7X zXH&zBG =⹝;zeŻV#nGVS?*~y?go/#Qf |=ھgt_` 6e4IJW$H*{Zw8mBvq3ߊCF|_@m5`d_{V:5H5'vBܩ!Ny'&54o5wsRB%D*^PI`Z?go/#Sv֟SǫB8fE(m>Qug9:gOmG3n/6ywŞuan_QmҦ(l,`뫭'$Mg9bpco㏙ <ߊCF|_@m5`s,𮻮 m;r o1F6 dc SUjږ֏dR(#~21+1&!ί/PH?N_? _F 4:.fWq5ܶor H$l.0IU{ rYދ{vY\X 0slLu7_? _FA}<)Lk(ИN[hN=jڤ 53>d'G~*Y@]5kgt_ v^Y\lv!h啡(qsϧ/SmBU *Or5;)hFP;u}şo/#QE@\m^ܖvSKHyO3B>}ʻb#ӓns÷zv.b|vKut,p77_? _F`(EWEkwэfa(vLVݓ#eN3"h>}be=*6<90H/~Y@]5kgt_Wݮ G&8mBvq3ߊkhZ8( v'$Zkgt_}şo/#P0 Eubfn%7,,q88=W [L[pZ4Ѽ *Wi89^@5ET52mZپnk\ > ?kpsi\AwOÉ'XUV(fr@U=~%>);<`W$QҊ)aa쭼"/"6*h%W qJ$m={C󟓏J(_2WiQE# ( ( ( ( (2-_5T ((((((((((((( endstream endobj 204 0 obj << /Type /XObject /Subtype /Image /Width 525 /Height 251 /BitsPerComponent 8 /Length 19790 /ColorSpace /DeviceRGB /Filter /DCTDecode >> stream JFIFJExifMM*2:(&&C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222 " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?LUpOT> ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEG7I,0lުvIzZ( ( ( ( ( ( ( ( ( ( ( ( ( ( ]sk5Ʒq\~]oX|7zk[Ns ;#Xmʁ"xVD۔rF8HVnL2n8LPܖ~5UӍgY4K~f3ٿû>}zp ^w"Wzӿ\xCEn&7 kmh ,~`]Ìu8V u![7xYO,K c@"VR?]NQ ^w"c tnY#qqm,Ou $`y?>Ufco^>G»׿綝޽=Ezu][Eqo" 92A"ջ<޽=E+ԨջԨ<޽=E+ԨջԨ<޽=EIoUtK˛4')opP?Z'i-ΈZ8Kpg֪զaFaSC Đȼ28jObm3AV?V ?Uȶ:7zhwZy,-ELȹœz /ZF,ogD3ڈ2H#vwEnfPH7K>,xyA b5H-lo洏u%Aq0q&*@9jn-o/./"K1"\AB" ğNsIm=F{wviр@,p@CL]Um®(R8<եy'W(l$yce ?a½ϲ'|y[|7}wc=֞᫹m쮍֦UV(r%@Z77 eB9; \{Xm|4* b mԑL>?ڿhy{6Yw::X=U(5oq$`yt/ڹcnn3]0еH<)}׷7)*;(%˴RQ'#8QG@p ՄN Lt¢ 2J3ʞgW,^*0Y[[wf%\s:P_ i]#Oge %K"$dAZQ@Q@Q@4ԣPlMz]բрL[I 1NTqSk(/?鴙mw)ͻa3;:( ( ( ( ǗF-axJ:uޗ+˩1i[b7?.x8O&d`qmQR0(((((((((((((YEAS kp9/]h:5>kN10nt(.I#8TOZ hc/7o*4xg'/=7^펧<^&{?xIL7w$ĩ6mi>٭e4Tbv:Ozi;[:4Em)^;;׍ Tg FH~3[5&%wN sr'%@ӡ47RĚri%ĥV]9 (1bB恝55 h+{gy*(,va ʹޮ7@;ybD,Tiup-z''=QEQEQEQECw3|8sVwuAa,Asm;>TpB:ۥhnK<[kF2:J!EI=I'O$*'*Q;]QZrk95ܢm.G\c`pэ `fSԴ=Z`ã$`) >[5]>Yw$ivQhAH)1ݡyc,ms#91P[9gK'&{i|/f$ V{u aU H*OI@--ux渒YH^2] ʸcH^mbXH>A84佷Pd1G4\)NLo{@6ҴsoKK譍Rq.60&>OU~]XKd2ϨQ ]6y~a#Z :]E"Tyv$ TPA%<}6wP\-.xC ga\hC ( ( ( ( *h ΅c o-`qYץ'\IlG3"'ޜqXWW&C_(Au=[NE`0 Es[H$KˤiD@HتU~nⅰ3I&sk>\f/#I9?oK~1ip~cc#<ӨmHu ck+>$˖7Ldޮ<ڼzՋ;:5P9Wn{,2!u{hiVXh$҄6H\_Krr9ڿյ} Z ^]ChDT5iG[и7]C&/v"ĕ<ɫOgk#m 9_G4<ϩ׬! ݌ U}: ıĪ ef((mbыW*mpŚhbpI)= B+ <O&dT?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4w!wUFI6OEPEPEPEPEPEPS ?g\AV4 ;K`%N[K{ZeT.7`c Vd~ l=JE41hbpynSi鎚Z_y$E&2DGe3]TI#Öv: rNc6 ~W'sVQEQEQEQEQE ݬ7sZ)hfCTȧAVG$Pơ4\*ARQ@9ksgo2|syozʹs˩6l\"HH2i6^m h ½ %N548iSM]O6Ga{'w&7`w9jYc2 H)0 UXA,Yng9 NGyiO%&F-IJ4(Rd NL5| fȗL!p8;~E5,`Q8b $sש}ݣ?dk٭T˧@֒\ r+I5MđOq!pcf&-Y[R^Pp BPI})vib/_ֿ)ZFQHRX'8k[Q"tkx W l{qIokZ[-ЕV}:<y=0nl>k>Zϼ?yZϼ?ֿ)eeAv;ֿ(5| oGE]5| >k>QQddŤ{0k>$,$ļʸgpڋn]Zܦƶ3;~5kMV_+)+Xm*Xݟ;x?4G2m0H?|RQ^#a`AWN+HsHSc$g*sO#9i@?J$ѰI U+H(싕9R(=6 HNt/?T&HM y*J(9$tl,H1JR);"ciz)Ԋucc`<~RмxSWj (QEQEQEQEQETg"YE5i_Vo i~]OVIMytdJ޴l|MO,7=ܺ5̾e֡42\CG%wq=兕XZG[D›ڊQe?7/viu,{N7Qޫk)7OM '+Cn^[g̡F=/Y7šAW^ɵ-g<9' 8 ι9m<7c5ViˉJUu݉q44԰ӬH4 hW "hd\ڬ+o 'O/v$e>qz[=j5F d^: EPEPEPEP{M:&{h&:Icnucx7Su] #ٞ;{>8I?41\KU2=A@I S[l. V&TqZӴ4\ҙͧH;Up0.~רehVLq4f1;R} bV1(J)s<*szPFZ5+VFr5`H?أiOPgû<+VFr4ejO&c}} b)*wgejO&[׬}} bYϤQ?A[#Q9?YϤQ ???ݞO#Q9?< kx@x@ 31Rx v`H?ؤKh!h*yoYNZK rROb v;[gN/Kg$ }J~xh |7u/b!Ż-lx%]~(ZuӭFخH(qX3֑s,Fu#ڹNod11X40cM zjgWׯ4Ki&t(fXD @> /<5kmLu[CEPRnBsȡ~õ@xكۂ=i ֏ƺ4Vb{縸NJCRU$')Ѭ.1y!yuv#8O FR@^a)v)9t+M7M4{m6\HІĈB.R8^E]ӼAs}/Nmuv 򲡖Lf8n66epv&`KU *o/GKѯ|^+Y䣕+c dk^v+=R2bXmD:r-ݞ>i12_XxNPbKh✨c!qm}xñK*I~NL҈TbMdl-NQxO3nt!<hDz\ZXw[ZNAgwFR]CZeo!vK{Y-͜,~lC{$|b+etDH3ʰO[3ZC\3[,>KxeԮ.kkK*02~^fkx4rȑuV 1IUu?^MZ?&QE@Š(((((?g\A>n(-"IRHPWx 1Mn+Ɨ蚮._m|p#ķ[5v\Ao=Zjcs#Z-ܑy !U0A|zmS=(Gv4)&6Q 9??cV+]sv%̟``%-Ͳ<|0Bg!rFO8ne-lVy'-eD+Ὠ(((((bȼ%ѻ8ك==9k`ǚc?:4j]эST6v_/jaEPEPEPEPEPEPEPEPQEIQEjLǛ>:oPqcX? P}}`c(~PTcX? >k>߱=?ϬOEA;_v@P}}`c(~PTcX? >k>߱=Uy\A4Ϭ3SUp (aEPEPEPEPEPS g);<`W$QүME^Dm;"Uш%WJ@Y;H-C{ O j?'/>Tu gKLCRԬ쌧uyFh<)h((((4[BO*EjY*I'@v_/jycT ( ( ( ( ( ( ( ( .$d SH5Y%{*!Kfy՞.çڋas2qr,GYxֵW}I/:; >}gxvYf`s2q-Ÿʺz.u;B.d23ף8Uq80*jRWgmn-0ɶ1{AkA4Y$7)@o5mNq0j ,8JA :ӻt4M1}Q1IW}97N.ڳRDf=r25 Ua)fx]'Vݥ{x tPn3'ϙN!~ѡxe[y-רFhC~f%̦4Do'̃cֿ+ҤS\}DBƮ@ `6Kqմ p3=NZ{7t?K8$bi ac2O4߳Zϼ?FֳHbx-q" Pyc#$;t+'̫+n*q^^a=Z(=ࢊ(((((,DdY"QцC ?g\Am|p]͌ۮ~|89=5o]zVT-Qz핃ϭo^sj)BB1Ž94emFgEm+#FOb\s~Fkgʀ=DD$gAXSjzEkz5=4]3ċ޿!z̟ F"kp(s#kkQE6$QE!Q@Q@Q@8뗚bX  r{3QҴ/#Py-wo$![GWCEd[뼿1j]эST (((__j6lM}xm[UE&B'1׹}şQ/$v'?5_I,֋&7h/xZ/ %> h(hv'?5_I,֋&7h/xZ/ %> h(hv'?5_I,֋&7k?X{&$,JOL2j<$e $?AAOIy9!dMj^\\c ӸvUh!xEZۮşf͙}/9k<=I?&oC$j>I%ʴ%wg #Q9??oj?']7?!I4cx$U?BχvpZ5+VFr5cx$G7?!I4iOPgû8O[#Q9?AAOI $??ݜ'V@GhտMw I'$x{MST+VFr4ejO&oC$h<=I?&)*wg #Q9?h5W[A33OGߥt I'$x{MEL|-J$wX_dg_K4}şQ/$ nX_dg_K4}şQ/$OkEDGFbH۱+J@mu%ZNokΊed9q*\é!Ҽ} 7w^eیq'9;c #i|J}ek{_"O1HLd-[WLNWӈ &˶"Q(qWח| 5Ԟ\m,pՙGyWqjԺK>XŠKiys;G b$6vMhxNi4"Kea6#,UQi_L:EPEPEPEP7wPYupa 0RP2N&\J"IAE6I[{sq2!hlp< Gt &H'I4\q &8胷'&ycT ݗQEQEg#Io^rk[EoD+EO#(V! QXia.<o[q:9;f0[{(4cRM6c_UХ"oqk ]2 2_s K.OW>G?{Nj/t[5h4t@u7 LiZusms1.Ei9K݂Is {]WT=i$|Xd_t}MFiF_8Ymmۿb2qtɮ~6Ge3!ˈ|~{]9u1|Wm c*ZO{ cd\|o3g'cYfm+UWodK VSp!H|/q'LdCgy7}3*#&_?ӳjz.l.4 R] |`ȸN#ٷsxN ^V$!]A s^MZxk%Y*2my Ƕ3J ]_ZjoVK3,688%v[qFE-wi[sJ8"M8e\1cp:Y-a{+xf,Ve$;v7o-BaJ$\$6pqV?/'/M?^g3lu9DkKk 3Q`K{h ˲W-ӎFs#%x{4sB~HnF`3sĶz]Y\[<\/1F{rH5_;H f̭ p{@.W$*3? 0]$ 2II?V-?Y%.U!vU8/,^JU۩omEw2.Ac1: U9m6[;\O{bV",6…eB3#u5[-ÄrVEYXv!V"+M;XԥM, lC*( {7m iMǹ~a2sPKV$[8b %"t.͸=i,嵱iQ,D˻sXm'wR1<{.,׸z*zmP;cዛo"}?R./$Y%t *MIs]|ya7%y}~Pv𮂏kϤ[\;aHnXkZoZ[n舧d-\e냀2mK6=/XKyaӧKO0Jw 9:bm=?&+Ao<#\8>nA :Jy]3Pn5\d0V=_O$^ OK]fŊ7;w  Y~&~IZKKid;8GLMxNZVM,%]U6 jlCMsȞH3']f K$q~y5sqk@s:~I54&[$3iv: ׍D^c6-9mr]Lɢ.c&]gȬkYudui4ClO//qz-KҾ]G52BG6n~0w2BRax'D/.E-nM $mQ-ՖTp=PvmWhӰoPQE|eͼMwjJL#uz] sy4xH b3ڬEXNmvmWj (i_NmAE;4i_(Oa?Ə;5\ ?a?Ơ???Qp exу+M)7OE((4Eo 7ۙT:> h(kv`a}şQ/$OkED[P> stream xZsܶ~_Kyoi`+$[u=uDŽG^HM{wBJ U\;USɏquMHUUxU =h"}ofz 15WgQh8Ƅl+SB#}h xVЄl Llc{ ۏ?HzA#NF il3X!+wׇ;|8WO);e:R$Ó$?:r20Eja3%H0eßfܻiOҰށ=AXONȗ"]jEX(w.FEZ5>3@f6@# Dqg03i9t7XT껼B}-1mY C[1oޣpL˲XBMu R35nKzǭdTr}U*%ĀF(X'ExZ凮\ Ac~,Uzʟ%IJs?yiYnok7[F ]pV>hhgwA9%xK/.T|[J(diZcrѹmePh8%h'y$8†)3deӺeG#=y7Y|Ƭrsl щ<^y@%CrVàns :ndnt#Б@"}/B+G0Mv|v7V 9QQlG|IOM#!K<&`B6ѠwXeVvu<_ʶE VZ\G ` 4yVbA ʙF賬= }~d3 # i<@Ђ?j SJFz`7!u@'D"V ]  ]x}em,'*(} ӛ  _AΞ shZtQxxmD̝ٳ)s~ kܥ8|[om:hbTTSaZv$UMP&0 w@Pт5_豠=ɟ;/WLG'G,n}pI6'@ $>0/dOFT߬eZdڙ&h/fqmJTxrTE1ctbl8&[7Dюex^m= [W98~e. 860i6}q+2;o_ź]͎}ʹ`8(j94`p@BodɐQ/uسɒQc&+;j64]ޮ 0nQE2#ѷ.gD#uϝQ@j{8J q "=0Z@·l\x5'e$ "/L .QwPE} }>7H- ⶣuN/}V F؂?qq!h $s`ڈ+ 5:$AzI񃧋0ӫ'9Ks"PE.Zlb+F>ԵAn5_.O2zɲd=H.j-Sq,-r[U {XE>tJܳ^LFhgiMi =׎/'Z 9lzՁ7は7-%]&N*䰆]wE~wQO苣sj6|-\M˜v8=}ۻ!pHm) 78hiTrXcy80:Xl\Z)gTЧh&TKataErIw>tk@w[Wd>7ekB?'& 4t h;K'xpyNMJQ͜P0)8: 6ޞ>xgdHcK5طk7GHW?]>}͋>!kӧa?! 0Ҝp5(aЗ?@?fR`/'‹#@WW/ݏY/)qa$@cC~l1>L"N!W}~2,JQ{|/XQSX@; endstream endobj 213 0 obj << /Length 2044 /Filter /FlateDecode >> stream xڭ]6WpiԪ$ٻmni4M ^Zl\٤7B1Lf6>:߈D;s"lq-RH10EemoGw7|##"F@M`PclQlL?9DC'_`1\+@5OI#TpT6vRTĚ")aL'd}\Ne* }32 %00RjfmL"aL/ C^|OLE+b[L4k+8v^-[yx?> endstream endobj 217 0 obj << /Length 806 /Filter /FlateDecode >> stream xڅUYoI~)}ʫ3sp̡ &,"lxPQˬUs3u0vL``"5Jdxi}1r02j&)|>4.}-lݩ4":s`"h:~q4~}vg )sx) 0"V;J <ˋP|\HJN oy> stream xuOO0 >'q¤(M;CHk&!>IK5.Sd9_^~'𑪂(rށg3[8$$m7JC`x5.u{XwU\4L*,3cX5%SR5~zM\&'#FK'ITo1"Cyha׉`fK Ϡ쀍B#Kk>#}k<.FtKcW endstream endobj 224 0 obj << /Length 3065 /Filter /FlateDecode >> stream xZKܶWUVi A(l+9>pg8386>9rwcJbgmM _%*4٤6VuݴW! 7?zѡrNǛ&TG8Fzs|{r)}fzO pj fC}ڼ/g NM2$iJDfW#,fҳ?֛DeIHơJ] oioe/42kmq1aPE+Gh`!i$\:|fDHeqoi.xM Yܞ`6L`Uӳٟf]^p룼0/msoi|w(`^3a +;+vXjܗ|fTek𚆻<_& hD -FWbߪPE0 7yј* ,.s)N rܸ?UmSɴ~jtQ ./zek[?lv]}{RSQT]Z8Ǘb#^y&49ҙˌ2gΏ5v=7]/[0- |O")./JT8fW> gsriiY UxU[St!Z8B{e87Sޯm>6˛lK;@)kӅ0P!^1%`77QЯ1@A/] Ρd$ae,w,z_??A;@Z&?:0»}~,~Vͪ@m|ϗPXzD@(: U/=GݚLhTokm߾V_48oNnE_2mv}~5Nc4 西{^ܝ*_\[ABX1ljeϺ?DŽ@ oo\0p"&xQ簠(g8tMeؗXb8 cݯjI' 3ȚdI+V(c 0z&fUfͱ28fE8UIl犄Hbt炃':7717ޮBH~c:Fq49ЄXkG4%`ywB> "G_pWSIlygˀάCV ɴ2&B,EYr6\lQpD(0pnpWXpȎaNɥ? _,*+%f(eTbc[/8=ٵM'Bƈ2)ڛ ;2?^ c&Hy]m~-0pg]#"DbƘBt,Q' LqLn;ḟ:0ZMEø@ `Apx;s,0B`wYT($샌;Û(uj~,υt> KU*x`}r~tAιw69/=h*1Ec?|Lwu|"zyMb`HH 09wM Cg;Klx,E ؐR3jXIlCݗ+c Q.1bX"@Iy[-# U|.HPCT cw~.AkY<4qZl桅EGBz2 v2*\&Ssaǹ'냰ZȯznbB_=djp )|,P$~tŮApCO.'(T9&(-dRhRYe@0ymhQ@ BQ(cj~$:8 F:Qh[o kwQJǏJJu FUN>&ߨc %Yph r9&Wsy< XIOa֗뾬+yt0}^6K+t ; ':=EۙG3VNcs8t(z-1<~|U|I<-O~?5j3+WkƋ?ظ/&Vnyo _~ƠoIwњصAɔD9qYq EN_ ]|H.1uHqreϐZ>Cx•}SB;/И>;j;+anT WFd>j-~bDss:uksx[,J‘c3ŧUt|oX% DsAvи?>1|P\V?lsnSGQׁ!O(PlϠ)/ʶl Xҫ7:'z"򾙊+; So# ejl\~bt+Jaށ6e!c['3J{ Pm4͜x|/'8h]y l$Jf٘_; endstream endobj 227 0 obj << /Length 1325 /Filter /FlateDecode >> stream xڕWKo8WVY84H6[ۃ,SzU6Ϳخ7EG8C dpAYµH$H#EQ0 ~_z guGa$qk_Շ˛?+˕v/RJ~ T,E"H VR6%Y}NybB`g!((ŗ"@0K'V<:8TH3aix9[(oǝ(gJ> stream xڍwT6ť8x  H݊K-PZšHP\ZҞsZ߷V3g~ް5GBp $PR ?$@nøBCQh.!,P ?v`qCq  D=@CѤ 7 #ӎ {; E puîhq `P?JpJ:a0Hq ӓGx0@<_#!nпF'e: O :\avP8nE 4:H(O^_U_`;;0W(@GY@W4\!X!e9=;_P0$͏ v 77(&՟" 7u#<[0ï1#Fpc_>G( }((* ^vN_ z#_n HsbH}(z ?-R0`l08鿫cP?m`^s~`_OX#>b#9FWP^ `(!ut!\5د~w/pYL.o[Av/S4UewwO\B`+CMjW j{Q5 +9#|`!~П~Zׅa͟~_s4+U AcgJ PهaK}" &>2zf7G`)A X A~{X2E v7@ m3(ߔ¶Bv3;PЎZ9O1I3Sb+bL҄jAnΜ >sY҇CFo>-GۄSɾ3wZq3qtb{Hd Q1ٓ\zXvWOmy& O6! #??= YJbՐ:'M!_ZczPbT"1^(#c7VJv׾b+^i`>gJC'Xs& |h3~>/eP:mܛ S}TE="L{nw|ct5wZIRW_;<qMXWw)`s]8 20p0.] m4˨6 ly[zC!IOc;Vc&( "{9gHБ0G6y5˵5s$p3h + xOq@.gI\|+LqPٚn\T(W`f|A2Zӧ.VIY>#m0!kyµ*ʅˁ ;_L˜(./a ,J'!{fMF0gCH$Q[Lhi/-lΙ> 3VFiEaC_h X 'BR{LoQ/=k_jY}4j-nQ"Vz6UHqj埀'\_#ڸfe,(L'`$ t"9pM3itGY\e'2[6k-}&E=}[Dm־\umIḄ内kg9llju$%Fjn* mJ*A99cH 'ʌơpft[UQL8,]+/|ZEe,ÕWN'+#PJ7i]*b6%Y7}stz < &.=<`f:sB!HX9¨CF] e5Es:)\-JI.ϫɓ_T7pt[=KǜKň;Ihb>)zbHkvB{*YsFGF42M7 Na{ӷSoS ;ܸ]\ѭI-ãѭWsOHؚz͆8?ҸoQ&8̐U4|g ( }hK ~*BLv8#7տye ޞQ/[$=tn4 b Jm%&:|si3bԪn#7ioCT Y-|&NL2*9患!uƚ?'M4|'1DaR>s=3]MWӂ6?= pTM-c'0[۵U>CKp"H% D0&׾EY88j4L\2J 0J섿UX F zi*ˈn~_>1@3kÀצ"gZ(~n&gXَO%Zg*n^ }k73*%0t7ݮ6 _YF3D8[VGWH6wrHٝF6Iʪqn8\ *1lW6 b۟^h~ZֈTU.6d,ޙ5b8]ZG1ߜk֔ :e^R?Zڹu5s:5SKF4-^S K⋆`okLSUv{q쑠QMDٚ=TCx>'t%tkNwtaJgn&9|ߛV|6h[ٟVYjdt7=oM9;Nto1KN*67N ̢Y-lKCVFT5YS{k 1W8q2 #rL-h.A Uzz;j+ݒӣP> 8#8h+L=+ }voK ;Er@w lv _$嵃R?ɆOkXW$| *qɳC4>SN~abcТ"8kTߢjrMpKDC7 w؎Ҳes$_ 9!aVJl0/8U)e/ɂכK`/o&TT ?;k\Y@ }X|q"{|l&Lޓiv aJ+5'%$K0V7˯tnDg^ԦN'=f䲂}#ibxa;U`Ϲ4߫eGY7JDf-qZbb/+k&P.?ˤyN>gu8C;%rLq^U MPev$x_ҡvJ:1箢DsmpƹyR1\%`݀ԏ(Jŵ V 1[RqW*NLm(CV Lv*.6] k)kM lè" X R gѳJ&n\YU`?"x~KեVs8* K~^C:rKcaȃ QؼTxpn8%Yr~oevTS.}>/q9튪t;!\Wm4%7[Ji5%$ͮ߇;hY&:2t 5^V Ɋ B͋2J'NSYwV],%\q]Z3RLx(JrYg,r?ҶAW8-Yl[jZ'18Y4B@-&ږR6"[Tc.̰-BIԜk<RU<%hBr׳E]#n*͈hFNG`wqd[9&F3Bt>nrKkr*$M'Hʫ fR~d<5:br,VJyYǾ0"xgqܚLL Eq8Gފ)Dn&lc i~\j6+wzadǯkdJi2HHۓ<Ōӓyp?lS}g}'yD @hwN7E_ׅػ n{OH2zIxDPyG_k.s 2gfVښcW1)`ݝngeZqEf )$kq<$rw5HO;U9$EJ"L&IB3akzK̀?2TI ϣ|غVbn ÇO"dL teR~R9vFk7 6EK{T'RNpƒHw}x܉'nvsk_yg4P=>7&_ )+s_\ 'в0 cQNG {xTdof|xr7i.vG;N3iIj(XL9.e׈gLpQGm(`KoTS3,OC׋f 2.5^ ňW2ۋR%/'4t9%}K##աݕᵏQP=j/VD rԈӘɔ[!{7:P80&|vn@}yJ&k%T4ʨ.&Jw7iUEL#h#C'4অ5" +f5iX[[_r{GGf\qف r8qjNTa@PXdgJl^9uӛ:`D^Ϟ>o+Y՟ &J&LcK1#Rԍ]L[?}n4ݰ}"٩)tK}kI_ܤ B_(J}\1\NF=PIbfQA`P3W$Fsf> stream xڍTk6L"!9CwwwC3H4R*HHww#]"-ysk}b~u~h(U5X,fPi8 f$x +ĎMCiƦц:#l0$]L)ay{@v?D3?@jcPbaP6y<`>>19P wo446PǿZ Z#llnnn+JfCPgW`2G+6 @'DA9pY@w/h)T?d?f_g_l`!pGfTYHffG!{r'/ysgG$acK"ۯ6w,;8@aH$mwf`p7_faK#*'.w pxy8x9P'ܚW{MG$WN#`y'cc 텀BHg?F`0 0Z~Zwl0y ѝ,0{M[WYL_/vN ;AQ5Z9%p=9gd׿@v0L~g[(o@w?g..7@.4/k]wRuV jaY9$n`Vwnfs8m6P Uk5{Tq'w`vwĝ1 mC_zOC fx\3 |PȻf%5 B|gC6? /73`CrؐԘ8;m;)P;{v n.l[p^.܍ecHc?\e(Sjd%AMƜBlXضYY-iPnj)/P|FƧmUYg֣uLLe2E9JA; og52@5pu(_JLL{>uVngJ9=uĆ@L]ی֯wqsӾXS.8ڂxS&¬",ƈf1giDڦ~0gaɆN= `t3=<gv6kYxԮS=L)ȊV^q9'5~ϱ=UvF$2T\TS Q+hc a ,q [M)Iܒ3{Cn!H8Rmɵ6e:GPΥ+U(MyPpV)+U+3L4 9ѼpU{* %á dRynxaI;_xg~z=YBs(]웛[H7LʥVW< U!Zj\AL}Y{u&k_TTnV9N6vt(DyI`;-]ؾyQ2{ET GfJl^f:7/O% { tD13߄ߩSHӢӄP{sC:"(…xIzUC) KtQR vrV.yOx .Z4hsE~\&T} / 4Rp\Z-Ҡ`%u"i0SYp:zrXx߬INErvM9X WWHX*P[Q5^ b=rUSV3w6N{,hY9NN!r N(H6>HVV&,?Kz(]۞Y )O/1-QnMMI)B@'ne"~6pv 5xC_-dX$u~2^j֍;[FPqsC3˲7ލTG+Ahs{崹~rq ;wb6Hs{裃r#7XJ=4Q/j#FZf[ n@r2~ڣGe=,?u n\[=kD,;7~L8PZV!q|>^s -N3/KxdxW2GwH"&Ŀsq׮-hBO|CZ|8`~UgOc3j5WqF.,6>dL4|7ZC[%sՎFM4E)7]ЫRc=gRx*b,*zZT ]4I[+v]Jo>W(*St ;7( /O3X@GF br࣫s E-Y$T$L3\$ute;#)h;!z $k"tg,?% Gşƫ/hO3="?O.?q|?k?2#.GvEu턝IOƠ8aR\:z[')vykūD1 I²7Uvz )2ϗQܤ&"b<>أ1>þn%/ÍN{K/28|`!So{ s&"PMSxO;>8h7GOH4zhJ7GUq8]_[P!?sfn5PR6 GA^ҭ:ݝ hRJӼc+ȓpk,5vERwr8+FlL Sz#&R8WDEѼ[ٲgGTBHu'ٶqګ\8en3M`yn"iɠ2$__D'3<,qڈ㳍?:j`C(9ĭd/bfy~4}y-a`F"uy3CSbWgFssd?F8ar&V9(vb_@n_;t |Rdž4:4eZ (-vK 3!< Rf!RgNŐsMQ>X9?y.92t^6i!춋ؖ5&2T4#)Gn&,|9?>c=m~FY- Χ΂Fu ]h 6|VsW)aVon/e)GtG~H> 6_ejz-*OK˕Ղ:|d\ do\?1)mAxp"]TYkz$PϣsCcwGBEzDuYe@4ZLTϣe|3 D#Book:3d=(5Q0%$E&zE"=6$A(37G|1rtUa@!$oMtD[rxlTt g^f6cz0V{˔A${yn&TOFq9vƜ5>0|`DJ{6YRtUhD (/o@";5.5≥V%^(1/[_6nԮ~Wd8`=JLn&;弧j#}#<1>722UBy"2pm7O? ىA=(͒$.DTp@E.1}%aXVh6֥Ys)~S }H~DK~XN{ dQw%{h`&QT| z,'MxJy$ a9vK-Uq'ps?qXL }ho0CtK{!~s 9ӆ϶LdFRQ ~1U#p'1mOVFɖWViQ`U"1F&%0g̐1XQƏ"˔Nrm}iϊeRx]K.]ݜs|ʽ|:ش)M3|4{҉gF&tNYbhM.6f<>@N#Kҧ\8[$iYf |WLU>lz5|#KH%BP9[Y <M,R*W57 1pOOT;_T 0\XwXK"&8 R#"1uD> t,,dڡhϏG?8 )b멊8i WkFv4ΨH_ UPtgwkč/ZcDècD [kUSS(+чTwϙR"aEQ= QeX W 1QER?rgFKg锅[#I«sV!^rSti.ZUy)~D;`h"W_nӡ˹Ipl46\n|SїAk|WF*Sݦg+xLai:Atof :%{$V<2*rSBs ^k8aGQQ|ۼ2M(#aM.C&AW"x!w\*ݸR!~C=(skXj?AfUHZR'U)bI#òLzVAypD%Qȑګ1wג3FQӧޖȗ0i穎Ƭ<>1z:0YTBzD= C cJPտ]-nPgI6˖>DnYWйT\GPxNԹM< 6:^"ܦ^r`JWնzϜ~ƶǴI'ūD v{\q+4Crwk'~%j/PYt?אT7{qg{X P% O r]y}?gUT9yp\rM6ql)X:JrcoWozsFX2آsKRn"P=k|+$i$筯jMdn oD\o-e7fK1*u4% 7<_|cԶZ-*(P~ӈM $]a!p0<  ;[!OW|z|\ԛ%mNf/n"`0g 4 ?P۠[S^jrwP}Tl ㎏U6]܌zfD=O)fEAb_Y[VJPۊ\u{X uJ4YIM Q|L1"[A%<*R݁.Z'!>n>RqO;Ke(H7uzAz klE)"#vYq塵i9VKuDOњ|c/*jz5}uckJrI,~R|x2x*%GEi>!iԢ Y% "k&2&S2 ߞ4X @=$ 0Pe+MB| &ͺj:n?}Q(<ѻnYo VX3fg]cSyO  *gI Ȟzf/M1mP0H^;~!qCD,Ôq!0.F=Tb!v͙Z !ˣPH mW$ހUp/0R!Y9\ԗɭH;h<01Qݩi|P+v$-]~@Ѫ36k (Ɨ4rE憍>5AۢKǢ̛E'~Jzy]f)W?Z]X~1_G+7WdL`!Oi9(!J\ ~$%XZMʸP=V )JOe6ћ]*E%n iSS㸎kS|fAپ6MMipGl $l*I K|HIpn˪Q@O3ޞcۘ}Ux;R,vD 13ʼ/RF]xG7)`i)pn 52du6OfXxA‰V[\^}Q$S%w XT`Vq"c.݅ɩ8|- hu.r(ҞDBo 3@]y8Ca yVB!Ѣ#ߣ>mL|h/2% cpBez:_}amWZ(sBT#lR,q {T 1vekv ' &:eUpjn\(lg@T[n`-9gk1(!i;%+V Qr0F@]9:Aj"%k!#kl-X0v[x S犊_ݤxYI 9>4Nl<|v ?YjOY>(=GB@gU7%z#g/gnSqyFcb2Jo Xb[B+Yo*yvT/l:wS1~:dwƳ$ޞ endstream endobj 247 0 obj << /Length1 1394 /Length2 6066 /Length3 0 /Length 7016 /Filter /FlateDecode >> stream xڍtT]6 !"p%ݒ 080tK>P  Hw)Rk}ߚ9gﳯ}8 P0 *F a@XXTPXXCĜfP  Ac1UE"-o8@2 Iaa@DXXo"%B|`N D@9U(+{KǑIKKrܡ(#BЮPw쉎8`tA#F{ Bܽ(y^~v^P Y0qL0qyƍh_ `8zx#({8`{@: @3 t a`A ~!p/$!X¯!X` S# (3 N*Hww(E3?U ꈽvߝ@"la'E8y{"`PM?,Doą%E'st c+@z"0g(8 (ohp#'#pο`~0V{ @_++kcaٔ~@0 ". ~LgO᫉pFҿ^ϟKU-ȭŅY\ 'y~3C]$v M5Z]hv.]# :Ў79epj|Vlkˆ-{ا +_&(vrysD% '6AYt1 $@.`"Q,=pIu>$J.)S])N~A{+w^/O})l".#$.dӻDdUm([ .U~(T\ꋳv"]$լҴ%YȐme+^``>W9"Kiay-gnor߃&6 {楟x'íme6$2s;mO|1%ӺڟbmTK:韇)!L18sfnٽk0ۻ`Pf469.992~x#^iLOăpM.e,Ipk\0Ua{ ]|+Qa*- ;gAr"-S@)kR*/rQw,q9UbM I\. H,0RN]TBB~b0ϳ$7iH>33A8!#lj Fi{>2Uei+kGX&.BY8=w¬|ج4 H>~ \uR?'Pbq'pij/]\Km9m/}!*w^0܈5˨4|Z(FdF9?a tyPsO ѭ XN̏r)iwiE"4t?}uyR([~ɦ﫴V|'=kÉ%"~Rl:N#Uˌ͐PBŚol©Ȁ퓡0ή7}Ծ> 1@ݹ{2e`Zz ©t'²^m3 34N!nU&9:O=T ݝ^V3WӺ} c;5>iW/.JJ9NO6u- 9̅4P)a1S5VZ|Ĩ)-e߷jG R qDJM!SۻLhyVw8(]j!uI('F3/R^n\Jؾ:X AB8=և/EYne.;Nw=sl% cN;䫠W̔̕x vQ4Ҕj'a^ nҹ:w|)ՠY,9m7jR>'w3 P״4o{>x h"NљVBAc3@o:@mۻ ۘD$]hyL?Qx(͆TA@ R*}A%TKVgt˓;wKcS^?]sgF*70?@ ACrOf%KT/{ۅ^N7R UL0< ŠHJ 1>zu%94u`\iJS.p -$~6@%%w>i #Bc:ABpm:KF&rcP! P("K/oi R^P h%Vd<%@Ճ2й2ΓtgIzXSX~R'WH`zb7ה^qsuxW7iy]ЀaNbdKb^c ߇c˅{Jb\v[!t<|IsS2KQqP#-U*U@]h⭣R){z1cqGeھ<$S zqOqe>8]TtMyx5NӂGݔ Gr`_HOJoM_d!B͘=,U9z-|/E햾e*';o)l慞c kbZ>`Lh7lC'"]hcNzڒIՄ|F[V^ݔ֚ۖ)%GS1߈j[ md ܵw 4МE+9mV]\]k?[rB:^tq[B3vGxZ:4$<ĵ+:_Bhulg!ŦM݁g>vt ҾsRܕ.z=x{w;N;l* B6@ZGBAл/vXքi$KQ.^8Dzt<\h$S^j ɮ8J<_ѮV9]̓o" >cW~IяйN]#&<\Y*ۄE=YyG*O|H#bMa>h?}~k"*󱁟XFT>uЗkgu,T7-)EO԰f-"8fn;Kc]+z>ZH,p#%0t-eI}ɾP5czMeVWjPPV';L=kyAY{&My7e=S+h (͢ ` L) WX 1:CX}WEHD˵ugE>s4C W=ĵ%qϡqAS 8ʥMbމo;Pl-m}9a$\-}B͹XVݸ#t c1u0Lz0Zc)z?ut ,ƇdY&2\-ġRK_a >I'hSp)E7N&!?34Q]]^F K+L}h2 8 ۾ApYGX+]5UG2<|z٬#}Tbo]sd+OAb⯏Bٛ,Ws;z _c07=>;ohO% taxqI7eFL~h'F6s9afU\3"Ι[?oSL%ʂTԅ Pe*:E#qtyP8 nO!,fEW|웹5K5lugG :m>,$P~sgaK>庩>kJ)o9~#ob`GN>vyS㶭k0Q]a=-p3V:4'T^Tv}Y-n}~Z(ab)._5JDU`5g+ii7Hx9AofMREKrwEXJ᝭ K̪egXiJhd~*OLq_Vcϼ/ 餵S#ɻL +.}i/#>]g(ɓ~vS\Fͱ>8ȕ#%@野dDWwewֻ>wCm=NJWVlROne`*?[@4Ϊz0~_v- 5ؾ$">Eqݡ~dk;/e"b<Fܾxp, ;xumVaޢx;}])g}z7}^f-omJ=qncsl<$;Q3Sր/.uLNJSFLЕۭWz]/,Dl:J5 'lۇ:< :LxQW_/ 5yu^;uM&89RZV.z~;(+gj+9Ywm5lAp3^tqwwjɱRdLKrN}yv](S{,9*iuCR$hRL%SLZf 29]xE.3+ sƌ>PI5&C2a©a*L+z K%> ] Y{k7luEuUp}O6k.~]ԇGf 9ďϲ #L-dޟUp;\!kS6>hcyau~̼֡`6KPqKeKdž (+Ee*9i0 ņ dq9b µ'KW 0]4]s/FvD4 $iY-Wj-1ʭK݅GdjiN#7HFOI-_j7:elGdec_H'Dmkl-^uNG>FBZMT1zbg)~Dk "#3(3"2>p0~MMX2-HBM+DsgC$V0H4<%:71׻V{2hΊOx)t-r ,{' .J;_, 輧ګ.F2b0JA7?6ϹCu 擉?vW,_swz8L%.TD36*ޡ&,ѵwKI<. >@^Aǁ/d81řDWn;~B&[}\%?}ʗY=%jMPMU)0/`{8`Cy {o-5Eԥ}9tSfR^/T|`t|S Lߍz /:WGq|WF6*ƞHs.Sݨ endstream endobj 249 0 obj << /Length1 1402 /Length2 6232 /Length3 0 /Length 7195 /Filter /FlateDecode >> stream xڍx4\ڶ ]0CNމ 1#ft轅{ѣ&7I_֬g?}ykϬgȯ` h~Pmh@a PCr@\Q0$B?J4j# 78$ J$@(7* x`h 4C w@c} @b~!0 mv8c*mC$A{#")(!`@x c k4B a=l\!C(L Tkt] ?`?{6+_ѿm` @ap@WEK퉾AQHL ncnL|(+@f;%3F컗_@z |^Aa;1\'na0&!hPBTT<@< y@~;13 ]P?"AٸChW7:"v00` !c@1 X1>0{ 4_NEE'_H/! @ Qyl`( ]>ݲ_K <Ab p菀"@0?w忲DT~?o {0 Q6CM! 9WmQh~}?vJ ӃXnKopD~=a0Q@0";a"( 5  2%6!Q!1+J;o2H4&E:X@GcLB@ _M2 t!Opv q|zQuoq=2޼'B9A ?Suc 4)_޽aGف jh,oǝf;$XZ ~>c \ $өP.kQ%΀32TtBN63sV%#;nF#`犭t߼V,b3g kvWVQQzk &Q%dk48EΔJR 8p-|mIvQ C[ RdJ&kz5 1mcbý4vEJ;Jaxn7.53O dQ\}4`aQڋ1 !xߗzpfAܕt BOGqm=ӗ=23$Fց$x`Y[u&ʢjid5O\N܄An^KCyQ8a<#i#ut[撡 d$N{%LE? jI>4zpNYmo7m]4s:<.@ߏo_m(M-*0(~(=tn?L&!<2coGw۸R=.p(lT%B eq"JT6Z']'߈@RW]6t]>Q|C5*!R)KaTh]BZO Ӝ߶`E^srp8O\( >)R'{/dGuK' "/5M~7S>кZj]TTK!xQoqu /.MuX 2 w3&Os&YT~R?"6pfVɱ=, +]X >uq0C'|l]s#w!mߠ|Ͳ9l#(DTs-E~(m"wTFJ1'X8:QTbYudaRe &{sN\WM2Trvg{!+EeʾէdҌt7PJ)@HG2!o}/z0u-~g]Z1IQhޯ >c8`^.Bч W wƍX5}an͓P K#r{^Z6"mm$ީ1wiOz ߊ*i+DH50~axp.OH-q9Plbm$V*ѫDMQ+OW}22S.栄\J^ U}'^[œbOnhF\wҕQ&?e H, 7T~@1D +e#dK4{g#KrqxJj3$S0~yي'cњ%6C<+7+,HB QEOOF+q#lc%xC~>c|3a$7K6.O+_&}JuJ8PJ7rXMK:V̭wؔdZlM#=ED~FwYl~7X껜g8or=o*yѻ>,DEK]"EzH <0,ϲVUcxnT m54Il|wfkS={!,Aa_lCg"ʇWHGޞƀFQYZj5??6Jj)ͺAHa!1| > 5IHY ڰ|.wyps':*3~5N5 v&Gf8Ȁ W;!-Xäp_`t_*BS&͹{*]r8YDi3&mL(Ε$3lVOv]goMUԏpx?7Dz@6:w{dp1J. e0^p͵ޕUz0LPA۝RO-~{\aoS̽I-w]^6+-DԼ_iTXMnlC۫ծ,=QLz/ Bha;\8-G83ڽdX[m"s'x]Ƿ@QfL`wsZݓJt 3o3oHxlj/9'=fw7M"udRYұxW1Y= >[PԛCn,}8zIQy"$xA+ͫ,r7.26RT-o{ޗfQu U z4=c\yAV$ASQχL"yuLL &`+|RbZO'y-%`8>p1(oTV!q޿,)U}ʹ$!nۦT;dVMӌ+.a]K܉=Iw_1?1(ťRz!}Uwn!|*[ɰc&yھ.ך);HItcjSH 4dR=-IdOZË$GV`(X)/}R}1 نGm= ;?%׍ʔ8,b[Kgp^cRX$Q~je] #J1C 0?m-!r xYrv9GWU/>R.Z֧Pd69y~ L(CRPf5yʞDGY; ewڞ9$eY|0v?9U{S='+7_*Ht{ I*\i> e$3dh+:47XxJ=E7s>&7wp;̿5c}9Sd7QR۸x.щf2ᦴEM2VAq[@a>6Z]\ Ye8aOYD}P ^F$g1U,S_XtWzqUy;n՝[|`z鼧^\;( @ Vv"ֹUB,$=Co-k d5f\hE3<5ex?T%|\ 8T["{ta*!jr"@A3Y rv*uztJ*01ﲒE 4Uh4~$H\ۥb*Au/ZT O@lS-%=ّ|b0B]򐋗Y Za2H@Dș'gpzTu{1ǜO)Yk>s t]W,+t}od~FKtܖ0R>dkqWO>c GJR~W6*u 9=YG8ńNU:_Vzƒ[s#ۚ% Ԩ摪 g|+J򌟥U_豵h񕵎C(e)g0;LZ){'|;ǯOOR)I־~dd J[nQi32ˤ#G]cڃ#z9#|&J^pٳsSҴ?w<,öY#u0%˽mTi\Fp` @PvﳦDm`lLf;԰\.eq%;/,'=/B~oY#Ȱo]>6QsR*d*! M+i^?Fחls, +e+];ً"뷠ЊrŎ5CU3sZt_-ֽraT%s@-GZE|e5|ЮCX Mމ#֠j:)^y T2BWdQo5ģz4RŪ 9:fujr/ ̏(xZ I;4uK;E.>4JJ8Uϝ)>~dyLI$83֗BPƅOBVd|`4OYATӌcBnv n)ٱ%[ Wz~8Z5{D@Y3m/a -4 RlE ^~oY7}^;WƅA<ݳY^#P'I4;=>27Le;"Ve/*׽z~6/]~Э&I=R+rz5ܔ/ BomuV[9ހ/'֗Viy&3}t㚪t. jI=olDx(ڏ&,^^dM³lμս&)O܊tq-v&jǓp}!D` t1X}[F+TF I{7[*zxEO@YTte6B A!Nc ߝl!`)#ʼsj-{+qrm$%+qzYF~P$6}קc yu7 eWgfF(vd$fԞ]?غ P_TJ̖DliI+6׹,]QgNU}j$hy㘩~Z1ê o;k%]I|ȹz}K\#>#o[^ gˢ>=.ە)F;SM63d]tTXQs^wpD*F?,{=iyO.̛j }ə3 |,GI\z<۬;qo^h=5!9e=Gc-p+H߉]:oNG¡<꣊$M|7D&gO%29{-nڹ[DotZy"h 5at۰j&P•VP?b(_Ot=fM5,7 69ұ(zs}fRܒ:NeHCOj*P6nڈZL]!NK0Q`gZFJiD;,gx~]Y"c;`(e>C1}fy A~g͆e--*с5x8o(őگ)%}t܆,W J[xe^ ]r,+ l:42Q_tXd^qGssMݜ;!/7c"G"9,/o9`Ig3T endstream endobj 251 0 obj << /Length1 1371 /Length2 5903 /Length3 0 /Length 6848 /Filter /FlateDecode >> stream xڍuTݶ-AzBUz/A1 JIW* "M:H/RD)"Wo,xods͵Z{DH~@pB" ,PUR`Q7) ,_U cjPFuܝ"b@IY)Y0( ՠH8PAX*w#TvA`0( 9 \; @4 y*+, `Ah s#50g2hMv8O(Hg 9D[h@!! P$rB~'Ca0+DBQ_D3χz@xΡ@ e# ?0 aοFU(*aSCb0{ Y'waD~ ww6C!j)xJe$%e7 +wP G!?_,a;@DGp{$ xag| '//86WUSѿgTT^@_!10PHFB(""-! rQvh̟n= 9uW-[%0Kݐ0 u T #Hwjx#(bH 7D`$7e5g$ a"[Y`9X.xs_u 3Q I zx9WoH8뷒 Ogڡ1_  Q_(a a_vF 0&*RS/щQ8gz35GTˮNc8nKz#P\P=mG܄퇤Ң7ݠ!>8 j[._*8o.[ɬ]T,9k\_p-i0twSmsXdJcӱ$>lOvWgNn{dY-{N_R7l:,āꋔD.{5:7)ã8Kd_}ϊfQn?'U40ȣaiL+nqg"-oU:u\ HM`jjUjd5Ԅy̡mN1j6JcLh('A*q/ɌRC M&z(i`S/T1_\_9Kyi{S⣷D *b6Ө3j)ryVuٟ19a? oJfl,AÜ-PU`<䀹-AvV zCO <y2X%#Ɔm%QXX ikcB]SnrB%Qd4O؋]_.闐J (D#/A͔% y#c"cIUO1g}k>]'{ 6*SNwo6qY5fk )"@ؚv9ȶIrbȢo%feXwC&&PΝDCwfϢW"-BAMYaPK ASսXΝڸe arȡbJM75 %T =ȹ@Ij 4 R kV?WvG&P6ԏ=k5?F]3 m3)uő(;Z۟>!>#ZXHZt+,%{&_Ř\;4 m)=n/3|aO\nCD T+QE;j^L r`}75̼XE`=P^xN e7>ޙuH2K&*9zX]x#>G͡ul%hȰP0Z{cyn ;[*k.2;~:^8f|VQe'ի.BEhnXs k?'M F,puMΔ1(xNwYEB}Xh5q~:|xL g]flƩin.psY7=5 9{f_vVhzRpqd=һ?y<)Qkl]| #` ?xI޸R}J $ A%Sʊ eËfGuyri\/^ {,zh0XcOA@Lɧ@`VKRfBȢx,? P4;iwp%{#UZWLbJ[4PĈYWƑƶyf?>nqm{ߴ(UȰ~V6"?|k`|ٖl=O'/fʹd+Et} .jz[*vzq,GJ4J K?CEqQI]'mW µ%u-l$=J_'S_װ{:)m|%a CLG'PQrEp4I_@ԝV7]85)F,ʓr6ۻoH`ӷR MyK7G/|,c0Uq Fc$ԨGu Oʹtͭ4~l̬;B\ewxM-ƖO[j}qKs) ߞA-mZY (LJ[tW2 &Ȍ)=Gqxt.~Ѻ\4\fԸ~Bl0!ڧN7E5<:!ESF-} FuI|u)!OǡRtUw;|,T*2Zw{ʄ«IC8!-=FNɹʍr?8xt:ˆ.^#kd7C,T?yɏ"b^'*oA]J8g_O>o^]vɕT{!o,뛹v1 U>K俺=nUymZjV·$̥&qJ4腡8-`M!J1OI?U=htQSBYVg'>5S2YԸUCG2G Ξ)/ h-е>ٹDO@psjK󓘰km{k BtʁԵ/9IwHL0'!Ry[Āζ'u#^˔ eZvo+BD %է|mʟ%[3s3V:MKwdMD:{RIubdj:L_]@qN{Tܻ.*p锓RIoϲc!$m*ʐ7!bQkJ(xsŎ3qYmDhە?\6{$_J1NytNn~[: ÄXz|THOMp/slR&7\Ə\o>Zmƪ4X"'wE ^L;o^gΒ-~;WFkˏ6+U4ϙT*޳'n˵6wGzVJ11 <֗{xf<㱖@ ŦT5s"O(ƃםKٓ9HVǓ.DŝE?5羴Cp<|@tq%k{$')Q`xgԿ,.S#>d?f,RIE21 A-l㑞O@ZT:(m5)Bn~jaRۀ砎܃EP%,k%%zA;Dr{\VJW>1G0eo,SW^hCͦ΁( %E;4*קH4۱$LjDl`IgZTkw$wy&d@zV*.j 措u3gh Nfն#G/EV Ma>yP1N_u(}V\#W &*]WV z7'QϕTMvn3) k65a;hVU{eӳc[(z{MOL%/[Fwg<ĥZ}̋9yvJZtxw'{lK\!Jv Pof\8Q0O{>]: ͼI~NF'bKmlTB[C 0&Bkҭ* EYzy0J$sܕV;ˡ$Vo*Ξ6UBmWij( *}A dK|p!ۖ WLSѨu,f3"U*:aIFA&D9ɠP|E,PQ#k"U]8ϡC6:q g-Yu1A 1Oqޖ#宇[$+X=4o ~j5өmnňYDz'o"DPmDE|Y  # 7g$_H2|+سc$h{i\޻|]YMY^j:pm. S;ܶs5dj`5Zgp 5YJ=_UCTfL~;BC endstream endobj 253 0 obj << /Length1 1612 /Length2 19059 /Length3 0 /Length 19900 /Filter /FlateDecode >> stream xڬct&Tl[;+m;͊YAŶm۶mV\98=oM?Q ;ģ͎!1K>'Nr4tzh0xupQ FcHju!jo&OSt)Sd+ Zood=0yi!gmipB1˄n1c<(=~`$һɾLH:(8pD҄ҵ=&ۿwX<=E^iYT:)Q״ӓOX%I+Has Ѕ31WpAfDRS}uv5 ǣP͓g(MϚ]%t; ,%DQQBȺ(܎w% +'&i\ILp^- \'n  O _0_ \tUzN6 +ZX@(~GKpm81襔xgaS yiܯ鸡=PJ@K> _poDiBUÑ_@|A)vSc*>I9,Tjp :^s /_)H \e,.\9GdMD#7?N\?Iv- (6 $ +gDҪ[SkB8LŚօ (ëE.jΫSK #`׭g.ĬVP=B'gPJ~L;MW.%>+;?ݵfU ~M{7i>ɘ9B2EѬ޲Υ-vtG3s`awEq6I9BgYyLQёUd iJs4WTB2ҢՉZ$WyԸ_ߘD$E~1ˁP{]@i/y2B;y=pqM8Dz4l%f YW$C _oPGF#%VW)ɡ& ٤VvŋMn)pe꿫_XK[Qʉ7$E賂c2ѡ?da6wx)>/^bQo n%uӔXw(zq Bˤt%wSnnQ6%+jʕ/ jZ[įFoTjj-qh1zߛ݄);dEвJ8=jkng}^6kEf^lAOZ GABFk4QROU0Ƥ|iIr]_^V~$ B3'3 @gbhfHlcA&'|woI1'װ}T1pIY)ؾۭK6W_#VH/ Mj7 o]({a.Yas`K.CvVoe.3׬"tWZ> q| SB\P=4 E dB8If7ep4ӕR>}SAu]~r7%J#Goؒp&>4Kp4-,$%jK DirTO~Կ 'SK*((_f=rQIUPI_hbC6J2j60#LPZpS 縢žČ;&˻Ƭ;5+Xq>?"pbЪ,`kUksɠ [!AX|~O"Oj/c7q0]Gn:[Z5'| "DAr9`CօR@"']ld&,CpۃѹpDv̠ sQ<2A`Yd?$A~ϿrF'!i5C4nnN6yM; ĴIn,zt%ن;zF<:#N`(ۚ&GrG)?,zds=lf p+Z<ֺPBY$=+ H Rs~PjCkV1 KseexA?Sd%)NdFɲҧW^θy_h\lG|!fvv{ƬoKC7-KZ=GDf=%%te_LΔ"1 -5 5%2OI_4G{#(,Q+#*߱FM8^ly1I_w_!t2e6]! sL5H'?sS[lh0yUe QR'F=|QIFy;m+},p&R Y绱Aji (ν6O?gn T}!>}NPYbp*eʤGVP0O%Nt.lkmjaJt@.)Jpё|ݶДeܽY$(G{ &xO82ugyshu~#q,k19* VsBm|vrDzkI; }0Z@hV]*I &x91>p /9tAɑ}Ta7Q0<m_N %ő&tRr.WI @v걏a.55T>v ҅nmoW'0sJj3bS V7EĘ%4d&Ţ}.18ǤbWh)`,a2 Is&ceKpw4d"u)(}s讒|n b ^h?:d zy*V>hzǗv)*: n0}WPp^Z+&t3BS [^9gƪʟ9#SArq}e0AwkNԧV\'Pl/{WF ^68w%OT:O2ϾWZyllOqEr+Yɢ2]ƼBlޟ YeV^ۇɝrҷZT&KXp$#3Vl. 3/ =-,+vH`L%\߭ %l:[>K|C2 |5&:f!3~k *_+Jb:IֺB1P.8!ޣ[o:-!w߱=,InɊ{@%Ůw#$Ոfh~ۣ3Y,1cvz[~6XaJ^/T6/J<͓.tcӾg#̌_3:+.ke>#a"8R󈣑 ljbnSea >U/'}I8ieği T%H?cc]`[2zpdPψJ.5W~NVBn{j0y)Ec ,իӠ2n+*Kl6rfȃ m7E/QX Tʆ7Q*ƈuB9IU^m7թ8&-TW^ tRIьA0)́;%?>MHje JzWr$a/~6#d-6>߻K*' pH j&t/  P·'EVjhM2G;Li>NSjtٸ_DȒ;縫Vh #' F?uQ_ڷSӢ͖ڮXo/_@_HBًr³XIV̤ y`E32`6D)4Bzk~RѰ|sR'&4~eU]l൤QD6DNDT̍My+QP;A Ӯ1ط{28fϘGy7a1YĜ˕2]e]1oȋp#Uy38'65˼."vf>ڪ\%ǁM9xJLAgiX+9 u@p}Wsl_wް;NZ8ʧbߔǑH&=Ů>]~mR-G Awl<`?FT&6A.E/Duy_Qb$-`/^|_ R3 sǻJ~u'^m>NgV~w>hS͜1b1x{vRVh|樂>vuz/ǔH2|ڿXϢ5Z<v|ϝ,`@ѵ8펚K,{TN vX.6XE7I5qv,;` zr"$D@$֡&pp.fh0okmX1[ yȵ[]4GqaIJIڷG9- wm(g?8AebYѺs Xw Y+^x;B$s+2ͥC>oM ݏ5fWj1 hQt\ /󜫑mawS㣠 6A4VQj,ֵ?w[S86Ę)J {/e9kz:WE^b RWFFa?@2ЯyM{_u2XixQOv~QK]aا0:֗"GH9s8:W]RO E(y&ԑt:5l'Qrm1:VEgXm10,hxf ]onz':ȴiEΚ+D+Snyh <@h\|{Ra-LuJQps7U|yoN/|QH:8jM\n*ݡGDn}2l=Q/K8LXUG7|<{m_lDS5 {uxA.,NIj|櫛NWy)Hh,3 hC{Y#5Wc^ykR|<19dtwv#782{Ф9j߬hU d%VC t@< lPngj[ܰq9-18?:O * `[9Ot2r&g_Pќ q&ƮJ<Ty?li zqs~f0L5刏]htՐԧ|G})rv %v.:>S(;1DP%K$^E"z4TB6ޏo5ngsjoI3[}2`I&k#UwQev4L qՐl%ߦH[vC>Fˣ&SH@|<=#zF09ɚCScmZ& ZRY[ĐCDl5ڱC5t1@ʓp%bғN^mU)[ /F(1Ճv R0dձ=}-}U3)- {P) 7'M"{7L 3*7Ԭoz Z8c۾yw[u8ZCa?808|Y.MCÊէ9`)gv[p7A..iOG5VD=͎y-:-уtK0 9 0 .+%U+ O3)v6m^m㬈kV#=:.JKWvB,=!vKV:<`?$Jʓ+ז#_{.ܻcZ +Q;Q؋/鲅2|g#}٧눮\j}:Kȁ/fX.{(Rb(AMFѲ}MۨǔÃ7bP=vO;X1KA Cbhrՠx*Ƙ{&fOܦNB-zJx$J/hsJvfK [ >ߖZ,l[{>K[54Ş썊VzW-?CNEDX: Da+I*T8?$JaI΢$ͨ.1Yz'Ȏ~oVN} KoAXMaUc =Nnˆ >&iUY0yJ aXAAd2:&ri+1B«h#khilOQ?TFDc'KwEJmbXD*rhad|Y\.8&YZyƋc6`.1(tQ- |&uE9s)"hj@ɛ#ɺdJ5:rs͞F̑gxr 6sAe^VlOAcpI'sUDL#OWL6xk7paU*`oٝc&Pߴ$3&vZbtHo5f+фnY:1U5s9J &Ec#SZ֢dtvnځǚF(m3vmt[ t>enr:SI-y~j:-~ Y '~J7ti˝WYuD.΅Ҷ.+ 䰏}JRhǢ}挿*RCH*?_ ygီU5_G޼i+)OV@:d%S)Zl_q֬u['Q.*u?!x.ӕ{j: NQcU&8y1gi]LJ'HW-fvvEFAlh) 92U& 0oh欰TT@ 5p3+D9C٫r9~,l˶$Ql+晽*ꅸ&Yr6 vA:]'U، ׯp"wNb%{&,K5~ [e28yȾً Ĺw})/*m$%\`0<[NkiG80' GOq/RL`7+fĄġmܞdQz,(썗C# }RѰh.%- eJ$Ԓr&tK!;W'ZF%O,"(|jqJI0tVMa1AҬ7.$HPB"S v5-r xv) -@ V3 ;cxf,oR }}?l5qjbz?s;a3HQ4찱vD 7XX $]1+?) Zg.&#j NQ({fJ$ )3tE2ڏIy QhbhvD/y0iߗ_^4 1 PlbձADZ{g]r@|Mm'c1=o  .BvcQ HeT|K$a]JiybۆZn$[`xܪ}꾉[$mIbݸ6EKPG=g-7\J Y]5*1 9nܕL? yEiKxeTvLJ2GS(<SAe:/VVB5)2^Z6 zRf L aw)xBlQ}bnB%ͣk6IG קvh~ Iڍ | `)@$۔DF,' JhB &3VtXk% E[RH5N|v{=   <3g UL|=ut9Sg6Ё0xm7-~@Unx˨yӰd)Q .Yi7s:Z0@/(r$B4',=Xd^*u/6^4j؜r=nʁ+Bg /LyY"913{`Eaz?E[¬`^myIA+z/nq)m{c^&"ZR(fikH? j~StF/"%>+"Q]Q \5#J} ƙ$sYOZdB)i%uf بҙe wRn&#Y b|qR1%*O!na4z7b) :ՌeODv :fUOkYPKs a!E&ۗlPG5t:&Qm2=BaW͹tZ:"vJ{, x&?k+pK$^r60[M~Ŀw9:'뿠_/ϔE-NOgs^ չ}h??Q3]i ~l*p-FoD#K7\ d'Ɗ4zmSʰl453| Rh#/>upgpvc&'g=o>b# k#HH@#׋o+8tVMKJ9D^Û A^ؒBdVhCdw_F=!UtT7XT4>U2Ҿ"歷J|Ph0wS&kӠi-K7뙓FjmKl+mq,&dï:Z) Vz",S&NUluŖ /A1,AoP cvȷeG& "'hǓm[3ot;@bdP83rc1 \Zƕ0%-ߴxtQJbv[ޏ"]Y|HOCz# )nj=LrN5;:ceJnx`ڮHB 'С7oO0[y0 , 1<txj܎/o-O/I"۸ +4`@+zI|n0M:̕qG {ze^*IE іb ?u_gOYozc*ȘXTkR$H|2$*dhȴʘp1^(()R1YdqJgI3 OP2R@>f[fwRmBWٰ|*gmgBlASǚN3^Z{ӤtJDn2XsqVU*TYfosi:ͦA҇ޒ͸"*V_F/E8 ~Ԣ,@}2 jM{m2Y"l hKmU]GH JfCF{i! Nٴ적-w*ddf7;U>l")i@hqA7֛YՏ RD%8,Εi*Nj/Q؛OtWJD{QQhǰ %^`N<V/<٬$L* ǵtcCaUJn~7C]1N7 Ýy>ahog鷪|<)sGe0vMDxF3cm0K|kI6U&h,??ܸ ̢l u"99Fwp hs re{Y1*0fhw 9Ov@J=>= 1x{CXG& ]q&ޔaƨͰzwc ]TqWlX~9v'}fn5twY$y7i2ۡNP`q@E+s66R){Nͧ(۔nM]gCҬV%͞m1xA[+ρqQ|luj-AI+Мl2[cf|񩅍X H5Dt#ʸ8Ty ">k*3!ʘy5k<~ fwفl7FǮkʢ^,@<$IqPČ>-Jp|ăAY^`Bf(w,~d<߮ysJrAa)0U*Z'%wx_4 10Ycbs:kۘ|~تmD_4qr~t']lw׷΢hOfa^B& V$Lw'N QM'@4dFB=+Bґ]Y2 C$Ey4i"ت>_)s *,_p',e$$h 鄸~Qw)DFz)4A0b)It\'!QR$CoV(r[q+- D!xX,)d8hrb7x~& Ii/p滂sP;~ʹ{s *o2jIu=PCVrJú.v4YN3uA󄡥Bfe⪍q'0˃J%Œ_(w –]3&cH:{c7*ffF"ˀq:8\HCbe{[+G?Ӈ)ugc*eOwÈt ?XzO*=ߍ5SdI~gu-"* IU{@􃓥ܣDeNk#=jZ.\#{_C;:@OT+5^;@Mu(8!UG&IvPh冄&:4]5xGغ3Sm,*6m}Snilu@nS1c aǭ|/vW\gS|-0&N!P3|&^ݍUX킀tOzJ`u: so;E8>R(y?/1aD$<@'Z2Nj2!=6,92rB>]/$C0\;0Q3D[#qT=hhvu+G.+T+7s,ov}J"Q^FU$쪀5c.ͼ"sH3,,$eܰR3I"^kKy#qG0ܝN MJhv[C"h&⢑ljk혦7vR.ﲎgs*uoR:{ꡇF'fGJAgA3roHkMsڞI1ImIe> n8qP~ЭsC¾S.,u~<5ĎUF҉y.\4"x[@pHo7)kammVYPz_J?t_qwE jMpyMbj2,#حڏ1dF7U:| hqrwL(Z=oWT{V87eqstk\&t^~Ų$WK\T)CrRx~_ʧw&,#Q_viMO$x{/ eq6m(vhFNK?˸)eD ulRzhiq~+,wt$dDY˾uKҺBЈ"aC"FtPۨo`GێoLBwP||7]S:忂 ԡ/)rQ2hҶ2s2 i. |Os=zUMLEs6\Ʊ)aT(/HƖ]㬰O m:I!鼀k̏Ð1£dc@Q Ԃ<,#TqK~S򱟄P+n7V=6Wm9G4]AAƥOR6A# ٩o"ezs, O̽&8HxK%fE,2fVVeDmh~`(ƙEh(m+D`e7&􀇺Mrit$IG5.} Jy+2rDT:|N`ܠ]I}IA=#B ]ސ #HOV/ kIwssAPES(F sY_Cwirdq"l,4{Ƒ+օԑL$+δzG`/ߨ['CG65`yuE5oYf$J> stream xڭxeT]ے5N@pCpw 9\kp -85~?{U՚5f5T*jL )[#3+@ lc(0Zތ\TT #"t@ 'd*=@Y_BntCo/ k[; Q 8Zf`k@\YEGVI@+A@@k56A@t3[{?[)߰D@ jۀ`=G[bbd7߄m"l|o`*&`;G[V t:ؚEښ8U߾77# q8\e 쬁noprCŀ`2ڛZ`ްοvvn;?9@flo9Mr!, ,?} DнB 3d%[Ƿw"H";q]rߡ6o v81_,lD{ ;YG[D!oR2vLU&3[k@LA`M˿`b7 Wӹ?AL<fQUc(7ވG CL``y;lO|kttߊfex7I_sr8ۿ)i+뿇r /ۚX&8VeJvwTSa2vmyG~wך# tCEAu îA!jʑV٬:nVQO$-n|(`Sء}3^ӊ^ Y{xD{C;4qߵCĐDxHfdم/#>pܤ{nWHT?Yc=̤~۬8IS,V}@c`[EMt<ȘՏ<6AhTKEą +y+jj6ki:IͲ=b \CBC/E1V_kRD m\mjCQZݺm::H}@2V˩ZD-60+@</<'R I2m7ixzS2{=wA )<^}B5{aLijf?fmIʩ[ϳ 6K )!UNF˕D>-BmY<> a|/5aN{Z,/daFuCU26[el8jcab~p1.*U-ZVWl0f)eDҮf %b1)Bq!8m`a7Aɫh/X.ˋ V]`AQ1k/H|?pX%ي 8Оl!lOĪe;ƥ!)[qY~GEm/sN%( 'řN>4JFLCYZV3D Ұe2VB9sa]lbBԶTs鐲~Tm]daO9֍(nS=z ,rGl է-ڜ,9[S&^Aaq^ox6n'H|p+=EFUI##:!s rߊ 2Ņ=#\hAj_dZC]V!~fr~{/df%Zw*ЫIyGI#a T;:H2N?1"\˨s(Ҕ~4 7^Jy2IR%Od?TC ~ 6U!5YNBvp_ꢼ ]~A'؅ez)"bFˇ#(-W D1*v+k:JD雷H)zo?Aw .DpG{+ HxNL_S7Z1rM>s1:K +Zl.lhb/깫?j5H?e`t&Uc)v\H8Vfkm$+a_#yC Y4vAr*F!5eՆqR?':7R&K3e[t>YjI+˼[%Y lc9lt7Wf-b\Oc}6A 9&jQcw-#ұВȕd-7ӲaCj/z+ŦX=hT%,4""%e?s;֯r[ k0` *0G'χuBnYwqG=a|QC}FBϋq4T-j"u4ЮW|ޝS"ߘD8iB%.K~Ó}\i=ljUEmO;1An49zT_O`8v)o89֋ yMH#FG5c;E}xwgpĄߐmpʇ24H=o ;4ق(s=g'P-8ܒMۜL :ΐOaզA>!d՟v.כGj|ʡ3?L"T7R~h"\y|h`3POv?!]os '{nq̲i:9%Jĭ)n@m{ I`Z;@{[.m|> e "ht}F6_p5}J۸喟p~4#v{p2J9 4L@b5AT<5.QZ.k?ş,JWjU6z"=h;.M/SQ?)~٠JJvǯ6zkWao(IJ;9iWZgdY?H^](8GEp =K8O_\%V䚫O&^bWG/ąB>5vFya F&baN d%7E{@Y;/?.d`#~L:O7[98h~$)W^Jfm_pP$iZGhZH?d= S|ubRg~:V [92z#{6jzjsCΜZbNHS򓌂pCPtgߺ ͵RHEced>O-jf_IlqĒK)ޯ[ySmwi;8 ˊ~h|ػdR[9zזe?fΡ5 |I8\{pa@*Nkj+~*)H Th v/&m)䶉yӿ0zk7PsDGKXh껵Q]U#7:A wՑOjm{LL[$0p5\8 !."tfvU;Rw|r.BхO?GHkwqE_]HϡXrr:u9\$k戈pFύIwrE|HQRSގ3W6CH,ηY!xpN$RTf3D"W1ׇ}u'޵ Lf5Rgm1U< ۬N[yHܺYBqoN*wZNn ƭ8pZNlJF]JoYSAcM5X I/ *˥rX]̻b7(Gty#߭6p-(N1\[38O`(:ip|k<gko9;tD0kփcϼ_w^-X'͢=2*œ.)FJ/O1`F2Prdl9@/M}v2B}F^9ux_6zeA}2rw9hdY{JH àQj!NɼhC;ξy vP[2E=CWl 0瞅O~" &c@] qD.L4ҥ5 uEEQXE;W 꽛I_(n{debDo,)c.5rn,~| VQ!|yJ2`[Mo< ~vk1e M7k6QGe* L"hTaoQQ0miœ_Z'%Սhά%z_:iouj>*^/V/Ji.z~TqA X7L7" '9;yQ*ܭRȇ V{NZ4Aw(NX8}%2?K$վd̳h|՜a裍>@ M ̶*)4k# Sq%%ø!l49=EL+Mu^.]Dʰ-+*~IYqd_qk3A;e2%]$lۏ\ωq.a2Ї{^<~e+O=@EC(=& /sȋM K;5|8U7Ye9QQ'fNݨ#K"5?z/ UY]JNg8%fl)P,a]5)'>z5]X298h.} X( *8/L퀖&ʶ>LIf ;S${~sC9?#2䟡ڭk9EͫxSPIVBAUG~]!'D+hD5\eYpP8#Iv~LY.  Zܢ:,tUsͪZs 㑰߭;?h nUC7!_6F~7hsqJ<àxl2eEhV,#Ut/spݤ*b+]+Tf-L\[b b5 >P6 AqV2ؒd+D*34'Mm˞vEV/|L1($NsN<VF&W$Y yM)kF_~$=qq,BǛBB@:Vx[ȵ:;6c3(NLzuvw+"#.!-DTC=NҳmGL [Gf8d\ӧ?=Um&2K4]W{sYPPo]:Z2ަY ` 3ቺ%׵z!lK dg`>˻dtv S(n6L׍) 6&KQeiM:x -BUOyf >NX,t&4k|l>YE{e__N6,`q Ee4f٫laNqdwaS<''w1i3to~/r:U`貑B{)%JD*,7e$بz*%jhw$Bu*udrb>6slM2=NJdbZjIlS])NuD_*k̻FpnAFmRW9Hx7We[m륏SUtqgRֳ(čTg c{=Ww&ߛT8!I"`bP( OP$WL 1bB@#(*&g8FcfCaNŚ]{h{^eb4LXcF)H$Z 5y?I=VBbV~L8ED :E΁Dfr='xYpVM;~m!@!@ѽ?9@bnf#6[V6j`*Gp^&v[NmM!شKf8z%=qTlŏ=2j\1Y@/waI9zˬ' _mXr-}1[YE 1r^(|:؛ 1;sv#DWNOՒ5 Y͆޾aUdw ctE$dCyj헏Gxm=Ҭ?v ["/OȂ$};fʤ%JIܺÊz&sU]svoXYn6e/u|InC;P^ZH^iQPŝg>Eϥ5 QvgNLxV>n2LP|< ([2 ˥ +ô &F ?SglM2(Y/G8w&8ژ.8S. r l^ Q}&v OMY4@6P9pANLgjC-#yiGtV𢘤Rq[gZI12+& "WXo~_ ;vQLg B /2tmF ;clr7_⼄;@*'H3~ݘNJ1,}g35mn-E"vS7;ܡ<@Y#qM٥۠0f?UjXı")rwWi3jiI cj]veLɏUcUʉ_ }݁d $ +8F=[5,ҹtW 0!+ӗUxAm,fQê(/EEN.ıǑcE {ѸY f܋cFx=y~clbffI5VT90a^)w^tTL!S1=Osy0@UUv;X;eZV4`dpnˢ0eYR~`Hq~>DOpp\=שK}JꊎMa(z&V4&.U~`7N3uL qn J#ل|RFf\RXE#6o C/c/mD!Ȏ#7IIڔ02߷#ZәEw JKɣDv3b9˖q60b~_[75HHhY~}D* /c\BLdz|LYgMڋXS%.Υg4CJ!_? T(|ed D&_j`w NDg-~Q%E.T'K\ k<;ǙqRuV7=J&1ER_,EuF=} 1נWW nBL}TM0@;OTVgj/-~Up_MAB+L7v{|x^rher/<tc4hGxힳl=&y«S`ӶCN>ZtYPƲk$Z*g[_]y xV ɦdsaTA_زƼ Z $\D")<lLb uFɻ=ߺxֱ\8{5R/#vQLi7b($js@˾pI|u{6ŏ-_j J%exL\Ģ[S"Mp-2{1 -j>dPų:l5p ی|lb`V}ڎ{R 7ͨ+;ܑzB.0wbڜFA۰ gVl؛?\Q(ɯSr$pcr\kВxO\] !f٦|NBfAEJ6K>U&2,sv*gtwJ\ݼ5 :qkWJCQa >0Zsane ?Mء`yI<$ PZs+\q/n+[FO9_aThM҅K-Լ\"ZBYC*E2kS4es5&~'"1$AGLTD(X}O- ĬH8ʨ.傻ZEI+N'Sn! (h@x %B;hvj2E.@OX؊n)«$/2S:0vݺa^k endstream endobj 257 0 obj << /Length1 1144 /Length2 11430 /Length3 0 /Length 12204 /Filter /FlateDecode >> stream xuveTK-݃6N74Ipw Akp9sg~3]jݵVRiHX́`+ + @E Ģvy̐iil]E! @3W[0HeP68<\4Cj[G7@ 8؂P` 7G UhtA,.?wT bkm `edbb7! 0'Zt@_?I[efe&ciWWW'A66'+3Ŋtec R z&m Z)ʋ?f{| Y]6 @ƬvNvvNa+o/ d 2sp~!7g;d+hg Zcl s23PK0*f@*/+II,|N~?JQ?=ߌ}Xd#?g@,#zRZ ;}q*!w (r enhOC]?tj`k!vWl]dm=j6?pm7vX8x8Ӳ]\o 2 -Gfnȟ=?g  @^[} j `վ}sFvfQ!/#λOΒV6U#`E Ɔ'>fVD=Gd`%"L9)FYqO+*5%7 I<cuwCv)(~4N=0@i<é6D CvvnN_'9ѦCQ("~muc,;x5TtB %G% D)!TE yUĺwYv.5}(B"8*h!]gޑ`mxd]Sqs{ΈJ\.nƱpO6tkHJ[Jwzb)6z( d#]G!kgHw ׵ .]ɕ;ۊ \U2f ˍ EͧW*I$uM C #9y9 Vx]eڻcքJ7N|EE.ޗD p櫙an:$hJiGE0H`m%d«o[n8MS?shiُdUe N"Bvd=[Qu|W,-.Bj$a~uu[:Xy&ljk;KWG0\C'y>:iXҩ_a$fyBOjIUܞ1B,!0jzM;O]kVGez1_Y3#3P"/ K_bPRZZ̗U&. [^^KG勇zD]~}:7)1&4-$ j8NCs5QhKnl-5AcaUR4d a6=gȻڕrnZ҈wm'E;ԍd=dKf[p HA"F=:Y$d HOO"­e,^`vb&vHH1KPUn8\HZCm{+@.U4|~K-*ǝYJnG-3 +\ܜSeYDH22O9{`Z#JF̻ěVh6ڬĿUA{;j *ib0g=J!35Ic9\J7YO+L*ل(2 u-I?E;x)07 #/]'+bzCuh$=Vv>;7LR;{&a/1u{9$>2O5/CTWRwdճ{hݎ!hA&~Iz.nsR3n蝦:Ī1Z[O(d61]U<Lv X" X;PEcvu/UCko%PnJ=>~&SpS̶^5 Qhqj#upm$2j5kXe&Ƹ; c+#U@cF;(w #74Q^J^wDr'}-))kNWJ#N`j'^600=Z'*uѹ)<;~Le]f;Q? |/QWb"L κx FlAdNy'Joti,E뚂 ."bl[Ric_gjmmeBƔQ$ ^zyU> 7gXxpv9ؼOpjDB3S`F*B60'R DZ%9l1]7LUΡۉC|w! et OJ'FK>ZD4kr^ʂӂJVyg Bi UK4N/vKJY ,%p %k+죞R5 R3[9[WnlW]" ]HQP;J;<ե"n}Qoro|3I=ltgȠdR@PFi%awƷ:Y,i2%uLZnu.븇kBܓBV}: }xY@ysS% Z&ǒx!J|C:+pS'Ϯ%S,#?(-G9# W@=qqpO:Y7-*qD"p Jf`rDr/tt՗7(Y|h!"7< 4Wk-Ei"Fh O4OR?r&}ImmaU|Bdd/J)q.I˯GXLۖ H aүl< GW7sŸ@G)۠xU I x/&~It`tA4~)Xpwi:Gjf_{O wU]4p]HRLD KmEʍa_̳IϏ=+WoŊd?6;R1PS\CjL3%nFBj%l9H%{rԸpY۱7QW?Q:}3+z]QIQ>~\Ht8r,R(1b;.Y=p]@q=*ۭ&zAgx'&7)߸~lP6g&D ma2K;yv4>dAj %TH?Jcy}ȨEZv^4\7SA5:|APY'_]GЏ on Ceecft ~^7Մ=|w xM!> ,h@e۳7^J "z"`#h$Ovˋ56Fx/vV;E1+܊l׭+6vryumy#$m\zns yRg)S"o+t'4s^ fv;ۈ0Xnԇ40|'8~e <)p m\;/_YPI*b rigww+T>F!0sj @G78Yv ؑb²#\sC@c_3e8!."J9C2-*v31XUc8dw˘]ظn[ZeOaӺ y1C\l=bǢY_TN5XHa9%:M># ڻ}c*߿^E~1\=RHlY?p,]Ou;ZN &KUp?n [̙K^tS_}6"9U>Ubz(.G[>@P6%[b` Hjˎ[@+G~c8: PPy'8B$Gb9%bt sJ61 ڿdinY`d =pC \ >L{8%EY,JYUhJIJjyJ2=6x?/V΃tYBy2 oZb]m]-9ql}G]z{e潪M( 5$pw],i#u5BS49u!1?=+i`a`xijǕr%S#Q=^8".> '+AĿeE@h'uH4wy8߳ܘmex"$,b "BcM v$喆]v7P.@$ twLQJۂeoWHRcʡ%ovי4`S^U#@C@ΰ_X4=">e?Bn2z10@z.h+C?8]cF-[cYClʭ@.Pd-1& !!q5}V]-̷. 6ڑYUmF?6uZɅ(3iW;0Ahٌ ,`o)Ӊ6.!MJReM $k{(^,.6yE-*bb]8I72 !"FQs/W+)zcF$SۚR6#4PKNuH.u734L\voOu=X:ҖVxHI)Z7bL(dcmߒ6tdy5GF1wGw#2tFZoi`Foā[ Z]>t'1d ^:=Dq:>E|2 bm6UBb/qx2 cVBɂ7v'\#U3i{V63)oL)[ʩ_'#?ﺋZss/l_*_nvODatvt~Z@{B d,Ns}l𺫞+}i^G}{A>t]nL^5-PC,Q^O9j+1#,?iH]ޤg̰T7u-E53ߘFd 9>zH!(/}s5=@L$?lC)=Psüa^ xcNg\0`4%AA1ZIMP:n$ ~dҨ:>}iK ZczdSLνɑǗXI>NP|șCwtJpFg X| \Eeu*Aw({,}dB$O-j#{MZ tۛ7 s5B%'B[l}$-"!L,b,=ckd@}bg=;73'JLj:=݃)'Se3E 3مoF+5ߗo(6h=J)`b,f~8ˊ[6QW\;߃3R`5mJmQ͍Af_VdR+5?ë6БFˇBҗ1亢S",by/vNp;bWCqn]A'c ɐRk"וzXϪb v%Ci[ .×ۢ/O"#g|ܮ+v)25wR0-e)g;9d7~8NⶹC/0kGe"* N'b&Y%4zH]wn5*ILF&3J-n4oI^ZF׊*WV v__dDm/|LS}Y|_3蝛?H7v0)"5g$SP7imr)j4Qc\[mA$MjЧ5zq^V6 O1@v4tG-e#wD2-G~EOb*wa\><#7P"zb8Aza^ץ=̅Qpb|eT0߬ԣÛƁ#LAYS֐O붼f/.g T$5[ f?l< b^"Z$$0j78ɛZ4EPNmfmZ@Hz,5Mwٝc[wǩq[yʏWb?|RáltZSpÃ@r!!V̇]B&? k#Q3HmRk)_m]@ ^[r| PadIMɴAaO&g#\ "4x_S0Iuu盷3+҆VqT qbGx)LӍC5lז2ߌ )YG>v8qiqEL )wč R/ & sXk5 C Ζ=#'GW:ڥ[|dR?Ŭ" vCћ$.ftSȐȅ1aTOtgӶ%:Ou98GDijF&1&T4Z䏃$jufK(2m^ Oim^?#̑W\MK.LsHb3\0UFh VD\0~lϩ}!@͟.,DXm^!xǠ]WrN , ΅Ͻ& )9")ۧkU]}+jS1SuG$y#JXK*Six$+}j?}PHܻv3c&ݛl\hF*Ƚ,>!=E>>3+wF]]Vi#fY1B, q"C )&=*(æsq%j۠>u+?T娟8/O4qKr8_9|"NZfaL A遥X?Lx~yjR>'S"t;,h΃«}4pœ{c3`.Xؼh>"ڔR|.F3jb:{TˠR6cS*Vk# iY^IԟB@啟2o|WeQil>+8[5z~ ܒ3<ݟJ!%:  rE ovڛ0 iLwQ & (kULߝ} jwNP>5~foI{j#m"$Z@ѠY3QH> b gqtX3IJ_H]lM<_fԱ1ijjD|G ;7`\V7ij*@E )֢ם÷tgr ,'e1]r|cC 3j6xJ{{,JX|`$UWQ&L⏁| o7U J.z/-vERWlKaH}Oe)rSگNbNopa<4j/ 3(I1l# Kx;Kv{K{͌އE`kXpdO՝ 72tYTWf"~8GܢMIJ sOGZbi&Xa9FTDxaiT4UiX1d:)FƕIƯq+g;{'>|_9ҤcK] ڧ=ԙ6iFΔ:Uз$EF1_8QUJG{yѻݵVA*BҰh_bS>ۍ, G&p*d{~_&zP@(#&291_7sLӗWbW%,F#hUT$OImPZHE^{`}D_9d '}uIBnHa@Tԃ~{Ӯ1 Ù\ˎS;t)%?`!9"d`02ꩾG<&JF#%q3{JJE/[^M{k$Dl45us"ɲ)/~ZA߄`m:{^;%Ґ q#&h=/h޸ƹrJk8[.}\A?9-Pr=3~pC=ž 1~*QZvC1Q 4&UC)Ŵ|]38B\]Ej 4 > >HB?O$;emw0aٜ377Uu-L5 o=_ wuXBn y٧U00Ҏd0IF)1 DR5;qe(D.?xFI9{9i,BO q>0azĤxw|xTĩE} NGDSLO_qFw"˘#" .Lq[{ K>hx&&M;R8AA}8NBsnf}B"=㷘qǔ^ԏefBp_{nd {n $?ݶZamYSFKI>\15]O"o(Piҭ@THJEs-7}LKucTUcR]aJg6gUXg0_7خj/u 1&zK[.W# !|Cv^B{nqѾq*Tm(z{Tن! pĉ|ә~& ZsP1f6^(XNgkWYv, endstream endobj 259 0 obj << /Length1 1177 /Length2 4904 /Length3 0 /Length 5670 /Filter /FlateDecode >> stream xmsy<-e_3C$13 cƚ,Yd 5{d'*DȾo>}_ss_ PuB`1x D <f0 )҅pC 9 F1!axßǘ0@ `yU,w P1ġQsJ 'x 1x3'D" 8wXO0(((fZHo  tAN;/q AG5vi#P_"x't!1IogI =oVz*Mk~Z(~.c?R( /y'" k'sA2`)X ஠_G{""!`8 3G A82(%wG(8t9H{؀%`rX pCR72%'B@)\P Ou3->w%@/!#",>G#G;  D~ҏ>"fY0yD]]F [Dp.[`=E11@řĿ`?7# /p9uSQ-"~H8(VtX \?#^E$i7dw/漚'eŬԀ8"S;V]AY#nǪK%C(E-pGB {ݺ|%V*",܇֋K^F<%OK)FEX֍twLýnaz-kWJGF;5he#Q68堯ߵH6뫽&n(^S+6LCΞ=Es}0T憇8"gH^g{^1:qũܗ?z:8;Gpڗ~ǰ;.v1=̕6qk&'U2~\ʍxk$e _·iL "^r[ nS?0 m$jbң Q<DHM#TL)dzx$rF膪Fe*pg LPUpIak%WS UX9, tX(`zʤn..[cЃEb XQj;[E;3%/ l86%Ԙ_I, MgƊTβK-@z_yQӪS_YYP(QwiRL̉ &t9vA Q72_wwI7R Qu^j>lP}dXze#E.<x^-֪N"q-lSZvTn`7#e*aM ze=KrW/g.${[){2qYL^sOqLsfG}~ܧ֟mr(#% wA ڜV_ :D*N7] 䪕%{+'˜osȵvx:ޤd{n5*Wo^1 "NW:i_}Di{{EfZo4>B#K NC>zNj>QE=~ёui'֙QIqD^f#89:ZW9om@)qW25];8QUW L}ѲaZ*Kf=>m0}^M!7/0m P>WTfG Ȯg ƳJ/tg y\Hf~FL@2lb{ynt\ u(zEp)2\V& uApfcs϶yJbIx 5)`Xf;xf٥G2 "FTto-.|iDYK3W ﴆ5Uz`XV1N (E]'ɪ#@U+T\X{.O#qmEUWek3>nj,Fz/G=jnͱ V IzIku;kuWIiM`{2t n<kV#fl[d7eX[|bWyϸ%y2dk=ѭb7dէEeuWss6BVO~p;bҗDW!袠lȌ':B{j#M۾c޳?BNdݬŊSzj@FZVx"u$A!Ta{fr7KnmS [ z|зq1NP!pgߞ E]nF"uK¸ .GךrSG:qh# ~D@hՙNaSS#Kh6+F82s;o'G#7BrZ W+Iک‚*^,\[zьazUzH7u!͟LuzFN42qJ7/:gtLJߞ:a7Ռ↰3qp_k-JЃ {` [ZcsXgQw| iRVɖP>5G/@ [Q Cik7lvd {Ҷ( #Y>pp;}RF :Z~O9ZrsR+]'arJ.VtO1d8Dɂ^O(m u몃&驵yMqxOBhxbP{䃽FSZM0[[6^gW(]a#'{̠Q m0FxL !pظrއ#z<,nWj_@HR$ްC}3Z`d7)'QOR^ ޭZ'I59 $=)sm+8G Q~}19Y >PY?b R*y(,U 'e0OB*q$J%csM¼kpkwSO=}KW#-y)BW[ <%Rs {&sl2 Frj[~Q^}L`eI;` b ' o?SnuVB|a튘WUgZφDWI>Ȉ#]zêf0q6|wp9D(Nh̚rJ_"ɩM4*[BlIBdVs`lms&ՁD@cIFѓqܺ㗫|m?%^K#Ď-}N HxH [UŎuW;HW= ODٝK:n-ܥ-8 GIw ) I&Pi6`[V3ƙ(u6bh2r㋔3[XXb&Z alúԥ|՘> stream xڭct&;Yb6Vl۶]1+$۶mU O޽O?}=yy{rbEz!S{c =3@YVޞ[^hj Ñ8\,D\< )@h`a0sssÑD<,-\TjԴt%`?5_Ζv7-+ p,mE-)y @ht2(Xd-Mv@j?93|r&_n@?*:` 0w2sꁋ=_r3rp}Swvq6qtp|eU7N #r;[~f_&/W/3O.c +W0'pu3/t' +W_ulZ=iGz0m(ӀԽ(휴Ae1W LꇻJoPSN0WOndH~&1:5S$<=R v@Òax:7|@q::hK0$6eəUog3Vk2.<ʥ>*֞K8B4 ,4$dW@%<6@=p23AJVյPEEAx%z񱰧N˿gF;{OAyø/ VGJ4~!kl_vŞ^1GMLՌ1)y$)z㡯9YÚ\[BE}/7^Wv̥L@ h7Xj6Q9~N1~nzt;%op2bw߻0N|1*E $֍>cG:p=h);3T>,ϐa€-g%~Å t7{ޮWfʪSo49G^.n+s=\ܼPt8spÕQH 䔩5?;D ޫe5ౠjR\#o+IB#@nO^>>3"DkCsFLl^GA&rտαH+3C1ǓOԅd0˷{ƿɛ##V?ke*Je]tjBwd[TPn×gS %ΎlnmVkZN?G)ha=@{8 "rIuKLPXpgU nbDD7ȴ? M:dQoU'3O'|f( k,'W8 q|Dⴜ&b`*FFX ܮtq8٭N3O״MZLa0~:K`ڧ1Ǥ;kؾާ|+ sF`3 7Q c{Vއ]!KyBPE4MԇYb.3%Arw(  _؍=\]B7\IU7q P GJ~s}*0gҳ8R0CvDP}.-`C!C{|*vI՟x>Q~X -43U@{kݜ\Svc\5L<"tG!M{ѳɱU·{RrGT/߮ވ=H[Paa]NT+-R%B;?ACWH1 ʒ672vdVC JH=i ۏGL]X"!$3FZ(!;-ʅG!8=h*g3yx߇gvӗ6) {SGQ_.R9,Ls+,8Qp 4A~3my*(%|%r䮙 Gm3Imjw=曻x̞ 9jm R2FzPTQSCs ΄i#mD5Xv43 *o8\ %MsQE8א0ocM< _ܒ%O Of2Fݴ|~2)"+39\y8EEUѺgq@N hQuᠺ[ 31(J`d.vk{ SzNGpOG2MeAYeV{,9plɶUdjgqs8HvK04DbD%8¦] 'y2qDl JNLqo,F7@5; KyB9ﰏKƈ!E[/=czt L:8w,؇2}WsPb2rȃV j겴&ꈤDESt 5/_"Ym7B [a4}] KLpoQ0wBSX]2*΋'[<5n0&=d rfc}DDH+(5Bv+:k u"QCS~Ⓥ i,߶!i6fQ갽NVPZHF5=޳m$4pPuIEn(n K_s0vAU?I=ҜyB> i*iz8M"f@6Os& F\*Gx1P^um{À-3\뱨lБ:#u-hb^+D[@D̹rj8Т Ԫ W?Ѫ&^.]EwDgh4!S":1ȎBȜ*6#줈Ň1< ̵9v lß8-Σkc= ϒvyڦ)I3ƞӑnhq8^n! căZ8(= A15>\CT,^'N-|uT ו-|:#O{ +=C6~>BLuz_#۝D ҕ1)31;VBUĢzJn$aM|[Ι==-!J0ue*R8k,z]s'7dzG9#w6 1 U2,GRvTuX$^9!ܜ<@ \}ksN:v*LyIuvf]™;sY2ꟓPe7SK4ly_cFr>:>!gAH02{fHIc3I7* L:nz3vUWɒ9 iB Eď_6ǿ7B G2x* tCZ97ku@Gci!rìĴ*RH}  ?$ kڕDփc`M\=Yra$ׅjGb[QY'5iA"m-}0y_(!QJ ҕWD.`rO>N|Ww(q}A4-j$ `2>nr5 ,w@,IF= y4(%bգʿҧ(wlPY&%9 =PYK_-sjq#¦Gcs.K J#-{ӖeERRɺ(n7D¦"<^f4dY >זSj!Y/P`î- 0j:8mG1{XX 5%mBuYOH%$^9bsNhF;o a7Q't}NbFEroSmlLПtM@?HR;3sxHt >,3ntA=w_pOKqɃdyES ξ D[7Q.5KFv8wƉ'B2/{Q­?kCZk*pu˥D5b1<<9 UÁa2Dƞ$<ws8m13gq޶D|2$=#$=8u_%QCib:S#<0];"Xιk21?z#2 0E I;NJ/Gfچ%{O1K^c=,jD hDJ\=({-YaxIGh[ہf^ JW>4{} l& Oo%Uf! XI)DqoIu PD} я}G q؎V(^a,8}Q R)>^̹P 3$gxY\é}L#i#@a7>FY"tU; F O )Q@+eM`o`ւ(goоtW P5#4$5U c ڡH/:tmwBrv0S? %.a|`n{,4aR[>L3Bڻtف}daΚ<{OR8h8c PX :5MRkW_iZѩkdq uyG `-q;OzՆ{=8,Y_ZFr,`c,Biu|:zַ%N$bPz1A²A}Had:T#Cp>!aAVQ4d(Pu/8!7@2j@#{xV$"X<>/ nF&` ROF55lx&DF3-atb(.ҎؖWU~,[݁I܍C*]mte?ίMgOH qYA'Cypnyzx9  q4>H3mtl:l`A> ~(x)4+L=f#R>2UD"\aIbp;ubDX/,&_Ucj@jУ]ϧOU"CS oY2Ӵ,$~nX_eaM8):9<SOL G^(]wyCQp>ʋ&Qg M  9Ƭ`VjWb00+uvp*m&UO]jOᣦA0${#oaFZ!DO_paȲ +G^b<ҽYU?(MkKvU1$?<2u [dTˊ#L1Y0fnJwvv ]1*w||>v [~υ/\70:*TrC}o&W*c2FmGX׃;]Y!CSzSӄneS'1BLP"ŢZEvQ1bxSFG!IMtDBS[mu13ՕXJ7jdjCD uٝr>:wO/e6aW1;8Kw,2IBֳ7z0$K篒gKmiNiɐoGc?\`6^5'L݉^9LhBmr]"\]~ѓ?Ai~Ƅh]yڲ/̡n2!ыCUFJc+`95Nd72Wv9?:ZPw4$G viů 99roNc8 vʌqfQՌ u ζzoM6hWwL ``f؜ >-j7WEwfx8i(U(!r{\F-1:5;lI|7\cCPG@I!Q[^ŴknٱtiF`00C@m4w+haii:-&UEAyemb$)|r53wAt+ʤjk9Tl\t-rL-x0{Ct(f J8c3}`^ҪR209tgOb]!$ "z;wȖJ^9 Yt\}fN5mrZm"uhaW"26HU0SQ8lZLuQ)øT}!qyV"3҃> )L>B5S8V`ME= px^hI&,!Y 63o ͱG9Wu&YUg(Fpv֨h\a,156]úRWiYHgJ՜nNlZLLhB̈́,d4$oKNb2mqQZ_ƛ]CܐVb&.ܑ#!Mo"فW֎w䯶ݡ }nX+Y챵&@oϊBA"1j˦"Rh`lJ09y;F8=+\쵦m3ujhb'yQFJX'>w::y3?#Q\ڒeV@Z &4Yl0uޡg%֮dX&+B6X%Ǖ/ȕK̂'Ip^:s e20 |5;vy`3FHPgjZn0#/ X±Ԓ}AQLp1NPGY?P#;?5PeX(!`" ڏit&(fTh6Y)cU$YZc6_wvP5s}rI;|4Yb]h5cHxAxٞz#G;}  ,2;[37KX)CsiUvf**UO(6o$jOrUcZ64O3"li&02]N?ղI eAq*S3T:y;kBIe]2C[ IhLVӵȝi$5C$ҩfH36uB)xUÆ2daMRا0l)(3F=,c͚^dKJqOzo Mj`R(Fq:w:dW zi=K$HgjUqiW>;0N-F:SGz!YYL rjrh$n]/D^n !auB:Y{ LB%ug1+&l=zlAK) yg,7 ꂽVSǗ# U΀Iy vڡ^C߇O?*P,ٚ 泤6%ʼn2:qCPF3!, i 7(_EW5>OJxЌsCyGU]`QcJe.7**\\ HiZS\a5SP3V t]0=/[Hu"jFZ>63 نҩ aRp^ ?]`"K65sh}yqZD][AD?AO|ޜ]V]双Kr3/C}j࠮]Os>bୱë>$*h,Ϸ ӦP {`<\n:i#k*/E'ޯ+Tb`夗@e}=*>M@qy>L:ix{.S4y䊖8S6Ub@-r׀.yKX8okuC,\ř$ ӒLjL8ɳ%6h")x/-|[e `벺ʆHq?pێi:ye7RORܱ<":67?(5.)*LIx,J@%g3(6[pyM>\Qbv](M=s\\›ݜ*iϬ:y3o@_D5QA%{ qv_\lcBsVX2by̑##mc ⬃*[ϝrjZZܬZ!X$_jQy=NॵGsddaO a РDh+ }u !Dj_7͜kyp_d]N7(H_ˏ˩շMW[!uͦ 7jO/U h[cc@Ur&b?^d?'C6 %Z\h TtpE>5zӔL@ߵ*k2">hXg&N#5~(xp318Gk7 W1b6 ǒyb er⊫J!42>M)|&0sHE]H{efgv&iP?h :,#,>צRQ+xVp3 U2m+HLۆːAqv"ִ?Rm!*K:<4lP1ásἺMn噃s RmWN~8Q>慴Աy̝65%B+edå+MEuj,Grѧ+Jm6,|vhxy7$c! 'ikժJr ī`6!6)c5ue&.{KED#EVh^f~O,!rqG5GUZ̝$٥FCHzc|pw+wgj2Ǫ{:f4| :n{9q.O"R{ W~n@ֈ4Hmf#b6n0X%z. Wl+iA. ?| UMҥ#Y军\xd$oqf9;Ը;Pmȩp,;w!Җ[Hv󻰠M/r!<){dI5oX͝-\d_Mő師$+{jAI99FA% ?S|AjZ.K.Jߞ=IG|Apj< "K7bYimbmq&]QgB&I`#əqM~h+e7s@!O;K#2ᦨYB]Fʲ]Ǿm'@lܸ_Om-vDm`Fg֬]f'_f.$a`#,r£lGҷ H. 2MPIYC;[qOaYZ)!TQ/I)FJ ,Tk@';)4^e &@\w^t+ƫyn[#+pǸ^8;o ْ1݃KdD吱 .kQ4a3cPeݶ+:@`k ȪYX} .6V;8s )ۄ f6 YHfʉv"ה%X#{,;O}_ SrM<y@f1H6+aG>տ@aYRk:޾!#m淲%=jد.-a{`$lbewƏ}~gDZ6T@ƅǦᾡ7FNa?9OF?x{Sc2 XeI( \"1DRRϻGlQ_ݹXfGLit+tհWxOZ)nLQ!WeOu:DS=\K0vʲ%t Vl+CCA%W7hlh7 ,L";z-^w`Qm}l/76=&A܌^Lc 3QX96p0t\R@3d_ ~6nډny }s;w\O>ȆD5aM2xVCˣ }AAs9wLLeq~I1TU+&4#ӠLj db}d`RγɝuΜ;W?A6MCxdŬyY6n#B影 < XK3^! T>4?ҝt w CQuAK^jTG|*jk/j#Wn9=74bI,))x3J0Aoj`H[aS2?a:[ ;SgSnD؇< b$i(/2஖6z.zițǗK|Nu O(xųDR::tVǫ" rsiЗ6\wK@,bXёRNձU2=~X_%1ZMcxf靬C-$L{zcJP{SH]& endstream endobj 263 0 obj << /Length1 1642 /Length2 6875 /Length3 0 /Length 7710 /Filter /FlateDecode >> stream xڭTg8& (袗#މ>`Dt%щND.:{oEDp${;9gx}ֽֽz.vf}>Y[ '/(Ԃ9۸\\@|P[* bvvy$ hj TB@!`ʻz!ah Y~mF` 3(@RP  @ymZ@.e-C2E6nA0>ڹ @ 5-, \mu ]Hg u H0}{h .n W˭-vKB H+xUGA:`(- tunvKs0 z粁ma(W86-+ w a xH=i P4ܿo_}K`WWןh?^FAv!ۜmn{ {^Tv.@!A.<-l낀{mv-mJ Me-[wONko=]4`v53A[$bm h9߱e e`P[o/a Ea6HPo _an5Si8N Lƚ.h+ka<ѢeBל\U.#eCT1=zݻ>}0M8':]m.}۫mMb0MkM؉ӸXxG ᷹laUՒC[2ޜ7cobMz5R[}*18a͡$:1xY~~kp>Ȇsc 1߇@8o!iOdi{:/6HLd1%Q# ?F{h׶ vZVs <W2O&͡{-O3WM[0rxk+s=z3¼*:(5ggz 3r>\S2/xZE\)wpem-Րd'ejqN "T<ާvm)ݥ]Mk{Se%T2@/[M01x f wHz،JCzPyn;u}쎼tb6n9I=5r;N 5)c >`' )zՈ763KxJ7xlgm1swkŸ4+u'-vI5nrnT#=j!OHS2+!Qr6; f *lcbJ˙z ^35 E.yCtFHO-dPF#4'xG)G Eqиa3jbѬYu:q٢4EG!^@<jÚZ0rZ}s`)V5zŻY*G{ـ^M5x&3NboUqO]APwLx̏lG}]:9鏬 ~T!|kkkco^2+M,cKjVΒ>V ./tL@ ;E[ؿsanp$h[ͅDγ>O$R^`wɖiJ8g */V7<|M@x/TےN-ܪr4`l{8<_kMXy6XZ5C6o^,\0!Cr1R6I!`Mjތw^2{W?VR٬u޲KX&Wk{$1t2zU7+u^N"n1Lʿ#.;1EqniyzU4mA.`$I nO`Lt#nT K!Yga@D$'n#`DcKTSŇrWܻk֤\ZZe,́JO&Sc9^SKt5;s:Z.l`wM'OZ5œvr|ׇ$%kOPƐcm ?xVہ)nrWB'~D?f.fec';¨]7RW9ց1j~~- _B~g qtnY2ݞaR\ *YD輝'e'2ʼnJ/:9˦EIX/h"Q"~k Sf* 4#1/F(7C~- UK} o.|ŒP!ćRȮetGzZ3V m+g9e<\pj)TkV8T oi_o.|u6iv[zmU{_.Xޢjk\#TӪr ><X 9~\{80;N'ȁWv_~ WvGāMR(ܚs"1DOOՌ$mď};ß;+$4q$1)Rf~He7/n?O&`|z6E:_hE+&MN5!5v ,]qaas̖ 33U-W͛Hr ,DW,˳XoHRpfP)‘}ùʽ Ơ,i(J⾠PrT>I^NךpDˮnXej a/Pҳ{[` -9O8D\F5 )(7]1Z?[#hg"^o$Lz޺G}@Jf1n|Pƣ `: _+JoboH0yX!;ڽ&ܽ ps~щG@W*/ Qî%c'CY͟׌ƎY!{ȗJ8\Մ91iȥ(j 3g{Sۛ61g#JT4cQ e/PTKEi^C_<%/cS,[P.<їGXǯKӦyyRSǕ{;:bSSEcb!E(f\ =1:froV>@Cb3)HL X[>_&@(fb}+M~B!~rw\ru`QB$NB$NĠ~W)zBJ1a~CrS)4c<G'f<LJH<#> |p5$yiӌe73z &fHgYFsp¾"͒}z\ӡ?^FzlLD:T00&EpwZC eKS lV=(΋~Ң5`&SIi_֦UeBl;([tJlЇ0D]k/L. ьr#1)Ė`rIc9%HY/3EDG 7Y.y&mKOZKkBKrAD ; G. ?mq A&fvZ"8$l2&5{Yf.!?~+o|j裍ڊ;yi* A pT%%:k"pVI)Fg~׎pF yK8pL_^5t3ݕMdz∅=K2bBG%7KJ4&374MHM``MSmA%M pFE {B>0 ^ϪuktHa,/2}Fmwz*}T˓"<:Ӑ@SHFփ:! kH'!EZ;V1Ő>y$;}$O,u0?Q< p4K`6s< c%M}Y@&OdFjXox`ݕܯvFTÏ!^* M@RD1cm%+ĝ۽e+x$5YCnErc _O*#ڙ?ĸɂK0gcVGv^I{^=)R!+몓Q425J="[fџT|TiO&'^{t'DQ8R[vm&ywG[|͏5`3+Ad6~m/C=7i?. UxAgiߔt]*[-Ӥ~r7g,nU{" DwdC u3 { ^ /0JzKkRzh5{2ﴠdko57),o.4~J'=~|e$\'Ϗ^:EMGWQ7>NkcoHf?0!&)pY=މPdBXݬŲ\qAf =m/s)ܯJ^ FoYdGVbgtRZH]Rmlj&쉧1[Beq9"' m0ZI`sFX`O-IWMVFYμz^qj%DJ\NS4FRXW/xP1^V`؋;bckzz'[0(#G!nj{0-WfڏIg ®_ )(qM<=(7H>G-&}ɺS?y)c<ڪ 6nq'/ x.M$zX+pdio$1tɸp?^Z^6; OqM\yp/Kѭo[]P|6'z9 wĆwE7;R[EGnvbWCW%ɚ:E wQ`٠Ʊ}ows, ً ,K➭>sf)/O2IL){Y;*xLf)$JMB;8!٣[奙"{"/V%yUZ׭/_^|v}~Ԡ'<+Uh,$X$ 8161p͞R?,^!Xl"yk !:H5R 9a!-̐lgGT3q\^P5xEjg+,uo/l*ܳtv wtϱ;K,VEn# OisA,Oɋ 0}g9mg)vM<wf{GuwoNPrs]'NW}`ҳX\䅲ieNsL?>YOn$ endstream endobj 265 0 obj << /Length1 1630 /Length2 19286 /Length3 0 /Length 20127 /Filter /FlateDecode >> stream xڬctfm&vvŶmFŶm۩b۶mUSc?cM]׼'2 == +௞ LN@ bj `f0qqq<,-\JT44`Ζv?n6v.!MM.3KS8R\N njgdhPp54X9R6v&LK`pv05fal`dk` 0w2s;{?՛ 'm],\*N Cr;[5zҿlaZ] -..22X:;z_e:[ڙg'SsC'Sg0 _7tpWg .Φ6f0LsmniϮHڙ7quӿDP-`bj g7%e>(o!7r+G#}ZFC;;shl 16nr`."hgFz+-,=LM,]-f6g/_n5V#XX[CۿMv&t~1!9AQ́EpQt[F  {~1s9q1oR ?eYC'K߾S/0v&mƮNNI{SSSce{c` z̼I^&&BZ]*_?=>F{1l(zRM |H s2g\GYbgT;ڛTT+uʟĭ81J}ygᡞ;C\8h2nCLߔsdO&/77VZ$Uw/eWBҧ]T+oAFe8iPXD>Zq)eɋUFY\ǿIٶ($BL$925բxg8XpD*Jb~@vը4\( Z0G>:0 hZR_D?C)Un^OoBs> cyCزE#Z2!EG;]-~`tgӰDP44_\/k'¢QЯ_Q:UBY=YV}r7~ՂqPHkءz1'}sF3Z Fo(,mƗHQ[8=?MHw5?*v(r2ho7t.`)s%:M3nF֣Ƶ`*S|]Ryn*2ي2d4=5&$UC~%29"5lH! jHnAhLO ,@ G $bbTHK`%,}E|u_DyWkV;g};K ֽhA s>+hKbC$žQ;p\193ܶ#PEv*at=)NzJ:n.3&M mUm-Oz󩫀?9jZ&(ՌDX Y _:ĆeO@%e4䈕O^N* X^TV;>lSUI5̪L܅oqoYST,L>2 cVx8Q,l4l6Ik"vGy<Ł3aפ6I2A*PrV[4w/aJ BM%.o/k* +مLzWRsJT s. Fh":꩙3]Ú1K4Uۥ3Z<@0 ͪS 6c^ݭH~yK̢ϙ?jO Yi J&yazr ڼLG͞t(v!p!MeJYHS^LyUW.2@•bUz;[c՜i1)l`PnP $"h}3ͨ6$N9i-ɐ^/¾|bN?yU2%(XaiB-,f2٫8FK/%!(N [c.YUe(5I||M633-2Ξ(y6ޘ;>vЩGMT$Ky7)˼Yvd/DVS~օ `:&M΢GRB?΋ġ>p0<|3i֊sf/YZ5:؋70+]zтHKVO!(nCrwrY6ر}R "2O Lf >nϿ2W#I}Z7z_2ajuҒEO*e]ap=99lL*?jMCN+"&(ԆϤ;{wut3h|,8lO9 0ҝso,bqa*I!XQ7`A'bXv8ESxz>C9N_"l=Zk"6N P]j_ONa=3S4; V'ss|H}01o62d\.^ OA2х)N63?)U$L=[ }{/ EN2yYԔp +•"-dny,?u_3cE䦸Y VnA; C3 :@.sٙ@$:,u#6wcuƗ%I@e3t7/GS?߰H&Z~V';o?n(_҄)N,E+e. MVcNbQu,'G39^}a9 FoĽ+t$to=,&Z:Wʲڂ^:J| : ^ߜI1aYUK0eЄ} ]%*hέF$;eK4[zȲ8 S']f+'M:V28>ĔE>Ơ?Q)$*yߏ]%jXa=kÌ3[K82҈.|XsD~&{d:{P"xb7N洍GKNsʖ\#*oHfWl/0KŅK^% %hZR\L.שLA0oPӃaaym(Wid!ۉB$,`fS&ko}>gjfSqB+d~s/O0"Ә:ұb\sT\VMR')(uL9oӶI98{.Z!sdJc/ssЛ EV}<-9{_Jӱ~D TGf(|NE>O߲WVu.^]WIɇ1᪕$-vqkZHy 쀉(G ''-e>M}$#"h;oqѦe nUyv,_yk|UwV ]h)uGguWEg~u*e2 &8$:O\qu"dǿ6ŵ)w IAtY%$d~ +yU$]v#G'Z*=ǭEпy1(+U.gcTle9t¥1f^s5cy΅iY/knlǥ"$ũU7dN#rߠS?7,o$qW5āqrx}@]ԹKǓAs Z{r \u9.q曓xF<mfDB tMbRwRpPJ7?6NjO̚ܧ"5vkM̖v|*@v3n.nfIym͋MӁu Ze /kҷ(HUMlS`r#x}+й}vڅz1#`} W#^Ԟ;Z/CsxBĴU8ـ}>U`6Z`? Gcxe1F_̮Bi?yx}?Ƕz$I4)3>17ݸ:JÃkӥhJd(XW,]K#QfjbH,pېebD=*jtxcΡ̊mQ5fYQ{JNˢOAXb\o O ߖ8/N:̵)y;3fx{4vΌ_`V|'5{miGmZ)Fb:FO)+G"<1hsK6T=^48p޹Q/*@|f߳h{F(+_ٌ0X%@;x?5 gS”/Fy"lH/@X/zXIFB“_K8ZD `LjPI&il w\ǀ>QxcZƄ8R G1Hbec>VY6YF"WGS&`ot,qkSLUEV "-DTyLKrqn];J:rКfH<kuDr9iUwkDrpWgioqM|9QYB6 40>U=J|+n~CU(A2>/@ :PC~DHXpD0X~PBAz(ѠyU\0QA_k><>3ގ=˺ rzs~T$kT{1yX!+`//p>N ;$ik7݀Jbfu' YsPVs 9uג*GMV!o@JAY6<  ~&kA.G#?])̺YL`>2S}?Mmۜe 芙poޥY\_;TA /!W} q} <-SG,ꭾ i01=:ִxIͩXӅ҃~(Xx>J}*uLZթI@5h:h&tňDh .2 d?f#QFLk-Walj=7\‘ނ,qʒ1 - ~Hz輵 652hB#Μ<Y"t,{z۹SºW2_ DXKI?Yo\fZ2Le͢>*z K6A~ ; o.e +&G~++hPF<Tӓ/sٮu[[%&4o!䨡j,">Rh"@iC*ZxsZD02&vol8h1rewDbM{ !YϡxTHbVCԍNZNi=rBډt6[ )T |kS /9Sk$캄f㒟:R.ÛNM *EYaTPR^xQptHVx?C˻ϋ3緢la\r0pV(QChxh@X%|e*EP/@bpܬΉr-7>gn]vsLm{QdYjE:7Ihykn&ư9e15_FsdI^t.Ԝ Pi}犦3{dWkPdEr`dtOw;C&hg /E8 ?I(h1oMF`Co^6 s Ih׎R{\ku;J+YND ]dWцQQ?7w=aj&1!hm&pz;J5RHƃmXUM,tGV9 v"d[In}2 Z5 pT+ŚfMmRBSx(=a?0bE(-q9k(Il!Ȅ?' atgB4TX]gAdOܱq€U1ʀSZ0B8Y [ۃ7:wJ-fe e1㪨AWm̴鶵YE}31|cOp(J}+(/Y4bj"N9!3?B@vRdm"~<Yɢ>O< M4ܻhPu &MФO:#'t~`'>ʮS΂PI?6 /tc+X6>'siOQ]h) Vв`C+$1L~,B|K;d=J ekۺx8Ŗ$jkX#bs$uJ,|:ja" ֘@4W5.}PCu" uo܌R_1=EM*haw*SApc9͇þ[+[\]RUp1Vd7%7фl8lq?&5i%ܓq:&:oUDǂ"W@}d~q6d>[^HAQ&e%;e6"Glh $ P8 Mu=z!y\7͂ |τܼu1|YOCʛTM{ :^ $þQWԩ'>p{Phr#af,n~(p-=za[ u8s*<(, q-OQ/:rR 9i7c`ǟk\3 )BA{~Dl.."q2G*gp& iߺݦ(11-.3̨S~ q2 UzPĨGM@YC85 Pq'pd:'(qw~ zˎby*M?81Wae vl$}$^h_C_^j*4i:A#G_44Ź1'*:g%  j Pʓ+` G~(gU\Z7}%Sɾr__6Α:mu[xW,˅;\ WI92"[V`,hOADX<9 ra,(J>/Pˇ[9mTzѨ;dcx8sI0?p⁾2k짅iz6=_˵SY%"*:C @z`o9ѧovӇio L 0 BX3k5D;5Kn[&i$Q@G#RB)iڃ#SY7ĞQ\uhM<}dz,&m=O^:69GD3+zmUz޷CwU%7rZ,CET_*z?lb)c@f>[\K%V=J;ݏxN$#pZ (~T5N,h+!2 I*43^%]zXS.ĭ(|A}O:ԇD5 W7`yld;w{y8۶Euh32f/Iwӏr.lٖ c<4nn>DlUF|7c NiO Ȩk-U5"HrQ)1 DS#ijCZ3Յ1pOzIfnAL6_f&#d<:{A{.XNqMR&2O|1-bDS.[n0N@I1s%:ѲTy_̊0WK.ogˁz|F&+#yrǤ`Zဪ6LV6|ZɕL77 jck}dਧ|ߤ:Rk#H6 ,@ٍe`aQj%*(?憠6P ݦ۵tUlNZ{&jΊA85*ͻ5SC^+ߢRAhbD#Z&h?|Kev29sHR+z;xc]'#l1Q"yj6&S ua=qO5~Y5K(=@ ( ʰk^Yv/_J-jdhB:]XI=,[!~AȎ>xzOq׆`G<к M.ki];$bTļe*ɑ:KHek'/FGm@P{hv(-F6 !%xjþwv,RGQqqgX鸲m\_qv8z9| D§X_z" >$ ɠjͰ&!h]Pf*<"*'I˲"NmHrll(l%ݟwBUKW `mse%v&Ik'Y?PO7P6pm XBYT3 ɗ6^f!Fbp@\ti+%[)ɶ 4;e~7/QFAdVۓRǨvL3skHT$FLIr ]J)boD+6Q} >;QǏnsx!]EנKUi@[LY>SPޟev Hiir{mg 06n 3q1뻻GoƵ w+Kfq᝼a܁yTAAGHJlWoF%:׾wx6⢒ ͼܥI=ky9!218b̐S,==yU`g, z z.;(jzV-'2$]w"mFxc,IXo^7,}%nXY6 Su}LUUH wCh9P4T9>{?M W늆Abhe/|cc<)[(. ?\ ?}&4|GdgJG1p]UTtq|EOwe-T Kie&0B |X&+*~je;qcvSVr B-߶jmt} 6>0Ѱ&/z c(Q`aY6VS}U83}‡aM«H%ɣ5u y*/Rpql(8snjL|h(4 a}caq Zźon:m|2f߻GʺO/N^p}Z!!4'pnT_n+۶SF?< Ԑ._>!煓X>;&VEPTloZǝFUUa2ʙ}&w0`@G$2hÅDJ9%Yk.d?dt+‹Gqrsuj-Ow=I'\ aI?78EFGDJ*77֐X¾`"B#hut%B"`eԗZژp^-E|?jC]wMw f"m`b[ຬ10IrkBuMftJ" ,qHuy6crkńPt߀CQ5Yme|(?qDCkq!ԙI)b16M`,h#Yfr$\Uia">*۴;_p B6/ xm y3v0oJo)6趢Ioہ(ȟ$Ȣ-@4Y#kBg ZfHܑQT)9i#=3?C35#]1ZQS\- Sҹ$'E+mUytQth X+` EQ .vu]@\,4 pݮp]Ea?*e <+_S +*KO3u(*J'Z\1ʐ#٫ċF++W{-ݺzZw$y`d.Ve'$x*7JfwJ2Յe 睕\\0e S2c0KltqRY ,q4#1kAk\`)-(" GI7p(2fɘ/ Ԡ늢&3VC'M&ftRs;=j/IM gA1 ^POZH>󢧉O#@} RxqRã)z(RV;&ꎷ95YA@JHT(U Qq#}h mPHY̾ƍjG.|'iTlcE9'v`E4ohӦxGWB;ƓS7(" ;#Qy@G)K"8odo1W~CWՑ|G.'Ј<( xBm&N3ִ/2{p k"J]i(@2ͮIʩ7HSh3;G#6):ʳ 1.Pz=6ZO]US$ޗlftY{ ̭ /U.|%㐱 tYsI>!( Lߦs4Ops呀fY| VJ2J{u[~]Z-9g1G7,Lq@t@6FqH4{&SSBRUoC=ileÁ0HqlK(VUyع{"U/xS7F.F,%mP-J;SqՌ-Srx[G5yݔAT[|x2kW`puTta `OehsyTۃe_)HGxRpwKqm965r*IwǢT;1!~'Oykӷg}9[%+eÑ.WZSDiVZâ7NA<8#] W} H>wCfB:6*v;q.O7hO%䚺nz7xK.pCMjDN! *s\M&qM==pytv4d1Ugc#8p[^g3_6Ք]ZM!+[4o!Ov]j))1K68Q4N.Ud jM1V G/tb,zj4lye>zRZ:E&Yyg(flV yj鎑+/4qNoR!9QZ~c/Te]xN9^Y !af79\9W}#t5ϭlzO\;`2Y5٧!Ti|)]k޲B ؤ6J%⫦~W{_;^5ŝo#,|3%L2q-.|yC+bUj3u*:Vl^ kA3GڃYcDQ¯y9)(Z~M%G@+_30,y%;6#~Ĕ@a&t](N:>Umڿ^Q /ٲfC[:})'}M~Ema)3%^>K!VDR2ֱ:=5 MMshQ#U9:~\~Wto9ɝ`/SN3ƭth],p $F,@ėhSwG۸[M.#:mǀqp}3I!+8S15 ěܚ\5:O,F|M'~ 9+aVnzN )s\ ]cDhg3ߖlMa"I8k] j_/dm|<FN +;ǟb\Rf%x \u WZO {/,5oH qR/Ku| .Py ž4 2bόnm5mۻre^lb5B‹5oUD^?Ƚ>oBAjRn60i8JZC& ( XRK_86b#!c2{ƫQ6q $^G2{P)g<5aq)rB-mSe!A> stream xڭUy!8a `555vQ@ǣD@ARJJO͓Bb1ڇy1DhD8@ှ ada1p< XyQPcpIP{di\pp(q{4P@$!z@(  KfG`ᱴ^4Ff% P< GhQ IbP4"h7aX^I!(  { E!427A4#!xN hh{N_ph}o?r@ p4B,O %b#QvY1 $73$ 0,v9 ,TD$[[FWjCo4E;-[4h| ^(mt Bk.IFFMVQ@ Q~p4ov; G0pd _0['o d59::[JAӆ Ŋ6D[x?{zzX? P ȫi'>.dA 0t(7H6DF? {0Ih p?8}h BJ%=l0|67'[w3Θڳ+۲e];_MNKق7NK6UHMʹ>L]p gYd?5q5oEZdigq\A%^r.z4 8c]MsS7Rl'WMBAsBD;o3kqcG ]]I΀{RD8G|=-i6n[S& hxPeF)sFwx%tH 0c{*wE's*'EkqEuǺVoئ.Xi>bOF^8] ?~`:_1N{BCHjAOҤ2+W>TSr^)WJ̫2qVf'EflZqYA~qSʤ/E^{&^LRH"_y'|8=ӻǗqnw=r=[BLGl;j. =]7O؎:h]N?sli\<À_1{(x-JA P[u68rsf9qQe!uqLe"FC*j*Ŧb.;א}Eaopɜ3}yEŔt}\i)Uey2j9̰QAQWF ~)w.ϰw.mDž9o@bځ\~ $*XKxtW1CmQY.ɂro`:%R*9Ut67}HBc7JZ# J=~b0Zm:1%htKMÚs)s F3C̙TRivg2fQX'Izzxf=7^Z%.j*{9qxAWUduЬ?c2ٴuBp[Y~lVE% xy4ާB..D-%:Ys Y #]I`0цTljk_* Dtrfp2F|٘־G e9>_K- fOJ. @lVF>xjÅS142t}aYQE'Wr&oYÙa:ݵڙOSt'"MoY &zL1+k[bJ6e~v<Qhۆ]WAF=#xf;<-lz=SIe{ 2CN\B[lq_GK_S^ӱuSOe'Pu<5#LEg#7[/YڭX5 N1vɣ]}m1ny9qk.ހ8 :m@8XH 4Mtuq mYmw ?R:N#b]*Y-D#,ዮW`>5äI@Q"S8yS1Xˠ+gSK>|Gc'$e9`IEF=v+cƧYh!,*8C"n S632,HG4_:z9W W/O&KБщc'Ƕc܅)jm N򲢏v}(aрYBVArC.2:eݛߴCM4Po]*| b‰ןS6_}?mWOUÌ3ωR:ʓu)7a)_p~ 1>F"߰q:^{l4FzAd=2Ir$6"Ć$qmN̜uVEar=qWaFkٱbf׮X#-|e#qL;ȞX o.HUq7a.~7L*.?YOuɘnh>4["NFh_8{'}g/J숻a$-"#BW0*7^z(%K-K>a8J<=I4 Qrús.l}yv4q.>zuŤGԚ/_*5o<IY??"ru7VէGwJD&pncxPDy=nh 7Ky%'^piVS]Gߍm֡j#WW7=pE,ծSWaSU3hu*5PR( _{6*%nWn G^)hugi dI0Q^/;'3V1/5.T?ˎ {v)~ۭBͤh;GjPnn+Xne>Wvu2i^F'C'K-'p_ 0l'+7Vty{p,=Ҟg+glZ+V&WZwT?=.TCsK([[@ W+(M6Ё] l>IAˍl_T8|yR(V'G񄏯^> g2!Ee7"/ 8>pGfGEN_Mҡ猈i^*Hdċ‘1<\u['xCn,@]m>(]ȝĥw(Ew38%|Ǫǰyu<ޅ߁O8Ik|6+b/!&Daܼ2޶PeQ3, 9A*ؠlLGpo,3/)zO/ڽ^NMSHS߲L 5 VrAcJׅEA6LF*X XX8WcB|OiK{.++_3)]Ǘ tA﬑-(I紙6iSnUf¿jqqAΕl_|\8qǯ$9ՅnRqJ-.d,~a\œ4sV= m>d1}7,Od[HBչ%:9 endstream endobj 269 0 obj << /Length1 1647 /Length2 11050 /Length3 0 /Length 11902 /Filter /FlateDecode >> stream xڭveX\.wwXn<  ww3gs;?[VW)PP3u:):3-]d&wJhv7Z@s8 `E98z8[[Z4Z 0'n |zp:8cC5 ,m1%eE)@ ht~OB omifbzL G p:Y@k~`_-]{'SvAf֎`Weq 2d,5\JoXۃ`;/_@5;a-hiln i޹ /ٛ8:zm` m-X}}[Z#1/2V] z=s{[9Y@?2^JRk_wZVgk򀿖3௅cmYzwG?\[Wbk;\lf0}@g[k{{w#ԭ;U @@{ng-*Clۿ߻'-%Q w^vg"R$%=o^a]]P^\(Sj=Ѵ_닦ꗬX<n)_%k(bB.w{oXe5;\n~daO?q22j\Q]!@VuQi:%Nȝ&/?|Ju;.0>aDxD~w,Zf,t\RTnu\g-3+k۰O%}3kSUuz~i2dp%YbSVLEU"@?KfF,M XEȴ~b!pZ=A؜N! *\xt, $avd/^3>ɟy!><N32'AZzN[Q#JRu02\P+e&v7 O?x(qM ^9n7(]Յ}$IqyXK5K٨@,>>^H'U֧Cuq.)]eCX;i#e|g,/S}~{/_)3 bGKkp.qpMgG%˞j<.#7r!EC#Hq;\DV oj@:1.W!97j 'ϐnDFR̊wa^h徑v4r#q)]oNk`IrKm/[0k{Lcisv˟lR99ba\(hsiy)޴lF1=ݐ!ÅA|Ru)%t p /Չtꀫ[I 5 ?O5f9 a1Ic.p;9[+鎌)sn $gB)B}W?ƼA|F{Oovĕ< gj$f rC-iz8ewdP{1iAJpbۘjӞz6PeRG[sKWv9, 3!5إ j<rJ3gmivmo] Y -N%vq|M`_~Dk\ /W#q[9:n rܷ>}?$HW4FmBqDb=vW!;;dOoiQh.QUǵJ_txbʢMZLG$ҾJ슅/pR\6k0鷢vqfh8tDE3(7]BL{ ;zX jۏ1E$>A.vS AMFa{ARZC8sX@O˼u,XBηp_Аkyl:h;[|Go;(C!HY?awZB%#S:\mאz2;"Q>X"Ԙ(:hn5cW<ب{~!948'BTmiÖ0Ur#t^Y12"J#dD)ub3G>难5%ۯ^@ +I>X<`yWbOL@w4tw~4YIUb+y*1%E2izV6 <#O@ GǛOsg nP NzI ۈ4׬Vrt‰>\{QJk5+6k͏ERfkNh*ՍaaQo<2k6LS߽>? %/v{ ʖљ``s[>,7(D 5wl E"gZK =D ksx%)c`s$$)nzTr#s"gc|!Opqe8VA:%2!稭E)O^EX(Um]%E$tٳyh9z9라`)M$\e yS2XAKhMj]G =OWC=Nda}xC]%gDIt NA$M3:tޑk:^!eD~gpn΍>yKD헏`::agY7AR~e,vQ,DǹerUX׋DQ.ˍhtB O)|~Ltp}JS Մ{'C.xm4e9lu'mIn9V]/^(\pl\BOYD1eoC>z[TXlvC/Ny݈mW6*W9S)kUZγn&LDUl*ʆb *m`bQBaѽuSԜ~VTlE-2C,^NB2;:3AQ`0+0'" {2 N Onr򂕖eh<3cC2WoV{tab W4lJy|+[}C3Ӄ4ySt$+~glvMwXczpG=p. M}pwN:NhUXqzŰg vcM?g3/%lH;ɣSV M4g /3UALfCJ'L J@ܹxPdʈF3%tնbpb瘂kT\(0t ;ZQ\f!AL5:l9*Vn}<]^ewJc`R;Wt`KSE/6k*yEΪ]ʖbloMԺ GB)}k~~vTp o%q{MRlpQM+=lfY1[#Zc7 5lE%ޡ540΂WBx,9auyYQhp &,`rG+`yut˖oVJ2p Bp"NKa|m3?CvПU (xYƱJv|⺽dKK`(ulھŵW6wYw-iTrNI4iŧ;HaONzue5}?&҈ ]stXC}:>驙PL'6s?)~ηȊ;F20*)dY1Է3~gSpڕn@;T:隭t|>gu 3Nո{(fSR*F xۧ'O.JO׀+eJefp'w>0by}N۟خߞ^4_/ɪ0 Zr@-e >VgkQS]Y]pͱ>jOD:P.nOfC$!!{doثevݺ;ISL\N5Ly$uD-~Zo kW=pc!b+p|o/1)`@ƭUv:7iڔ4'A:?'5d젔v0!S 1N켭;ϳ%/LX{*li%H%+z3nď`x$C_5,#ZG>3%B ڟ5t0ܷׄt; ׂSʑ1>1]ch9iFpHy=+oUƍc?d*NWkʖ`,-/q1秭M/WR<&Df*:X 1LOjʶ83.sw̮1}mwG\%l wA88ﱍV^.еʄzٰzl #u.FF~%KzCww:T}Qg;7f LLX)5do s 덱:>˟Ӱhk{;r;E!XG]=JVy2h!Ռ*V1j*@f35NmH>h3c>:TBaÊ=2@5Vxtunyah8׸aluw˝7ycRfPjbo#z` = j%h@+? h3 ?x,eDb,cCY!n׭|#G{7y.\{;@8qZNz-Jsrq@©lh~bH_4ŸC4J{K(t&h l)+E 3Z3H}, Sl\6XJ_nart q4va"ʽHA4=V;\']ORJ_n4c0,|&raQ!Q̯)Y[$wnMxAD }^xSȆ2F,N5@\M fcnkخ<_9QE`Z$~,ol"tE +&C/e~~hM~r9m@B <4엫RF?ϡ 1;m'C e&GL6/Zm/AP=Kq7)4xP|Ly6N=_I\(͕$!k}޲=`~@ˀjPow&1?%VYq_K!dT1!X} q@`Z iuV-R];'΅= MF~"]CKßb/i(,=jESCgeCʗ"VU:BF}+ u q%I/`e춰 G\ pZudk|c40;5«!>_lKi>gLgY Dް|hQ# R&=| 轠$ITR݂Ǜ틫)SY 3>.ĝE6Ba5!N>_ Cp~;1Hvcs n?Faeo@"'Z+? 磼h~YŪ6.51qI;,"6s#_2孇}]49ڀ7BQeetWQ@#v٬ctT¯=M}pbPn GMf`_}1E9=lYI ,4bC$;sA;=#QmP-uHPuQYd10(e9k5dv.4_!' 2Io¾D,;N)Wx"ƥѹ_?qyfNIBUc20mֆ?!D%?(HjT{؇+eYՇ7_%I0+"pC Iۢe7~[^:}a- =R~=w, y܎SVᗅ9 2G%].1,{ɱh '5-[sƇ% h5|-jDFe:KVC̄3ۣ]w=Kz38Z|H39+ e*V٠[]\eh$TofWq_91A^qJAFڕ8x2?BSpA'jߺgT^*6-EE<8-Ng. Aws8@3u%Aw@dW3to:KKʂJY^d5@7iv'kEVkVRukBlЮ 0cE{d|ҨÂOK[} -K19;9>VIZNvY 0_TeIӡk=m3HD6#c?<>:DlW"rqxdR&> endobj 201 0 obj << /Type /ObjStm /N 73 /First 658 /Length 3437 /Filter /FlateDecode >> stream x[[s۶~ׯ{6/qvSmf%c 4%Ö>ɱceAF  j(v^˿ B?=Nd1'dz^̧~1~Nw0B>uWX];@i$,1P&^z,Pw4`[v 6fE 1ŗ.yHb`D%L o~+q18 w dui@mO٪Ґ y¦JcoCCY~7Z+Z-W_|oV~` ,Yni̸/JUnZcT+( \- _uB{3ϸ.6iXQƃ^L *acEcZx8X獱5ChQyXE>A >L?a,yi\5/=TP%m/A 픊3U18,# Pe8;0]WmTWAP.Q ]t4C1C\7ּ73@QqZ7qNG~/&Hl87)N kJ:/9AZ:t4@x[b>=` bz O!=1}CwSzFO^K3~WzߋEj AR(?Qax>P{:鈎N.#Eп?p]d¥8_HaxyFkFpY GwYբ:ތh^}Uľir7M1IT&w+]]7 5c42v{mAhrEYYM+'e-2˯2=owBl1E X `wg>.m .%ܦڸM<ߢ;Tħ6.ǧvoSD4Nwʭn;2|l'U.7&_,잃X.z,Wy?'l?b&+Lb&1~H,-H|"iD/$6 ~8'N}f|d}P$'uՎ-r4NרdDND&ݤIMxm]wIg_' <051A2E0BF47F41A7D14CF8893FADE378>] /Length 820 /Filter /FlateDecode >> stream x%MlUg1{}wgQxOR|*P)-R]Xh4Q.&Ot+uA(Ƙ#.T1aBsܹ,a0+Y؆xj!XZXGfFzhC^WvвDV[H`s- 4j=5QVVs(ͽ~ƀNvOC0Ҹ"E0 u ]MԍUȝد2b)5C~_fb9r Df J+(w onF?RhA1ߖNhц?dQjL@Y5Ud(2!Xh:DlDtvJb32D3\DWy?M&u.DoʹT{؂hUJ<6mꃛ\,;ɵ~Ab 1dwp>L3]^ ˚M]ySst/{pwC#b?͓p" #m?L{x qaFNS-ljcfeO#~ 'Nc8xEloO*Ne _^p]0>@|kYf"y[qHv>'?gCwNy$zUc}Y7 9F""i_&dO f/!K`rɩo?ID5$W/J"[ 3R,tW#}ZЯAzC H'ՎJrTj*O>#秥5wp~Of~y2j endstream endobj startxref 1553463 %%EOF nip2-8.7.1/doc/html/0000755000175000017500000000000013414613100011102 500000000000000nip2-8.7.1/doc/html/nipguideli1.html0000644000175000017500000002756413414613100014140 00000000000000 Contents

Contents

1 Getting started
2 Tutorial
 2.1 Quick interface tour
 2.2 nip2 for reflectogram mosaics
 2.3 nip2 for nerds
3 Assembling infrared mosaics
 3.1 Infrared imaging
  3.1.1 Setting up your system
  3.1.2 Capturing the data
  3.1.3 Correcting illumination
  3.1.4 Correcting with the command-line tool
  3.1.5 Correcting within nip2
 3.2 Assembling the mosaic
 3.3 Balancing the mosaic
 3.4 Other nip2 features useful for reflectograms
 3.5 Printing
4 Reference
 4.1 Image view window
 4.2 File select dialogs
 4.3 Image processing window
  4.3.1 Columns
  4.3.2 Rows
  4.3.3 Applying operations to objects
  4.3.4 Batch processing
  4.3.5 Error handling
  4.3.6 Making menu items out of columns
 4.4 The programming window
 4.5 Command-line interface
  4.5.1 Using expression mode
  4.5.2 Using script mode
  4.5.3 Using –set
  4.5.4 Other modes
5 Image processing menus
 5.1 Colour
 5.2 Filter
 5.3 Histogram
 5.4 Image
 5.5 Math
 5.6 Matrix
 5.7 Object
 5.8 Tasks
  5.8.1 Capture
  5.8.2 Mosaic
  5.8.3 Picture Frame
  5.8.4 Print
6 Programming
 6.1 Load and save
 6.2 Using an external editor
 6.3 Syntax
 6.4 Naming conventions
 6.5 Evaluation
 6.6 Operators
  6.6.1 The real type
  6.6.2 The complex type
  6.6.3 The character type
  6.6.4 The boolean type
  6.6.5 The list type
  6.6.6 The function type
  6.6.7 The image type
 6.7 Lists and recursion
 6.8 Lazy programming
 6.9 Pattern matching
 6.10 The standard libraries
 6.11 Classes
  6.11.1 Parameterised classes
  6.11.2 Inheritance
  6.11.3 Minor class features
 6.12 Controlling the interface
  6.12.1 Tools and toolkits
  6.12.2 Workspaces
  6.12.3 The Image class
  6.12.4 The Colour class
 6.13 The _Object class
 6.14 Optimisation
 6.15 Calling VIPS functions
A Configuration
  A.0.1 Calculation
  A.0.2 Image display
  A.0.3 Other options

nip2-8.7.1/doc/html/nipguidese28.html0000644000175000017500000006250213414613100014223 00000000000000 Lists and recursion

6.7 Lists and recursion

Functional programming languages do not have variables, assignment or iteration. You can achieve the same effects using just lists and recursion.

There are two main sorts of recursion over lists. The first is called mapping: a function is applied to each element of a list, producing a new list in which each element has been transformed.

map fn [a,b,c] == [fn a, fn b, fn c]

The second main sort of recursion is called folding: a list is turned into a single value by joining pairs of elements together with a function and a start value.

foldr fn start [a,b .. c] ==  
  (fn a (fn b (.. (fn c start))))

(The function is called foldr as it folds the list up right-to-left. There is an analogous function called foldl which folds a list up left-to-right, but because of the way lists work, it is much slower and should be avoided if possible.)

map is defined in the standard list library for you:

/⋆ map fn l: map function fn over list l  
 ⋆/  
 
map fn l  
  = [], l == []  
  = fn (hd l) : map fn (tl l)

So, for example, you could use map like this:

map (add 2) [1..5] == [3,4,5,6,7,8]

foldr is defined in the standard list library for you:

/⋆ foldr fn st l: fold up list l,  
 ⋆ right to left with function fn and  
 ⋆ start value st  
 ⋆/  
 
foldr fn st l  
  = st, l == []  
  = fn (hd l) (foldr fn st (tl l))

So, for example, you could use foldr like this:

foldr add 0 [1..5] == 15

(Mathematically, foldr is the more basic operation. You can write map in terms of foldr, but you can’t write foldr in terms of map.)

Unconstrained recursion over lists can be very hard to understand, rather like goto in an imperative language. It’s much better to use a combination of map and foldr if you possibly can.

The toolkit _list contains definitions of most of the standard list-processing functions. These are listed in Table 6.3. Check the source for detailed comments.




Name Description


all l and all the elements of list l together
any l or all the elements of list l together
concat l join a list of lists together
drop n l drop the first n elements from list l
dropwhile fn l drop while fn is true
extract n l extract element n from list l
filter fn l all elements of l for which fn holds
foldl fn st l fold list l left-to-right with fn and st
foldl1 fn l like foldl, but use the first element of the list as the start value
foldr fn st l fold list l right-to-left with fn and st
foldr1 fn l like foldr, but use the first element of the list as the start value
index fn l search list l for index of first element matching predicate fn
init l remove last element of list l
iterate f x repeatedly apply f to x
last l return the last element of list l
len l find length of list l
limit l find the first element of list l equal to its predecessor
map fn l map function fn over list l
map2 fn l1 l2 map 2-ary function fn over lists l1 and l2
map3 fn l1 l2 l3map 3-ary function fn over lists l1, l2 and l3
member l x true if x is a member of list l
mkset l remove duplicates from list l
postfix l r add element r to the end of list l
product l product of list l
repeat x make an infinite list of xes
replicate n x make n copies of x in a list
reverse l reverse list l
scan fn st l apply (foldr fn r) to every initial segment of list l
sort l sort list l into ascending order
sortc fn l sort list l into order by using a comparison function
sortpl pl l sort list l by predicate list pl
sortr l sort list l into descending order
split fn l break list l into sections separated by predicate fn
splits fn l break list l into single sections separated by predicate fn
splitpl pl l break list l up by predicate list pl
split_lines n l break list l into lines of length n
sum l sum list l
take n l take the first n elements from list l
takewhile fn l take from the front of l while fn holds
zip2 l1 l2 zip two lists together
zip3 l1 l2 l3 zip three lists together



Table 6.3: Functions in the standard list-processing toolkit


nip2-8.7.1/doc/html/nipguidese35.html0000644000175000017500000000705413414613100014222 00000000000000 Optimisation

6.14 Optimisation

nip2 performs three useful optimisations on expressions. First, it finds and removes common sub-expressions in functions. So for example:

if a + b < 12 then a + b else b

will only evaluate a + b once. This can save a lot of time if a or b is a large image.

Second, nip2 detects arithmetic operations on unsigned char images, and replaces them with look-up tables. For example:

a = vips_image "campin.v"  
b = a ⋆ (a - 1) ⋆⋆ 0.5

Provided campin.v is an 8 bit image image, this expression will evaluate with a single call to im_maplut().

Finally, nip2 has a VIPS operation cache. It memorises the arguments to the last few hundred calls to VIPS, and the result each call gave. Before calling VIPS again, it checks to see if there is a previous call with the same arguments and if there is, uses the result it obtained last time.

nip2-8.7.1/doc/html/nipguidech2.html0000644000175000017500000000450613414613100014116 00000000000000 2 Tutorial

Chapter 2
Tutorial

This chapter runs very quickly through how to use nip2’s user-interface. See Chapter 4 if you want more details on how the different bits work.

nip2-8.7.1/doc/html/nipguidese27.html0000644000175000017500000012146713414613100014230 00000000000000 Operators

6.6 Operators

nip2’s expression syntax is almost exactly the same as C, with a few small changes. Table 6.2 lists all of nip2’s operators in order of increasing precedence. If you’ve used C, the differences are:

  • C’s ?: operator becomes if-then-else, see above
  • Like almost every functional language, nip2 uses square brackets for list constants (see 6.6.5), so to index a list, nip2 uses ?
  • nip2 adds @ for function composition, see 6.6.6
  • The : operator is infix list cons, see 6.7
  • The ++ operator becomes an infix concatenation operator, becomes list difference. Again, see 6.6.5

The only slightly tricky point is that function application binds very tightly (only list index and class project bind more tightly). So the expression:

jim = fred 2 + 3

binds as:

jim = (fred 2) + 3

This is almost always the behaviour you want.

There are two special equality tests: === and !==. These test for pointer equality, that is, they return true if their arguments refer to the same object. These are occasionally useful for writing interactive functions.





OperatorAssociativityDescription



if then elseRight If-then-else construct
= Left Form name/value pair
|| Left Logical or
&& Left Logical and
@ Function composition (see 6.6.6)
| Left Bitwise or
^  Left Bitwise exclusive or
& Left Bitwise and



== Left Equal to
!= Not equal to
=== Pointer equal to
!== Pointer not equal to



Left Less than
= Less than or equal to
Greater than
= Greater than or equal to



Left Left shift
Right shift



+ Left Addition
- Subtraction
* Left Multiplication
Division
% Remainder after division
! Left Logical negation
~ One’s complement
++ Join (see 6.6.5)
-- Difference (see 6.6.5)
- Unary minus
+ Unary plus
(type) Type cast expression
** Right Raise to power
: List CONS (see 6.6.5)
space Left Function application
? Left List index (see 6.6.5)
. Left Class project (see 6.11)




Table 6.2: nip2 operators in order of increasing precedence


6.6.1 The real type

nip2 has a single number type for integers and real numbers. All are represented internally as 64-bit floating point values. You can use the four standard arithmetic operators (+, -, *, /), remainder after integer division (%), raise-to-power (**), the relational operators (, =, , =, ==), the bitwise logical operators (&, |, ^  , ~), integer shift operators (, ) and unary negation and positive (-, +).

Other mathematical functions are pre-defined for you: sin, cos, tan, asin, acos, atan, log, log10, exp, exp10, ceil, floor. Each has the standard behaviour.

You can use type-casts on reals. However, they remain 64-bit floating point, the range is simply clipped. Casting to unsigned short produces a 64-bit float whose fractional part has been set to zero, and which has been clipped to the range 0 to 65535. This may or may not cause rounding problems.

You can write hexadecimal number constants as 0xff.

6.6.2 The complex type

Complex numbers are rather sketchily implemented. They are generally handy for representing vectors and coordinates rather than for doing arithmetic, so the range of operations is limited.

Complex constants are written as two numbers enclosed in round brackets and separated by a comma. You can use the four standard arithmetic operators (+, -, *, /), raise-to-power (**), and unary negation and positive (-, +). You can use == only of the relational operators. You can mix complex and real numbers in expressions. You can cast reals to complex and back. Use the functions re and im to extract the real and imaginary parts.

(12, 13) + 4 == (16, 13)  
(12, 2 + 2) ==  (12, 4)  
re (12, 13) == 12  
im (12, 13) == 13

6.6.3 The character type

Character constants are written as single characters enclosed in single quotes. You can use the relational operators (, =, , =, ==) to sort characters by ASCII order. You can cast a character to a real to get its ASCII value. You can cast a real ASCII value to a character. You can use the standard C escapes to represent non-ASCII characters.

(int) 'A' == 65  
(char) 65 == 'A'  
is_digit x = '0' <= x && x <= '9'  
newline == '\n'

6.6.4 The boolean type

The two boolean constants are written as true and false. Boolean values are generated by the relational operators. You can use the standard logical operators (&&, ||, !). You can use a boolean type as an argument in an if-then-else expression.

As with C, the logical operators do not evaluate their right-hand sides if their value can be determined just from evaluating their left-hand sides.

true && false == false  
true || error "boink!" == true  
if true then 12 else 13 == 12

6.6.5 The list type

Lists are created from two constructors. [] denotes the empty list. The list construction operator (:, pronounced CONS by LISP programmers) takes an item and a list, and returns a new list with the item added to the front. As a convenience, nip2 has a syntax for list constants. A list constant is a list of items, separated by commas, and enclosed in square brackets:

12:[] == [12]  
12:13:14:[] == 12:(13:(14:[])) ==  
  [12,13,14]  
[a+2,3,4] == (a+2):3:4:[]  
[2]:[3,4] == [[2],3,4]

Use the functions hd and tl to take the head and the tail of a list:

hd [12,13,14] == 12  
tl [12,13,14] == [13,14]

Use .. in a list constant to define a list generator. List generators build lists of numbers for you:

[1..10] == [1,2,3,4,5,6,7,8,9,10]  
[1,3..10] == [1,3,5,7,9]  
[10,9..1] == [10,9,8,7,6,5,4,3,2,1]

List generators are useful for expressing iteration.

Lists may be infinite:

[1..] == [1,2,3,4,5,6,7,8,9 ..]  
[5,4..] == [5,4,3,2,1,0,-1,-2,-3 ..]

Infinite lists are useful for expressing unbounded iteration. See 6.8.

You can write list comprehensions like this:

[x :: x <- [1..]; x % 2 == 0]

This could be read as All x such that x is in [1..] and x is even, that is, the list of even numbers.

You can have any number of semicolon-separated qualifiers and each one can be either a generator (like x <- [1..]) introducing a new variable or pattern (see 6.9), or a predicate (like x % 2 == 0) which filters the generators to the left of it.

Later generators change more rapidly, so for example:

[(x, y) ::  
  x <- [1..3]; y <- [x..3]] ==  
    [(1, 1), (1, 2), (1, 3),  
      (2, 2), (2, 3), (3, 3)]

You can nest list comprehensions to generate more complex data structures. For example:

[[x ⋆ y :: x <- [1..10]] ::  
  y <- [1..10]]

will generate a times-table.

You can use pattern-matching (see 6.9) to loop over several generators at the same time. For example:

[(x, y) :: [x, y] <-  
  zip2 [1..3] [1..3]] ==  
    [(1, 1), (2, 2), (3, 3)]

As a convenience, lists of characters may be written enclosed in double quotes:

"abc" == ['a','b','c']

You can define a string constant which has the same form as a variable name (that is, letters, numbers, underscore and apostrophy only) with a $ prefix. For example:

$form7 == "form7"

nip2 often uses these in option lists.

You can define a name, value pair with the = operator.

$fred => 12 == ["fred", 12]

Again, these pairs are frequently used to pass options to objects.

A list may contain any object:

[1,'a',true,[1,2,3]]

Mixing types in a list tends to be confusing and should be avoided. If you want to group a set of diverse objects, define a class instead, see 6.11.

Lists of lists of reals are useful for representing arrays.

You can use the list index operator (?) to extract an element from a position in a list:

[1,2,3] ? 0 == 1  
"abc" ? 1 == 'b'

You can use the list join operator (++) to join two lists together end-to-end.

[1,2,3] ++ [4,5,6] == [1,2,3,4,5,6]

You can use the list difference operator (--) to remove elements of one list from another.

[1..10] -- [4,5,6] == [1,2,3,7,8,9,10]

6.6.6 The function type

Functions are objects just like any other. You can pass functions to other functions as parameters, store functions in lists, and so on.

You can create anonymous functions with \ (lambda). For example:

map (\x x + 2) [1..3] == [3, 4, 5]

You can nest lambdas to make multi-argument anonymous functions, for example:

map2 (\x\y x + y) [1..3] [2..5] ==  
  [3, 5, 7]

You can compose functions with the @ operator. For example, for two functions of one argument f and g:

f (g 2) == (f @ g) 2

6.6.7 The image type

These represent a low-level handle to a VIPS image structure. You can make them with the vips_image builtin, and you can pass them as parameters to VIPS functions. The Image class is built on top of them, see 6.12.3.

As an accident of history, nip2 also lets you do arithmetic with them. This will probably be removed in the next version or two, so it’s best to go through the higher-level Image class.

nip2-8.7.1/doc/html/nipguidese32.html0000644000175000017500000004231513414613100014216 00000000000000 Classes

6.11 Classes

You can define new types using class. For example:

Pasta_plain = class {  
  lasagne = "large sheets";  
  fusilli = "sort of twisty";  
  radiatori = "lots of ridges";  
}

This defines a new class called Pasta_plain. The class has three members (lasagne, fusilli and radiatori), each of which has a list of char as its value. By convention, we’ve named classes with an initial capital letter, but of course you can do what you like.

You can refer to the members of a class using the class project (.) operator. For example:

Pasta_plain.lasagne == "large sheets"

You can use an expression to the right of . if you enclose it in brackets. For example:

Pasta_plain.("las" ++ "agne") ==  
  "large sheets"

Classes can contain any objects as members, including functions and sub-classes. Functions may define local classes, classes may define local functions, and all may refer to each other using the usual scope rules. For example:

Pasta_all = class {  
  filled = class {  
    tortelloni = "venus' navel";  
    ravioli = "square guys";  
  }  
  plain = Pasta_plain;  
}

When you define a class, nip2 adds a few extra members for you. name is a list of char giving the name of the class. this and super are the most-enclosing class instance and the class instance this class is derived from (see 6.11.2). nip2 also adds a default constructor: a member with the same name as the class, pointing back to the class constructor.

For efficiency reasons nip2 does not allow mutual recursion at the top level. If two functions depend on each other, neither will ever be calculated. For example:

a = 1 : b;  
b = 2 : a;

Neither a nor b will have a value.

You can have mutual recursion between class members. For example:

Fred = class {  
  a = 1 : b;  
  b = 2 : a;  
}

Now Fred.a will have the value [1, 2, 1, 2, 1, …].

6.11.1 Parameterised classes

Classes can have parameters. Parameters behave like class members initialised from arguments to the class constructor. For example:

My_pasta pasta_name cooked = class {  
  is_ready t = "your " ++  
    pasta_name ++ " is " ++ state  
  {  
    state  
      = "underdone!", t < cooked  
      = "perfect", t == cooked  
      = "yuk!";  
  }  
}

This defines a class called My_pasta which takes a pasta name and a cooking time as parameters. Once you have made an instance of My_pasta, you can test if it’s been cooked at a certain time with the is_ready member. For example:

tele = My_pasta "telephoni" 10;  
tele.is_ready 5 ==  
  "your telephoni is underdone!"

6.11.2 Inheritance

Classes can inherit from a super-class. For example:

Pasta_more = class Pasta_plain {  
  macaroni = "tubes";  
  spaghetti = "long and thin";  
  lasagne = "fairly large sheets";  
}

Here the new class Pasta_more inherits members from the previous class Pasta_plain. It also overrides the definition of lasagne from Pasta_plain with a new value. For example:

Pasta_more.macaroni == "tubes"  
Pasta_more.fusilli == "sort of twisty"  
Pasta_more.lasagne == "fairly large sheets"

You can use this and super to refer to other members up and down the class hierarchy. super is the class instance that the current class inherits from (if there’s no super-class, super has the value []), and this is the most-enclosing class instance.

Pasta_more.super == Pasta_plain  
Pasta_more.this == Pasta_more  
Pasta_more.super.this == Pasta_more

therefore:

Pasta_more.lasagne == "fairly large sheets"  
Pasta_more.super.lasagne == "large sheets"  
Pasta_more.super.this.lasagne ==  
  "fairly large sheets"

There’s a special symbol root which encloses all symbols. For example:

fred = 12;  
 
Freddage = class {  
  fred = 42;  
  mystery = root.fred;  
}

Now Fred.mystery will have the value 12.

There’s another special symbol called scope which encloses all symbols in the file this definition was loaded from. If you want to refer to another definition in the same file which is being masked somehow, use scope.

You can use the built in function is_instanceof to test whether an instance is or inherits from a class. For example:

is_instanceof "Pasta_more" Pasta_more == true  
is_instanceof "Pasta_plain" Pasta_more == true  
is_instanceof "Pasta_more" Pasta_plain ==  
  false

The super-class constructor can take arguments, and these arguments can refer to class members. For example:

Fresh_pasta pasta_name = class  
  My_pasta pasta_name cooked {  
  cooked = 2;  
}

Defines a class for fresh pasta, which always cooks in 2 minutes. You need to be careful not to make loops: if cooked did tried to refer to something in the super-class, this class would never construct properly. nip2 unfortunately does not check for this error.

Finally, the superclass can be a fully constructed class. In this case, the superclass is cloned and the new class members wrapped around it. You can use this to write a class which can wrap any other class and add members to it. Many of the toolkit menu items use this trick to enable them to work for any object type.

6.11.3 Minor class features

There are a couple of other things you can do with classes. You can define a special member called _check. If this member is defined, then when a class instance is created, the check member is returned instead of the class itself. You can use this to implement class argument type checks, for example:

Fred a b = class {  
  _check  
    = this, is_real a && is_real b  
    = error "args to Fred must " ++  
      "both be real"  
}

Defines a class called Fred which has to have two real numbers as arguments.

You can define members called oo_binary, oo_binary’ and oo_unary and do operator overloading. When nip2 sees one of the standard operators being used on an instance of your class, it will look up one of these members and pass in the name of the operator and the argument. The two forms of the binary operator member are called for the class-on-left and the class-on-rights cases. So:

x = Fred 1 2  
x + 12 == x.oo_binary "add" 12  
12 + x == x.oo_binary' "add" 12  
!x == x.oo_unary "negate"

These two features are very primitive. The _Object class in the _types toolkit builds on these to provide a fairly high-level system for checking class arguments and defining the meaning of operators. See 6.13.

nip2-8.7.1/doc/html/nipguide.css0000644000175000017500000003345613414613100013353 00000000000000 /* start css.sty */ .cmmi-10{font-style: italic;} .ptmr7t-{font-family: monospace;} .ptmr7t-{font-family: monospace;} .ptmr7t-{font-family: monospace;} .ptmr7t-{font-family: monospace;} .ptmr7t-{font-family: monospace;} .ptmr7t-x-x-207{font-size:207%;font-family: monospace;} .ptmr7t-x-x-207{font-family: monospace;} .ptmr7t-x-x-207{font-family: monospace;} .ptmr7t-x-x-207{font-family: monospace;} .ptmr7t-x-x-207{font-family: monospace;} .phvr7t-x-x-172{font-size:172%; font-family: sans-serif;} .phvr7t-x-x-172{ font-family: sans-serif;} .ptmr7t-x-x-120{font-size:120%;font-family: monospace;} .ptmr7t-x-x-120{font-family: monospace;} .ptmr7t-x-x-120{font-family: monospace;} .ptmr7t-x-x-120{font-family: monospace;} .ptmr7t-x-x-120{font-family: monospace;} .ptmri7t-{font-style: italic;} .ptmr7t-x-x-90{font-size:90%;font-family: monospace;} .ptmr7t-x-x-90{font-family: monospace;} .ptmr7t-x-x-90{font-family: monospace;} .ptmr7t-x-x-90{font-family: monospace;} .ptmr7t-x-x-90{font-family: monospace;} .phvr7t-x-x-80{font-size:80%; font-family: sans-serif;} .phvr7t-x-x-80{ font-family: sans-serif;} .pcrr7t-{font-family: monospace;} .ptmb7t-{ font-weight: bold;} .phvb7t-x-x-80{font-size:80%;font-family: sans-serif; font-weight: bold;} .ptmbi7t-{ font-style: italic; font-weight: bold;} .ptmr7t-x-x-80{font-size:80%;font-family: monospace;} .ptmr7t-x-x-80{font-family: monospace;} .ptmr7t-x-x-80{font-family: monospace;} .ptmr7t-x-x-80{font-family: monospace;} .ptmr7t-x-x-80{font-family: monospace;} .cmmi-8{font-size:80%;font-style: italic;} .cmsy-8{font-size:80%;} .phvro7t-x-x-80{font-size:80%;font-family:sans-serif; font-style:oblique;} p.noindent { text-indent: 0em } td p.noindent { text-indent: 0em; margin-top:0em; } p.nopar { text-indent: 0em; } p.indent{ text-indent: 1.5em } @media print {div.crosslinks {visibility:hidden;}} a img { border-top: 0; border-left: 0; border-right: 0; } center { margin-top:1em; margin-bottom:1em; } td center { margin-top:0em; margin-bottom:0em; } .Canvas { position:relative; } img.math{vertical-align:middle;} li p.indent { text-indent: 0em } li p:first-child{ margin-top:0em; } li p:last-child, li div:last-child { margin-bottom:0.5em; } li p~ul:last-child, li p~ol:last-child{ margin-bottom:0.5em; } .enumerate1 {list-style-type:decimal;} .enumerate2 {list-style-type:lower-alpha;} .enumerate3 {list-style-type:lower-roman;} .enumerate4 {list-style-type:upper-alpha;} div.newtheorem { margin-bottom: 2em; margin-top: 2em;} .obeylines-h,.obeylines-v {white-space: nowrap; } div.obeylines-v p { margin-top:0; margin-bottom:0; } .overline{ text-decoration:overline; } .overline img{ border-top: 1px solid black; } td.displaylines {text-align:center; white-space:nowrap;} .centerline {text-align:center;} .rightline {text-align:right;} div.verbatim {font-family: monospace; white-space: nowrap; text-align:left; clear:both; } .fbox {padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; } div.fbox {display:table} div.center div.fbox {text-align:center; clear:both; padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; } div.minipage{width:100%;} div.center, div.center div.center {text-align: center; margin-left:1em; margin-right:1em;} div.center div {text-align: left;} div.flushright, div.flushright div.flushright {text-align: right;} div.flushright div {text-align: left;} div.flushleft {text-align: left;} .underline{ text-decoration:underline; } .underline img{ border-bottom: 1px solid black; margin-bottom:1pt; } .framebox-c, .framebox-l, .framebox-r { padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; } .framebox-c {text-align:center;} .framebox-l {text-align:left;} .framebox-r {text-align:right;} span.thank-mark{ vertical-align: super } span.footnote-mark sup.textsuperscript, span.footnote-mark a sup.textsuperscript{ font-size:80%; } div.tabular, div.center div.tabular {text-align: center; margin-top:0.5em; margin-bottom:0.5em; } table.tabular td p{margin-top:0em;} table.tabular {margin-left: auto; margin-right: auto;} td p:first-child{ margin-top:0em; } td p:last-child{ margin-bottom:0em; } div.td00{ margin-left:0pt; margin-right:0pt; } div.td01{ margin-left:0pt; margin-right:5pt; } div.td10{ margin-left:5pt; margin-right:0pt; } div.td11{ margin-left:5pt; margin-right:5pt; } table[rules] {border-left:solid black 0.4pt; border-right:solid black 0.4pt; } td.td00{ padding-left:0pt; padding-right:0pt; } td.td01{ padding-left:0pt; padding-right:5pt; } td.td10{ padding-left:5pt; padding-right:0pt; } td.td11{ padding-left:5pt; padding-right:5pt; } table[rules] {border-left:solid black 0.4pt; border-right:solid black 0.4pt; } .hline hr, .cline hr{ height : 1px; margin:0px; } .tabbing-right {text-align:right;} span.TEX {letter-spacing: -0.125em; } span.TEX span.E{ position:relative;top:0.5ex;left:-0.0417em;} a span.TEX span.E {text-decoration: none; } span.LATEX span.A{ position:relative; top:-0.5ex; left:-0.4em; font-size:85%;} span.LATEX span.TEX{ position:relative; left: -0.4em; } div.float, div.figure {margin-left: auto; margin-right: auto;} div.float img {text-align:center;} div.figure img {text-align:center;} .marginpar {width:20%; float:right; text-align:left; margin-left:auto; margin-top:0.5em; font-size:85%; text-decoration:underline;} .marginpar p{margin-top:0.4em; margin-bottom:0.4em;} table.equation {width:100%;} .equation td{text-align:center; } td.equation { margin-top:1em; margin-bottom:1em; } td.equation-label { width:5%; text-align:center; } td.eqnarray4 { width:5%; white-space: normal; } td.eqnarray2 { width:5%; } table.eqnarray-star, table.eqnarray {width:100%;} div.eqnarray{text-align:center;} div.array {text-align:center;} div.pmatrix {text-align:center;} table.pmatrix {width:100%;} span.pmatrix img{vertical-align:middle;} div.pmatrix {text-align:center;} table.pmatrix {width:100%;} span.bar-css {text-decoration:overline;} img.cdots{vertical-align:middle;} .partToc a, .partToc, .likepartToc a, .likepartToc {line-height: 200%; font-weight:bold; font-size:110%;} .chapterToc a, .chapterToc, .likechapterToc a, .likechapterToc, .appendixToc a, .appendixToc {line-height: 200%; font-weight:bold;} .index-item, .index-subitem, .index-subsubitem {display:block} div.caption {text-indent:-2em; margin-left:3em; margin-right:1em; text-align:left;} div.caption span.id{font-weight: bold; white-space: nowrap; } h1.partHead{text-align: center} p.bibitem { text-indent: -2em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; } p.bibitem-p { text-indent: 0em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; } .paragraphHead, .likeparagraphHead { margin-top:2em; font-weight: bold;} .subparagraphHead, .likesubparagraphHead { font-weight: bold;} .quote {margin-bottom:0.25em; margin-top:0.25em; margin-left:1em; margin-right:1em; text-align:justify;} .verse{white-space:nowrap; margin-left:2em} div.maketitle {text-align:center;} h2.titleHead{text-align:center;} div.maketitle{ margin-bottom: 2em; } div.author, div.date {text-align:center;} div.thanks{text-align:left; margin-left:10%; font-size:85%; font-style:italic; } div.author{white-space: nowrap;} .quotation {margin-bottom:0.25em; margin-top:0.25em; margin-left:1em; } h1.partHead{text-align: center} .chapterToc, .likechapterToc {margin-left:0em;} .chapterToc ~ .likesectionToc, .chapterToc ~ .sectionToc, .likechapterToc ~ .likesectionToc, .likechapterToc ~ .sectionToc {margin-left:2em;} .chapterToc ~ .likesectionToc ~ .likesubsectionToc, .chapterToc ~ .likesectionToc ~ .subsectionToc, .chapterToc ~ .sectionToc ~ .likesubsectionToc, .chapterToc ~ .sectionToc ~ .subsectionToc, .likechapterToc ~ .likesectionToc ~ .likesubsectionToc, .likechapterToc ~ .likesectionToc ~ .subsectionToc, .likechapterToc ~ .sectionToc ~ .likesubsectionToc, .likechapterToc ~ .sectionToc ~ .subsectionToc {margin-left:4em;} .chapterToc ~ .likesectionToc ~ .likesubsectionToc ~ .likesubsubsectionToc, .chapterToc ~ .likesectionToc ~ .likesubsectionToc ~ .subsubsectionToc, .chapterToc ~ .likesectionToc ~ .subsectionToc ~ .likesubsubsectionToc, .chapterToc ~ .likesectionToc ~ .subsectionToc ~ .subsubsectionToc, .chapterToc ~ .sectionToc ~ .likesubsectionToc ~ .likesubsubsectionToc, .chapterToc ~ .sectionToc ~ .likesubsectionToc ~ .subsubsectionToc, .chapterToc ~ .sectionToc ~ .subsectionToc ~ .likesubsubsectionToc, .chapterToc ~ .sectionToc ~ .subsectionToc ~ .subsubsectionToc, .likechapterToc ~ .likesectionToc ~ .likesubsectionToc ~ .likesubsubsectionToc, .likechapterToc ~ .likesectionToc ~ .likesubsectionToc ~ .subsubsectionToc, .likechapterToc ~ .likesectionToc ~ .subsectionToc ~ .likesubsubsectionToc, .likechapterToc ~ .likesectionToc ~ .subsectionToc ~ .subsubsectionToc, .likechapterToc ~ .sectionToc ~ .likesubsectionToc ~ .likesubsubsectionToc, .likechapterToc ~ .sectionToc ~ .likesubsectionToc ~ .subsubsectionToc, .likechapterToc ~ .sectionToc ~ .subsectionToc ~ .likesubsubsectionToc .likechapterToc ~ .sectionToc ~ .subsectionToc ~ .subsubsectionToc {margin-left:6em;} .likesectionToc , .sectionToc {margin-left:0em;} .likesectionToc ~ .likesubsectionToc, .likesectionToc ~ .subsectionToc, .sectionToc ~ .likesubsectionToc, .sectionToc ~ .subsectionToc {margin-left:2em;} .likesectionToc ~ .likesubsectionToc ~ .likesubsubsectionToc, .likesectionToc ~ .likesubsectionToc ~ .subsubsectionToc, .likesectionToc ~ .subsectionToc ~ .likesubsubsectionToc, .likesectionToc ~ .subsectionToc ~ .subsubsectionToc, .sectionToc ~ .likesubsectionToc ~ .likesubsubsectionToc, .sectionToc ~ .likesubsectionToc ~ .subsubsectionToc, .sectionToc ~ .subsectionToc ~ .likesubsubsectionToc, .sectionToc ~ .subsectionToc ~ .subsubsectionToc {margin-left:4em;} .likesubsectionToc, .subsectionToc {margin-left:0em;} .likesubsectionToc ~ .subsubsectionToc, .subsectionToc ~ .subsubsectionToc {margin-left:2em;} .figure img.graphics {margin-left:10%;} #TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-1{border-collapse:collapse;} #TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-1{border-collapse:collapse;} #TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-1{border-collapse:collapse;} #TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-1{border-collapse:collapse;} #TBL-1 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-1{border-collapse:collapse;} #TBL-2 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-2{border-collapse:collapse;} #TBL-2 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-2{border-collapse:collapse;} #TBL-2 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-2{border-collapse:collapse;} #TBL-2 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-2{border-collapse:collapse;} #TBL-2 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-2{border-collapse:collapse;} #TBL-2 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-2{border-collapse:collapse;} #TBL-3 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-3{border-collapse:collapse;} #TBL-3 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-3{border-collapse:collapse;} #TBL-3 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-3{border-collapse:collapse;} #TBL-3 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-3{border-collapse:collapse;} #TBL-3 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-3{border-collapse:collapse;} #TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-4{border-collapse:collapse;} #TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-4{border-collapse:collapse;} #TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-4{border-collapse:collapse;} #TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-4{border-collapse:collapse;} #TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-4{border-collapse:collapse;} #TBL-4 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-4{border-collapse:collapse;} #TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-5{border-collapse:collapse;} #TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-5{border-collapse:collapse;} #TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-5{border-collapse:collapse;} #TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-5{border-collapse:collapse;} #TBL-5 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-5{border-collapse:collapse;} #TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-6{border-collapse:collapse;} #TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-6{border-collapse:collapse;} #TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-6{border-collapse:collapse;} #TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-6{border-collapse:collapse;} #TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-6{border-collapse:collapse;} #TBL-6 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-6{border-collapse:collapse;} #TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-7{border-collapse:collapse;} #TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-7{border-collapse:collapse;} #TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-7{border-collapse:collapse;} #TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-7{border-collapse:collapse;} #TBL-7 colgroup{border-left: 1px solid black;border-right:1px solid black;} #TBL-7{border-collapse:collapse;} /* end css.sty */ nip2-8.7.1/doc/html/nipguidese23.html0000644000175000017500000000505713414613100014220 00000000000000 Using an external editor

6.2 Using an external editor

If you’re going to be doing any more than a little programming in nip2 you probably won’t want to use the built-in editor. I suggest you start your favorite editor in one window on the screen and then in the nip2 program window click File / Open Toolkit and check the Pin-up box in the file selector.

Now every time you want to try out your definition, save the file from your external editor and click OK in nip2’s file selector.

nip2’s editor automatically adds some semicolon characters to separate definitions in a file. If you’re using an external editor, you’ll need to put these in yourself. Also check the syntax for adding separators and column items to menus.

nip2-8.7.1/doc/html/nipguidese29.html0000644000175000017500000000763013414613100014225 00000000000000 Lazy programming

6.8 Lazy programming

nip2’s programming language is lazy, that is, it delays evaluation as long as it possibly can. For example, error is a function which immediately halts execution of your function and pops up an alert window. So:

12 + error "wombat!"

Has no value: this expression will halt with an error message. However:

false && error "lasagne!"

Will evaluate to false, since nip2 knows after looking at the left-hand-side of && that the result must be false, and so does not evaluate the right-hand-side.

[12, error "hot chilli!"] ? 0 == 12

This also evaluates completely, since the second element of the list is never used, and therefore never evaluates.

Things become more confusing when you start calling functions, since the arguments to a function call are also not evaluated until the function needs that value. For example:

foldr (error "boink!") 2 [] == 2

Again, this evaluates successfully, since the function is never used by foldr.

nip2-8.7.1/doc/html/nipguidese19.html0000644000175000017500000000673113414613100014225 00000000000000 Matrix

5.6 Matrix

This menu groups operations which operate on matricies. nip2 has four ways of displaying a matrix, but they all behave in the same way under the skin. Almost all the items in the Math menu will work on matricies. Most of the matrix operations will also work on images.

New
The first four items make matricies which display and edit in various ways useful for different applications. The final two make matricies which are pre-filled with useful numbers.
Convert to Matrix
Try to make anything into a matrix.
Extract
This group of items extracts various submatricies. You can also do this graphically: just drag-select an area in matrix.
Insert, Delete,
Also work on images, which can be handy. A 45 degree rotate will only work for square matricies with odd-length sides.
Invert
Simple matrix-only maths operations.
Plot Scatter
This takes a two-column matrix where the columns are the X and Y positions of points and draws a scatter graph.

nip2-8.7.1/doc/html/nipguide.html0000644000175000017500000002672713414613100013532 00000000000000

nip2 Manual
Version 8.6
John Cupitt, Rachel Billinge, Joseph Padfield, Clare Richardson, David Saunders

“It’s quite simple really, and at the same time, rather complicated.”
— A. Haddock, Sea captain (rtd.)

This document formatted January 7, 2019

nip2-8.7.1/doc/html/nipguidech1.html0000644000175000017500000001105613414613100014113 00000000000000 1 Getting started

Chapter 1
Getting started

nip2 is a user interface for the VIPS image processing library. It is designed to be fast, even when working with very large images, and to be easy to extend.

This guide is split into quite a few chapters:

  • If you want to use nip2 to assemble infrared mosaics, you should read Chapter 3. The middle section in the tutorial (see 2.2) does IR mosaics very quickly.
  • If you want to use nip2 for general image processing, work through Chapter 2.
  • If you have specific questions about some part of nip2’s user-interface, look at Chapter 4.
  • If you’re really hardcore, take a look at Chapter 6, which covers programming.
  • If you want to know more about VIPS, the image processing package underlying nip2, try the VIPS Manual.

If nip2 has installed correctly you should see something like Figure 1.1 when it starts up.


PIC


Figure 1.1: nip2 as it starts up


nip2-8.7.1/doc/html/nipguidese34.html0000644000175000017500000000322713414613100014217 00000000000000 The _Object class

6.13 The _Object class

nip2-8.7.1/doc/html/nipguidese22.html0000644000175000017500000000514113414613100014211 00000000000000 Load and save

6.1 Load and save

When nip2 starts up it loads all of the definition files (files with a .def extension) it can find in the directories listed in your start path. You can change the start path in Preferences. By default, the start path lists just two areas: a personal start directory that nip2 makes in your home area, and the main system nip2 start directory containing all the standard toolkits.

If there are two files with the same name on the start path, then nip2 will only load the first one. This means that if you modify one of nip2’s built-in menus and save it to your personal start directory, in future you’ll just see your personalised version.

You can load or reload a toolkit at any time with the File / Open Toolkit menu item in the program window. If you open a toolkit with the same name as an existing toolkit, nip2 will remove the old toolkit before it loads the new one.

nip2-8.7.1/doc/html/nipguidese30.html0000644000175000017500000001265713414613100014222 00000000000000 Pattern matching

6.9 Pattern matching

Any time you define a name, you can use a pattern instead. For example:

[fred, petra] = [12, 13]

defines fred to have the value 12 and petra to have the value 13.

A pattern describes the structure you are expecting for the value. When the value is computed it is matched against the pattern and, if the match is successful, the names in the pattern are bound to those parts of the value. Our example is exactly equivalent to:

temp = [12, 13];  
fred  
  = temp?0, is_list temp &&  
      is_list_len 2 temp  
  = error "pattern match failed";  
petra  
  = temp?1, is_list temp &&  
    is_list_len 2 temp  
  = error "pattern match failed";

where temp is an invisible, anonymous symbol.

You can pattern match on any of nip2’s data structures and types. You can use:

a:b
Tests for the value being a non-empty list and then assigns a to the head and b to the tail.
(a,b)
Tests for the value being a complex and then assigns a to the real part and b to the imaginary.
[a,b,c]
Tests for the value being a list of length three and then assigns a, b and c to the three elements.
(class - name b)
Tests for the value being an instance of the named class, then assigns b to that class instance.
constant
Tests for the value being equal to that constant. Constants are things like ”hello world” or 12.

You can nest patterns in any way you like. Patterns are useful in conjunction with list comprehensions, see 6.6.5.

You can’t use patterns in function arguments in the current version, hopefully this will added shortly.

nip2-8.7.1/doc/html/nipguidese12.html0000644000175000017500000001300013414613100014201 00000000000000 The programming window

4.4 The programming window

To pop up the programming window, click on Toolkits / Edit Toolkits in nip2’s main image processing window. The window shown in Figure 2.11 should appear.

Each of the things down the left of the program window is a toolkit. Each toolkit is a text file containing a set of definitions in nip2’s programming language. See Chapter 6 for details on the language.

If you open a toolkit, nip2 shows all of the definitions in that file. If you click on one of these nip2 shows the source for that definition in the main part of the program window. After editing a definition, click on File / Process to make nip2 read what you typed, compile it, and update itself.

Click on File / New / Tool to add a new definition to a toolkit, click on File / New / Toolkit to make a completely new toolkit. You can also right-click on tools and toolkits to get a context menu, and you can left-drag tools to move them around within a toolkit or between toolkits.

Some toolkits are loaded from files when nip2 starts up, others are built from the VIPS operation database (for example, _arithmetic), and one (called _builtin) contains the functions that are built into nip2. If you select a tool and then click on Help / Help on Tool, nip2 will try to display the relevant section from the VIPS manual in your web browser. Currently, this works only for things in the VIPS operation database: try _arithmetic / im_add, for example. There’s a section in the Preferences workspace to control which web browser nip2 uses and how it asks for a page.

Toolkits and tools whose names begin with an underscore character are not displayed in the main Toolkits menu. The idea is that they represent little utility functions, rather than stuff a user might be interested in. See 6.12.1 for more information on how tools and toolkits are displayed.

You can have several programming windows open at the same time (often useful, if confusing). The Edit menu lets you search for patterns across all definitions. The Jump To Definition item jumps to the definition of a symbol.

The Debug menu has items which open a trace window (use this to track the actions taken by nip2’s reduction engine) and which report on unresolved symbols and list all current errors.

nip2-8.7.1/doc/html/nipguidech4.html0000644000175000017500000001003613414613100014113 00000000000000 4 Reference

Chapter 4
Reference

This chapter is supposed to be a user-interface reference. Chapter 5 describes the items in the Toolkits menu and Chapter 6 is the programming language reference. Chapter 2 has a tutorial-style introduction.

nip2-8.7.1/doc/html/nipguidese11.html0000644000175000017500000005501413414613100014213 00000000000000 Image processing window

4.3 Image processing window

Figure 4.5 shows nip2’s main image processing window. The centre area is the workspace, the left-hand area is a pane you can reveal to write custom definitions for this workspace (see View / Workspace Definitions), and the right-hand pane is the toolkit browser (see View / Toolkit Browser).

Drag with the middle mouse button to scroll the workspace window. Drop a file on to the workspace background (from your file manager) to load that file. If you right-click on the workspace background, a useful menu will appear.


PIC


Figure 4.5: nip2’s main image processing window


Workspace
A workspace is split into a set of separate tabs. Right-click on a tab to get a useful menu. Press the add icon at the right to make a new tab. You can drag tabs between workspaces, or drag a tab to the desktop to make a new workspace. Use the syntax tab1.A1 to make references between tabs.
Tab
This area displays the current tab. Tabs are divided into columns of objects which each behave rather like windows: they can be moved around, folded away, loaded, saved and deleted.
Current column
One column is the current column. This is the column to which all new objects are added. Single-left-clicking on the title bar of a column makes that the current column. See 4.3.1.
File, Edit, View
Use the File menu to create or save workspaces, to open workspaces or load other objects into this workspace, to merge workspaces and to search for workspace backups. Use the Edit menu to select, group, delete and duplicate sets of objects. Use View to show and hide elements of the main window, and to set the object view mode.
Toolkits
This menu contains all of the image processing functions which are currently loaded into nip2. They are generally grouped by object type: all of the operations on matricies are under Toolkits / Matrix, for example.

If you select one of these image processing operations, nip2 will apply that operation to the bottom few items in the current column (however many are necessary — two items for Math / Arithmetic / Add, for example), or alternatively, if you have selected some objects explicitly, it will try to apply the operation to the selected objects. See 4.3.3. As you move the mouse pointer over menu items nip2 tries to display some helpful information about the operation, including the number and type of arguments the operation expects.

Toolkit Browser
This side panel shows all the image processing operations again, but this time as a large flat list you can easily browse. Type into the search box at the top to filter operations by keyword. Doubleclick on an item to activate it.
Tab Definitions
This side pane shows private definitions for this tab. Programs you write here are loaded and saved with this workspace. See the Programming chapter for details on nip2’s programming language.
Free space
This displays the amount of disc space you have left in your temporary file area. See A if you want to change the directory nip2 uses to store temporary files.

If you left-click on the label, it changes to display the space nip2 has free internally for performing calculations. You can change this limit in the Preferences workspace. Click again to switch back to disc free.

If you have objects selected, this area changes to show the names of the selected objects.

Status bar
As you move the mouse pointer about the window, this bar tries to display useful information about the thing you are pointing at.

4.3.1 Columns

Columns are split into a number of areas:

Column name
Each column has a name. You can pick any name you like when you make a new column with File / New / Column. There’s no way to rename a column, unfortunately. Objects in the column are named using the column name, plus a number.
Column title bar
Drag with the left mouse button held down on the column title bar to move the column around the workspace. Double-left-click on the title bar to change the comment attached to the column. Hold down the right mouse button on the column title bar to pop up a useful menu.

The items in the menu let you edit the caption, select all the objects in the column, make a new column which is a copy of this column, save the column to a file, convert the column into a menu item (see 4.3.6) and remove the whole column.

Column fold button
Left-clicking on the fold button folds the column away. Use this to hide columns which you still need, but which you are not interested in just now.
Expression entry
You can perform calculations by typing expressions directly into this box. For example, try entering the following expressions, and pressing Return:
2 + 2  
A1 + 120  
"My cat likes\nlasagne"  
fred = 12

The last example shows custom button name creation. Normaly nip2 will pick a name for you, but you can chose your own.

4.3.2 Rows

A column holds a number of rows. Each row comes in four main parts, not all of which are visible for all row values. Rows which represent classes have a pair or up/down arrows to the left of the row name button which you can use to control which parts of the row are visible.


PIC


Figure 4.6: Components of a workspace row


Row name button
Each row has a name. The name is normally formed from the name of the current column, plus a number.

If you double-left-click on the row name button, nip2 will pop up a viewer or dialog box for the value of the row. If you left-click, nip2 will select that row and deselect all other rows. If you click on an empty space in the workspace, it will deselect all rows. If you Ctrl-left-click, nip2 will toggle selection of that row. If you select one row and then Shift-left-click on another row in the same column it will select the second row and all the rows in between. If you drag with the left button, you can change the order of rows in a column. Hold down the right mouse button for a useful menu. If you let the mouse linger over a button, a useful tooltip will appear.

Graphic
If the row’s value is a class, and if the class is an instance of one of nip2’s graphic classes, then nip2 will draw a graphic representation of the row’s value. See 6.12.2 for a more detailed explanation.
Members
If the row has a class for a value, then nip2 will draw a sub-column listing the class members. Subcolumn members are in turn rows themselves.
Text
Finally, the text part normally shows a text representation of the row’s value. If you left-click on the value, it changes to show the formula which generated that value. You can edit the formula and press Return to change it.

Alternatively, selecting View / Show Formula toggles between displaying values for objects and displaying the formula.

Object name colours

nip2 changes the background colour of the row name button to show the state of the row. If background colours are not visible (perhaps your theme turns them off), try turning on the Display LEDs in workspace option in Preferences.

Green means the row is selected (click on the background to unselect), red indicates an error (right-click on the row button ans select Recalculate to see the full text of the error), brown indicates that the row value is out of date and needs recalculating and the various blues indicate parent and child relationships.

4.3.3 Applying operations to objects

There are three ways you can apply image processing operations to objects in your workspace:

  1. Select the object you want to apply the operation to by single-left-clicking on the object name. When you single-click, the object name will change colour to show that it is selected, and nip2 will display the name of the selected object at the left end of the status bar (this is useful if the selected object is scrolled off the edge of the window).

    You can select additional objects with Ctrl-left-click and Shift-left-click. This is necessary if you want to use an image processing operation that takes more than one argument.

    Once you have selected the rows (sometimes you need to select them in a certain order), click on the processing operation you want from the Toolkits menu.

  2. If there are no objects selected when you click on an image processing operation, nip2 uses the bottom few items (as many as are needed by the operation) in the current column.
  3. You can also type your formula directly into the expresion entry line at the bottom of the selected column. Chapter 6 describes the syntax in detail, but it’s approximately C.

4.3.4 Batch processing

If you select a number of rows and then click Edit / Group, nip2 will group the rows together. Now if you select the group and click on an item in the Toolkits menu, nip2 will apply that operation to every item in the group. You can group groups, and you can mix grouped and non-grouped rows freely.

If you save a group, nip2 will write each item in the group to a separate file, incrementing the filename each time.

4.3.5 Error handling

If an object in your workspace has an error (for example, if you are trying to join two images of different types), then the object name button will turn red to show that this object contains an error and the tooltip for the button will show the error message.

4.3.6 Making menu items out of columns

If you make a column that does something useful, you can make it into a menu item by following these steps:

  1. Make your column look nice. Drag with the left mouse button on the object name buttons to re-order items in the column, and add comments to explain what are the input fields and what are the output. Double-click on the column title bar to add a helpful title to the column.

    Add a comment by typing your text (enclosed in double quotes) into the line at the bottom of the column. Left-drag the row to the right place.

  2. Select Make Column Into Menu Item from the column title-bar menu, see 4.3.1.

    This will open up a new dialog box which you can use to set a name for your new menu item and the name of the top level menu the item should be added to.

  3. That’s it. You’ll be prompted to save your new toolkit when you try to quit nip2. We recommend you just say OK to the suggested location for the file. Edit your menus with the programming window, see 4.4.

nip2-8.7.1/doc/html/nipguidese26.html0000644000175000017500000001253713414613100014224 00000000000000 Evaluation

6.5 Evaluation

nip2 calculates the value of an expression by using the definitions you entered to successively reduce the expression until it becomes one of the base types. Sometimes there is a choice as to which part of the expression will be reduced next — nip2 will always choose to reduce the leftmost, outermost part of the expression first.

For example, consider this definition:

factorial n  
  = n ⋆ factorial (n - 1), n > 1  
  = 1

And here’s how nip2 will evaluate the expression factorial 3:

factorial 3 -->  
  3 > 1 -->  
  true  
3 ⋆ factorial (3 - 1) -->  
  (3 - 1) > 1 -->  
  2 > 1 -->  
  true  
3 ⋆ (2 ⋆ factorial (2 - 1)) -->  
  (2 - 1) > 1 -->  
  1 > 1 -->  
  false  
3 ⋆ (2 ⋆ 1) -->  
3 ⋆ 2 -->  
6

Note how nip2 delays evaluating parameters to functions until they are needed, but still shares the result. 3 - 1 is only evaluated once, for example, even though the result is used three times. nip2 has a trace window: click on Debug / Trace in the program window and check the View / Operators menu item.

The advantage of this style of computation over conventional imperative programming languages is that you can reason about your program mathematically1 .

This isn’t the best way to write a factorial function. A function with lots of recursive calls can be hard to understand — it’s much better to use one of the higher order functions from the standard environment to encapsulate the type of recursion you want to use.

The clearest definition for factorial is probably:

factorial n = product [1..n]

See 6.6.5 for an explanation of the list syntax.

nip2-8.7.1/doc/html/figs/0000755000175000017500000000000013414613100012032 500000000000000nip2-8.7.1/doc/html/figs/toolkit3.jpg0000644000175000017500000004651613414613100014240 00000000000000JFIFJExifMM*2:(&&C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222 " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?LUpOT> ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEG7I,0lުvIzZ( ( ( ( ( ( ( ( ( ( ( ( ( ( ]sk5Ʒq\~]oX|7zk[Ns ;#Xmʁ"xVD۔rF8HVnL2n8LPܖ~5UӍgY4K~f3ٿû>}zp ^w"Wzӿ\xCEn&7 kmh ,~`]Ìu8V u![7xYO,K c@"VR?]NQ ^w"c tnY#qqm,Ou $`y?>Ufco^>G»׿綝޽=Ezu][Eqo" 92A"ջ<޽=E+ԨջԨ<޽=E+ԨջԨ<޽=EIoUtK˛4')opP?Z'i-ΈZ8Kpg֪զaFaSC Đȼ28jObm3AV?V ?Uȶ:7zhwZy,-ELȹœz /ZF,ogD3ڈ2H#vwEnfPH7K>,xyA b5H-lo洏u%Aq0q&*@9jn-o/./"K1"\AB" ğNsIm=F{wviр@,p@CL]Um®(R8<եy'W(l$yce ?a½ϲ'|y[|7}wc=֞᫹m쮍֦UV(r%@Z77 eB9; \{Xm|4* b mԑL>?ڿhy{6Yw::X=U(5oq$`yt/ڹcnn3]0еH<)}׷7)*;(%˴RQ'#8QG@p ՄN Lt¢ 2J3ʞgW,^*0Y[[wf%\s:P_ i]#Oge %K"$dAZQ@Q@Q@4ԣPlMz]բрL[I 1NTqSk(/?鴙mw)ͻa3;:( ( ( ( ǗF-axJ:uޗ+˩1i[b7?.x8O&d`qmQR0(((((((((((((YEAS kp9/]h:5>kN10nt(.I#8TOZ hc/7o*4xg'/=7^펧<^&{?xIL7w$ĩ6mi>٭e4Tbv:Ozi;[:4Em)^;;׍ Tg FH~3[5&%wN sr'%@ӡ47RĚri%ĥV]9 (1bB恝55 h+{gy*(,va ʹޮ7@;ybD,Tiup-z''=QEQEQEQECw3|8sVwuAa,Asm;>TpB:ۥhnK<[kF2:J!EI=I'O$*'*Q;]QZrk95ܢm.G\c`pэ `fSԴ=Z`ã$`) >[5]>Yw$ivQhAH)1ݡyc,ms#91P[9gK'&{i|/f$ V{u aU H*OI@--ux渒YH^2] ʸcH^mbXH>A84佷Pd1G4\)NLo{@6ҴsoKK譍Rq.60&>OU~]XKd2ϨQ ]6y~a#Z :]E"Tyv$ TPA%<}6wP\-.xC ga\hC ( ( ( ( *h ΅c o-`qYץ'\IlG3"'ޜqXWW&C_(Au=[NE`0 Es[H$KˤiD@HتU~nⅰ3I&sk>\f/#I9?oK~1ip~cc#<ӨmHu ck+>$˖7Ldޮ<ڼzՋ;:5P9Wn{,2!u{hiVXh$҄6H\_Krr9ڿյ} Z ^]ChDT5iG[и7]C&/v"ĕ<ɫOgk#m 9_G4<ϩ׬! ݌ U}: ıĪ ef((mbыW*mpŚhbpI)= B+ <O&dT?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4w!wUFI6OEPEPEPEPEPEPS ?g\AV4 ;K`%N[K{ZeT.7`c Vd~ l=JE41hbpynSi鎚Z_y$E&2DGe3]TI#Öv: rNc6 ~W'sVQEQEQEQEQE ݬ7sZ)hfCTȧAVG$Pơ4\*ARQ@9ksgo2|syozʹs˩6l\"HH2i6^m h ½ %N548iSM]O6Ga{'w&7`w9jYc2 H)0 UXA,Yng9 NGyiO%&F-IJ4(Rd NL5| fȗL!p8;~E5,`Q8b $sש}ݣ?dk٭T˧@֒\ r+I5MđOq!pcf&-Y[R^Pp BPI})vib/_ֿ)ZFQHRX'8k[Q"tkx W l{qIokZ[-ЕV}:<y=0nl>k>Zϼ?yZϼ?ֿ)eeAv;ֿ(5| oGE]5| >k>QQddŤ{0k>$,$ļʸgpڋn]Zܦƶ3;~5kMV_+)+Xm*Xݟ;x?4G2m0H?|RQ^#a`AWN+HsHSc$g*sO#9i@?J$ѰI U+H(싕9R(=6 HNt/?T&HM y*J(9$tl,H1JR);"ciz)Ԋucc`<~RмxSWj (QEQEQEQEQETg"YE5i_Vo i~]OVIMytdJ޴l|MO,7=ܺ5̾e֡42\CG%wq=兕XZG[D›ڊQe?7/viu,{N7Qޫk)7OM '+Cn^[g̡F=/Y7šAW^ɵ-g<9' 8 ι9m<7c5ViˉJUu݉q44԰ӬH4 hW "hd\ڬ+o 'O/v$e>qz[=j5F d^: EPEPEPEP{M:&{h&:Icnucx7Su] #ٞ;{>8I?41\KU2=A@I S[l. V&TqZӴ4\ҙͧH;Up0.~רehVLq4f1;R} bV1(J)s<*szPFZ5+VFr5`H?أiOPgû<+VFr4ejO&c}} b)*wgejO&[׬}} bYϤQ?A[#Q9?YϤQ ???ݞO#Q9?< kx@x@ 31Rx v`H?ؤKh!h*yoYNZK rROb v;[gN/Kg$ }J~xh |7u/b!Ż-lx%]~(ZuӭFخH(qX3֑s,Fu#ڹNod11X40cM zjgWׯ4Ki&t(fXD @> /<5kmLu[CEPRnBsȡ~õ@xكۂ=i ֏ƺ4Vb{縸NJCRU$')Ѭ.1y!yuv#8O FR@^a)v)9t+M7M4{m6\HІĈB.R8^E]ӼAs}/Nmuv 򲡖Lf8n66epv&`KU *o/GKѯ|^+Y䣕+c dk^v+=R2bXmD:r-ݞ>i12_XxNPbKh✨c!qm}xñK*I~NL҈TbMdl-NQxO3nt!<hDz\ZXw[ZNAgwFR]CZeo!vK{Y-͜,~lC{$|b+etDH3ʰO[3ZC\3[,>KxeԮ.kkK*02~^fkx4rȑuV 1IUu?^MZ?&QE@Š(((((?g\A>n(-"IRHPWx 1Mn+Ɨ蚮._m|p#ķ[5v\Ao=Zjcs#Z-ܑy !U0A|zmS=(Gv4)&6Q 9??cV+]sv%̟``%-Ͳ<|0Bg!rFO8ne-lVy'-eD+Ὠ(((((bȼ%ѻ8ك==9k`ǚc?:4j]эST6v_/jaEPEPEPEPEPEPEPEPQEIQEjLǛ>:oPqcX? P}}`c(~PTcX? >k>߱=?ϬOEA;_v@P}}`c(~PTcX? >k>߱=Uy\A4Ϭ3SUp (aEPEPEPEPEPS g);<`W$QүME^Dm;"Uш%WJ@Y;H-C{ O j?'/>Tu gKLCRԬ쌧uyFh<)h((((4[BO*EjY*I'@v_/jycT ( ( ( ( ( ( ( ( .$d SH5Y%{*!Kfy՞.çڋas2qr,GYxֵW}I/:; >}gxvYf`s2q-Ÿʺz.u;B.d23ף8Uq80*jRWgmn-0ɶ1{AkA4Y$7)@o5mNq0j ,8JA :ӻt4M1}Q1IW}97N.ڳRDf=r25 Ua)fx]'Vݥ{x tPn3'ϙN!~ѡxe[y-רFhC~f%̦4Do'̃cֿ+ҤS\}DBƮ@ `6Kqմ p3=NZ{7t?K8$bi ac2O4߳Zϼ?FֳHbx-q" Pyc#$;t+'̫+n*q^^a=Z(=ࢊ(((((,DdY"QцC ?g\Am|p]͌ۮ~|89=5o]zVT-Qz핃ϭo^sj)BB1Ž94emFgEm+#FOb\s~Fkgʀ=DD$gAXSjzEkz5=4]3ċ޿!z̟ F"kp(s#kkQE6$QE!Q@Q@Q@8뗚bX  r{3QҴ/#Py-wo$![GWCEd[뼿1j]эST (((__j6lM}xm[UE&B'1׹}şQ/$v'?5_I,֋&7h/xZ/ %> h(hv'?5_I,֋&7h/xZ/ %> h(hv'?5_I,֋&7k?X{&$,JOL2j<$e $?AAOIy9!dMj^\\c ӸvUh!xEZۮşf͙}/9k<=I?&oC$j>I%ʴ%wg #Q9??oj?']7?!I4cx$U?BχvpZ5+VFr5cx$G7?!I4iOPgû8O[#Q9?AAOI $??ݜ'V@GhտMw I'$x{MST+VFr4ejO&oC$h<=I?&)*wg #Q9?h5W[A33OGߥt I'$x{MEL|-J$wX_dg_K4}şQ/$ nX_dg_K4}şQ/$OkEDGFbH۱+J@mu%ZNokΊed9q*\é!Ҽ} 7w^eیq'9;c #i|J}ek{_"O1HLd-[WLNWӈ &˶"Q(qWח| 5Ԟ\m,pՙGyWqjԺK>XŠKiys;G b$6vMhxNi4"Kea6#,UQi_L:EPEPEPEP7wPYupa 0RP2N&\J"IAE6I[{sq2!hlp< Gt &H'I4\q &8胷'&ycT ݗQEQEg#Io^rk[EoD+EO#(V! QXia.<o[q:9;f0[{(4cRM6c_UХ"oqk ]2 2_s K.OW>G?{Nj/t[5h4t@u7 LiZusms1.Ei9K݂Is {]WT=i$|Xd_t}MFiF_8Ymmۿb2qtɮ~6Ge3!ˈ|~{]9u1|Wm c*ZO{ cd\|o3g'cYfm+UWodK VSp!H|/q'LdCgy7}3*#&_?ӳjz.l.4 R] |`ȸN#ٷsxN ^V$!]A s^MZxk%Y*2my Ƕ3J ]_ZjoVK3,688%v[qFE-wi[sJ8"M8e\1cp:Y-a{+xf,Ve$;v7o-BaJ$\$6pqV?/'/M?^g3lu9DkKk 3Q`K{h ˲W-ӎFs#%x{4sB~HnF`3sĶz]Y\[<\/1F{rH5_;H f̭ p{@.W$*3? 0]$ 2II?V-?Y%.U!vU8/,^JU۩omEw2.Ac1: U9m6[;\O{bV",6…eB3#u5[-ÄrVEYXv!V"+M;XԥM, lC*( {7m iMǹ~a2sPKV$[8b %"t.͸=i,嵱iQ,D˻sXm'wR1<{.,׸z*zmP;cዛo"}?R./$Y%t *MIs]|ya7%y}~Pv𮂏kϤ[\;aHnXkZoZ[n舧d-\e냀2mK6=/XKyaӧKO0Jw 9:bm=?&+Ao<#\8>nA :Jy]3Pn5\d0V=_O$^ OK]fŊ7;w  Y~&~IZKKid;8GLMxNZVM,%]U6 jlCMsȞH3']f K$q~y5sqk@s:~I54&[$3iv: ׍D^c6-9mr]Lɢ.c&]gȬkYudui4ClO//qz-KҾ]G52BG6n~0w2BRax'D/.E-nM $mQ-ՖTp=PvmWhӰoPQE|eͼMwjJL#uz] sy4xH b3ڬEXNmvmWj (i_NmAE;4i_(Oa?Ə;5\ ?a?Ơ???Qp exу+M)7OE((4Eo 7ۙT:> h(kv`a}şQ/$OkED[P?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2otm;VYy`Ŀve }ñnuz$zgA=-B72V}iiW:׆%-/DjX! 垟J_@8m>S LK`J aCӬR 8=y<j6C}GAEEaΊ1FES'cZ8n@H{+I&^[[fZ,6A}A dZF-lj+Hq mM£ Ygƀ/8 nFBđ1 v>WS@}VRo-ɲ]9m$FAc: խŲZ"[U1+I pyPx8mk :ۦc~ycw1(p+3s2,2#|uuv3r>iBM3W2~`G>թkگ䶽o춺Kl df}3{`-mp6 j(]B' P>QM?$Z- lQՎ:s^oj^ѭ443^'tBF$轸s~ԧm_GXfz KPZ7Tt6w7B;;iy6?Y>(^5IbU,3 [ZW_?-q7U]Bř.-+!?\TSNdte7 QH &q8[黟WԣNF$Y0AsۥP/GssI;}XhoEȺky1U: Y>hf9V4/$owp#3J 9c?Iu^_2(™g#j5 xyV!0+ББU mvb|+6sҜu;/s3y{"qw4Iq*6PvJPqЖfY} #c8IV(Zѥ* Q)l|p“η5ЌHlc 4[BO \ yl49V7}ʤ\{W7V5 tTc4/oX`㞴tbꍡa-K kcqE ]6H'\'EӭWݽ%U$71, s*n,\f/m$h 9y#4]zx"{k褗)t r{4z_֣ I#Vb_5KVG7+HpEK}.;;._>[,xT,H99hOaX^M爦Ǜz9R1۶;S0 }3qrc"VcRWr0`dw=1XkjwWnDh 8$-l8dFQ;Cq ^Fͅճ^4m)ȁ`@Xkogec$ktѐ#A/HVٌZkZD6"nF|Lֲ5V]D@-J B&NORI$$wKo(E(((((((((((((((((((((((((((+g)WAcpJDRJ+DRJ*-Q@XVXP}m/mf;e\38_A(:V?-JEYWc:H],q@A'9OV?A'@+Vu:;{۵ ev} kTԮ<`1yDB(e,{SEs k,vRpAkѭ,2hNZҾ?-EWÿ?_K8µ3#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / Ԛhy[lqwlg \ ).B`Muc^hBlX&t6k2V ^q:p?*5kx K[.|=S$r6A WǍ~/zu#R<ihW[`hW[hEolop5kv˫zTQ`\χ>; W iZ553]0Y]7 !vZWcԑ9Ȩi ]mtӳj=|][r}5} M6JVEAO >i?PRQ=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@,.-whc8#8kfea2 _V9ߥun?'IO;|ݍkxщ ImiHNw>2 _bx(%5ʠ~|[$siMו9qJ#F<iW[`hW[nEoloqZO]\/GU}:jߍ2vW*>o>tV^yQבGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^smC#.esHK\yLk濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭yͪLk5_ XMUp95w'VX'V[Eolor~? Uˏj?iOgm?ZΧȩJ\Hh=aRdD2U^ Nuny;[ۖH,zUufW1r nyȪگEU~S˔vN)LEq %]zCIC6?סמxgF_kliG (5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( U5}U k+ ?S?hW[`hW[tEolor~? Uˏj?iOܧz+ JǑQ^Eg|̽WGcydHbyd`1y<"F%U¢fj Q_]gh ~?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?q~:k xduP)qA5fIh5MXQEc ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( T5}U k+ ?S?hW[`hW[tEolor~? Wr/ZHcb ( zѬȹ׬ )|qA+x#NuBjy zӿjeq[KvQE1Q@Q@Q@Q@Q@Q@Q@Q@Q@4׌2:TidUr֦0*Š((((((((((((((((((((((((((? o_ozMyAJƇ:v'VX'V] QEc[[c[@?iO!k/ZjC$dz#Q*:(LQUoiVL4alfwFl7W6 qpnZDT,W.݁皱}@+V5UWbW_.]EBEWbW_.]EA#2?]uj9_?Ge_]?/ur/ʿtl_ ժ(i_/uؾTQ?ȿ*l_ }@+V3?=~?UؾbW_.QG+g{H"̫}@+G?]ZW EWbW_.]EA#2BUڵB3eb~R@(W袪133 (!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^lR&? o_oa?CTz;}J+|t J+|tZ(ұo-ұo-Oß4Aj/ZjC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( d5}5 k+ ?S?W[`hW[tEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW'I6O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((? o_ozMyAJƇ:v'VX'V] QEc[[c[@?iOW_vԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE k+k4ɴ: 6fg #QJqn_tSU Ž]S?ԯҷJ?ԯҷJ(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((// ]J+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݲ|Jݲ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((/? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݳ|J髙ݳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݳ|J髙ݳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ܳ|J髙ܳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?}? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܳ|J髙wܳxJ?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O}O MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܴxJ髚wܴxJ?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O}O_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s^.+kriW[`hW[1 EPzV>zV>sFt-]q>? WmHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\׋kwܴx1@z'VX'VLBEoloq:.!yL Y2 ' rG^,ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG{Hm⑑.2jpkέzU"Y?أ_*z+CY?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?خ2$ ߥt_ [?ԯҷJ?ԯҷJb(}[K}+`}[K}(?tֺB q3,؅''_ι?֎뫘&2ܼe{pt,N3Ku]bK'm7}Ew8T8r+JYbi-3>a=+ =FMYu핲d(NcҴ/.Ak}M?3"&U>a#m<⎁ԩ Am5퉆fPiڜWwVoq Up9Z}WᥒX\Fc@ tUNTk 9yC9n cL] YLEv,? .{m}˝y>TX5]$jֶ-w ĒM Lї GCfϤ]݄G=a4%I~E%}멹k%փ&!d,)@#2:-7 mDWdTX&R _Z]x*[7ڛR\RXh,Y{iyR~ }~"-OiE$:T嶎܁N4DLbyhƒǿJ4>2[Y-ssUfȰ-RDA'~c:,so4Nee9lMҮsSڐ\q֧()F[q_z7r^`!r:-5}ً!u[nO͟ӴiM4<Y}T0h4{?G-S8>U& GRBO6*B~qۊv_~ (խ /tudqǡ5oiQp֛ Frpyk G]MWku)dYLИ9 9:xY'o/JQq`8i}:彨ӖAF6?($p="Ė/=6;r,~8҇=]GO=?IO-Q7,hfaV'rsxY9%n^QA<{u\Pi6zwA6a/2GqkRK3}`{s2#BI\zw͠C{}&&[ $H'uFp=|wFdF@@})uil|:ut_-$1ppx8U|Io%?d:Sno$0Ǩ3TgVƮۀNN=Z>KkSwMџsRZK8O2Q$NWH+Rѯ!BoE=x͍ϩ^x/}XzToi^c_OO\fD_P qEtg ie_^XG5j:$X+{+c֕XZ0(S;qQh>[+k>͛h2e MSVv%;m:}>3_o/˅8]4ʀٓџsXڇ+ϳz7\㧽TjW$fբT4IaNp{Q:->{wW٢:nL5]ۛ˘t(^El)fDU^q O&<]9CJ=*Zq{[_OpI茅Jb:3/FZf*{p!`y+82{USXoEҚ?-Ulx'bܮC[Usޛ/ȉ>l ojCeeI\<,R&s zA٤-pdBiK@N=뚓Dԅŝf-dr+)ϭNxv.lU펞$sܐ{SWo&7rHvwq;!A {Zp H0==[cj)kws rBZޛwB `~Rֺ&dDɡ%$˼X ~@'߶ <^I^ > ~@'߶ <^I^ > ~@'߶ <^I^ > ~@'߶ <^I^ > ~@ήp9FOk~ ~G ~@EyB``p푚e+ҳ!:SQESC ( 3٣ (z ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PIAet(hqRQEQEnip2-8.7.1/doc/html/figs/snap10.jpg0000644000175000017500000012101713414613100013560 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qquMe6pΐǒe5 ZήwQa*MN7_Te$/k#N7_TeH=-;x+Q \wWfwQEEQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@#L W¼Dk4^oU/ †Պi~l 9]5":+f_t_@ Z˙875LRurK9%2\T$Oz !¬c?aV LyKi͹'MuԤ<٤b;8--.LV-jYۻhp,pq#;32YvqO2)-2t{nw,fd@(P$e-Dd J :hFcJ tEw_,/R:dV]b8}*ٶL}h[x r%~s ݙ^@۾aBCg%l0 ^H4($}j1gcvpXI4H^_0*9㊉di]@Yc6篥[RIii3m;t;\\*#2,e݀&Bʯ!l(ǭ9maX0 ODCkE#`t* ǎ,hZYH8=Ti(UC,NN P{u(rCrEtRnPCnl98) pPB`Pbm1hQ@Q@Q@Q@Q@Q@Q@Q@S fN31ޮT7V^@beO igY z00z0j srirA&23S}r}ꪢP@sJ[w%~5u?ޟ‚(,((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>bum9!ف5AV=?k}qOVe4mcGyG?g[{O? Կ罧Mv[BzΞl?(q{O? Կ罧MvceK]쬿/Q'#V=?h+R5Ř%6+F~*@֟-Q* !pj_o&B/i}]mQKo{8{O? Կ罧MwexQ\ VKkƥAQ'V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!s.to7n,=rmߵ2++#H+ )((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b "ǡ1HG$C+-AOglO+U޲4ãLD$j::tǮEt\cS[6+o҈ )' =ȭ5gҭ5Xu KG`A-g<ץ 1<;˪x~kxuv7c~͕ gk ĹH͔}okGH6c8PYi:BivA1; /vFlX^IZM'44fyy9si:,-n-g]S]t#\moӬqr:Ҷo_%B:;TWB!?88$cZkNơ,uw rᡇYO| kptQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE5S)ڙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WZy%WZ†Պi~l 9]5":+f_t_@՗"D \g e"~\X5]?jUniUVH ]OXpvҥ7q甹4.)OP}23֏"_54 T_ݹY>n_&~ƏE/oFڢ&6[Rh]0I,J$>6pcRg,4%QL(((((((((((((((((je=S) (((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH q}'5`ƔOji9 sFjG@^K\O`fcY.E, @Waz.?ſa3q)}Tf]m ߻[w &Et,ֻ{cA֓{mYJs[*kRe&ˉ:/Ǟޅ=(((((((((((((((((je=S) (((((((((((((((((u`7d>c[JᎃXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH s73R#rd98Jڅ<[Ҩ#&r.:gs&{(ʁo_G/֏ُ/Gٛ~fFw/..[{yYƫ9#8\ُ֧/L73\G|`h%QLAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U tZy%WOưDub_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐I֫`wF@ʁ#ff ="Hq{'FO%ޝ,Zܗ1]#as cEf6Wvur-9BnV NpzP^xI5r\Jrc+?qF.`V&5^7c3Җ= S5JWH̡=5_4bM;R8O,(X$$ 㑑ȭ3yXp$I%;]Ķh[Rez~g=ӄUr9cw8>\NkP_ŵǝ,ˠt-;j( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (L0(((((((((((((((((,.dcͼvkVz~5_>7W=?AEuҥG5+pQDpQVd2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~Uq3 XW\n^AP!)_سk+bORb_l6?OMQύ_liҡ0Sⱴkn?#=QL(((((((((((((((((je=S) ((((((((((((((((( ʹ_ k}ro\z~4A2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФԵK=&'k6rX(& O\"ФFi13BE<~bd>ՆmmmC8uŦgw&jqr)#J-Y)f] nPn_~6=k?N#Xy2yg9?qa~%[ӐZO<>ݸ5I%Ĥ0۴H蠓{7uFiCgpZX;#Ѐd{)/uA쨤BJ)eHzREPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\z~5>7[=? buמ>bЮ՚_wV_)}qOTjRl1Hrrcژm'=iJsҘl?iO R!O˜~D~uvD4V%"ب d c\ݕΫ5kVU`prFI&|3$X"K-$9֘?$oQ u$lL$HyOsFwjazRiש>vg6m H;~s۹ mBy2 zsY+эJKIt'oץbTiqc"\vitBgwڡ+GoVb6͇0sjuQ)+YUcE .4vj(;djj^źerz4a6pGzcI ! UDr~Wۗ{.c{mcl*9'WCՆos:~\wRBnp>E.t{մkxO!7qp_°4zU{Yy#1<|QŶay4O,_)U>)i,욕 qΧ{?l-͆i] ?[whmCM 85oVuku q$'\21!$Co˩[ݪ:(d:X)Oh\j663K9%Ugy X^ͥxq,Fgdn aO5&qjif#kd6Fh9=0;ԸY9y")ڤ?Kc9#2D/7`p}+BSj3Ha{5$˝nMג`8P>ƦNqWz\CMbͼrƊnc|#*y k*M'QL"8(팞5Rkmzɭ; j2, B`A[KTHn ćdcUvɾAERVuƭδAMэ@KPH˩ZFpUPGo$7ls̤} $rdB.2?u1?_? ѿ+ehF_ ?rB.2?='?8/GA A[/I  "#?2.iO= ~nSYsz!y'A&fFp%6Wr0X¬svsľ&xTad ᇥOjRlXMp.HG]g\ѲGC}"?/h?ة> > F~6_*O'?'?€#ѲGC}lQe?Pb,>~c(,>~c(? ?aX2R<*?'?žEڙO~C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (+>7[_ֺ&UxkuQS˯f_t_^uמ>b`@ X"_k"k8ϙ[~`v=9鬿k\SA}k-I:5J#q 3tf줕#>P0wVjk٢a`Υ8@Gb(ۥ}Gۥ}Q}Ro>˩շ?UKs}Gs}G_eԿ*_m~@_Qth(7glt?Zoٵ!/6aS3B=$((( -.YRC}0KJ`O ( ( ( *˻/ϷTK7 4( (L0(((((((((((((((((*5Mu7M4AA2Y=|]ס]5":ӭS[_ZjI~N\hrz9l4bs gEfxFG؃ҌO@!LWu)41DWXm~# w>Ԯԡ2IY:&ټ#i|С^aze8MFO. TeN>S5}NFaL#О?Ma\\0uj@/kdwGtYm5<x=@Y&7Vr)n_v+By /asJCÏ0늮?Bv0TA0wHxОj mnOZsYM,MmnDɸ@g  ohhuޝcr.[1(q?!K߲[$fUT#0)l{k-zVz"nбXk{)]ѝ)sj{/_Ӯ Ibm WCz55LJK+YbI#tF=hj&']ζX# 3dӜxX#x4fO{օݙC'ho2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2Thx_2Tr⻯.Y^$U0]\^ڬ萻ƒ 1, 䎡GT}Fò28r4x<#DMÒcWYhM7WvmO)7W#q,jivA@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr&UxkxuQS˯f_t_^uמ>b}qOU84mbmR8ȞQ?*ԁ؞35rA?Y&Pb~Y}OӐ E_]l\.86X;U|!S,&pHQgg,z{Uf<П("Hܖo?] nxc$8i?Ҧ%| J)~m>[ϼ?춿*+cVXc`h 9J( ( ( !)ddO4q$e20ðb7mћvj(ŷFos?6]:'$2jJ(((((((( 8.yr3z{TQ@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr5>7[]Oƀ;>࢈>࢘]5":+f_t_@ՐNdSA^=IE=.$BYmGB*{<g[`|'\Rer%i'QՏӦ=r(_Okښ[},@ O)O.=PqEl/~\C>oqèJ]&8 lc9)i)w]a)3 A6p8ROҠnMZux c2 ݰ‚q4h5+Hv uj4-/.].06 qNX / JT%?pB2\S5[&\\YSޥi95[̣4Maksi-Jm(h؃\b oO0k\b.ooD-w$$~dͰšmr$ woÚΥm}1`XpFݴqd躭g{}mrgi&Hr zCF^Sv67l(9qߛ'=5N~זo:ꡱRGQPݾ..-`x`L0\c5T#s%Ϲևחh_]O"[fU'>*ƥ։0&' }w kWrew-{gqٽ7wRvTh9$0튒×Dn_,B`}:dvB:K]K LW6q̷dګvOk;#[{-` œ8n{}]-KlҤ#@ʒF=ꆉORDø-sϩ@ yvE~,S. s;V業G\j7W3:EnNI@;%WJy,^NYc3YgZ$ҮuXcR<fBO(uu.bK+˫#L襣NbX{QkɦHikcnFx?ōS\4LHpTrNF+7X𖡩^]iӵMbSӡ1?r,2Ò`0ڧ52 `IY# z M/JPl3ʏ˚H*^]z|-p3f(8M7WgiEh>M6('<0c5+$Դ˫\Dђ:f#T:ޭ- "ܱ[d pן{^_E-gIWla`i0),7QxVbïL^;Z_oH4xT Ht3`FxSN״cYNXճBwi#!vzAwiSA nVbïL^{:MR! $ |p6nGQTt_ULtʡ8N3Z%ͼ,XC>VWXkm!]s~`I$hXi5/nP(*[S^A_(}K#cn<ӥ.vdCyVS#xC 9:sx_PD@1wPnhA;ve֢m5fȚLw01sX%I --؎ﴺ?x91Y[-ޞ\)o:Ȍgv+>qG=*%? o|.1mjN|Vp]$23VI Dz_>j]5d9}~O}̻Ӧmc\wq=i:Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr5>7[]Oƀ;>࢈>࢘]5":+f_t_@՗"D \g e"~\X5]?jUniUVH%?pB+ O\"ФxQ Rn*:U?@n'4M\FWmP0O>ƀ3n_&E۟C/oz[is4!1rWwx`I8C'o[6|nUef,'%QL((((((((((((((((je=S) ((((((((((((((((( ʹo ?]M*7wP}E}E1 Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*R/ JL8@jMR8ELdf~SmLP<1^hR_XJ`KqmxMvX5b%֨'ΆKJm8']mvF-6Iق#1N+E/tNIgl^3铊bBN8Aɮ[Zhϣf7.؄峃iCz_nexnd|@|m$zUgƕɧjivK >]X7[p_,cfqq֩YZiykŜ3a/]kuv:Hl5 'e*3`esץX/n?ޒ3dI^MRWiaDCe9.;.Z>VvW*aԕ`IQ*0܈ixm"dBA#d8qRxPv˪隝6jIȨ\Xk3H(6©q{4dRc8c Ac/H=6@t4oYji\-)[a\6FrBkcP,t.pbGSA81kk[Tf"ӮfMd.wdq-A-ܗmn38აNFJ6_?_нt<.g`.HܯE%οYGoq4B@2}A>Eaê5%;{DFIH@*K7^uJ{k[ْWHbQnCsOo=S\[;;V`PS''4y>w au`R2Aejoc n22?ȹNdX}NnnRU@`iFmPU\]_Ak}&l|&n~؝OF B=MVXӮ f}_͑W -?뗺?pOW̟ L=ȧRi|(RWyXXFݪ:jw3h7zmׁ!Y$]8'oagJĺuƨGo7TAcC 뜃9@4u{IXiIdynXX`W绂5 5Ա&: VKݪlhc?w56Jǥ\*;ȬL4t$S6_9>lEe}s~={uop9mlnU~9R3TMH]6LiR F㸜֣{m~+mJԮc(匼ݒB du?jͫ[N[ih&xpqчQ*u{bOkkY)&{ʫa֛ k{] xLE2O-)*͸Nk;R.oeV;vhNܼ`sGUv:ֱwim۵=VU M,uKk{5V")3sS88KLaA[;ScS;r1;SuiM JyS#к\Rֻ{cA֓{mYJs[*kRe&ˉ:/Ǟ޺ (L0(((((((((((((((((*7u7MStAA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФJBS)*VKZtR!uJ`66`]ρȨM/YDBHA=' ٛ~e(;_kh}Z1%h1%i/4s ח3`Ĝtƴod_iV FN ( ((((((1GS$wtImK~_캗[߃Q]K~_캗[߃Q]K~^&ȹ12F~PEPEPEp f|gdh]MOEG Nt ((je=S) ((((((((((((((((( ʹo ?]M*7sQS˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pBƤڃj7pdV#'Ao!)_J_hs(e4 cRCO]^) q/ 0Y;~[ z]BA/KdЩU$Lhj@Ml=Tdm1,6724ФQ*n&#<SF㺂Vw`9f}k{auq%fUr c ;TY_ Ԇ d GLdu?1v o `q ?ƺͰť:NɧmKqp[nH^VW&Ζmj&kauДdW_][CC7?&_*q];9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕZz]6Hv;A qp{UD4? Bī,jXCK9'kIVO|+;KئvmH\R+?[}&jԺ 1# s3z֮q"9_->~k4hMݩ<ESy|b)hMK:]<E/`{P_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\x:/s\W/ῼ?΀;>࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_ z~Ћg'C/ JL qH)"O)8R3&3LOx\quz>_]lu(7]~qt=GëHW'iU(((((((()LlHz629&7mP9oo.ŷSQ@~-3?]MEBHg^@bmg'AߵMEQEQET76N9P* EP)h ( (L0(((((((((((((((((*7Q ʹ tA2Y=|]ס]5":k\SA=Ae _7kV W_OjU~iUg+ O\"Ф(Ѭ-#5Bc[9c1W/ Ji`Ą򫜁}ܣͧծe[xF#;N*Lj1G-E=HL-cxVg׉pys/}.zL[b.K2-ŝ@.-g61K/ass#I4K3:vuh1o ne>\r)g8LSumM_Uyh쭕fx2r zg:dh.vHy<^Ny*z_?KbU73\%>T dGCXz.yk_j)./in~bHcAV0 ( ( ( ( ( ( ( ( ( ( ( ( ( ( (L0(((((((((((((((((*7Q ʹ tA2Y=|]ס]5":k\SA=Ae _6o.tk2*vsœoaS:O5]CۏP;EwᑑYV4 0HR8JTmP*42pN="[ ũin Kw`I 3 *;Eg}+t}+ts~2FOO0k4hx.x.wه_̿Eg}+t}+ts=e|+; ;_ ;_a/hYdi ]di ]f_#F'?NW'?NW}{54Vwӿ9f2FOO0k4hx.x.wه_̿Eg}+t}+ts=e|+; ;_ ;_a/hYdi ]di ]f_#F'?NW'?NW}{54Vwӿ9f2FOO0k4hx.x.wه_̿Eg}+tdi ]d_#AS*ԗ1ʓe~R@#؂ YjEمQLAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UoA?ɿrtA2Y=|]ס]5":k\SA=Ae _((/U_JJ? U-ECE%KOa *?gGlQEfAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_w~jTu~V( ((((((((((((((((*9먿}ro\>w0}E}E1 Vk|E1EuW_y/΀;6EM{kO)o(ǽǽ2k$)͊Mw$~5o^7rRQV;5 l+k'U){5/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/^> K!Y6`jEI$''vQE1Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s\W/Ͼ]E*9 ( )e^{//BVk|E1Et\Ka`th+y®?{OxI`TH-(eo9;5z0^DofgڼU@_t}_ Zeo}SE}iϸϵxWk}.)+7?֗Wk}.xO< z=w}iϸϵxWk}.)+7?֗Wk}.xO<e60IG/2]jW-ּv>f8ib=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC*MZ_7N(q/ sj(7PzoUN.^κyyvJ6J(7PzoZ坧ҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛ>+ol 8iYMrtA2Y=|]ס]5":[H j[."3a2 SҭHFeIL{83X>5DͨIK|I 1ӵ%~u6Wi(<'GPAcPmoFrFKz#i>٪:=if 0wrD+L8ZαbjO 8.p26O'Sꐺ6m {M7?.cF [>٫uw2Bza\ep6L:qA?g]aiZ±Ȳ8RDLmbnlԼS0.s#'k6*1FHs[֓U5KH#[&:Oy-&՗JUqn8#_gkp{ͫ'gMlwMđЮvZI4-#(,'cڲ!v0>TR]OK*@SFoe!$6 3cy9+lN thP4q2"7?6 Ha\m/~c ͕ &\u>G[eeH-Ǭ_9+M@Z.TcpH;q:,#~" ;Gs~5r[KmV?,M. };֟S[,X&y6J: 6/ﭴ)/.9@ Pj[}(2|i"u?7bΨ$'˟'m|)|:ѽAbN|Uqh&!nV_Ij-tecwNL HղO>`2qҐ,yJfj'V:X_vgOíbx9-K`e[%`~_,>uTO7f͝<Q}B;iV7dUvT V3U$ w\5 jaR[%+HQ3'uM2 6,.!Uߴpp63֗AsRVtѨ\ m0 GN?[Ivic7l #Vs6_[jY[E)LY9ڽc֛]Eu絿ԆKRhž*c?/&Qt:(Š((((((((((((((((((((((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mc•~" qn?zMr>\;Ut@6v59GOSQE0EPZ4@ƃ FOv;G5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5J<5?p~UkGhiQ[6֢ 0*@;S0(?nip2-8.7.1/doc/html/figs/snap9.jpg0000644000175000017500000006676113414613100013526 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qquMe6pΐǒe5 ZήwQa*MN7_Te$/k#N7_TeH=-;x+Q ԑE. sD0vbrriZm Xôo?He7}~ntF$d{ЭpMu)ۙ|KI#Kd *:a dDL۝2q Lw]JC͚HY(ýaBܱq"oR֮5'r2:{A3 %is"]c,wGz}̖oMN8VR$F@ OHDf= =?WAtWy9%!#?I{El.㍠p98ҭhJ:ʻnnO'օ (IRXgG2 -ٚ5 z*-$6~xrZvʡ#BRI֣p,F0aOJ.J.9 8H^f=k/nzU*y<Ƙ.;ӹqC*¬;3"Xh jͤ-olŽzӖ J :|q$IAIt6 PO2==wLr@,xRƅ%9D*`ߵL"T8 o w^N҇$7$PwHE,6Y  ?ld6fsšl(w AjeT( &*jɋɳi vX :V'pчh?tV^@beO &g$Bc!c<8''ުIY ˑ#P`u gW"TP0u gR Ď(((((((((((((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>bum9!ف5AV=?k}qOVe4mcGyG?g[{O? Կ罧Mv[BzΞl?(q{O? Կ罧MvceK]쬿/Q'#V=?h+R5Ř%6+F~*@֟-Q* !pj_o&B/i}]mQKo{8{O? Կ罧MwexQ\ VKkƥAQ'V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?ko%ΏoqèJ]&8 lc9)F]S[è-ݣ>>~l\I#zC\:v.5 `Ӯd{ ?U<{S[C(((((((ju5P(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9]oF?*>ՍoF?*>7莬WO+gwQWA2Y=|]ס]5":k\SA%XJ+8^X,k\SA=5?j7kV D*uOҪZ@T7-w:3Gl~)<=٤?qM V} qִ~?fwڢs5H}e4}/Y3n_&4i/*BI`:V!w<ѳ9`@ɠ (`QEQEQEQEQEQEQENjeQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WZy%WZ†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Uc?ݶѭ[4}-sVIK3U<4zJ]Z{6*r.>x`8LrG» u-sᛉMݳ6Knv8t7ۿh_A4/=fRMUȊd N=N+rMNQE60\)31)aNd`sBFutQEQEQEQEQEQEQENjeQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WA0כ2U tZ†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@S1)$*V,FA4+0ϩw>>k3@T }Z>e?ֿƴ~o>7M3e?ֿƙqw̆5X1@:>odѽM0 r;s@(b ( ( ( ( ( ( ( kS_2(0((((((((((((((((((((((((((iAcՍoF?*z~5 # Ar Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnN/vF\uH42T 31IJC>5}^).` cuԊ+7{lrpcК6OٮU%ݗpۖ=XSH1sv4$Q'qZfWԢtFe%FO)/"?2iڔ10ydB! lEo^&F[$5O,pDy_j/_%B:+%u3T 6aR@nj֮:{MZCpd[i9BcEPEPEPEPEPEPEPM~kQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U jƷ#L _=?†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@R;n&s+ jˍ<*?%?pBtbelILKFٚߕ ?4+P_6>t?zT1fTٚߕ |V6>m`$`Ҁ')QEQEQEQEQEQEQES_:QE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@#L _=? xZy 'g=?Μ9\ͫUSQKwp}E}Ej`2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФԵK=&'k6rX(& O\"ФFi13BE<~bd>ՆmmmC8uŦgw&jqr)#J-Y)f] nPn_~6=k?N#Xy2yg9?qa~%[ӐZO<>ݸ5I%Ĥ0۴H蠓{7uFiCgpZX;#Ѐd{)/uA쨤BJ)eHzREPEPEPEPEPEPM~kQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\z~5>7[=? buמ>bЮ՚_wV_)}qOTj]Y :j3n4aJsҐF?MGZ\LU #R!O˜~D~uvI%l;,Q$ΩCcq9k٫EeCc^M/kaW_jY_rh7Gt¯բ!M /? o&k=_qEeCc^M{ V7G$6?ܼ)=;ƭ /? o&HlyS4{XwA*+Z++^MrhUWVW$6?ܼ)?!Ma5hHlyS4CcúaW_jY_rh7Gt¯զjúM]tg ?#MN2ٓ*sM)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\u7M((!_y/ν Y=|]ue _ /EO@Q@Q@z÷oBO[yu8IEz*UMWB/~)*_ *_Tk??Sb(2 ( ( ( ( ( ( ( ( ( ӿVqMng/ԿEUQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s\W-]M*5h ( )e^{//BVk|E1EtY>*zi6?SR-KEEERգ̰HEdX۱*+NOxbYZif%e't4=2եEftTdb$6MϞ5b->sS__o_&HmS E9/ /G$6MXOW|?o_&QEj+Cm>zK /V(5?!=O%h|?Qi? Ϟ4Cm>zKՊ(OHmS ?!=O%jZ}$6MϞ5b->sS__o_&HmS E9/ /Ps$oiaUۜ{(Qw`5kQVfQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr;>࢈>࢘]5":+f_t_@xEMPǍqOTԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr4AA2Y=|]ס]5":?*j7[}OS ʹo ?@pQDpQLC.՚_z^{//7[}OS ʹo ?@pQDpQLC.՚_z^{//7[}OS ʹ tA2Y=|]ס]5":?*jbЮ՚_v֟m\SA5Ci6?SRQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@xEMPǍqOTԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\>uMo((!_y/ν Y=|]Mq.0c !U>ZC%Q"@np RStºyyjW-2]iSVoOK?>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? z>)A>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? zrٖ8u%;?>~fWڼU@_t}_ Z$Hn}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?+RjvCy~Y=sVU4}MkXǕZ9.ysZޅҍҫ}Mh?ޛY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC.?ҹo}x:Vs~D-Ͼ@pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5\ki_is0R R4K0WQ[$/Zfp08ϥTV5յ,@iN;('>_Qtiv/6ݍNXPOR}+4خ %p@tFX@dY)"&`6gi-kYOw\|jȆ]p,].+^ K[ @J. |Ik__1C3XAr]@9 '}m`+ QğQB\Y#tJ8yD5+ #VΊ7-Ğq$8[K1)twPQtыiXc}._cyK.PU[lUIڹEjW#cOԟA#ݼi?F$wRH#Ғ{Z( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( 9밮?ß}?΀;>࢈>࢘\5"S4νq5e`2Atve?tvvO^wf ioTug}3OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OJۇy'ڗl}?@o?I^h>"4kp@$o7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 U1=5upuV:[}ևhcPH<pQNaEVBJEh r rv |5?p~UZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZP(`Wc寥ZP7mDaElZaN nip2-8.7.1/doc/html/figs/ir4.jpg0000644000175000017500000002555213414613100013163 00000000000000JFIFExifII*JR(iZ)( )( 02100100p4C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222224p" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?GSWa#M\El 7ddu(9s4dspI u=I LFp'o{|Hdۯ)>}BDF,r@8T5"["o[>gO4Iql-c,[l aޟ_ŷUDd=>hϙ?]e[;u[-ړq+R*|p@<vJ#.W4޾[zo&-Fi *(USBXO>\Ɍ~"2ЀH?\?_-xrI鸕([Q5R HȒPOP* >@2܌cP*y$T}?w TU_'3 Hϟq֠ TUQi] >ȟ߻P*#[lJSgw?f-#!=h}|@(g nԞ\bV\l ES4޾[zo&%gt -,u̘H-#!=*٣Mgp['W? UF[or[ )>hOzo&me,'d?JESAh4޾[ U?Ð jOMĮ1JЫmKu¶O[?_-h}|@(m )a<s&1R x{B rh}|G['W? UF[or[ )>hOzo&8pGj8`#QK<*;(Vޛqj[λ<(Ңt?€4<v/7M(t?€4<v/7M)Dq8' e[;tFcY;lc'N? YFDj>jEV[Qk֣Qk֠ 4UoG=?ZG=?Z,Uj>jEV[Qk֮w^%écRnVmYw1=(sσ?r_>O:+/KVѬH$H.u 3ՁoxA@$v.QTh4޽[ U?G>hCqi:0FOjzo&GES6z@/vi7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?¥;k|ewB{/c\Bxd0v_ҘM\M_+5q68[ yÁ5o+:'t ׍-EѴS?kC$C9 ksj B"+rXC`FHnAz>pH0QHeӱҮ 6tU5wsmA1š<a $-xVX!q#1ycj+Z\p `[a>bu^iwx7# $%Ew3nmӱ?Pon4Wn/` d>n:.獿?MGq/n]6k0_9 $RJ2 ?B¢ c2nSN?4 ^w%!nS:P鶭<=`?$+o6?S%.r"B[.{Y[kZkӲbB΅##*f~{_5J>G1v[=$իFo*FIy`Ӷ7g5SL+GhFX\ڽ׮ζfl$W%{aj4v<>;af\DjRp[Kxc.8o'#.GK$ï?s\y3% d6vi{K68^P)9$"1NrT0#moFp2 2xVlEq~6TAd Zg[: ]ƶtkXL-Xp܌JWmřO0uAM, +g=㞜ՋFo+{.fFqcqg\ZZ݄ikfvuQ8^qsyqMaˑr o۠DWے#o;u]=wѦE,QGSU \\yPbpGީ7Lb=L?!=8\'ԌzlҶ," x2 <ƕާ_c3ܞ`k2>:8^ְXm1,85 gН(8tfO?*<` qu^us[[K[&+nbQ%ٝve8o痡뺍c Kw% 7.X8'7`y;ۼ Ἔ\UGRlda`p2p:{viw1AuxHk b9Y~ *j,3 /]HH2EԏA"b|3G\. lW wWlJD*4&r{&h#EpUl=vOR[}fS{QQdh~]TnQp= dNL @1XAXRi.|[v\ 9e1O@ =a(PH 5=~ҭݥDv!\8Xz?/wyT6ϔ:{]U|=6%vJ/P g5Nӂ!چy7A7OXd8C4湋fԚ=h1 o0Tbpyc6^]CȁaaHTEQLG{z>D:x qcWӮba7ːr8tϽ!V֗0Eoî~p^\X=ۖvrbW+>`^QR`|Mg#͡.w2<gz>hrKq ggNN̗ST+ `{S=smM.^4kAʜ-_ΖOK{ud|DڅLBCfxxwP3$lVR8;LmCxhewCoZ&"pq p`GsKv_c Fq?jЄ묿SbDDijs:2M]؟_ʪ+7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*}%ŤYd$c~`~U~jlo@W+V>wBk/c@j?ꚸ-Wmj,o`lNSҀ:PؾSmY5֤om{Wac8eu nMqEE8?PTb&vWwkk!8Hw+ǽli6ic}5/S )a? =rO_ƀ.Hl-m溆8WUs'֢򗵾 G?熣MH0Gj6 <1cEusizN@>$Ͻrzd@-h8 %?RO o$udfS]: ?熣U:@nl'كOޒB -}x┠ıGdic+-ϱ2=rO_ƣ򗵾 @X;_T7dd+1Å{wQT+K*r$f.pO:BP TFl *=ǵ  ,^X_ih(*=}6msp:hH5!Fjm.AOIϽ@0#4VOMGϽNYJAeq(N~4)GSS<[kky{ƀ%uX%Ulld4^#DI=6ms{NΥZvR0AN+Ld[v_8߷b;ȣH"Hc`S򗵾 G?熣⨸X|nz{0KnؚsϜ='r H\FigwAɹ=2 /a&;3:$rXmI$U( GQuԃr6FI?]_RokYf/j0F D3l \o7P_'lRۀhz+bHŦ,ہ~PX]\^S;nؚsϜ='OAg6?>j)q3k;܇T~P jHwu 7r6FI?2-;!;$h[Xo7>CHЭ12M4cjo){[z,? yCxj?_*(Z0nE#+c'VŻbk>p8؟jƊʜ#}pIˉ{Y7&8"Vmu+Թ_4a%#砧j: ZM:FqLu㠫>PQTڸ&֨uԀO>$sT+-ϱ2=rO_ƣ򗵾 @~@_V] H ykRd$`ΫyCxj?_*cEusizN@>$v׋|q?,.渽7,A8x:ZgwAɹ=2<5/@-- !"T`NFݨώqj}\#P!6Gep9$$RO$Z\^ ̐2yp ~K4>zD{zwڤq|Q4\!yI(j}.?EVTq|Q? 4UoI>j}.?EVTq|Q? 5俴?EK^?w^ƏũE WZ*ସ;aoJ;緈_jP^#b; |2Ā$c+K yior,+TXJK{[tC*eUB){[z,? ԆKc/_/)M,-V)`:dcv<5/G?熣Ԗ)aM΀qQZiZxaeemmynsQyCxj?_*( GPvVm N*](Z*'ɳv1n1wQTyCxj?_*'tbߍD*84CrYH>`c C[ Pfn pȡVp`Puo P,qty@5gSOoU>'>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[quo4syrs 60)k}nH׎ZuSfYJGe+V>Ejl?pQE UYlX3liM1J) 5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm5l3)>t19ᤍOz9(ofYJ(#nip2-8.7.1/doc/html/figs/snap4.jpg0000644000175000017500000044632013414613100013512 00000000000000JFIFExifII*JR(iZ)( )( 02100100w#C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222#w" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(;mSL;6ZV\̱BXOpWwf ?f=K_Z<%?,g>]_ZOZ{G R}/(.G,g>]ּ_Z_ZvyG N}/?E=}hּ^?.Zvy.yG?!tӴKp=k_Z<%i>^?.^z篭y/-;O]?!tyG?!tӴKӸ篭zגӴK J}/?Jzמy^K J}/?G-+O]ּ_Z_ZVy?iZϥC篭zגҴKҴKp=g_Z<&i>]?.>z篭y7-+O]?zϞy^M J}.8?hϥE=}hּ]qtѴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-_篭zדѵK?.Zwp=g_Z<'k>_]-zǞy^O B}.8?hZϥE=}hּ]~qtеK/.z篭y?- _k>__]<_ZZu}E B}.憎.yG-]~qt\X֏=}khZϥG- _篭zדеK/.Zwp=c_Z<&k>]mzϞy^M F}.8?hϥE=}hּ]qtѴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-+O篭zדҴK?.ZVw.G?!tҴKp=g_Z<&i>i>zמy^K J}/?G-+O]ּ_Z_ZVy?iZϥC篭zגҴK N}/?E=}hּ^?.Zvywּ_Z_Zvy?iϥC\Z֏=}kiϥCi>p=k_Z<%i>^?.^z篭y/-;O]!t\Z֏=}kiϥCg>]ּ_Z_ZyGԳK?.~z篭y'-K?g>]_ZOZ{Gӗ⭐g{Gp=lH 8כ?4뤷>LOA8k@("Zy&&6"j7K-cG+6|Ck$kRKXꗉicOp@@ IUxZ+}7zw9Y\ZB(c=G =8,cԷu2ClQӜfg,vs{KHеq0vf/=C+h OS~/y>n+z_ϧquuqmp"0=ycZvܛsO_g=ܖ[J@)'JҒm:;7ق.}1p8py&x_^E*pї;WAjĚm.[KIˈr\G&Kv9 }& ʶ@$U1(ٍ3d`73J5jE$Rpk-@KOhvncFd7 Q}N?#Q%yVYG1N\𦽦YIy{46{ldpWYwXE]Tsorڅ^R۷2|(`Ǎ6vxgC;?(0HH;aA''AG=MO=gFn~֝ͺ+kavo0nvqJ}Bz^^Dlo&Hr}H=C n>`_yڌ%0C3j=: N][NL'in\r rgk]]~\g?0;+Ⱦ{5-RGp{o[Sp֒C5GηƘ֬A!(`^EUB0)8 W83_܄hlj$8 BkGP k[76+ Bs֦_㶶{Vzޛa6Xm˱S#s=5_jm-dkYu֕v^B(''?9 vz, ZV< |vZޝb/n٢8S56K_ҭB;9 ㍻Cӽ.[Aͭ-v.x. EX}Akc޷X6Xm˱S#[IsewtۢZmw;exwW3=ܽI5 וBPNxPn47{<袷ݱXt9*@iL }3^ . lGwlρhfLM9ΈtR9>si7do? [y3HdR=Hc/=}dnݏV:_|:S`OX y$myqXxoZgӥaseB:ZZewi*=.<J/Wŗzcg^\u%9].rua+G2IQIjw0YK{K>s|b7RO]iF{X/48 9VN4(a[me± gsu߽MV7Uu-nQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuKk <=OVZz$̫'?Ҁ.7o2tV$4S4.%VS9K8!";ՙqq2a@ b\#eΟ76FUאڵ[5=6\-FMU$bEF[Ҽ5uۭ)ms0~5\(&2Ź82 S+fV#fv9aPc1?QľVqიIgݹB>^>yeM^cu{߂.t[&9wԜuW BtALz"9QE21E0'=+VRJ=+VRJ'e7uv̪2IDqFRm;t1h&OCHg8@2~gi+Lbibh\nתYS.!ԻRTu'.G tiP4zesRZ-.XvÅq$UpEMhx/v}*WpՐGr\qJo-D %D:.z~x-7h\,*H98(Oj7ELӶ8=q=)RJ=o\xm2klt(P=َMsPE'VH/G>!AֹPFPGZM-bR ҤX\͞@>ՑEik:D2',Ӎ/$m9|sQ<: 7S(' 6y #9ϭ2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(,It".Br^j1H9R{P&E#ՆO}t,Uh (5I-ؘ 梺&ǘ~JKڛ^WxAV J bF[QmQL c[[c[@ ?-PdFK-i:%Ӑ22W!eN{37&:&(G4PtI?ͪj":FI' )8v'Ү6k^= Dr3*1@X/͓+L gNʜdsj-wRKi#*јmO09& o3GHѣ A3G<15hdOKF+6йX&4f0Z[CFPΥw-\Ν^i7wc9uLai3N k{DFec 7$X,pr@Y\rsS9\ܬL\!PҊF?xW>5Dȉn"GeS+YG#5 KX&3#s-,KąeKhXqY-חR9i\OSQQQ4|}= qEl%\~_\ kmeB餍tCo,/@qָo'I3 )p>]'ޭůp5\X\4jȠHq 2e؛FKKnPX@9#8izC]岶iY݋mPHubFq9sW-v|BΫ`:|`ccxTH%h6]0##&]N~( ((((((((((((((((((((((((((((((((((((((((((((j O+kھ&hG[QmQL c[[c[@6YCe?d}뻃ʝˉ#PN21xJrBonOy` >$$dRn;?&(a1m*Oaak-Ƌ끏W|0,W^]>KHV ̙$9N^+y:foP0$m/:NŸf;w;g4Ci7@݅krW &Mb-m$GeJG \)P^xۼFVx#6r;m, 9on1s&pf9%ĬDX(UԚζнiC BɰyRu?!muoO  8"a1<'mgr\1o  QKh7=qm&wBӌCAa1Qx~T a<+amV[Xom&-TiCAG͐pSm}-em I &)LiS5 ,:]٘ϙlAz4ѧͧ]i.,]D0T7{Ǔa>L_ 7;]acn2  Fj3 R)hĖK( ff-/4oh2k`mxd"8+O*+pPU[~\C\qȩ*29ߐu+jh#U2-Rf@gYY,]@c7699qXR[7!lo-yiob iN (`mc؜>_]Z,]#"fr3~RYaim6Tb;`gy0Ogy0Ogy0Ogy0Ogy0Ok{_,?ѩH[=pBqIoy.>4geۑtk$K#p4X6FGnG\ӯmƚChErU@,pSTu7Wo܍ÀI%UB 2VܩBi7fLi(0(mwVOܒH~ETbHKEQEQETbHKEQE ڐ@pKEQEQEQE U X( zrih ( ( (č#,H)̄(1(cXAQ@J}QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVR;'ʄ~fqsZZ]8I)K2ztֹ&i|tua(  e-ޙy7qu*?bO kV^G?n#[ K?%Darʖs j=I^5_񩠏vޒ?RvLr+KWk[ElgRGJ%K=KWH[Rp|]#mẀAqKCx"W1/ebBfU#nA#wǸvPhK `l+zT^D" 1즹TT- 'i! sK[ &Y؃q(< $Ӿm|#<덹|zWB-կ 2[!TD8  8Lkڕvc kkEp/oΕwXon=jeogeF!E]NXobzV>zV>h SŒmQrEu1‘j3_%2*I8mǯ8sT}"#f$UT !}O(Tq|UO=GxڤK⏵I>M9ހ:{/ K(Z2r(U&aIj}.?z߃Q=G~?I>j}.?z߃Q=G~?I>V$QYQc,NgzrsV&Y(UG& VTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?!M0UQN>tcDnd ~'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*!'rRs?RϥJjdxX)gRĜgGb)c*#Tq|Q?>Ǩݿ?Uc*#Tq|Q?>Ǩݿ?UcGKcPj}.?>'\,a F%XzH?5%VTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?7p]F̣@20e<A j}.?>'\f?RϥVh j}.?>'\f?RϥVh j}.?ɸҾx&U(Z(09qk~?RϥVh j}.?>'\f?RϥVh j}.?>'\f?RϥVh v|ӌrZ/Ff\VƧu]-Պ(V("XVXP+g`2ywN49ٻv.3\wfkY(B7+223!sèoF[c88mR2pxQ߯ՅA2ȃ<}hI.!+ೕیrxϮM11O SxjK+?\yH3 Aө'>l\#oV4z¿ʥ|9cܤi4u&V~ؐ_}#2 ~:i'NH-9b |g׎/uGk=,lv;7 `cn ^_Wru[* ﱺyf@sA։|U'-$cu;7̀nWSq>b}cx6zQ/u7k=,lv;7 `cn (ﭿW:}SA7Uoad-=I$&j wk [F$e=e{ip6? ]Qtgi>W__][KD7??&_*9q]=|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|14n_U@K$*~lm'?_K. FdS[  OqY6,H2KsOZt- /W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _nn_YDGBs<E1SS7V֡*Kbe*:FSKqYYk0٨-{slm#hGkZ|U.I3 ]]8rAd#.VIN <зq?/o%SV՟[}+E͂\%bI )'i緡-TMkDԑ b0 ~5y뉩I{5b0n21ȭmKMDQ̂0'4[ EPURm7jX";kz?nZo՚]" 9"jͯӇt~7S|憎?3+/.%ϛLUh/Xr⻯t?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.KV)#! ţœpxlDO `Al1Sjj8FWϴl۪@u:ҨGr` wDTV#Ij憍]V 5yej?zV>kFiFxȲ̎ppA=wY]Cm3ܖBl~B7^ϭ7F*[[1m=o?&hIg+HFp3ߩ9BVЬ0<% ?Ex ~g'w1>&hϙ?]e[;u[zo&[D[otzbX/̿oo.hC3X?!Ih}|@JWSp$zdU5S4c^M/D=|nh{7G٣M\ hmn@W?8dptP* >ȟ߻P*#<ې} cQH-#lJEU"~?G EU$[wyQD€-QU~ȟ߻QH6Bj֑"iw2f׿4rh}|J--ͺV=1\b-U !nP[4޾[ o98==F:M/٠ϴO@f׿4}?_-*6X s !nP[ tU?G>׿4rh<3R}?^M*٣M(6X sET6І*%fBl~Bzo&.QT׿4f>>_0[?^Mh}|@("|ۥc3(6І*%fBl~B-Th4c^MB2}"-Ny=ğjU{"F@V9G!Inq0?̿oo.7'" /̿oo.7'" /̿oo.SPfc ?XhqII9'&Uj>jEV[Qk֣Qk֠ 4UoG=?ZG=?Z,Uj>jEV뺵~~S)g9ǨNOjYJ8Y=Nyӗ,fwW ։[⫮kHK4;?V>rWVŪ*٣Mf5rh{|G٣M\?^-h{|@i;Df4xGޒGd̊EV>UVAhYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?i7?J \fu$0Ox.p;V(Xc[[c[@fk 5"+3tvI!_/JcK ʱQ#ʧ@H+tb7336rkODKּ<G4|6$swc~n|ֱ`$ Ŷo_gDT>$:%h[Fldz zn}W la15->9&X^ge}Iŷ^Ny B9 sA-+&IRw'w<`E++닧Q-"" ǻfynggH4hpxQُ?Tx͌WN)qۻe+gh*}4@y ƍዾќg؏Γ̻0M흒EA6۶"v֢ݥ,f2Wkcsmkʲ٬`T`S)SO?TK.q$_" (#k:IN~\ #s4Ƥ20(CE̿Yv@\*z TY4rJ1N^>fxF;y&OjӨ1-QIz1/f^{_dq/ʇqO5~#ݏŰ= Ac*k=.?5m#8I죹 jD'K^5Ҽ2IJd)(9#Siu oynʒ'??y!1RMZyⳑp`0 qw#G#&u‡-K'GGo{M7>n4ũm^wMF8y6)ֲnWP@}:U5y +4jWG{R̈p[i8|hl>jtt+{mb0I=jЭZߊC,Ӥ{+o00 19*k_Z\^Am-塸%ak q-Ľx(-'nY2Usө Y2Rog Ahdi#S)r+}D-H,%CFOaUy˝&Dp"lv 7?^iT6'Ͱ xYCo#?7kD 5}&n$RIG=ֶ<+pU`mݺwEvcGOgSj4n7ϡio?B.umʆ[#}x yrN;ki^Ie|f 9 1{ 5vcGOg\w5N=nL{Y2NX8=I]nЩN4/5",` 3yɮ_iBYId;o!1$U?֍"4kY$(i2rp j]Q-6+kiU`T@c)%h8+!J#6Qcsmu;KEy5xEJ0pns[W:u59X@.]V1)v ;qSZ^W%_cP-nⴸ_p*IɤSҠK)|lPE'&_ZO-:\"%I*(Sr1֮ $N" J #c>Ryy ccdxѕ"ݤv$DV6հF@8=EbƳ2Dll?'zˎwao=(EHT(e9uku?կRC ؟_ʝE1 ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@H B9l g1θB?ٿvKG\^!KΐEzV>zV>kFiF-g<ڰ|)R GKTO>7?eGqet.D" 2pz Y?<<5/G?熣B[:jܧB? q Z^3BqS4U @ȋ"qi 4^Q_CϽF>Jʱ@ޠ?Jd#j%rEBۛ !f-KOR?L#QDXj ϽF>Iyv3lF8#`^oOe7y{ƀ%OJREn@ y{ƕ\%aж@\6ۋ2H#_薺]]y@Ioݶ 9#_\թ%3FRK)OPRUX20AQ^?:yi@o( GSUA g M'f&o'L𶟥44 )cAG~EYV=Le?]fREQ |S|2A ;(ׇoZ Ѽ &9o~*|/nUA qǖ?熣UXmy2é@[R6Pï_ Z^3BqD9sixz˦~HX11N(`cmP8q~P_vom^3l1jz|:m֌`òUVֶ%Λ eDnLܻ'椱y'ۿ>_( GSUA g M╺'of&eK uUa&w}j9sixz˦~H7QTA&$M'*a0y;8<玦~Fߵ?ϊoQU&SMJm3ƗI E"tak/K֏ܽƛAk+ RGTXQTYu\EͿјȚPGj$㡐鸜Q"\^+2韮3@1x'D76mn#ǯ>rIT(*?熣xj?_*-[r EOxn."A,l j8cX㲝Qz> RF)"kVfU-PGk8Ғ՛sB09+94}_ 8>/m;dm7O0Mj9!Xpc֝4}_ ZmV)+yp $:{H++xa%V o[}O(Eqn1>U>Tq|Q? X]I9 u82{OzUTPP0U'\}O([RϥGڤK,U'\}O([RϥGڤK,U'\}O(0kWׯ->/ݷgv3+-/;חTU;7/Z #+-ř$\ Z_uowILєvSt'K S:NM텭_g_LI+x籶RB`T^XQUzciK;uA *Ġ_~Yy}M @( GQkimcgkyc3Qi:C{aktS;|U2*?( GQEҤM*>\mlS=p1jgkgkmokK j (x{[ݒIO@<" L(^ZIu8 }AU>'\k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4g X՝FX}~S\~!Kκǻ||ӌrG.:wv[SXVXP+gVKHW䃟p69 ?s?[dl-nDql.?!) 6ݖߏOEvW̐ď$&PsяOA1rM"^3-S '(lndޝ>qхkB۳s]H:?1^]+nmΖ) Dau'sscop˴mpօg<8u}t`kB۳s]H:?1jօg<8u}t`kB۳s]H:?0 > K* 0gߚ@ZжR/O h[vss]ߗ?F-Q@ZжR/O h[vss]ߗ?Foyq `ֲ#J+jUkB۳s]H:?05m9.w~_xEUkB۳s]H:?05m9.w~_xr^F@7QĎrc?X h[vss]ߗ?F-99ԃ h[vss]ߗ?F-99ԃ{PȆ%ITPU nyqu օg<8u}tbtNcȹ;2cێF&kB۳s]H:?1S ?:ǘF]"}~UYg::\жR/O h[vss]ߗ?F8~ut%Q0^PGBH\5.@/>J  D{ t$ []M#kB۳s]H:?05m9.w~_xuz~s{(cM+$($ߊ@ʭh[vss]ߗ?F-99ԃ h[vss]ߗ?F-99ԃzm{e%35 nyqu օg<8u}tbU nyqu օg<8u}tbW{0kYDO%Ï4ִ-99ԃZݜAwыTPV-99ԃZݜAwыU]/#}Bk ̊(bG9p1Ҁօg<8u}t`kB۳s]H:?1jօg<8u}tb?9L"eA(1F4+&1MR}.5m9.w~_xжR/OseK^6qSGg皭yw{᥆XΝ<.$2*(`럺9<:Q~v h[vss]ߗ?F-99ԃ}b7:t8~8V#ú_^^EUO3EW\ї1ڝ}/t3kB۳s]H:?05m9.w~_xE!ZжR/O h[vss]ߗ?F-U{>PM+$($ߊkZݜAwс nyqu Ū(ZݜAwс nyqu Ūq2[;#Fw(] nyqu օg<8u}tat=6bdQ"`#J@ZжR/O h[vss]ߗ?F-Q@ZжR/O h[vss]ߗ?Foyq `ֲ#J+jUkB۳s]H:?05m9.w~_xEgKC9du2+9:5m9.w~_xRiZжR/O h[vss]ߗ?F-Q@ZжR/OCs%h/̣kݎN?1\_kWHem -99ԃZݜAwюJ)u/ 7CQ)9 ר֘w_"LDd)r14}+_ZݜAwс nyqu w_"LDd)r15Uty.&[#h6;KN={KfZݜAwс nyqu Ū(ZݜAwс nyqu Ū K9@ kB۳s]H:?05m9.w~_xEUkB۳s]H:?05m9.w~_xU/#e1V8]m9.w~_xжR/OZ*m9.w~_xжR/OZב}졚;xW2HPIǿִ-99ԃ$1rAwOOO[(6ŒV'o~3R7݌ϸ~1R7Xobb,olorv[.ݸF6\~C:W%gIĖv!$s1RzmAҐΞYǨi6RX"h+hz|Ώ}鷘K:|1*vFGִc]Dv\%XpYԓހ3|\K+pF sVn8^{pGUN~?5y2\usY[@u5+ /\k(kKܒ3Tf4+V4~? ǧXz柧YEXX䐠u7?)yGۯoxWtBEfƐ Te?+zK6z^eE`USO|ݜncSӿ^z#F5gb+"I֢K[-F?OcnK-5k2_:{~~?ټAAM;ǫ<)~ڿT yXVG34-r{SV-s(aSӿ^z om-1ES,-|<.j= izj^Z͖(a#ҧ7?)y/-{2Pw98nʏCG)该돨Czuk6(G{P?Z ,[_zu;W/٠,TN+mmrz!:RD=(N}OoSN{U?:\,u iv.4r{I_V m)1 (aSӿ^zٹRJnG35hqjOK5Ԍ1/+k\K/\bV (ۧr?L-^,>#xQ2=yAJ ;V% g4;[W#, 3nMrMlM4A\G#8y'iεn"iZ'ZQ<8j.[?;p}3\r%ơ,c/\4)ukMqf4Ʃ1_/4'?8>_j9>7?)Ac~me`bbB{B}׊͵qf }ƨj^!ס[Ԃ@o_f4,tsOլ V,H[OrHP_,OgwSnF>65Op>f4,r-ZK$v˻92ƾMo9Kk>}sT?[?ƙ֟f4-r{SV-s(a_25֣O4HcgRf4-r{SV-s(a_3k)ƯxYbg`ټAAM;Ǫ&,Q=.F?}?xJZ/?!ƣֵa+ރӿ/u\p}oSN{qoNa(|au_<\uk}E֭_].5 t/<6l}k](X}oSN{qoNa(|au^]%a'n0p%8ty|sJi9w=!4 Yf$mNA9Or ޕu}rGOf̩#!O7~x5 w$#=딗ZFQuKݻ;Cr;OV]jyG꫉G^99oSN{K5 >]ZEqDt~5#R[_]i:sяsؾ i/=GټAAM;ǫ~ߩ>shԁf_QQJ][?OV1[ı!m=!@?P<#u_]ilr-Zoą$ ?ټAAM;ǫF|O}_/8(}N]N((k,{.[t #P{Ө^˟O4iCrz[Ow*jet!8L jxw W?wDg5FV>f,-۔>.zr`ZQ+O|St֧7?)yMcwrQrZF{՘7}hyS(.&&5լo{/\4)ukMqf4!}J<_o5 G?>.}ӿ^z?OV1[ı!m=!@?y/p/koꚐtGO/>v&?gcSi^մi =1rxsc0gYo#ڗQ]{s~ i/=P>> լ<آ%9Bs k{WvqjZ?[Gb^kK}ӿ^z}/\}BӫXyE$J?r~A%":=tX^?2O.cÕ Ɨ\i+24%9L9+JE'xI5D_}ӿ^z)uk,r{([tʊ޿x{ū0Yn];ד^4f4/4r]Z*n:2Ŀ٣w?/h~ i/=P_iz桧KX"huĿ٣w?/h~ i/=GټAAM;ǫξs?fĿ٠gi/ize +C1W6{p:!Kδ<9+6h^BY[ӧG.:Պ(V("XVXP+gݛLT ;Y6\ m`}J3uV 5۷D1aqHe=3H{wy2,[/-U$=$桳YOhkfXh&,ԩ(N9*-SP2-V#1$&<] [O6b%pjlS>ku2鑱ԑ_5sf66THò?1Xi EhGn8QR;>|Ggf_HVny~f͟?vRi֝V[V=v3ܥG < λēK놙U[L_M]ƫck[XMpuu-/.qO-dŪk_zc j9n2 tAKG[n(w;_VqM׼ j{^9le!CXzl, 1y;Dx g@5r3+ڭ,LT!SVNǃ.\THNkw< ޹.ks2OXd ٍp) T : nl~W-wg\EtF#a7wjksdN*qe5NWrx(RMp:[5@a)c9dU\V7ڴI5NV眏(1hϻ'V<.o$nop{㠧x{6_g4w0>_Kg=j2x9xD6e'?ֹ)uf<~fFHlM[)#8V#4y2j14-^Oմz^m:o/NoPnkO9Mm7r~UtO ̍>qXYwv,D;pHx)B4`NiqE8gW?Vo>hg c*{B+R4"Iҝ8"zL1"Dt}F&9ϧ?ʲUK}Ja㜜m>}Pel20>t--4H@5ȧd+ q8?Lf43N |ܿZq}+.⮟7dlbVA#4؆-ǿcnB~>RnA{u*3@2>}ɑ"oc8=0p)zi xɧQ jqPdb?Vug5T*nc98 TI BZĒ=hbB 4=K@֚ ||S 4¹뎽9;P!BF=6MBs3{$˖:f6$Ҫ>*֬f3wP*@;vŤy7åz1VF2FNaH6;H`?vVYbJ3Ehdv dFҽZWPEPEPEPuƉh7c71g?N⎑!KίxeZ Ìn~FӸR73V(Xc[[c[@fk]Ѯݸ! }J|5#4#]Uv m8n\~C:RjxҼ=A g8?Ur18v @Rj̐ʙ>N[x?2# Tp*.sP!tKIS հ=)߈ok[^#2R@$Y\ ,8=k>#Xy >^18dsҰ Dg@pG;Rc֬B00r٩5hɗjE*!*TJ&ק^*t.Zӏ7=?p3g+o!Z'ƌAIyqQ <2TrHtTe' +n ynǫ&STխc }RZbw{Ⴍ=moR剧gk"ue#s?ꄚ 3cxU[s'WZ%dDń9[hldlSXW7ԧ`X}ݣsA>KF𾣮B?R1 |ƚ61gmK@qoݷ#pF;*՜Iq׸7ܞ3!pՇ$OR/)4OOlsقc3W$rzq9}EM5R<ce#Aힴ.pzc@Dm(RF{~o'ғe$,#jE1LV)3s~[F?jqqOR3JaAˏLR23ޗ'84z~І0I{~JI~|SH$uڝQ&GGZq7M' Gi6fAGҤ^JhNXҗv~ 9ErvFv67l.?!) Xvk:{ p@y{p8<VϗP6t5ZN{;Rb%s, L:X9?֮L3~uZr2?0nUVj/$K@_Ϗ4`w [Kr-du Ut3 0#^;Y֔N>?m]:W<{Om^Y:uŤ1MFEr/Еr8Y쵠:lʼ#,nI_,R+׫?~7llapy _3~BEXDf),n%vX 9[<Ƚ3RAc9_ c㊸(2>N郟N+`0j!' 3bA‚}O4M@(1R!BF)\6:#ʫaH.q]J;~Ζ?2iFA$֌\Pчg_n[dP=6V?m*˔NmV9OJvV2T"_+XGdd&e[xwK ;t*Mbnt+hԨ* JP+K :եka97$t\:k<4F>L[n~)}2רW=F>CIK1ZBg#MvVyOiS^^ecT >~%= v5 `ݴgTKpZr-dSp\7xw1ﶕT#_)fA 8@H.w#`N㞤v?!fKwL*ƘemIN>֦+&gR( ]}k{y7#݄@cۓ՝ ԣu*WQАёI4GG#0 k{PymGc#؏^kYM #05R3P~aVdfwOPm[k*{hu㡧9 ?sw~x" r303ޜU8cy  lI_|TD8I捹d n3 TN]q֑ ؃A·dwEA J[`gדRSo?7\v4@?n~4$UO28|cӁVbP#i%Kzz/˝i'#9g4q{daҐǯj,"2JsNaӌM{NI>6p8N špyT&pxN-7sQU9@Mi?ʘH\HX{npqG0=4HE[2Mb>3~ptۏN=+u&n=uI ۷?x[N8!܉W]5ỵHii+ ;P)hg#%z7_ dFҽV ( ( (; 4KAq?wt \fu{-nncv37~#B?ٿ!ݷEX=+VRJ=+VRJ|5#4#]Uv m8n\~C:W+gmkn cn1vAҐUgğ֕w76c;v>î;Fx]K ⌢x)f#s@ 𛳭r 2GOR k[YAsmm VDzF#./rw]m9nL>OK`/ˑ"G_Ǟ*7 Z+Cܫޡ|ߍnQEGSjfY.}Q‚O,Jx\WUhnu#/"֍XWi>1L>Xc ɤgJ ё1I^;ᾔ aR?:`8:#Rv50(y`Uia``~ pžmļFjmGͮ:xlrJK?Γ_֯X 7Cx#l~P!_HU,ͼp .=!Gaz͙Y wtl=ʼɝU 2Bed[72Kn2Z²z՛V,J9Pze\ܩye#8 }G:G(?lf' -`r W뺜:k8ǚOG@8ZMRH D!Ǧ3&إzmƿgf[^9c~-P4s RyzظU8=1֕wuJ^8`Ke>Fu})4,Q`tm򬋋n3O4z?u(<5mi^VkJ#B:62Gyyr[Gʃ `S^iv|vrW=v]Njlnw3عXr@Mv9m:xL%H'Ҏ?Qk3E2HdxsV󵹔l0{>Eu(*z9Z?g$ʏ|Hjb9֣UݱpSf %DkO=.A ;h~4j

Ӆθfj!xF}) F[1`?Xw4Ьt.nnt8BDa =I},c7e;/Ų?kR-$e˲# <竉G mgQْx2½2泛`%7Oxφk%(T>Q+F.99q}w'sV^x`cU3stWJ56zϾkіF@#>к>aj"6΍o;)1YK7nv7N9)$0O0 ^io9oԁys֡j:q{<*]wHx`GBGN<?++Owƨ )1@\u#B|7nlwMp?sAo?8ǽt$?HYd*€35?`O~ ۶|wv1OD38*~#{YJg-T?7[>/؟3~tnݳ;b$;UI2F Yeoݿգ" iOvϛ@)P3GoE?b 'ST,4{o>bCӂIɢ3[>2؟3~ytnݳ۱ثJoc޹{6?c#tg#|q Ђ1WӼS40xr]!~#|swm^O -^K?eE.ـ~u=2oifp1W,q4Ŋy:FʋإGx7Ů0U$q\`T·#dtnc=1UOH6XplaOJ[n4<%ok}5Jiַ:c=|]hӝ=ZQ!LUx'ݏ|WYjIg dB FG56*^1G/S6y^o&bþSar[}F𥥩4Tb8Z{cڲ gpUˍ?Ӵ9;}o/j|O?xnݳ<#WFy{^͞FRUk۟`gf|Otnݳ۱ح,RH?c/< t86kp&1suy?_'_>oc+L][FP8NrO՛y|x egPdUPo^WL+\E=sKbf|Oytnݳ۱اiqysI!>[cm9yE=N{UMA61]#6L>7?n(HHr+-zq,$rZ3c. QF쑐>l] g ^}1W(rK))$g}嶆8H\e_AoY|AxWd#>5O#_3Hpp?%5Du@*<-omB;ǭIzGJYS?\Nƫp"hriڒgv|{v1ۭ]4*&FU"Y \YjGr$[?#nps_˾Gg'Ƙ$}Ĝw\c%q/㑵FEHhzLq,DWab[nޜm楒ͥxm 2PpAGzc<]񤚴ݮ@q^'u~k?_R_'ݻgcZFaf8U Y n+}+g[cޯwΑpt$>_'O>oc*W[6/dnz[Nk$֚O?j>s[P`|v/1F#??'ٿJ~1MX=kJ53ĻZ$Ů?#P˜M' ۶|w8|W&-_6r|Xeo=?8ǿXuO?7?' ۶|w8|V{;79ZFg3tutSP|Yϯ똾={T@_'|7nTg?5OC_/ox7c=ҫ|Gr{}4TEPEPEPuƉh7c71g?N⎑!KίxeZ Ìn~FӸR73V(Xc[[c[@fk]Ѯݸ! }J|5#4#]Uv m8n\~C:RjxҼ6}|pcFJҚvOctw$RQF*(M7R/B>ƽsúm%C/>4IVq\ʇ*?j.7=mu]?hg 3$C(O=+=)$6/7L"=}F{UΣ0sv=_ cc^^fݮg;q׽?Iu. lrW9(7 |=jǙ.}‚O$g5eVдȑFYpk|]@DX[۶o_V*QS*m~=Vfr??>O0~"ݴV θb+ǖALM*im#,OHthxv=a ƕo7=jFN[ A#ʺKmMѷT1%,R0χّX1OF'504aGE(v= n}*B.I>ǿ4 K@)vHE< A"6K±t[GI$F8ߞ:kꚮ$52t>0x䜟ֲ.4M Rb:וqI(-HSֆڥ]{zU)5G*yb~T/EO-Kf%׼`!pX@a)ǡiE<2p;Ȑddm]+hVG cFT~D5\@6FǠe9 ⺶݋C2 #'?97 9++1;^ qזi҈HP#yEXeIog1SWduyaiw;m),l91+=$qnV۴9gӒs\HcX0,?hYZOkB+q?( wsS9hg7O7,OUA GTn&KMDPt>¾vrOZ)4ĒHi@ZwauF~)7݈ TeT56:91drsN O^Kj L~$Ԇ, ~mb9늶WɨlO81lp:tI8wS{bbNr{u!8G#w ;rs*Hr/ n1cڞX UYYzdX6 Rb$g\ҩUPn*9K s8)BTgnE.aؔ1=HXARh@q?j<`*0۲TOZx`z.Oֆ6v1](P?C`B?J41W%r zUd ԑjqhq ue$OCV!*)~wc2S9'`.9**mMwCddlY ]ьVqoN^E]Gy6%*QJ'hhծ[_iGalG<Q@Q@Q@׆[%݌8goq;:Gn:Ɖh7c71g?N⎑![ΐXobb,olorvFv67l.?!+3uV 5۷D1aqHeóYOhkfWhwXFU$"c,}H> ҥyRIo%*Y봑Z,w2!r}^Ա<L}ãoÛ [Enp $|zGJWn:*Yi}1ԟR{v- [4y\.(Wsw8?,e_NɷP݊?\|Wtʌ ާW>1OR4}Vb3evZeʷKrx;CXU)+nua n<uS+nXY'#短w~ espB +4#dxmLK=~;fN #5Pch]qPFP+'Z1vlRmhv@jO4f|;Wq;`:5jFn*N*k y+FXRSu8+5>2Ux?MT -i+ZjS[1II9p|/+*N<+џzAN\'zQIFhR .v#d!N .~a?P22 Q^/H9kѼcZr.?i//H$/ z~9&˥+C-GXW^$u2@SvBۍ{dsQ1ON Vzޡgb #-?CHf)Y6a\i21iYPK9ZT)8?zT\D \*YWvvml@ۓ*u}DK5M$:E^[OkNp|e} L=v /USa@6_w93ޥOF ͬ30H k[q6~NVfY.|;MLlHh} _4S>u;hN2K7nf,H@#%y G[,w'A+oOw?Kt9qQHk0:͉Դ[5@,L#RxߌU{8ėW@4gkz5RMrܧ[}3[QVrNli7<[-ćE`w']y$ӵy/tXC3q}c]xUϛ5B6Oz׭GOV9,=$yy"rP_J ekFO?rjS>xc>hC̬?S?J0ֳ_yx'!>7ծ19BGʹF"bP3aXzb+($hT\;q^KGGRrVzi~As 3$U=ca@$ȨtTΛp\eVoAO>)>\ Lqʏ+;:םv{ \iˉd9YiYjpGmkgh*2?ֻ`qʲc/Nq,! 9YBAip R 2sEA {q֥)9c~])E$ab({6LJ@YC>yKH1  U=T>Q8cjT9xѶw5E#8j_꼚亄se[^|/f&@>p[[j0s6OڗYb&]y18';rF0ZA qi\z|GM>Bs㚏}i6'$Z7iG'␤I9?C x#==qS+*BN: fw2j9lgT Sg 09'q {֩˲aܞy''޳56eb>lWꑄقғ%zv3V,u=WZ6l| vЖ|!ݿ%QE ((2-f7c?#{GQ?+s] 4KAq?wt Vtwv[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC-VCZWsZtϐэ]}Ҳ4^t[n)J_x$~F5ܑLRh@2]BUd@EWeh1PYdkq>>~ՙ#[R(1\kQýWVn>{orWۺTS G"2ϲ}l"vzC7F)k/ڔ7MJ[kY$7BN=7zn)6}1KB= c-lg`ۚѹ;{,ܓܚu L^]\Zkn\QRHֽ1cy_-gqfZ]ٟ6s+ Ez66d|Çz` 9 y<?뚵583zrg`R/8n~MZH`B Nt.}F;kt.}+ԡЗL= >>aiZ/FAY7wr0RRTql\F_J_Ǝv*Oʞ7g]7LJ![k& $|W+z:|oIjޗC*g) ) ;^3m(K=z?iz*5u"ۡAx7<ʹ3b V7).ʣ;x5+UWRqW?F7a%z`\jУIzP>n9F:1cMGi8pI?Jǩi'cCԗE h! 8q*Co4V>XUߥ3ĞÐټ 3\o  ㌞:̮ȩ%u[ $>UbOkX8۵lx~uix-ѝV%lsק>8V2|5=msPNl֡w!uWc3w?_]i^ $ǿ;G[vJiGOB/q^(㵞'a]rcWj̋"d:q.dS?.?2?*|%Tdy|+.Zt|_TmR+f{'ÇZ,y6pOo=[d-Z/7I\6n?OR|_e͏MGL|61q\uK~W:-ѳma}mҡ̟.J5,?KJUjOg-M=6z:ڹ%n''\ipH\^Su4{#PacMW償kq{M:=e'r;SS%_$j2Z&R+k)clK{bfIɄK3r>}S~sӏB+FQ#?Sdac4"swG<8vtH% by¿ʡC\niM$.e-͒: p]4\"i"3ҩџK}打n揘7={ۍ+RT1ɟVQQGg2ȩtl;ǹ d0݃) ?N*äɓ$.*]Ƌ ZktRHr=;֥qu\jqA `<1@Ty"ILX9x2}lWRed=HN@ַIz1w)xNY$9 6 -00$< R#T H落m" -K? zAfFUI%48Uq𽔗LfI88^Ag#g@R ~ԽjT##|zk%mV-,@cV ܟZ¶:鸣ZxZ9 gښTvʥu' \_+ÚҮ=J|GAgUr~JX(U\cGc.#`k+`vXuSD%׵t^,.5YnaE“'ߡ'=s\H"ovJ#'*O La}>ƢPOl[UxnL4Џ-jC {fuil巑Xm# λ{FP[ m#rswz4Yc͘ts< DCSi#љU2ǴH A;g2<%kixVc2(WN2A# JA?XAmJӥ?0(xg3C5rnB$fpls< ֽG:Nߤk FXA B8w$Nܵ>tʏant9i] ͡#*EWxzչGop8?z|6qG\=h/SF8;גvq2A~YF}'²|Ii|^.NS|캷_֧>*(v",W ORGbYzzO$ 'mQGW>coH Ҳ3>iy'Ȟx }7ֽN1WDa)E\ތA=т!G??f\9Ӟ?J⫘G)Tז޿̹Q.$2@CzkIc9#bIAWpn$iY;I]'ICm/1vq_Kߏs Iocc9cH5HH~S} ׭2X`'5=D[,}HKrFZd?̯ԏOnc⡉Cl2U{I0Km\ ׁU=͠w3͕22O56 AG4DNo#~B3%/FkM4o.K7,ZL_ޫ8ǸP?g '8FoƧ[˔8ϡ5rRtgcrI>HG w`ίr2a׹_9kp~,HxoQI\F74rEmh3aB{J*r!jOsH%npO+޻;W8g-t+ LO9)8Pu8MpXM+N$֪9mIaRt;2i$092PH|87JޣH rFG?{:99C\!iXdg Zt{偈:9;WYi$zs56"M=r1\I`sbhT{``ЄEwϡV皑I^qZ khtVE֋d`H!\VFG,[3Hi`oz90/F̟}x .?:ՅơY~'z=:Ŀ{\'#1 H8A?2wVHQEQEQExeZ Ìn~FӸVlhv3p#(? Պ(V("XVXP+gmkn cn1vAҹ_ ?s?E힛ci3pr: C4g?m&?9\T/S$NN-ZR rV4d>|EJҺ5 mB+7\g}GM4ք4&Mo$Ly#ۨ hk:WĒI)ī` :'$f>T!??:UvR{ҞVqddyUXpαF ;x.mRQ†S3#Pi`-/GX'Ixd)E'-MOoej f#?;z! p@}5 ;1 k{^z~3+ٜͻܽC T BI@?*?Ih9Hqֈe=+`<;%,LOn0'i<AĘg3NG=*Ē-nϼRӢ5=xH!dܾKR✚GwQ|/U<@q6_m̨ m¼yanIe F ־GU^;a$A\wz/EՅgS{y"(rW?)<zW>kju`#7N0{w]X|k^K8~ϕ:3]Z0qc) d(X܊ :܃XD"F+ j_<׋#->ع2>IqN4!i2H+T)^f_}OB19\5]«mr>[@"㚵޳4PAViVV?[ꪸX5s%%dzp*zk'r"@Ο0?@gYWַIJV?U)j3~'ҽ8_e EAv#hl%xR7eԞM5"Fw`% n`@Zb?!o1qN/?JkbON?4|S'#h鱲 CCmAxR( `GӚa@iq7{6<> HI_J>RpAqUAcHH#i!`ISEeazNsӏ Rǯ)\,! T瞹梎/)JnzRF(fqcW4=qƝ5@n <[R5頰)z hraTB0i1$Cq*@%Ii0n=?E*AjFppîӌ ACr=2F>lLd9s)V.}uJxP&l r Mp0( GYٵ8hsW^kWlP bҰFnם7u$2kmKMI 7d*)p 8Zє 㯯_LLA>?QkIsß}zy4IK* 1#5Vyn8H;&@ ܢ+3U݀]J\R:H4yIˁN~{!^=&j8Q0l~ Qu${zGT8>]Us^jZVEUQEQEw^lhv3p#(?[%݌8goq;:On:C;ob-Պ)zV>zV>kFiF `f!8]\z 3m] {H㷇/󀠨 mz/beZԢ!sRY=juCU|?-3M%wȊ/WX%O=RW0^'9{H2[8#Lyž%DJ9,Gjݍ6{ }}Q2O'&Œ 6GM:׆2N}*ʸg%wkm4׃J™1Jµ9鸐O[c_1yvw#9ێ_MboW;#8S:=sUk{{rCHs *:g V1rWr]7xP7g! Mowʼd--"38]LsxnՙP>e.x-So|?0̅cJ7#jpFTS߶r%̴;IN!rqpr+~1hH3#  1SIm$q&,'="?@zt>5'VC_C2A8 s埕c}H<9j|+Z Jy0}wGeJHnD c4װƻW Mt1f?ش^ds}  {eYkٴ}FWY#(W,Fߌҵ͟bG8t\_Otv1fVDS&6W{gֈ 1=xneŒ3 vIzSf2@>07"} :?_WAG+n td@7Ӷ^jS_tsǹi:Xyv8f9 `t A]׭ɃR#=OjRM F-M|fs^z3V9tzN1zb|#A;fG_+~SR|#A;fG_(26:7=qU [>.oup |Py'דL@m `=m:nQL̃Qtgץz#O7Ht*m~S:PZ/~jdJwCM|Epw \&sfŋpJޫ{%wA*4Zz3PW '#~V4 ћX( 2ƝX#˷}?8y&<~ϰsiU@,yP˒?d=&A@&?:i6CX>O`.=sLF-Ic<_OZjNTIw.t4N1'a硦: (d2i;}Jǿ$V2鳱ݝ zk]wْ NYarzGzHn\ps*5ɯ]++1I*hpMRr!0UT]ҁVG3ψӑڐ1 <ԏHl_XҼ&X͹'ro\v6n >WWNRVaEUQEQEw^lhv3p#(?[%݌8goq;:On:C;ob-Պ)zV>zV>kFiFu)|5B^XRQKlm@t 3h3k:[@. {i m H}5]jen#;n,N@֥YOhj(MxI]ͱK7qR7pp>5CO͛DV,nύ9'#v(-J+*#|Lm7VcxO12#cw^ZͫjwRzn-kfF;VFﯵU+i'En'(.[C4< 8{W5h[W" b%84N}[9%mÜmn=+5&MjJ$a(B~Ss_4XȲȤXqצxo]{xm/鿌c#ɯS䞻38U0e煵9%|toZtc#LXx?}D_tho1Pn5"f"O#5ҡў?,R۴R #!׃Һ? d(gn%PsۿNx$u 6nw?-|r+>t)H&w2:%z/%Yv7q$@v\VQ#H%d8E^ůj3\NJ[[fc٤ `r?Pڏk.`MߋVTCzy}ioM&X$$^c`:w$d~5Z^,-dc߅:5+m7rUz ];LL^ w?;8jQ,w.u0:ӖDS_Ja 2^g]r\d{B"b(z$jT8GdtV֬RM}ý2y,oЀ|?KT}1?S5o*sD م)Ĩ?#d?usXVϴDTB2@vn>g]TW۟~*aIG8 L$/?Sy!6Ϟ+PIn~8y|nA ÓOr(0e :Kf9%~R϶*|!sFiT8_'yb:?<?u zZw4{BTZmjKHO%  O*.yUSbO=ڋ٭4.U>汚{O.@5J3gt'Թv5=]9rwy\FO;We&~4Ȳ[JC!Nœ ǥx[YJd1-O?vx"{kY$[#*ZGl)ݸ|RP#hnΟU|/YmtkvfʞP8LXo~[k48>߇DyDrR՝4iDzaojo5Z4 N1#ԆIYtbcQ^@U$t[Pqӿhi U6ۄJy服t:!-9*\.s#8ݪ60mbD\}Ղ*i؅6D=V>3lEH?Yra8uo0`alscӨ>=k҄ZVDs"3A=It)L}p{5>)ң̎>X㿦+XFH>KHotLßCA~`?ҢVc¯rk|C&l+܌ukU'k.[:YV Hb,pxyIӣ5k2%E};qԞ#Z=QFiv\,-3}=cI}P!2wSSxOEDcA'{VޛXV'<$##=z=J.>Y\1C1K(m*!SMH=T$MKӆa[oy|OBVgn^h\ #%8'X:Ԯ/TM#:[I2胠5ɠP6W)YSܹu]\Db}wo>4Qe[ |ϼ؎sIKmHe]GV&:frwy*AtyyY~An̑€þu~{FJ7YFHnz$]?ĐCx8J^rj1,ԡDU8{7֦[y 岏j[:KI |wZeٺu22ΌOO'NkT=9ޭxت|b+K`:1A<'ӎxvs7d喸yX Q\gO?OlVJRzNӏo{ք%H;BNFNKs?,{Ujo:x~Uϊ4^آ$b)$jI vUoz:CcA *4?VgGYaq*4jҗUR .ğIVR[ZUBIliO)o8.OGR4v^H&se$~;цAMzn2jړx&+e3d t hZ) aA76Hf'yO |ɦds&A<U6!OT"7:S@=^\_3k\g*?+RƷ.Z{g@e@Bg55rW݈k+G*~`O@v`:)|yc I*^E$giL6s^t$ @vz5մwsMRcגZIm5_.GR97u+њuXY'pTtu y;()$o$w7@mA݌9Q6;'o\- 2Q,Õ@Sh~Z[zY{BNb1&=OC]=! 6zdW.P.ɑ6ߜvydF:},sMpCΔ81~.pW.tSo{#\B֎<Hp0ںGMyS BAd$0Tt)ReFȇ 9†9Z,Ҿ)51y9¨lxf\qu3W5v!<<(zǰLQZ2hsʴ3 Yᝇ+?MKRse8d2}z$4<(G+Od +6~q OV麔N-JqW q_?I QyrLAe6=U ;M!5 3F,c}.霅 9gftylrG\veVt,J8US'4DR-ǵBt0>R>`P`s=4ϧ I֭xH-%f; %;'޻b:*8z4bWØC1I=n6_ZdIi& '9FSӨȭH[d+:s^գU/h8gElLE%[Cڽ -=B\.^Ja=ZԳZU[uSn>Y/4#"$<ec-5ˈnIF$֥Cbq5Xb-n_LfmA?ڤe~TǍ/ݓ`#=p<{n1쎨ylY(Tݐ=+5ϱƑ uPJ~6zԝpUVz҃Q'itg^^m'ƽ&;-Š($((2-f7c?#{GR+s][ 4KAq?w VtwV[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC'5'u*J1SG kJKT1tpeoI?xBN-K,(#¢78/#<1]E $Oqy<z$-:{5Ewu >gv ԚօMLk>Dl4v@{awzl^u㴓|9WT|S~]J ƿ@y?[;_P]^IK>oN~J0~E*񼕌xnocPI4jj]w t_ &Ž"}" O>wc ?Z/u8w:q9 #'Ӯyҹ(*;:?٤7:ltEsדҹOZp[ H0Fzgvk< Xƶꦩ7[٭JhBF=n׺3<#ֆ>j=V8Գޣ՝ kTZd Hņ1gҽEuXX`nKy8${(Q tE1,qFƣ 0hGmB{`Sv ^k[vTڧ.9:7O40Uip~"nqz^@}QT#7i0bUl+*P>lnzGj%4Qn,参7Bj` ~~.J0ve_~>IlJcv?Zќ%ǣJfAگ6l:2[m*ծ.]O/~]r#F=OB{n*#wz9|).Ro[2B[FVl1ֺ*'4c#;4h#i"339=t^ċː<={Wk$#sw^j%ԯrw2R}|agv`/_6ƺ'\𶣧XIg~d711q<+c܆_Q2GA/m"M $HgFK1$.8ϰ+|QwiA}KNx A'ԷLN3 u+h,bد+4>\1 L4Ga'<`sĿv_$?l\ƠzmzjWHE{Z(+1@0Vvg~~ 1QaK2Fx r*f`@?\u/١C5S9/9W{kQl5ĺڣU@G" L1`Xd7JzՎ[@X.S *|yRxqv{JRӱƴ0K!P%HnjKTٕ :V0CP40'az_]-nfIxWs8OLJ%ۦK?;q*HBs`J2˸qxqH As(d:KMX˶@~H P[RwTkytۑ3BOC^qpN*&QI?z/T|AkOmV[h?.OߙQ)*9-@t6Zd W1N+1Wܺj9{0.m+Cm=GlF,0L)mS8G\vq+%i#G ֱV5fjn슌ܝ<3϶ gZ둥ђo2BFЁF{=*d\y3''>ꯔKgBc=Ysymy-6=8>v{NpԪ򜎕G > thgE@@'[qP1n9_~8kl%i`Q//3p;^ƶIO 5bhr'*}#+\I5O"HYc#ӧ=+P_cQ6>f|%x~H|3x# Drq;(q3n54s۳4h˓k _"SMnr ,fV8< u`<X^=uq<ʀ c5NdG,Xï\qսBr|w]7W$kEr{:L%V\+DX~χ[ pDdLU5[F͵cr2=+\xReR`2#s]U=$ULlФ91OSZhDc"eE NNwk&2Y2mAlײixLQ1* ;kq_WIEb"-%Uc.'FSR%o^m瓒8TdMNy޺IF).]6dճ!+&AHr9j܏iQ= 9L 娜U5jmU jU;CdpFy+T 9{X;GXSLι^/k1ux8cqz#V!"{#Wך<VВ*;-Š( ((cD݌3qKIuoW|2-f7c?#{GR+s][[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) /4oyr3"Hza#JKT1tpeoI?x}J]&9,<kPiȟT9c|A{ Y~c)>~GjtңKgV'0?rY﹐:Tpe1xy͟iȉ&FrGֶ޷Ps9͍545Yo[i`OJG~'WbYF5;kۧ*@c/5="M[Ak9 ˹hr 85?4MF;kXd~%NO[aS5H#}==Ӿ'[HkXg?(yoo濟̐tUz >ց@g>EltIi=<$iM1w94:ьzg=rK"9#$G=}~0oy08~$K &9hʣ.rg n$#٧X9gIWU7)^6ۮTLׇ귗$`4 }I83q^Z(5pҠ!I]r̤dsޤM'uu;p ;n.UA"?:.mxՉV|3?u /n̟= ߉dEJ''c]NO*Φ4ixl$W|<8Ku2Pګ*QxAz4")fnןy_ΩrFSԲ۩jpMGgq$M) )+) ՘4wHlAbRi ,CoOsޅ\7` K+g'5)BMxUmsYI>讃MԱ(Xշnj=z]K^|~9gMdY.NA5W '+5l#0surImda R>LEE${VZ~Ynyׇ5hd<sb.0Z<8^|Ѱ^Ύr{֕9cU@:n?F8μBvGi+{_"[ ` OHyC*9ǹ]N[YU€'8g#aYJM9W6p:w6 NgwӮ!ԒU hrőcHRFI' ޲u./ee/~]cY naխ Q=yQsSQ84-xRT*Ia=GG"3+Ԏv0?}-3 fňPT`m85an) g*? .6.^ۥ˘sE.+*=bHcu[b'Mjזnjh:|G;f{v 1~Yk~j~.n|3.Ӹ|}WxJw1wKTkyo `8E׵ᲳUA,: +b\g[Gd;ʧmId`kgMN,oj4 $䁜w5kVk.9{2u8ϊ/Ѵ9ֆ؍v`q h#VB$uiYxG-g<929Ct髵,6%T%Gdv/mm.*2֮[pUTݟJ|/Gr/$lN}ftUbG_%ViY{ѡF>;',wO+kTX-쀍iϯ\{{XCZPj视N rRRqB֤',8o\$giUOw 枣lL@9] $*N\˕SqjXs@+DY8}$Re3Nk Ԟ8]teӒԢL9ݞFkH.IOlT\& REtr޸"2rA"]*jgy=<#,gMk+6xdt`G519zqַUrXIMR2bk(ˆəBRsse a[UDn n늨[*?:7gt.sՀ PNO޵-4{IQmjp]$=u:[qje+]ѝi^ΊjSо@ވpC~MOy,yNkM!UOYj7i\*K;LY:]mT c.N1Z)QQ62Fj%}X);hRд ޓzk)8g WVIN1Գ=ݳ%<+`q+{jCI\EsSXC^ѭWa6d0 0@ZE4˙yAU+M[TMt~e,rdgl~ ,, b~R/ֱtw5UV*K2!x`#c*1{'f;F{qh 8[}Q[b?Y/!⭛!usWm՝&va,.HE8;W5  [zQCM3k8NH?V14RXd6W5qԘɧ1Ժ}@Sv{%ep^<-_jD2].'%8 s\c3J/Πpso¹~!nXې +@v2޺QA#+AaʐUOJfe\(\~A>7On1򯷱> 4 7u9-1|F`'S8#ܖaR;\}:X:x:ȼI#VK r_#afQ)fFrg[YYoN5Af5 8!9N o$k5ƒ9*2tlD boAFN̹RUD OC~ōBS1\@osʟ>:"uc8v8|5;}V(d_xm8xz4:?R,o1\%l880N}RYj VB sQjUY{|rq={BSKASHOCF?9b?*RNb5إ ?Z}~"{PY䑆 Hs5 b961Gf>Q,go5ʢH"bJq]wK H>T@ zqob |>o~y^ >Ym.PV.J(-w[ӦӼ5Z9+ܜt8?\t(|O>pnLT,Hd-#iQ"0!?t7נt"Y p28R}\57M"dpg?dKS4K13\bm._qY>1=,фp5~9$;-2᱅,j?HRhTr>jZ#6߼Qٮm\J+u6䫂8 Je #S V0 l=I)4tVMHK?P͐Gp c )5 *#SH"CO+>_PId/ajb*ytJp}+~[/jApI9U\\<^NAz<5EiܢˌEi: I2 *MɦN,~\ؙIGC)S!%4yQX~YJ,m(AtrEJAfQRs *]]c6z~Y G^1 J :͏G@}3>,r,q0j1O'quMBseku(dp2? ed58Rmٴ5ja)3}Zn!O#tG^g.U=;ic~"%B2r?Vagh5Pqn%PƀFvp?J]n06\?ҸsUuNЈ4^5Suh2q}?۪n\LnޕiCla H3rq:N^R %pq[=r"~& JJ.KLNYf0[H\P7;tQI8+[9&*Ob?$œړXW+8[S؂ONT9:u̗M,zɬYr0wcpL>Z͌|ݽű72onw(mT3H0xǵhXb0u|4gK^\Q_W٭#{vtE!^EeOZ=,vG+4W` Xs7rW?. u)2:OX/%F~R8ۊ[xv -Y$1{_ԖX8s1'#8i- AvxNi TxοIJW4QYOPO5Z[y}SkʫOGN9ɠ]mg V%P H2{s[zdK.ͅnnWIcIւvq]F _ѐnDsJ2@Pr*04 -;Ͱ1z'z htis~ ץ`<7\yW,o©~m _ӟofpy)V=i[K$exsǷf| {vŴC4nzgG?#LWb0]ACԕ#u/iZ2s>⹋o\$'>LȽXStHkr}Lg݆{x%@?YQYZw$1{:.4B3:#+v!W=edX2\7>V (?t{*Iycwb ^j^,5>8oqopg9mN˅,  nFDAV\]=Ho")(ѶӵJ $,8g_?ʙxLUӬe.f ,.̀A9/BeIJ6)7 \Tʈ2$njWA{v'Q0R1޼w^Jg.rS3ܞ# :+Iub)TU)X/үq]F?0z1霎6,k8`*sZ&ܓ9"s@iV´~T˽#TݡRBVuFNSQjGjw78Œ-ڵ$-O66o$d-7(NAc]^m6mr ;I# dk-d(r ҼM%KmsWiygU <@϶yQyT˻=jIo䴴u1f,Ov3T q2uQ fZ\,L@^1ڒ[h-nZѶc!rלgW%Uu}@GT,w6q=9I] SI $_xKQ"l[wܙ~8$汰"#[aѬR1 cJlOcUUe `F},S̸XWi tB:qag)]%c"]@F:|ɌF?5I5rn`@(;MKXLW9 >sZslhiEdl8FYd|B㯽s2 \NkkE渘|/^UedxkE\vy~')v&mG#g-ߛ>mͳS {UHPXg/SKݸWD6cW>v _ljO;]yΥ.[?ËסXg_J]IqҺday#zYʼ hM 65 ں=G8}+r L.E0H֗-#fd >Uat܇@I%bxsZvpK 3ye:z2FpW:r;qu3ށq4Iⴁ0B~fxQSE; {nd!uR6 x;r$`88:&gXc/"KcQI>$o8䓺8?GnʩY.w431U3HHǯDyx\tK.2&!$.'޽;rYI;('!`Wמ+6#u2~~Wi?k+8J#mpg&g E9>=atc,\Vl`IoX|?>E?Ʒ_ltxhr~֋iq@B$yǧo˧Q%)msU6E<̹79sL #䙙FC:t-U`YIc @``wx nbZ{qxPs~Ra.GNnk8DR! dD9o,0{RmJ#U`XƻCҰ\‚pIj2ݤ-_azWتu(~=\)SC,ؐ"<6WsXtdc!L0;~.-'8$ `.G@FExmiz30Fp{Bt%?ˌzjI`/=oʪj6>ʲFd;089?wr *ltZ-g!P?x񏟽q̆i.$%|Dl?S]ww߼m'}דBœ?ϽE:r{NIsuEq$n 1'5h`cq̻ΝҥYvFp+MKyt_!G5rI<;39#Doqv8<7@2K?h{3P&rF;gִϔß x=\*ھY(=yQe-ӟ:/ӽhYZ|s-Nʯ3TVRj^huX'}*Kb2;V [%98A̎fbr+Uy- TʎƜgR-c.&m#9G5z:6ZF>d2QI&r+xP8VV4cnAZ\r,lǂAPIa#ιʎ52VCďf,|ՃZ%eQƲ.GkN9h2k8Ud+r9+GGPR-Y"`GNyL :}j,]lrO<@I1Y:*nw C-Wͬj:=Ϯ+'Qm }~I-Y2zUw7\fb}.Kuo10zgs֡:%r+:LLK#q .VF4Ee1T_?g[އѣpĘ?wxYrM}%8F7YV=anXU,ҖрxRu> iݭdy_LUkI%+Aۓ#Bk^H_)"dU2'nwu 5ec7?lS$E ʾxGf?}&wRGar+ p3(T@ް/oy3G| frmkzZUPE¨tm$VYiR6"& '\cY9wY~ͦI.@gohgS5b&gG`t>:2-Igsg'?B? ۖבާr"Pyܣg-m$ $zJCތbrGOYդ_qR tjw6Fhr0Aߵpzb2Ł =jMrH&ganѭ#厹kI|]hs Jg&ILLs@w[0Y%l~F}/ýM@*p\^% 0P[K}q5ܣ71>"y.gUqq˨@K<(8JҒoo"#dSthUT`_]K{o׭A-i#:Ƥc%fim!G|I >Ԛ{x#gU in$LH$sקN~ qoA+]p+?_aJ-"P:7?ª=ܓtQdvx&+p`ߴ5i."ZXzzgZJK8kNTEG.Z0^fpg' `tZ6i`fLG,xA5/Oϩ!d$ qo*2)@H8ӏ] Otg{*Kֶ ,Fj}Նg,]&YT: <j/#N ?7_åS; YNݪw9=O^Mj}E-# oi>NIמ4bzvr*e =i9cBEEYRhA=5ww-7O,eY?8zM'M˰>tҳ|6rızwűKh% }=WU+1\yC#bFʹ|V,RKpAHG=q߮kԯ# }z. DO*_ j{oj^ǮYDYJ RFݤ!'[\)5=w/[j epFq5g4tsSITꕞefva1#S=*NJm;V[8D-鵏B 7Ka.le7)q֟=Pynp8P)cT%h&EW珩jhzqZ^2 6 A-%2+8598nA N-!$Iun>dp:SDG]p#55tyrUw4vG=i`8ɪ0'ک5f.fzrjmkwuQ[]+ ;s=jXWz yvRdri DHJq?wF@m93۷+ӵ/H/bq7mA';>{-BkI@Ybb93qBŜ@SUMC@ᣘt}zҷTCH=sV-ޕDr%5pI\R#ӡW].0+ *64퐫Ԋ4@I?(VwC+)<ʲhس c5(> w ghe>}}6N@,`m2Zv>y?)<7Za19 '9?8MVô xX߈r+ݔ,Ȓ>V+=K:O 4s0ϯtmIR3/J~<I歰#Mѓ p qbᰖM"*/>ƳȞe?d?ϭP6ѫ8RUҳz׶1Fաs qY}(O?u\"x?j]>!& Jg!0N~MD4ȣO H sl{UdҴpڸhG֡8FҸܛfsWP1?FA)u#jzzpd|cl¢E"4(zC\"BxsӭH?p>T?Һ}(#3\OSAӘVGB1 t:=7mӃ KF/K 0\a$u\ΦwVb#^{RW qI~mnrx== \kReb=5fHfP9}6cջ?Hz]VFO1L0Ckr d+5|JIyǸUhW>0FĀ硦3[[Y?+/ѫ*m*FA=k6:?0\׫I^^i?Oo +ĽŠ( ((cD݌3qKJu5w-nncv37~-+B?[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) WhwXFU$"c,}H> ҥyRIo%*Y봑kg?m II-QSۊcGjF$/GM;XY3>R:mO?Rb֨614 :m.2Dy篾k+^3<Tzsz?ЏFcG.g:INg!hU 3mo,^+{měШv8#`2p1Ұ.'\ЌzczΒ擱0R>{fbLzp;RGuqmaC2$zQ/`֒XHIcGCx2|DR{3DGϧR~i$2f"_-0~P@8OkFQxRkMI$#'?]úm:[; H}|d3g/sv!y~lʤ5Rs3YۙkE[Ts`>X;w_Z!)m%%bjJӷk-qE.:u >/_fgi0sTTΘb#dBm&4?0x }VNC{I(c2Z]PqRFOƺ @< aXדI@$`{#Xxiq[+U3vY-ΫkcyH?OV/$FH@qֳ%٤1bK?L֜1\c-d=sV3$o%''bŲ! ~]$<.ىYW5-KhҰs`qbsXF.)AĬH%YK[6`^'*3\'h}j"1HS~Ղ 3CP\ZVWk07&9w<,czuZ懴QqJU^%gnT4Ƹ9EpMoݳnU/0PX9"8Tm:`]毭ǭʢEi#uP6QwSb [+(RfخT>Z1Q\m4{%=Lc3OWN?JNYVy\I| r>%}kY:z"$,#d$g88*gNjiJm^\#$:ޙL뚫-ح.f*$<~5^ۗyAe ::wqR4yыVklm;gG5ƅdF%\S +"-%JV<$63khYđBg^z\8L[ւwmp@9 _%\(MII\\Y@Z#RH9-?!Wn-3{ְ?RkZ1\vuaI~xz=B+,g!69ymX#tL7R>0N35I-g bcw*Ht[^3$ ;f?5GbMŘ]iCb.Z۸lmu k .c ~5bB]R+̱heN>0O#z֧p۴׷j*ǡKdwC.O }U:v8BzrGO*-YNszz[ l-#+͋-N$jȜ:z}Gzn%K($q+E$WwEwzdi3Hw⸷W)Ӆّd8@NʱdxH +:MC"1<RV9M?'׫I^\,[ٔn9]\v3EUQEQEw^lhv3p#)i_eZ Ìn~FӸVC;ob-Պ)zV>zV>kFiF(#-DT;s(A۝3tZq}daČJ`R?!) =³C_1I :J󧈤Kw7G1JTi#4x>!EH.F g?mض٦_Pբhh%+ uYf~ A [<{$ծXF_|胯3URюް[JXʨ€xC|./ao/#`pGZyZ(I+,傁Y$SxZ8ڣ =8J%RV[ KVgY4X[,r`1T`tZą9l^yJ < I^}:˖gFRI<CZ-3S. ff]ǿgUm+$'\FO{HԊ2%fgi ^[P\u>up$y9 ' ĞtiKrn@!@$Ϸ?9(4M,$FIU7pO]>=f$)x?`hO*2.vFzVKo#CqV}v[9}58P'VHmn;ʱƒ}qW|83PA=8=Tڠ]rc*?>3gnjp:,8n,rsIo'#OǸ=G? Y'h򧟭z޷ ^kcH#%݀Ba^;|2ݞ Yarx`o^V;wt?L2jpE`}S+ρbjA$QrǞO8GӬ/NҮn#1)Ž2IL¿ lIxT_-ڡ@ivF@϶kzKT.gF,rzޯymߞ͔:pO$vES##xznT0F+Jnrh.\D`{k1Cwv'zqhF9HeP $q=+:kn[#bmB{p:ք#OG2ȡ$HPb3G'kAYevzfh:Xi͉6;}O&] Z(A?9ggУ۪\;|#лɴx]ťf219?*4.)HQǽz Pe98Kf2ۓ>4K4iʤȬ\ c~U \m,(r1MHpٝȹ!aG$*S8G }+A(%pƣ*;EghlKk!ѯ^#y_k ^dbw1+֙|R&ec PĎG#ֺiǞVG=YGN׺D)FLrS-כU+韲E,KcwS1kq[+[Eq2orB?tFt1UZW WaحEsӯ{ H~og-gn۷uG<[bƥGcMtmr@NPoF9nocBWWE9xI hAZ[K !uc[5XdA,sk,U8NW>~U>d>k7p]F4kFy%%Lp iwũViIBe2A+pGZ4_BF,ȻK#~FeG7{՝݈, XElC*3CnI81׃5&6D1VpY218CD7y2~yG9rv/\/psV&:7͸ro'Nx1N]J:o lK)O>?4 L7s8,H(L -6Ĉȣ%AnIϯj^v[U"5$g9?k(B4:տ;UOc^Uህ>f~ϥl閒&w 8$瑅 QCCu4̓[4*O˼=+3vo(Ҳb b1`tFџ5k,6,Dk t1͸ĺrAZ%)j-ry$yi/@'=eXdAUdw^[[" *eKUvu:o".D7pc)lx?>N=K˕ܰ@qzNn !<̧CooҮ_xMgk;,zM9u"̷T~cN1W-#ɶ!#U|,}.3՝;ڭeP \aʬkizg}&{fVl 0y' :fX͎X$PAU,m4*)ul2=Amz5Z0țvO5-_m˧lZن(B'!ݶMsqjeek8ڻrۻ[*t뭨~Qg*ߕ2F1v8SU`[}: @+oTSl?،D;2FJتzBm&o"HSMR7D*|ߜÞN6YåBXva:{a%̰L `1h&avhևWe x˹;IdWUaKv86[/%$ ʣ?kEk툍h،CzG:zMic$A}j[k uK}GQݾL6 w/W='E3\$HޒKjtb33ZzStmḕ B轎huD'L<~xk{- _15>c]OF'dL/nS[?a5ʍVy }i ]G%/Rf,^^[_oz>'Vҽ.*ȉ;)((2-f7c?#{GRҿ+s]M]cD݌3qKJu4wV[S`}[K}+`}[K}(3lj ?h򈠎( *':V7fkbN[ $GeK .G<IwwvojGc ";NIl'"JKѬtp%orAKFYy%E̍I'-I'ӎ*[?$Ks$K&MՐyېNxojߺ|olF0Xj(VO>p U rI\wyPI[m08vZ˱R$k;$pbВ#6E*Σt9b~ R斁-[>yL)1b1tCơMB!["BUPr;q(Mc䞹?jN5[3#F O?LXh4)nE83m'PN8MQsMվ PIpDh{Mj R).e7#A`s$ s:e[N}N?*Ӷǐ#FwZpEK ڳ5X4Xs4Oʻj>!|DQּCg,qܩSA_ǿֹ#~Ye gyFq׏Lvp@.z%Ω$9 lz9ZiJ5V?\ {P3H <tHT*-:6νq )H{ZGI(˹SAҟW"Âs2\Ȓ\}kV(#cTE_8 5Sӄ9^)](ڪ #%kx]?Z?qmى& N;w׽ww 6vcI iʹ(XF c,SQKTһhHr3qvΠPxzIi$M"8ϯzUE+7kRW8-tyn =}x^3KjtX'{DKuӡbvz}MRyЅ.OLFc'{ZZB:桔qWKOifqoͅjUd/vڦI]r{=+1(A=\J<-xn/"b" f`9' & gsn-r|,|1I#/X->" Ypq5xS6DR_’\JL A 9R#O"A#~>⺭+Tu=-oEfe c-3泂8 8T ?ٴ>SSYC.9=\+-<&jHE9~_5l1|Y< ~ۑ8ºΫ(]>$Iw;{ds7[_IrHDl=ѵgQ--ⱸK5b'9ӌ-ވ[}ӈB]އh/⦵ͽNq+=d WY5ƪQHxRj>xCuǖUc(%5N3'Tgo4MIdR g=H&$1W \^bgmjs:}kYŠKr721a76׳v5!/^&$]~@~;Ou |M\LpX/K}\YٝL{Lc_"8U%vJ1P~G<9T##)l(t>PJ(H#} I,edT#$9fXSex&+skcr"9>&ܤfi$su<=,V/S!FS+=69qܞ|]WF̗ɨ̒Y2Ȍ,eUE`2s9xubY Q+N`8o]mʧpF{ߌyg 1T$zdqԑϡĩI\0/*]mbe^?㊻nUQBl4s[}NFWVR˼׊K0ZF )Ez>ދ18L~5{jЙ.s"DTQNVT] I,9">[p$IJFO՞+3lV#sʬj)d q)YDaOS}NEӲg1Zok^vJT`t'&BNBq}{WED[`re3c?*IU0>SӎGq]46}k#ۃ՘nI2c$[7:SmpsƢyG,KKw>m 3{hVu> _amL}vy׿5KTEIf@;6ҧv9@w`''c?ol0 >m!%H`69rFg$Eo ~bO|1T rzn\S%xg$÷%G'ǿLiͪGy?GU] F3$^ngEp$g=+!,FֺQlF#䤋͟Yӣ3Vl `>Z'Ka¡o9EYV1Dn^^Ro\-jZ[d קsJ{t#[IoVp|G)#z031o'xdGjܯKё &U >aNF3HI28t!_1cשnd@#q6NaTP8֮": k_>;ᩝu-A2ܤϥuayUr~er#:n[$9w\ΏjS9ڧ<~MA^edɏ 3*D[U0qW,FP0k:Z:}񁞼 9yna cZUo1_ f`)i9*2]8w <.1J iėWEPEPEPuƉh7c71g?N▕![j[%݌8goq;ZWn멤3V(Xc[[c[@fj߈oYYJN60xv*fkb+(Y_ɂ$fbT6 ~Q)1zF[^Ieʈ f9;H1W/S$NN-Z4$.tkK y5FˍՉ+؂=y⥳YOhim;Gc-Wog RιAU/jy+',/װ9? mޝ+[0ϳ#{Q]5; M+tFz]YkэR0;~5iplllg9]R)9iJLВ4r@13<Q49cW +)Z7f*M۶@w#?wkB7c%, -4;"$d5T0zA>^jby[9Ϡ ֶRi7q+yWrRGQ\bf[WS߈a9E\Ҝ 'bCʻ ̸@! ^}(PvT˯G4dԌT ֈ4T@윈|5ۮJ3qެ*EGD);&˵#ò,>Ps*:S (b0OqW%tE~H*g‚IՁ;@V8geT$d*.*ǙGՒ8L-xRsj4t%ib,#+1f$0 } aV[ h%;!#0FxqZxQiVw$p}ͣ*0%W) 4~d<\3XVg,+X$>V"*S]N'hSE}Y;`5N-TE \q[0=am qrı.ۋ[6gb6:ZVJVTnFXb ]1{rz2n stA32?J-VI0>?BO 3tݨݑ-ZGQ3KȬ|1O-F_KcذE{lʹIXN\~Az/ћ/r;{6Ku#fI['~ry$HF%0pݵspqӨ#DKM%KA nFzgy:"Qw;yWmw^VVG=EnYnʌK$<ܓ9UdXL%c,8a9$v98#ﵨMJC[ chrɍfLVgݯL7oyf9zZU7_6 r9G1v9ӌ7I:7&vȕߌy$3`2~Egw=vX)þ wRiIvU#$A,r{0|A4Iqi[ mv~kIkh(a%\d|푁5xz{>u ?vMە!iVhw"Rd)'kmwOAooq.G~lLH8=֥))=ASh<KۃXeuYDg}ΫIp1N!Vw}1ʳ- Tկn#f$HK :#Vd, st:e,r##sH,VBrO {Ri6\ySj%0H!u#rOZ3=, ڢGyhݺCl^1ҴVH6 $I'R;JJ~8+^G HPK(l\r}N]V2`w+=\"{7aҹ14]N7"Ў8w%c?S޶~M!$+d~8/i=ʜkW!1nd''CY>|#nXC'ڐsWc)I5k"nˆv*;Ǟҹv&0$̜Ki_ƒ g?=9P[uN]VpT07Y[)ʞQ8v1U}/RfpQO5_ʬ:Hq95-w<%^xgߦq+Y/ F 8k}F@_%~P?5ضdcYQ\t cǯe 2'Ԛ؀?6}r sM4- %.H9 {ҬEq".܎^z[k')ҨbҒ$g;S.DI;Xs96[ ?jJqZx h+pl*sf$G}0=zun[r6$FWxgDd52!_*xqe<d}0I[MV6pC} U#_$G>`):ǿoWTg̎IF&x/]C1sr!##۹0Op`}_WKpQ| ȎnL^&x,c+1+~c-(o^s덵%v$8x>%cO!wrp=F{;6t3Fsk7(FONsk%㕔>"]Rv%y43_s?UO8+U#R qGO`7]F’z} tJ׹:l^'25=kܥ|Hv^+qqтoHP1=)R9`QMudqҽ&KoN 83*Q@Q@Q@׆[%݌8goq;ZW멫lhv3p#)i_Xobb,olor-=qQ e:V7fk]Ѯݸ! }JC3l, kY)<\qƹbŘTZU)gx^' t5gğmVH.xp?(~t`2U'#;T%&+簏h!:\&ye؊)?k:h{S^0 =)5뚯mYI&3t?֚P݅n~gkJIMN¾$79̨H ]Z]},ogN Gjy`{+&p۔ޮ|LR$&i%u3nc ǕZEl_dD?Ҫ۵&[9.I`y_ZӬѴ湚u><#394z42OAk9٤/cc]#?V4sUC7-GWݢNndŗQ3]p >3N0Ո鯃 "_bA^O?1]$(!ֹN/Ŭr!60#5RZXQv$$+1Qx$Wбڇf žmm20e3@{޹KaH bs+%?xV'< 0(FgUr==75]qXk( d'v5c¹ڳs+ st, jw<*a[r3֢mgj[ mؘGwf)`?z\ns֪Db1IYzWx+DL<)A<ѤmVu֣h"q6?@=L.Gc,OE^留3#}yFsrNPhv ±@`6#aFhܻV2Ļ򵩼pɮd#TEg &}[WgOW5T(Z1g^vvNsֳm]YeJg}=aYwpF=ǡ\ZZ8v+G83Dmղk o\g_]d ~{th$ٴ p#Ҝ q,~Sݹ=J*wԴR[8Kq$cl])6kU^'Ngz+]>`021K)U?gd8=njadNv6/5{k$n"8 ?^p;8}.tSivn\[;*A8볉t *#@W +@y4g|B=Ml|sA&L`gE,xcjz VSo6]=zq ڼ1^j BybsMyuoL11=k\"q( >xf3N4s=@u^A(((cD݌3qKJu5w-nncv37~-+B?[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) XvBl≕rO PƶMiisS71 yv GE? 꺅y66TLvKۙ^qq+6±=? -@|SFH-aD #v z+n"D-('?ӯֳE[0MiYir KRqu6 Ixqӌgs]MFJ 5Fkw%{נi]Y#ğ(ПZ௵8 B2zU9uXtP1]9osqVFN<lI'&P"GE֯Kp@Sc~sP궢=hDכ!v/9!Qo}ͮs eI',!a\5=Ȳuec>$htKxa3,; u9@ fƔ&K˳jbSI_ӟ*-F_HUiy0b]@y*孹9o-`2HuK!!͑AE@C@^UVcЊ`heˋ @<zqm9[+t`ç[=x 2+C_IL5 OH[rɳӁJThtpuI缝bHI(S/`"oFI s+(F9e9vn%6\-eYU\';BxMP dRD;ozDzR0Oq;k׮#B6fX uEw4x  4^Cpŕf1HJJ'Ne)VIoB +js5?0`'ic>*`Vc4Dz3zu5OY-QYq39< z 5 ajf$Ӷ}N[an) UbGsKa8F/g?mkoinRP{+wL]pC)ʰA漣ƾM Ӯ6&b||6!<ǒxܪֹΧ%6ruReGT`.Kn{ڸ.$Ҧh .g ǔ,rv1Uo6d׏ SJ(XpÓ }0XًYwj䟙<,&.PLBRqOv\d]y.#`8NzV K?*m=Џ1n1c^'v\;"&=7r)*ص5,W}:݌N;I VoBN@0= j?eas'“9ox8',zszQ=*CG-B-wMY'gN)є|U-Hې7>8Qߥ4BFgZFyF6 sO}~5Ax`vTf8'?^5 ?,k@-CP+++$9=)tM*{p巂A5uMӡ~UHO**/{K1Z$;q*@?SZ5⣨IpIlhdQ]g5kZm$wSN<،cs(wwoNN:w-+SGq<(yH P1ʭ]lq)d 29OL+1- U*y$ڣn {j9&rJ?bKFxc}*FIL&HknGؼlKT;@V6vkK9jxԧ+K>d@󭛈"z"ݖ%3goT4иJSFTce" J6ċGEZjWD3|L#jS::Le$rj5)e/pB@B}Kiͅ*3_µ%XݙXURz9kxFi{V"XĞ S6r0~k{5.8 nt饃Puv1`n0}鰬 Qu"WٷhqִU@ ÀJvZB1o`bBK1pG] z =ǚc=Fd&TDMÌPqK;s8밖SD+1[$[Il `{c;W35׌-U@eV=V#?nZKui;b`bsi\8=XT6kjtVde[3lW4H+a&#Et`b`rrf_.ryp+ҕd^@)`;E|cz!#ABڵM%blrXeHx{W~qN6\'91ԏL.9z3ůq8F8i0IqxqM^-z p@QE ((2-f7c?#{GR-s]M]cD݌3qKKu4wV[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC-VC[2ƳD1`IF*p}q`Vj"6n Y'4Q"i|^NߨiۙfڋxaQZQ"8M:$/oΒk+K#5X?ڜ&\3奎h ټqj%2vf<)ZE#$eõn^QIhz.^?#9ǽRCg]M!sU ;n[ɱ5rzv hR2e0duێ`6I!A~j]h&?дf`F*>UaV]Y2͂YExq'ҩj6gH`~~Wr^yJUN3VMܒ\yVJgivzg'齌.ח)jp8>Kq+0Olzv+O%R,3Ҹ=b4 *rf{Fݚ,4EG18#z@ڸPi^"hU$1@= <~tQ ,$t+Xd2GB yY$}\ }28,/6I ?t9l%b2:&O;zO\ڳ/2n,.CC. sҭ!gC$B6TNyϯOaDPDe2>f-g h́q:/ Xiz}~~rP|s~Xlj^%(Tr?y/$^28c.+uyez`T7i[REdeg1)w=J2ͻ"ig= %w??6:Z?hk4Xb0TϠުz^YŎ"e$ƶ>cGued #,@#'?OӓOF(nhk3G=eڀt\yr$y QyOM灟]z\\@M;=]$bĉObOXva#Ϡ+©Q/fy~:DHx,=llU1Ƕo7E'\?#޽5ẏ|,[ix``0?֨ܺbcR2݀E:j~Fʤ獵\w\eѰ 8;?t=Bmq@ ȯXMhI MvRt& uH+H<?^j*eh+ŭ8yIKWhY3B>xUm|#$l\qZK TdwvJʄ-~ {B:oUHZ;\߇oՕ홗pPǥSѪZu9:RpZᬮ/3&_L}/Kr!=-B=kRV ,KMZOؖzd,y=E]6¶Mڼ/eGPT;FhWϯjbt'?#Uʅ?V.wW"PZš l+KaJ%1Ϧ:Ɲ]K~Y3ZLKpî{U猁VS٣%J T5Sۻ&byGҩxXF(oY ?*[ >t(a:{ T42".NUI)uw7ar}3Ҫ ʊ^;OW!.;cf=4`19*ZFSlUݔOj;idf'?21+Ǜî rd={"dnF?kͷEwo#26˂ ʏC*\’?z@rx(mHVn- $ߐi$id_u ~5EºH|(ak˹UVA~}Es$I)gld@֌$dJ$㌌~~SǹrY U1c#k.pXpm!@AcOYe#NVD h@khg5 5(`^ K"17Pw{z4{YݽoEzckG?W\s[V++_E&Kѩ<(\^}pkWEӄ)(-2H2f$\c\+PWrCn?v`O'RP5;:MY"ֿɺ6`Ay%gમ>Dr~lX ;E[+c 叿'kN>~FX # @g]%Ɨg Wح 1j'Zwm= Elb.N 63>sskI$yg=3םmˊ#!Y,ÃϠҳdmAnE79=>kQ׏#>gG\ ʠlmKoCtH\S7:aUlۈH\3z {՛j6cpoL9ޕ;XQׂ;OD;'ZҴ..fuh F܇r {nϦszg$p^m''r+K~(Ӡbd+yE%Q\pIWU;ŝͭw20Bk5/ڮ,gi#3)c?.3Мz\<Ҿgtɟp\g^fwe5P#S! ߓZapuD Xi>3nE @*`eI#wry M  ""=鏥hk7veAL1  W{UhX[DY'_}IԭkWNޚIı\o$FA9]|T4jTcSc~̂A?qij E+=r|N1UW:p_/#_''rT1E|TDgT/SJfFtIB;'#pG57^F"C@ӿ+ŷ4RRFGt2#O>`r s'㯩銂KJqFÀ&@CWMcjl[m@#89o@H<:Xn.%A"G8axL qPc(_țU4mD+pޣ\8#IdTe;g_fM0yז<`1LsیB,zEմ$=`FV1"R<寅vP؀ $Îdd㊳i.>Ԁu1Ds"K`Ic;GoZWcY=NR ]w亨Nv@cڝ5>K8I{\,-ŵYrxI9}2`cL:f@i]''Ii#9_rc?q)c $q2v֮eS ,1KO9(\w5^$::G-*/Sd׵POz)*z*Gi'!Ӛ[fԢ~{FU#  REqm/dcpMIF*זe$gI͉ispQFϥe]YHTOq{[.2ێ8zcĤ4dn-\doƄ<͇>I4ǰhQ29$ǵha@P JT)M{V{:I8S%Iq26Aq[:)%&fco#Uu]8[,M8?ikF2۲eIi$Kw~ GaofOxpc ojx+;!9cUJKJ8 :4UXu68DTA%INYW?6:thB4MD0TsbXhά#a7##366r?5D 6MeRMDR #3ҟ++J*fXg kNiETsg`o>5B쥊(olWMRfS0sk#+f$tN"Qf3:O ksqfЖ֧ kh(QEQEw^lhv3p#)ieZ Ìn~FӸZC;ob-Պ)zV>zV>kFiFmۈ"یpݰtW_3O\5X.hnAc>!iLQ@'5gğxvvʱ(Y%8$$qM,WLlyXn6g#c$ӧ@a}"O"+2S,Z_98`^d=yS&$Ĺ@&2j J۔F"gP?w5f-,9a ߭fA-.vv4ʫs#PԣK(!zZn -PEqpT 0p22GsRԴ4)ƮYr0@ZQ|BF/nH,S&rǨITIsjdVQ$[&7}yy)6]}Rm N՜Ifa U=W Fx!6zJaCt=:Y3g O>}EBډWILcI[cy=6Oz[B裛oFLl$:di:H+~J>4z[Hw'P^FCasϧ}MY<;c .p GI6"NsҢ>ݑ" W/Y:=2{? v{7zg!Zn˷lۙ L72)B@ɤD*N*zƅi[w1fUJ ik&zP_ 08Z2G֎t[w#$q-I9m-U$`kg`W&L4eXg){XW,fT 'M\F)hTz؇FKR9ݓa<-zl9+/g7wtK3̛ULQl=ٖtIcr9zK B8Q H-ڴ-:R6sx8?vڅ堏$gqQ?we y1ONIoM$f#ڭ[_\[9x&91#1Tc#֕gF5%-|e[&nsq! dRs NU?JĊz0{qY-IۋźX:r@8ǥ6}o=:^%*R\KZŖ%U$§;'kkKy?f*\:,zJWK{ 4"{rîGz|}Y.Ɉ7 zj7 aH%YWx6sp:m&gYJ,3˧xCB)%%݉n]ҹ~g^4ug4h_ys8o0*` #=6XkS\pp<׈aO!Tg[0>7}kLʶhIwkRmoOҤY_0~D'@W$a.H#Dwߵˋe+†-3U RޤdSG!sLݔDXn19Tż- >pூ*ޖ79Dr==.kmmR)V_aOOzU4j<НozQq&p>f̀1sslB f6eӴ]JĘr%mU2x'ի5Re6I{m8 picr`wʁRBf!NMN(Q# _Iܷ^I97x۵fiwna潉ei8ʧ<æMMN/dl&l\ f Oҡդ*=0Nֳu3>,M1UdbĖ,F۫a<`ch6cPE,4V]F۳J-G›~9?Ҩ\=եܐ)`ʑA= 5b1G?WOq{t-<@K ($8A=N:?#Z(\G~n=p\)}ɺ%8`{#cYqћب3039#䏧8R=+ jQًHcI!U?P PbXX{曎1֠p?icUËyԫx)J,tHyw?D!Ԃ0FG,iv@}\ n:em?ZrS5 )4e|{+Z8*q\q]q*C)ГҹEUkWW ԕ=?+ӵmǖ_gVT ckP ,4Mn!󧾗-X!Uw6\zgVHy=8=΄Gک\Hϵu8Q~5^}>+gBN053pw8i85zvz`7`=A~HM8p}GɔYOO=o[ʎ FsMU:ֺQ3PfY.?ov$=TNSFT֭M̿6d=s:d$@6X#v r/Z+f!$\|1aǩSmZOL5 jصϹ"iw^Wk7̗7@oUUPB '4FSkLF`S[tFaQV%]] ?(\1Ԝwx9UݜeNG#޵.O zJ qhM=km[PM0'bַnSuZHFAKWܵ&wVf3Ѻ5j}.1hLҼAXqz6}}LZı$쥕F#'jU-4{??^vYp;`]GzKIn3kZ⿄n0'<`(xGѐ-3!~:!p1ЌMhPpWx5[k8%¥U!?{$!gQqckr4]ޡ@+^55U`:ˍOXm9#$uǵte}Iʁ"y4xfIuq4f=S[DH-]q ?z`j5ΓB"zd-Јݕ=sj;du{oJn'5Q VooXbBHϠVTX٢lr.#c :i%9] <ƬЇva۟VO@2zUV8c+-kY7IlF&=ʪ FFOq۾=n=-= QЈ[Jk Svz]*VWdFޅy.ͼ*c2]B<)Rw#]sN:cV~M=jň_Qz26$IT=x΢l i4f$pq1zV1FPV[ғZf ND8M:k}ͼHH0p? ֳ3w 0U'֠OIdUQpxSߧV%Ջ%uH2FN8aysOMv,B6}rxnmS y g54Eu$մ!RW9Su\FVT(p8 瞧8Lb1HbWGʩ>:ݔ>a)7O@Tq} ]YPq^XQ޳[V`ѓگǪDUTs|guњ*zuvo$!S}qJ̒+&@!QqcYxd:X<ҦťvkY#an' {Uƴur%lO.%HW:&cۖ i *[=Z V8;P}=jf d[u+!uS#Ҕ^Ot`R$rNTlW%Pe6=^1^{[;P*]˩[[jݗ :u%4kn1h0{[G2ay}?՞x͟Wu=X"IU*@\Z#T%S(#ڤ#"; 2~(+Nⱝ"`j4}j 360WOSqILE~ *wk6O*cRhGO;i858Xҗ'bq$Ҟ.3 +2=BE?:XKqRٚjǴ5k)L668:r fAiw'T~Z0xךNKAHg8[ Ls鳺JHU?N{+c^3p}E][ 69#4U= v@jRI?jmK*,N:a80Ҳt>6 ;?*B09J[x'C¬KmD,1RDiS6T 3Tf!˴-m,AKa c„좵Vg:g@Go~i ]L7NzlqwЌ֊3lNԋAL7wO)eϯҴR!b2G N=U`o,+](f`}*6`~Ts*99B ?:]۔ֶy{}}*ڀ0s"ёCVnqYHnr1T&Y"ʡ':%L,q9 ک .m*11I'~~F ngiΐ@38Զ팞eFءoR ;9n%*O$ PnX-{~\SWzj J %(qN}I^\\$-T@?Vy%Wg71@F?+s4iN-f j篻w+.y8G"W\뷎ǿckH8K2)U隗Mt-U= ~'LᄑXZҴ2k,f2[WAj6+p=?JыsK4?nJFQm߭CZ~"hE, WďW}lm4iUnM s03WKu 5mS.s/2aO+xtX+ + 'i.?K@pb+7ΝnoPٷ-b y=IЮY#+'(899~0y 7+o-G6f|xaddwo \Žuȥ*1siMzHn*6r[#[vm Om%~LgtXerpuZ&731Bu$~VPGuk8K[^^xb1$Ux,${S{wwz^<@rwP:gȭ0=Fsyɪ,B cj駡NG=\N?!CF,3'=0Y!Ac5Ryvh)Oұ?*a@h1r3w-eǡIUE_D%~VBwlsPٔ Xd~ `AS_s?LݬȪ ǜ:}AhjvڂAo)VNY% WE1rDr2Ng֩3w,-X!H(p=W۱Q^.EHU-ā{g a-pp2 W,5]F& "223I{ck RMgxn68rzֺc{ٜL Ȳ;ES$qh-lG Jv@ܹ铀GbA3"\csNddqۮN23ZRPE4o U$Z( k=3Đ]y\8==\`9b(gAl=@OM՜)7̙$ }KN35i y&uw9JQoA:I>bwH-R5qr:?`NzsSEio%mH\dfrsXwuazD*D+$LU<3"T6˦K`OMݦ>mĤ/BRH9vǩqi#$*]l" @NA#?z *`]@g?졃(G&74F|1FI'G݀ᕕzWq֛sJ!imY^I e>5Q3ms{i~dqʲ =I ֆ4sʪKTqR c30žJ1%ũk} rz^]$7"0 }Azt\\:¨$dg=?_yuQ#ލ^xs.~ת[iL$q:o4]y1U緡}~ktý)X"hr9 V{&ѲN1Y(G\zF#'%!py4Hg wɧDd9ܮ.ݍ[yNH)Ey:К-b B%p%'rǽ,/E?=NeB ;v8#^bGٛ-wx$[wo k4QE ( (; 4KAq?w \CW<2-f7c?#{GS-s] !ͷEX=+VRJ=+VRJ|5#4#]Uv m8n\~C:W+g6tmk2C帔6ND|c6ҐJóYOhi~K7& q~)SN#uqLnB?T=|ɥr@@#44hL?n7KR]U|1L|Ekj+ٵFs{<299iqk(<2]wD8PI䎂+\=l_1gF3O4]lb 8 h9269*yn\0籪Ү,H"=i"-e(cKLb NsK֌PA52]L5OZ_{>[țֳO%O*)I!PcXr 2]L.^]MJE'Q5>}EXK_m>⥧ԤFYy+}i$*T) #PF8u@`F9a5|y{֕"`YHkc*[fMaݟf\i?-H m?9?Rk 9X_ʶlHUI[u7$^[Ao8de<3m v$Ue r3hkvJnⶣe#2ܷ[Jx5BX!e^צ`輎 uB\-x>ƘmqxڻthdmDFI\:?ǎgp[8gi `aZϗORŔ8T aZ&=%I?.,GсXWOyhۻwCT6C=Eu%9' ӑ"U{]h/9r[+cA֜CL_7^&F"#Z)'[%թ ߵHQpyP z4-Ǩ#TJ[)`08ޘOOxhJCp3 =!sП«:; \z TW:-H2(b+t$pj<`FLSrH<h(]zՈgr 9#ӨJ;ۑ1RO1Qҏ(Ӻ!aB ثclOǖ#"g#=)1:Ӹ:8um.;=X>:8ۗ He~bb~sr)嶒j/Ԛ:̏ l+mKĂ|Iq,[D0Sʁ>z M"UԆ`ִ3Kk2v{gxRJNPJoDcrji"@ZqRX ;q/#223l_C] k^[_xjofR$z%5z^oKWhu$[P+:Trڥż23,.d7Rŧ]6u* )z#e95R`:֓ZǓ_Fcv})wGOjܧLo$T}̣#2{(+n\Ǭj8n?ҳ=")%kW=mm,6nM Q85~>-J*1M66kj/Wih@Pgu1RZ)F,K+iRU@>k6Z p=O g,1bG<|}LʮG;m$̺wn]E>cy|==3Z)K3>wVw+*cϾ}S"W3t4iJi_B'I xBR0/'=+XU7:Se@PFx]MkIRCH^=vIyzwEJ<\oҳekFӽIwHHRу#Xy*y-n,C@aYG4:Ԑf \{f7^:YD9Pe탊n85h5RN(昄(f(RE6wzJmv1SOS=% D85KRRf~T)'gR:M^NȆj@' Ac3R\} ː}k(s֥ޝQ> .F{Y74RE( p>q1lH]P˃?íL\ -8֗;/c6% ROZw>cbmV?ָ>Lq%Br?^˺\cOYM()<9Bӧr&Ii7=EKY-ٸ% ??޴ 2#S`V;M"2I]%X$k'yb:.WdzKttlr>E%"IDKEuCǒ͟ڂF<bWGOUc :m s]17f.l{V+hȷ!ǒ#1\: uA$ܐWssK;x5#h\@8Php#10P'`Zۿ" WLXDRd`rx=EJM]NiP2\[[0/I|fK1GFۑMcV^Mlz5r-$- cG_-;L,h<{T$Tɨj1;z`)ډ:=b{?)YOk>9U;QKI$èU_\n,?i-5-%(E Zǔ&tZvK:4`x=TlPHav\;V]-?H' ZVY#IbǷsJ7Ӱ+>+GJpzۭQy0mW]s궏 l`Hv?*m޹HÇ1RU)讫Wi׃A6;c= Ǯ;+֑ 1?&v]1S 9-G5`yǒJ2 H>e]QؒHHIIAk7hmg1x?8U`1w?謠 S\& GNƕc 14ֽS:?ja~}^p?&=נR (Q@Q@׆[%݌8goq;z_롫lhv3p#)Xobb,olorh ʶ+W :VfjRa$JW G`x:t)1O {CO׎9?Ϳ%F眓֧YOhk2T~+t;Bq™3uv\j+Ξ"Ky-)R]%4(.sԙ4fqH~j7g[ҵCÚZq{7yrW۸<0##U1[~&>)~?olڌw#9ێE';Rbi!<@) ;E!R`q@ h1Hi{b(c4iqK4@ (1Gz1h=hvn)M%%/Q@ QE@fSH>:^N=5(&}=2/Xxsܵ=)`bx  G+}sv^>l@ݼ㕐t_rjjH%l~< d- Z1dvF5Tyb# UcghX䔂VQ~j]bKYUc0&t.)#magLV|b&@:m|~me'+Oi A8= ghR2YU^64mu-jve}>'UʎyJ[O-]zګe%fz\6[`k¶)T%_UƮA2boEtl:dx_QVq A?DdrM(|E;Z~+ KDZ>k)?x0mHpw ϵuќZʭt.ܴa?޴bpFzedħj&OMh`_o>4[orHkО2*?JF( *OTRzMcfRC]bܯs#?ZLG(/+WL݃Ni0y"G晑޽3:/r|>נsGo k4QE ( (; 4KAq?w \CW<2-f7c?#{GS-s] !ͷEX=+VRJ=+VRJ|5#4#Z_eU1Vv ^ӠY^ٴMZCpceRЁt2 .]/>ًtfQIR.QzuCRXZxחOBە P$II*pI)YKFX?OhJn}ɤ)@B>zw> iq{<2]wD8PIҹ1O'N.&aMfM"'SKv 7n &9ԣSjFN21Q4wҗPbf{PF)9ϵ8(ǽ7E.=h@ bPá鸧@鸠F){ъAGzQF3PO&8(րSM8@ JE'4")%.(4P jd>=( QbG88)c%+"\wfysrM<+:F{/'dn;1 (?8:纟jʏVpr85f=N EKJF9lPƬ˘PܶzJώ{y~S XCzERKf^X&.ٍiiF3.NsΝèSS;ⱖ5X-@!L?6sݳy~?1?OL2ǝSY<+_ 4X+&a!*3a`R9x\Z>zrX{?:N/hMR$bdžR8ntn'0 ?^;}k̠dGWL;1NJI po|93uCqYRA]qF$g~ԺwSHӆ>[N]$Ҏh#vcHg,JQɺʙmXvܙ8%n#xۊhKYA剥5&瀐%pv:m.$E{{wME(-uۯ F"7';IZs˪'U<|/ 7\7œz K+$3Ԩp=ɬ+ ȠD%G |oǶS%T7*]gthG>q!5JH W +Lt&MPyޟYS*km/^^iQ"]TrמʒbBii߾`BD2G9ڶ8s=&a_*#cwn|Pӧpr[ Q^*R\Ҥl2?\m҈nd#o&煎۳GvZօ06ڌF?JX\g8D# Z3E=3;m=* &My]>RF+רBA ?u]5T~5Aе-nI.~'ޤg7Zf0\1V^ p2~?zf ٭䑲w6\O <:P?{0 :rE HaJI=Mc1G4's@r{zq9MǭI@ۃb#idQЁF0h0qҀ{ѹh1J\sNHLSM?oS@ 0E9cE&8KތPc:Rb\vGJ)R~N);QǵQKAF-%RI2@j*(j3.g|lCȥ.T>fo iqUϿΟ< s)+r}*yGn?fp"]L⦗+kp?J.$UuIF*](KRkfZKGZ4`μ.gYkMm]8{]"gZd *UpUʷY<4Y=nrkf ʠ~u {& d2y> {#(wۥ^*F~SBjW{3ןDѮca=B_²<j6:2qkz]kfUCIg8sSxa>Q%fo'a9e brGQޒvTK\`ELc 4ǎjbHu r$e SݰX܌/ [ 2Oj.c6HSɧn.fOyGv/ >÷^A岨¯9vYZ%w8>|8VTsǿҌTUe);1hj&tDG\Hzy=Kk +* 5a00z{sEB)^py%P˖خ3Ϻⳤۮ*$3`s?sJJ< rq k+9ι72Q cck9?cG, kVk&D]`Ano>艻w ۜ7} 7@5'hEL]`An47}snsn4X4ֿ7}7n:*s cv-|CC6@`ؠ Oֿ@=Ic\0 7g47}wn:(ۜ7} 3@5'hE]ۿF0'ݟi[ᾌmsq> ZrƏX4o.EscvOo2tQ;q> ZrƏX4o.Escv-|CC|7W;698[> ZrƏX4mأnsn屿ho2ntUۜ[> ZrƏX4owmsq>oEscvOֿ@9hw(ۜ7} EMۿF0'ݟi5'h9?c@o*698 |CC|6WvQ9 7g@oo, k?`k_Oᶊ698[>ɻqWnsclog, k?`k_Oᶊmsq7} E\:(ۜ7} 7@5'hE]ۿF0'ݟc' Uݻmsq> ZrƏX4mأnsn47]7nscv-|CM9?cG, ks|5vA9 7g@oᮈb`N1?'`k_O Zrƀ tEݻmsq>k.؃nsn屿i5'h9?c@o"n698 |CC|5vQ9 7g@oo, k?`k_Oᮈb `N1?'7]wn ۜloOX4ֿ7]7nscvO苝DscvOֿ@+|5v `N1=oᮈ msq'ֿ@9艻w ۜ7} #|5;698ai?`k_O Zrƀhp0'ݞ7} D]ۆ698ai?`k_O Zrƀ苻p0'ݞ7} D]ۆ698i?`k_O Zrƀhkp0'ݞ7} C]ۆ698ai?`k_O Zrƀhp0'ݞݶ7} C]ۆ698i?`k_O Zrƀhp0'ݞ7} D]ۆ698ai?`k_O Zrƀhp0'ݞ7} C]ۆ698i?`k_O Zrƀhkp0'ݞ7} C]ۆ698ai?`k_O Zrƀhkp0'ݞݶ7} C]ۆ698ai?`k_O Zrƀhkp0'ݞ7} )kFI?تW9 cv-|CM9?cG, kiKinsn47ý%wnGsĜcvO`k_O Zrƀ$oZB8ۜlo֐>698 |CQֿ@Hݹuۜ[>u.w>698 |CQֿ@JݺMmsq>ywIbN1?O`k_O ZrƋɛ.69x[>|iK9j17} W9?cG, kVp"0AT.r6n屿i'Pns |CT`k_O ZrƎU9sK4fsqn~>|.PuU 7gm|CY5'h9?cG*Ϲ|;,a-ns1c'ҟΛ@sF1=o9?cG, kv9<,7WsOxLkmw85S@5'ir} 9wo҆1ݟiOc^1?O?`k_O ZrƎU9rv#ns׌n4dlXϤ&N|q?O?`k_O ZrƋul_9ݟí^.sGݞ>ֿ@ˣVN.rݟi;+98|CT?`k_O ZrƝmQsn屿i$V+sn屿k?@5'iX.h7V#ݜqc'xOنwE$cvs>ֿ@]vJ4ݺ] c;c'ҟRn.ģݜ |CPֿ@=Iеlli! pfDU8$ E]۵k19tak7@5'hUݻVsLn>ڵۜcv{5 ZrƏX4UݻVsLn>ڵۜcv{5 ZrƏX4UݻVsLn>ڵۜcv{5 ZrƔxZ'A?촫eӭ->[nջ7 q4%KO+{ѽ?Uӿ?_Ɓz}:Ϣo4eZޟ_ΫjZs^msE*na2='^>}Ϣo45};. P5=g˵{8Rde':$ l'<^ KQ{[smfGTŽTepnezo/NVVkz}:6eIgpV7.mwi"aR5/MEhC06Mkƚ"y$ky2\<.F⵼9`bM#gf=XIzo/G^>}kz}:͵lE{=@ "FX.I=^>}Ϣo4Tִ=3U[n?/h#>Zޟ_Ϊezo/GKkz}:7zo/G^>}ޟ_Ϊezo/@=^QP+E)XO( r23-&~96;OO^r=K-+& Wո=;xXH28 :zFiwc<~[\wA# X3tW:vz +j2de+aEA<$q;$jh%PЯ㾴Y4`. G#dƩró^Cuo-y+si^5 NeķіXقؠ*z:S//R'oWAՓJյteFeu1™T`|)jɥ꺺[20%s2:X= Oj6:=VGHt|f l"GQԮa ;kZՄ E{l|dVOK}Kuv=g_υ4-Y4WWK{TfSĮpGU+'r3]t*2RÚG<7kV&YɳHBǁ[#s^{MNm9˅vVn)7m72"[CَIkz}:ʷZ[5iLccӭy|0 1%<8grOԘIpbkեogOz,% 麵T-^oOFuA<5?痆65O/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AKz: b[_JmKh;W8Y>Zlaȋ+ eg$ۇ^k6oMjóO9pAcyMFu-e[Mp(`|{6?"O*GOnF&ߎ534{Y@Q8M槮t) ڌ[x[f pv~*_}K;6 -"CW{3/8 ]-~J5[Xg=B r88ʁYZ^-7X4'.jI%TXkWP 'Y:'^-D%JqN6Ib[|淇Sk:ҟ\YYC p<]/u]v+*o&0AA6re30pC2\8/.4ohD˹Ҳc`QI={Q%ӻ) ((((((((+7]% oiLኞsZU_U|/,Z8`L:0:1ҁ35Hl康yUC! +8`H V`Pѵo u߶j6|4(!AZt|Ct@Z#{?ҼAc?Wx=^Q>''lH}䵩Y~ ?o)Q^_PSxZmi:݂] bHG8HG[Ws㑦ױ-ڤjhA4PHA8ⱴ/TۥԷ~)yI$>\IKo=Bۂ3zESjXܖ ɝ@w_B\/(Š(((((BvMZ"ZR7(ԀqPj__/k|s..zl/!kY㳶AfbGUu_ iZ-҉$ସCm=^O".'G =A dz+t*?S6J=G ěn$Z՗{_o)ji~0X/&ТmdJT0-ryU#ڊ`y먵iZtucy4FX 8<%ZnfݴW`Up'1Ӛ(V8H>EFQ̶$NŸa30ہucҵ`3D\py)"A2qSZtSz-5G#kZJX-֏mH'Ӕ835WMͳi { J6V&,uRxAdWqEwc61Վa/كYD9#/zsNIwkY(B/+ )䜒yҊ]-t$> uMMu9usu}omn%N|I$]S(0(((((,-kh|v6C޶+֝]YYۑ{ EG8<Nv/B?UWօq]yj*Y\JA=x\_JJ1^/yN%B{_o/gKomWQK ;5sq#s s}<+Kg.e'nf\? 83yxMx.4.Xi{|0`m_^'[&:ik˳Cmb'+뉸Khc3[j&IO@29oxկ#ƿxt}sBԧMF;k$d!VR lZJ'}RΑ.e(,#g;}mu._YGg @9 Cl$p8nյkoYHoyыd6  tOxSMN5 .gäd7r=}O^1hP$MKE0WUfH<7iyu1|(n]05XicR-`#?X޵-6@Ͷb${G*?J?uɾ u3bmMy۽NSԣg["s+۸v3ڷt^}_ (Š((((((\{K BkmZ[[F^Iw(pj/xg\n^"fsmF'@j:h"ծQCqw2ŷq'n~6]][J׭#ޫlAje_ o&PjpHdz+t*?Sz: b$z?}ZԬ}䵩HVָ- \}1`3A =(nJQ^FڿKޣsukCsqwGm;#p w~/m.ē^:oآ7p"A6C&6'&ߟj3+eGּ~#/ ALQчJœlg$Z.$xWV*ٴ(2HMX`J*ERQEQEQEQEQEQEQEQEW?JoFzEy$mbyE;Ts: b[_JJ1Z2QkR=/֥"9<;zUM)xEo8$*ҺԵMQ;) FEb }Ĵ6eG,|m3qlQ H K^{iq2DD>{{KX.#{Rxղc,2昌_u!]H.i`:w٩n<1MךET(2q$anV BOk{Kt 4NI@B` *۫[+Y.nanY" $J AE!ECowkq,[4̨mv8=uK=kO%}PvW['QZ4(@QET^_]Akm̓M DAX*»i[/i8 (ĺ6}qg\p僸DJ,B1עii2wg"l}XP^ ب5l }29+?h%woU{_61i=|M&h#4} ~"gW?T,~odz+t*?StkR=/֥"űmS_T2z%l/6(q/^f:|9HjW:=!̖qhpymwŚ u+HЈL 1Z𭝼IqOl!H␛ud2JM Dg}SFӯS$,? }΍\PwU Cs%4d~]j7WZ%El-kFX2Bt뜪Y7z.Դiڽ.V58Q*߃9P+ⶆ;‰Xy6.'T=jo=2ΐI/h9 qڒ[B穅 |-s[JeXnCwWko%m|+ooo}$yۼa^kovְEԎ4 =PŦiOgi;O ¡%/.0ZwI_Ցvw+;@_ϦrMwyxܸ 8wmQz=3Lo&K[ֺi&e&NH݌ת4ǰk1lf1lTP<:g\:Mvn,9ٌuBӧ馟ISީ߷jQ|g{J&_1FHL!#xwBԴsP8-$#IX͘Q;^-PKm a {i3qֳ|/ᛨúDƲYFY#O$4y_ҳ_~w.X'm7Jñyz1fsn`슥5 o 7%z$q>#:X*B=+Լ~+֧ic}X-v"X8-:k_StmR;]OI/q\[$cMKG~KhΣi>ֵmB宮0q,L#F-dڴ/ޝLlaVkg}~K7BUGiJ)8'9ICgғJH-^ +B0?*þB糷Qo-m_ Z/~ .']j \M nIL8^6~okng巘$9ی+(5mi p6 o RX6<²;tLmX!&} H~xX5>th.o\01,Lg9'9<&l?vfIuyMRXZI)B[l#$e צšhqjEiɨw] x9|g0OJo%| 1~xg_]uc,Lon{?ҼAc?Wx=^SP+?.o3kGl?;r-jR(fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣWѹUy Eq]]|Ť|EdfVV."gW?T,~odz+t*?Sn̑kR=/֥".ܒFl|A࿈!a^OKf6wd#)(@<G){OS;k4ltcw𖇬bm+XB!c.csօko[::(Š((((((((8WxF-z=ywK$oRo=[#}GwZs_JJ1^/yN%BY(Rnn.wέF9ҳ_j:D wDA?xGvg?S|s_ ZE~̷H̡Lr1 +)Pw4"ԺΖw̋4MW}@wMôFc*pڦ :BqλQP>?Y?A?BιHVY?K г/.OJhb :B?Y?^(D, '@? ڞ'*s5g^#/.쐴wj?S\?|= kA4;װ:\ŏuYhI|'=#w%0r>^.j)*Dnip2-8.7.1/doc/html/figs/snap2.jpg0000644000175000017500000007771313414613100013516 00000000000000JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJUs}}謽=syy#k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZzV>sFt-V|m.?e? Uˏk: "r]*!s $KUU{X+u9պjonZ0V!#SбV*՛]\]'r?%^dw]Y*;0Ռ;K6kL0 Ř7Cᵂݘ F_7`v, n|d*]WuQvG%Oq<{KFv fQ+HA$j)Z[xB j;C2ŻVT6 F/Lcm`bg@<`v$| 9wxn?j#Y6vҘ-$VtJlM8W@Ł.hX*Ҙ8gm;:fmg~$hCX6+IWPm=ʖ*],G1oǛ,ݗm1*EQ1>Ro"Wj>RiVyO.S;Cm0VR!(Lɣ@КKb7k^Ʋm\ڛ4pj ݎ⣂ɣ %<4$ı\<2cVcG%BȪ2F8'ןJ[hz…j:M;/VCI9fCqGv+q?ik,F- Ď _ג:cSzp&f]cT&%bȡCyŠ((((((((((_I4V$5SQk7Kf{S[ng;W~xeOa)pcpkm8)sj@52jЩ:٫K?ljkZ ?QVXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWJ5O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Z\U9#K;]XRWV<֖4dWuVsp=xMzp+?ce|"sɺ|W'M0t{/0>g^x?.jW7*c$L){/0>gQV?,+) |E8+$ (5v-ė<9oj=~BIyTVk/hb(Dc&9$``O^co;^ʄn[(Qg73(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO6/f;k+8b:aZ5UbQE2(((((((((((((((? o_ozUyAJƇ:w'VX'V] QEc[[c[@?iOܧz9#K;>յ4E!E&# ; "Eep3*8A6LϩY*jv9Xd2!4\wdV5~> d }lU^X.Yaw ;s蹬-CLto&FmgY(#jpzxo_HkrN1 Y'W:K<:$@ 1ZFKxxk3Y$A>v$cB*mNgYؽ[p?*]uCk/¯j:UI&F(݀,q1*3XZӖKΕ.eb3Gw=w:ΑY8qڡ׮FA8 dX1.J|*8Ljsqa׹ $Ե'zӭ&F)Y7ss`)[R`g@+@jao=0FF+1Xђ$gIhQsOjJTJUbmwL[Onmn[lIu[=B(%Jf;m '^Jӂ-Fknn';3 +g:^iYL\H6|u; -՞P!eYa:qXA:׫))_=S6,v}⺴ͭvK04Q g=꽼B.e.z@kInM,wO ;pFzʝ5@Uی:Fm~33«Er0CfW8T5PDۑp3K)l[Vuu3tǥkwdž8vWg\Ñ̾MuQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEzWYmZolV!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@yAJd5}uRwO+Ұ4O+ҺAhJտԷҶJտԷҀ9?NxsFt-]w3VŮAvGdzc^U jF*Zo?!LELnLnVN☒C!rC:Pz[u^/l96 󃎾3GwlM"Pl;ٝ(fkzXhڥ-_ke@p  J,zy\M*B)ʲТYKɧȇ`2@o'9 p8c!`D"1l3$䁊[ 2Ĥ%1!BY'${ſ3-/{:ێrqr*];۠KR< GEH>0 OJGŠ( (((((((((((((((Ҽ-"͟Cj׬ ȳgڵ ((((((((((((((((+͓@ Wכ''h|COXo_o_or EPzV>zV>sFt-]wß4AjS!]B%G7O"Ѧ7Jy7J'Z&Mib1+@'  jְW0UpNXd[pGzLg'K]Nf6$c#$/Ccv;/ fIn"l I ۝l|$zq~&&h"  #+d H+2}~=E"> I\q\ʝ󱦒zhvi @0 $FC63PK$2_L7ngV[$ny}4eZO{3tK; #^kFⷙf9Jd}Jں5/!XBi3,pO,q߽Zi+ɩkF 322r;K{?e{\樮mYU ]`)b 瞝Sm-AS,.r@n> /d֍3F;pQq1r=Fƣ>g%P̛.7ln*)~]Z颴Ѯf[-2%<8zǭ*[rH'hX!>w=sWT,hnۛaapvYh0ۥįBrF![sG?w2rWCom\h5pa,.7Ln qM_GZ//4Bcf5b[-e CPN/?bSc{u-pG<ɘ~ӌ>yߏ]_0/Q]>eMdԝ?Jei- iYpg4,}7k'9+6j2}w~Lgv(s3 ɵi-!+xn#`X31y⳵˖0av*nqp}t ?nt ?nic_pA.-vp0iP c c^qVmE+F/ޤ*C-#+z6k(6k(񺧇n-?*-v֬sC/<ÁzRL/&$Qٸ]`xǩk(6k(񺅅Vw}fjdDi#$h̗35ё$198$>º͚t ?nt ?n_z34 "OuBc7ˌcO=̺6cn"X{8f@]?f@]?0ӯUr\}L֫n[xQNz7l*;P[& 1 ܈G]#:u555 M_޿ o'qk-(J"3HϧyAxݤk0fnَ;G? Qtl? Qti$L}o޿oݧ[kgM϶PŎFj\ڵʹ֬*MJg,3y;WAX.GѳX.GӖRVobJݾg!^mɆ[]\>39|tQǣL,#͜&$ bN.sy]c7Fc7O?? k_piż1"\ƒLUm߰r;jvmjKU0#!)f)#ۯw55R+~q~_z3/ZyuE[HayAI\ҝ={E<^b6'b0C]c7Fc7SykOʦt<+geb3 d8"qrՌ :j3L͑y={xf@]?f@]?iO[_q'NԟGӭ4R.BgEKgh^+k 0Ld|}Ӝn"Ϧ?̾}+2!+YL,[_sZݽ ń5+*H#*H8xwQL9$oVi#1'haÿl? Qtl? QtU5~z30j66e+UgC dcHa+ir f{0/{;Is޻t ?nt tkg0je?u5W02Dpv0V+Ѥ#i;QVHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW'I6O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Z\7?iOܧzCESQEVw?\O֍gxEOdMLiK㏪}`/k N_n[-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEaiQ_EGW: o(2 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( m+"wNϻn1Wq\NjT%')NJ.+g'VX'VV@QEc[[c[@?iO)9ß4Aj pp 7Z7Zp}aqhUf$uTPVX%lXs:qd&^>gl/E?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|kL?kL?\G݇_ʿOzi'zi'QW)]M3dt}]M3dur9v*e?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|kL?kL?\G݇_ʿOzi'zi'QW)]M3dt}]M3dur9v*e?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|ʶ6[3#Oq1] `g 9TQTJRrwaESQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW1e1e_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s/_]=s/_@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3eW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>.]5s>.@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3iW3i_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>.]5s^.@z'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW5i5ib4O+Ұ4O+Ҙ(=+VRJ=+VRJ9#Kڸ0((((((((((((((((((((((((((((((((((((((((((krtxZ =J+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܴx1]-s^.(ODRJ+DRJ)Z(ұo-ұo-7GR$1)O뵻eC\˓?II?|QI?|Qj}aܿOteC\W(W(>ߋ0n_sr'?OuyR+yR+}Zo}vu/9?k?]r'O>[\5}.?k?]tY?޻eA =Z>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'޷())r,@֭W QLשUZoK u}>e?pb1 u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}S"O ȈK)WOX^+\_J+|t J+|t!hJտԷҶJտԷҀ9??Ak**1RȭX.{rx?hk;ۃ-ZG GBː=~wU.2vwW|x Ls"e+f<.ҰcdՐO\[*Id 1}+BTd2*beS98s(J0ދիFTrd0qW4N[E*Ywt״hYD]WrGRT @\mD܂&O1llŐV-'ێi4Ro&]`G, q\=PykwÂN*O\ͧK{ r|ƕXYO8;/BfZjZU 2C8Кѷ8kM 98<5ګz5Ⱥ,hLpGPp2q}lմ9`6r9Lu9S<],HY slWf^Xiyh cr#q`q8imKXŝi9\ pgiC.ŧi(ɖ430+na񓎹֏@^eI,z^גjn(dgrǞ=^x(4=B;V0n?ΣTՎef=u$NpGA=;fn=\a-$Vl:VWZ_#GZt >;x2Jr# N>>:@/8b8<u$)trȂ7gcfizǁ}PcWmo`W'' }QnFu%юHrhϹ-|AGrܜ['('Bwa$pyhcomuȏs]fgԯZ,q*[4o뱯L'm.KKxI"x/ G:U4IJ\PF#ؚVMyMJe-P)wOe-x͉@2m&;iOe6q>rgBޜf}ZL@c hϹOmCzg\ǽ{JqުxHֵ ˈ3j]C '8=a}=ƻl7&Oך:N/"sIp"R㪯8I[xVHѮOU]HJ-[A -'{tFB%X1yw-3O`ϰ<DA =*][j7A"PMuϖq6z 1nWUE!-*䁌MKDhF6bmg{fٍ_z5!.xR9[ =zT^ pO2! 4 'IjBK 3`2FO9֧ki<;zV*OX tz~nH=ɫ]|KCoo;];O=ȭ8fHPrWz-ҵM9!hoM?yC) ]f2Z]GAdmfec,H}zsE]A>BͦcPvFw_xJn~wtPfB{V`]V-{.;)_`{WVzư-t"-!W3'WS^:^2up?4y0;A4]KHKhO2!4PN=U?F,<"Ғ[ӯJ4_C[+6 k4)2+Aݏj/&HCS,@ fsUA'U-Q1[%XUz8it4syQYXv*@ E[.Xg=\r#PNNAZԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]ݬ/./J+|t J+|t!hJ17ҵ[Њ))8OWmj6v򼶒 `W9qsecU?Rrzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_OYgWh8| {Ե?l_O+FȊ* B"ƊQFT`+ ~G ~E",haUF^C^ > ~@^+}?EyM _#϶x_Q^ :Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Eyڟut- ZO]~ڟ}?+b_~[.N.?(jxWֿG,]kEmO oX׭o.X׭o.?mO >ڟu[_]u[_]>ڟ}?+b>?b>.}?(jxW}mt}mt\xjxQ߆}m.}?(jxW}m?b>>ڟ}?+b>u[_rmO >ڟu[_rX.}?(jxW?k~Q Xo9EmO X?b޶ (^ Xo9G,]cڟ}?+?b޵ )?b޵ (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>>ڟ}?+b>u[_]>ڟ}?+b>?b>.}?(jxW}mtֽmt\xjxQz߆?b^.?(jxWֽm?tֽm?t\yjxQӧo.X:ߖ^ ZO]ut-p=GS¼.N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t>;Yߗ Pׇ_cEmh 4*T'?N+t$#AL Z)Q@65.#QՓCZÈyg?SBPuHmI5inȘS$Hpƴn7eip D?'p֭JczwVm7[ʴhڜ^6w [Kw=-j)J֌`YI+h;{TzZ4g P #wM9$i*g `TrzJѼO`[Owyc#5硸h&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumgO:ז\j7;Cu_Үir}Fƀ7[Dҙ6[z ?sX C;0.r9g?dXG)ɑsN=7HKWuY03юGko#Ik0;˫!ud#@Ҩ_M <: .?mi ZIo*WѬR4dD"-`V j1e@>lq=/Zli #;c%}o0tm~os| vϡة9J?JrtO{ԡ9AE2X՚/1I=,,ĸ:g^moLJEE@S ?uO+)Xg_://'WӴQ`>g@MOk2$bKi[bdp=E_N@1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NEjzIqoOH8] UQ-%ҕ|759O蓱LJJtQ[m%߉$$zi!'ʯq;Z1//'Wx) xv:ᔎ 55i??oЎXobb#V~[IV~[Gʈ RFO֐?MM!YfoX%Ͳy<㓐W"vF/NAS%ςmcrp}k1ܨ۠?wsi5 +3}?ʣ#R1?J= gZ&?MU!者'h0[B\o=قR|G8N)s.(~U"ʹ_4 [ui%n$X* f*iT?MU!Q2mQ&G0VL MWE 3MĎ)fl pjEbX_'i wu>]ϼ5g̨2'Sl#އG]ϼ4;9H9۠yZ=u?P( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ⴟ 7jk31V(X՟y!39+o՟y3i@QƣqBJcJ/'r|C:?$PK|Rtc:91Zr0Pw۩r4xșn.nnI`! 9 0Him >LyXlv?Ӫ~ٽX58c2IUMȚTyp]jV8bIR9 ,r9DI.;[jͣxѢ++FLSFr$L3YDYb@?\uhIoĩpX9o#Qƙ\&2gex?#on<ן[ RsrMMFqm/&=#-qnlb7)C}Gd]bԵSܦm|f&"< 689\Oɕc,˓Ʊ{ż{;vQĥѱ f3ԠsxP(ɝw,Yt4^wy o)Xռ)+kkw[Bxٌ0co^8揲~ٔ,cn9tT>IL79=K-T|G/vCjtB٪( ~j%_ [ *\kmZw6׿ekCnPdÓӽ"krjd`{qVf@8joZ7fYVh e?>7fWyf(r 5j<$ss> (?-- (?-m ֖Y c@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@qZWC5nwV[SgĚp<+V~ OtTqC דyG&#LoPqTN.iސɾg>߱MOwbםiw3X]kss|+lmLm9 L^"]AΈfwt3zS/#~bX?خVŷzLTFkB@$S}xumRMl>cM$hf'#)}`bYϬW +>e4C`4=մ%*@_e 9+_2z>r}QL.bX?أV&7R?YϬQ+?u?YϬQ+?u?YϬUh##EE *-]Tכ?c-;$2OjϬSlN-??׵;/\h^K"[\c9uS+?>g>߱\[+Lk{g[%H%g~:C5ֿ\GQVv-AVM_ ;v3 ~aX?خoI5ΖڂYSyDUCmbI U_wM@wFĴZ*)p3uEη6}}`bȣ"}}`bϬTdPaX?أ6>El( ~OFEA?>g>߱SQ@}}`bϬTdPaX?أ6>El( ~OA<`PaX?ب,R-a! ǥ`YxZYђ9Ȕ}-GV?'N眊nH,7}}`bV$fn#ݖ w I2fQ6g#e|\ P;oYϬQ+?5=fZRJ1kw #30|d>2Q֢KXa[IFPYĀl98sIjC~bX?ة7Q#~bX?ة7Q+gh-"B~g>߱Ipdko j[LP"HC)f GCFج(~p4n=jnBC"D7xVֵ;ۋ{-(ZwSMt¨ G<t_bX?ئAlISW78tt-ἼYZSq!c"u 7XU2g4%wotl}`bYϬWGX܈0&̥Upxq`֮]x Q8fb *_޿ٵ)fU$Pm,C-R2pk}STȬRKKb}X `u5 kA~g>߱Qgh-"B;FV<kj<kjiA]ZI$pE.<~֭l'dL 21\嶉zܗpOw: 8'l*<}htgoiqyq*'?~p=|wFdF@@}+7F;4n7hr:"lrʣcbxkWK[<6¶OSu.LWoV50I>E[}"J_ pn?Z;)㶟*"dc*w+_"I-.cc ~fOA޵p=|wFdF@@}+:m05f`"Ef8X%QMD#<4K˸-ψ2j.GE9,yۭ\]V;Vҩ!xoqߛvf: WwQ#؊ͷQo s͜vͫ*iVVpah ?m?&O*\LU&7Qo cg4agCіB=Hnu/m?&O*\LU&7RfzdͷPn#kc6'Ua4-H14 O kgNMIhC|FK8Ae*㓁;AJMکbfE1.{v9fs ?'wyۨY; ?'Ѳsknud{DF?I4Փs ?'7VN?I4l{D@ۨY; ?'Ѳsknud{DF?I4Փs ?'7VN?I4l{D@KK;α Vp,@Ohoi?ʳvA="OXOqz}hxE䜉 `0{dVA𵤐-AIKFܪ0@Ϸz%>g=.?"_*?ծ5u[de2"yB@sNAP{[t_:Kh|~䂤K?qT}z\DU @$F%%u?YK%q'T:αa=.2ĞZ%]]`U&YW2~J_ 2ژ//mfh$P*A_%6MJ.H1 #؁9ù/,M=Y î~$s AH-\bo컞Ns1`+[%%z3u2o*yN뷏9d?k76r:"Ky vdbRIY$Tkc;IK?qTn{V'rfO8# m<.z QK?qT}z\DUIq'QK?qT;"2\zKR;OOƱoZ%JrA=JvEs+1Aw|/OM7_UܮIv::+L7_T`7T{z}Ò]9?U''Z__tW1 ֗<.KT}b$=u?:?UX.OP^ռ3uYP0 :u _Ntw|/G)0rKy)<<ͣv4-AUolUNTM"9?U_*9%#8cXEHaUFSok_*4s!(؟ZԌݢq?#]q?#V#V(X՟pϧq](:xcZk|w㻫C]+A/N2`Տ?ud<_}[}s?*‹gԓ{=M~|g¯]|*O۩90 eITwv hd89[x9 G#*Bϖ ;4Kksv"ہ.b;Hf1`Pj>/ k T\kY 1'i%k7ԧ2.+&ƊD  Nl4c0dҪXڽR\ܣZ8A#S) H '$c֪_+R̚Nu+ihy.LQdm3)5S][Mk^ %Ii%vba!U gRn]7 3+[jZܮ3G1H ʜ jq{nitXe@DlNޚWן /JmehdO\֖^G.1]vb+֧cs}q.haVڽ9NO%oGyEPYu]Yu]-||*d~GlQO ;V$ʪ2WUAӴkߴZ2Zui3HR(0z)~PwteBVA-~Q]盧2a}Qr=3W.h(;H}V4-vC733Hn}F;x:M[S¸m\[ٟh3UzLZ z)|m NjKmsO{+yIX_`+o܏Lo?gZET3fUtPO?gZET3fUtPO?gZET3fUtPO?gZET3GqlfU=p*gZ>V fUngZ>V fUnsleTfUoTk y;0]0@,A ^M VXCc֮cWPXt(.8HmŰrv@TBj->ƞ\9FTvsZz?=_@֚K5Bmy$czW+fOӢL[EW?*}=_F𣥃̡CvM;=G߻o<zu/mƹ1N yt-LkbQK H}9;M/YCdv׉2ynd.wdqZ>GڿkksԮ-4ۻioOR .9SqZ:C\i$t\FHNpѨ%x_~}֒,QUGڿh__~}ր,QUGڿh__~}ր,QUGڿh__~}ր,QUGڿhGqG?Z_jޢ֏*ڿhWX֏*ڿhW>=fqeuvhKq,Ѳ+̻jsu7K?Z6,XRL;`vI\ͻOBYŬj[YC@iG;OߵL=\5fxԪH@ܠ dQ.k#U4~6kl 31V~csCYM[yvȾ]5L1F7',TRTJln5}P# _915FC$Em<ͺFPsdrp*__[[ܛioku,IVĥS;ra9Ϋ֏Z+CV`mVTW dZ_~}֔*$N<k!Z O{G$? V8H|HBIׄu&hԆ4 hBO78QԜ i%7OȁeI[ cH }P(HXc$dP1#XlØ<Ew<1kzOLY>wu,X28LḧLLdpHfڍluw=xϰ2xvay#^9w zu gYZ3**@Hw_O^9sHEGqަVbP>1@Npp=&SCVfOG`=+'evЖ3ҺV_o kGFUv=F?;_/LNXobb#V~O#>]wwҸIg븠\*C+5 *W- qBN3) 导Ei$ҭ&GlqNJ% ovEq` Npzg\EׅEw,Rˤ^P,Gypr2=σ|9Xx9wq#hđXWNx5tsکª-.kwGi>?/DZߝS47p;7lQ=888Y6$ni ȎBse3ZmƯ-L?e,L˳snhxQmwv_J~[Oڕt]#3$QXx̖Ƣ9YsbA t֞=fۙ4۳<3a /uz,1{oxv2i~|3a /uz}~:(Š((kBhvDݡ]&M 8Tr?h~K ȹ,Bc)!Ӯ^~.u%gF$^{$X`@ ŸzV~ gmDH̿jDA?6ڢjol6 O*hW^HNyo5 `t4罟rqН7k6vQ[m2IGd. F'R1ЌpixiF{{;OKg 0K~Uizk/iMl-K UPrFQPUЭm>=:m9;BG9Eu\:^_KZ}3O"XFzFPI(X#eQe4rsP)'۽ n d!zg/[7l"5hV̎ ;p}~ͼXtme7#s sM\֥ ΗU@RzKIl7QEOsLJ WGiP5Ux@P-XW.ܦ&dv{?ӌU]n!O9bi 6%sҸ[>[yTMK7qq]o-/{,k!Ϋ)vЖ0+z Xv_B5a!ר`v[S+V~O#>]w477Jꈱǖc9nxKO jwHUchIdRWvGM_g<8nEI?׵練ծ F59Aµ<9jxJPy3>>L=TѻQzr~2JեiP78Kv./L*[6'(H0zɸբˉCMDe+&oK::_'QdjܵQZ(°(X8U ']-bP6Ӭn<C„یc֝Hԏ2Υ9S+~̞Gٓիб[G-/Q|ӑמ)8#B-ot&V -c:.ufOV). {od"ȸ_XڢžnJy،cg`Z_fOVՇk8u-5l#-qawo8Q[xm>_쭚v?op9c ·}=Z~̞Gٓժj('Qdj}=Z!2zfOV~̞Gٓժj('TWiyo[?_ fOV5ٓը2zMECdj>̞SQ@=Z'TPKd,ܷ?ʥ2z-z*R؟7;Tw8֓v_'Qdj:?59.Mq$iuv4jAeL`cCS&<1S݋l- y(ygoK_-mufOVYǭhOKK+K47Ny*)|I{aj^^SI%buYAP%j?2zfOVw^#JiR57 @/ \@5>{bRnmS5˶,q-2zfOVWT 7z}jHw!ZkUHV"ݗ/q'һ ~̞Gٓժj(.<kq[z_르(?*>!+6ndk y3M,M5N<␃ppzZ5j,Ԡe[)O)ZbJ:@'iy8.sJ$8⣑4.쪊2K=ii8nq래r΍>^J f# 8 9=sN~Č(.B["ZsYU_xH7<qkSzjWRoXNL8gX]_J ePl;~ 6{,Q(y#5Y݈v@A8#xֹl :ݥV +nݑG 'pq/,& y㓓=OzTӸ՜Eې}%1}+`H+Ȯ^u=wX˿v$c$E;QE ? ? -ZOt7ܯIpƸgKBe7sQHڊmavQGii롍B.0 P:B^bDN[g@cԊڕ_W|ؓ=3JKC$+)|? ֝8ӏ$v1VUf-~ bsdf!of/_'ؽX&㓞q[||YKR]%VR7wnlJcwxK>}^^C['nѴ 2{v]G'AG'AI_!obhe.[?`WY;%vcXX_6[5}JOh| 0?iQU7y\{.T? O~>O~.T? /QP*'AG'A@h^||]y{y{b=fqHFTQY3Y~o=IP:Mèl$paܥ&yc=vپ\AaQ1^]O'AG'AEht OGMrf9`IJ?m[iFvq[ h%s V]9U$epE;ϓߠm,nahz9 QeGchҩa8gp{AkbJN~v߱*y{3~s1ӽ=$/$9,S'AUqX˽5N1}#ܭhVܪ_q:N+^||.vQPs_X>64? VyA\V |/ԆpTQE1Q@Q@Q@Q@Q@Q@t 7]'37{a!c\u#HgomQEE1?J'O⻻g\$3PsT5gX_͘ZYzͅtCvcyFP:V&1Fi9SŸa!s3#6b@+GC {!KqbT׎s׵1OhY2ymل1ujI[ gVw.dg[fAs޺?FO omٷv}+ PqflM)OlZVmW⛻.#YMy${r0C#kfX|t3Y3ƎQT[nu[FRmm0D$|Sf.tV_](DNsߊ;EZ'^Oe& ^jI$[ ˓铐Hj}SZ77b6QIDY{* A1W%Іo{:A}-D1 3z4 ˧xbMݵ$:wlr9N–1_̡}{k>m?Sy'TL(p~7z+]N9N]>q)r +֤O[Gsvݗi cgt8J{g.)u_7_e}Zo3$ڼѬVD!.0cJWծVXW7%*ͻdVlxcuƯ"(v*v#5ţGssws%Q,Һ~6=+~sԳ[Hd'- e,OXwV1Gأ:L>տ2JUQF7sJ.ӦNMݦ]Htp1CiK="muu*̒ 9 dvZmtm@X#(ITLJOajKk[!]QEQEQEQEQEQETsǼRTsǼ@QEQEQEQEGqCCsqf]S-Da9T/S#֓}?%UԒ,i7!DIʣuߨEMaer6v -]w5-B,JqK0HMIUfmi wQ5$q\;~`dxq5歬DHXjՃ>{ú~#(bRK~zW q-,qmOCPZ^[uk*(QIYj'Onw2gP[a@0E#2`~P2Gpy腔0R13ɥ:7^{,添419A(=*ψEaw֧OO/QY%vu/pLOM$7O/G_ʝE!QQ@ QQ@ QQ@ QQ@ QQ@ TW٥=GqiiSiSiSiS.cO/n/_ʙsʡԬ,^[}}Gz}}7epE-?Zq*tVᯆc_=$Vģ7aI'?wo9 ދ"O mUU!sc')t`].-/գ$+Zq*,.5ߧeixو0i?G=Tӯuhޝg$g$eX;Z-]wsXZG1v?qV~Ӭ"B<[@@R;|j[!oH77\>R0`*S}i[zWO/\?ش隤z|vBIP!$WuIj7iS O_z<kAjC8*(((((((Ofoo k?BZk|?5Wc!i Պ(V(";g\$3Ww{+F}?j5\qvO& !⤨yRgeHg0 ,uK:5C%ws!VBy= jn8McxGvښX(2kA;uK\e'aE-4,rN7!A/4Ym--1O$o=@u`?Z'5SLmm:R Pq𮃐/titKa& Hs8`i>irͳx[Udۍ0 F$%\l"0cdz{dTyQEQEQEV]A-hV[W;I"/ Ҁ3olHs#рOV_W@YE0̎4u£kdұJFzjH]öeyb 4qɠi_%O4y$vV1 #;SVbNsޤ6lTXXlMOeR&+KQj^;l#82IKm$B#8V_/mÄT}yӴVooBb/e eveH\[Ofb |>QI rI+\B %#,0H@ E[< !|tWBA+)!I5@JFX`::TEgQ@ (?*Z?ʰ|m h3)((((((+OfvЖ<!ݿ%_3]q?fXobb#V~O#>]wwҸIg븠~Fժdp%Hґ b#RMe#Dw48W7IxĮ\6w96W45Yȳ!YvF`*NJɞL^q]3;Vc}jwV6؉H. g,CxaiE%&p3,騵V˨%8B,58;kSYY>}JL/p'^K]O#C˪N$jrг2H9!ĺ\iOrLVUpCrN3Ww.em_LAgyeI$Fe1U}n+hhQEQEQEȯuseuoƝGr@S q-̸6 .1ךۥͬզqs }ؙo+U,V{xm+W2mc]ޗk"7**&8"}YM2I@:q(9S~TyoS~TyoS~TyoS~TyoS~TyoS~TyoS~Tyo/T[q*7<#}ڀ4yoPhyoPhyoPhyoP7/W?/>ӷ_)uݷtWeOhP<4N0ț=hͯ|ɡX[[q02nbw- TWS[`;U 9?:?<ME-QZسȶZFCq-۽ tu3t/i~HttO0{Hg?gݭRiKnJcePXߕn c'K nB&>28K+layVA2(ko`חu7]6x[E?"?wammI,Oq ɕ[09۵XԤvKZ(yۭ\kDyե(=p{g![K݅ &(=7&W,Ilk<I e=RyotNQ?ʰ|m hO_ ਢb ( ( ( ( ( ( <!ݿ%nOfoo h>Ca\}3V(X՟pϧq](DGqpH#ET1g6OVw-wڴikޛՎs zֿם3y\뼥RƹmgCOx/Z4kXyN#r0jwu5^^-w~fNvF1ր7<Rƹmuskoa6g>vgkq-ք[-f ѹpzJ[v:)}_?G}G[]ڬV ͽHd9hF\}:Է1}E4uc}cdߕB{:\:|Rƹ7X.|Q1i4$3MV7ʁ܊Ov%6|.Ēlol,+~RƨMYu] i,/&eff- jiYIG67Zѥ=s%N}MpnH`".H+ջVY$OXq W#{c1ϧ@;F2Q=_k'|McQ÷5NOr\u ^fiq1}k2/=0'%M'K3gc9[sw4QE!Q@Q@Q@Q@Q@Q@Q@GqIQǴ@QEQEQEQEEsʢu+=*ͮ¤ I'9$ =fqs0an-PYn Rϰ$sڀ/H}P]h!vrG5nT-2Ą3𑁓Àq\J~wu@ַhB4SK)ܽH+7ڗE]^^Y&sj:񞒚ej.EG(8\`3VOiVHyaŔ˛ xY Ac.%IFl=+޳^h,~hچMY0lV#hoF]b3JM»"BYSYӗWJ7qD2傎3hj%o-89Xv_A7ybiqӶ?W4%Fk\]3<.?9]ZxSZ[IB@ NXwt{(˴(?*Z?ʰ|m h3)((((((+OfvЖ<!ݿ%_3]q?tv[S+V~O#>]w5$N.属}*zdsGoqq$ I9, O&9'v5 j53^9K1%Hzmh4#6`3SAuosȞ)v6?* dt*󃃵\kڤVSl- ݑUσPZoMFo_ ~@p6%vw_z_#>M5 A羾hݮGb39ɩ.?zE{ qks/qݜ:EErFQ&mF;dاbl ;*{ Yn+gc?skG4SnG[k:BA~ ]ujQ q֢`YFw }φ<@>׷^WG=~o^տE{;o4YD%(AV6cW.-5u'${Aaw?ۛ淼+zݳ<wⶖ ? ?3:[{cDgT>Yb?Ÿ#c̱#]qU\ߺyT$QVS4X* Vn%6,"nO5kϏߡ[9tt!Ӓxt')EEqwVV 6|\Zk؉'nj{4y{5J/ B)#:_/$;u=.v~| | svݴVZImN2IGTӅMIǟ.8 >?~>?~+Rh%Ibqt`؊.{4y{5J*(CGCT | | R.{4y{5J*(CQ\O٥>^=p*<E]hjwϏߡϏߡTP>?~>?~Q@.g|ݏKu{KU} q(f`{Ā PǟCTnl.K-BYd2Y}̰q9k x mvLW(e,. c }Dc-͝ŊŒs;@?+0ڍ#kϏߡϏߡ6/}>[stxf\xNWy[i?~>?~EŅ),Dw/Llؑأ | | RiP5UoC_ oZǔ`@-HgESQEQEQEQEQEQEWI ^-sux'C3׻K@q_uWe!HgmmQEE1?J'O⻻g\$3PsUfmjC5ij8G avaǥ!DhKRO@?ޫ:~ $n #Og+ f ?@1jnt]f+N9ABW$:>SU{_TپYkn:~e@S}V?4TfU 7ٟh3CQZ3GqlfP*o?gZ}V!3fUhGٟh{KU-FM+igELp^zUp+b/+>@dQi#m:FcVP Wއ8C\Ck6Q$jR>Z`*Mj]k6 HK7*ޕ|e5 nw/`w(,ig\ )[fYjaX1WQ ̑o;.1$eAx=K]cOƍ=$knuKE6%(ѻqF[ t7p$OGmSӭ#Oƍ=$jndzIѽ礟C64oo'?PuM礟-9$u'?µ?eZ=2G%ˉ8#=^itfҖ #79\>5qݚ.xSrwllU჆<{Gđk6zlVpLM l,+RpN=9/t=OL/5+&k&BOKxRn$/.VXw`J'TjmZwzwZGe=ȶ\9cI@>Ǯ}Rk-YZ%ۀy`R?ʹ]V_u4Pc)4>\IA|<zL]>Aey-5{z [h)tYWw[ PWy~>Զ~#k.M6\\5~#;Exz>kkgv.r ojС4.=H muR3lL|>BGYn{跰ˡILYo&"!y f PWe q8TՔY;bw FӎqsM7R)K/Mͥ. ;/`dx+-_CL^ EٚI"O."I~Qx@S[?.nn5 %ڧ r:)$=*վxDࡌW$-\[C>&v>Bx R֯緊k-+YRʂ;Kk~K#u7WHlv5$/z :ҮKCQxwZ}vk,⸒fN9sZ7v/n-Za2*!ԃ\V?kB%[jnd$$7$nleosADG`FpT ؄Þײxr]4OIS<% qsOŚ=qne}m,oJ[u)G \Í g'#wJ: ~'Niopx%H.g{myu[(C*0zUeoc#MԠYxEI>̻ܒh|*wkO(66Co< (\g 22)SCcoľl}&%mz*R ab/'f (<}転A80\'2OK>Qqya`tv:䵴̙XN:OKj;zƟaYmvnC£o4Q$oH6!(!GVÞ׵w:[o?^UjohźMg'8=)/??6Ay?SF1\] Xʳo0>] r )PЮ Lv%'ʉ:H.@w=Š( O_z<kAjC8*(((((((Ofoo k?BZk|?¸/_:C;kob-Պ)YW ?w?J'O;̾Q+ pC:ӥ63A:W4 [i7x3:_n9=(VwQW:e(;wf [ğo텘*N##D"D6Hn#R A޻ +~9zc֑IHu!Cm Xt $ley2]3_6zƏLǷhf1} QTHT+wp71AT\kiy:?L?3ok&V.VE"Ti6^+<-ǘ OLqU?Ui3C6zƏLϋIGݧTy#ӽB6upd h 3ڇ_AL~/ӹ =cG&m@cchZ.$=pA ׊I\̈b#{ݿ/b?! ͟Ld/Yx7Yl#o"ˤC}8y&@&8 rG5KQ[l`z 1H$qבDe0x94w~T%pC hv $GBgҤő@\i1M4rKX{kim4[ڬWO=DMڠ6Q8-!懈3NĖ|F+-2rR3뀕g6zư.qqHDIQTTKN_qWQ_g&m@5u/o_f_ =c\7Q /?3oj9d=yR?\ltX!< ov7? ?>o/ZMߜPDOOer 9Gd&7&Fpqޟs~_O0ܼ3Q 1#h4ɬ..;c9Hi@ߩSt15(HRHD^!"r?>o/| _+KYt{]HaAX 1>p6%04 +] $g:Rk"eoO7? #9uc#7 3nj/bI 1#&FjͫZD@$OOX~_K˰~/ηbGaQb{mo/ wAe1F7by`H$U+k$I#F䞀qGq֖ &63~?  <ͺFY\'g'¤W5=xYʞ ?2?*p:,kp::+ \*=OO/-~ooNܝ3Q 1#~k|Ƒ'Fs5uo{"Jo7gi 1#bGa\^7Tv~//T(?*Z?ʰ|m htS)((((((+OfvЖ<!ݿ%/:+|?3V(X՟pϧq](662QLAEPEPEPEPEPYu]Yu]%W}v!e nx ?{ j73]M-$pH=?Bw}^ELg7$17_HۮT,nUGֶmC*pan#ߵo{? ӿMLpxBT5ךsqZ-[sHORwg Fwv>YL9SbGui_&Bw}M+{! 9ۨƻHaF#zG:S` kcʘ2=y뎧o{? ӿM?64? W|QEQEQEQEQEQEQEx'C3׻K\t {\uY~QmQLDwҸIg븮YW ?w?RR?Rv( (((((z@ZЬz@ZosVtyͿخZ/5?0G^k_j6jV 8{h7|KZdwjfݹ1\coZYH(uqSBMi5 [S/RxxEĆ8OONj:ՊH~9@LC qG$vI|\j!7t˷]ӥhj ѯnmK 8dO+ u&QT:(j7>cX$Z7W86g@668'sW;]B7ZD{cgUt WеK]f=Vվ(fYqo0`ԓԽx@n!vY =:]mS~ɯՄ`; 3 53ڃv[]j-usC4 YKa0#i$Z5\Mx/~" @ 0F1Ƨ HUFa,k .С7pO[\=n&K09O, UDʼyȈ*>84;LׯS@{t]5fgbu$ ]]i\,K t@ pךtE!1gPct~uNËyNmѮe1.Hb9[M?v ok-gOuPNぃ XH/lA'd=A\bԮ4l ghU5/}k~_)EV|Q? 4UoMoߗ EV|Q? 4UoMoߗ EV|Q? 5/W_ Sk~_*l$E nRTt?JC3ЍO5W?_teT{S>G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{*9w[IR0/=i{G} _(/QE} O=i{G} _(/QE} O=i{G} _(/QE} O=i{G} _(/QE} O=i{G} d5\IB =*O(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PZǔ`@-[i{G} >tW}(L?P#\L?Q?Р#s0hG`B<ϴ=i{G} :+>}(\L?Q?Р#s0hG`B]wwҸIg븠(0h 9 $s@QEQUcHǐ~4y[ʒ<bE h((([0Y܀Y\(>h?ռ+65۩ati%eU<8> .#0/n,,f՚WۋsZkK{j^|z5'%) j+|)0z^w5Z#ͩڥ26B5ͷ'jyn|@ !wusߵ _O3\f=bY,MG*>. vz+ًYW$鎹p:|њ|g(}D^#7$A\I)xV$MV;&[)v`SbuL?;<њtj:պ3Bd"! |dlҫ 9/qH,.!gt2| S1<ݻnE"x3n_&,adZ^+&s`.xI H0cJׯ槙]\VuiuKY$yorăV]suKCtm?0qzǯ|;,њ"҄Zc*rBqb[=rqhKYO)5.Fbmt0hr2xR]BHV9|ӄ<=G=)^!:ޘvOD9 INFk ģSHhv\H|;r3ӡP=uT)qpXܶof73\Qn&U3q<'Sʽ]UvjN:YoZkYK0nF]w4QUo`$}$2"m.N.K,qD (weί麄cpA"-QY6Rqc{k$-<`,zy$ MJ;m$1#dykX^&%+Xr9Ns2qIch\p鷢7,# c#(ZijEP$7Ios$`E3.r=2qOeƟjI$ ۄ<{{o.WJ9,o"!HfK{#)s9q3(n=CZ[f+. ynR[u[j̿z8Va.QU&t{+؞eW9NjVUtæވVGܰG$݌tu ROi$lH=Gn=RǶ31YKe}j0=AV]rH8 e, Ap\3,R JTps=@(n/$<_ö@|9%} o.WL˷0N8Pף{Fbʿ"`}pA%cj}I$&fF;q@V=Q[+W1" A8 Tt-V( %8rG~Þ:P6%[܌RiZŞkum,Z(b + HO:AkՐ 4I{V񨕂K@%ϩ[,=K*F# 9:,o~ɜyr[I- Wa*νgtWN7b8<ߟsESմˆ-g~qL>=FkS²ur(xk b $9ޯx#+8rY ˴ž[nynoisڅ %ef5[H {C$FU/x@UkmFxudK2#ڊmn#k1=|C"x7r|k#`0Zi umt%{,avdq]ƦڏM&v(' t5-i~\1rN9S4pZK>j( $fR89ObRIa;N =3P7׿O0oz-´"(d1kQ@'$$OSB ǵmi$kԹYN@s۱}U x{'ODm;K >[TP޷9=.-gzwve*y70s{iwV[MIn!WX[І 3NA>q9+d7(w1R(v}Ek\E`~p_5@w8]X<'Ζ -77n:H%4INF8Ϯ;VﰬrMԵ-5㴅XNX70sAm^ms̚-M-͓EllIʾN1gMvRc95Y<,<ۙ=:|QGw@w ]j:#6ٖY;ϧM_H,m4? \o\G4q\$KM6 i[[$Lɳ/RFE36Kav YP&e;-2:}ޚ^n^kfePHC.rq][B?9+e/?;Wş[j_U۳_? v)G$kY.Vإ!vrvI] 8pzo̐{Ē|뷥P _vC}:KlљwW:z%ӰNͩjkedm-jRRY3ж1) Se[I$dh㐣ٮҊ]-jG%jv^[ܽ [֞D;pP8$s֏k[i,3y`9$Q[2XE P@ 489|9,56H p cUJ 2Ik=֡cÑɜ # wSt]jWڴא[YGdtفY2$=8*Oh-ei}寖O&4ه t=^E Oꂊ(EPEPEPEPEPEPEPEPEPEP\:됳wo@EG{+F}?՟pϧq@QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\:됳wo@EG{+F}?՟pϧq@U[h%zM!bYz\UC"{hC9; I?(6vQx\()Wj󵪬^"fHd+;Rx&@w.᱗8sBCEdM}_j"o7' w~65z[xo LO8f6.3AP+&6.w(H$v, 0O*jV,pC@(((((((((((((((((h$\{As3szqx⩖6qLoVP"٧ߣQiUc5j=ơH_ۜp}igh4? +6>1vl3gZiWWc4䲧\PF#H f{G~G٧ߣV#uNiE9m BRK9h_8e`x4?7P7C"Y_e1#L' I^S5E9]c! i̱x4h4?˻׮%Ӵ; 󈣏w*3K/ t,?}]_\:<V(X՟pϧq](.ԴqKN?ʧ?`'U eU4h$y!R@.m$3r'ҙyӢ-XM@,,zz訦M j6oEkyO5[vsִukѪi6bIp9;ճ=GLw}5乒o,+G9ۜZ;csiow-k wOpaV 僀G^hx;,5%1QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPPzUdr$fUt ʤ$2@#M7ύ@7_]1.|1eoW:^moy!UB䎕KAf͛h2E Mu|u>7_]@?OimԞRLzN:_ZKv חOraV # G欱*Jd$yDYsύN.y j'~qtyύH /i]ۣ?/ j5."f"[*Yv'ޥ2 TeCq/{B?.2Z=KIol~mdI"u]@ ;T5msS20MfQ-1v|ϙC #ύG'~qtZw2t:VX4Y܌g?J_B}-f'ExYRǵt|u>7_]6u1[tK5}Bi]@#2[>HO++ 83[:]ņK pq6#9_?.>ONbOI2¨yύA*DVS+#&p>N??:ҧƮDh_y+C7J27H!Mr)ArRݴ2_2cjR|_]p{zYƍ/lsҴDB%X1g~EmjcN{mK]MHT Q'  Mxd+,mؕU#9,}ncj_R|_];Pf_^lѐ8EV<ʵ>o/.mKquU)+ЂV[l]{E%dcN9$hqrǧo8ԻG66)勻6+wo]}r9խ؁[ S?o) +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57R?5YOO7oTmg/?LRt\|O?ԟ]|I>g{hx._϶~O?̟]3Fkr}'G._϶~d3^ ğߙ??r}'Eњ?\$m3 ğߙ?.fׁiO.\#m3p=4f/L2tiO.5|G>g/L2t\|??̟]|G>g{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2.fׁiO9G._϶~d\|?̟r\#m7(3^ ߙ?|G>gQp=4f/L2?r}'{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?.fׁiO.\#m3p=4f/L2tiO.5|G>g/L2t\|??̟]|I>g{hx._϶~dO?̟]3Fkr}'G._϶~d3^ ğߙ??r}'Eњ?\$m3 ğߩ?.fׁ'iO.\$m3Ip=4f/?LRt'iO.5|I>g7?L2t\|(V;{""v3t5ۆiQER_*5nsfPʏ##H䳹,'74T\թ,g; ?LG"‹,31n5s5Ϳ",r1t6N0L;cU:԰(m Z6P< z|MS:!: B\: FY^K'  8UU^+o7>B}IJ4yź^gx֘K״ʼn18`+3isxZW7K_Ʊx4COӓMpY}(iW L}b|F6}>[h-`1y8ϵYԢY / n݅>vK)M͜xOlRL-eɂxϯ" y%/m*\"-9;YpC+w@Ӣ-ݒ+;Jsc5K+4RDN>ϥ%ōů(>pm9>Չ6L)(U\ʬVU+ەoیdPyҮEKB$,v늂-ݟ2n׊؆-{rlwݞ__!m?ioYÓ54H2"S=Y,^tY_,ƨIg>zϾvVGBSEv_ ˁ}EeRcGa*GJ#HdfUP>ĖQ.#Jy747 5G:DZX=ɘ#9MpͰsRZ4(˳m[ Fm"9,[]&~^>Ѵ :=z QO2?:KGO$GV1&Ռֵnc]A>ҍ[,oozu,Ј@˧,:P*[ӈJn{Kc}՜&vMN:W<'t  n=M:[qu}ms[568B$q@6<#'f}i.l[hVIxPAZ?nαݥxg} Jf}FdHve1 :\6sG;Fq0w TkdӆڄVԗ0wWqDҬ{%0~jLxaVf _Qƀ3la 9%;mg'O!BkM QB)";rqUf[vHix'@h'6La=~y3 _JYڣA|,3Z`ȷ1kb tx0F08RM1Jyf);*چ]*3?teJćvXpqa[y>2d`:y84[^Koڹ'´Ha{nA>h1 aU#7dndS򩭭$[fMb~PrEh-Y̳琬=‰6^3Krۻ|Pap,h)-`N[̃IDZKrp{ Ypy;4hfBH#d9uphkC- OԷߖݎZ-fdio;$-6?ސ lgT,)`!o>8^6`$RN+RM3tǔ,sTfZ|9lO}@qm59PH 6;F3'zIؔ &Ўi33UCw Kc1zH o:3A*@_JjE,w Ԫ%Jf}%vC02cYsE$KcXfh̋ $Ƶ.a* 11EZ[ [yYil}Iv^NJXUe#?L֭մ1iGLFnLE%,u;VKtsژ,;!YXKw8B$|MfX΋v/7p#j7QhBI#2cssŴDXgA<*F֛*G P3c$YC:38$1LdA1R=1֮ 9v#n* 'Qxr~ z1$=~dO &9#Y[8>pFv\;[D]QYF }2ĢD}2wrzzeq{4~I^O#fдn[o%OZՅ 2H89/ݾ&>Srx.(Ϧ]j);'kݪ'Ö\^%_$׌`kCǯj :;$eؑ2^GJ@Guk[ JO|TveuGmhg=EIssgykl۴M/wP=m7  4ch,,;x2>y*lݳ4yqC7b +&Zb,Ct\$ 8e=["m gE۞:nV~ke@e.$hRA$M5Lqt#Kln,."lF2 B<ԋsJ6-] UnQ(q2B`v"+x.ċ'^Sb2e$_{O;90|83]++_A@&幻K4ebGK/<nnz7[wXPFq`zc?Jo#( $]*k,#09=Mcdby%CV֐kL;pZ Y؟$ (ڥ& G|graY;qCmu25̞R>ݻvZIO:XVObj:\nm9 u[7fH8ݸ^P{Y Y){aܡO$.{^4+0ccisg4ˋKMhǻH Uu5"u pzY[`C#mq2 diXJ5nc H=Ni3m@GOL8i-]-BCvH2a[]G  ?\gKq-E$&*r@^GE*[ @?ME-ݝw6NЫ\VO,aGZkj,HP4)$;r2s֦-Hw Aӏ~dYi.`1{k6Kk Nlabk(f$2r=ԗR.f󌄘cޙ$Z4D{)A?@mFUŴ*[[A:rBg)gs [nCr9.[yY!88hOyVJ٧BZR\;TSs.xF@=(H3kw1UIV7L.ܝDZR[89TIl-Zsoe9g](`gQP2Al.?in }Sg&Tz9݇| NuSB.E+/XfVeJ>WSGd)j]U_\K4f&zϖgsc㑌CTh 2JA*F3Ngv  z Xg RJ'lhX 4Y|=6y=Z4f(R* RK#}ԍ 134fK";ʄI2@֙@hYMom93֫P倱Rt5Q(4f(%YbG#]0Q@jH'YJ7*Hg'YJtPFh њ( y^gqUp8Z4Q@hP䷙eȽQ@ I$f(H >cztPW[Wd*n2`-z~UJy幔3sNUh њ( mfr1O 'x^G?!U4f(3R$$8fE4Q@jqyph3PI'$4wSDQ(Hbޖ96+L$Y9 v*ɥq7BҖ :gp/zf$+HgdT[[#; `~uOr}3@ EPȨW<M()#vFNiPEPQP_>E#*3UO;Sh (Y+`r8"ff,Y$J(((c~^ٜ6(Ve`X3brI9&Dۢlc(~(fos9ǏΡ(*TGq2(!~YI'$QEQEQE9wf07z mPEPJ  GqIE9O9E<)]G+EDYG8f(!BVt X_4"QLojV^gM?IIV'LaV?T'ߑX:$i7eurA]3ltNM7[vjk{] حN"<<$aXiMlE>%ޚz4'ߑc cat%K]dD2m vGGYKgV9B6zqIa-t_awRw İȲ)5ooڇQ@mC_*5smMZmTQI|,=g1r|ey 8'w`>)a4Q>Z4L qNOVh~%2n@:q6Oo"k,l,dmvASɩ-/M`Z5A tM]zdU5^Kgt3E)uL62*#`:fa/6E3"|K?j@mC_*HtOʲqHuE#@&;_CE7?Ss\N y*/5sPz_X-~쮚zS3% +4?D$z^"u[yaOS 'Zt)A(cGAGj>&0\ [~}[ xowhۭ5  kB;+SN|JJ%BxgʗCĭ,V$rO"ʢ +?˜V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇP|#N'kOݯ:Wo=!d}ȥXd}Oݪ? m_k=yH-_>)z&koH<ל¶eTt"ͭωͶ ]T>ݷ]ߥh lb[n<Db%HSm#m#Xc|W=C}#9[UuQr/]W+o_G+o_BCl]h0 NџmVͬ*& O-̇$}_@YU_@YU \KCWC{NOPd7Z̊ۏ)F%vEgU)hYHv>GV/,?*V/,?* _شUush2 W=]W+o_G+o_B@Gcqomy+:$wP(圖\iGj!8a $4lnsڱ[x?[x}sFI''[MpwW'pJYտ:j&<g18?V/,?*xƗˡ Hl203ukO=/8׊+m#m#⩁]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@:G?Wzo{Ҿw/neY$c*|$#MuSB.E+/XfVeJ6~ѦV-#Qrjާ7L{ƽl@u_;8S>٬6oxV o}({}Y\);_O}[ya~RzT)nn.nu+]??3;݂3Ÿkv5rfmV$,O }W-QR$>^OP-jFdSC6s3k4.J .%u=w#HԼmLV2HmGY_)$I<+":z,\`U*qe_x!o5,m6niLe|L pt,zVCޟ çi :'b 7 *Ɵ|f >x^y7u>f?5 ɚkp#ߌڨn-}Qyٙ8H|GYwe-V;Yvu᝸?JLߛPYb!t&y7HgI @-y隂k|DKCrrGU7USyYhIpzA k-Łw2e#,v.^+ kqhLojX0H/u8i!RHR،<uK.mmuq RHY 3 w pܢksiZ+,vc\8z*mSJK/b%u;3vG@';]ÿ׺9Kb#p Y|“q#wpLq>s'5+;rv`P"Eҵn]6եL1Hq1gtTWԭbVfEi'U'<|3$ LI+tϴug1zdGdbl隯eCK=rv$M " 2pWZ]tkZEem=PJq*cXdu qtzA.~s^~hkZ]AwZBZ?27IX}+F/[#Zܹڂ ǯ]ΉuWk5nhDs5iutkgvISEv@J°Z?m:4Wϻnp#KRM,-de'n i<֒n\۫khF${%A8y26y31Dm;1Yri70IgY~ٜgcAimi4qv(@Q$27$ `tJO3]Fo!k(.\eqs%7OL$Y1 4 ȵB.~۶;thAu =,N2FkCwkkrZ%)_(3דtwOq=FĖhA$ q~Gkv6ofUft*#?.y#ޛ-0C*m0.Q[!z;xuROymmRJӲPʗ,j8삧wIn6tXºL&]с԰$ʹ6Gee_ '^.n{yq!C L|Mss$a>Y`̇f֗ūOzG$6*,JdʆGUZtPWXU{yM6KMNy$j7c΄ƫ,vW{k=H'ŕU~݇T{/3T2:䃁QkN[5mNZma>w,Cn=`o,d96-&}V;|Ln->S򅴖7y3H$g`R C}bxY-4- ;\nٷrzfjlNИ`[rq}wQH}WzͻA]$b0)U#-ǽTtGA{=lm\Hc8#j{q]z^< Uhc۳ۧoZK]i= !Bnz Söݣ}NjAMz։pPΟ4NY~ FFCڳt]FKnmM.;+@HlZzhWJ a'`IG0:u]?/#-mvֆ|G4^f|Ql$~sQtZPMyK\!E[`=oj 4>cAS;F6K[#2$2lB0s_b4=B)"X]:\09ni|condȎ!oaX9&눬Go1 mU#q;O@kWO{ty/cH52tV#95=^Mk]>Ucnbbs$dqև˯"jKmn3*Ot#!ԐUNӼ:fq}|pcG^ ZVq3\sT2OnjcKåtV 4Dyy{sin/&im Lpp}=jX/Yl0ֳZx&Η-dxjX]jmm4 GLjZ_Rg{{okZ[/8[q&\afbR9U /Gn:XVv8RqNrGcU4MCH3_ZXihѥ3-Ĝm/林įevt:itKk-"#^W[Aft1[;eʕWf;elKkmy & 2K78.pG>S=?_x-F爴>@,eܱ;8 YAw5bSCk#1m)FU=+O^=dRXz_I;E4=%SzإXpa8vZi$@MCǽ6bW0 0!8&5s'ODm;Kyqjz忡6!t'?BA]r:ω4Cy%\KS>حqo=  < &/?RK<|P@8*Gr jZ|bc] ;Cgv8hg}5?d{ S#in=Y9gѭ^9b6sՇxj[iQK[skn/;O͖TR{^mԚw1^d? kή5wAs*g#liHAZ\]Ϥ_,r <䎔ofGx=cTkةhնBw12p=:[ֵ= 4@]c3` r}}ꗈ<3wu7&k"fm² zkJ^@ZY4WW wc 1~rx:*O`ȭjK|kj݌ oQP((!b gVFi-Y2g8bwn+\\`,mZ dFm<ҵ4+}oY=\Dp~Z^5C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (10T"McSg%=!`H͜H`;jށ{{\# ih%pȘ$9`s3.B4 p9~$s?ܲ4AX'`yX&U=qץAtke읱Ud_p{f4 B]DϦ5N|sC/gS-l!-*0ll.-R{o0?>ľ%Ү<S :s|%۶e/yW>e'1\3ch/?訥Yi,ci $A0H+E_٤D;2}<_+o*G&]..? _(/?&wGm<'<@y>Ee/gb?x?/]^ϲGy>Eq81\Тue/yW ;Pآ@{8G_^ϲGy>Eqwgr,m ۓ"ve/yW>'* [B& hH̼e2}3ii k|_(/?&%ҩc]3ƢON sӚ_(/?RoDO$Go&&2#[^ϲGy>EpG:l_IIdpy̼e2}pJ13%@M@ۍue/yW|}p B48R~O|_(/?=⤑+)6N&1Ah_(/?5b?O?Bl€=̼e2}x숆 s>a _(/?+y]sʡ.}ue/yW? E?/֔x0B8 2}<_+ KEQ;C׏ր7<_(/?q >isϙy>Ee/u>T_yQgƀ6_(/?}Ot,zҏNG_ 2}<_+LC/?̼eSƛ U̼e2}*ޢKx@7y>Ee/˟"3?0(̼e-6[W\?#Zn5vEvzT_RM.KdYsF ?A[ՙzvns;Z7L\bF}8W:叴Vٻ9OZC,Qz[Yi\?#ݫc8u€5vK{({=-S^d?TJu;€6vK{({=-F/T U&W(omǿ Ƴ}`~? Xn; 98d{=-y˵?«^q ?@Noo祿=ɟj8]OP|K | 6K{({=-DxT#')m\t1; 6K{+>$zΟ 2EF({=-mǿ¹MLMPg@voo祿=j@s"sV({=-mǿ¸=`GtuWgٺ6K{({=-?Z;_zqvc@z[FoyCDFضG?{oo祿=S'LupE@z[FoyS$ۃ\U%kOLGhնK{({=-0EwDb%Πo> J Czoo祿=O*H"#5$8ݷ 6K{+-O@bRDyzwDdvea~Z\ _>!| W^ƺGx7z6K{({=-?ƺ̝Z :{V~{=-mǿ¼vh 8#aex{noo祿=#ȎUf/$r2C>*=mǿ ߣ5|@-?@z[Foy<_5o{DƴuXugbNsP]t;L]g%19m7=Y2r)d;H$ ֶ]v(HV^J?پNEݿy}I^i"ּJI ,MJJ݋>sV_%H"nmb*Rff;U c=@rJxO` ʞȐ!'&3gKrɽ ]*@( )2)d ^v(2s{֎6VV&QޭNdhUҤ`QA*ta?R;@ 50Uێ!SZ@֗`Ċ1 P֡aqҧ-wzvo~w.Gҡ`H+* QgQK93l;E#H(}h7@9awm$giÂ0h)+& $\ɠ0>>K*еet5Vx\LQzBɹT=klR.8Sk@Xk RV3P <,ou#ctnE>͙ jrɤ*FXS#= A"HH?]$GҴcYNqSVZMq@S3[ɺBqO@'W484"WRjϚ(ZNk\?utr_CLKtwRE! Ea\j2YC*]d@5LŘiȻD WbE$0o5?~b_vii MtҬyE&oдڸsnsBVdMUE:8ʿLJnZElJZElJ "Yv(3 ?پYz{7Ҁ)ȷ{;װZȷ{CbZtg' ocZ[HP}M1 qTe|MJpD 1T3ʨ R2=rxwjn)犱i*ɒX؁ 3ĴSqkq׊:qVdlWAҶګLU@:PÞjI$Ue'ԞhHB D)&l>CnI tFhk`~yRmU r}hxvK#Jvָ1|DsPLXkkd֕NӀ?ZAi.@УGFqY+vh""9+*#4194|1;V[yNћnEiJ9}ZBn6VT51ں-.9bJ€:RFUHqWs3@<ԇ!@3M'#P83FqE1 $f+A>5Ju4>Rva c0+;zPn}:ߒ1ND $fHzwgIT!:9RHgި@fK֭^x&YlGXwүF01zUheN8=1@PĔ(OA6q@N`|iZr3[> mH5glZ^Om\u _EgLkLk9 a[Cv_#O՗tFgڠGHU<}*l ☊NzgZsYwnZ`; (M瑚HB T6#w'ˌ?w/-3d^gkVնqY5 #pa܊]ïUdRR0WoCYcpB@*(yY"S.:v+"87) P\Nu5N\HoWp(qm2[0wKlJTb hBЬUYoӌRidm$TdV3s5VVI_85$nȮbfʮ( m),2k/JʹS5w;)pil;aV0ۦ@ěT+Tbbu0zgie y<%= r 5 `Q j9B{ktmZ2k*—7=ekAǺ+ekAǺ*(e(+/XfVeJi"ּ~떟-^krv~*RaSQe'CkpcLj k8N{U S+bFU-QWL x5S&ݚv TDY R+ j&G1Z?*\wOy#w59fd͌-S\ J9=h$MI?w[x#Ui,<օg$U!Bu=83ހdQ"zzT8m9J\ r6Pq]RBc>L6QAiiW5!KΟwP^Oɨ!ϖ3EI@ sT$7?7%Jr n~T'cҜshOENO4O^;S9݀< Ļ͗*y) ͑-TRֆN3LE"{=p oaI:Uy:Uu<=Jz~`DQB#86lbQTNInM)$һҕ昄 #8Vyv2,#ߩ} Urs5}[qtҀ2u4կ+kdKPQ@!I:YY\KxmQ1PNȼ&BMWBMRg&㞴rGsڠ03ۜ<O"[ #gai'+ky=*iFf) i#nrGJhKpzDžNqҡL;/RS8jN ! hJ{ B*, ˵y]"#@-S ꒁKb @ nO2(@p3ަ"WPZ2I"3[vAfRj]OC&gr(*d&-׃+Jx̗`"`41u⹋T^$[u=DP-#;|͒)КXTSG(~du0=4KIc Fh qϥWPI]jL#'4T\(N h]']JJ*X #RU_ڳX@s:Ӣ* Tq7<{ȭvǚ'^:`,#<ʴ4'/qʿLJuZElJVElJ "Yv(3 ?پYz{7Ҁ)ȷ{`K潲EݿyI y=⧄nNGndcQq)tL`ʦqQ8F(hAQȸ:DH֥hPBV\*xbI4𱃒jެ\ it.kR 𪮅Te,1ґ@IG0 Ww&`A'h*`<Lv(Ŭ,dU{midqD,I9^HB:``˰ qS%hhsN,Us}))$KpFNF}|Kc~}T7rXz҂EA,߃R)٨ejIlMcL2v1EyzuTs@ƥв69wndFcePNi;SZRJ>v-L%'i l5UU{q@֢zc<֍m,x ͹rj5+o,N܊Ηk="D' {#:,n1ޮGdLp G>2հ#$EJF_#P6>ЩI4w9gr.ֵ4ȁ]A0!FUmdXi8L54:3 RNA=1J'5\K*L(e3OU ʒ$I-)Wq@ oZzz;Xu y=iBNԊC=!qtVf>#8Oeb;c{х$K|Z~H@ ҢJp @.TҦV}(Wqǥ!^@4/z*`$P3߁ދhۜSV|S-۱?hJZejf##oNSy}i̿+61L䷠ ׈K 6EfnTMY$?+@"e#ʓ[n*Tc9x^5*Qo0Ji.ư}@"&ֵ-pIPS {VLYOP گ:֔RfS(/qkNYm8<ۜWcLF8"<RYR9z":֥|YZ;֟B=)/ %sT:1/sKj4, WpW ^k*Op{sۚ.<$NHpN2TTPJ&(݁5_&GWַsZZ欥F9rgQF)`A^:TLwg#(vRz**=nATWSUz,|r?Z OSҚdO= fAҢAɩFGҀ2.*=WNV @=8Hb& |c$Z]ͫo٘Df/=\u _EwLoX:gO+x9nCv_#FLEF}) p(bmSzb!u'<A9'4 w&)Y'5]`3ڀҞ3g?6?ӵNUOz993aIJSU'AOop#ʼc@DM^ *k nwf'( lPBYUr\4R`gSgv$4bf;֋^b s@7u8j☤zT$QC fegmҴ.`dOmL8]$0/`c8\S%` 3̴vm|mF1ިjVP3M0qjq"s@hJ֝P=0gJ\3V. eA@vG&/Q94UV>=ħqozS+F8rk.IO5~"uPOcZIgZRL'J@A+P珚c,m\w@'ڛ)I;sEMrwoY[i9 dcBҪc.+Z銩`H2nj;f$jnNds֤2.ƀ:|bcFlj}{VmtI 53T5 vjs* \<@;Au'GZј=krZ<zaҀ+4 /Nz<ZF8G5$s4K{P|],qX\֍@wh$ XqIsJo(<(Մ@o'ڶ3wtF!Iuw$ڙmwVa+ٮBcgW?X1$Ljgj%,dҸט}?@!Rv'dbRMAutIY26qvM>%ڸ` QӵL)s}~pHqf_i~sSL8 AavB2UuShuN;,Nk> ddʑVDH[~4䓚= C@/sV\cު[W#9LOJ S {q\|Y6Zռ!#=q-9789ۏ;֍5߈#cZ.K0I7mN3Vem%<涤PT;qhydah$sT5|oF%=*cChr{Բ͜~ 5ve w(AzŹP6c5<+ZEɠ n@&q(Q'\ܩsۚ殴ʼn[VR F}+RH5oOʃ< *KUN3֬,sV4؀79" 6}}*$O@gXNm1:@_Ȗ~E3E,5Jo}.C$`x۱4ԥ跷Ue*ck7IZfM#[x<Ȋ5O) z4Jh̙*yܶaVˆzw{P֝$~Ճ" w[G_ށ0UnLbpE<3ݳ?UUawxx4úP9/Do?Q"}k!K5N-f19=Or&b8 3ܫDFy5gGҳ-5 Z: , -^ z=5rz;:]oVjH|#j/_O+xA[Asw>kZ$kj??ʐd?3Qd|1 I8*1+&?-)#+JzƱi".|~R9<.-˗n*6vA+s]~O p1h?>5YnJ+#to[]xoG&0qL$z)jaF=kz/V7/٭.2܀7s[f/ݑkP6v5rzx,85o;۵t:SXOր,BD2ZҘ>VbFJ\HF(;6%oW[MyZ}=(Ηd'Ve d[R<{T24z([qT!RL#Ԣ1OXs0.TU{p#f"hpE>b[gcj '\H 0dp=*I4䌝 st 7>гǂ3e Þ( NN8I:{S+œUh.Gb4LY3H@gA:4`PJEfjkַi2GweEqi UT8$סAF`+'Pd¨rL|Zii.W;H@ZPc9gY u,G=Mmx~ԂB8YW_EX??VΛc"+gMuUSQ~7˴QEYV^J?پNEݿy\k-?[׋OxGLCfNJÓQgdɂ2i%̠iIlsjvZoA (l1[i Q ڼjED0ƹ^آPǎqר`р~:WWn}iyanx~VɖP)U$ր*ߨM7N$PV-O5=鶯jyQU`ι9 %p $㧥=TaJfHAҀ!V[Ji Gn*I4QC)WF;T{]J\*=hV&_29p:\y(TMak5aOY1\8F\yA@l]D]Mr7`oAr)@ rT({UT(#h S[$*Dm9VVE3EhDӊnQ[V&,'tg@L~'ŷSZ܁Ij~_PG59FLI|Eo;uZq 220*tHr+ iCݰRvzY AZk)VwM8O-$dU)lRBI5:\FGozyR\J;RKz3oVɠ5=#OO㊍Y~krRFBk鶫N\$0{{e1H]L;UON./ #j_:`*[s Xi F{D'Y Hbq9Rr3[n`g4݁ kc=bkno?JkvhT@@K*A +1$u˭RYῷKyvź~h*潧Ϫmc ,Ϋ33|`u#ƨ͖caq;y[ndtDt] {R^c{_l|Cwcwi[; rqӟjc-JVo.];R 6du*G`Q۠=˲3[M^H XʲkH_\mKv^ `C ?F_ ?vtVrFxa U ab|CmuHg<j ۸#Uie>[N9.J3ɮZ9LWlZәnԓҀ:WӄUz dV:E-ԥw;sEqA ?)(-&Ҩ{D_1(w/ KcEoijQ͓ЅV^\h孵I#",p0}@L}RK"$x&4exsPTfP[Wkct1(l}R^Æm&K$w;xX4{mRI÷8lc8NtHYM;8f9 `tB33p}]]Ks$WrH >R;w2 nzLJPA@P^&r`cS"?J ;JNqZŁL'CZ/%7'=]wCpHJnYXBS4 wZ~גsYYyo}aT֥>ko#[ֶ2*(6!f  @:WIr| +o5؁ހ"e7Etv䭋}5DvXZ Knk5F&lJ&ͳT#v0̢F2r*R?z*MHn@}igRjGX ׻*!QA6HnFTWНh;e;rqxNzHڲu Y`Pk%ȸܪp tVQjpw3@5=E!=k8yqq4Z#\ӽ\$栁p5nϯzAe8&AȪB1=E6B3KkXLFkR4 3@"FnJY2NkH1c#өWH>@Ug<֤p f0Ry@o|Nrk>tqV߈5&(cs 9 |z C g8ʤ]DV 4`wGcrR]ֈQ;c=Me^[= 84)Psgݰ =WNM8Sր$SJ Q4cIy;EuÃR,`"D•*`(<X{V f1Yq:ze" d #mqiޫ\BRA)TcaԶY#kKrUrGOifU6sjMZJ~TҠr4ێOݛHqTL@jnт5o I5-߽'ִoc (N--T\9!X$bSq6PۜqY2ٺj_:b{7q@ݿڭH^+OC1>U>Ze{{/^{D'Y-kR;aޗ:XnEt}P^+}3kxd18l >x@w *WE \j־z[ ^<(9aԯno--%IXX|w4W>#|̭僷'zSƌXψ㕲0 珖9E$ThuG\u;\xC5}掃KoX:_O+x9nCv_#X_e9MnnkllbJC9= nVR̅9=+dmTiĊ3-Z֋:VM7\浬/pMg`mgzU[<.z&)qV5^m5ܷV"* }֨[iI+qZ;13ɠ zvy wEAY'r~ojkZU$.*qEA m[ wx9']NQgP[vVG*OEK=.96:%1o8t|Aԥ\,V]췓W8=2:-@*\8a彄g\M@nݎ3ZmMeRF>و@wAҮ^G, d+Ffi+ @O Ս@F{`VuZ(siOxzgӸE=jEI>o$+ VUx$s3裎i z9JK[hM6lyF8VD}v**MH|O“RNN1$Z=+ZS zk*{2*>bYFk5O34xEr9p(X&YRAiƻMM,aY(]ER1[M H{gjvuڀ+_) *DX4 ج'4Q^-]t#AbM-szIKg(dbZēF[4h Sj@0 2B>ڃf@J~sjپ_`GP+&vl\dŌvGZn(qڟ kX@-&Wzf{Uy.^FӊmMX:ktơu]<*Ż[ۮ*FqҀ:+ddEszeaگjl`{W#$\P!A 9e#4˘#C2P? @e֫\Zȷ{'֒-YJ59vU $ 1LDSV=iJWHTy 5bsxcұ{v|aȔp1*ĹVR!Eb.j9-=3C#'#@#{OZ=[V&$?9Uj Dv < 3INsVC!qǵ,_WY@ة[wXPNι )4>zz5iJ~{Vvv;}^,c^\I6T |&Cu5.b򲜁F]'/Z+_ÚFfQV/m s֩0TַA> c3T#-5Ϊ1Xv 26&1g3Lpk[)>+XZV Ļ}(6VM¯H(# d]=zջ"Wk-\*;V s@㩧oM!K.HQppZ2?eDHAZ16@`ʼ*sx3d\C%9֌vnzTc@G֧{0>ZE[u7\<okù8 [^6P:U^;( 'ܹ'.K+'#Ykg,ii>ߚA1Jnc$H$f\Nl t1HSsg;=hg7#sӇOhcS?jT0sW``'aPzS4lac+w. \[],88]YLcGZh±c֒5Ǧk3DzA;O=(}/ghC`dk3P8yŘYz͝w-@s'$20$+Wt7G4h#8D#nDGB94-}k"}CBzć:ѿtݬ/?~t7{!/?,P[g1[ݗv'Y9?JC8U;XdQ=iחEbqU.SޘZ[so0qѽ#2U3q@Ƥ{bָBK71ȿ.z]YHEj@IU0MbC9 KzPX 1VHsҲ^*F{Plo8S uUWUa$m@IE ]cj)nRxF2I iF-rɭ4B8TQ6Кd{rw4%H$xVqEOFxC)8Yr zP,B jIȳ 8\N^N@e*h[8vA3({է&*!bɼ}hG9l<Üjy1P*x NrץO9FEK8\\$yֱ}VsۻzVT9'w@ 4GuK c G">ST'Fv8 aDlǥCm:8i k&Cs֧yG5YYc]́j^#=hs;)u#WYSIC7c@RUU,DfjָV&pu)c(FԕԆ8sR`"@j´PsrkKPn P;1lE2_YL3*÷nZ h>Gs:;ol]-(NLs[B+K#= lPR\g/X ,ԳohPZui#8+8eAֳa#/s\DWl[\܎9kK}죧#uph{HZ<)EUkRkc,Jap}=iZȡqTPȓ|^ +wj$TbIL\/'8aof@c.ɴUF7NQڀ&ѐ*֛n#ĝj䜃[#*—7= ȩ{'+kMuV)ROV֛*o՗h0c=Zdz}(q׻Z +n?o^{qqۓI &fD'^RD95^OnL sY`ym)拉U`%e gzlFH'eڣd\e~cWd9I&4Q63ָv#q޴u2VL+6I+zu[TQRO5oP [ݫ=yZWn֦.Ͻf2"6qnhl p>ar)CgprE]yZWqޥyPqhFzS`GXgyjrcq{r`I$PMLֽ se'z> ]¤Rs*nF9|Pbe'ׇ$a+Vف@ u*nWvf.y4}7E}7zT6rOYnuP*#$qZKf&Z#GF&nOޠ  ry/ N]W{H^֌,( n;Tπ1`d*jE#ր%tayYb95d?7nzUwId6:|iN}hy`I#Zܳ dcXaH+HڽHL\n/OTǼا>&)$!e=0-]D/+bF.WXiF h UGTnHHԚӇGR )"4@t9`t7j~1[" qY:y[\ 'Ono_,URaTygtZn#6ߛjK/: Vņ< LG1"yNb'm Yɋv9R#]b紒Lp+ӧFb(Ib K4x.@ )y\z_6Y0kI/Li$(0(l&8ł ҴuU 0+InRv+CHyGQrj@Я:Sd-HJXM2T=EHwPLX(!88?R9xy=S+sX1<@la.eV]?*DZ\X33[ 1k?Kbbx"?tNy NFMJe "ǚGJgA n~I7K R@^FK`d$qθE\R?;$ 7^yjE]s]GuTFy\JI'z,$<֏j>0Ns@5ݐ*c魸XR 硠 ymZZ@dg'UXle֧.wI[ĩ9 -g Ur+O#tWAzć:ѱuݬ /?~t7{!/?;[3Rni߃ҐX*m Hq@1* 'kFoٛ=g~;.Y`*irqqoG\W9xy5(!Fz[H =qN¥E+)+Huw|pQ &#m)$#ޣ<Ϩ-(0{t<d-og+ ^HSG Sc1XƜv9 =P ~5^BzIێ2FC:c֌o=*E(g< 8 m\s1T"#)O2M:1Z '@%#ٌfܗXK.qPňPB"LDH z m`T;ZtvMgJͻM6,BZڱXFlv^i<€`Wֶ΄; N3W?-*gҪ YU|6!XYsekn&{0FV%=rɳljMmBp@Jy=q\ƯuZZnkڹ'9(8&,agO t';h÷lH3c(݉u i楁2GsҮksO[ogt{CFY8{],eɦY)ӵS.03f1IɆtc_HYdc$S)+ljpj)Db@vDNqQ?[yی\ut\-JShv UK݌(_hq?!G5'ƻ#qXb8Il9ϥC>/]sUx@AJǷI㱫a|) H@ q@Zdl0ߝiJJcW[RJ}x+*—7=TAǺ+TAǺ*(e(+/XfVeJi"ּ~V +-?[גGn4[!ɭ+UV_Ʀxj nS+H*Xj\@I icfpлJ'6W_84Jq"3od$oZ34:Ś \6uU#qfPS@MPA9p*)G):2FoG4 |PZ9y3 PS,I⋹'<ec߅qy6W6NNjls@93ilX#ZlV?j#LBIR@HZ {P18$ )b`I`ր.EIh'UKiGמ|A@nn#dy8tG3PZNCEi:e0<-*HA;~4PXSd`@OJF@90STNc5*1@ $*pJ'5:`'<Ӻޓ*OJc WaaqX4cVS}*bG'Ҁ1aakX! vFy۷Z!sR}I#M ό}8<q4R:U;/՛k5rG"{djRg8PߚQZE'[?7V|$j/zH|#j/__+|>u]F9rCv_#Oտ[TwmaK0!Ґ=$x8☎~Q*g"y0=릖$`W[ʀ#H{gޓzG[Q4DX$sLfQvkZsu v;~fk@G`TqFB72h*~j Nh@ZO|=~;z3&TIcBNOwah_T7-qRҴa (Oy =(4 49Uk$V Bx Eeoć9j[Ҷ$o.UM: SR7 6P7zc71B\ ۳4J+5zո*$z{9H F#5'(*oMSC Y.͎ i N G8Va3tG5:A b]7@c\UA0Ayd$H9Y|h=F]\>*0?ZKqҸYÁ fA{[c.j$r uvfTN xa+b ـv,V*1Vb zU;չ^U/F>GCojj@N/X@TZ;GZMfS&-gkmT~5.-@ʠVVK&kc;۫JdpMiIT'ҏt#uZ| e/u6WcT[7Er ܂~#Ry h,sp/cBlGnrzVlm 0.|]A5ƴ1 SMq?JtҭANW%"|.k.2~q6'J>O'(?Ȣm]]$鴚HK"gY'|OQp:è&Ҩ|H`OQq?EuFj^Eq?GfH5z+ ɮc| .jt9oޮ#+Kvj`ey#yWy| 2?Qp=$j1ϒKךᲿ?Qqq꫸|Lu$#We+<Qp=5IiSM@58e .iF@*eP/We 7/zqԓvr?*uH¼r8 7/=SZi`^a_?‹3nn=E1We 2?|0›Dw,+8euKw[h^oq\RGL*k8FWy| .V͍Z S+It_ڪ<5 خҥ. 7>,B9OQq?EW`\i< >_'(?sH]F W@޹rԱM,cεḣn1E3Pt՗=k`dƟ)/5c ⋁7 sQԗ#5M !TY ,'+ EIM5K6UW d8 YܴW jwIl'W=88޷lfBخwQ`^L ^k7UmDPqVgp 8ZD4:Pe, Ob=sUQdb+*9DSt<Uh7SG8W4hp|m#hdT.2:zҼ3ZJCq(6yڣ5y }h䈩Z}b.sFQ" PMBomSS$:v')q@f-Iv'U{5~B& }UOP3e_Rf_~gײ"_bpײ"_U?W~EUeJԬc=@?['!Eݿq)o9I xSQeA4þ:T[i\(Ơ2r٪wQ4SUsYry5m%q$lx6zԷcZfTP>V̆< Q,H=( IrSB^ WQlSBB@*tɈQyd!UF-$PbvH \bkژH8'4xTA 95VM^P{_Δ)WjAHm tҭYX`4Ez=Fk^ASZRB[vx~!$/ҝ uHsTҽWxj1`| rdP{{WX_>[GrIe#@#ֵ55I/Mo3Cwvo4|1u1˧ oaq+Tظׯ7[)QѴӥ[}xɕjg 5iƖ/EBE[zsZ6~/Lnb.I>?iך4vb *oU;G Snmfu'h ppRA4C1m0šBwv$V go},(2:Q?Rz3^JBא 6[+&,Eޭ\4䖚e14o$``$#UCzilIGGsOO_饏CIHԒm*evxǧiw5;+;+!G`ฝ(6NX\CY,ZAI-f?'& ثq;_~CH>ةb|ޙs^J$*zW>WuOjj$KK QB" I=RjM7SmnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ:] idnv,K0{f; aȒ&Qֹ{-@/)vrۗ#RtkxQv{ҵQ6sh/8"LSigPk l(4f{Z6CN.|5{ 1A&5g4fK}.[:?iLH|Į7=PR[KF1nׯ3+4fiZϩ[C{$I Y2('ҚWMRhlCay#M̍gjzhD[hM\+Nq˹#r8F*oC3Zx~(e'+$R1_a+1K/5%!Blݒ,g>lz_p_efVǫ떶 Rx>3[Pj4JPeWb; ^_}|o H$ )NjH<>Y T,biBg<明Hdj9&glWn8ț챑kE99#vYp}kMMp=hI8hv2~(9$Pw%TXq)aľlR]ia}gUEyWMZʿLJRTEmiJTEmiJ "Yv(3 ?پYz{7Ҁ)ȷ{{ OvzHl{ ;q UGAWI@i6irz:?VPZ idlaZiJpq5AmoS]cD~$KJR2`{RZ׵:GP23@5EUzKHJiGRɁ#'j 0gP'*?ZN^\x Isz/LkvHTRFazҀXq1(%Ozm#85fC' ew YP1="U߫s]Jd^zmyxlp(gz@e=q-l;t#,Eju亗n{PnUar5$xmXixgI$ðw ]>-wD #\д;1URRwEuSl{lf# s[΀0bq #t  ~cx +=ǒ$C#j1V8X+T{LiWI9GۆѸ$&kq" _SB,귏a^D*H;6Z5љ8fd.DrF\#s[?`ԮQ FIbfR1iV&,g`'"aTɠ vn"63dRJcx;Su{qme21%ߵX߽.0N+^}N*`WPv yXeF) oˎ&役涂L|·(FAOgΡ%܏c,sU=*Ȑe$$I۷Nvaţns =:S nc18K,Nn;#k`O4OY \o/e3]ZF+EY"V2\ ĩ9 :C 4sv,s(re{i!7ޮw?f6&ECp_;um]ih IMNU+492̓ܺcih6^f$C»Iۥ?/!~&Xßٟjq\w, 1Ϫmnj/l "Ocpwvc?1^iomP((U?aު*8KRV*3譃fV V̷6ݼ6rR~k# Т_I avG99 .yn yK6<ȹ;Pq@[m"C#H C<6G,$cC,6Hbrc_jM綽e-`zFGh~a0hSP~U0KmZX.SB00@zZc3]WS.'ifN#%xN=jH5"}G$r_xBH9qڴ/<7g^00;*ĺ=l +;XăKO÷ԯTci&v2D( $.wViI?,_;N8e4pmL0g܁P/!#gE`Cx4.%j r@deQg#ޱ!;ETS}$Fbvt&rq KB+mtV6W wSnt8cےDP r8Sh!뚼(%:=_pluOuR{%[C+#H'%A{ qֶ",H$KFe!W9bIa)<ۆ|={^ϧڄ?8ZF`%Fr@ gֺkq:y4*I韺F?#_޿F gSOW{k[(8ڒYgsk:q$/WsǾ-c54楨Gh 2/P<8LᢙCP2khm݂BXRWF]-yeZxHm-.~wHI 9k_\m-] #nHQM@Ӥ1TD+o>^v=H`ҭѡH`%+##=Ԃ? u9VԵ.ovjr^m V9SougmB9˛hVه*6=Iq[3V ^"TzI X,VByS=sGz}hXv%Nr1x;/lĈ?Ҟ@p\qݼ<eEv,œ~\x44[ {zH6IgąϰzD΢a$ P{, 30e@ǽ?ÿi5;tm 8T`@"FJtӭc#+ c9GқaiO #H펙f$΄3s;a$9㨨om,omXL,j@`Pmiֻ pd $nܒē6oiwhEW,ۛr{HoTAcEgo+w#I"3&ԗo bH':Gĺ_k,!c7}۲C|/pz֖!;7dH\s"9j|d1m٘8y-uRxѤxt[Y]0R[Qvz⡖RҮeGF2"q؛ȓ1  pi@WP,C(Įy-;s յ)5[k Aj,Oߙ:㏭Vuilo :$oHqq5\iVWS`mʳ3$(P qHoƗzdΊxT YÌ898zS_୰[e#@@1mֿ%KUvy>сYx\.5'O-%yn`F[.TPI O3X^50Kfce>A~٣^792h?1 7ϐ*@RX/eU,Gi΃Qh彖X^HNG:sR-|I]X ӣD8'?J>~ٳ#֩h:vsܠ3H $AK~L'N`x7nn\O!FwʓIyJX9Þ:t4־aĻĘY!p0;I|Tie)-om;GZ?%}IlH:2ߎIZmUi#gf(_MD ʙxLecmʣq8+N[+yRH*#F0({i57+yİ+!6IQ]kmp,"8bFC)lg9ϵmǣFlR쪬K+N0wK'-1/+$vO 5LJtⶇPgلE+ݷvs1zѯ濵 \nP:WO\YHE p2qۚ't|N<eԫœ79=sVm4{;.!A *"n?}?$rY ߁<*-WV$6m!A9usV]5!# p8>v]o@XrO.ulS̲Y&II,b95xe>{l [T1 9=xҺk8,<;W$'=l%8İ;lAuU,Bn~u`U-msٹʐ0 yҟ%-Xuh6XcIeo-sy849# ~U\qBmv-MQz~y[0f5F36"ZG lȎH˝`}Si3İnƑIܪIQ׌dbAERQEQEQEQEV/ROcxE=SMx?iɹjP7[ztm2iX[ːSx'CcwH9ڝhASctOj7`hIVL%#JK$V$ZE׊͉w0֭Ls@O33mj!\ԖhR ӓU Doޜ Os61k+(-d ksҹ' ۈsҀ35YTPZF@ݎ ӳIp{֚: ξt iT|뱑ki" w ^ xzE8?[Zw{ұ_E8?[Zw{ҪˆV]*²ojV^ v-^k[֟-^kywNgj6`b3kf2G1嘟V5N\XI}:;vE8qއ ctj\b9\җA&ixMuxE'\\zp:]cRKιb(r ؁Һ Yl \wxh07w@I.$R1FN 9/6udK4papcjm\FNFo=moyrn.Q?y+9my"@_kP}Wijne_Jc-#3 :Nkܿejzr?kFai- ] ӐxGK_M>}YI<l_vuku%U; _"dO(mn_Ω֢BI?:7/HbI?:7/@ E&ܿsXKKĈƻCeXp>_Ķ>mݬ7S쪑 Eo^%#k86F& VQi- .FN1 Aywojj:Eymo*ܑɘ9 Wwnpl;{[ۋ v$ VkQiQU>Mѹ?:-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-qv^5[ʌCm*3|U8Srx~u-j&uP+G!~U :ѵuF˲\$5fP{1_(}@]WY$X7Wg=Gw;˻k3 哟m]]/%]9B_SGOu$׵G`5H+E)b7ֵ5h8fM/%ڠ`XA뻭A~/ಎ[e[q <:'ohW1ۣ0ZjXrI5~GnZ8 @-f~;2;Bpe<"fteHyudx/nmB![ <[oom?V\EcknW:ݳ=K9<R\Qb+V,L[]Y9#=FOk4>td7k*<5dVn=ĎG*A^q1(^~_vjW5!l N+*#XW֫|krQvy< [VR7$ \T=McH[eu@C9 dU7c+yRȋ w{V-Ɩy^Y^I#nf8=ImReTy4Ms+裰}V3v6\`)-<6\uF̍qں>2!z #}*;,?5)Lր3|y*#j82hk}4ȉުFяsQ]O^+c;sk:r$kBJc)lPTEmiJǸO+ sW>Q[w{Ҫ IQ&v( +/XfVeJi"ּnU8dn?o^8J`k,9x-|t01 qJ*NT=)U 8 'a֙(0zP}ācX=ϥQo.~:b݅@ .|*dIt~+rh5;/s^{^ dk\mr7s %$gր c ҕ:Hm*Y0H?Hty$' OruZ7\=?L_iAȣ_L@ey?+ b<#w) wf(*vrxF8iM\_ʦs]j@Mhe@B*-<+9mb#6,PĺMxV.L(lyl7mY v_v*wc6Rzyu36ج\f~;{/zdob=q쿙끟.Biz:,==mngcgF?Ͷ+#a R\sދbob=q쿙끑mngcg|/E=9\&?Ͷ+#a6ج\f~;{/zgSkIӁҋSob=q쿙끑mngcg|gOqE紷mY v_gdz7l33>AdW*sҋRob=q쿙끑mngcg|?=S+8`lVG3v?{=p27mY v_ϔFỊ0`lVG3v?{=p27mY v_ϗˀڡk gdz7l33#}ݰoe\ 4[ʭPS(\?Ͷ+#a6ج\f~;{/zgO-Yr\?Ͷ+#a6ج\f~;{/zg(֧eՏ&mngcgF?Ͷ+#ad8F7uvEpgdz7l33#}ݰoe\ N)n{`-lVG3v?{=p27mY v_ϑ]Z8;*w)'ҋeob=q쿙끑mngcg|AUoW99HN1E秷mY v_gdz7l33>V`[8ҹU 8s[6ج\f~;{/zdob=q쿙끟xsag$`}ݰoe\ lVG3v?{=p3$]Nشēҋvob=q쿙끑mngcg|Z7'jЎ Q`-lVG3v?{=p27mY v_ϒ1).浬f3(RyX.z+}ݰoe\ lVG3v?{=p3m=c8$cҋαmngcgF?Ͷ+#aaGE*8sob=q쿙끑mngcgyb@{R`7mY v_gdz7l338$ Ҡe;w +}ݰoe\ lVG3v?{=p3ɼ;1jH̿ }ݰoe\ lVG3v?{=p3pC`W|ᷓENgdz7l33#}ݰoe\ Fz5Y[=h\6ج\f~;{/zdob=q쿙끞c#i$HG ƋαmngcgF?Ͷ+#a ZIsob=q쿙끑mngcgy8($R#j`շmY v_gdz7l33<{S $J,;&?Ͷ+#a6ج\f~;{/zghJ_#pX.vlVG3v?{=p27mY v_ ɂzN$j#"mngcgF?Ͷ+#a|^ژW- }ݰoe\ lVG3v?{=p3v A;6Ӂ\6ج\f~;{/zdob=q쿙끟0x &ޕN;Yob=q쿙끑mngcg|u,q\TUQ` lVG3v?{=p27mY v_φF gڳ^7G`#}ݰoe\ lVG3v?{=p3󗕒HsҧS*g,>ob=q쿙끑mngcg~޴g߂Kvs6ج\f~;{/zdob=q쿙끟 ӓ9VlX.{k}ݰoe\ lVG3v?{=p37F9q4X.{k}ݰoe\ lVG3v?{=p3\HpN XKTOE7mY v_gdz7l33>MHvJ `R=jR( ^0Ō~gikt-E$U+2:;0`wc1=~΃:R$3&⓸mtv[=O^99{S߂<縈z m6Ҹ//r3]}j`I 93V[?9 V$zg5V ^8kͅY@_P.sZ7AT k0q[vaְHŒwmnr={s@*3m= IޑA M#88;Eă-kWUFǥdBwphaztT5IAmf)`zV}nkf ``o@< (%PM`g/uE9/!\P3il7[@dө4<,}]!>PPj`0y=LZ8 SG50()t5~ R9/E5"9HO>ԱiRygwS\}Ѽ1(;?W7Pۣ(-%Vzy USy^=zERCb GITZlLEGVJB .1UYthXvI\ |QGNw7TS?\S;^0f,݀+^ zZd^d>=kqce^Nq0G*\aGjuYFeL?v3ڪd@$ .q@ |Xq"5~OIVq(}2}qN.'5]J=hfUyW(d'Zsl׊)!d0TټVeT |Q@ hYGEe_.nTnب@nFppa/:8FaYz$ڰ.Z`sjvcO[y fS>!bԖ.N:V@钦7Gn\xN#n=z 6j3r7"+.y6%ݷSנO?~g_¯?C!k#z/X™ Nq ة_&mAcZ10?JC \»|H'.d4-S(u^kk=G֠҉01Y n7@H X>ںq?WgG?'mu? }ksuo#?V# qW2wB29^'ndU&fƀ9:]֠17'uÓһkoVE5\'8b K]=h}!<qjs؛Es[ұTW)/ŻtL":UǺ+3QC28Ǻ)!hb #/Z4#0hMfO;oAG$M&x($ =cGϟ]ϟ]ϟ]ϟ]ϟ]9J|H 롘H毁 P%A銱Osr!RFXw&[\P}!0+HyTknUX"UɎ{PDp=ǥGA;AO!}Ki1m#ڀ6<TT?*UH@SU->g9_^Vx{U¿'z{Qy$]u@rN+NH<(ݸu+TzzӞprsI Ą @99& j.jE2˞+rT!DB܎jP%yMɮ?Zc&E@!BN[BGST% 'y +$E> m\ K¬ o>d LÐbuvJմ+OeiiKBX={Uk jO͜SQ]!l?*?u柕vٰtQEq:Oʏcy]l?f@α_PbͰub[hY"D^jke1*&}(/UE.V54'rVjҀ3րe||L 9,fV'S\ -I44Y*JЅ5#SZ,N?dM:S$?ussU.W jřD8>ٛg#ұnHaCjGZ˸g*F^yTkbK@:Еx\ډsڜ)=[o$(d(P98bϦj VGNv N} [.9 R@">6s=Z `aPh^3 uOYN1@ lRyEH`{$`H杝Ãڀ!*59')&9@"JZ7ɧƥ^[⵶vTjS8# P6sǭ%D603Z T'8T'jIcڀN7qFp֑9#zSd1{2S|ҕp .XR9V:P-aPXZFڧ梈,zn1.cZR =@r _CY2$+켅T眚RHLZdrFrjY-׊D۽gn@7r:Utyv4c慰*YJ`k-$to`@+*0.\{%`;;==i@li8^j9 kJ8r_5|I>wR:toNJҖ[SZnlӣy҅u G&岺 YKsOkM[8FM <vc4LʼҀ.EsZf4ǵVe`OZxWrfzU-Y[#?Zɞoܳg[v#'(fҮ$Qsr+ jW-pCzZX`c*ӌl7Ɍ6j8p1YCZ 3 4,13Ϧ(;N%,85|s.K6JT*< RFO^9.z6٩ zMCВNJ3P':WOh} s:$p*q1bzT35.Bd!'qVu+穨 vZxp(S$Ʋ c%zۻx⁏8r gf2rnAk^`Edjv$F@~Oǥfd2dtf%Fa]Fw7H29$i :zg%2NEAod7sVnH9 w%lE)[r8=q*~er:boݪ }f8zrO@\UlqڮάT*hLPRT"f#f+sUcC$s@qFz>&p&Xd{ZmFswvnJjO8滉!\~m*@V[W)mtFv3cObUuo]>xn=z 6u*ԧһ(7_S]_tWA>(((((((((((((((((((((((/zg/z۷oZRnϿg ^n*]l8וCר](oI &xr5Ā -RgY(srAaS e1,p\g%419Kl 6iF"\y-M(ڧBKےxf5HkA4xG KoKVS$ju((P=}d秽IҸ=*cH l6O9Pޔ*35}cL@ %HzX31U;@< tCL_lz@P BHQǂs}jgm(aZiuˋlv.RZDuM9_*F'4ه}1M4 =*+3~@NLLzM+p+ֹTv_S[$яP\W<`Ȕ߽kHA5u_񚺐NHpȑ'u[ 3L!p+= yd3IOJ!wV|U q4rJ\϶n쟭Za<e<Ĥ׊0x!9Upx%sJ0JU2}hE`tq3۾*E( =ZwEcA m8:yRI`T>{paKb1Y+򱾓H1y9@],㎝*Btu`X8a@d5m8eZg).jp4{ +nJ؁{WUiA`3@ ;[u36' նaDfܪsЛFw]%|pkj4q].\$[o\At69Q@j&JE{pU<|$DA@r8XJaw9Wh}H;f\1E!eθր+T8[Wy$ǖjŴb=(ݫ3 ĎZŰ mC^sh랕[!=bDfQTԢ&(m*yW)mtFv3jgs)mtFv3/ߢ0OD~RJ OvQ}] ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ("U뽟UnݿUjJq+>Q#oF\oZRnϿgL89cI 4h#_jZl *Z g֬JĠsMH' #R}˹2fpŀ'ڀ=Z1ǏAEn+E@})=*v`ڢyq,9\"A)'֛E'5Vi7"ր ?2ROLֈ)JUSPN$ ;S& rpfjJ?գrhArs=cx9@1@YAN @ǯ\ىNgXmbAMM4ao֨\_tDT~{8խob@f Z(4a7$1RI@mʟB:na'ڸT҉ *Kp@5Bl\@MqVZews2:.yϭX{I (a.1kH*HS<{~DTQxϵWa.I#Ҭ!U'z^jlBLH!z !p㊟q a1ְ!i Wh\\FTmaT]JƝ޵QuGk@V5usHu;$Ԛ`gҀ.^\`fKt$.d)ݏAYwFy a@P"ݷhqd[ނL/Z%Gֹg{y v~=$tLS\0y'N:֘Mb*<՘ T1QhK-N+d l.Zrs@ ,mw"smڸisZi-KHM4sZR.&YIoO4,-:ŔR8ݝj`?Dӑӊ,/nMPɶ :\PyS~Mǀiۛ5-@Ӻ=p1YNg5 1@lˎ8~4<ڪN`8 P$n j[k YҤ.Ek鱪FIeHO>92}i.$E+kKNOPyPv"z{S4 ֕ "oLVI"14rۊD,sڠK9.$[P-cU53tpѶ{n7m`}뙲ViCb7 øTNkON,3ޠ#m-!8#uFFc5 υ8Rܾѓ{UU$#ͻ"@TxKph^%q U{pݴd*%v%T2\yvw -4dUe*8odpր.Kq׽d0j7"Qg҇$ –ႄ9+kFP0'fj*DNùjމr6T$(Ӛ׼ɼiȏ9NyRkӜ=Xr+h]c*x Eq:cͮǵr7ZRs2늲 ֙g$jGgTY$ET]kFfq0  ~iifR@ǽt MNcU*ȣgh.Nsy.ȉYiBր/:#+jrIZ, Vm ز`cF @1? N718X*A@]`}j>*\ɻ(ʨxP[v,# v?8ZV(Sϭ\`y-%VRZzZEz\ zTրl`:+~wqgt@Z$DYқ4#}RwfmݱZWRr[qq:y|4y;\\rrx( Xp+ @]=Mtq8 ߚ#h8 +3XLtn0:Մ\B)Mǖƀ6,ry54h3JQ[ W);ރ:V8P$;zf\8sTopb|3ހ5E.qY?)uRͪB9YVMik[^ڀ4MdZǓjqF2h(k+Po/<ҹny99up;x ;#sUVЄsji qր7ʥFR.(n ̄1t卶3p2+9Ȏ=ѶH9xm N\܆d#hC'W^>R=z O6@OauXWA;Y%@8'z˷s3$<}Miɛ{O0ǧ5e+GzR͜AI:f9ZCfLsYtL' a Z ^m56y$q\Y[L*z`PKS\@5x@r[<\:QT6{ǶQloZ9$L'TmUfwǥrʩk a^zִj+hCPZwf}MT>S;O56+Ӡ3PӂGjO1jڹ#ڲbgmTlRjlBxPNьK "+l*8M=t"#M={R^\GD 4۩6D/c$HOWv`ISHp-HqjRq@ KeAcӊBj%΀2[!G8{Y1ްoOO>lvIPt^G$N Pn;N=3UUG5#(9%d0+9v &ɨ")mtFv3D/Q#5R/Szwǿg'_EaW5>EEqRJAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{?5xSݻĪwuw^W}^8>g vUe)lFpxӁI YT"s'1xByt樱(8*EjHT󩐨"/A֑aRH=mߚlI 8uUf@'%^;P9:IR1OGnp7zVO-QPޮŅU8-1UЯ}*BA&h.q*z[!*Qm޵SV;chz{FXw?AUڠw+>cej72G%EizݶR j;띲NҀ*jD8Ia*;/<֮G| @^Kvei*I!nތ:b 7@'4x V`Gֹٖ .I\RYIpqt"Omf-~oZ&$u }vE|y'3b>j.1E"؆ldB3]yG"B294x pAo:K R *3qV1FUbOu`9#ӎ3+ {U{E0(Sju=d] mj3/֪Ag/4q@ڽ$@Jnej UR$@ x$ g֪CkqPIqq)P2_zU;M楲P]-#6'ڲn"(uAZ&+׊]C|2EL41WX=2h0*&Y7F-biVȩ.r HP%$w Q7<էp!+ҢlŌr*yc?3=dRG=(ؕ>7-ZU}OL:89TFeJsRCRt4b#1RI@ JcYEFV$.@Hc'S] hO8{&W4Er)C;FH`R<~A 2Qs$w;K}kǭlr_.94&Sڴci̒kqrPsڀ3n6у?sc$Fq]|J"\$ǻ8++p8VZ߫=+o.}(iJι~dJgl@@;}m3'i؟hAdbL *8@ oբ1YMƵ ^N}<y(7Jy z|C'ր-8pҡzO&,OA{xG&Qm77>٭)b8(=`#8tXx!, !q@al{u2Z p }֫6ph6D [x( tѷ _Q~u:u{lw⋋Pd0`ji6wzeWo |ёOѭ #m۩ZdR>Vg*h Bjr~Pxڀ qLqJyh9p8ccڬ*oJ6R©${K(LIQޢms*ǃGT#μbd=Pba+jf!9n_OTKpz#Fqjw G!~Osڪ /J϶($)5 ?tzԶ?Usz'\FCoPjtBz!$%H4E$2`ڬۄ\8ϥYK2O@jéOlQ =9(,+>QO^a!7AO|ҽ=)mtFv3Z<&]fOgo^=O^9</͝ $E)/+Wer((((((((((((((((((((((() _ꞻ _Ꞁ6%VzF2Oqn*]l8וCר+ $6h IlX:BYT)572 U!oϥ1^Ktrҋ{pK, o}:H=]>Ҷz dQ:s@U$`f%;G Dx!%}x ˰Py:%=&kFŌPpLF*EB}AySɥO) 9 ÒyV@"!ϧzeb⢑ r V/㜚)qƳ8Z $^ct/_AP{=+,xzP7 ri0;ꢱWGD993}3tAw CdIo.X߮?Jѱ#mmU\MY!d<-R٥xʎ2^ ${U]93=Ur;R:cNgʨ t qL$'޷,/5i9f=kn28#4$TA0#XMZ:kAʃYl/OƯZ4nU Y:6@9qp4z] .AmA@j#^Iհ~*u^R,MXYr) Ǹ" c?Ҁ9T}j\6E],VU$(Z:LϭZ4F@U%TiЭivdܑ@59˷`8mvYi!5lP@R[[n8i!i.]zus׀)u $z\50*K.)gP_[]+/h%§h6RZBU#uKr `fHV9y[5t AOZ"Xv J#QYZr܃ֺ#95|dvLIYIek9HNjqݳ@6qc"@`}*]J>PY@qRq_j{s@ ɥu j"GNN@quRMS²;} ZJ*~A$Ur58\ְKt ;9Mi2}(1֠2c@U$|9'OZ!6; jqI39Ö8#4$d $-dիɼ+݆* rKO1쏦*rp# ~S{Vض2m"㟭sȪ h6[$sK3pFq[ְQ~j_׆SנOFb1]ïSŶ׆SנO?~g_¯?xkJ}+|5>EEt袊((((((((((((((((((((((kWkW vUe)lFp|nhdbI W[JWw[)N7u{g3BA)k4X =* Ð3N3 b!v·"GI\ hZzj#!,;w'j`M͓ɩf;S8 2ر#4ʢ<Mv بu .?Ji9i _'x 2p^i$;QJ3K&OA@VNE,tI^S->VWU VSfy7Zu\ƽG&٤3Ҁ"nԩ#漷Y+'zݜ ,&椆_)u ً =9AEsӢ,ナ#XWa<^ v'E*: iz8^\TZBVY@"Ypj{mML]"M`Y.ޝ - 9Z1 ˓ S͞Lگ-U'ڮY8$sNW1֮1 *ʃ|jyXn r*CTo ]% E]J<OAsOĚm!+E2hQ?jq"155`w]07S|9wI phLG[Ұ)cج乸f H'ַtVH7 {U^9^'[vFq1eGJ{x#JXOPfh%̙`*ֆ8bb^zӒ`\ibb5r`Z۸I&(J8|N [Cis 8Gf\ @84rqC8YA:R1׏5Y{ve"6~d+(i@ tHc~5'*՝\$~v8NN1RM AT1=3@&lgT%8' YjH# ."<'@^xB[P~'ry5mXG!\{֍Z ƙ4#+}슂LPWyyfr&GJ."f=sf,FNhll V= +[ [l\ml!׆SנO+~n -#;zz~lU'"/ OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCר7 <^n*]l8וCרZ|RCdaGN*G4 2㰦"ċsUC&UP@aM'^;80< i=zP][`QK0wd4ˈǰ I%T !g'@Y0Ҁ4-\WmXweNF&e]2Tis&3dq)I +[:WB(dX[ ݻf/;m(דPjE@qV?C58^饜VW5$ҙ$,{tu4ήBu8 p:TF9IwhaV8/Whm#:Uǟl=> # F8J)9J95^òVjb{^ l3޳7< DžuK:l{b,$(ާ8*Hk)Kc޵{W6=aڲ-͑[r]xwefZ|AcaW #waY~3b., ]Sgo^=O^9>r85οOxn=z 6u*ԧһ(7_S]_tWA>(((((((((((((((((((((((/zg/z۷oZRnϿg溛vUe)lFpy8\.xl*F;S|LDre qZL Jq8l5]#ڧ$rEsX>)v$Ǟ8~ ly j{m#0BEdG tnN9*8dDC&[=hq\q։G`:L S$w2T`PK:;nNy4CXFynxFjwl䁞J׊[iwk2x5@X;pq5L 2jF0.9P oT3Qy+(s}HYJ8=) $(J{ӷMTܑT&bS4vPDPsIn'$f#3ekZŠ 4kn ֨G v@YۖI(j=|:\F=Evo֞̓@d>#90$HYS;|w&'׊`=}3+v"l1dbcVl,jlG5 L:s,ZhQVn_uzc#nU2H ]$kRyHTl-85rSGSR 0j̤OTs rcbSh;՗?)DqJ(G4Zyx|O=*Քch+>U=kAr=j 8g EeoU鑊g2w /mrwyE*sts&r\*0>#H20]hRJxF5,Oxn=z |Wԭ-nk-#;zz~lU'"/ OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCר06I%Vz]˶@z*~PNOC<ٓe\Fisڀn=4ض`OQW d [ڀ9o&gUT 4RJ? ^@٤a>o*$ @)%3zTjᛧi0Eɠ'޵Xʱ9݂j)Qy>EVk3ր,M44 g֝Jۘc@ rlEj䊪*wXR QN:LFK>; qK֠*X:ր'!CԊULa3 MvA@9}3b=;ӥl& M>,IH[o[Fv3;OBN@/5}ml!׆SנO?~g_¯?xkJ}+|5>EEt袊((((((((((((((((((((((kWkW vUe)lFpx{Wkn*]l8וCר'X;TnX2jܳ(42v|?TAqKj98e٤qpAM,cɩ; f=q@st1&Ʀ{u _,GY9 gޭ `Vw| H1k:kYO$1׭e^ʥ >BMV1r*Kq '3@n:o,1]^xXHX3&r3h<}h}iH%$cj0I8Af !T`#Lr&T9w^;(չQJqb*ziwM Fxӊ3zn[,/ Rshx1X K1l\p!rHCn2x (wiB$sgZl%ֆ/ 2ma |nzX`ÚH8!N3ր: 0-7̓Nء8)oie^JbFs\3#ߜF$dg &ր>9+đT-j*po^2qޮqjYJ3oztۥ׸ ePzX+ր3USZY.rsVev1@%$V,ŇjHrɬ#4moVHczTۘ?EpcIl fBFҤI Tf#`U#}4*dP^G5JkLUcG[kAzmfd;u+=Ԫ s@ ƌ)ǽEEqRJAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{?5xSݻĪwuw^W}^8<,Y#ݿUjJq+>Q/nFWZKXu>6T˵<☆m(ă֮naEP?:׉v ր$A_+֬2yJƀ0ㄫtT9Ks֦d،ǩi]:k5 O;T$3֔Y6%b܏J͕IZ :Q^{q@B#p+/X qR:U멶#q\u< 8 =bvP})$t]9Ȫ'LFiҞ|@ ۶>s4ċ(^jMz%<(sfК P(vg#ڙs~V֯ۀ'9-x6Gau^gMḶۇ# /Z+ v@4mgUӪEߊ܂#Ŭ}0et69_F9N@ϭu0ϵS`L=*բάUzS3ր$ҕTnj{v\I$@ I~xFPaH\]e'jۭtvw?:4WoԂBJkԂX7 uT(\cZ奻ԙpY.4Lj#wa^=Φ#LvWbLP\MNVi 2XcZ5 TGg՗.|#Id Huȹ%k[x(tf _Ej$1}_4#Iֽ9yw%NW<0?Hz*q66AO"ր;Wx۞\<^3ۓƴ]~4җ 9 *$9?H8 fQ" Yq%MFJ=B U'ڀ-^FK *p+>Y5nq('ҭAnqs0P¬gn=S)`sҙn|0r@_҉$Fe#\Ny@yWuqR[Ci8PN}2w+qKn7$iHIFS3Dž2$38jNy"[ ;xE4ˢYz deAJ{ӊ8O-9 =*vzgjruL<*^?5Z QR6ƽݿUjJq+>Qkޒr mgJq׮x=wN\cn^;IV#\(tRsפci֣c@ # gtw.3ޣ'lAyEw~9Æ=j(ƃI-̂R~\GZ`“g_\y(đݍR'vAϩ}kS\?χ1i1949bhW`j a_$g@NLt9+Jc#hsM F@yZ[3M@q۸=FnvN=hӭZ+b9XPB|b?S=Oɮ_ENzⷤP1ߚø0w`'us `)W%H.q%cvKl[(F1@ MxH6?rI¯Bhk8a5cd@&]`Sd*BXԪƹ$7I,5%tΤe Jt"9_U;[vbGsU+&溶UBqڨj6߻@ֽ8[*]9ZtfLqW&Tl@N=+/Ox)KppI@9)M)06*U( x*WLZ63NL٨m<\bUG*GsY ɍҬ/*H"]wG" @ao\=FEr'%ɩ35^I=hE'#)t 5ÒT[X<|5YHD#o(-(;9V*{V鑲եL1@/v5Zm2n޻Ȯ$l>ŵZq}<#@ wYڈFLQ U<(߻ gBᘒka<9n[%kJ? ڈ8SlGmkYBB>}:Pceimx5W?W^Z cS$e])w!ZQ+cխρV` @u=vt @b  }quO'"X0O^jmR%dj,Axɷp͎[Ԧ)S f2mi|cO'ڍIأ*(u$g+UpXjv#vEWYw&Hhf!OczXx5418 ˻u ڳmk=K|K;UhwZNbl`ֳSق8&7]sT.ЏAV>lA`kw<sMmiVfSl,bGq涢U\ b-{5mF-7dcWR<%#cy'Rk22+`w'!249#lޭ[:\T /_@j-$go^=O^9?:exWL -#;zz~lU'" OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCרlk-%Vz,~ؒǿױbݎqYiJ݆/8!FH@B**A: (7 iISO$Ԁ(#ޜ mi.q;fP[9@ w{RY)|) nLvh/%)'#ZԱXu=Vldnku z MJ!aΩFprsFGLo-N\` S QSL7z*<.nm$^MsE0xXKV'ڀ=i1_&yp1\X^FŢ\;׏q@gpYܟzk5HOҀ3b{rp);)^kL@ M'l(q;֚i ad[`XKF@O,P*V閪"IZVG# A0qaKmǎGXw$ā >sj4X@qۺS] k$;P뀡@zBVԢ?FBA5f2,oJȯzXgެ8x4henMtH']֭#4ӟ!F b H**dȘ`GNbBf(:$Z/T?)fJ>q(GwjيD!W!$N7UH=*(-J˼敭g#q_[XJI'ڀ2 џJ$jČCu<@3)eђåu/8 /3yOhnLEkX xN}#<@PҞTxUP ©ɥOp&F#k=?:JܨYU6 zvK,c&zʱp95i;M\IYT+& Te98;r7B*zqUwb ֻ̣$Sq,5  O^&+m)Bɬ{&'"=&&W7JGu[9mG\ּ ǽTU>}j"=9%HFpKʯ$ʬ:[ n:ր;;aPEEqRJ0EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS\=w\=m۷JWw[)N7u{g3qu\oZRnϿgɼ%tB򀬻h27V'bWǽ=˃Rri+:1|jIH#fzP\|ͬj2Sq=j$v⫬^3Ҁ.2~已#5x2:Ⰺ׊U0*79@pYE)4d w4y$vh`1ZʲұGzڎԶVD0oZhsL_.xN=W7(3Zf'ԋuY>^* )8V$qTghʧ6.!Ag+"MA ;XO/ I2s@eܲ>^.V%ҰpyiAI \:ڝH QDȄ1@6 +2'ڹdn5"К{>Zoўl*H}*݌ $rM#؆BqONI@c<7㊜E"(a{b8NEWYNOyfH8+d NJm5J8FS!%I?($ztRڸ4%r݌xsfɢE t#cuH{T C#ሠ:K{FQmmёӥv2۴d9NALBꠌ>EW9C0=kV}@8T2)4LȘXvWTe=Fr2Ih/tf:?OZsbY@Z[E\&AH WjgA@}e[22G85R!$9Us*ۡoOuPT:Tlx*[l9.VG`1\IbsXb{te\MϯJ{a[IaP0+@D VKM$u[+u< cm!sQxPv| [Qiܨ`I=kڹveW$\1;~sҀ!HZ=vՉXռc 65"70 rs+NY" 1ڢ%j%x\_NzD3SנOTھ_NzD3SנJcEO OvQ}\oԧһ(!QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{75x?mpإ$B93P'̤q^nUTxIY3#>mK[܃?{=p3Oo5E7Q!$U @uNնl\fAEmVǮ3w oe\ _{#Ka{_r*?Z'q:[EmVǮ3w oe\ 6+cgcgKAl/y}UMnW8 Wd.m=q~;{/zdmK[܃?{=p2^e a{_yR !}F\xb-]/elz7r v_.m=q~;{/zd~ܿĔD^X5; 16+cgcgFtm33%_{ g̣ú?_t;o֞> ?э6+cgcgFtm33%_{ gRfv>MkGlk՛EmVǮ3w oe\ 6+cgcgKAl/y}/K93? -P^.m=q~;{/zdmK[܃?{=p2^e a{_y(b#F=b ޺tm33#h_Ͷn쿙끒/[ _r3W ~5Y]/elz7r v_.m=q~;{/zd~ܿ"V \zftm33#h_Ͷn쿙끒/[ _r3=#?]+h_Ͷn쿙끑]/elz7r v_z-/$f#} mK[܃?{=p26l\fA/_/9rUz.?t͢6+cgcgFtm33%_{ gvUl'ڸNGf 65M6+cgcgFtm33%_{ g}f,d*AMzh_Ͷn쿙끑]/elz7r v_z-/ RFQ^.m=q~;{/zdmK[܃?{=p2^e a{_y2qIvic5 6+cgcgFtm33%_{ gZ 6;,txWM6+cgcgFtm33%_{ gͶF?_z[vY\& Vtm33#h_Ͷn쿙끒/[ _r3ⷻ7A6˰ԟL=׮6l\fAEmVǮ3w oe\ }^g`ҧ0k[EmVǮ3w oe\ 6+cgcgKAl/y}96N{R.^.m=q~;{/zdmK[܃?{=p2^e a{_yٍCSݲpGmK[܃?{=p26l\fA/_/VMn~3/zdw͵qiJNJt,cӴyH/ze0VMn~?3%Ďb_ZF Mzch8fe'c}=p2iv;O=q/zd,8S81]n`z3_^wcOnǟ_p8k k5q*7㞕iGwKtҞ~?31K @ChTon{쿙끒|wp7'Zu_L7<5W)<8e\ SDaE; 浬Aw'־o x`#ú#u@c==p2_ FI(vq3%V'qRzzWwkɛo[Hvzɣ'84g(((((((((((((((((((((((8e!PqȠ-t[˚duȬg,ywk**#FPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLzo.f4k͒WyiQ ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEG7I,0lުvIzZ( ( ( ( ]sk5Ʒq\~]oX|7zk[Ns ;#Xmʁ"xVD۔rF8HVnL2n8LPܖ~5UӍgY4K~f3ٿû>}zp ^w"Wzӿ\xCEn&7 kmh ,~`]Ìu8V u![7xYO,K c@"VR?]NQ ^w"c tnY#qqm,Ou $`y?>Ufco^>G»׿綝޽=Ezu][Eqo" 92A"ջ<޽=E+ԨջԨ<޽=E+ԨջԨ<޽=EIoUtK˛4')opP?Z'i-ΈZ8Kpg֪զaFaSC Đȼ28jObm3AV?V ?Uȶ:7zhwZy,-ELȹœz /ZF,ogD3ڈ2H#vwEnfPH7K>,xyA b5H-lo洏u%Aq0q&*@9jn-o/./"K1"\AB" ğNsIm=F{wviр@,p@CL]Um®(R8<եy'W(l$yce ?a½ϲ'|y[|7}wc=֞᫹m쮍֦UV(r%@Z77 eB9; \{Xm|4* b mԑL>?ڿhy{6Yw::X=U(5oq$`yt/ڹcnn3]0еH<)}׷7)*;(%˴RQ'#8QG@p ՄN Lt¢ 2J3ʞgW,^*0Y[[wf%\s:P_ i]#Oge %K"$dAZQ@Q@Q@4ԣPlMz]բрL[I 1NTqSk(/?鴙mw)ͻa3;:( ( ( ( ǗF-axJ:uޗ+˩1i[b7?.x8O&d`qmQR0(((YEAS kp9/]h:5>kN10nt(.I#8TOZ hc/7o*4xg'/=7^펧<^&{?xIL7w$ĩ6mi>٭e4Tbv:Ozi;[:4Em)^;;׍ Tg FH~3[5&%wN sr'%@ӡ47RĚri%ĥV]9 (1bB恝55 h+{gy*(,va ʹޮ7@;ybD,Tiup-z''=QEQEQEQECw3|8sVwuAa,Asm;>TpB:ۥhnK<[kF2:J!EI=I'O$*'*yF^r}  Z?dIFOT/-e92ηp6 JRJ?civzy:+FI7FVRN #Gg\!p[]RyQz,Go)lUk 挕P|=2? W;{<&W2;O##!k{%t~gVrfbN@yԄbCa pHFw{So)lU_|> @:>Z+ƿo)lUI5ާRU >}}~4WhSQ?o)lUekFQAMGeϟt_f{-_76_* j?/G|;3L49 ʥBpS@=pp?!UOů&ѿUVklgxYQH]h+:)Ӄ{RBsQHh;(((?g\AO*')EyjWwB__Elm'oKv6F9ګ^m- }GRJ쀰A0 "5b/9;$R ,@}oP׃t᳽nu. ǴVX؂<; {ERQEQEQEQEQP4sEopmt+ymJ.<Kg>a=PsxĶuu_l_%zZұO qW-uS,!hٺ0"~YM %EĻTl'{}QZ0p֍:SikG\y\kO>\fݔ/#G5gCWQe9NjVwj#6o3tianO#EʭP$q9˞@<砮=)B"gUJ=Ί$hyL]p+(?1 =YL-[thv"O- V o͈ D/ª*#@$q=j`Z*>a"Z`X\ğn\L7 #MrO3\ƭ->|`ps]]vA7YI1eo'{r y*ٱ.w6r8Izg'r'~|6n9۷n>xǧ#k=Fݙ^ʗzj>u`d8ah略 8y뚧\p[@rbLI~u֮[(bc`r 95&(qdF&Bgx5+)I8"22/УQTktef\(*ڢ} >OQte2(۵qgQTt YoT&#H g覹{ TOH+p(((*}3AV?PTg" fivzl[i֫ios2+L d`J̏VحZ[{< Y-m<1QT#:cF $ȗW rlQy;g|qMiMf-I7s 3XdއFir=?wi?zԵ;IEu$Mc,LQ9"p}* hw RI+[[{y',X+~_q xZw*VG',R,y"yuv#8 s2gm߽1j_ ӿsnW=]._}褣n"vH/LEI>[jI3 .ꛎ{(*=7i?z7xZwCP[I派Hȓ2g<ݻ7dvsZTүu R9eIZXjH.BdRvhU@;?HO7icCa2GֵtbWY~$ Iм2&FFQ`ctZ̊ URe@ŗ#BE?~,.y/ juNjt[h?Go$,lQ؅RU7/-km-̏1.B[9)~Sn3dkgt_}şo/#T>)ѵ+.̍8&\E6HI rI IVw[i:MvjSG$4k,b 9 N=E\_? _Fm#HԮ4=!$Xi E,@͸xGSSi#"])SpXڎ>v;G,NY,BU޿6ڀ;:(§?g\AO*')OjxSKrzH(h;"PmЎcmN xqaѭe,. fAP>-9,,>?.%NPNk)6}X㵶KH+c pbx|>GkzŽ>Yqiw(-q*$ĎX 1K;G*7=ٺMIg{{;Z/9ZdcGuw$DE# #ݏן?ԞQ֓T&}8]ֱ7̄SZigOh5.uh\±SE0I< j3h7X zXH&zBG =⹝;zeŻV#nGVS?*~y?go/#Qf |=ھgt_` 6e4IJW$H*{Zw8mBvq3ߊCF|_@m5`d_{V:5H5'vBܩ!Ny'&54o5wsRB%D*^PI`Z?go/#Sv֟SǫB8fE(m>Qug9:gOmG3n/6ywŞuan_QmҦ(l,`뫭'$Mg9bpco㏙ <ߊCF|_@m5`s,𮻮 m;r o1F6 dc SUjږ֏dR(#~21+1&!ί/PH?N_? _F 4:.fWq5ܶor H$l.0IU{ rYދ{vY\X 0slLu7_? _FA}<)Lk(ИN[hN=jڤ 53>d'G~*Y@]5kgt_ v^Y\lv!h啡(qsϧ/SmBU *Or5;)hFP;u}şo/#QE@\m^ܖvSKHyO3B>}ʻb#ӓns÷zv.b|vKut,p77_? _F`(EWEkwэfa(vLVݓ#eN3"h>}be=*6<90H/~Y@]5kgt_Wݮ G&8mBvq3ߊkhZ8( v'$Zkgt_}şo/#P0 Eubfn%7,,q88=W [L[pZ4Ѽ *Wi89^@5ET52mZپnk\ > ?kpsi\AwOÉ'XUV(fr@U=~%>);<`W$QҊ)aa쭼"/"6*h%W qJ$m={C󟓏J(_2WiQE# ( ( ( ( (2-_5T (((((((((((((nip2-8.7.1/doc/html/figs/snap5.jpg0000644000175000017500000012205413414613100013506 00000000000000JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJUs}}謽=syy#k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZzV>sFt-V|m.?e? Uˏk: "r]*!s $KU42U^ Nuny;[ۖH,zUufW1r nyȪگEU~S˔vN)LKާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ9#K>6ioN2WVՏ"uU8,q^Gv2r {3Ȩ\n:SL7?]=W2yZʣFgh$<ā '?J^=UKa|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|ͯ٫{6ViecX+QL(((((((((((((((5O[)^^jR_=cƉ~:V~:WA-Q@XVXP'_w)޸oNsφo5mM/ cQnI;9·HmY\< ʻA;N2qPMv43VqJ2<>h"'Y#war 1)f ($uߴDCF2rAcĶ׷,V*|˖X].k*= P5>ɯYE?.,eHګ0([__,Z\Ӿ<+ BEaz㎧3Ē4=G3E `F)b.I|ЊS%w;y6/V2ʗD_KꚎzE 7`rKc z L"ִxX wAO]9NsiVD-N#evn두F2'hb-'Y#K8,_ c`ʨ#pA1S|bcjCe 5-Iޢ4IyD/<``GM zV%Ԡ}X$Ǚ漁c79 Đ3u{X[e /,,w$};sqV/"dIvD9=6%ڮ:RXi&].1ù[[2]VP EyY# H ןҴ࿋Q)۲8t Ar2x9Ηtzy{S7 9]N6@㩮iKugFTcYCtn8NVNrW养.O#*MK6ݟx3k]E< TG|yzoᐋd^3ZR[K4#Mfy69cx2rw_Ƿz\$ٕ3Gz>-gm! vz\m@0%՝vu 1Z+i_h1Ỏ:ݷ!có/)]}}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^lR&? o_oa?CTz;}J+|t J+|tZ(ұo-ұo-Oß4AjSp? Wr ռ1kj]xtQG@}>וBDA tOSh<Ua$÷Pqάr~|Vk7WK!k&vNdqC <㯥 <'La%,HTgcq#;^76uZ0P7@Ko.h4hLW⩃ 2@c<ǧPf{(Q$C?;2;An_Zr9>_)_C>>: [;-8y Cب_R0 -tNOqopH~H7܆$rT# 9}Bi"ٷq^\"(|qNrxZw>dv<ۙM,B ?0BNIr2uƴN*oO˫N4ۏmo%n#Q#+xĈBrޏe"{G3Lwl9^LwUHԌdܐyu_ }Ki5g6Tq6쏗$J$?Jpvt2(Rifh!0 yIjiE"EX&n,[ <9 b}:L) EHPp7IoLs Ər~=dgE(:2m[chS k|!3A\A5zLR^$(qbVP۵7RtGpqL``~ϧ^N*Fv㜜u*p\D+ʫCz67D!Qd1 9ҺzQ簢)((((((((((((((( ȳgڵ#,6zC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( d5}5 k+ ?S?W[`hW[tEolor~? Wr/ZHc9DЅIQS')iҞiҀ*ֲɥZheXJ#0B #Zu/-7w1UaVޓ.S & | >Pݎ~=Kqٹ{{1Py,X9(p:N-h¬jFNۿmA/d~ [؝^ESQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^fkGYmZQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE k+k͓@ V4>KާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ9#K; _w)ސTs} tOSh<*ֹx3T?uK'Zm⺵K{HeiDaa}Rݕƕύ9 zI @':W [դiD(*9I|u)Mf.c\ҸO~W|},xc+R . mrH?qW1xS3=Zf$P:.kX' x/G)Y݅]CIc1#׵K^#VR,󜍤Ǩ=zW=綴 A9,4ݝNׄU "ڭ$ œqnj~M;E5V:-CH׭ZYFrtҶ Kt-;Ep!U %m/# Fq7A?1ӏF˘㷳2Lc+ssV^}ge?wzИtbGFI Tx:v) MI{#srALvw~8<;?_skm e-P7gnF@=;4,]*h^/5$QqsޙG,,1`' = ^O薗Vn-m@?C_bO{ZiVOcOyd ,sqwD֚Jjp ܎R;^1^9+[}k?>m"X Xry~} Py 3EuLю,Gs\LyaQDZϙIm/3&ˍ }sh4ko<.LtO+qJ9dIZ80O?_b -u\qDZ 6q+ܑVO_=i5|k2ǥXK=Ky;[\cFsCW%E-EtV?Ь!A}پn XAnex#pB<|طh%D\?/~f>OwnsG?=rWOYi|>qg,'u'sҙ{ki~-CD>ZV\`2y Madn ڌf'o>݊$OI-4ծp\|!_trWEŢi,0f 33­Es\Io$rY~9}~{{\讲O6}ɇyy}O5A[G3m2!ͿmH猑Mc?N[ |) }.c.I?"7qw8մsq嶙ty\3|8rG}η,6zA0vI"{ժꌔg`*(((((((((((((((+͓@ Wכ''h|COXo_o_or EPzV>zV>sFt-]wß4AjS!v J{x'#Dycer!FzdZbomq0Q[w_KUqM6?4_F uc#q\OjH?\h28{9Hp@?L 9"_SMm\#~gp GiB$B#,ʎ[o^+ ֿ//5~[;nɅdcg9z~X%9I5a 9(?kx,O"(-${ e  kjSuE; KHJ= zxrfF$X]@ኩ۴t@&\~{?s4QkUt.^M9@'H$}y[ѵxʼ z W 8=#??GƛŦtjw=1 , B1m8Ϲǥ$mq}>KHJ= zx{??Gơ`fdή iww2|4c@ϴ[KhĒEsHaXo>{?s4, =74.HDP '#=Ses.|f% =k}U2kZsUk mo "#pQGs y\A"}&!;Hdu8VokQm$'V/XKy=YnaDQGF}84 #_5Ƴ0vp>oKQ$ѽiI]N oΛl9Z"kiYSϒTrpX g vc??GƉ`IYU6"Kx y0Kq봫wg/8isY#u Iم}=+/??GƟw_/MċmsI3 eV ~Î9mٵ.ZV4KDHd n_??GƩa'mDj_is<-¤F0ZK-dKԼBcpJdgWPm};@̙ߺB/R}KY5unXiEtlxqa7])`G+Arvߥc~h}ft:-n $Vp$zV>sFt-]wß4AjS!Z-uk滸W *2w*H瞵Po B.|Ó } mn$IbyKhf%eܥN ǑLEKx$V jYkwql[u\?'' `:V^ 4gfb qcx_욵 ]&XtR {R?s[{;xcϐJ{gtA8r?&Mƙs%d95LxFMcLmBH#e]zVW$Ҿk7hQԩ;Ty)0@!pzǷsM^)ѼĒ.o-ʅ=y^Es>=w6VOe#FrN9݀A?tVVRW2(A{om  @;x?xGpW*|?jy<X-XoDt%.We&E'T`H(>-q:yvi"K$|f gn%NNH!EczijsݶƨF`/]*ǚ+C&7[j|*F$ &I I ' 4[=-YTb6G׿L֥rKsER(((((((((((((((((( ȳgڵ#,6zC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ~ \kw!L |=IEo8̙}@}0qɬ@V(Q,i߉+ח;VhTeW-wyiN^+<=xozPԝV2ƒG|W-5]yP2z.y_ũ6yhɐǡ 9=zUSƛtU;v%F- G q8Zs[M /vw0i#H.$, $d58 ㍹Glt^g(ǖ;qnfZGE+Pg^ÎB5̘M0}+*~u&u (5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (=+,6z6? ^Š((((((((((((((((// ]J+|t J+|t!hJտԷҶJտԷҀ9?NxsFt-]w1u?B]BZ4O4@dY— $Zru_hs5ch ;Խ}O գ[Mc퉚ONN@ ydunPI9AUbU =3*K.n47$4 29 wst=FA#5ޥ.c1-h:'mJ#ڥ6s<;}Xb,FNґ9sN9uxגKŌ~dg'^2wjXZ@T6:3V=r4>D^KFI,oL <ITbR쭮hgXLpNH;HiA'+{kw;yᐴjT)Q=z޸*4e$93J۞Mʍy_1T|s5h#n^8D]x%AO8H02`NI 4 RTU (Š(((((((((((((((((J6? ^<-"͟Cjפ0((((((((((((((((cv+cv(WDRJ+DRJ)Z(ұo-ұo-Oß4AjSp? Wr uG7O*9DЅ11S1k+\tLg)E pdMkH98e28 <*$4|9%h.Ky=p{=D޳pu&59nm )Zk4{G*%xrpz'b[W3\y0 :xG+3Ǚ.vA3aPpyZZWOs*if6yHyݾӢ߲,P-]ds5_hZ[It-KVnU}v!Vp׾֯4i

fouq-ƙk I"lhړR6Re$Ty#QO˯=]>qgBϦ[q!Œ͜tȢ[8k ib yc"pXp=uCi[]G:Oej'f8R :VҢ[Cm;VذPz azTh+ە>Et^ ohn MEb[郴NjM|l+s6JK60Hi}9+;ox㳵"3Lg ז<][b64QdR3hߊ=5~P:9EohBޮe q>Woe=HG+*3Q,zQSо0 gwp]8Ǩb&g,q;Xӥ?/P{3s=ͰѴ<`xR6/'Z}ݤ7ATϥ)cUTo⨮_G,?§J?`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`-"͟Cjת|i F7aT`MXK*]̚QEB ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( |_l?Һj|_l?Ҁ54O+Ұ4O+Ҙ(=+VRJ=+VRJ9#K; _w)ސTs)1$2=pANZo-ne%axGz M\cNP}2@LCXL=?ҘװzO~)b?5?q5^lܕ)8HS@?ş¬#?"O*|IY r΅]>S u.<˗[k+ *aH>}h} Ve%yRgSw*le ~TWxbXmOe$v tK0q ǹk1xXi}=?]E!@Z n 99]A9j-Zdfm/7<}k;F[^ٲGoāGFxI\?6>Ovǭ4ڪ=WRMݝ>w=.HS7"h  gSVBW+n#YE`y9PG {krb1~S[Pϖm EK!еf7ky:Ju$FCezV,|m:J[lw8 O\-ܿ'/VSkP^I )9D(  ie, $)fNҸTz~QRչ#GIiiBnd 67>8,sn*mqu °!?qSxܿ [dt7^[-Fq8(Nvl`9IҤn亙RHZxy*2m99OQOSu?lYx^^?Sh>ĕIϪCqj"iP3(9(P = 6p:whRZ[UCu.TODgno'"_Y4ڻVCIT*I냌?%}O{47"r0%l 娥ks~GcNig2D0ӓz Ԛ]朶EchJ:b/\<j_GWiWfE*H.70 A סQw nc 1n‘ sQB+)~AOfӭ5;_:yic ֭Kc%B}pTno{#<3߇c:+(3߇ǑtWQGg!#<~CG^yEٟ?, xn =7WKy0b 8׿v7S7mF<@ƼnQ3rVtP mceݲ e%Q^Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\ϋWM\ϋP~:V~:SQEc[[c[@?iOܧz9#K;^N$ٷDO@]B%G7O"Ѧ7Jy7J'Z-̖zLHbDb3 ҶT5 %&Vcy4:XjWKAL vJ R89]QA +wEe'-t)t4* ݝu̷v̻_,Ut=y&fRt+tjx.b?t]8Z}^k[OuXYH{,Q*_Mlg]dg=8jWP+ż*A-=ֈK2 F0t? Tc6z-GRkdYdhxJ35̅e W!r@yV5K.{ВII=I^vm!6n=B#0@D8ǖc 8Ebu ~kInnǮ+Ѯ_0^x&[ f^PJs׃>Is4\qҽ# ^Z/Fvģߚ؎IRYf @Hռx@iqȩtf I mVҋQElsQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\ϋWM\ϋP~:V~:SQEc[[c[@?iOܧz9#K;o?!RTs} b-ctcPY:Vq1KgXZ {7NJya%B =IӁ*-Jksrx֞MB$GjAHnԗ[aE$ʣdn“EsC4 XHIݳn8*X#VA'9ǵt\-˨$qU1@.y]c\` gW1WyS.u ԵvCO#U@_x튘j\\ywi Pktb\4J\(Sg|sbRK)"A= 1'z.OJߘÏUxqӛX 932j$EGy"w5\F@]æsbSѝ~dU1\7DpN霵R:p8NU&bcsrpkVwMyd2Ur㎞mnm6LIJNfܟcNXc;m&fN}jާu4vLSL@%3 ~WI?+]$VWl@-Dnyo95b-R%@ֈ(3I>Z:K~?QM+EuZ.ӆxQB%$8 ^ZZ=ŴHXϯIڗ+qWIy/oնYyby{9@GZZc,z[,H\;?I}Ƿ=qWiK*;v0O?*Y5$]K)H;m$NH' O?gEu]Z] 0X}T6F'ŭ[zF'*ytQ}_+OWG2 ȳgڵ?u5zPzV>sFt-]wß4AjS!J ?ҟE1 7OmfϱO*n|?4Z(O!?*)c D`J`Ѫڍt۫M\FNr\̋-ĉ,N"9@z늍,Vk"̎ ;n=kvXcH`ܧ7rx?طP+[7vm~?qp躸mM: .5X7$[mk#lӱݽFpW}~b~CQ}AM[^72Od\CRYGNAg_z}Os իJh UFGp9ob~CQ}AS7{zw(9d@.&.Z"H9b_%U]A,ΰ۾X+9 [ߨ?o?y~)Q4~?sv5k 9F+w?*&;N'T 1ž"cRK#7Vٖ*y6E#T)=hjzuֲqm2KwzpN9"[ߨoۻbRƻSK˧yDK ULdwq'IgmKw5B aH{"[ߨ_S~?̿9d[w%u'dF-GYk^ \-H݉8WA}AG-??E?;[W#ۻ'[$:nW$%{)$U djž"ߟa_Ŧ mU𧊒A!e`EFHF+ž"a_+9+e`Uю'^? -MC#H7Y9KdI>8u?طPb~CSxY> F u;~SOӖE햔D$ %r:[ߨ?o?y~*~?9̿9q᫱?~;fq=6>5X;yx+0 Z迱o?y~(žsGG3q˙eDX$̘<sڮ*_mG?s[?طPb~CR}h25Xk&`h`8<9NV5oj"cT+["[ߨ 2E?5"[ߨ?ןaο~?P<Oy猟ɫطPb~CQu"2&yKgpдc *zTPIt9QEdQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>.@'VX'VLBEolor~? Wr/ZHcb ( zѬȹ׬ )|qC4eVbʾ#'ӭ\r@>r=kj؉nŠ( (((((((((((((((((((( N_~hVtjQVdQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEYtYjhW[`hW[1 EPzV>zV>sFt-]+/ZjCڍ(Lڙ*.]5s>.@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3iW5i_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s^.]-s^.(ODRJ+DRJ)Z(ұo-ұo-Oß4Aj/ZjC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ]-??WK\׋?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O5ib4O+Ұ4O+Ҙ(=+VRJ=+VRJtu-]CGe +O.OT[\5}.?k?]tTTV]}o.OG\5}.O*O*OSG7' rG.O]''?G'?Gթ_kw_r#˓?' rGʓ~_ʓ~_~/뵻eC\˓?HU[1Оڥ~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG{Hm⑑.2jpkέzU"Y?أ_*z+CY?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?خ2$ ߥt_ [?ԯҷJ?ԯҷJb(}[K}+`}[K}(?tֺB q3,؅''_ι?֎뫘&2ܼe{pt,N3Ku]bK'm7}Ew8T8r+NIRݞDҁ_nՃ{&}:PŲHK'wpXt1Z\mٌDJ&L1yu(vwfc͑8gЭH8Zv5WeMO1Y p;䖚[ͤyۉ;rv5[OϪ^Z\GH$GSҟ| ]\Ei;wIJ\uUZzv6trmet,5 k[I&XDhC#3T.{#SfH$g"ܵ֒ATBі jts"+*,v)v/Q[-. ^ټade-ěJM.t,4H,pB?>wt״hYD]WrGRT @\mD܂&O1llŐV-'ێi4Ro&]`G, q\=PykwÂN*O\ͧK{ r|ƕXYO8;/BfZjZU 2C8Кѷ8kM 98<5ګz5Ⱥ,hLpGPp2q}lմ9`6r9Lu9S<],HY slWf^Xiyh cr#q`q8imKXŝi9\ pgiC.ŧi(ɖ430+na񓎹֏@^eI,z^גjn(dgrǞ=^x(4=B;V0n?ΣTՎef=u$NpGA=;fn=\a-$Vl:VWZ_#GZt >;x2Jr# N>>:@/8b8<u$)trȂ7gcfizǁ}PcWmo`W'' }QnFu%юHrhϹ-|AGrܜ['('Bwa$pyhcomuȏs]fgԯZ,q*[4o뱯L'm.KKxI"x/ G:U4IJ\PF#ؚVMyMJe-P)wOe-x͉@2m&;iOe6q>rgBޜf}ZL@c hϹOmCzg\ǽ{JqުxHֵ ˈ3j]C '8=a}=ƻl7&Oך:N/"sIp"R㪯8I[xVHѮOU]HJ-[A -'{tFB%X1yw-3O`ϰ<DA =*][j7A"PMuϖq6z 1nWUE!-*䁌MKDhF6bmg{fٍ_z5!.xR9[ =zT^ pO2! 4 'IjBK 3`2FO9֧ki<;zV*OX tz~nH=ɫ]|KCoo;];O=ȭ8fHPrWz-ҵM9!hoM?yC) ]f2Z]GAdmfec,H}zsE]A>BͦcPvFw_xJn~wtPfB{V`]V-{.;)_`{WVzư-t"-!W3'WS^:^2up?4y0;A4]KHKhO2!4PN=U?F,<"Ғ[ӯJ4_C[+6 k4)2+Aݏj/&HCS,@ fsUA'U-Q1[%XUz8it4syQYXv*@ E[.Xg=\r#PNNAZԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]ݬ/./J+|t J+|t!hJ17ҵ[Њ))8OWmj6v򼶒 `W9qsecU?Rrzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_OYgWh8| {Ե?l_O+FȊ* B"ƊQFT`+ ~G ~E",haUF^C^ > ~@^+}?EyM _#϶x_Q^ :Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Eyť#9fܒOZ煿?M煿?MEm|?-SC4c1 Ѓʥ?TжM?ɫ{sxtSB4h[|&o΍ .lf1U\вgkzCkS tGޯno΍ .lf1U\вgkzCжM[? s`K""+Ax/ߎ*Dݟ0-w7Fl|>2l8\gAx>֖[3π>G:77@* 3g 1ڰ ho웑 D?g~:77@?-Gj?TжM?ɫ{^sʀ"жM?ɫ{sxtSB4h[|&o΍O om|:77@?-Gj?TжM?ɫ{sxtSB4h[|&o΍O om|:77@?-Gj?TжM?ɫ{sxtSB4h[|&3y`:'iHsn}ʀ#жM?ɩq 1 B4h[|&ƫ<-hƫ<-h/ om|3ȭks 4hжM[? ?ɣB5osxtno΀*h[|& oսѹ:m|?-V7FhжM[? ?ɣB5osxtno΀*h[|& oսѹ:m|?-V7FhжM[? ?ɣB5/`󼟴ټg7@?-Gj?TжMF61$de=o΍{Osƍ.[iCXOE#̊/3ѹ:tQ{۹-&sEcqac~+qK x!`cPQ8-ѹ:IGi"2ǂt\㧵E"[9vKH3:77@h3sir$#ljB@⤝4{U@w#µw7F4 ZD1 ORF9&Hkg>Ju:֦?P6"s8Udb3(k&eV0B9Lp*?P80]Gz Z[Eյ$hX6=V3w€25>GqRJ p^*T p^*ThX`W0EUd08,}3}QYhv`jڈAo%wn!~{`R&t{a,úAf]Ji#SbcmXFʀ9'zշg 98d9?1CVOx>,#}A @ -<iCVO,cu7 +i`xNpzPMkHl7W3,۽O- 'ڲ-M1kg!0!ewo9c;WյocB\麁+s:D\褆$[Z̷RxJ1%rbX[K}z ?/񃥴I0l&4c8xMYmP]qjm/l 0!2 ̾u'>ī}X&%ŴA': locuKqm62cD@2pOy[?+?pBku o4 HzO \"Ф}CZ<1H"e c<~UW4wI;'z4UYO&G!_Q͊LK"%ZOdhI,MS#O?"B4(vAɀi~\I,Mi?i}}GQF?Eخ90/i?'z5O?/?&s'z4UYO&G!_Qsb 4.UYO&J??B4(#O?"lWdEJ? V=gY?F?Ei}}GQ͊샓?ȹ V=gY??* 'T?/9]r`?_xN6l;3m %q[-<ݖܜc?ZUA#Aux%0O`~No!꫕ǮFG[u_#-K V\bMIڅ STvoQ%77G@I#*W?5wˇy֦o7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇywDu9S-]Z蓀 F 0/I!伹ytMdhɏ0SO+CY֦lwKU3`rCɮwOu+CnV+]4݉Qw ch^E{kɤfnW ’ T~6tMY54]Z Gh\cIV\Xnt2SzWW2K6vmSbAYw购:OE!"-xdˡyp}2'z5׃.ndqTu 98ʓ'EF?ErJXF.U)\ V=gY??* 'T?/lWdW&s'z4UYO&G!_Qsb 4.UYO&J??B4(#O?"lWdEJ? V=gY?F?Ei}}GQ͊샓?ȹ V=gY??* 'T?/9]r`?_?* 'G%ZOdj!_QG6+LK"%ZOdhI,MS#O?"B4(vAɀi~\I,M1Cay[740:pXfH|)o`Ow,ȏ 0'5Q&+8_,~Վs4kx#c@dgv?YӡԙüI ᜑQ;B~[(Їߖ \?F4;dkJ}+ |5>G1 U뽟UmDdo e[#?K#y4]vtOit/e".pN?rR*;.\яMߟ?P q>1Lk,B@UB zbsc;.\яMߟ?Fv]ٺ9ţ?O Ztn#:+.$;qv~{>EPgeݛ3Z1˻7WGqRJ p^*TQ@l𵤬y=CNעC K&lmbb)aEwOG4y)Ɗ(SJz?o<Gh%=7䧣(OG4y)Ɗ(SR&/b][I*%TzqE䧣<E <Gh%=7䧣(OG4y)Ɗ(SJz?o<Gh)E6nȯⶆU"G.҃z|Jz?oJz?oOG4Q@OG4y)Ɗ(SJz?o<Gh%=7䧣( Z%KK{i%@93N*hhSP0SJz?o<Gh%=7䧣(OG4y)Ɗ(SRmՑ_m D]<E䧣<E <Gh%=7䧣(OG4y)Ɗ(SJz?o<TKؗtJr U$gQE.)Ə%=7E%=7䧣(OG4y)Ɗ(SJz?o<Gh%=7䧣( QM[+HK瞟 jhhSP0SJz?o<Gh%=7䧣(OG4y)Ɗ(7~{IPGSnip2-8.7.1/doc/html/figs/snap7a.jpg0000644000175000017500000023006413414613100013652 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVk)i9'GYe]G9Ep  Sq^_, %8?URAu=5C*"r;pG" 0'K@.I$Iޓu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Sh xbXzM/}EEH&`0 *S_ʢ,-܈IBPXFiKIQJ3jvǤ?zCDpQDpQL]5<]rk՚.?4]թlp d~E}Q ř!ti G+_!OƠ>2*iױç^M Fdmdcºw?5?]xw+i`O[ox,gx ,zV]x_ᯋ@OӞ\˥E71f0zF~ɣ s?*S0Q+#&ac?]q+Kꏢjiq.3\%|e q5±?f.V>0GLQ۹A46;r uǑc^j̀D(L?隋?0t±?f.XKGsFChYYB:0>`@mLiY{+K,B9]qTX3G+#&a70Z/9mMmZ0[Y,]o+#&ac?]LJP>-Ys[wcީ±?f.V>0GL..SD:Ћ_˛F3}zi=.'IMEu418ݟwcTc?]|a@_}։ W{aטY0qPf ,LVGP,E9UI|a@?0t~!\񮩨Ky>$ q1_ڪ±?f.A%Eu|a@?0t䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@J?0u^HЏ@ ( )˯fǟ Oz}^a㱝6zX4\$BaR<~ xّOb/5I5 7V^j+<5#+lY鏥 :gXe]hO?>]j֑̋^E7X(l6ӆJ]KK{hu Pn!ʸ%[a94a$Qk/R\xWRI=qZuEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE2iImƥݱ2MVn#3 6 $@ 7][PmCOW ǒrYѩ';#۵Wtv0:+bHßWW0*tMWnӒyyC+}=kzCB2RJK@ ( *e^gQq?J˯ftRPEwuEo2[eG_PWGb@u=EdMJ~\G ֽ" E--{ }ryobizD_,pv @hQ@4:69vNH)b?UTr,0aB@ hw<by[) 7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"3}"K!`4kv/ ѴKrqln%q'%Q9kIhxWq+3Pȋ3RRr_bu"Xϡ5[ :r߁*(QmԓXL/b7myAj΁p^jilV7zc9 \c{zD "Eih%?:/?*kHLPED#Gc3==N? t}K) :k0[gikK^0IDT0^+NW$q;VΡqcX>r$18#L쓖PCEr6rT6ܣ!s֫$XL~h6ש@y_Q\⋆ӯuY-`id'h ;d*56I{T i:PgEfj7:|w:ڳL" x39>V6$QE!Q@Q@Q@Q@Q@Q@Q@`<͞ls  ۟ʸ  5&Ux_AA˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pBƤڃj7p +GԷ/ J/4hgxdHS1i!ŧu?Uj3)oR9H ::͍ىUkU1!cw\v,쯥)(Ւ wNx5 ^W'F\\;mʨ F8=SZZ5Adi±Ò~R#q>CŖ\*Z^-b[E+ 988AkWsl90I($=Ms:ܲiז2n&ya>@ݐ+Z7j0"e  z8%_K[.ŨOlַV0Cr1Vm$VI'zt3ɥVR8 þr7>V'fぜ3C1Lj>&!?![w}.zmQR,›JDdg<Y,4on?7Ry?h3nW}NHcaӞ:go2U?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_Zuj61Ǝ&p;;zu6N8fD3밁CGJ TBvbz{.m >]C6Sqr.c*͐ON28xvXf(|)#qZUdlbo̰gv7P  =v^{)-$F>Q;_@'#+j>[+ x.-m>[ϼ?7]~qtyυZdxG-P0 ?.S,&pHQgg,z{U[ϼ?DWDp*L (YMgcsQE?_#׍YF2HY 6(Z)~m>ϴ?(%| JqI^C;r*oϴ?( ŷFoU\zg#N*Z7mћvj(ŷH"IKQ @ 9Χ ( ( ( ( *%EA= $o[ϼ?(%| J)~m>[ϼ_(%| J)~m>[ϼ_(%| J(ةQEQEQEQEQEAyw wP~ 7rK=;O"[B$:;Vǽu,5O ZZ 2m~5xgNcC:]ۆ_CWM(^ ]O[6z?hF7lFAA+NEjf+GfPX MFm"ZZ¬ZL.B2r2>´`{H DcnUaK eS. V1"/WZM[n?ei%6Gx?ȣRQJ9r?}?1G֢i[# ( +C!_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%5="IGҬYؖfkt$RqN/ JùUt#\Qo'+qk]՝9V)4}G.F%70G?\j!?h_0 Ii-jfiӭl e8#4-ת[ĚmszRŴ}GoGpmXqnj6zqS9Ԛ]>_%u4:w}9u 2!pc$Q#ou #CsŤlPqjM[iw+f6IxHrҧ>"Ԅ7Q\Nl%J8=T,(k%+:7/6-˛fkKKpa6*.KX^:\!!w.ьؚ״>ɩ7n͸ٵv9sÞIm38cssн?kVӘ%`A=ooxe1`*&O}h: /-RdҮg3kē>xR{c{C"6ʟΒS6œ^wRɊhSuuw%:DwЛyeYH.EPrh"iGw#M~c>dZc)c@WSF;mDÇc1|Qh"e˦4Ze+{8$idrz[W)<>? mwl$w[xZXMKYJ%@`Fv|sK'闖koٿ:g=kYs2nm>VVT`}:?3ڬk8naY J̇ E={՚@E O(אk#V8ĩ'qqϫ U\%Ə^U^ãv;3潰i]Ě71v9,U]XYHy< .J#c}> -)4)s!dA_,_>c)SÒyn%g㌜67z6[_ɒ" ڮ,ͯ"xC"Xpa4T+Uy ioRn2`|qמ)>lr[hês>Z= ˍ:SY0)KaKdP+o#d G,6[;csxFw}P[8DnTnk \nkBiMy6PU=r*߳61{c8K^U|Gikuh X,e,<(S(ϨQOϨ>T4}.\sN:K$ ?3ZYygPak⨼Akyf@X31@8QG}Ec$E.r,6[|p'$V~yYK\^77R6 '5ygRoγm\R0Kmm6""烐852k~Q$wrH)PBOn?:67N!z]紽GÚLglT2qg}C} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu ?tfyg&jĩO }Xgd3Mnά9ڹ }*__oC ( *̆]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%]2ͧu?Uj6跩RLњu\њu\\coRAΥ7qBzy#:cC*P~`QN2Q`FԑЂMOE0)}>E&/[P^ϵF/[P^ϵF/[PkX$Gi`ay 8Ԝ՚((((((( C03 FG;A$q}>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^)|U~[p?X-UYngnHFE'p\'>ԟ>-t\O0}O-ٗT4NpK=M,ʦ@dȮrNմ}rBm巚/;gAPLlf6_ \hmũhV;$rq9C^#k[d@. Xw^mR/VmX 9K̒MR:Ym6'*ݕص-(Wjw7ho9L t]38k[yesY-}F+s'5sup%y{'խxPד2U_ }(o?_xVwp}E}Et.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pBşv?-woHǚ@;}.4fo}C3@sM\#О ,':/ J }MuPjx'Gt7c{q .zdiڂyWٮmc9T$2xM7wWیq~ןKm?tn8{m>o n:wQY ^ |W[$Ą*#`WÒ+j6|LiKc8|=(A]:TxdkxZuf!caZK7iu&hⷈ^dYqӦ ;xol@[x sPm4;K'c-#HW֦[漽df1c6N0y;knJrs.i_b]>I7  #hZ)D6&Q)qEZOM;ͩj+cO9j/.?ꐉ^ly,E i .ן%gDQXErRY| rq8&ݤZۥȵf7j&ݝ]J9wV:$6i/$E9|i֋mY,Yo%vW0 8=/Do3x+]Y\ib |gK1$.1;WV8Y꠱ iӁ t+[ki dm䁜%׾muqss&%>׆#@8_XT[0 ]Bdc_ AGsa>[7'$j[ 6m]Ew,Xp#? oܭx!փϖ+QI (b>f8<zj76Qiz̷t,^- rGM_ C,70$?gYDX%w. y(4Y]JK5e[O֚'~Hu+hI 7Aݵ299:n͌X8&[p @e15{Vӯc>M߽vj;H^;w3x)|K{kյxch0RU癋m'nricmg~Y7 kxFhc1xRQKMy#`r!}M>}{PҔ+$V^ݬ8Ki,mN_]1P;)C5ѳp1(6vzψtWщNQ2G_ۧݛ߶ycOc=;MyR{cg}i$HMk:å_P4KԎhP7b1DD|}i$jIw/oXl Tcלj \]yR#x i(QsMngoZˊ[ ]b0N)ϩWNծۈnhdW 8=5Zϴۼ~Vۑƫ5΂-MV)L(pr^'@n rm#) eu+(oa/S*lH=y5K=btֵ[hIa4jNmO>rʫdeLn(X@k{| ⛩nKIxb2\j,nl8䑏nx }'3[nѳkyTTrs!.9T K Xc97K sU@tvo~c2n8zwC߇nJK-\Lh1;'}]FݵiUYo(mh 0MoS\blu4}N/1g+EhI> d 6),@d-:^_FzdKVj9nkOMo!QC/P qY>Im5Kho<1nCݜ{S-;TBSDbE d!sT%iBB}Iy$mgbIsW  ?.x[EOթ_5Z'N<ӏ+iۻȷυFw4VVݦQ!.sP]j t{33\F~=z֦o ?.q}GՋ-JSa{owUk6ź=ܗI}mm5E$SΊ!lgz,q}GѾ|.?n J#ӃW}kJۉ5;$7 4QЯ?7@ ?.q}GԺitIR2ebS_ǥ%ƷZ]KNC%«IG|.?7υSjurgkpq#C2O,uM?SWk [C0L>]?m.u+9;uf\u"Voe-'0L@ ?.q}GՋ-NSG{ kC V@YZG,/,. [xH']?մ/]B;wD\gִ[ųlI\{?}\Qu IR`yaiR NO#OgZX,n/?rweuPwυF5=f ?6)-e^8He0bMWN,eK2ɢr q}GѾ|.?M=/VV̢B=9t|.?7υZTPnq>]iQ@?}\QuEf ?.q}G֕|.?7υZTP >(̅?cMCᎃW|G#my?xc= #((e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`WG<@'*F~j$\.8Eg|.87>?]hQ@ ?.υZPxQ._]Mil'2 3OjEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEOV5{To_׼ )|qE? ȹiڙZo-?UtNQb"S!sҞJ[ɯV<Ic#,$N=Q'{}yݥuiF &4:Z}Pr,ޟ)~Wwj>ҞMz)Y[GVBԍ͍84UicP"kngJcdsؓݠl'$t)}=C< cYm#ɪ#y .1uSѨJz5%H:ܚ)}=&Jz5iOF ~ҞGSѨj*Qj)}=9/o^O^>o_Ir3N9vJសs~:_ ? 9]5":+f_t_@՗",k\SA=5?j\X4֭?J@Eo!)_M<±/b}+g$`/ J[fԆ!h\>FUs0:[T> ckҩӵ;k$jQ6<2@z]㲼[F-r@#6Ӑx泛÷maq5a|㍂EltޓRM^K0 #r>@lch[^_C]_bѬ,̃x'psnʑAHXdw"OZ1c&s'H,H6=##SXh+xdpB)oUo<;wqc@'8 y_jzsy'[/N7V+^ѣ1" ڟ0+V_h6<3kI,lUѦPTYf[MjӮڄ: zIo~Wq?ѹ v_4^sDgoo\ 'TIfQ' BK-DQd}Ĝ }~wk 'Mx?1(m㑑_|K\iWm76tAzEϛT<;LE=rKH{R>^跗ivӹpAL&"x1sf-yl>-A',h[1䬄i9R@{',h[1䬄i9Rq]^Y?yn}‘--7\QZ\F'rBH 0HG֝k1ayq y%U`u', VLMfMF٭g1!ly}ֲ j:O$ZuKf!)po'9xVsux& {k馈N#@Jz1,@sYwZZ3ʁt[s4]SNӚYEvp̊vte` x"K9{Ⱦ 6Xʝ`p:J_~x ȹiکX}>p"".vs9\? o.!ӥkv]Ts Y>_+=e44ŵml GCK+UW)Ga?sך.kwod {q,ܞzUw[Cqp$rAovm!+:m3՜KM><[LHG $!Ts*κں)qM+ ONf5 {{Ԓș^D,kC4a 7Sިu 3ۛXzĂ~pHr(T] ]NUy ,rMWnTe6Kn& vNϮ)eMGP6k%ԩm83<==F9d-Iާ^=/tt&='T5י)O1A:`zu:baxpJ6=X6\!H%lcP^yҨ:.ޛq[ `eeٗƁQGjo{ ltqxG,/3bR"}9POj}eiز+\G&>΅5/ٮ[gGYB îN@X׮lKA $co43T[mbky-K ~jxLkL[ZȊH"r7(PkM֭O HkhzY^OV/""Xҧ # Pyzg/yӛjxNF]Jy$"| Am^ӵ[-Zo1Q8*QXW8֕;i&+*hEΝ1+yv 9B;%n:sM_}m.5VmyM7ܲ2Jw#f] sauxҭe;@ `xitymm }:hnaK{#τ)0 O[5Z+2=j $C*6H@Ջɍf ( Jd ֻS (Š(_YJ=?YJ=?硼DuYAr Vk|E1EuW_y/΀;/EOPY>*Սƭ6rF8'go.tk2*vsœoaSX&HRSq͔>`#'P5?ݸi?'P5?޸?@s5#"h`q~r-.#tf9 20O~Tuݨ =ڊ %}mE|E}E|_ iZ$xF7fT19|9%rzt+\ow{ipd_> 0ۀ'V%D7N,&؃j+ȳל?xfj+hffj+hffj+hffj+hffj+hffj+hffj+hfzOגҏ>3Y/> ȹiڶ~Xr[ W?)~PqsQCp^HWeo?l ZC0b'9 {gZmλ53b`JBfs#c_J>TtzRѭ.]E IpG^ՏgX.uD ͑1c}ҏVt'bԮ,Y͂|cT+ =Eo+.H] ?R}ҳMm6ćdCe SS񕞗wy 77Ƭ==\V( eob_J>V( eobu3'?W=??mK=?硼DuYAr Vk|E1EuW_y/΀;!:Ef];mYc}iyjѳ8ӭwEb;(;cG\w?5>"+& }w*ے3c ~y?k?T\_-mu[Y#ܥ؏{1]z?OpFi/ٮِ+Ivw4 Wk^jjrlH*v|޴m:4%+@}rG".a`cn% sypG3(QUG =_~,P"[.H7y= Wm-OO҃ϩ\xXB'-=nmk)/qGoRMmqӹ3{ ?#h$imHYrq[޵`3DdF@ːH=#Rf{! "zsCV[#N-:i+:mgYx89+>&/ӵ \NT ה|M_))&*t \/p]H*>nN:dqX7vg`$@ M{;NӭtkX-##BfnY7/UR5[+-L#gޠH-f {2Yq''^$am$Җ{ĴX}>3]F:\ܼ?]crQğ1t}܅$'Ku~M6R  pk/egJ`9Q1\ijڳV 9S־n9ڼt=oi<,_+|A <ۮmc1q+ռ="Ε^p*u#QsE%iTQEY!EPEPEPEPEPEPEPEPEPEPEPEPEPJ>R>3Y/> ȹiڠM3j?#0,#Pr;z.Z6oP/j͜DžgѢh-;ۼW}q6FSj~[p5hw3|=q3]_hK-j0*EΞ,KGIePNw:nVs-EL[{ JیZ>E_ÏiE&]Fjڊ}3kb@ F-yhh9]_hK-]ixyrhvR 11H#)Zj/,r$cwq>ZPZlbj^.-+I"$N9cx.H%[O5wLG8kK-iEקyj'nouasoqo%֞wP[ c5^MP'Vu1$1<|gʤutiE/_+_c#%%\}b+iH;+.o ksiFK/^I#0%B۞1߅uiE/u7^UJi s$O Ԏ&Uە@|x;wp+ˍ㸉c-)Wqٍt_iE/m-Z~Gm ͻ)mgM/^{m5\" ͸HlWmU>G_h`rS/}-U>G_hS/}-U>G_hS/}9o^O~ՍvC''d= #((e^{//BVk|E1EtY>)qj-H~Cҟe _7kV W_Zh'U[Z~U>/ ? <m,|$`mAs^}jmE.м2<ݏ{zO]MgwZyNc< s׌ׇk$DvqB!9$m$w'#T5Ueʠߺt=qE/nVZle1r <pFs/'^Ӭf-ZD c39 O,9sNcl3(ff)VX `HLu(禮.YTqnɎ5k9tX1dn\r&/^A}~LхlO'۰!FjĠCi<1;_,Oףyj[N~v8MyK*I ou.2.ֆ<(#dž#SꖯΨ[9AsVլi?pNv֮Z,y?ˏ(QP٭n\|?2Y\^.$olßjOMRXW ^ٝ@Zaȓr Wq 籪 a= -e).J)Jwu돭qT~Kcա*u,"֝;{;$S_U=Ϸ l#Fېd;zW?1X%O> st88fARU{Ra m'h.z>P ՖͨI"lA3$vISh wX\PG# Px&ωbC82 vLiK㏪=7.Z6ж}(fq7^:qo-?Vw[SFwhIDGDPN:Q>E⿍S_,/ݦϤN` GT2^eLj.6noq1p1uiNY~h&s9kO$$Q&xR{`O5-ϗߜ_c/Xnt4GF$#{-{X[;k;B.`4͞ U[%fsLv:ō}:Y&{W ~}31O_^_G\d;w :OPW{$Rm4i Ix>́ +5]|-P;1)̐/yTg8 u}%lP.BJm[5N#CӘd:4NC2 ST]֟stqk5ĿieʻyQ^xxhID#mݴ!qU{ }=u~׳V5LysC`Kۙ,ot\Hm9T %ŋZϴ`u+Vxe  1 ~C4?%mjS_j hѰc6^xahOE麌wX9'<*5O]_]s^. cAnO'RKۉ9`ےRBg98Jռ0v}8*d# מHۭ>vkIw-kx')Eo*Ul"%w3d8|M?έR ( ( ( ( (9}gF?* ZYJ?ֹo?_xVwP}E}Et.՚_z^{//A?S_)s`u5"~UէU[ 8GsI6-`Aq`H|}|b᣷V[p 9z90s.#ص6KOCVo{x'[6_&=cyxP\[,|̳G8H{Pfg"[ٷ3q+m.gO1|uu=ܷW2't[l Ǘ {YҿW׿x{E+lrTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEzo?Zm[DM`OEOLIn)wq 7|B[ nl#h#kNVGGh&纣w prZe&q⛻;[aqڅw |/vlP#h#kH6XZ*zjՃU?co֬UVVUn|pQ\''ZE+]\].DRR%Xܑ\unTo^汧̯s$G'Z,⹆żO@j73\Km)XW;+o~g%~_^^8_"OúZWu#״y ֍jq<ҬXЛyT@, "+~?خ?*@|M@_D1y250PAU֒5veX0=8''K\^T$&gG_ѭid[GAz.uG{hZ%ڸ0HikKx 6Jc:g `t=@K?WsؼCg"sӤ ,k՗a{MA=+l̪ %uzZ+Q]Jk! w45Ԗ(m[Guvr`q:zob9;<1y-:K*FYpI:y_@c5 Ws%Wh y$c}zbz!?d3g6]c洉܃dry[5A>]n_IyǖZ bh(đP4SrU WƩ㥪1EuA,wqR#`3mpE/I&\ m_3~7c߻s__~?خ#Etz~C[5KMSS`$O2ܠ!qӏ? k9Gwe_υ2xl7qYԀ9Ԟc}:<~tZÖv\Z70SNlVf%I4p,X_%222;dSb*=KbCGo΀/T<~ty$C´cE|RywEal7SRbO8?o΀9o^O~։oI' %Ck׊i~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@PFUE,|=e|-~J7l NX8cm%?pBOk85ʎz)sTϚiVo`KaCCq石YJ!\c'z՘t}R7o"'pP WQ(I #qMKo"M뙧Z^bNB[no8Ṕ+:%ܤI3Fy?ZwvO|7o!Rdm!zrn_exGmSX+}Gk{ YItlDHReOj]Va)tG @kk{DR d([{GP d(x+~[t9.'I2-*džV(d[,V68 dp vexGmT-c·  $[k2 BNTFyRKUڻ)bH%ġFU'8*Z{'i{iėi$w,#?:g`/rK17 Wآ֊_Q72@J>Tp "8;wwZTw[KFC @IuK U4;{nnO,1U8Aqˋ2]HK;У;Gj(o Zx継Tf%6`s¬7\;Ab8#ֻ)}G߂my%Ϳ٢7Crޠú.Ϋ -.r[,Hz=A{+Ac<2>«\w+3g1!֔:XKٟk4[TOV’[ΒKnaKrŒ*/Nzzn(m|Vr+BXygg9] A| <1$srhWݞ̲7wco-3HMdgfXpAJ,2U++%+{ĐIF$mȭ #9[MԵ=7i,mg[bgP(9qQk~Rw0.u`iڎ$wmT>`OVok"E,/j82ƒ>nߗZDځˉF)}N_oKmn5 i7zmSzr펵]>i6W_cJK,5vcPUW/lkPG Gj |)>Ɨtl}C)~dfsy7W9][CskH+FF1[>+4/3L#*oޯ8P+Z= L;UXmeġÌ$z5fQ!,:FGr)_9YIn!{o/liiP[3c8qT[SӴdSk7h9}۷##z[@ӝ. F5y`0cz#5 m_8Wd[ߠt2ukSJj7iQĻ"I~U9P^kGWVɧYLK}t}76$?.}i[HFA4R`F WMNBH;I :G Q@Vw|'t˿s媳,>Vm#o-+r2%Xp #-IA;,']Km:T(2`OTzAkk[=L*hw>q+ѵ}P\^hmgDTdH5GX0 ËqjT:/_׭6-OX,c1[v):橽[_ Kk[93k`K}>}DPE!F1Je.JkY)sZ謼1iqZ:Ia3nTUbJqZmei8[k_{G`:4XofVur߈.^豕8Ѓ ? _Iy%wr5//{Z,`ge2$ZҷixVXI&[ h'>?AӴˆO9g,+p (@wUolZȑKڬN"Lࠓ׾qT|G> ] vW #邐vq]s:w 4; 1)n]:K.mVA.8d19$sGo{&҉.VY̛SEB뎂{RKVY,nivw`p;3eHٮ$2# p햟iY  s$I>9M'^V(&MW1ccs^l5xFX3D* w95e#NHFXuڥ*K麥%lWϐ#r7 m;s5k6;RGq,*r]b|5ΓneE̎yG@XnsGaw2FwHرepvɑL5.#D aG⟯OO+guQV ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB$#V,K35O8[J%a hcFF.17s2O 0:9N.-?J=zE=@Y=h=j7֑JVHJ2:1zޫeofuD4i{C1\AqI,>R:b rrE$kf&tFBP?AIKEÔu IP_bƬ *iivDmu9tw7WےM"mI!=@*:=7 :ŖYHs)-K[ScE0*㓁MuJZ%tk]7-?=TOmjZvPOg9Xa\ 90{WO;f[?[~a>i%QEgY7G)*M 5ⷷ3 m-R22PQ1N>Z՞k[,vY&<=;{{[n-[fP O#i/j:RZM]%ҳ;T#9Wzd#05!!e,7vkOwki-,n&u ۔҉7ir$#+n\%dw~bgdZ·_PXM3\:lf9]FIXmYj[;{iewxy۟;,;E$ _WNgy5B{`[OJ}>;;PZŤmNY$jSz/wF-[zEA?3ZF.!XY*>W% 'W=ZU'+v:WN6>gs=s=>dW??&[ϕ<c~Oc~OD'֏|_Ihrlnɍp1 OZҺ0 Dž'.sIY>'MC4Q#rSںJ-dpM$fW) MlTJH۸drFך5]`QֺADxH]rgZ5 Ţ;ˈOfl`w9=)UO[h6%o.-> VF,p͓qXvw-sإ,,>F sBե\5;{mJMus@ RX[6qڹx$V*W88@=Z`6f)tOSxr9u+ ڄSu wo<7 H:_= ]@o >#3LG SƶMwu 2hS0n2z֟&yuL{+ LM#Sxucu+M*^D.v$Ok6) NI$KCua2nW ,zex[Av%+$;It*4N,nQhe3I"''GZ_^uy$-T L'XnYc_9L9>橩$Պ"iWW Ar2?SpQ^mejlڸ4{o^ 28{q=Η^j3O\ܸʯ"`OJoMmt3:Ѣ׮-W84&YuFlJr|!tt/8) zStco!q JרsS'#3H#1=5թkY|J.~@: ig@- Q3psi-m?oK Wv"KϬZiih;Fg-=F*=Ƥeo# Еޕh {MxNSK͸]*3 ]+_#IT5jm'RU? u?硼Dvb_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%Y0DgYheU*o3EIXw^!Hc>[B\pqzwEu-!nWOǩVrrs=dc)׺NX8@qw=c)?1w=c)?F.'F.'Z4IQIUJ =۳s:џռ#??|њ@f[r$`b1${Umo;Ͷxn0$3DH)>&Am $`*Y࿶v"{\gSA4Epȧ`sN0Y( ?(QϧV oizzt;RH`Eg=#FZvqqbm-/Afl1,Vyh$-;E+1Xy #SYXdF+ [[X`\ |^Q-Ǚ1n1WoiּMݯ֒k 6'I-%K HKhk6a%?xP0? +ߗx=1TYiZF#aach0)a@'CC6_m%];KKyW2Iĥ]V U/4kvNN-Y0 `9Q@lt is*zjՃU?co֬UVVUnBS)*R/ JG$"EY1;~=r0:yN.m?f<:DO3­D ^[7l\fkkL7vE~T3T{-JimHh7$sftB+QQKY qiIezc%1 X{+(nڌc ANI$[]ֆ%>{K{6ȄÒϽQ+ŧ32H납擑Ԝgi[j68ǖlԿzoؾiL<ٟ] 9q{$ֺzt[k.dl#H|Sn jZծc-lGV3Fܼ"{UkXq#(1ޭ۵𳘔63M?/s4KlR T珘Ό_[-ʉncʃ[7O$tVrBEX(bUO| 4Mt߼@zY,Vmxilgw/Nk-v?-궫ǪOiqYK*0sHHhnL{+01"29rp`;Uo^]0yP@u +yPIrhDlowlmApR6i#HsZ=۹7bc~_z[1|COjzat >Φ4bB1;G#$ ֹԵxtőԮRƫg,~`:_jlW7ʠ;Ā1t&ⱋSиx."YbC9|\``x^:,[dr!w֭]k:j";#Mϰ9 4gs|n% Zy q fyyn.T%vY A;]yמTXlww<Cj,iy',X 08s[7 |{VQC0>;zdLVC#`9N~_V"Եm Iu;\p7(R;xvtχvҩaol2|p*Nm[h|<.< *y ME]$+Kj#1)e9qZW1ukk?9t$HEp ẁ;T5JC4A U!$Gu I A5<)[y5-FH*] 8Ii׶Mu3\brb[VY՞SdV~F.7n!H /rAYk,QƂM6;;ČqKw{keEƱ,R e2/|;ms4Assc,0 1t`}*z]/&VtP}-]^'l嶕\0Nfo淕W;^[wmVC#`l5rk0Ed&f}s+裰_e(_#=E3FvI_Lu5noHT٦(ҹ#cI[7֑\YYc6`ߚϿW˧{wnl4%9;vR3nW9uX4QI%> nX$1rGZ~Iy| @Wh N:;wpKdmnFͤp?]44?8.<6wcU]QE!Q@Q@Q@r)YR/V]/+K圭o:2{څaў}}lj>o gۏ>x={u[FS%;o"O"O:{+m'7-C98@I@sR^?.c]>WɒхGʖv r9Q$($(Z4ŷce{Zl# >c#cjԑnhnw,2zc~DEDE @-(1]v~DEDEjHk`ۼ#|[>"'gbaIQIQ_m&+iź@B$ OJkte]-',V"sWwyw_JP$h_P3e~\)HT_bmGO(%b0`eu Cg#8W$($*ܕ_N)ۅѬ໊hc{C#QiKw$ |$ɮȓȓ}8 06yf~lbGn$xs{yڽȓȓ3CfY{q*]-o Q^̷ BRLX3^IU;u3ykMYssۚu@{qGI "In2c2v0g5xP~chGOfT|аux'j/"O"O/l,}oY+k4fP$4!"TMb1p;;e =g(OO`SXDPO-QEQEQEQEQEQEQEPNOJ*)@i`FVR}{}>o=\:Q(Us4f){}>o=\ jb[xW3Fhڭ_أV/Uњ(Us4f++d`zr)Y5X>a>ds<}ɩo-B/5G͗4VVݦQ!.sP]j t{33\F~=zy\UΏu&u4_,ǃ dvxխsM|Xy+NM].mv]^V/  2 4=?륁kju#$t9$x+3UEfk<2X lIu{ 0y[v {?$Rf*i݂F|z_ Ti6Vvl[C 6q۴- G<߅qu]ʶ:3@0#85d]F-[GN, ٦Y+1as ;- yfPerzUSiK`/Χf,3Oqcy{i[%M:[ƲI2 qұCe=zȟZ{yf!#Am铎ON5]9 _ڵ7e1qT4]~-kR!x&x98rn<8+>$D+`u3]*kz hZjHo50P(9慭ޗu+ 5QmU3ʨ j;kJ5ANXzk>u `G2؈ln%t8u k[c{yݎԺ__?3t>$$VLdU;=JH6 C9#WiCL{ۘ[IKT j=1ed+;bMg2Tk/$V+QE!Q@Q@Q@Q@Q@gm'RU? ?W࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%]VEI\֯8@4>cnCbwQLSO%S$OeioOg9֍֪4o4kxiU $ [ 2QCiz fӯ㕣k"|*Sg͌xzU]Bxn[F Zܳaw͵<-~t9!c@4_;qvF-KIR֋ l 67dm֍'V<R707  ( P{6m^Iogk 0[{_{G`:l" Vry.z_ZSFyi]xYhբٖ]& ,r48 C1fQ3{SHBjݝ#E Y3 sHIkb Y5kKp$9d_zh"NO&̸{iIP7PwH>)$Auiw-2H9Oܜd.yӢz}YCy40#a8%@`p}Y ;q(_07cH`g5zö$"y3 )g1_-L{2 >+5 tpYwn'ezcZ]FOZ¶40rq:ömm} a噰x?D~P{[t_:Kh|~䂤K[d?xi %ۼ&۱&̫<76\):9`\oöcshd˸[!T5|;W[Gv]P0]~\߮3څ X<"??gy^v88IQqoy6(]`u')QH((jrqqg]zƱ]Iiߛ$BvUT=zT"v1-WR\,Qp2`Zo$Bf)a} 6~M?Bċ,s"BTAW:H tjm,q#cn2[Y4ڼp+R+FXyֶK˖)$ sQ]xvKL1< #p7E ;5~E~ɨ']J[j.'rB/Mf_KkQ%wf0#(m@6 z].;kk/+)ܻdr~ zvZۤ[F;$$gn?7Z7ZѼFUw7zѼz],=s3\یDYju.v3VPR$G$'V;Ѹxj>Ҟ\%!MNF~F(z)|m؜_\Ukۨǝ?Ə0:?Qju?W2 Dx7\ʰi'YmŔңGMqp\g9)}=VK-D\#ӵRź#%,NB}|@/SѨJz5s%gӼ=5Z0 hmr [SVofbT}tn0ē_@SѨJz5rm,"i  ׂIWqfOiqKM,lcҖ N`(3PCj>ҞU+_&+0%pgw>٠)}=5:-.xr}n/>mrKUn[k#vFp.0rOhJz5iOF+M{N!YJ,FJGBGP\xNɎ,\#[;X$2W}=W8b}qOT"~\X5]?jUniUVH%?pB+ O\"Ф=(ۑc$~5{?]\)}~->{?]])}~->{?]])}~->{?]])}~-_"~-EU_=fd(Dڠr{uTQ@Q@Q@Q@Q@ב#۽wJuQEQEQEz(Qѷ#HjZ({?]'P/ůGP/ůGP/ůGP/ůGP/ůGP"WX:R$:ˇrF:"66մ=yk*+'bݞH~G(EA%sȈ5 .qiS~s_tSNXRE*HGs޻Q_Jct[:6aUm =OLUҮ&\Ix9*$6Ⴇt_Q_Jm 4IgK% h@#k8KrO_ƥ-k*Sh|ucJ9<yq_J>KưԞQmLR?46DP1c#285-V\a% zҠHI۝ČqץңM8c{}=IR}h[-u<Z6]_E^$Gc4Ia8ns oZ:6xZG(ZxJ/ҕMEl\E"cϡȋ—[$*lm'LPiXucuD/eom} KbŴ 8as*@O<f룭Ra{il$ZP0=q^_J>TJ8XaHaQBNp>ҏRЭEY/eo UQ_JEY/eo UQ_JEY/eo UQ_J㵟 7d7Սz?/p ;%W?\7莼WO+gsQWA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U_Z~Y4BS)+?@O,ԡGnRNAQZ0N%-".a,MnPLjuE }5*/E;w w {]rI'WxfGi^8u5ׇ,?<'oh]8{s[kl>4GP:֗W(RtYU*xU.F570G?\jݬmo.em(@PY|w>T~\ܐ}Me剃>._O24F]n'[[c/x`mOjl" 9.x'Qdlt[qr;&Mf̦.0?\Sm8Yfږ54)dVNRikoʃW,vvf9<0msohzj#y,E[wgr){[cjo'(i::|vQuv"WU6ɻ;zU;kwJR–3I,,1f ;w>²_WmP֗lFĴ4+UB60g޵ +H5}EbEeI$8tť کbfE1.{v9f[U XY-V 3}0WYہ},O2c!B5ݡ@3̿UmԵaw>ߠy57*iv&8\HH߷ 1-y`nm[fz~I<[Vhמ9WFCnHT5-(VW7a#)VR0s֖Z=v3Sծveqʑ0%K֥uk-Kxohi#WV%wg3ڮhQVVKIQhTmۚһ͝ܗRc{D A^=|4֛[ׯZN.^7RO$۩4At8:\"Xo_ Y9ܛr\ VS@:-vMSPU3Gv0_`fMy̶=JTn8ݽjv5=:[]E-$!YQU$9=/vQ|#`(V9EdK>k O;u\\4?1u*Zƪڍ,/M/lJf9#+?GPG~HH 6G=;>pﱁ0U:)ֺMYndipqG]ڙ͆[j7֍E6/NxoB7mZC!#qo*8/i&Fѝ `d_IN6q}w2̥v($*z)=\|?1?"MZ+`-፩SAw&sPϨ.,]uE.VC5#(8䏼za{YS"Kd(r1~CT–o3Zh{1 nM8=ח Oݢ)QEU-nL q,>}p.%}G5v\ޅA2ycaԨmZ0G&@9Hޛ?nuٮfR7CI{ jk}E=.Zwyi8lҦ-{x5jlfD{wnیfCkWiwewn(m0H#:{?Ζv Xl[حŗh, ݹ]cGMu;JeHioa0:]q}o-}6-Jŝ,큷9ImbaLܴP2n@!Rm2 k7q(T8QOsl^hZ%3@mG=~_6jMV}[V_$.r+O+.#(L(L(yp#rxv\2 -^i!u d;TH04=cMY7.fHeeR{5\$0f!e;\J=[T\F0'A~DK]>,ǝBf@8]ڋl.LncfiBH|A&oD-,YL(\⋻+IaEŮ2++]{zDf{c>"cpp8K-iE^oR{[5TrRI]?qQM8")RG48񎤓F1G_o_hK-`i麍$TtqCU]֟stqk5Ŀiav(K-iEwOng;qs[":G-`se厳b+[KKN8"-N/}%KMOMK"[,ͳO}`3IG, /3FH9n>mY]$ocK-iE?Q5%'hJC:H_29)ώmBcY3#8ː>cK-iEjr_kiQl/$;$*rǴ^zwkkO99%ն-=K-iE^ėq\^GiMۋI]P9D$ }#MK-n{+cr~/},O]JKv?w*[;J<+힋̦عf۹1'`;﴿Zd}4}&s~p m\d+խ侊]?2!=[GA 8ֺy+T#"-}4PiE/ 7_hK-CE3PNR M?]5x\&Uo((]5":+f_t_@՗",k\SA=QEQEU?N.O@jӠ((((((((((((((((((((($O,zg%̒鞜u溹>w4uL:X'56M&s<֞H,Im̢Lo,mÜ.r>`0zyw4yw4Oaiz=[ |y $I5a+tEŅt0%KJm ]o  E?6i73AbKneg' WWE^PXn- ŊknxcҺo"?"?8#w m a8 O Isa%֣߼M-jAUTȏ2[ڥlurAMޫ?vmvyJҲLKc8+SȏȏhDMDMRw4-c"o`Z*SGS@wq\W3ῼ?κN$].򛿵rtA˯f_t_^uמ>bb,-G1OTϵWo vFMQShVe9 Q}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUME:% PXݘ5i)4ME.N$f0r=U~謭zQtx ?f[E 6q'#=ת3.:Zk1[xwꏱ6vsiԚ]NJnmj1 =Z:{\ޭ VP L1H@'My{+?2[4Y~S6㎃9 m#S[5ahEwjŗX+ް~ 3Wن vrUbMj]T4|nTj`q,{[?a^,W4ZS v6\{Q05/5 F1k^r]J Wmo+iICYLaSwsV:*i#/>֤n ).=j>n.PQ[J. q [|y_U ߀&tUl Fvxϯjx\$O6BF 6>=CEtc>mpHB@U{ YݦK8*Ox\.F]--fKw0"*3 vybɹޤPH+Ls] /'{/nLyzgajK鰜riu?[}|tGnvِ~n$`cGqEΞu ]~۸n ?ڭ˿ X^TLӑ~n Si+n<'d%;TtN]Gk^x~ZN)Z6 <5ƝrNn"YmF2ObVxvt1-dIC9tSX[׉,MuB(A\>CA˯f_t_^uמ>boO)Š(((((((((((((((((((((((( -@c\,~cMzڬxH$l6V[.oΣKĒi!ZX"JdddvȮ*ZߢAgvЋ%J#!n=F:qNkF<$R+(98jo?Ygl紛B7M^[GqT[cM֟Mywqo yRq~W/3?_Oe:silWۜz85`^ǩma@`B')'n;T [[xn.(2>2p9>'oι}oSo&I4pI8]̙`AYާG?n,CzTqpySsn$nn ]Goιu['Q7M<^W@t#"TTBxӍ"rA#iקoΏ1ߝp:<:m:{DEtU )Q|ɧ,nq`%NO懧BNקǘoΑf-k7ܥwWΆTXT:f=Y.;{eSa`Ivhz_Zu?\ci^jK_%SeMBW9=9:vŧƦn[y-^P(T3N/;SG~f=o1ߝq^#Ԇ ^i. ,m=;]45).KtHL@|xx_ח^gjee&@Rek.u8ߣܤR(3Q_Y].Uw8ۅp@е?os?.[jY5䮐lnfp0q㡤TյkP}=[I[ >\p'LRo _woΏ1ߝq%VyZ# «|FHsR֡jWL7]YUf߰yzo@ZuS%&[! OiA@# rz֟ifL6HB8;O sC:1ߝG-@c\,~cMzڱK wlE& m 8'5ګMeOdcyl,g+#@֝Q_KoΏ1ߝpji{Lگ~aM?6sԗZ-֯C-aBD2Y-x#%6d^׾D`̉G#ß}?ΫikwD#wj*χ>$Ojߏw0}E}E1 Vk|E1EuW_y/΀:֒AC4?fs9#j^*e?X<,$ p?!/[y=a*M?t"3>ZC^*e?+7<+K}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_ufI{nsцG{Z+7-c>RSTZwR&̻QUHa$|7qӾ5Y}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC\Q\fp ánn}Mh?ޛNgncZUJ|mQ :1Ԓx*I|3UwwDOWvtb>5թ_vu/0DŽvPMqPrwg'zd^ ^XwIDAf=I;5(7PzoGթ_kw_r#E!"O9[w ֬YnmJ᯷ 2M7?)>4}MiƄ"ɞ*&kdw1m@J w@epP?30ߎ=1S}Mh?ޛ9M4 #ogI sk? iz{J$^I3K$gpxb>4c;b+؝D1ۼ?gòvp19lTXXlMOeUCbb;BҌ6W##펙f$zf4ص ͟4 c0ILV~4}MhOO𾕥gQYbuC{ 'Mђ7Pn+3ʡbpq[?b>4+ Դk=^`Fċ AR<6#Cm9&e2ݙ$V~4}Mi c3NIz#:KqNCFM=Evep<_T+CPzoGءƁ7Daќ9OA|Zƻ}$~9ی;PzoGءƁC[ʇo#1|v)מ}ޏe}siss 5 czӾ4}MiV*3 [aj+ɼ3 srtӥRh]t6:nP@l{V>4}Mi ?YۤO6wןzGxcKէv3G3Y?drx5oPzoGءƀ>kqu @^e gK(cp.TqbrMZ?ޛ(7}n+t ok5Ag2.vsJi}] y j}+nn*ksPzoGءƕI{++{! $~Iʑp 3X^uԭ!` +0[ß}?΁pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5ޟdg+9m4lb6횣i` ̷w$I,_23`qJ_[+m@t#h$q> f״~,1`s횱{k[s,Q('>IϫXj{o Wlm 4çnuΕ+( #$D v.}K˯e=ߞ  W=>R2*}aN[r4m\05i5]#[X8JM9%nzqRi*RmY~$W0Pxڲi&tȷtI^ lmnij~yݜ/J)u+"lEŭ18]0=M;kygc}}h7,V%*I~U^on:: dMkzke cbGX*fgkEynaҹ}ݜto21@ j汧]xhC\AѢ"-ȣocmf;JkK{KH\%U+'$bO>.֚ MڒezNV,4:c7I 6?K[y;Z+tۼxs{yUc#linssO(4Ozvz%a4OKr2&Y}ʽ=+y)db#1=QIju!̊W]=S"Y>W/6$Zyc.KFu?( [5lgIǠH {a.Y'@}.oY\d| ' MumijEEOq?*v/밯Q4uFDwcM?Wc{D@3*VoSPΟ:btUI#@?dލ@IF:C T(?ь E%~ y_3kP& <HB3\"Eg;xmwiϥȰ3g8548/g aHIPwH9$rh~l?ku7cX@ Y3[_eC20p@ poS;PgӠ mq <vO.=ux,k; jmJΓOA(\ ²N3Nn&jvNn0ۀ@pɡ+:nHȎ59,z\>amem[Dz]ۉf|~U[u;Kehxi9 0ЊK[[Rԣw`xf#iK6YjwDhr.W ޱd흈Is "m6s?0=mfͮCVvlYuhBvr0O^Š€͌dHFPO.1  ˸G?\o\#-)5c6j t!ͮ!gvnPt_KD1[^1ZE p㜃s֍ ; ]@\Rb[-s}_gyEq#tJ8yD5+ #g[K/[rO(Ɍ#YblgN34;}+ŷV1,gCpH_CfU-&Ta_aW厙/tnۿ1"U#r7qjeek8ڻrۻ[֏۱ H<~CoKuu{?AgwWv^ :1R5=""ƊUFyQ@Š((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@M<ȝnn^{כ?o(7Pmei|/fXh.b *=xp=ͳD3[3c÷rp#;7Q X=oL2M^pG??hך?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckUu\\ܼj6P[Wۣ'#6@{G,mc€=6IF cs{?!RW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7Pou\\ܼj6P[Wۣ'DL0d X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*eѮe]{S3<38ck?o(TmP  c'57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ckXc{qm(kꭟu[LƠ:x>࢝Š)2*՘Ѥ 4$Tj2~j<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*Q_J<nCHŠٶVڜE-nip2-8.7.1/doc/html/figs/snap8.jpg0000644000175000017500000007221013414613100013507 00000000000000JFIFExifII*JR(iZ)( )( 02100100/C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222/" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?qQ{LT|kGUQ%̭%nԟaEvozB::XLG5&Z?&F? ?c1'/r߸.1xQ| A9Mp>я+Lu ~h^?&7h_<cN_G&:q4\cF? {r߸?1׿%/} 1xW?Q A)Eo(я¾y^E} 1xW_k-{R\cF? -wReJ_?"/h_=eJ_?"L K|GQp>я+L K|GQ A).п1xQ| A)?2%7EF? ?c𯞿2%7G&Z#(BhG&Z#(]E_(я¾z\Ek} 1xW_k-s3\cF? -s3eFo/"'h_=eFo/"L|EQp>я+L|Q A.П1xQ| A?2?#7EF? ?c2?#7G&Zgb(BhG&Zgb([_EO(я¾{[_Ek} 1xWk-o31\?cF? -o31eF/"'h_=eF/"L|Qp>я+L|Q A.П1xQ| A?2?#7EF? ?c2?#7G&Zfb(BhG&Zf"(\_EO(я¾{\_Ek} 1xW_k-s3\cF? -sSeJo?"/h_=eJo?"L M|GQp>я+L M|GQ A).п1xQ| A)?2%7EF? ?c𯞿2%7G&Z#(BhG&Z#(]E_(я¾z]Ek} 1xW_k-{R\cF? {RcJ_?"7h_<cJ_G&:q\cF? {R߸?1׿'/} 1xW? A9Mo(я¾y^?&=w4\cF? =w4gRO?&?h_<gROG&z}5 .x_I~kKKY]#]L.ά@E \5>4N;hG"Sȭ9&xĻ-:}+~ L-`rQnu!W/ey;^UQQ N(犱4餸<|/(#`,W!ı#Dr9vεMjLӵyȌ)s4><-6>զK39KEԧTr!B }*F\3=vI{7gɫ_Ӵu[KǟJkfP݇N@D^(ӵ [Mz5齌ٲV<;wEO'tj!9YHUO&m?Lt.&b\ ,{*)ck}sI N$H, FS>wu׶/`) DޓGO#VƭMÖZѼ_oe9f )^2? jtTFy.1FlpGqkLumI&,6@Lz{⠲մ=7 {c6oo2y>n cicA+ E~MFx8{-+I]JGEf7fl$DmU9\KM_Zиa r>կqG_UT1Kb6mn dr6ĶwQ-[YN6΍6:=KY?W.gkzqj };\2|0;֯ԵU;EW` i_ |3}kv; A?@Ls֝WQ줺K9 :O4 z$R]VIivFPvC0O𫺗4ciyΩ*r, O$Ċ>mlev2C[D3ğd^MoŤsIo4fn3ۯr5ֿf{_'WYҵ]$=R-O!OSYzw|&T}j\jr{w0\gi4=i9Dhێ1@5=2KkqnҬD gL ֡q6mn[TF  2wq᚞O \_[Og{r}o1A ۵^O΁5Ң32 t8EgX hᕮ-53{`#/P3fxbSOk}m,.t !Uʷk ۧuhYmς 1㿭H#ЭgmZé`$1#?3)fLIu&Qiװ-գM7瞾:2ƫ ej>{a9%>Fw_fd;|䳛_3`ք1/ci}e,6Ig-B1$w:z+[.v\|=ii o,(895x@.-ضtgR.>},Mxo#ٓx;psi$..ӼU}iiAe3X5h0F1R&7 (Y{#{+Зu-n.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@Z]_]1",oAk-1͌!}B>iעgp'Ў֟dAnr"~4ϟN17ʹ {[qCqia$#׵aI|_QK|ԎshEtIHgkhxzPMV2A0ϖ;3t:~V5O<yWr!=7w:6ۖ1{񭸯aԡTkqUq%([nS9J]/}֞t"ֹտ_mc%J3L3d9?NyouVR 8STs< tNdHPWxUiPV+L[K}+!_Z[K}+!eu\uY)B<U^uIR6<5.p4Q@eWhrKkS?uGPZ{-[G0E]͹pTgf `z*af7RV%}ckny9i-fuY]6{.KF.=~ }@uާg"`$>0?ա%CwCafG'Xk:uztsј`crwuڧѥ+9˂q|9}(;uhlo.ak{Kd̩ `~4kr YHQeן r8<847RXVnHW*BF~@ եeI{^Zsr 63n޵ޑ{g{BeU *8?@RF˛Y`٦Hv .3j7\K;|g&!Fw)dlWvq=#zO+mwυw f+u%ZO3!1!ぁy[uio{4W1_rhcw0ٙl,0t⇠[Vbu  m;HcX UZ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(ۨ )P/)Pf^~TtPIE{W+ԭՊ߇ bJXox7?:Wk^w9cI.;(`qQG`]\7 N&$Ip,FI ܤ (’/i?O7G)/du-_cZ}ͳ[wiϣ-fI R2X"i`;$O\fR^%'%_nu0NO<ֺVo oQpsg/{%_nR^%'%FM/ZUKEe]\)SkWLwP9+V)/dt’/i?O7JC9_*j0mry:"R^%'%_n8·XJmw8T's`5x#=r[[=>g$"?Ix'IwjQǢOd4ub4wxbŃU *='\mY^/X3od@ "Ix'I}@LkX\ŭ6%CXȨzW)/dt’/i?O7I+g/an;8[)K񑸌[j`Ҿm<.]"20\ewqҴ?Ix'I`Z^w3!領]:Kޙ,S+;s׿/ltkf'I#1#Y P3%_nR^%'0W.$ub-9+|?gxJ..vp&q?ƺ>)IĈr~F2 XMKZ! FU \i3kBCmZgXDq\" WW KĿ?K?ObL3]1^(Z+V%tjcDմ[l3,8Rfv ǧsZ_K?O KĿ? \i̴-3÷ ٥YB y*?kԥT6A$Ѯ1$?*i~kh-t0|w|yIx'y?|Ekk5e"Fv , UkeWzjpx$sڕzy_K?O KĿ?Q'^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?OAA6 +ob2 [Wh\%K) =IV)տԷҼYu#n+_-[i;-ӂ^op4t$,XDp,8z-36-< aqH4oYDY)'Y (RMh-tXrBXYl$kKr"GZ,.SFkMkaq/89'iS<)~UJ1 8v"77^o;9,o#hKH5[r[ ꓫ~ +vCJ4D* 1$ԞC˦n],@[;0'lq[Uh7VkuqkumG4r۵ G0[57H  ;O95JUѮ|Wwu=H"ʪ22{[xB9s^ո2,s+!ԙy&u@ Wj`Ÿן?JnWSkWii푑HXs޺qֱcKI{ww$kLm#U@[%nտdr:kxZT&4ep0bR߆暾8 Sv5Hv{f\u܁ƷDHu;{ۨ}xRHti7S]K!sw'>dwhO=-Zz.7Yϝ!M쩆iש閷ѩTeU=@`?Z|-k] _#KiVu RGR+fcP$QDQ01v9˩[m>-ss 0u`qVZ1:P[[[}4QZ]2 cM上P2ѶH  .6^_ܵ\ya)j>~'GSVӮoU'&:nRPx#w>7mJɶY$B6Č3޵j7Vw\_l"l%6 M?+aiwkqot% rO|sғ Z:W5WѿŪZ4LK1UmMMݬIGb ݂H_Az"-!IubtZA#RN98+7gYӢPӬoZV&W ?gzsi'^_?"IJX5Α·VnR%%@rHWWXP/u_leYt)dحEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPԿ[Կ[or]L},d:o->MZCu J8+u@giq X^M,&X[dVq?P).4=:kim!iづr 1@Ǯ\=],ڄvM.}6;GUcn*xx[O,`:_`ûI~tϳy1w2*ŗ$[6=_JfoS3]-6$_ԵHuy孄ݖhԆ$4o5hRk_,v[D\9cc(ZmWv ( ( ( ( ( ( ( ( ( ( ()ki?Xvlki?XvsG/ɓ77jv.vm%K$"t#j]}>}mjvo*|< g޹3iutڕkhaIFH Fy銽w`gvAa0YJeQ˦93U?jϬv֑]ϩYm7Uu+;EٱieUCbq\a<>+#}>. o n@`G v梋MM1;rƛj.$扜XƋaxt@t&SGCu%}œnBYc&i8eԓ\-K e-I$PBWGM-{(c87@=n_[Ԭ58K kSh%Y>VC9f}=Svb3Nڻj&{n/Cy&O=Z@q^gVǣ^[ê'ՑV1#+9+(pz;jP'q#gu֘HxAʺm:i`So?84-%ͽ =A rJU~Y]]SIJ]mB 8eVT|Um+K;;%&BAj.[úYZMO4v+`GjNe]B95Aͽ$zjvm%)4} B;->E uf6*$c *mp|[{;NM0![`u@Dq}*4ȍSg]k[j6Guv_"/͂j6x3uL-e-bJٗ̾ͼFߞszb\XkZ_IfRqP@q.` P3kVL6Q[ڭǑhE"11#Ft븨lr((((((((((((((((((((((((}ՊlaOmmP~jwZzQ_:.m|fӭy4 PvONz~4mR=kGbF'M^Jm;Afݹ'ִi_@AER((((((( KA5mVƱ KA5mW;::Er/mdg{XJnj8a0H)twbLD~p#=hZQ^sH#SI]ž SNBk' q{sr'-nϔ$b@p8qBUyigd!\xoI[mRt"0T6+O1ߕ {]Ewk{Ė̛S`²Rz{еv=&+io-aMհѹ&U ?)Nz@MV<4)9v)lZ+y9)=>båKC[[iA=uK~`ή|;$k֛VVKFehݔMz)e<+4)5uHnea,R -$ $3'ҏ k{uk{eHc9vF jh(((((((((( KA5mVƱ KA5mW;::k w%uUXHp~Sj/ˣ )ibi$ YFH#qK] kl\tL.}<+&ߦG:m\+(NY*E,V6фs"F#  @\" aS@Q@PCn.^}.Y߇љEAR@Csgm{ ,:5^O,`$pFs1PM%brI,O&Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@:}ImՊaOkmP~D% º-[K}+fUKJUw~r)^9P+xbɭe2l_ܹzK X>p|H̎N8#ۢ.<+:^$kZ{ІA$S`T'·7Z^+t[ˈqnCj#&pY0%zl-RU 3ס:Xi S݌BTM?\օPEPEPEPEPEPEPEPEPEPEP-c@'k.6c@'k.6wu4uW%2ӯfbsxmU$fwK0*n0 ԾX4ْX67׎\T PkVcŠ((((((((((((((((((((((((((((((((( FGЍvqV0?'kV(?VRJ..,bYH.qqFտԷҹ}\?a@WJT_Gq}ɪ?k&OI!HWM]Z=ŽE <֎]sXtжK0J/Z//g習;b1o Yg >qu]ťͺ473*K9$`U 躅ܗWed"W,1AM=UVmq/cnܞˠij˪4 /PdIc{Kmem"ͷ]7#9?xZKSF((((((((((( Z/O??]m[/O??]m\h_KgKEWAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEpV0?'kV+Q?#]@W3km|A}-ĩb]FKO ~5j[^{>uAYY'Dd cxZ.`Is41QdRISolqҚ_3"i)倁*oGr)ld8W+[?u)ܲ+ 7 k5-E owr|8^8-m\oآnIHM;_9A&tx]%uQEQEQEQEQEQEQEQEQEQEKX%{I? cX%{I? z?k~Lh9((((((((((((((((((((((((((((((((( FCЍvqV0'kV(?VRJ#-pمt:W'j6NL$*#"=ȠD巂v9 O223yX%D7с =Aj;m:K1C(@\CиG"VU.tM&nn)e:`xHnM3"'}T8hkZEML $`(Yt>;٬mxT}_/ /t]sq]16J6/'htbR%ѣYHYZRvMwW=o(k¾2CJ,v迩=ɨ&t$&r]"RV0*ض@Z:Rh ^9!`v+FeHG&7.{3-sub^uK/Hce&v۲d~];Sխ;s}5f-ח3!N_57ÖMK4JGBOsUFGDRU$< 6hL˱u͒^G.k*C.$QF9뎵ui6]IfTWpkRAC{Bܽ$!B'olqTa J=Z sN&>\prٝp/M<^cmj֕my_hþu_4ry+kTm/֗ 6%Op4qA]%uu}&QmFkhițGd} ?$ JZC ( ( ( ( ( ( ( ( ( ( 7֫UVo@(((((((((((((((((((((((((((((((((b?OimWk#_2FKob3o-{2WCoqfs^j֖_m m3ae 388J? xW  NF@XP /nO.L-1rI"`0N?Pc6:-L!U՟ ˻k DGr . OV۟x֣ykyF'6d"Xb:柨Zկu k/8&oyBTS2,!zunZ?_Bvg;yZ}pfnVIJYS*9muGWѤL&Upks}jom-qqm{Z~)qR2E9F"5  ,sRxBBX+s}j@v+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}svnZ {@^)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEŨFKob_imP~xx^CWor: ƻy\un2bWkR[} ZGp1}$w~uo /pY!k˒>f$r@= aKoZ\ijOg}c)<bI'))[YIhc{+)P^|/,MhDx22;? 1 -lKqot!GN:us:e|C. $-hʖ; ['rut_QuDM7R67T;@nuC67T;@nuC67T;@nuC67T;@nuC67T;@n1*ns?΀4袊b ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8;_imWk#_/-ՊտԷҹ ۭψoQ! o-?SﬥX!  WOos€;h`y0c. 3iQCW--ɸC";8'k cy9kBM6]~hR/mGг:6 Ԍמ*{ i~T tՕb.>n91BQ{Wԯ-K :FqG'v7QEQEQEQEQEQEQEQEQEQEVoVZ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEŨ:-Պb?vg[\?e0VRJ..,bYH.qq^[xL+ |%*/>E@Qmlln5<H̋Ky(ƴjXq,P11`dеv$JS=7-dVym'J5Cr=)-ZCxcI^TX=\:J{ {A Ə1o0>2x0z]A/mᓸw8}/mmo9XH]VSAAWk{jZ]ipI$PF+>F`T(w+PU3n `Tՙ)Z(Š(((((((UkP( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8Ko]\ez|X [K}+f[\υ!QUw.>}T55d|ϵ\omXH[ϻbqNOnn3дۑ~&YQrm6mC KZI䐮rs^\HP(<)9s'm\ľ^۶N7ʽB^_p~`A-lI,c4.qlPA b8.McoRK,xZuM~"m?s8qG`2[ZKjRΗLFht,XAo i wurmXIvEG6(nHֽy"-{Vʹ~T/wrb8MjFkd*'< uQEQEQEQEQEQEQEQEUYֵZjEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP m#_/볶V+Puoyu֭egy`'I VRJ#-pمkCA40] #uX}p=MfZ;S6LahUW~*3Om[ds}pu64Vٖ['u/+j[1*3?>U{/= ioc}wtZNkE:CyTON'Iu͐;2b\.m4 PB HA* .+8T:' GRӤ1{bPՐcXU{Y7&f<5n=SOb{,d_"^oX%mĖf=$Ud"yM帍$¾qr@\#մo=B;e2 u4r((((((((((UkP( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8K]\ez|?X [K}+ћ_4ո98ۻnɑkտԷҹo(<5r㱉pfCIHIij7?&XzaĐZMa=̲G FV.9=p8Qh j-֟>!4gxX1,2ۚ.K3v|&9.ď®Q`8 7JԴ?>q-nK0AiAғF/V[ƀxa/G@I瞕SCo"PN~ͬRlFfG008]'l^IZ)$tgid$`z] z^QEQEQEQEQEQEQEQEQEQEVoVZ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE[Ǩ:ՊmTz|?X znԿ<1,[ˮpO.O=q\EHcShxíP1~e8/'ͷ¸ ;?Jr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;hfՏ6/-v89h<h֬ۻ<5wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ /65l\G!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3mS58[W/i`D(ZV}Z39&fS+AYuۍp(fhQEDlbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('E9mPvc ڤnip2-8.7.1/doc/html/figs/snap12.jpg0000644000175000017500000012313513414613100013565 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq(merD1ޟ$L!uCN?QQxJ f&mjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5LIcwtI29+yͯH?'?ƕ5(^E@e bE4S$D 285b>b|:.߬X[\rZ7(HUAǭoWj?#S98$:Lu|G&ZwWH?2ӿUi_*z(k#N7_TeH=-;x+Q b|:^ab$Ѝz}y!B5][df^\=Tv0=zmF4"4^­R*(UT ;V:XK \ܰ;m);?~AZ*vn;s qN.FV$kE$p0pɌ"P`QIfş3lrI9sO1Y#>asՑgn1?JU%>l: dU\JafVy'CQo^[jೀIn1(z'3qJ.t᧘`p:V2N$* EY62)0})Z'ce%T| ztEyodZBHC,H +0Q3ҭh\APw{X]QJp ]NI#ne\y8R}*dYO)nO tI K+s.+*ċtGw,Y7v8o4[x Q%p㷩 rEx' o0!y $Muc<+97,>$$ܸ򰪫Crx 8#Cq#/N d>dMETQEQEQEQEQEQEQEQEQEQEQEN0>FUu*2B(3eW p?o~YL11MH bKV-mbEŽI=I5暲4VF!%R趭 }]#BK\m[^S^=å ( +uמ>bЮ՚_tM<JZsߋ?Zv_)ʌ_싏"~g+j,.Tbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/>-.xG/8'+^4X|7%C3g矖 y` I='-QR Կ罧Mj_o&-#ĖżJќ[ZMAƨ'dnDE!OBI=}zT(qj_o&B/i}]ѲX?ب|!q_j_o&]"a 毤JWpIv1ʻ<}#G"\|Ch2{RiW?^(qN'Ah[o$:}>?¥]7ގKyU4$3C{F~@* t@)Qv!%snO G#rOL)|_.~O?F@$_IZbQUpЂҕFƓ?j?4 V ?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&\f tGg׊Z? ?뜿-wt}k,:݉V5՝pQDpQ]'(˯f_t_^uמ>b}qOT"(((((((((((((4sBJ$ndqЊmڻURR2wLYk}:Wp**?7ڹZΠm,`Lsk>iژdڅզX<:!n?:UnK3.47V8feۻ8RS]B=Ba d9r,K.6ʹWg#$mnU[ݟNwbС$p+$(oA,_J&a(P@O\G&m]b9%QO'ں=aRD I @qX"Stvv֖ő%FSv93]}?kYuZLβRK$k mVf/(#aǭ.ZK By~U&$l< Ƶ%(۳7.*[B6,Nzz#di-r9'oi)ʂI$g%-Q\g@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE@9[V>!\m[\7莼WO?;>࢈>ࢺA_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARM#G#Hۜq2}NCs4mNs4mL C/J2s>+,Z+X 9Y'o?zSscĐ SJ7jYLйaYǥ\i^ z2<9 Yr zZ)RṌfwg VFGder#X\*C#+dpH#Aʖ2G\V[F7n=0Nj%w+̽N;覍kAyQ; BL**ǜ_zlǧZ ĀӠŊ((((((((((((((((((((KDr趭 }-Bڷ|1Gֹo?_xVwp}E}Et.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRL[?j3ž&)B=&-?HnrNje\³hE Ǧ;U}Vyʳʱ\ sVϷXKfPɀ1Fv1hmn GhݸN:? ۏ,bQ#SQGn9s[VZ1cQz܃=p*` ~zڇ#t*1P%M6EnQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEih_ջᎃY@63ïlV:cJ..W8C((q_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARi?S O2tE% +^[ kWvHHK򞿍z5s::{S3NGf3ƽG+;3WO0ُZ 8;7;Fs]ˤ\_bS!Ppڽ9֝6q-6ehc$pϯJXڗb_SOaے1nW>d.O2`v1QCbx(hEwmⴴ{6yчۜ#i0\PMÓK[6^"*K?յt9@?{|Pp{OPno=ͼ2T {4ZN(=#f?/^ϤtKLldO|#FsSOB[ܛn%h~B9?]{sO~Q akΫ%D 1eG'=17zTN-<6`qtMc*Qd}}'g(O~WO=Ǖc,Y ÎT+-w7^L@ 2T }G U*QS??G/º F[[4"IFټ̆$`u&E%6[ch# לv)}~7+sO~Q y:k{ՍR$Hn#,r2zw^Z$7!A\d}s1O볽/e\~{>߳}}'g+gK]n2Gq5-Յ^sr$`Q?'4Qo?b/^Ϥk%dR xZQ[Ã#9FŝP$M+MXP#mק:kw[1In&2Ŕ6Ntʑڶ*G}'g(O~V>%an./,0D.ʸ#M1 &+*PXz{C ??]=׺Qk)uQPEade+4%œ=H/eӯq(2~{>߳}}'g+y5{gէQ-N߳}}'g+ro5r-ݼ-y(%ʌ {u_-Gݺ [pNt\k={`I >{>߳,k ILpх-n?Z\.L"uo˜xP YhWW~{>߳}}'g+_EOkrNTdx<+. ki>а*tG([;F1ZសvѨAIZI$;>࢈>ࢵ$e^{//BVk|E1EtY>*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:YfEfnTR9c$m9MsJkFX于7|z}+U]s0 :sMX7jQސ?jɧ<FkFi4Z臚0v;PpwdW_#yx ^+$%RxYIU+)ITk3}\5@ "1#99\j fե'ͺ6V ӌm>p;yZ)G1dɌc>R좲iYˡöHTqtcd8bD$RQ9^}y ׃x"ۻ#~Lt壸{Y#GMf ԩ{.Sz3*ͩM#(AVܡp kǵ ;9G F?QC5̶-d9cn{'BhԮ#È&{ dƢPg^:K*᠑5 J$ݴ H#۵Cxt̓D+FʜB;@kK7%kVK'|P*VLM+-pBϩEWk]4,ƚ[Y!DbnrGO5}j'؝Њ(,@u {Y_,hB:c}j?NQw#R/E C;EJSlhkt᜻9wfyMk+_Lu)WI*F8AzQl!6ݵÖϘ#UlcF}9Goy5R*w?xs(;>K%ƈdzzܼp(JA7]fg$z)}Bw{gޏ;3j72 H~Ev$‚z۝"[gnc0İUI 6WZԡ j/j2;F$^LJNx9Sy<Ӟ]ESw(<ی|>A;E 3?=} WG3jw27 pAsU#0 a&h)u3>Y co'YSX(%klB=s#ۅe?263/_t;K[VVa*r A899\}K3gI32rpu@=*kk%dВ;~_`Ga ϱњ[7W h68*;[LjS1cBNA 玹 :(;ھƭ'YhP`DNڄn!`p+0}_@tjkEhdE pK:O_zucJy$Xڹz*^_Om#a-t!oKOƲJzŽ}jh"[5+YV] *@P a`TQi7hu&Y$q,k| Mۤ-ɂiH|vg9"Pg{Wb,KյiȊPb:O_z4UE̒,d!!fbxQ,}_Q}?=78hK!BQ$ZD>_{6B!&5urE?CA_c:嵃+x^*z~5%ORg]qFrww;>࢈>ࢴ˯f_t_^uמ>b}qOT"(((((((((((((4ATtO}c>YgaOhƽRwPےBCPK}sQ];[TL Em%̶ͭh[2?^H`0Ǡ5/麥]E)Sđ hED>LFT9Vi-n7M--.4k;cBqW|I $?ֶXClRH%iğּ4aI$~y[` ٩c pJzh[{PUvPwm \Ϯi0E7A^µ49UdLkYCA5nbCSZYٯfA=03{qWk*dT ͻ~8?j׫STB+WcO`+4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (: 7YKOƢu_ h ( (_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARqM>iڝM>iژ^1eH W|E\b鼵'W|E`jq߽|S7nELH83kroY9ʜUB&&f*p:k9e m=Nn/.cS2O\{RװDbgɆ\cA檔_VW7qtv3{ULZh1LH?1Nq j{JVs I( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (: 7YKOơuo h ( (_y/ν Y=|]ue _ꍷ۾mG JTvj_ϭ?MY}mh*%wghSU5QEQEQEQEQEQES%(|$kl ")|R$`E>((((4ATu )oͩoͩ9eS^~xQ~'oo-{ <[㌲ >|2p68#DҮs=w/Ӥѧ(3HBh2no,Yͻp<09?A [іZ$VR x{֫VWE 6X1߾O^ cSjE+tFqמƺ:İ9$jA7'Z. 5e#EWnQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEu^n\=MPKAr_7wP}E}E2Y=|]ס]5":wOϦ1[prހg'qS~(\{tyX7WЛ۶8&Vfe1t~:gӵQΙ]:?.n'@Z?EITu:< TqWgRVFKJ{|n21TYuwI;#z4YY_& G Q͊쎾LK"%GehH,MRO?"At(vAɀi~]H,Mi_}GQ.?Eخ90/i#z5K]?o?&w#z4YY_& G Qsb 4.YY_&K4?/At(O?"lWdF{o~EY<ɍڤHҟwSOcỏs,PEۙdIį̤NqZIpy(21-#.6^u%|} -K}?/jkRŲ$ȥs岎2N֦+/2 ţ\2D:#lC 8sj>_agaj_Ϸ>]{q'bmdZ!\m u5ul;cͬ"]1͑cݒ_@Ϸ>G>oi^iz`gXc^*lIgPP5&yA+f|㌬Z_1:p Ro}Ə-K}ۋ K$KGS:sQZ̚t!7-S;p6i${2?/h_ %I!LʊP\HÖ,r=*nw;M*#ʅ?n֟gaj_Ϸ>Z]]n[wVXtdHTn;2Kg]LVsn?(=2=j2^6L Ro}Ə-K}đF÷N֥x$GAYYEcϷ>G>Icj0\I"'4fp}`"^Om v G8֫kԿ_ Ro}ƺ'y-gT&88%ݱ2 <6pQ#2J _ Ro}Ʈ]ZyvWWB|R/#8[\O8 N|,8' RU{[)aj_Ϸ>V.>iznfg.Jz6kk$`,8!cŤjYaj_Ϸ>Z]\7vZ5\G.i=u{+NP F{Vg<}XqZ4aj_eEO^2N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?&w,nl_z}io5^MN[qQAA.՚_z^{//kXB-1SGmhkoo"e _?_ϵ7G/(bI O6#]I q=Oj(((((((X1J8Qkk(I=X(((()CKHzGK, wE-vu4$\[w9A5KJhu >%fu HںH@dqSI5]\$e{itij2<ʄP m>;XI$ʪBN *Ԡ^W'oKclOBcY9eUp*rOLjIXI@8QWݞ•G̈n5mk=f8mz]GPFKr#ͺRy㱮}JJg}cdq>s}ngd,7bE- 7rA|Dz[+Uf,~C/:W%lѷ鵎;ism)]nۿRԶwo 1ZY4Cw{ bPW6[QV !vuýKI`-L[#3S[H{As ?.y]#ߜ_nsJƢGK^Dv/vqU[@X:),%?k&tks,#Iq*Iv>S!lb{+;[660zuE?RHܸѮa-bH68h~m<?@` â{Vt6ͅR\;eW(P>MwMY ēmUQK4tlS2A8l8`TQӞXvG:DD?Z)%eoYlRWwvRK1c#j͠郫3HŘ67ehڱtWdmE6gh/=Ǚ3) |EX]kMK3k4EJy ,Ir xY-HM۞(>lREqVef[-. xb ]$v$qXTSx:mfxik:;H!w`܁KǥE1*v1|? ¢ԩdmEm0򒲱cԖ&/49m6w 9z{zĢ7mK/0D`5@G' -\U[/??ƏIlh !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgjp:n䬋37uo S]4ƜTc;>࢈>ࢴ$e^{//BVk|E1EtijiAk[x^K[rǴ9Yk7ZiXE3BO>Yxmr* eא4H߽R87t'|TՕR +J``C@2O xi2h5A^ΠZq?W1/%Ի[ے`L݊9Z6+E0Y^DdR<2U46M=.`4uD>YS=밾4FENtVr$T7zFsPi֒I.ۻ_4gic/Cn U,'${WU|Jf6*I!oHS%y'^JƊ 0[djkKW[:>9>~0id[ .=Md&8idj2VI#a}gkp#'V6qֲePA'OFJ|h=!Y4&V_X>láԬ^`) (((((((((((((((((((% g/z_>n\=Mᮧ@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*z((((((((((((()CKHzGR M>iڝM>iژ^1eH W_?Q5{_4-qo*|I|5V'dy1zVZÜUԚBڜ}3U9\ u4&oRE@֪ZD^F ~#Wk7uAERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQExKAr_7C/?4AA˯f_t_^uמ>b5nn#$Oͺ%bDVP>#PnK3mzO~ ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRk֫s+ yb(@yݟ^⻉#EU(ٲ;9 zbnfEO䷊;{g>Ґ\qSfp zTH)Z]}3F l^Kbx1L1 #*H'8.&xKk4&;O|i<.5{=`Q?]%X—S*%PrUӭ`iv|352Jn"PZE/ʸ#Vwo"-r/F kxzdH;j9luGbF6wfϿJ‘[z*[UN ';Xɭ>[bq/#W0zeXŨ*HHM$}XKNʌX8Ssp{q+I4qy2Wnl¬_7"y>4Xv ׯ?[}b#W^X?Swg[eR̀(l`ay{9FҚ3C(8݅ uҔuJ R?G#WE`t[VqOL'9fM-N.Y V$l =xTU"TW/#Ʒ9x5{=`V15gdfeW˴:٬厬g RG(jz}𮪊+G(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X= Z6sFdC =zz}O _'W RU))K'5H e^{//BVk|E1EtY>*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:tZcǹ+8rO?7M41m$n?P׺m‹+D"Epr>U]VMb]C(FFSTdӺ2I͙c K/\h$yۊCX'XWg?V+ EleYw8'ElD+61w'⤋M፣{fʨ bq*6')7va$s+rm1<PL=<?uQ?/k.2ik!oC XmAuҴ7K.#@uQ?S~/|3~kmۿ:9PϦwRM"}ב G=VCoǦ3Us,WnD @$& ؟_ʚ]?adrqiDVmgٙ`ʼn'9LF$p?6'bq*_Saet;sa* # =}7|;$1Lh0 ]TlO/Ma).094&駏Rf5m /e֭'bq*OEae6Nl?'?ƺ=؟_ʗԨ/= mG?Q*k>9p~chaA8?15O/FT}J/Ϲm6Nt{Q?R0sl?'?ƍ]TlO/GԨ/= mG?Q*k>9p~chaA8?15O/FT}J/Ϲm6Nt{Q?R0atƆ&V s?κmY6b-%/3}ι ?]G;z ( *2Y=|]ס]5":k\SA=Ae _(((((((((((((= -!h:tH: @-QL(jIҬI] 畂D#t.T jQU?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhפ+SujSt,qʬr2p3<7 ( )˯f_t_^uמ>buX}9 =@@U4#'D7r?UV(((((((((((((= -!h:\ZJ) \SFO'ѓi(4dJ(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒM?]E*7sQS˯f_t_^uמ>b}qOT"(((((((((((((4袊C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (+>7_xuM?@pQDpQLC.՚_z^{//A?Sמivww:ܓþH."bNca}Ƚ=+mr8M֠hk}2'>;koVMk+R@$?R+t$:X3ɥ=5f n*{ M%#G (˅u-~sU_p[.< |\`=q[kzپg bdieݤ}cm|qӷLQ s(:,-a" íKÅQvW[_?:QEQEQEQEQEQEQEQEQEQE= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr먿}ro\x:` buמ>bЮ՚_wV_)[O:Y*YO"Sp~Qj_\6O*-QU~s@۟?>s@۟?EE`pTQEQEQEQEQEQEQEQEQEQEQER4QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UoA?ɿrtA2Y=|]ס]5":`EZOkz򇐲:)U'9rdSx]R++>o"+|sw=SkKMƒM'>H,L_#k u&QZ@LpWN+?EP?EIQjvN# I R:V%`j}CRDe08;tue5]P9JedjAV A[/\!_ ]d11?~?_? ѿ+ehF_ ?rB.2?='?8/GA A[/G$7ls]d1uAQ1??:H4o ? ѿ+ek"# ?riO= ~AV A[/\!_ ]d1{LO~!p_ _ƏH4o c("#bcth4AV?EG9G!_ {s#F_ _ƹB.2??c(CYj[^E4aI6_):z,>~c+C"?/h?ة> > X!bɻ$cO= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@aly>e)Vt;/EO@ ttP $H{QQ$GV=z(((((((((M sJ5JKKYL!X}>EQEQE= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@Ӭ:tq[ hG/B|*.nu>0ż|q'Dy$XH ~C_ zWPݼ gTcd3c5K< zi^&JPPsȩ+3< zw:2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]l_-?ֿءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_u`o$bHw'lw?ޛ(77~fLVSVQKY}(}*ءƏChbY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC.?ҹo}x:Vs~D-Ͼ@pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5ޟdg+9m4lb6횣i` ̷w$I,_23`qJ_[+m@t#h$q> f״~,1`s횱{k[s,Q('>IϫXj{o Wlm 4çnuΕ+( #$D v.}K˯e=ߞ  W=>R2*}aN[r4m\05i5]#[X8JM9%nzqRi*RmY~$W0Pxڲi&tȷtI^ lmnTzU±t z;(--n2*($n%LoE_QcsaIu4`'W+ _\1Gg#E 2erNgxU(tF+#Ԯ2cԎtOZ;:+ܷxē< m.pHwNxTmAEkF-?kcϹֶ~ZU.nAUoݱU'fj#\u>R}0vH!qߎJ# JKkah(((((((((((((((((((((((((((((((+o¸}x:` bsןO#?:9Pٗ4ګ}/ڥ?yߋo혁YEP>=A O? O/G(OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O?*nj_Q @?zU{EU%yѭ—6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o)W.7P#÷[?Danc[ZA#t}E:!SXdU 1(9H@4\h1I*dWcyk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~TQ]yk@ݶmj"8(Z(nip2-8.7.1/doc/html/figs/snap3.jpg0000644000175000017500000024221113414613100013502 00000000000000JFIFExifII*JR(iZ)( )( 02100100g4C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222224g" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?3A#'.4̣p-/GkWy&_ RHk+Xŝ@篭zגԳK?.Z{Gp=o_Z<%g>]zמy^K N}/?G-;O]ּ_Z_Zvy?iϥC篭zגӴK N}/?E=}hּ^?.Zvy.yG?!tҴKҸ篭zגҴK J}/?E=}hּ^?.ZVw.G?!tҴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-_篭zדѵK?.]qt\X֏=}khZϥG- _篭zדеK/.Zu}Ep=c_Z<'k>__]-zǞy^O B}.8?hZϥE=}hּ]qtеK/.z篭y7- _k>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-O篭zדѴK?.ZVwp=g_Z<&i>]?!t\Y֏=}kɿiZϥC?iZϥC篭zגҴK J}/?E=}hּ^?.ZVy.yG?!tӴKӸ篭zגӴK N}/?E=}hּ^?.Zvy.yG!tӳK?.^z篭y/-K??jYϥE=}hּ^QtVu$8k,>)iSN̗6oWhXנZ^謌Xdr )Q@ \y5L~C\?+@%HŤ=wT*(R.6[pjrںYNbԞvßj ^ݶXTr]?MtuuPNlȔ/c]:UoI.c*H+-t&GN<9XZ>'5=RMixLPsi'Z\mv_tB{)lcbT MyK0d8B{סpgAFڑ&?0؆r OHu|w4_/5ys:SZDp[Ex8w'*;6FЪpT^y*[I,|E7/$euIϔO4ag8[}> eqmsgX%$@$9?vc?mS%q!s/5F(5ITm5tK߯4OmyY@ 2#ڽa[_x= [Ŭ)ه0MX?̻|汈F9o'qVcz6Hٽ*s%-uB7vt3b \^״ Aӷ;Pd:OOƷ?"NuIĩ+"r#@sHVf VAI{}wO9͐EV&MkEմk-*'i nʯn?G&m/t4O ,Wq)]~?z6be-B o9'8ペ;mn+ 4-ᣀ嘂a1ҸiiP[IJNA96021hǧC;u-nDQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuKIHR9¨PD!~LnsZ% Zvpמ9z]rK-@v"Hǫ3VKB;_ Ki\k2zb:}Μ2mȽ >% o5 L&LrqU[Pi ݠJ)]یh7zfc2[uc*}Sw:u\GpP/v\dy|8.۵RO=~Ǔ$1vϩe{Xe]4^Ku{7ÝFI|(r *+3B&U뽟Up(LԌh#Rb_<]=G=EW2Hހ$ݚw_%Ld[x1mAہR,d$Xvy<{:R7)Fz@ 1JRA(cwRd?=T~Uq6DL&G@NqZ$ dzRα=ޏeȑyl w''8Pq:{;227QQQ_ʴ".!Ц#Hi8Ssw:mr@Sh ='Wyi}p<9ŗ27~},T-վW8?EhjG'}۲-[܌j@;OP _ʛEZ] kk$Eqیr23Z>,n|L"v' k7f]ym+]'=MZ=ApG8 ˢ4(Q#2~G<zenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@Feԡ Atj#řR{z(wĻQa~ֹ28iaUh 5$d֋R{uFgYn\bk*~IOΝk~6?֨;/CE_Ҋb'U뽟U]NK]K=rԶ,P7c=j{>|1SRVht:[|ܒIS%4++"&gF]esS\kZs$qنQH1cHǭ8kʼn)EBʧV u_gU2M3S@~#ERvwW泏AYԡ:{cnv;Y<8CCLL-=wZTe<;56:j_Y @YiW&x.綆(j\ Qw(!*ιY[X BnC:M^ nXy]ֹv{Im.'m=sqOb*姊 y $ lP8# kFn2pnW)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW6l*Uk oMv_Ҋ,O?5xS{?5xS'?S)%,Nߓی~"_KJY<-n19U'h\d ?ϴ ie$;R4ل獻I=z\}mnwL?/R&]LiͫNI[9C6y?l:u#3 ҩ\IP֙`(Z$=CrdREiSY= w=wM-l^p׷<4kå2MQc[8mI0۷yA򜑞!:92_xc*w6sn.b(]QgcXKw&k&&]ZO/n : [[O\[v"63$2rI#y`Zt,2)|_h}SQX,g}Unmr"8̝c9󞆝o؛IWTѝh-NqLIsٮ.#c\dwNIU?؋ x[V/uRw185[;IicW,|Bg'ⲖM;A-ew7M;L ^@ tKI5&;Hn4)t '`u;S_]#[wvEKWG6ʹ+p.R_vZmWFeVGFާkӉ.巻]?`wYD_嵍Dǧܾ% kx `B f1#<:;QQ帷[2f26{к;O&(a15{]jK !iJl#*|W:4Ifҝk}l#9=Cgogs8 y%)E-8Գczz (>Dc#81[I~ש{ n纵I$Ne$sL+7s= KeHT7D9ߑ9Moa_Ky0\},vYWjW"Yd1K1:U /IԖi`Ծ$r,1s={R[Z%O5!Yyk HjX<јو츒5#Q\-m.f'6# m,|dj:(+=_%R*Y,KEHTL?/W:_XϨItl<)T̓98zfGcx4jBHQe$&YN>c39WlzgHʥŽ9vuj@4-G{Mɧuo5@J0>j;SIӧHn(qN8Q2p*lbc\%M8/8ϭcjvԤNq 9GW'/t7toŔ19eOfX OI*c9$tN5Qswl ZuPux52}OUXCo4MICFS'jKPOu >e9{:l5M/RUUChi@uq\̺NMly}4ZRFp\SoSWV{ dZ<BF ;h^Ϊ5kvecy6)IZe{D_fy!ٍf-9 ̈0R zg?Tլ~]R^"@Kv'?4>Zؚ-oEkxPܫ w W'=9V,u (b:؊Z./o-m vl`@gy0OM.!(SvH =Y|[4/ɂѝG6KM%ƣͬLIۆA9zSz6-6?"Ҿ/~՘LW}ٍj֟jhK@w ^MᙼwOUԗU2XNWsן ^_wuGQtɝqA8zI&"h!bpcvw$RcEEAgov{1F‚x%NjI".J\{ 57@g_ڿ G,ǿ'H`-ӮVe`$&qtQE!Q@6HX9] B)P{K =>3ѓV(UQvb(((UjQ)h (jߴn3qKEQEQER2VPz2)h((( ia ;7H8)iGQxȒw3Y^.;49wɪݶ [Ya3}a;9#= IVӾkXh8w8掗=xlb L8=zָ>OkK8^l0vTR'$2ϰ|W. ;;K]MdM29 }q5~n;REKyFxФ(cw}*ᣍ/Pŀ,i8'S~`vWi֍srbRHE:[.< \`rxp[͔rRT9淑ִO}- zSM.#g$jo3nOb-YZDPZڗ Ϧ +^ ^wWhW 9w?>¦D$3u AY^(o /$Qk+F̠;#ң?vf?fo[pnǧ_’wv4TTLkldX$a'zu_iڭ4Yڛ:]2'00wS#T>Qe}( /zg/zղ; [X\ZM,/l1Z;je;@e?Zf,C|Gd= #5 L?:͞u ?1-sTq|Q?8N}ٳqpG]qхoiͻ6w8#F<{a?gXeI.̈?+`Mr9f :n>?0]=&nqpîFx wڤK⏵I>rXɟKߛ=.Xu?F'%8\OgI?RϥX']K=.uxчj59.u?Fx 3N$h2y)$?j}.?iYj1KovHDw-.H瑌lcw~9=ڔXg$ >_ qz&;I>j}.?ɾ)#.fxMgO~lw?FЏCTq|Q?=Z1Gsj']>ӏ]iNowv3Tq|Q?NO}h e8b H'?N?0ټib5sutbtuj}.?>'\Ńi’H#͟F^ПwKu~sMdU_j}.?>'\{A-j6sw?1 CvDRluݟ2VzڤK⏵I>yS|oݝ3ZI@뻧?F7O !!kv]ӏ~taj}.?>'\3QkYlc;x~3ycc#>'\}O+?9ӵ=&]щb\(A9wӏsҾ'\}O+ fSq9wqш⾆dxΟ|uO)5X✝z/ڤK⏵I>yŷŭۦg >X}ƳN,Kwt?Lg*㤙j~'\}O+O\$ wtF(LX[@s\}tbV&H~§cTq|Q?. 'Z x#n>qщOR>?0}f>'\}O+d6z\w_i-CK:n>?0}j'\}O+o:[n͖3|Avl=.뻧qх?§cTq|Q?(L}ٲs\wOO8ӟw9.뻦t`oi6w \0>qуt=Na?Rϥ\kMuݜZ/c󜅜֨0{ RϥGڤKq\%d7x0?1#66z\0ߏ~taj>'\}O+>4ܰ69.u?Ó6kH,ETgvNwq1p,Uuj}.?>'\ȟi %͞ :S;,>{z\뻧?F֨0{ RϥGڤK#==f :hS+, swth8?§cTq|Q?+.F}Awt?·=C#7G>GTvj}.?>'\Ʒ4;=.ѸkxLbj8#7x8?§cTq|Q?,L|P:n>qс{6T=Ni?GLmRG˫-,˻"cn͖3?vls\wO~t`cS-"[9tTq|WX-C'9uxC Iݛ-Gw\}i0{ RϥGڤKSI`Oص=.>qс#-6Z9.>qч_ƧcTq|Q?$i8$_6~uxskBU96:ӏ5ZًMt=RϥGڤK0bvsw|}Q㯆U[MֻlutcE$%ŭYTq|Q?#o>m5sJ]ӏO#|znΙP:}2O]7l&p=ҹ9=u8?u(X^."1̀36r<`aoNWh# yB;{/CE_Ҋb'U뽟UnUjzYJ3+ޣC!d)@5VQ9^:dxF-3zƮȴta&WzAdpW4YqZ,ږ2KGg;c't)G&*e=gpf׉tZ- d D~]:gO-S%+xݏjT dnӭvsmF6I~{O@}`S֝p>ǭcGtqzzTC?iTЧ#V@B8Ӌ\Sd9>Vi&[՝m2}q} CFw+PJ$S MI[vczm;R63Ir1I'+[jB'Ok$yӉ攨*a 3Z1Uojfb~UݰlJj{6TY[lg%W$v+Yb>|/ .?c[ (J؃^{'ASAbv J=*;)ڬq}[Z-nWE~9'wK˔yV23@GXacY4P>B1WDnOsleBxsUtl-2\QۼɅԀ=R6s2 p?*(kRV5ӫm+ rbw5G%/xbY9ç85cٯa/&xX) qWaw,pG?&7P023OQ5ut-A1J4wg@GІUVe{2_ZR1{PC eH縥9;Q ${8'6^UCCZO|x!EZ| +.1O?ysMB#'=n#0s֖& y?$0aϥqiyn@ zvsL`zq#c!3& $?Z'K9ۇ_KaϽFG;%Npr=i'ӷ=s <Ω 1 g'ۚa9˚Bö3GLCOM'q: 2 )Tz`>qdE VhS$ 0=Rb*g9WIr\d+ׇZ܉EpvFN0~tZaLܱNkӢzF})(-ns\xIwi#n6c7f .2ma:wBPQE/zg/z۷_ZޖRǷ#o>̑^n*m,ӕoQӡG+ifNdxr)JZA5e=CA⧉ָ͉+NϯҐZ03Rl- 4Bݢ"[yciO=#cQf@q}UfcND!qi˰]c&d.Eq#FVƬqJLlB#ڭCgP䯦?kY7n+ST؁"hdy/RcFrPW7h12G)ԭ=¢mBض<|^E5i# =>aSꬤkE4SJudU34eV߁+'!8錊^%Rq^i/.ĹK{D0ڥ(;˖JzQ,?N8X?~ 1[xzK䂽O#Uc"Tarjr3TfN=BVh^ۂ>ңK9ҒUW>Zr (NaC1]nNHS*ZqiܶCI=`W,ꘆ:V20[ĸ2q!kŗS8t$#?_–1X\i1NʲP.9|fJC+ZJ9;?$dĎT kuӡ \HM+cy!*׷0ܤ 0U<[I3 #cn:s|Om 1JICۏƵ8OUNRK23l ;tRZ?B ĝs׶=Ͼ3R3ʥ3ƊHh!̟zyHz}A!` z›t홌[de w瓏¹y5 Մo$?|GQ@^QwA?X.ltA#`JӅazUM^2xxk 0?y{;*JNN:zκT⮻O\V|uxUb/x{&p ~?\R(jkzj.$2A@N(p{z6 3i&6xV9qjv+4Ã2Q `T}ZORB:TA\A桿b$SfzdFԀzTQ+9'tⅽ&=~^~t3Db:ti%cFH@)zri`pZ^qMWa <ԠJh;oƒ:xaT263jv8u}k.]\ҩ(㎝kХDo[zԜ"rsXsZQ5VT.f7qښZf(4Z,zqTaR+P|TdMH\hSZ;N}i}ۢWeAy,CVuNl7]%[PjhMi\I|?bRʇ+>kKӛjä6[8KH{wiɶiy%}s0t̴DEQ*?CIZ嬙[9ۀ@Mr:mZ@->a礋Ϡ=={9~_.6WQlPZz3S0"p zJwZxb,K:C2 f1;q㋶$Kְ|L!+ s>⚧)ik#u+.F\[Op{|Glf`s4HA6z YoIT<7\r@=r[eMhʯ,vעR哉fE.n(8޳ﵭ3M.ݹz|'-(t@eGRW鶬u Jlp|\~/ l< ޭHȖ͘jJ;LNNqܹ@ 8Qk!|G> ՃX0ݏoʳe Yl¨(VlqFf.">gjtѤLD7BU=x`,;c'5/wrGkH`{-֓4XgHč`zFqh9#Q"Hqǰp(g'J0AvGLќ'\[H{JLM$/VX豣 ݜ5&;T):sHOqڷ+[+l-$xdhvmpq':k޵sfpAl1Ec7$`Bfq=״67-t..$h}x?{W睂^W,qM a)UsP4-xeQ=9j:α۴Ē6n#c޵sj*sZsA.o- 2b@]8IZ搡yYomr$9 ݴ{ .?VntƄ,Э)l.dY>d,ݹdxբ`ѐ GlVl>᫒-p-\օpn4ffNzkj^gҳRF(S0Ole`*@$!GM_:=kj6ORv(le+ 4yĖA1@:)sߝѢ Rk,Z* F'<iWbI.]v+x/mMyWZ`k9.W2'G=rs+)荣wVʦx pG z>?@L $ueC331 |zz'-9zfmv2; HP|Þ!*_xU@41xҬl~9ǭmxOJ]-9LhĹ đ8T| whMl[J~~^F';J%iFkbh^(L#OIzObxOc\5)9"0k|]_oOOFbp>3mt )l&%q:|/' ^r٠|B~U#V6k ÷8k% ʑ#`{''vnjt{ۢ8n[<Ɠm(" Spw澴@pg!XN:ʠKck(.֏-P}A>BHѼ `/5Ϸ_7th ,+՟/?`?\ك^*o=Ҫ]K=זOQI חg3r~S֠kt4$;WTk376ӓ}*##t_ʷL ~lGUr]4sgG>HS6y!=>hNc],n3ǒM$V`Je 냊ʭg5bWt*ضKd{ӌ1 Mgr~@{"Mׯ4GN)/o׽KC@3IjO' ]cSLF6=hǏp)Tx'۟G$ cGJi/֕ Yy>~Gfjͽ&Y̠@F$ִmj%a^%y#2ZCKI]R,GRq@ZIwi#n6c7f{ .2ma:uB/CE1 p^*T p^*Tn*m,ӕoQӡGww7QHʲVQ9^:d| Ypdrj\JQrvGqvgd1O ݫ{LL:n[&d'߇W|D;!,{w+g_Sjɛ[ B6TDIZ8Ze`XyA`;DŔ_E H,t ljYu<-T)G+ne}rJG8O IRoOO.6/W>&}aW 8}3E2VFN_gV\YI aANϧoT 欤8G_zI 1FNXwFlMw?LՇ 3`K)?(2t?j$*vX撖]_YcWPXG [^4bϣ[:$VD0Gwm -I> !yLkn%Dwr|E''8v29$m/{2 wFx}9 @flsNxxz+Β.rypAߓr8Əwme$ &'^׿pTث,nls$}3ɮj+ Ą,Mliڕ|y^tL0=N:g~56乔Ey‘ۂZ )$,@Kds~3nҘP2`/r9`y>ƝbO s0 *$1 .f*2ci\;TgiJO,FWUȤAV?t1I͇)gN N W=2Bj8S͸;{wz5.Üiք:Rr?Ϝ;7\ZΙ҈40Yyn:$r+[aZMr]-Ă8I-r~HK9'zu81N!]'U$rUSLܞ QxIwi#n6c7f{ .2ma:uBPQE/zg/z۷_ZޖRǷ"Rq\_ZޖRǷ"%ePێ=L)$/DND:S"@=A$CXd¤v9hŘۘ\LG:~U<=fQ%лQ8*X.aA]d>[0݇O[SVGxZ֌gei2dHI+V$i4O(U4ZjS}GTQ+E,Iá #R⾂|M+1:aϷ5#2`>L=*+TdɫX }|v >nԚhD5ܚM\9:S.^U«@RryWW7Rږ$lznnJ%TQ4ކ5_xD>n$\|9o:OHCzqAnv|c'osV[`q#Wv>5G TR0ש|GO'W9LڋY;X72zxrbfܓJw.|) .I*7#5_I˰ S,ʓeXt;|yv;O5H>X.B1yQ?[isPcxf9'#MʄeT'7}3ɩxF̖``l p[L#⼳ljK3mb}F+(~k*baNn2?CJ<ȼx0{{\3 n Ia[$ȥ7˞5`YnθUT=7 &%si(Z'tW*T E\]ڹ%KhL8WE! ٗj>h=#?Η,J{mj'= h;ebfAy\꘮MXd\֭6ݣvQjn'ݩ_`u(6nX\ Ci RC*@07A9AGB)a>] R!}=i$sҮl GsHF?EJq&HϦMLxnԍ + rų؏RG\Tx>brLsHv ;ULL>mGը[mȋz~qq v>c#${O_J•ny4eO&'EmvX^sT-L-9vM##9 ƅ'f]gw[O+ 4R2N3ϭy^W g >˪AC qzaqXkq xkR/m<.0NiYߩz?ž,ͽsȷZ-dː 0gb˩%rk5 ͠[2n4z >rYY'hb62壐.YO@1pjJQik[+9biB_'8=:JבlQ:p ۗ'ӍfД12MG`dA4i"4r(dpU^j:?SgٻA+d#2Zc6ZW}(,GqՂ6+NgGf=!)i3Q<0H (^NǜnȭFQI777w"k u 6S7p+F}qXWJQ߯mRᶕm&w h߀HӴw" {S+b$"0vGk $*ENKobdSZF4V#'kƖR;$P둃2+,qC/?uqE{grv>'/Kq3}0m1zvT#1 rߘlVvD`2T] %;YgM1ׂ1-#:C 2w?m "GtǯY>&b|r6$Up<9N..$zF szf._J$>a`s^lȍݧB=sHh.g-@N[H.O4ƈc׵ ;"{{O'2ۊUtr (;C@U 'Kn9˨\t3>pKN؝8pl(8>ҋ5IpC<`ۺzFz'8g?ҩNKڍu'Jl?݌YEN Uf8f|j_f -ir+w08(~bO qqH((q=@,^fw~@!J<7r "'?\ 1r;:jn(׹)/ CתrP7z*RFȸlj E龁y/ (WB?A$W3n;Nu6Km<`)ra#H$ URp8nR>ʈ#\dTF$n-(q{1G*g&<~4AWJFde+ex)DLN|OS<pO]pO@vVQ9^:d[42+UlKuUme(ޜ|{z2<5K8MN~ta ?Ls/1څٲhBx^IC V:MnUB7 yeߌ/6yRH~Vz_±o%%wQs1XĨ- 6^҅RY) ? E/mGETM}jUs^s&QJȸH%Qˈ#]Jq`3n*ά|I2 ásJ>u] eI7VbϦF1s\3Z }N8V`OL`Ԉ&rT6ޜʹ.!V-3ʒ6;-b"vy?uBWG$cqmlӎN?|5o$cslE8Fcz s+R`Gu\c8\?zWvH] `ӽ)% J#l= [Xd*pGTd1G01 Vn$ö;}j25&9W V_fӮHڦ[as0"@{ rNN+֖E@ѡcհ:1 "VЙ*H') yEIqn wOW+,6 2 Z$hfRC׷'-͒t6`zҼR`1;-ΪJ C/Ҳ.oo/MøAc|v#[Y_/Ҿs%Gބdp9ұfh㷂ܼ@erp9,r{EKśUv|ξNIAF2|? Ruyo@vx Rn}9B JAF=SbMyquj;ɞ^yiroaO<aIu#q1ER̆ I>sQ|)pI_b9&Hk#9́ӹ}k~߭φJjԖ{û߱xO.; ο2 ^3 ~ %kgTWGQU/uK 5C^^AA*$p cu?rڏĭ"0kT>#[ql٭+!}=E>Uh>crp3#;1ׯ¥@NKh̬1+S\Plb<_e(IU[OT玺ψtbAq!?Oֲ'tm-^ $K(Wb:juP ʴQT+KЩwǺgZǖGV*;F^A;rp}xeݜR)i;IM/֜jD>Z|=u`.c]^p^axsQqu6N:t^ŏJՄg\,T{}>yU$+fDe992t, }J/[`qq^ ϕ7Բ㸔$!x'[%A8"0~j1s-r;{?ֺ4#󣚆&S,fGBدOW5qC0j+gXߥtP#Zy溟 LHĄW*N+WGdiH 8hWKLwq={F{xIwi#n6c4uUd/CE1 p^*T p^*Tn*m,ӕoQӡGϩ\\M3<澁_ZޖRǷ#5kX켠 ?c+)J-O2gdxLg#5ca}9eal,ɳgcp||0#3SS!G$GK+bœ$9K,/hFdp7.qЂy=:`1Oa2Z^Vl#,+xzv4Ҩrמ¾k,E 5/nFJ<#ZҮ@ZTs `}Oǧ\:ɋǗ7G?xӓY?+xF1nfVs>2ֽL)M~U# 9~%h7(KڸQ'I]VS`H𑰻;u{d۵Pz;q^Cu[ usFPTo8%x7n躁is |i GּW0HT߄ĹՃykb?0kzSFI'Xťi'=?b Ы|`\:fA/&O|.OY]6k)H\BqRJ#5>uMf } $ *9F@N+({l,7õzKޫi&Mf{ۖ1 Փ 8 _5gc͔\dr~$Z](P%_);'*? ٸtu?]R}n㳱nsȫjލ9^] ԫƪVHvsTrOD$Ps:ʮhuH>V?1-"M v]0-3~fn"ԡ_ 2DdU$3[m1࿖;\01ˀ߮kح,m,QkVFo/m"%ſ5b3,F'JӱCHG'$(=NsVcijAb70G\}F|Bl#v~>k@uRIhp6¸o$U# 6gڹ[tY2`Ò;8į9ǭ;4-bj dfz$m+4df!DI>qMylQפUU֭{yaw n8'VDdwH~cNeY7.MZ֜etuG1'FK?fUNz?jZxL8H9U`>rMY!o24 FdfF@zEpԑ]jv-ίAʵ$9늹k5)(Pp?3X8mxͣ o'6sʤeHӢm%_ǟUu)hоabxU `M*W?εTm2|~&%MuF*z77_ ޣ*2@¬{*f?֥яW:d|pG9TFp }E%q S|Ѕ[˘tf_P-߂ǧ?Θ6ċQj21NM{W:8IPofݎ 'qMld=3\~(?ye !_j^* Mc$|g(T tE!t`9YDG~dXMcN'n2]4˻*zvw<QQŴ򧍉jG2q~]l Řp qQ2 >@sHv9Ol.F1mF~#i]eۻ&#/u ?3?hfv_Ҋ,O?5xS{?5xSݺĪնgoNW=GN"v:c;\88WVVQ9^:d|-KJOO2OuI''$ڦvVc"8>`9 m~*ɭ]/ڎڏOzaog. Lefc==)(HVlnf`y^x2˷e, \#XSMSo\ r+wN0& [6ݠOT 'xtB =imK Cp^u'Ca"gx- Mi4\ҹHrI?/qVS#6 qv+v 緡{Ůc崢kyWr9Ops^izNKn>l8b3xp8oQ=խnM,R9)r)G V ĨԊ{ÚdR.yAH_^Iڞ$ܘ2̟|\ޑyh0R\K-طVcR?3` AxiNFֳ.4)v㕼7ZPUfOݻ;Nzs޴=6j/le9IdqL9[M.1]}q8sОTqX<\/foyZao %ّ(mH<hc)˕<0?kI]ۛ=J9<r>Jc<'$-*>?}ȯk/CTqزξj;J|PC|I}*MmP[q2"€ɓ*'4#MK V8*$cd~t{Oּ#X1R$2ϱV@K)b; nݨbUD(5sXPtԜ0O#tYU{-*o-a,Rp̀ ׹C7滕9a&;lbkaOzjVe}gTP9I$v÷C5i^搪a"PnĎ gSqROޞ Eݳm;Gi>aldN2j;&OZƠMcTXXԙJc_"_4m3myKy0 j6a^^a%9%i;hr)?=oب‘˧Zͦ˧-%h@F cQTAM 4K-n-.Q9;'~57[_= D.0 9eIl6W6ZMk1o*h7pvb<%m¤s&LϠ*񮒰u/  C }3"Z-{6@XՀRHCMVMgIZ8e:`/_Ot9^bII|+e(HB~'-řʡFڻԂǿ>zK6*`-щ8 *lP7˅|3p:5qQƜd pBJ#d=!M}GRH#i\̒12""CL# ~hKK-VKU1?4=I?z H]U:r?{F6ƓlPKg2{FHuMm|R 78<SWFױ^%7E-('0p3j͵t6''dO!92LZ y⵴+ZK8@V/Oo8K6q;F2XEvznm(?^]QUq;wqUbFob\A^/*NesM$^4>Pf&?uBv2+ ;"UB<QD1 lp9$8WT:3htgAH2)}d̵3\*ؖ_f:I{4v+WZ 7?M֓ܳB׀l'`['vӎޝ+]H'W5+<\<_~J [T'M9gYݸ>; :"Ms: n'a4_(B rsn45 3,x- Jz&k{V3Eץr1*.w.N2qU776< ؠ?ͼqs<xCHUýÌ|ĒGL{Ӆ)ӝXAld ua.xsID^;z~K5Ǖsh3E {ry6IƉUH9\E֏Ci Y,}IWAҀG]U4֨7ğ$%ymcӐk3g"X4o$qq7,j?|wWK-Z1 5ƣ ;I }nR9iO(vؚs׭znj7e$`Q@$M8i755xCO:?Xf'Ծ]eۻ&#/u ?3?;KLwq={?VAJ(T>S<pO]pO@vVQ9^:dy6X(!H9=ۓN_ZޖRǷ#c׮3$ZEĒ*O~g׊>FՎRӎq:e$QOS}zV>j:VIhAz/^ZLDj,nEUzm(SU;:fnvY$ uV l# 3еK]Imf1a0t661{ep7y>`.>9?JcKVOCROvAC.~*W?|/Zi6](em{gr2xŝՅI$lHАBs\^[FdZ^":I,ROL32g;Ksi*rt79tAs:^e[XFB=q98Q3eTo8wBFj=Yj>T-1%c#;Ssø}cHJ< rcp=k5=Lp@8v?j;_ аܥIpO=YԦENa [2@:> Lk<_lq xD<;90ʏ&ո2/|&[T]+e(rѿߺdZky޻E]Юa,`]8 6܀̬{`k YgoYlgsxGY4[h zdÞN8<՜VKGM(K6nc;Jd1# (#j/>!Y>Fm7LU#1r 1*Iq\i,kQ~C89̓Ք)bK=>±79UFͪfQuյy,vmx %q%&6#MO]>_y;vơ0P|tªâܝuTG-\M:_7 4) ,**A9ۆ rͻ`T^#֡tEn$rΆ(gCۜs;5ikN G?i9KC`XF|#wuK8?0S[izZp؎h$ֺĄW=j xۏs^\GwdQ4s@ּVP*TVS-ȧ[! S*ȳ&C98+ /krZ,G+|c N?.6$Gq#`N֨ą!:qV{=)@@v'vkԴhom)l mOZVĄc9}Rl1Ep~o0/4*~u]Y:U8_6#-rpOcb1أӡ%ީ1%:QT(?ZQwy~UkTKE%dpq-b,S>ۄj? *vD,#.k9ŵhؘbrm\A"G&J#.m^CwpN+cx>!A*,m Ќc:pLMi_˴JYldC-ԎұC:WDcag *~,ȭq~iOaySVb4pGP0]"g|\MDM$F-_c>s$KK{K̨bGe'8&ZyVdGצk8܊T}?+Ŀ36={͟[D' ^+ 4Z$ i !YN8rsq4]D\F8,Ksӑ+{TMJVaO\pwP\٤he9P⸭/Q6Č F;g~zh)>If9 Ǡ4AݙՃtfP?(v:@O{- d , 9ƴtܮl>dl_^6,@pv``Zܮw6av<-wɗ"b3u N9y\I=:q({iԒJ=K2uŧ\FCxv=Ii^z}X 8f%yPzwlr, q(pF8WxN0n*U3:pZ+3gR{"7]p(UTd+ux=ݜ6k6ldrG#8< q"Q׭m."&8+I(EQe}("y _ꞻ _Ꞁ6%V;zr:t8ϵ]9àl:UjzYJ3+ޣCW*\e>܃U㜴8![AִgHу9հkJG[\l1[!~Q3:$IQ-xJ󹏠`U sԘkwGaur=kUG ιQҚgY}8l J/<޹גk2gEܕT%d,Uܹ##y޷OZll0gvn8kWzYTO,aLÀ-]}?SWpcU!J奝Ho$ :Md- FN9=OԀq;'>oaI$0 |8sz_I.#Fx}?LTJqZ"t8sD}Lq2K o(# | qY^MgX6$Z 6R:hRÞA 玬J50Zm_a'֓0jfy$TWvuA9 2N'5Qx$}UHA*=+Zfr#&;V7 E$rNMz}x^ExV pG`OF}Qq /5ĩH7;U.74/ 1+|Mjj2Ǫj3_ YW? =eΛ({3X]@+fHR>ׅ\q{>,m܌DsP!:W/ӷT{d2E ,Fy}ITm k 9T R]2=?%[;2I9#9=zu$Z7lkZ>H?:1F7gx@[}d8;O=JWALig#!ۿ?A[^"Α.!!w"Eަ%6囁0G=O#n0A2J6”=v K׶`Bcd0]s19Dw`8?^xږ1.m\yXUN0y\Jr4xGxE54kY..&,YF#88x)JgƨQ sǯ}>`pwm ܱ=8՘ a%<ӧ)JŜ D9εDϯZMMQ`[{k+͞h|xS$T[2H=.[B6q1=n^Ooe<D&mu7*X,NAm֯#ɾ1 p `N> ~j.(%}F5Ϲd;@A]$vmg qkyMc5dN . Dp*`gڦ-ril@hʪJaxCd~~2L 1QA$r:Jn6͕)EW 5vӺBmk0 Lk@.r>^.Kec VYE^HnwI>2 co)'>=Fy$gx^5&"9:X5rq#,ez39c6Dyg1\ӥ :)שh*. dc$f!+<~$Ò֓`3_jII1< $d[TJ̆+9htcHlY,Q?i۹kcV9횥I^Uݭmv@H@pP“M\ׯ]c%Yֹ}Z/M&p[Aǭi]oyfs4lv#ߐro0IoG $` n#ҺԆtyx8{.y'99=Jh|S:{tJ惎-dLBsy@kbR HGXɾ8[[Gr{{WvVQ9^:d|ۥKCf_2dyJ;Zf ~eERqZt٥BRy`{}G FdjƬ%QrᯈSLU<'` xMb e؛x2 ;B:/-3K[W^v+ 8Q'*} #0u'8j'E.XwLgySTRV (ϖm q$;.01kigv yyeAʲ$W2,Nʥq^oSgN>g9khL7. twa '#ҸO ϩ]KV9fvkյ+t=DP%/VUcRvr~)"\26;`1큏Pj܉Ur}xDZ})o5wrTg-#w8F~ղK[R4>rTt-`E}QR (/ʝ:uvc%A۟>mD&t@R(y~C T {o$RAUr0~~[a'sήc1$x4tSyS#Tv]3dUPP3~Yk\|ҿ8 zz4p4d-Bs1{ Wy m>_^VgRr~ci\Y7P@cg-T pH=x-錩l 傁}Y <0JҸԋĨmxFp]2 9sTOXzOvelCg' b2=*6tf!`y>H85E1`:WVZNV=NEt͸6tHQlXd{3+g7r}*x㵅[tca1\3MMN%1:1z+]+,}jM ,d-#l dg[z F#U,IL֥]_B[lpoʑ  UFNEדui3 $>9+1-M7'=\xIE"I6kAaw"e| ǽ,Sew '?Ϯ*н[r`bw؃@'[řneO5HcF7w7V+vp1g'l~I<ᇨ /.Zz&**ۚzZ%HXy_W6rN<*? P Т =%OcZs˚:U9+s87}-w'߹!A믳+<. =WYYn'9W'iwbU2 WYE叐{:bD\޽#ҦH])ʿ+ hx 5sqT q9M?s^ y/Cbå AbǓA9#?vr6Inz0?BʗKLwq={?Qv_Ҋ,O?5xS{?5xSݺĪնgoNW=GNcD$5VVQ9^:dqdH6G9%Z⓱x0ENX#@TMtS[[DRA0>j5:M~Z5h-qqVL.@SQҔXvYm~`;q5OS籕=8ooDwBq@zκӹr-w7"w8=ZKbmRk˪ FK`XvE#Kyq(E$ArHðnnP)h9y&w_k{_<g!;& ۨ΢е+W|k$g(tsqrǝۙ7 O'Ғ7D~LÉF<$gʖua&)Gv%xRy{mW##VU͓,m D cA?KCRژ%[j1C\q]<јA+- .L;v"Cc"l~sq<~ 5EZ![T@vo 207`ӭ`xOFFzҜ&~R7 e' igL{luly qRHNd}]&—WP.6{ 6zp`ZGR<:r$Z>FsycK'ssyxyV!Wq{ e[ijc,/]S=iN:ؗw[~ocFvc&2O{G&*)#qmh<1WlvqʂvUHz~Fs q47-8?? 0IVF-(|{y$v=i}Xu$7\F iN˦) 1i >|nAWsxa=_*9&KkiTl3!;9wF8Pw1QǦk9I"ŵHQ RۑU8GM.[R$y$~U3NWżeOkk_c/a[#'kuzj*L|@U3Gҹxϖn2:U@9iVQwե)v.'$W:0@qXڽȎ?=cr {cj@Ugqc*z'KTLG?yAp8WO֥$VL8uķPH3H:zX.23`WMg,E^0LOqJu'I꣩`F^ 9Uq#`0+Pft vf{(J:#8nJBQ', 0z [s:z* ́FG_*[m;ytC#,~Q?yhL kJґpq?5?ؾ͸FU9#9*X$?gD\ێ95"vZNN%X}[$O\Հ HTdҜ.JQИsNv~*.C~9Zf ]wG ?ai.t&$Fv nһ8+kaG ˖M\&CKr\$=ӤP9>n1I+3rd$On3RuEu tQX<ɶ;ʼnݲn ݺL5̖a79HF0-'"U?;pǑѮ ݑ^m~v[ai݈*}g X NbOw.cԏPiJMP`2;.Bh粈"G<8ǧӧ@.'V[u+IFR ⶯!6 IJ2d.y 8=!iG39LWʓo =>QSDsOuAem>3853Z|kUxqJ?xFOOQ6M9f8đ_qm,yj;B;+ <̌dk[G671~g=FE%Ƨ Wr@Xze[Zh*"Fc=O{&W{6CpZ\aXMsXK (~E(@Kna[N6\,zS|dJI=jH`E_"RVG=I0]*k1Ir%:tck% (kHI $R{U+?H :Ep#>rdj dx#+:cT$pEsm;y|эLul33/w]eYcP&'FGjs0 K|[gvE@~FG#ڤihC1ϖqwj ̙% 2@U68 `=86pqӏsOŤ{3C[[In"ȳ4 gP,3WJzFסCp;f}? k^I̮7 ueMGH)Y}$C^V!FU)Jp9;DU˳`0;}kaJ˟+,sK_5|G;hT,mXQ2BmCSO֦^ZYdp&@ ` w䚎II׈1*7 jڊ CGpUAbq+*|om+qnSfhY${%u(KƌRU$?Q<=*/1 ȨaK2iSr\lU2tMnN gq]"YD*@ƳHFX# ݳlI0Sg"*Z \P+mEp0~a1\*0a8)km*)ԟ-}+ֺ"3N̛Iaċx»}KVٔ'kӋ%$9uv^,6qbיOBm̫7( z98wM"YvἳcWTsXfrk~jF(qQx㞵p3po!uۅ~2bMohx05[w%}cyr*}ýz7vr6Inz0?B~KLwq={?QVfv_Ҋ,O?5xS{?5xSݺĪնgoNW=GNvb$L|>-%V;zr:t8jAFB}Rl d~4ˑik$KRGSÎI"$3, jTQv [9qzJmZ9. Ks7ά^ʥ-Mܤy8N:>$h3/0 QC2t\ $YAtQ$hf1O] vm#" yjweϠ9v;pc˴ dzt isjsu lqsFmI\}ǞgA:G $XeV~?t'׈o-zuϑF{ɬox?U}Nf˱ ~wn 3t8F~Z}M -d2tH}x?,bPjuZ8c2g֙ ,;XJ׺5TQ}3JO$'7[o9,IY*"嘓u'=+~ԦdtNA={*  m~ >xs=$e6✏4Kۈ~Kǝ!{Q-*[AgfI=kJyu8%\J^KF̹N3"(8>sk#8֔De#DCD8Ao^z׭uV/||U^ӌʵW~sn7b ^8Yp?^\ 0q{V ,0[FsVY^:\Y7PHJ>5o k7]ŎGʔtbT9pQ7/*ɤxjQɂ$|*6PĜ8rH dؖ>x@ sy5r [`416鮧',$b8-f8,pk Z[@ZEYwn.x1+,aN{t@. \sXr\H9Nп1'U Ji;h[D@x/׏W&D6\+s.q"A?1|t̹,t7WIPO9?pq-ͻiT1zI}1C!=>Zqag1\uIY$ܟǞ>nN޾{F5u) d`;{ד~(՜G1t.@#zEtzP۳"(*! p}O5ijjBDk-ܷ zwf}9Ge*kV:ֽ4JXQ9<&&) c7*ngj6sA[P6eZ|8 qHK, ,Ae,gH-ߌУYd)@?{bG"6KqwT0F^r;zױ6?Hl1ɴ&,n$WiK$-I Y1 czj{ePfXs8SG8"K_"=A.S#wOOnZ͉nQP1'Or02d$mN3X\XiZ\05\AX$h냖ss덭{= tO"^)'ܱ7򫫣iyQ؀6aӒx~U7<9cim Jw<Z98~EsLvz\ik޳~D*0squkXE0^F9$׋^,t{ srpk;lu/u\]evj8q!e?{x>ՁL[i1he cqœrK*ݿx|r?*#[繎2v#"@t;{T5tE7\ls( Dϒ0d)inS F v׵sZ;&PE+<,#xuXlgGܩI?tm@dy,BI If[_\\ˤP8ے~#R+mU$PNoF1{h,nsZ Ko]ْU'\+u=.K'.\ZcΕ K,OĂv0p1鋪_ 4;Xc*LzytY[D!sBr3%O?~{89Ln|KHK6cq^U, 'w&s2)VPsN縨t땺x3R9.H {cS2M"XU 6c^y]Xgk/m Kv>PAZaHF~x^vZS^܁%Hͷ6qוc5X+tksyY)P3x=ݓ&<8?0< QȀYVf6yYe;Xq˷Oý)AX)AI k3$8ߵ1{u]kKO\Lv!XOVf4rd9QK8ǘsѴ7 : \8={V+uPrsП]y BO֕L{Rm MKן|x Y2|HcҺ *đ"^֨8 cj!sI|5jc p$8_@sVe2]9r09JǸ۫b;ssj_+/HU` sei#50_}"1/PUlJv{f`p #=)mCǽvt?nZ#p+ v]oi6 AϯLq\|FpdSz}+ҝHI9 sOםvN~"T%w?Zj c?c;RW\SQ7/Ĥ#ak|l.F1mF~#F)|$ˑwLGsч_fC;[/CE_Ҋb'U뽟UnUjzYJ3+ޣCKKWѭ,#0¯'p`_ZޖRǷ#nMY&*9iC랿ҹ12QH֚&mFA=kr es ֔ Kyf2EpƵHJӌ$ R)25GάK'IK5ؒ!'2WzA/xxi_CT<5^YDAuGl2ATv?JkIu!]A3Y"M!dt8cg yfm&q+_Gpf<,pˌTkj54h߾:%yl'<נ yZ)7"_q& c'X鑏ҦhyqM( p==Ԫ\'4W'6/ Oqsa<'=,˿d ă>vwl=kg}kV 67 XC{eƼn-VHT9VU*I͎:\ VWc-e6hQ.R 70*ngs&Igql=z~uv[D͸7wW?lt˹mIT! 0H/#ݸʢK[[he3fIO~x'Zi$he;HR%}ó8n 0R$OVOC過Ʒ_IEk];q$N;syJMW-x+LOvE5{ib3.>{z5hFr"1ڼZV𼰱$9<5ySd]L  !qs'"F.XӨ>j:9M%fHH|+%Ti$AD(7"X%%;I/Cַ-ⶍpdv\s;gZM.WZAĊYG;FsMhkRif,w;;nWVF|!5Iha@@9' R1g* ;+ٮu)/$>h;G =sӦ+`6yhcIYFA.0ATmKCNs&'' /N2p1fyiRK}t]:HI u=J[@bO*4QWY%+շcpnkAΡsS8r2@UܞD(B;AXx>#y$eD@YrKK"("'=Eyo ɇ$Nsq?Vu ]vC: b0;=svy y(ٲF==3?P+cs+r;E;+Y~L\`O=)rsZV٤ 㞟ګ^,wqB?{UM;քdd7JpJ޶bfNzfiA{쑂؞3֎4$P2:8b+{ng15uM\LUBnG'kdhF$H<} P#'/ӳ E6 $݌=}ɭkQBYfhr{hq5j["eݹd @^mH$EU!^k.F1mF~#F)|$ˑwLGsч_fE/CE1 p^*T p^*Tn*m,ӕoQӡG%R K"d.:VQ9^:dxܼڂ &Mcg} 펓Ac7NJ *S4V\g2ULON+e.o Ó\֢RT?o0g }3\P+ڝV\& H1F$It\!͐5Z>q.j̛H T$smjwb_v'Iv9+ Jr$HAy?N$/ =O=?^+a[HS#1-n`Nr+ކST;|j:Ǖ O9ں &UY y?_ּGKkKG?8>*K-۬ cߞ+N~Eds 1x֋vW'~p:=d_R+yeD9 <ұ=>lH&V 'C>^K%G9%QFT=kun&$d ~?&[ue ; ?U3J7Qae4dkg$.3}ik'RP]\}p[,12I_ V۟~²|AℵHgrQYy$3ۖThJj}KhWvze{]߾@[ dwsEN.nps\\jv z}.g!Po 1=FONxWEIPQ摱kahUӌ`chbXZZpTy=q{gSޡL+$y #ʫI>znLsd$py TI~VۮRH5bV7[=O޴l KhiG%s;g}],DFwd8Y Nc+Hq*D .@FӻJ1U.v^' ۡ")8D8~QvCWlxOrr p8Œwrƙ&/u<|.I 1Ͽ] KKwTYӓѮ5VL$`nIcSbaae.#'*\7$t8+#vǺu{QNW֬VѶ|q?~ՃNΣ#֪:Nq#zt)q XPɑ}1?!Tv"TJcgTK%ͼ$"H<-~,$^bg_dsG1i\K,mHI؜d\ .ce`@xfشj$~[G Tҥ^F,^,jFE-l4Xc4Kԏ\kFJd")e߷ 8ߍW;n isvK" {Xʕ`qۯL~o $QdLuX- .>΃ qM !ʂ{@5:=l~zRp`À}UŤd?,AD=~>CG 뀷Q#neν6Oi8P>ﷷeVI+8hIA?V9m8@8*6&0c*H+A}*o`DN>^rN{qX)NER.bYݪAT7}gU9*rYr8@:~#8+ΫB BnD6I)WmAB`He#,sOZ cC=>\ZҪ{%ܪԕ>$2?:B\Lgۃt5ihgr]bIVuɷvHiֲG8u4T)IPZ6Tn6i=w̪*NG?ΥsϽT^KP@=Jp6\te.ZVm z.T`Py2d3 P\dq\}n"ɴ˦9ecNr%ܱӯӥ[#ꣂsDZ馧Uyla58> e" ;gcc3k33wcc\|GC9~3W4G!O6 U;(Vf9 :zk@17b1㞽Eu ?-Jf{^vývp6te܆H2m68#v1&1)d[9fSvg?jBXc5 (%uI6$?,LGM~z|hOqk@՛:W#WZ sF޹uGlIir?*O4WKLwq={Fk.F1mF~#F)v_Ҋ,O?5xS{?5xSݺĪնgoNW=GNWwYv@"Q$x/"gT_ZޖRǷ#X< ePޥutLl+A=]JUm 9w{uҳ.<[mY fM^-`HV2ORg_=4o!PB9*>>ЛO{{ [^XK`DrYaFdbʨ$QKR֡O$nIxRk*,m_  ˟γ%wE''6V;3(Ņ9"(vЙ@=[[,^^8nNNb1ºcˍ94m &i(-vqʃӠ`?7Ol4kXc_8sn 8mtDby'Ӝu+sRWq`1T'2$6#/K𭔒]ʯqrA8;WIB#iU|=fԦ̶ʭP  ̅~Eei>(uoM|6A?;nrsTevrJrx}i". 2m]* J'&EItX w`ў}Ҽũ9\/jC)o -~zV[xr2^ݹY vrIz6g,}#n{~=k#_׭PGpmwzɰD XԀIrFJ:pWl}eVh0ag ϖ2͎Ӑk[D%̖1U#!BOʻ[Tc!ámOArO2i $"'`v1N3WS )SvgR.yFw5a2kFr -n?u>\ 3dq<qQKm^ΐYR̠9?Lh=cc 5E HY"aׂ;tX;xO@Zjor֖Y2H.H݁Z_gk:TУY|uHǾjM檵ؾYB8J ga8WF/>XĈH9ܧ8 `d_jSx{}ŕԬӌ )F}9.O=tar0z9xFRWl !?Ez<$1pAt1Y[6V#,4ϯz~|K$hfGqr};qMq[0u3cX9[w"̬n4+-}ӂ@M8>bqڄ'2:K\OL㟭fEuxqe*OLxZKS)'{Jh*kopLX\~uMy]uƩoC崇%\n> +h;nqS5 >Vޯ!YX882/̀9'zwg [4\!!{zNTđqϭoϦ<o.˴/r׷\7Ќl`wR34YP&o]*,G}ɪb߸ca0'&UW\NTgO,c۞C=:8`ǿT!P|\gqI'v[?)gҴd3糺6D2v[xݜS/1.Ӟ;W/< b>ճ<]_daTzWg\8;SI F8p <ҍfO9+N-ʰ}{U[(~e,qZGCb=+D*9r sҶ6QI(oOޤ:W6D$%s=O#he;vFfd02  2n%Z?%,[ Bpzt쾓0RY{qV)/FUBy3?to[r$fQV#D W&Ӳ.WPpA#Em4ܤNN*7c$:V{ZΤtQkf>12–I6ӯOܽз`OA\}jխ41°k[2p߽!RgFc-g'lɏaz I2zWEtX,%f `m|s7!{DFZ*x$N2r7Z չ`Do֪HؙE)K{!hd'ܖך-oC[)`^64GkO*JpSuGZY6Q%[Fr]yS6&d%ח$+HZ(suϹ|2kzҵK[P#wVgu_^BS&0I_ls注5Ův\)|¾0 ~@p3$cӾ!6бNF>f\1*{ 7@@@8* KIGsм?ANA=8z1-O#B1?r{vsAxCRy9R<*0 1U@>hvzI :*3ZZMhm;d*X( s{jLj{7yŠ_֙0i"$mEF&#LB{ ׳ ?%bf;?ZӮm`9 ry2AP> t1f9cN=* Fد``^I80ةi3ԩJG==]*2~[yQ%zTM.XDe%NH tWK^3MTJhLvX37m,w+&ԓIpkWE%6UG_[[iI8 MoiEt=8ݜgUSPu 9uKoY^R9A\;epq߁l _S d*xs$hʜx?\+AE{E?dujaFu[ٕ[]p:|~8Zg2\U{zr;Z LexiSgB՝$՘od-*]B~?+Y?&kiEgۯZhe:ۂH Ivp˸zwwSӂܠx$M79UK[v6[Xe8'φ3m.&ж #B/VTHQpY?НMgj"@:#'<#SGC*MQUHa^N P@=qS.se5~ӵZ[VvPl" G=3U9 VVWsc#8*GQD7>P9Jj%{ؖSZ¬mD?`NiڷXJm㞝*E{y@9 n}9Yבi~s`2oquO$ jfCt1~C 3$ږ_9'l2 mۻ?Z"7l1bd!sE]ɰ.9!]On80 ԞΨE ;d=⚒ $1~\;{] Acwp˔8#?K%ɹhqrkV반Q0I}N7Rn-7̫4XvrӠ@e #RVe>Vau5ȏa!Rn=z~[|H$8MU/]%Ӥ ƒ5 2xG]5iR,=iR= vCoڴxV{R# _5&kIwn(9=+>[AўqV4ˉ',1lq 3br,Yd_$EˆOUsܕM- ]9+pQFv|kw.oK6vά̿LݻW1F\Rn1#N_ծ4nOG5,+I,13I?Z#[Jҋm$qѿ A幅$aBlje#NvsEiY@J95 xVFXXΛ{3hMu;{K%S 28 vGIPWm #zWAi&0 \W,VNg_2F#쒱 w3y'w -O>ڇSbESYzHdx2 XWi$!V;TcU!mJX$zVOr+Ѧ2spA4s5 ѵa*ota1 < !)ƵkTod|{w<9qVQdZh{3"7c۲SޕkZids;ve]hYp@VCXZz\n>V2;^XYn,%w@K`Pz8*HYr1vSBKd^k=#'mjVa1;V Ƕq[~?m)ц RDg-n&ҥ28eQ3TetȥsB}WI֛qqvs .NsڼN9v7e}my )dt%X0϶Ed-N[ hdw`峲ĨKb^H_#N}eqV'Hf}OJzS Ƹ;J/8cRǧIci*YEry8c\jjLFU+ijB`Ecw|cݷ!UM ȐG]܍Q咺7htκ [CǮHB-Bedp9]sޜ>#[-i7V/D?QчFFU,,q/ :[%nkYO5İM !n@ſPgkos)N?\u<I㡮/ɥ0Esor)>L3ᵈAmgJmQƵ%7-Ɛ86,$>zZ۷KɖRBNV3u\e:f ռryU|d1P͠hZ%&V1glq|'tΧpAϠ#PqIYH$ /nޘ-/!(6{8W~ n:ո' [_H#1$H8p#R}'*zϸdYm2?.ڮ2MS/["䧖NTߘTt FO歇GH_̊#_aKFmщ'pHbީRq_dWP4ȲʈpW<~wy`sY:vXܮ܇fO!ߎcEp,ʩpx2V쌛]ӥr!O'MQ29R+d= :vVr. Psu=h~((=l^3"ZGcik d1̙#cl;k[m,+ uJ|Ctdo'HdIfmE4˘d`VW)9%F' tqҢ)*m A;t0B$t9rzU*zU b+PxMM3qJ뤴XcXc=ycǥr\SO[[**|2:I*C[mQ:ڹ+i8%g=M)bp@U YFAVYzXy Kĕ֩ڼJVX\ VrѢf(ZJw9 zW9㟒,Jߋ2ZFFN[v:t;jy#Zg$ISp N3G>Ҙ<׬y^]eۻ&#/uqxIwi#n6c #5Tv_Ҋ,O?5xS{?5xSݺĪնgoNW=GN$G_[[J[oK)Fv{tqsTI7jInK+ƣY5&쏕E-4#I?.i\v#֓]6EbrQaPFqZE%ԦG4GBACVA*^OG欦#QTfI1ݚuo ኟqrT`}k3!ʒ1f֮Gd9si}2`Sú-T}GZ2g |pkK`8^*@\kzkR}rs[֞/?(ccNKNplP&Q,@=G#]41m9!hrIp[mb z,݉IK :iU <~ZE_:!QH@`dx=UmY旒KulUj\-N|y\⼌LưeQd21wdN[“Џ P~\Z/!=7.3Y8JaѐDOdw ?վCs^.xVliV܄PzVњ0ZS+ i:H*GZ_kHԄKFTGO ͧmg|Uх Hj2Bp9;Ͻ]Zb`[ٌ*6eq鎕.YJz]7v8fU}?l_ _bb͗ =kēxB8=TVSʍwĨ]ISUWGyq}W~VhH4\|ӌQI!cyoab+_Or]$\$y~@ [h#ÝSӞcGuXոsv1գKjUB?\SsWQj`ԼIeE!eRU ԦK>k~ e!"s݃d885yQr*Y y-hN 1á溉cԢti4PZXʸ]:-g_v`IU6)$cTs+46RW-D |!]x> `M5Wi A=^$74JgFoT ;9͙Wu(8qן`c⚕q(Y# 294'q>ǝ^+"픳Be X'p!QR=N9^%RVG <[X:a*z`᱌ޭeܻЩ1ߎO/RBHe|q~ˠxJF-DeF8+jjVqճ~5Kmi-$IrHo>y-,KulPŔdA6m!}m\gm86;P]BX\M#\)] M%ɮ/d`˺}-?1 p8#'FUE3Bv q\XkQ,$BOW<.285ia(REH 85G-E$'ak {[ຮ@~}}Dkv wr8'89T֬1GbG8r1Xo9b}3^<(fr34x%(R A-rE.A\8zgy3Ɵ6@P۸\3f,W^F}feYV{m㐭֦QPHQ\*GDR%BvuMܲg)w>\cElF =1X>6n qV崣uӷX630L~)%L${FIQpO8CKLwq={o> .2ma:fPQE/zg/z۷_ZޖRǷ#0Hm%V;zr:t8=i `PM&i=iee/Μ.XcsRJM +CftTM+uW.#qZ#& E/AK`6Q@ SF{Kޒ~V#hXK铂CqVQR0GӚ#֊N(jLY'G*V&i,]jy{mnGΦh_=59!.pGQx|Z\BA(G PrS [>Y}Jt9tW]OS%1^Vc1ޯYfXkPKXytfDz{:*Ք|7>\q\UZx^lxHݓֲtѥ-w % a\χ,vo^r tV^0_/+]zL(_0tWVԣaJq(cb~$ՓSr6q3VatQrq)Bf-pϭ^Xq DLOlف?i^CCa7w@6yU\ +wFk8<꣙${ᅙ$Vm~-cT^ 2}5#nwqsQ4ar@ϥ gq|`vV9ݹ>q?kxMό9Xq-w峚Z-O0PA+:՟.Ҥ0w*5PvHpҳ } wjn9PpV998*#xqp}b۝9h.ch 66iq.4g?.)Ѓ8Ug~`b"q.w\PE KxGTrOaڴu]b G\#yj}1y'ޠWkXn K~0yUiHKW\Y-Hݾ2pz)}+myqbux#szYt 4s<^h+b?| *kWjR gbywxVw$r #קxѷInc\Sz p}1O*j&zs^IIwi#n6c #5Q%ݦ\b8۞=GP7QRYYJ(T>S<pO]pO@vVQ9^:d|u_bۯJ[oK)Fv{tqs$ C֔uMi=i Lނ)B@ƑLfC@{Ru>B)Ɠ%INh=(@ {RKۥ{P ){Q,!i) IN0:j1_qgQާ+so @6VV)VG˟CKc}ZXRG5:jWQ<8$'^0e585{QZxhX ~~o¡C86c)]r1Xh?#h&o0t~jÆ+y nJNyړ$hZ=M0O>px߽Is69Z;>07QfkZMH#q\'Ѫt:OK6XN?B[w>SdUH{/Adq~? o< a{r V]%U-$TkAI cO`O:q@swEZC:s?U+e]cwUFltV'樈 #ۀ s묧aUxkQ3E+cqT&/ mY͞T,?1z|DQٌa;9#oBBQ|­Z\tX}6)ՃF iΌ>ʁw1U_TNBA.ϓu2d` ]]υm&Hl*'PAyAqA&;ݞVf`PԌJhϰdRsڌhSG N 柅 (2)֐N8RwIZic sNR@ 4SF(rE/ZNԔLPQ1E'=>h)*̿CJ(wHa¬G),zQJwf]ɌI!Ub˔p\)̇*H)r|;,kPAդ2%?T8n70_ҴmQ} $|9̮k'RS*Y ⲕ=Ѭku;?&\_ yKqMNFA,bo c9c47s$! }*d[YyT7{O%ʍkjxbWe`g88kϧ5Dfǂ 1'klu[?[*]F3z~Al'g(S}$Ev s=nAhdǥ{6rNdvW𶗨hnPxRlZ9CR4L3ק4@ti5_x"ضA煕{}E>p>yZ9 ,Sp,t[a4v#<0qi/[ mQ dX%uG5ҧ+3Tѵk%O_^Z4@ vetZw Z/c8!iN?z҅>HՕ8L~]q18vL 'ao-`tL~]q18vL i. 8}~CN _;B}o˺t&'w?ߐ铁t7a`:got>O}Aƕ}WL~]q18vL i. 8}~CN ƅg&):O𯬗L~]q18vL i. 8}~CNo@?o˺t&'w?ߐ铁t7a`:got>N;ݟ)¾]3MwXX}2p.,Lbqs>8@՛_^cW_Y,Lbqs>8L~]q18vLc`*) WL~]q18vL i. 8}~CN q"(:@WL~]q18vL i. 8}~CNO#o c _[.,Lbqs>8L~]q18vL $`k'a K"+e4ߗuLN>ݿ!'o˺t&'w?ߐ铂csg7 G#/¾]3MwXX}2p.,Lbqs>8.3G_3'#/¾]3MwXX}2p.,Lbqs>8coG_3?g t7a`:gotf3:dϑs YE?W+i. 8}~CN4ߗuLN>ݿ!'g G#/¾]3MwXX}2p.,Lbqs>8.ȿ?g ?o˺t&'w?ߐ铁t7a`:gotp>EZE?Q@𯮗L~]q18vL i. 8}~CN /#/“h#Pg t7a`:gotf3:d%s*uׇo[WL~]q18vL i. 8}~CN >X];S|ѵ?*Satq+54ߗuLN>ݿ!'o˺t&'w?ߐ铅d;.bq^߆ I׮x~7Wki. 8}~CN4ߗuLN>ݿ!' 1%i醷c*Qk,/¾]3MwXX}2p.,Lbqs>8J/rY--Escz{`Um~yԬ.3W.,Lbqs>8L~]q18vLd٢WimPFCݏf¶,ιQds]o˺t&'w?ߐ铁t7a`:gotkm!C{N3T)7]tŞuz"o˺t&'w?ߐ铁t7a`:gotXx!}&={yx;^s(70M{o˺t&'w?ߐ铁t7a`:gotuэW>vC"8k)嚀n+4ߗuLN>ݿ!'o˺t&'w?ߐ铆.|cs~[*)4}Mѧ\xϔUo˺t&'w?ߐ铁t7a`:got*Iu%ovvn- 9hy -:4ߗuLN>ݿ!'o˺t&'w?ߐ铃"9Q"#w1IϱY]3MwXX}2p.,Lbqs>8^wgLQWcO#xt-'s2q U4ߗuLN>ݿ!'o˺t&'w?ߐ铄JھW#j?. {0tK}6f3:d]3MwXX}2qsS3KLwq={gق x"gGpnJ?<ro 9(,c)+X:bC$!"ڢ Q@ EP1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P( (?nip2-8.7.1/doc/html/figs/snap7.jpg0000644000175000017500000015702113414613100013512 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH ENC[sy%b{d AG]HC".IJiԈ]b*2Tw>l4M.~ШGiRMc< 3,PRGpݷW:²F{%٥X 1q>(AmpO迾j#"r3]C8|ϔ8+oLAwi,WP11NN0G}h΋|'S H.ǚkKl]>?) d`dOm{X~Ȓ5 P,H<k? O&{%R+WMiM"AhD UbpǖH7~3[yuyPa;X+:=]l_o?bAqP62Җ WC[5'³Go&qv[p=j^^$vMG *|Hܿw7C5gx|> kOQɦT{ 5;DӒkj>U4ɵ6gGY %ԔQ.ヌG=}(X*[_qW0i1Yڴ/b-ŕ<}qXLԞ-ŔڇB#;{^x?ȣM`&־CϮw$[f9xWVzf%;DW36%JMzw1"]mf,AP9'4#9dn6`rF܂ Bih2$Sl[@a*G Cֽ:K!rj?n筗*T]O>.KO[T${ 7tZVsȺPDϑ0i9(~<]_mcQw=lU/QO>üm6 MCph85%xWB/*7/mn筗*mx-YIUhۂ8 4RmË-UH[o/iնX#p27g#үtڬUh&)BЅBxm?Z~]s]1"fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮ`LQ;[|zy'g~fۮU #Kx?ȣ6v0(࢈>ࢺL]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_?m5&Q[ 2):K O\"ФRFwKD[/٥8lv\ZS5[&N߿>)kS}VES8uj[ ˸X›Y" 2 tk[{(qq$oø.ܪcu5u\1xsoc2EwǦq-/.{+R)(ԤAA?6zs5|AXQq8su'ݳ8j>{<^!T8V9}3/Oǻ&bLF =I#S\hj}儲۪XOݨS LVDŽ`ay X"e  z8J5#,N n0f0)W8 u<`szv}=Y^S|9Jc Dzx1Vꦥ] (xX-~owCw㝉~wķZvZ٫jڵ'l*t$qg^/cJXwʓNФ0Ǹ۟[ˡnxbY6 TzNV5uZ8xKH:nid]fynqWjngb#{+S]c]zTXsޤh;ɝ c'q߽emg>W_]mjMyTe#R PCC7樱^V;(T|憎?6+/.!ϛLUh/Qˊ>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eLQxl ƄLm,2FEtF g t_OLi<-[ٖ'WBg0X@?Ivݝw6s8[UG-wI)̚,q\9> 7OMFc;F-fmO+CϤߚ->~k5wj8Fq"[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6KEoƏI5?ȣj8@w[+6&bop} s]n4ۜ"7!Gr^@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*tWOf#Mo!)_JY6~TsOၥw" “#?Bj4DžV(!]8J(?͛|.8<ٿ[ϼ?)>_]luև-QKo?mc-ɱ*dgo*%Qđ/ r1SJ+Y6~TsOVQጒG`㍤J_[ϼ_((%| >m>\EW(%| 7mћvUDW2Dp*ӊ![;tf~-7mdT/%FPF2rNx'((((QftnDE!OBI=*((-E| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>;{Տ[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_( ۟ʹ }Q4ۖHcV6PJ|1Gր;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?JiRS_C$}*ŝffBI' O\"Ф;_,h>F=tIJ\ZC5gxUMt˿QF #گO-3?Rjt:ZE4pe uꃣ9&\ޔm:QĻwv3bjZ\OWL"(_ka9f6fI 2x|:eGGXo\]k52Xcw?\Ro| [?j" ).UxV'Q 6}F:tRF;:QD.5u',F=E^Ag=jzֲXFc;s=I5֟YY4ʖQUH =;~Z_ mZmRNRwfP-DpJ $#&?Iګiz<WfM=wU! 7G$iJgbYВ}IYUƌp\,cDoSѾLdL. g[̱In9wj1ߟa9{VSxWoJXo}]n 1[ZZY٧Ya,3xR}nm w_krd>tʊ?JlF)-nDQ)-=,]Nڤ,VKIXFB3H0Ҵmqqrm˴lbb q)mj[K@"Ea@&O>2 uv #NNkBx\$jO#~XzѵKˋ;QHݙBdI rA2k7[&+7R"ң"zZmf6w2{(9Y14UO4o~.p]6gm.Rm?0\3Reoί>)_m?s\̳OzLv5ZVaswҳ!lCx^fB?k:կmc6+{:*Ivsºlj/q#Wb0a]ƌyl.ZWaq&gs a s8>nVR#0O#CKg{‹o Aj \am<WϮXT[oûi8' އM|_愖dxH 8kȞ9Ƞ\6ziG"/^Hxԛ!uuχb[(眴VrZ:pꠜ珻֣B}2N{im RG"198> _/%j ^,3_G,+Q"Ʃ?#<ۚWPkdMOr7ʷ%Lkc8(ן/&7U_0@ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0_ɿq]MOɿr@pQDpQL]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%]2ͧu?Uj6跩RLњu\њu\\coRAΥ7qBzy#:cC*P~`QN2Q`FԑЂMOE0)}>E&/[P^ϵF/[P^ϵF/[PkX$Gi`ay 8Ԝ՚((((((( C03 FG;A$q}>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^2خA˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB+ O\"Фrqqg]z{75/[1KdPᩱS'K Υ7pB)xifg2|F'#*I \en fޙ#kj_wk~sz <5L^>}_& 9:v4ow;R7{Ey/Y#GMy'5Nۿ_ܯ\˧j}دOxM+$68z.DJc ; D26pAVÓNsjzڮ'6"X=p5]yp\\ɩk2OsuN9ǽW5y4cC!0){mPx$WG|F%I sږM=kQ] *8c;HsBcw+j0m:HmbTRH cަ<ڍ͔Zf-Ū3K? mSW7 :7{Q 0I]˸|?x}+J %WR;mD{A! _JZ-RmwmLz}*⫛c%Ɩ v yvgiMk^kմ;gϓnw]s?o#N->׻:1>J@3=um^%gb@ ۜXsY߹{DZ,Ѹv>p8 ^hj^e,dܤHlaSO^76724 kn9=.uRKS@fLD/>ET~o%!u tl\ J9 M>s$04b}ӴTLa)GƠfXS:mNk^x{TZI5xΤ2AW #;F 7q0ZI<,6]K (2x'r^mԡH^9.Znb|mh[,Y:Vy wsEUӼukj6,v8Y.Ax*=Olqqm|ou6Fߕ6cvs ~&mՊA= ;|4Ã4u5[Hñ H5i_kJ$[X| ʱR1zMRX]5u8"XMAek3SiwϨ\=S  9ph 2x[i%>Z;N9$cۭ,1ILtli%x sU9=Bv3䷎:eM젒#xP9cs]ߵ̧tێ1~-vo/'83 d`xQmZenVk[NJcb`M!_SYZGg5'5:Ee3,bqc붎ח2j0G&/ՠڪ7q}[~(Ӽ5wwi'>k^JᎃXQzGV%%v_՝pQDpQ[.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pBR8O)8R3cP%?s(?|uѾ_B/\qto|.8Т3ĒpkHebЮ՚_wV_)}qOT5~s`OҪZ*iRTޥ64 hp֧Bs)* oMRx_pU@MnP'JN^( F8>lxU=v;{n-l%|NAoݵdՅ;6 `ozMK×o4SŸmx5,0 3myיv?Y}+F`C2 mRAF0j4]]=K)I]̬vЬrIb7I%:vD-4Q4d[*xUc^K"kb]dg,p:G_밺]Mbn&k[KU]Pkg 0H#ߵAVIM=ik ƀe* xMSӡRv&$+jCN e_˚[oEnt=F.Brb# qGTrxG{/XyKmMI6ŕ+4TW,; Tv}.Υ;6yn2V7/'zhd!1d:PW {;Z|Yh.&Xvc_(I`c$ իr=FX1n>mxYvA$eƥ%y)toKPO*Ee#)aGόq܊IfQ' n6a5=sF"+-Ac];H m)pOJxdw%sOˬEa0MJ]8SK)1]B5Z(Ð 'i5Яn-XKks(A~K{m,o>ӧ LdBVkh EsEA$rs)_5.3`Qu&n`1$Vψchο$Fx8|zI8ⳛͤէ]U73lu=jQTHkq EjA$26{sGEt0w".O$Z^ެujvǜd`Si&ԮmnLFky'F2W*+} Xu/"ZhEp1yTv:ݯ#6ĠQFG|S?~_E.q^iZH{J&teӭ#>l RT|1Xm-!pMHV{_3%n-N}3dfT-͘>峌cз(6mnwXǒ=HD(6mnwXǒ=H3޲"muyd.3 D9 |6CIɫM)Ӵ{i.M. w>RȤ_>5KMʎQKi6J࣯k't dXlZG;UDOnoRE{WO7W``v 25lREeg9;sE}; P FՒ0 '@k>“K\gk-lBiʜt8W [aH &qf4r-F[Ckuiq,]Y 0#Zvd潅*VԜ?5ZM255fxą$Z|5 *zA?U֬n5iK1==?_.3ysY)Sd~{š2E,zc֞l?m{'y?Ieg?aRW{c@,s{ݝ4lΩq1A{ExMWןM_(j+(j+OkM&171d0!V9+ӡZrIsH yu=ffB0`&iߎt-]{ŪCQʗ)#q zѷҧH8Q}Q:g4iG|\5l̡FEU2x__e]BLl c!?]=?J>r-a  8!YԾӅ߮y1I5;s[N;2$T #gP:unzZ\eE!.A#$/ҸKŚ`+D+|GOQ[c)l8駐r@ꭵfVU<40kWxcN"P(er9P0W8g^Q7adЩӔ-so{RK8Fc}v#8AcXXjWZi8r}&54;Ni`ligܼ;7VHlt _PSDi21z O#$18e s\xڅz JYo;co>>\twƒf^srgO#mwöՍ F7|r#y-׊ 6BJ8$བ{E*ʍx4 ]Fsj[8OZWj:ȳל?)4nPY{Ǿ@V:Wy ԍEspiQEdQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Z'sEoxgX:'sEoxg\7莼WO?;>࢈>ࢺA_y/ν Y=|]ue _GYŨKS(Wu J}"~\X5]?jUniUVH8t,4+eXv 󳜑qs=ydaqh`;+0kW[yye3F>`O$OOnUD:ޕk y~Bh ?c^qoy;7.h[C &4vPȻZpC;2=OnZ:|nUl 9׿5ZV3X\ oU9ۃ?Zmjl6@;A.?ȣECf' Utgqesm{BaK{}+O]>U7Q-VԳZuEJNb}T?>܁nAz2\,l<ǔMb'p >h䃑pq㑚mK UK6ᷨ{0dzSգ(C7VZV6$ ~\p'MM5މarCm%A⼛>$:ު݈U 1O^t@{8sKvyXTQEvEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!\m[@9[Vs~:_ ? 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@q=Վ 35 m&[ y*-@Go K)(I sjcy*B0r' yNؠ>s(3`S6e;4KRѴkA Nv!L۾ ywBWi9FzZ񥪲 W/nl"o63XPv}r>`1=]X\Gjm{_yZ?,O(lL{>Ay8߉2DHȍ+#R6Akԣ̫![He[9v'?Z򯉿 %V7XT(*J׸ ZcOk;Lk8NHF[ Iփ%͢ODTO"6mCWxW/kRi0U88;O99W1kf{NAme܉ v>LIAm4x1P:gYto7 F Ťo\HkAԎZ<練*yޥIEGr3cy}k׊X4gmp<2:^vzDnfV]@A9c{۹nd2O+w=ɬ/u/Rȳל?~:Wy 4(((((((((((((((((((((((((((((((LKں ZO /rEt6 buמ>bЮ՚_wV_)}qOT5~\X4֭?Ji0'tZO"O/rXV>R\4K8G"b)rncO^ I֏"O3Km Ys ]yc!n795oNngR2vV!{$ъJpDkׇu]g`3qGiMaQKm?6y=X#6̨$ :YOF'E'W]ϗ7?<U?*7-~be?lk "`ɭ$k%4ʱ `{p2NOO%?s渼&Ix千#aA7;AWq V dSD7 s2Mw[o Ǔs%YGq*lstJгԦ/-Ma*λvࢶ[9)cf?)o`[ [c$уǖ g85oxSTR@vڣ9?Tuy8nb$?w=?{ ms@|M@^[iӮb7\ \7ەKÃݓpxO'=w>tĐ&1}09x<쿓OVj_^(-WoL\cWKR;B%q1(Wvr^+]?bkY]zc W0SvXn&[?8r3wGևk?QS]/Γyybm!1-70'aO#~5|44j0ȸz=ivwk/d{G/(fI6c,ѓxY/#+VV$0*^` QOQ]KbIV6r6 |zfu&;Bw;cޟק+]l3*4q2*F|`:Ӣ`@m#FI.t@zҗk~?خ!EuxEgx/%Id@X׫. =6SZ&{xVcTK7=S?WsCwy#8Q`ikMs,Pۼm*7tߓw9J+6rwxbZtTdzuH ,k[5G "JH(w9:+:B ~tgm9i# |Rj}O?Q+,2Q#ޡӵi ;=9SKUɷ{beY0F3 f Ԋ_\H]2p(>QvpS;vhPrNs^u,b9yxFG^_]]jk,LT"<0.0y5^u"*4##=2>j<ܺzkMtVgQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ딿-5O5ۆkT#AA@˯f_t_^uמ>b}qOT"~\X5]?jUniUVH H]Jg̯I]29mW`DT Gs]RU)MgcsQE?_#׎j^y^ #R07, lxW8=s4K^Ih\gF{ ALzn}exGU G<72tg[{<bY GU.=NO[D*T,3CAҽ (-| kom|/tcA+:.m @lS>ڛl% Ιr$ vohYT P oh`Eww/n75r@&^2PX r%'r(-| psxVA<$mq"DIʞH=}I|5;ܾǑ,9fLc ʹ=;We,I v(ʣKU/~D^8Y<-kN|3o^ǿEi'1L-V'U'sqE/{A?d4RF4HbA|{wUatQźQe3)>G/eh,g>FXgU}S[nXyPy~RW瞵rT6p!FK gѦ "\s/E!ơkl^H{)Bp=j͉nVR$*ؒ29v"?GE!Ɵu7y 9ttvH.wqWu GpnxX! ϧZ-s5ibhdb#+X?7mj\2Ҽ'fl3#ך҂Sk c;3fr;AQISVr*wYRKyIx)nR<8Q\SO_ E q*ZnXehK, 9+_y~='5xW ٖF1.m5iB,^KN9]]Vr*2&bЮ՚_wV_)}qOT5~\X4֭?JiRS_C$}*ŝffBI' O\"Ф;_,h>F=tIG)ŧu?U©\'_4跧H ;UFz3 QR2FGQچ3\|=֑ζRH&<6pcu=;F;+.4%G\lA|CAė7׷Rl־dΙHۨ]sR\h61ۣ8ZhXrIDWY J fk[Ѱ_- <45; ݜuܭT cgom=ݬR;sy%vyȤ*y,&?ޑQROs}~Z]gjRX3M\`SREūuOR?;Z@fxUHE1 8%P`qԊ9?:\ZJx] iӧNo罏?rNo罏?r'֌Zxs=s=>dz[ϕ<c~Oc~OD'֏|{{z&O>}^?};{ߓ({ߓ+2}h>+y'79G'79^FOW??!?_9??9?LZ2}how 'Q 'WdѓG}o>WNo罏?rNo罏?r'֌Z>[~~Cxs=s=>dz[ϕ<c~Oǟc~OD9#4}^?} KI3gvV_Ck}{ǻ([Њ)I0$LE>δtY!/q1ҨR2@kRO3z?UhdѓLF~u/T:߃VO>K?ΥUFOgRO3z?Uhdѓ@ԽS*^~Z>d~u/T:߃VO>K?ΥUFOdݛ߱y|){ u?unyMS((]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%axS!#/MoI sAgژk$@2\v=?~5[gZO*ñ^0Xa9`n&X#3?Q_4fUUkF.'F.'W/(4n{F~cgۃVL ]X O*^X O*Fio=ȒycE{IWiXm0}L(cKHI> ( ( (*e9E%̒Ȩ1>((2Pih 0:-Ā cz\LUX+/s2T}/s2Ub8S$pf^d榢 ( ( ( ( ( ( ( ( ( ( ( ( f(((((((( ڏn*5ks\W%ᮧ@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*R/ JG$"EY1;~=r0:yN.m?f<:DO3­D ^[7l\fkkL7vE~T3T{-JimHh7$sftB+QQKY qiIezc%1 X{+(nڌc ANI$[]ֆ%>{K{6ȄÒϽQ+ŧ32H납擑Ԝgi[j68ǖlԿzoؾiL<ٟ] 9q{$ֺzt[k.dl#H|Sn jZծc-lGV3Fܼ"{UkXq#(1ޭ۵𳘔63M?/s4KlR T珘Ό_[-ʉncʃ[7O$tVrBEX(bUO| 4Mt߼@zY,Vmxilgw/Nk-v?-궫ǪOiqYK*0sHHhnL{+01"29rp`;Uo^]0yP@u +yPIrhDlowlmApR6i#HsZ=۹7bc~_z[1|COjzat >Φ4bB1;G#$ ֹԵxtőԮRƫg,~`:_jlW7ʠ;Ā1t&ⱋSиx."YbC9|\``x^:,[dr!w֭]k:j";#Mϰ9 4gs|n% Zy q fyyn.T%vY A;]yמTXlww<Cj,iy',X 08s[7 |{VQC0>;zdLVC#`9N~_V"Եm Iu;\p7(R;xvtχvҩaol2|p*Nm[h|<.< *y ME]$+Kj#1)e9qZW1ukk?9t$HEp ẁ;T5JC4A U!$Gu I A5<)[y5-FH*] 8Ii׶Mu3\brb[VY՞SdV~F.7n!H /rAYk,QƂM6;;ČqKw{keEƱ,R e2/|;ms4Assc,0 1t`}*z]/&VtP}-]^'l嶕\0Nfo淕W;^[wmVC#`l5rk0Ed&f}s+裰_e(_#=E3FvI_Lu5noHT٦(ҹ#cI[7֑\YYc6`ߚϿW˧{wnl4%9;vR3nW9uX4QI%> nX$1rGZ~Iy| @Wh N:;wpKdmnFͤp?]44?8.<6wcU]QE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@&Uxox:u&Uxox: e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRV׍lB,KEU>\d ]BҢ28Y"mXqЃnfݲU@y-цQRs8@h_>/l,3H _K/ ?Eh_ _K/ ?Eh_UmKx.ap7`\0(}_Y(DݲVh 2In'IdhBEc$v'wː{w PQ)(4H;T[p;((((((( TR2&=0(M}{}t4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@w}ʤ0'r?λ-PĪ77}OuQP.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pB_qxiqAd|#<6 VKZpH=|ޞsH ǭǭUhhHҪ#36FI[yAd3$^ͧ_+FPEFTϛx-|-(2?g*;kgI" #yP7][hImrC%Ɓhv! ӠO[=[X=TSsrln9ϭNyz%Τnan -QAR6Zm&۶y` *uoŤEogA`]7<+]~v+ioEa-?l!#2 +-w?-閺MYndipqGb{f~]'W:FaZAqwf@(7n$;k3 )90HrCPEoM-qĒn}1SlHWogg[dr8]E-^KtinaGxBpJ w7/!P`o1jm-oaI'2E4(f&SoObZ#d}V?ek'pN~f-c1m&iCmg`un'm$m %3`,ƈ?V׶$tѺNI).7ojK&ӭAKxMc9a*MWXxnm^5HRtr|`w-im?qw!CLjv8/$/<1HU`\g oyD~~;h<ݎqq/"lP9fOsRS{ (Q@Q@C)ͧu?TZ cKѠ+6I퐪z5;Db[iX7o%Ǘ$e<Ҵ5m.VH,R$m ;*~9 7ZÉXEv.(ui,'Xue'xF!1j CWծdim-xi"WV%wg3ۭmc+l7ח-or.RIYw(Ңܗ2cyF4nwZk?QN\O+@7ϴ_Ě>2Q֢KXa[IFPYĀl98s[6\vz7 qn^VSw=8I%󤶍wH*H|B][ZooWyy֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@#7G}OO|\dʹ tAe^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWqjRU`Eqtmñ?Ƚoo.Q@{?]g_o.@{?]g_o.@{?]g_o.@{?]/{?]\*k/\LbmPOS9=ժ(((((kȑ껎O: ( ( ( =(ۑc$~5-OȽoo.k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(2i&D ){?ʹ uj? M?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UWVVq "/ J5.${(Q1q{VEIFé a3HgK@/@r:S[T>3qu~qeMG ` `}jZ6ZP\2(c)W^>ki`2OKzNc~kI)1xW4-/!cx;SyakYb"Id\˂y(6}s RhAiĀFxگObu {y*#wi@#T4 ^j2 y\AS6mُ#O4u]Wڍ͵9X].hWl`r9C*Fc~#G= ѭ٢mKXw`6I,Ay MfMGѧn$ynF''"UGg&ךPZ*hwꭵs vLg%խ [,s=ZSxRk\vMf&GrF3Mu;2I&k:V~ɶ.Y)13$sٶMm, YjF>S9ԚZ=/2K5ݥm$=ݙO&L(roÜ[ھk~d 9ǶEhܫ^ڠ$`?Zep]]c2 nsޕN]ԫ+fK' `рP۳3 KA-6UMfHCՔLֿ]?kgArL#;, Ro]ZK{&mZ8ZH. ]D7y洮3gw%Ԧ{;$nE"(PWA=M5Eַ hԪ $~fvDOeH'k0&Bۛ%~?ޡ='P03@ /ӠH o~QB:+ziyumwQZG{舸hYw:vAokutӫmx*zVxmFٚ+%Px]t"&yVR_](^`aXxYi7X8Uã˻q8#+湨6H0A+D3B>cömm} a噰x?Iqc﯄r1N%bڹm#:^_CɶUޓPG*~`6y;PmmuyhN%ȅ.2ƴcNkGw7&\U ?,sNËqT>l݇A 0WGjk-/rk,kN'oZONQKI."{dVT``I=qyj',K_ĥ `}ixjϻn]c9W=:jJVcm 7KSq #!B6xaJv+ioEa-?l!#2 +GO<`h"`玿(umkqyq[|\pQ@7bcnsaVڬ嵣F$Qk1,[ЍmV#-+HF2H}@}xFʴ uIgarx!83W~Ӣͦ\_]̳)G !@JOga9_OV=X>A8cjT~]ɜ37K!W]QaKb22#^wTH d7?H<}۳v33jku=S7h@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVs\W'ῼ?κGA?ɿr~ ( (_y/ν Y=|]ue _ /EO@ pE=AsTi,M31ῼ?΀;>࢈>ࢀuמ>bЮ՚_wV_)}qOTQEQEV?t:̺?N ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( () M?] ʸ}x:` e^{//BVk|E1EtY*mګǍqOTԆ;yy@}}PH2uuAt?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*)^@cp$Dzwa'xs7Q ʹ}x:` buמ>bЮ՚_v֟m\SA5Ci6?SRQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@ I m!GCcC2]i,jse<&:aQ\jW-2]iSVoOK?>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? z>)A>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? zrٖ8u%;?>~fWڼU@_t}_ Z$Hn}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗ϰ^Ʒ6[ta[;OV?ޛ(7!UkƥNwt,>m>[PzoGءƬ̳QUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCb]@6ruԭ!` +0[ß}?΀;>࢈>࢘]5":+f_t_@ i$MS]K{%x<dFb;OPjv׷U̾zI)zw kX}G& #|y= aF:voNQ%GKX,VSCtrFI}RFΆRuI[dIK}y O}rks=Kjcg'kO]aiiZʱȲ8RDLmbnl[\}l^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U{ VT+A)L69}*}-[ʐ[Y sV&ށYGqcݸW]%Iʮ |I_[ti防+{Zu$+v. w az>n]>f`8Y3PM}:K<#N2qsՊHf>77} ;P/X̞, 6DKѣ"<4=jz yp:4 b:HkX1ǩdn5efg}(ȱʋ.N2 o@IOVEM.|ҙLWix>QOkY[b.-mt2vi_}?/;4Fb)U$ H"|+v e Է@k"k]S+[(m&ܓJŗBnnOnE. {fk1jSZ[]:B9.B\ 9'y(vn^blԔ+lzu=tFhK p6 8zvxzx5;'7NC I8^@:m}o˯w3n%-.{S]}.wi۬2#vKi$"鞙VʰYhc9Ƕiy{8l- FMb@1F9#GOa~Gow}[ACrjy"O Z-ICzUlXͩڃ>lkYݸ۵0*pw蕟sf.)ݑL+qגh<-OuG1ڹv/5|X eIhΠgKqYKTwWmȚWt|zDЗmqukq7gSst>^M \.wOQ-4tFDwc k+m=_lfK4[]éX-+GHn >RZt6'5nKJYS}J'Cp PN$ -lFK]h! )Wk6mvWRdb{FZ; hW}lc'֎GW2xuXĉcN hW]l=hQzU9olI;PgӠ mq <vK\ovz%"QPuD:(h`FNch6Yxb徲0'3oSNB/;+P=.VG[B&1\ ep'+:X|6ۗ|D&Lf@qlg_@u& ~б ㍤~ӭ~%>Dr4\nU=qҏ',KO5-C^EA.?~ѿ;v_~?vS .wW\s[}_3g=:qA^-`k80 s@E7ma5¥ d:Ƣ,t|pYTֿ[+(%_5~;\t1sduִ}&݈MbDWD[]7: ;/⻶rLъ=y4TE 0- K(QEQEQEQEQEQEQEQEsa\>w0}E}E1 VkDh?z(kldU~Roʼŷ@," ?HgoʍW}?G'ڗl[ktUj_Q @?z~?y'ڗl}?@*6O^a @?j_PoʕU_JO/G(R €=*=p*|EhHK X=oJ6@{G,mc€=*_X𱵏 lDp#r޼6@{G,mc€;k-;K{5cGu;HTp9^m$ٛہy,mcXw6ZdjK<_kF6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ˭*MkQV"ڼv?q𱵏 ?ckDL0d 6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€;{*MkQV"ڼv?_&fQ$W?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckU.s,"ڜa_a X=o6@{@jX=M-y,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )hnip2-8.7.1/doc/html/figs/ir7.jpg0000644000175000017500000016313013414613100013161 00000000000000JFIFExifII*JR(iZ)( )( 02100100,C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222," }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?3EA40(\Oui2.2!=qZƖޏEjOZOZW_ O ?E𴮿"'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=IGړּSQ FI(I^) FI(u@$\kRzu@$Ѻ|.=hRz׊Ѻ|_Z7_OE'jOZ_Z7_OG-'{Wړ֏'x-'Qp=IGړּWQ FI(I^+ FI(s>K\jRzs>Kй%.}=hRz׊й%?h\τ_EھԞ}=kh\τ_E./ o"_jOZ>Ԟ./ o"E-Qp=IGړּ[-s>1K.=hRz׋й%./ o7E'jOZoZ?-I^- >|atϹ%~Ԟ}=kſgό?nY?7{Oړ֏'x, >|t\iRzs>0C?gό?n?jOZ>Ԟ o7G- [p=IGړּ[-s>1K.=hRz׋й%./ o7E'jOZoZ?-I^- B|")?h\τ_EھԞ}=kh\τ_E./ o"_jOZ>Ԟ./ o"Z?E'jOZ_Z?G- [{Wړ֏'x-[Qp=IGړּWQ FI(I^+ FI(u@$\jRzu@$Ѻ|.}=hRz׊Ѻ|OZ7_OE'jOZOZ7_OG-G'{_ړ֏'x-G'Qp=IGړּSQ JI(I^) JI(u@$\kRzu@$Һt.=hJ׊Һt;0Qp=N<05d~T:\լ|R 07#nCҲ5K.&9v\ּBJ\+vl࢏a5"T֯5Fal~l` w1wϷ " b s^pOBWWJЮU`c_VG>Z]lnُ]+/`iVa Ej%갭7q\,I 7ny_ן?ࢳ!Rd\uA[AvWBԌ-XuEݴ[2E%I?#8pִ쯴O :[ɥ̾qtBNAD-lpa@ מWxm}v8ܖt lzecA`< O쎘n0Ad ZZɚHp0GMqEֳCp`yV9'=?P\IqۤG;ā>G}+nF嶚,'vAֹ+H[x}JÈxO 7?(>Qkt@"/>Z4 ,.q(XgѸ x v:H$_bX?{qֳ4r; &u׭-QYLfpϻ|dcڒ} me{z֖WW x 8\tWLqw-2Gb8u@՛L6Ϭ4\"p;JחW/<3mũ[ZɥF>(\X?Q'K[q ̐&wʐ"X Sa~-~lnŶ3Ǯb*_-KU(0kII!Ãot|>mYI1>Pnq/<;魚++-;HYcX Sm/.uN]/ԁwl,4WS)PxyБgkK Y-nbn9RqOK9Dծ᭗L1Al`TҭAd ZZɚHp0G^u] /><=ܼMtI{{EDȱ)c  sV Quc=R#+blwN>a_k[譍wQ_-A'5]9FvH1rx=V%_ڟ;@1r8sև_g iav-81=3ڵKmu% b ۜ\C[.n{}:=%DRLwO b>۞W=k+=+=WHYF/.>ʜ#ױ ǒA 8 Lt.UއplԁuE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.U#q*SPX/ꓓG^F>y)|XILD(Zi7o̟Mf7[x Yݓ#TQ8e0RO7VWb8~A+ ^[$3˅ c%}H5KW$*^PZ.u0\\-p[ ۬,tZeAp`&dF}*Ś#I*0 :OWR3jt> ѝuÜ{^xK||Q-Ҩy滿@Az>~I&= UĵTHC+\??Ҁ>|!Lj._V^/7UET5 g.QNy>5# F~fZ/D?0Vx^y!bph7QE?uhڴ=+Px H1z}B-mLKueӯ--sB\r1֫PQOaeHètޅw/b3{/.$qg2 AnQ@V5;KŶCǚZ#@C S , ;L׊(WKۣd#_&wg:kk=n`H]z Inu rcb0^inSYwyQI&.IA@7P"҈1+i'juwPE2gX'$Q`Գ lQеN-o1m6AQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@Fe:]Jd`=)_rU)ƋZ:eJK:N2^GU?bN_eۻ1KٯplmÝmK&MR?ڮkcmk_B9!~[reےO׎Ն<9h>ehn:ՈAs%V:sHf S-C_f>m[T61Q0ʹy=*l?OE|E@ S 5uǵng:\{b{R~GZR OJӭy͸i,X:6WbX?cADrPA-l5T@Wo/χ M K ̄ 9Rig2KPUѦ! eXOݜy⋭;;HybR)*.xFfݵb W'J'*>DO#G#!Gk(ܧ8j`[Y$1`PLI8~=Lm r93Mz%߉'4]]cZcF9N?^Y>bRJ@m;/j\iP6FU;?\mNtQo#P \dcx]4m^ yAs?uO(MLaS33< Eein:O]MsiVڴk dВ9-Ӵå۾qdKxa̙(YKvF30G5&mM3\{d_|^mffrЈ%8M_3kDP_…^=6xMK;itƷv#cH~1s"[iZ^#UKy@RF pH/±ZVc[y@B8C@O}<5XY&#[.pWB( 0Xa6o$D-3Dr8ߦGsxL.uCpfϼFX VW_?OuxFk(ܧLB!y}0kĖv M)|T$¶/Ŧ5Z^V98*i'cFY-T9$IP$SwُEk+/j'QT#"W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O(" ?5O+{,7֗ q:Σ{CLMs^籭x/u2SJʬ2@'HڛV`5BbQdu U ^w7Nos! x|9\fK 5QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPU&4yS[E(25> ,,XYW;=̗0q\cT8Jc#CNozGl̷Khm h/JTz#H7u#RQGn>}4aim';1+7c$2Ouڭ]33A$ C}hۨϳq;ŔWj#$Vwc׭yu?񨥶}NGsZW,ZVYd8qF{K5KvY;Yf6Vo m$d!+C|E!h=QaKl^e{K:}ثZvX:n 8yUN9Q\.umu9l&smyܧzU3t-5C׶)no(uܬ'^u{]ξM>G Nfʰ 2292jRyMme ZBZFQ.sǷ_Š/\ B[;uLZy :ejVXny@ ڡNR(];_t}*+;I/FD 3ɷzS'|rEf~L$qޏ :J+[>ޥصx%%w2mGstvK-rOE+ $6*((x]犤i[yP"'dC߿Ӂ+cR[۟6G!` .rcQoQotW?g?iiy{VGQoQotQX{i F?Q F?WH$QXDH~(H~+Ȣk!{i F?Q F?Wdg 22:=dz/%GG%G^wHH^dGQoQot ==k#(?߷ ?(?߷ (^GQoQotQX{i F?Q F?WGaz'%GG%G^wEՏOJ4?J4?¼A{Yiiy{V/m#?(?߷ ?(?߷ (=DH~(H~+ڰ=##;jHOJ4?J4?¼=m#?(?߷ FwM̒ZyE$zs᫣WfvЖFgn|5_}o=Ϳo{-ϙ#zarzN__\jW7se"K` eP@ J2;Z+>(=xolI8MOjs.i_b]>I7  #7d4u4W 5UmO2[=-[RaFiD FH#zv_uVnsu-D1d Oʸ>a}EViRd#!r%ڣ81CVvw1V>#Σq-E<%ǟ%:6ZKo^5ż7IkȚKOʍ8K~GAEs.F*u(ZRwB@9!oPZx{k{}:%yϻF\(6$qh@:+.5!v,c1GRF%8=o_M~(!`zz)Ddj-jV om7nUH֙ҝD܋zLmzmJ*6èU-ʏ %6b)%[[ya6q^?JVk0ݷdg9mɿrroELM__ڷ7s}EPݷdg9N4{5 [qb+nxcҵ<97o --{`susVL;တ[g/4c?(\b<97o i+?Qt MnK]He2's* ;ԞЮ1RPEPEP{j)/QE7M;~^|#q᫻$he;bp6v׎)֟L~u ܎Cq#IP+ZjF0=ꬣl׊BMXH^BB ш~I gmB{U(٣SQ67dn1鎔] 4W{g yB+ 0O/$v/B69턉2ɹC3B#fa`yE]6kx%% :TϖR`n8残u݂Ƙ,A\t]h%ᅚLB,Ff2,.PF zM;t (((((?foo k_BZ|p3/?4w';KKGX# A򮆊 珅i~/kFk M7{yإ$u[tGC=f-"FB~cbEa_LY77\u{rx~tå}(Jy ,TI۩PX1_Z\jHl܌ca׊ܿ)7{}F8KH#-yOV_ ɨCw:|HP&Ӏ9rx~tn_΅Sh)\^ڂ[x1NჀ=jMSP}vmͫy_ܿrx~tn_΀Mѹ?:Z)7/Fhܿ h6Mo+a'rW %Ka_%\Q؎޽w/FD`#+Q$9f}տnUۂB qʀ; ;R֍giꖴhkWPvPnAgr+Qd4ɀİPsC\τ4k{WcH ^5$J@_K O#6a@Ȯ\_0˂r9bp=}խ&y8U)'9?~ӦZȑI,,p y')~Kj);+*"j2uKQN@ ]p>涱$dBJ x(9=*{oYu wqfYELYI!p;UIYؔzhpqjpiwG5g1dPӵkgq/~_wyupq[k8u(ESy6 J;ϟP->k^I&%|(#6a@ȥ}: $_As<FM %#,0HRW1wcmm*(57W,IljOJkzV5vSYLM#Sxu'(͛+5,D3<cSKZ閦_. BibII>¸`w(JdHv;Ջ;.KBB*5*r\+g<еm{#-/ey<(Kt!I ֥ծn\J@,S穮/_OSHⱶMó)i3֛w6cm^Bx[wm:f3 fV(HN~ $28 GLkm q+~y"T?"עhNKJwTr`CB9-ϟEOmg|*zE$hUb9N6PhH=O:[Y?G"Tw$.T"?HD~' >?ƏEȩ5MHAm< u+,ҸZj{">?ƹvw߯r cFJ2ak?Sh[Y?Ryt:]?">?Ʊ..eQ3tIk?Sh[Y?XRQemg|*k?Sk=CD[Y?G"TeQ7">?ư(D=MEȩ4-ϟEO (Qemg|*k?Sk=CD[Y?G"TeQ7">?ư(D=MEȩ4-ϟEO (Qemg|*k?Sk=CD[Y?G"TeQ7"֏-fͽl-8S\}u>U`(5gn *_4w~r-H3\IXsqtw6'I#K @fܧ>8BڽoC|_c?rJ~*Celddr3U:|}~[<1>pDW>4FZ,FOҰ4;FѴRi.oOrA2H\~ռm5n L9iEJSGD$JRF4/ߡQf,y###EsZ4K1W *菰lnztӵ]bɼW- =ܻ‚O7SjWa{z͋BӠŴ\7lf"L^1W?пi~sFQΕ_$sDJsӽwt{(vA3̟F4/ߡG#m?Эj(Pg?h_ BF4/ߡZQ2пi~h_ BCoWd1& ?пi~kQGdޯ?cBM1& ֢e=_yƅ@O(cBME{z' 6Qƅ@O+Z=; ?-i`-I"#Xه2 ~j6* '][Fu($KUYiꖴk;NTZ\??ҺC(7ntOBIOA+?.=k'j6.-{ȾNpHc'@C.o4cg,G)n-ɡE8jI-H{Kǒ9UI `G_Ze  p5%I dZZT3XZ\gR:@CFDPUWL8Gnyj.QvuA$:`Rܐ38?F>€*Z(Rdc)Vv+D JcTkƮdim~(:FM_rhlv[fJA5@GL`ҶZ>hw,&J) cmjv1^ZZ[Io(܏#5c#M oL WI,ƱFb4P$`+F-: $@Qj>#*'`9fXAelSn-0q9)*S寥Qյm3E,H8.QS܊bi1$[SB1IakQޮZIdsK/i#&Ҁ(KcipZ#:rXzyMcipZ#:bXzy-}(Ҁ)_j"F/7v2:SO"\ޠ~ܫ<2pA~iSpr:bfw1"j7˦Kv2D2GJZ+{Kf@Fz <ضeZMp]A]۵*|`F3ж-t6zX=6T@f)g>i ̚-lnTt'ץ\汶CxT@6%'16p1v]wb]Eo~5rIF qH6?%0$lIS̯a۩h-`XG8bNWܼ!1@$ R=+S)xɏ̍,38KݫG o޽bc6qjńjFmujeeP3zy10 ʤ 8}Z52g}w18=E2yEӰ-yҵݎQEQEQEQEQEQEQEQEQEQEQEB׻K\u>=}3 OfƉYG>ϸ*a?: Xd _-?ZMtrZ |/ѯ=3%)&OUuf]vi%gg-oDޔXy8^soO֏-?Zm݆rVW3ZEgbcR4ȁ͸N| @(֬G֫?Zyji@`arjzS\Ojc@UU#QgĖs7$2a+|)'x=*{/hk=vSX<2`|ҙ7;;ZG9h7s^qȫ26ؾ6&oBZ=IKIsv8lQmmoamssFkQ:兺촂<=ѫ=I8uK3Qnu %Q%Q%Q%Q%Q%Q%Q%pZ}wտmWPaZѬ;R֍0vukP>`W '-W4R?n[}?W@ԬL NB;Y鑑z${Z?uȿ {RM3'>%՛[-v~ >]7OJm-@=O>j?!ymq7kljY*Bv1Q'GPծ xYaH#\'oo-QM@VMDŽ$1ӨKQ֑ܛRr tW @q٥Ru{7ھ{͕mQ?PGzWIeo5{n|U;6]:y&^͋@A !*T8HU=݉[# 0I?O.k}yArbkv|.={Xyxxk4Q *E*!YoKJL{)@ Rt YQ`R]~EuOq[x}&PknQ$Cn*@GB3i{kOs{EHW člUJ}2K׼1x>dYO`qϽTޝ=ݷw9yc,1 /"m|[ KT_HufHћYWdPX6џA ɃzU^4̸*TzZ-8roh5kܕ'Lv}V!/5#tyGgo1gipl:=ak/-L:0pAށ_M/[DfOVfKwiw pTE$d 7wqj׳ lo +@qN heei26&LECg?COӭ4Ake KcqbI9$I'5]Xt_rQHKG֫?Z/ZhQE%޸*ơeZ2o2oUʈ~OWia(v?'&bIA,yu櫚PӖ( ;lNϥtz卒3++ .GǶ?QUR r3̨OɆ#WnnZUx[ 0A q,EU>U\b#R@R[ ?XjYY~zʤQ??I\3b(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@u>-]O//{_xzS/Gkqs,~X'V$Y>ƕqk0$+GC?}'y?O4}IO&v,4BB;FqR {DѬsdgC?}'y?d7F[>:y%G넓#?)8jE}'y?>'R@}IO&C?Եѳiż yp.9 p?'GۡjZլLLVQ`>PnO5-ۡht>a3vNt&z'i^Y;;R֍giꖴkvukP^Kjz]?W_@Q@Q@Q@Q@Q@Q@Q@Q@Q@ V~f_>Y袊Koq]?UEm?ʵ)eVd_5 <skM Ī:ă>SW>>$4e䞹^/:I:Fi@aUfMJKidU[hʐYFH珥pTͮ_-)[m+9LwcӏZ]2ᘲNaix^XSI*L XAicCQ~#ԓ(U]am~a;i<4^y2LqO],}OZ:;(n #aUWY3[pH^W߶8fsr~?HsvF:[qՖ(-.*Ѵ$zQV\k8a[gʃ#8GZ:V'Ew8+:%{P 0H&Δ3,!}nw=)}~_bj> Eӥ{ChnAqO-َ=4)@jc$be;Ic ŴMṂ"HOn}<LLnV`Co{讯Y%[[u@`N}{t5ƩKYXc,,p=:Mc|E.7EuʱF9lqXun.(f71# }}+]m}etLvEp(% uIکvlI2nݲ= ~^:Mۗw9+|F#3)t $1ZW[h_oV;0H93PZ8~?QOQ]^,חv`y(fGؓT{u=*-?[c+wuܰpU|C68~4DEDEUk|dxOFO;A;8b#ӣUDd~U^IQITؤ.5WvpEzt2uzdF+m`@9*ܶ_ؿ5iQ34|m _"O- QpWQ]Y-@{IM-y`Me N=/3q݂@|m hȆ'OY$) ǙclZa6ȻsF+[AKkFv LDzvDEDE%@,kR-ձ8Ɍzs\-̺jvPQsSdbp1^IQKPSfm,$>!73>vvI6{gNbhf :[BCBț#,B$zw?/W:x~gct_;;R֍giꖴkvukP+M'IpFcfaA<+Q꒴Vecih]>U8ox#\eqI~c2fǟ@ hZZռ-K Τ+(hg۽J{!:;i٭*]RX$w93Ie%yc-J)-@K0-YN8+ykMѵ_I4[٬KxR߉eT9gVnjnoAKY۝]b>vѳAU%ܖtdsy&Đg۵skfRA [f{O.tg9t)t_Aٟ{htEck6ysܢ6=pNjͥnW0ā$2S+?RѮuE8яWtY, npI2Ȉ(@ſ G]N1&F gizέxuk};7VN:+q{<,]1beVn{ {_ÿۺG_ U>TR\Efg' {Qяk7Zƕigy +8#3jrV2M+%T`J63k^Biwq^^\I XpB;P:օy[GوΘ(9ҟ&QHaEPEPEP%UYV~(#Wx$Es# zRIU>\˕Qe?v|сU(մw,0 &CXxgPye/3FjSiW y7s|aXW,rH?fMq '%- UM,\: n/'S U& j奭V6s H,_n㞵_ٳJO&ٿ%s|I`խ=XEuѯHaXgҜ.G6aLz$>q6o \)7j^^Uh7O%H[m8H~"xngEidk87 ylܒqƻٿ%s|GlS.߂kp;$۽4)k-#2+;l`vgS k' qk#x]lS6o \)'{~A|27n a5EP FQNJ?&YmJ$( $sbٿ%s|GlS.{_#& ZUEQd,9lǰ)Zgy)h[b.H H ?fMٳJO&/{^5 6&dGd+ g t }ini8HlE哜s3M7h͛W?5$WC:.5/XʰT %3"q[x~Q7IZiK}1Hx6o \)7jӛBG'.xl/Hc'䓴epGZ4Z=<[,1:`86o \)7i}AZ߂8F-5ydg54iy! Fw*A#]WlS6o \)/ks:~qhn$rPp Gp6Zm#HEЪ6G&֔`]NggMq]Xȶ q[ygtyepg'Qq\68ӥ7c^D'~9>u8۞GlJק-?_:WZ~YZ݉ ,zW$_[cqc)98A%tMMn`(]Wi2qk\oMfM=7UTyHWi%Gƕ]B&*-Np['py>K[qqgs -H\:q^z~{cW $s]Xyɍ kk6j1Mecvy0ps;_p8e&HhTOISi({ $R%'<f]Ưc9_Ir GW??Oң]/Kq+jMmɁG% #V`Ku H-e6zasI{k_j6qgP'\ޡl_Blđʠ,%H;14)ӿ.Lmkw[vs :ۍ-lwwi407eVO?, Xj-e7s^ssLkMBocb # TFd }/)O-͑1 ʳ@ªؔok!Fk-ය'@6G'sZ|6+}-vm\4#9g|hW7vxȶiPPOYE#=ͥ$(D[[@%q)tvϫX-YݸiF~R=KV&L1+ӴX֗G y6?;&ѴdK\Ū̚\ij=qq2y3"|9z~_ :]3zķVXtsss%i.Am9i27s5 2mV3X\Zqd&hYVTSI/#[Rі)7*I vå rW7ZZAC52ȫjl6 .ho 2=0qOm$Rh-di$ӹ'ȊPYڥݰfYdxوKc  ]Z]>:P)48ʺ0eaO_ CQ]G N 1$lmmS`_ȱyָ׬_ſ,^?57bv+?E/?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhQEQEQEWphunF ( ( ( ( ( ( ( ( ( ( ( ( ( ( -j_:딶׺(랾ׅڧ_-,䳺YLR})ti+[X|"Px?`[x-P*)A<*`zWAtiOF)M5sawn],;G;4ShvDo#\'v4=W5=TfFe%e0 9N 㵸dVҬ3G8 tj>ҞXWzb st#kpA7hɩVV岛Tm doFVj>Ҟ\xPb^y#%p1ItH#A"rp\)c@=)ՑڝٹW8܆ym6^Ӭ/RgG*ٖ3j=GĺN;AytVEMɱ}[h;Gy V~Ҟ\߉{+U\0En ?b:&w)H mSy4j>Ҟ\$,` ỴZu4eye_ݰW+X@MtiOF)6}&V(n+d psCͧi34мd`GK[iOF)˟[]Gg-ˆHI72J=ZKv|uǢTGGj>Ҟ\ni/, .u >\EywhK\KNPg~ݹ>jMΛ)}=Q@|U:\?/WKokbv+?E/?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhwQڙE!FjeoQ@ xK$ɍCE&ˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E>%1s4ucŠZru]cFw`W&^gh:K3r85:}nEз [ R%GTEUUSEjf+iT]h_ 0F3О㹧M/jVoՅKyFݜ'k/eoOrVefo$$Tl8 ={V[ZZ ]K5.2"2#ҏR}y }N95t[mUO,(n3g{귶dkp쪀W#'= G) <ךӯ-Mwn7ܠE׎UWs_J>Iiz=]y߈}sQ1K$FѢXCXd1Hn|PEwj+D|YXzdc9zG*n/k+I.f{u.1 ym,4I˵yKj#,C:ZSi"HC,bfFh -:rk/eo%++֯aw>A >ts1ۚ籖MsdwZ @eA xɯB/eo7îI*р&qV]?Zyϫ׷[_Io$IhFUX9}ҏPӳw!̖Yՙ~g@ ) ((((((((((((((((()֛NNb?fJmԮwQ,m'$mַ.om n'H-s;Wڗ;*."#OlK8.ۋYmEme1zu=1ҟ٭7oƾH;pHmdc6K=]5+ڜdc3JtDԬeΩ%<|:O^B^_ wMq$H q̣E׌4"7 o22ϴ0# ^Ɵifծ,1\" `vGj w,grK̨Ȭ8=yV|н]ͳGs,4Qd9[u5"Cqmsl&PFH ЂEs-i]n xemT/6cp}kkDүm SR{^nI4@BHI'N?gis4ms=QG j `Ă{c՛2iE8XT-9G5^lˮ6~fVsONt6{$ªzg%~jj!HU)dVDC8u#꾫M.!e}y8ėOmHY8'+P5+=6nd⹺ĶvP#)=G9>,}.oɪ Y.Cݪߐ .c[M,m\Z\Eos4Kua$*>#VDʒƩFYC Z$LQtP[2.<.![ 8ѽ!O c& \M$J9(V$Uu!6zwMq$H q̣KK6WK lrqחд%N5ۼjla w<-Ə/m=:eĈĒ5OAXWҵK^K vYc(N R+&afglX / kئ}y52XF[x9 xZeu{E\ !p~OڦaKu-:FD0 n#$W7$!5 =-bL:g'tl5b_JJX4n Z׬_[{?}BدBC(8_bV+ev_j$wzwӿ-h(C+\??Ҁ"z]?W_\ں(((((((((dt}j2րERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES6hf4iEW!UѴl&Y#UF+1_hK-r ={xR}H:g#+x'G҇t7b{s .zd%z}&j"̓n;OTSWާk5ySi7davsK-iE*W{]KhirQ%ʶ={]K_etA!x|+u1 SVv)]viE/赒u lH#0#I"C)<V}4d/QMmlsuΛ/}FwW@b׮~sT;Ul *w\07vPiqڭ77"A#=;Vugҁ368u6ΡrӌӶ'DR k{E څih1\fOА^_bV+S?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z$29.T~b!5 =C}M:(0((((((((((((((((('Zm5$\(-Fldh"c29()rE.F\.Gq+9! pΥ#icK{`׭%jy11:dǙ}if+_n3}W[GGНO@kچiZͲ^7y8Y~^mugK֞nUA_]_v [jax8nnrl!d&^Yye%=ۥ91e&wdeo>2>tʏzkKu4KkYn#;2z k .'FAyEjj Zݽ]]5(%[RXڝgZYx|hehsr@ŮNL/4nrǍ qgޠԵC YM)!hI2+1lYxbЫ}}-YK@ă~n}Wwwrߪ,:NSn`ҮN풕"Z?G[hV4f5`@ֵ̲5-6Wǩj]W~N3#lHdw7dkHh:wtnZ1[-ԡ x!p8dO_>76QbYHXNy,w:)k7vv C=ο%9\'j42KOi(A d 'TG|G̿xyޞ@{>'W7Qox)r1O l/89y#|6oqiCui~RT2dy61 ŕfIe6a|;Tx>>Nkl&% |ہB0 8u隦h{X5i$ʖw u5Dߋo21yau >F|u /H.[;Yՙ~g@ ) ((((((((((((((((()֛NN;)j.e&W jz柠iIfO,QqNv$158DǠ}O1ߝqW+8.dif+Tw`A2MWY/uQU/)>7gsښW?[y=;{4P#\O F4 Xd@3t+Ny8}:1ߝc}:5^5Xg{ynDdt:Ҷqs|u $(9U ;Z]ɇWP=٦ cBNX/_"gnqθxo>T7{y%PRv#S^\w5mZOVVb' gk?\^C0֏+DТ\*TdH5k1>q+E @995Va_KW'R#bVVk7 n&oj*l/k;W[ Cӿ-hvkFAkWPvE/x6ǥuQEQEQEQEQEQEQEQEQE~gVeU6(0((((((((((((((((('Zm9:mD i>Đߑfr V-nwW9VRu=WWOGc}owj%X\#= L;UXmeġÌ$z4k5[Li7ݜqҶnByD1I˜p8yl!$&(^FyխH 'V8z(tk]$DCA}n c51?@Z|["CZ#g^ \~lOGuZѬ;R֍t_/r PJ_wm]}rKj(((((((((֬G֫?ZmQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPNNru 5};R;n I+|g#O'mw7K<2iu}d U,t-6=C{o E+=I Ԛb9kmR,c[/ H|úx@<33jeQSEuܱl1c5ދK {a ػc#Q؏jCgRDmLrI ;s"'?QoosGuq5E.Bڄ Axc뷺楠H,d2BΠ8?wz~ w5u-hۉbCnw"|=_\cn-tB1*HWˍc%-!ۻxbyWִfx̹dylpyf,M`99?/Nӭ--Ž6HUE_1%԰a /⧎PF9;[5;ssq-}hKTdhrQ:Rlt3Lm- i^ivv6PɝG +zɥ~z[GI q'̊2DdkW:E@bkY)c3p$$sW[D[KӘM7s<ի[{+ u*G808 ϯjSڛ^>ეl t=h徶欺<OrF଄aIPtw)i1ߛ[n$lc۞Tv(o"C̊lB 4\ {v!HJXa#i=1Z;MI}$0[[ʇ=y^ջ>6RZH`tHnb# lE.:_և]m)lu,ldOOn*Mbj[o6c38 3NChKn2d EW -L4P]KkKLctbO]P41,l$'!uou1?b}:C1["CZ#g^ ]Oo`OCb6οNTYw9ݮ_]CAں<EPEPEPEPEPEPEPEPEP%UYV~(Š(((((((((((((((((i@ ~V햑&~w:u7y<5 ]yO33LGcfsnwc6e)]Fsj\/>$bW?ׯ_Y;=vq.3*r.M>-(1]c6˨^:vR-S ʡy"_4iέgwE[Ƅ|oN}ݫe|f۟/~l8iҴEؐlk3m ZfDnN& T@l)eyERVNon)t_DPz7uvz}cQ$c#8Vk4}-ӵ d%ICcOHE=oxma6 Fw'=xOwluTWƻ.v3Y?kH|2bx HSxf(`U\sKl36yes?uSGfXcZ{>b6dMii,Fo#.Ϡ8.ןWuqO$pdg9 yjkHf0? }:/i_GemK 0V|<_ :+nn~(OQKi#Let m.dtkgH8Uqhv1-Q@Š( Ƚush/]?1\l/k?E/?֝kFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@9:iր!Hckrl%Cp#%4> hȆ'OiGgvER&7Hу8zS?'QG'QL8e6]N >Ъ6G&֔`]NggM/'QG'QU_i.ek4vv$+4*"Is\`q}lao'U0PK[qqgs -H\:q@wywI%y\e\Tjl/}k%guL5\p(BlUVwe}Ǩ}~U}:%[wd@ :n>e"O"Oڦ`x+nfQ!˜К-XGj[dUhDEDEWoi-+!״ky<"X%Wdrދp$$($+^ (-縎ho_+ŗ!tɮB"c+\yǮ5`#$($*k(f3-bqhuη$wZwӿ-hA5r PJ/!/x6 ( ( ( ( ( ( ( ( (/Zj̿t}jEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEM'ZڼG<+c=텴w $pehݛ}a5Aoyg%bd8yH#cO6ZApv#VE%;(98"-QƝ)!;;fQji z^s$[xD4Is'rJ@s]SѨJz5 K_P C07+C:ز' ÐF3X:AMpоf[y `oQjV_OTxre_Oo-1BZ@ rH'ZgtCw0\q嘴- cCB)}=ܔ0uKOt'e8ȑE$p2k|+O[jj +l,$k~ҞYe~[Ln;Yfz /]QUkM |"O;o[>I2˝dWvvVVݕ?uGj>ҞNeEFNỵ'1 ?@Z6uE'#ӿ-hvkFAkWPvE/x6ǥuQEQEQEQEQEQEQEQEQE~gVeU6(0((((((((((((((((('Zm9:em;HKKBh>a[.;U c+Ggiϳ4onQ b:Y&l.tvs}O[[ZjQlK׵O"tR0Io\ zVLZbKuIօSc= N;Uߦׇ_'?7_~}%&jqe7*è*~tX:eIYc &T+qV mc\XCu\q.Io͂D2sd6:fԝN5$n]x8k5u+JvLWZTy'A r7cE6zK"6KFB7]7[f,-$X#x7\%X|W!_. ZvYG,FFI=o}rmBm6Q.Gۣ<sɣQ,ZO>{+%svV]AZC'UA'AXi֟Va{.-49-4OEE/fI{x 5e `|cdQvF;k >@Z5feXWiVɮEbySZ--re ulVQ5XRZ+]khJ Fݡv9jꫯǪ+͐%00rrr#=(}3\y݇Ulʰh.lk/ wb,{ׂe+ TNᜁ߭O1 ?@Z_~lOGuZѬ;R֍t_/r PJ_wm]}rKj(((((((((֬G֫?ZmQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPNNruiusB4runH)keQaUWASG7c☢д_*8EM @z}ҏV#MVX \?9Q)޼-c~ ksH9ׯeokz^[KwLda,14]xN!cp#*H# 0hZ_ 6>G+*v7W6̳@F$ e@Js`doI֠Љ ŵͳB##8$GB k}Ұ#sB~G+?T zE­ՅK""ͻU_ZiwQ +ϱ${hԬ F~b988 Q_JƼ񅍣ˋ[눭Y.f n27ӒXpjXZY^\R[<(aXG/eoRx|][̐L&Tګ2i.- d0!' s@8 /eo޻ m̾LRC`By8v˪3jv 4 Td+֍unb1\,rq>XO6. CN(͆&3) }OQO񝕵ĨWpI!`rX@8]?WZeo>+{ku+{VKh6)<9z֗Nm^M ](Alncz~__eo{7On.Vt[ vK6ۡԼEjisAb r8\FF:еw}mrh.ux5mhi ach۷qX<7SX-N䢓zCKfίޝkFKZ5C+\??Ҁ"z]?W_\ں(((((((((dt}j2րERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES6hnom>k x^G85h:6N@J ȲG#gHdfhzIZb9ȼ-|!Yq]mpF'qzS&d%.uO, ƺZioo@ٛifծ,1\" `vGj w,grK̨Ȭ8=yV/ZV 5K}"G[^[w! Y5Xk9YcU;/}:O5/Lu#" CN39kH4(2nD`zrNtiE/Web\zM S*L ITy:D94XywnHi#n7v'uu_iE/贆}|/v| @d1op⦹,.o2=nX$;K8\Qm}Ɲ };@Y!A,ryI%i>U1ev$q^Z>NeoDԬeΩ%<|:O\tSIԯ?cMde/ݸ3sV_hK-%Cz^sT!ycl*0퍮ZaF ;OWV_ǩ%ԠUJu;QZ>Bo[Kh:0kztmb:\K#t0 랝{gd*^R6+А?*>\^wx@?m?λNTYwkA?ݮ_@x =.ͫC_wm]}QEQEQEQEQEQEQEQEQE2_>Yՙ~g@ ) ((((((((((((((((()֛NNɺi!tm&+I/oFH.UQfy 8]Nrv\4sH~1rk|9y̗O#p rQ#۸D ={xR}H:g#+x'G҇t7b{s .zd<~ olM@_3F?| F0\c,4/c7l}+yϿJj7\5;_|q'I̐/. mxQj0e-͖&K6v=?ֆwe{gz-. wVW G5^^jW&V(sԿ;y[؛XlD |TO=zU#W{KO^byUU2=J̶p`MFC}ڒ ߍ+FߗOH$we|D~ZQU\s֟"=~K;[iuw'wmjx5[bmnؕQn_OPyWG13QU럓_ҋ }WnRw/hAμu_=3\P)x @骳2"#Ix]DX6=Rǔۻjq=:潹hu9fG8+=3wq[F~Ya{I]*qsyn]Լ}mcq4k x$R|ro}ɧE쐫(mӹyޢO ]]͆#Kl&Rʡw)6RԵkk,"Z*3wBzUWsP|Ci0'2C$Zи%'$;M$G`n\J*j^ދKBU+9Sݽmo[vCzlWQg%̷[j_ ls_#>SY>wgi+Cm-ȫ!l+w8mB/qxtf{o5s/G{$o$1$I&brׯl]%/e0%6Ɏ^o_E.a-# StV$6]j>mvdUL8=ZuU;~f|xu'VIIcA$>mb[nrAb3B"çGFmp0~7cjx$,P<`B-MemZѬ;R֍5r PJ/!/x6 ( ( ( ( ( ( ( ( (/Zj̿t}jEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEM'Z"Gayw4Gѵâ:vkeosyғ vFI,?֘ȏȏ6mn[侳7˂Htps}j6hLq67݌(Z^MmTG-ޟG=8OyۢvO𵕢Qo_a]IJZ*+-ch#h#k-qwv鋈up3v^!Jaq–OPW`ݑGG!=-uǧ5֡nAys=^(|N+!b9QY?z#f`p0zSr%w5iڞjާ?)bda0"kcOMupb,mA ϻ}Zcz}<]Foʪ U'Yiսҵ)wrB31;[@jQg)4* 19Pg<C:"?nK7(nW=3\/4ko"wX+::D  s޲%gu:YTWXv׭4z_z7SGS\-K$pįTſ}1Eo;|G̖V07$Pc}r #n 6:"?]`'&^[d]F6ݍk7YaGfZ:;R֍giꖴhkWPvC"H0m]~ΖYd[-ޝ[؟{^Q![rx~uQQp?:7/X{^Q{^Q x~uQQp?:7/X{^Q{^Q x~uQ{G\,mn_΍B31SuryjۏsFܿe_?>/Mjn_΍_ۏs9ܿe_?>/MhA^<],V\hP1xrxOW>/Mgn?&idiNQ%tbCнwCнwyh/MΧ=f/$: G$: [_gn?&?GmG}/ B=V\hӦٍf~l@֬_?>/MTa4&uiJ6}>CU/Mgn?&9>CU/Mgn?&,`0} WCU/Mgn?&,`0} WCU/Mgn?&,`0} WCU/Mgn?&,`U=*ۏs9mNrK:e ($O?tsxSY,V+hû@xd.H>5}_?>/Mc**Ny Kyyc#ºQG;)fbL<ȧ75ծ 3}EvvrJ/Mgn?&_t+m(Kݝ2R,$#&4j)b-"S9|v*ۏs9VV9eqDOԮo-//nkB9ozǵMyh/M; WzmdB+t :2pq,%$O(2ciwv7b_?>/M%XEO./m/V;Wަձ>*sz ~/MsZKl$rX'q:;R֍giꖴiC+\??Ҁ*3<&DM+a@\߃]6rߚjCmtc9\ *ʣ8ocPYƒex@wP۫,?aXk^E ,) @9JHC*Y1#<+A]Bn=seu 2A"m/>x-3lRn#<8پ<*?hݳ{-ZE=<}i<5wNlu Apof]sñ,t=- ̒(+]ZƼY4q`R4l`_8)V~?#Ryq8$z$ }wP$oPD+\ {adKw rSr +Z[jχAk!f#RۼɎsvsލXy5/8\FԗUPX-Zl ;Gvc"ȋm+n ]wWo>3Ctc&ȫ66`{'9jKdnS[tK%U 99Iko? ;+Zu[HP1PdU[ 0rwQ\Cpɖ961Gat>t DJEI\߃g|)je\&|ƬkŮ.q>yvZLwQZv;ڭ_ٽah Ԋ$8/u/|}_Xb1JtVRQ\:Z ʢ B/ɡko_G\^pksXmco-qvǖ#SֵkhmIRvl$A_ɯ5\6KjjNERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW-k\c]Mr6f4iꖴk;NTLC_1_]Ctb$L1@^ ChbyRVD+zq6IY).[trңptHg_[̳CY* UaNJӦ8e^(*A+m@Cm@C0B`0Wah۷1OUTP +m@Cm@CӾZ;%w8#ic\ӭ 2v}s渿Yv ?^Yv ?^;!mlh:Pv= L^姛gn ]ף]נM:[ehǡhNn{Z%.1q?e+Pz?e+Pz6͍6S>s -T4O3No@{h ]F;xc;s*y  |9cKʼn_,󟻌u7}北}北-H9#K$Ktr22)V }北}怒LٟbT-mGkrM)M۳{% > >ht&9ov3R3D,`rp+o@{ho@{hJӢ7ZL $Ic⍤>[S<ٮ}北}怒,m#XU-`UJu==jZ1Q݋Sf89 =湏YY;h,-mok 0s qPţC$0q! PG 5Ϸ=Ϸ=ܴ#Kv9PJlx46[\XUsgZ?gZ Y`8(,z\i``ӭs~}wc5Ϸ=Ϸ=GXxqۥ%VMXv0i7Dy +o@{ho@{hK[lm1fK:aǾԵUIJ%RS.I@+}北}怒M3Oo%{ٚ.1 açC,p>l3r7}北}怒 G[tSdKt  fN㳷K,JgZ?gZ퍍6S>s S:mi.6$*1 > >iqX6vKy"Vd8||?Sahݷ9}=o@{ho@{hH`"B`)Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@rψ-j?bMϫZ[uT {hӿ-h+$v UB(Vbrweyk@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@dD`vV햚kO $ibnip2-8.7.1/doc/html/figs/scr21a.png0000644000175000017500000007440013414613100013560 00000000000000PNG  IHDRZ0Ʌ] IDATxw\'do{c[qj-8PAUjhXօ[hօ (2d! %ysOx&{i '5!@ua343[vjNῷ,^u !OAtwo|U([\j߾R&$-ǿHe)z !{]->?o!H=6HE >o5!54n_m徽2yHR"*}z%`W.DwinIAQ*6Fn ۺ7o-:n^VNnfF"ci>WR'nגv͛ԷqVn\ӣu&NӻY@ }GԿ)@@:> GnN`dIIsE˗u9rtoQ[}jiGl?K~'zoa[˿<[?*(UR8Wa~%z޺6S=O"!i93ըu'Foϣ[|uęu?MKMZ!AugLz>M(g_>dK<|3v)OpY.!D ke''v2 ӭZL:=;Lz$/Kqǔ#ϕԼP[iSqIIMqiƃKObu޽}؂ z'ѯ'є ;m/=,/?rKGJrrB:{gVB!!dʮ5!PBҴS1!GW鹪rjRKa !4-93Ϭöײn_E#&B>sjτ*X  nmgK$矝*yN2!<|/"?&zdl*`Xф"|7}A<(`Å֝#/V}am׭I%6^!-?4[ߠ^}Oo>\iXY4L%.& ̭4z9H9H9H9H9H9H9H9ښ[?)Uh@Kq ^\Wfh6q[$يT2 *y-ܴޭGر&ELx]t,Sݲd;اo΃^=d9n:0%k]Y~Yf棉Y&B^614n/jM*fQn_9^<6B9roHhLdl_bׯ -L]\%AZtlk~yѡC,?krE۸a[KU]TmCHؖCY Z*G@⡊?LP{Ny%3-Ӂ0XԷjݮlt3o!SU_uC;tDLi,zK71O|Ya[{!VΦ̓=8DUH\=MmGǦ,2Z~ى牝ut+!yl. {o=J{_&}_a=nK۟1uP{3]/(#t0֕=&Ȅ"!!i=.!D^cBHY*,#t1TzQrQ| ì'Pdgf:Plː-Q^.t/^\LJj^OQ ~ΕK׷m1Dq[7B߆1u^\/(+_p#2Љ/,{^eL5Vuq|\J/J.*]vbѴ&,"|ʟHeP[4asb!Ӂ0}Tl}}]"GxEzrӞV@ "aW~߽>,MB8_Vq ;u_^L;T쎄;R7C~dxBfoD5k!wIK05.MSWEeyGVTcVcX4EaÆ 6)*sxNeX7pgdĻI'?zv%D߬Y.A1ޑ?#¾YuZ6._N_IȨ묞ݼcXCB: Q6_L}? V٪:3F36SC?&6Esbo*6;ZnN Q4qQulYuܨ=KnU넥{&xHʷtn  ݼz?5?}h5E4MSL0X _UN%5OU۳}mU²R`XaAO `y,,̫ght(&P45|gغ 8=iƦUh ,4*P#e/!0F:4ku?W~nv3c:.Ul6MK a+``sS:hKi>P,*}'I (*}ȹM@,,@Sw-³a3ƩjJF, 3T\IbLRB VMlkeebb'e/Τcϯ7BVOlcmn9tچ1P-X;4PanY="K 74pS'J?;dzgGZrkٰum]JHsyvUME?J `96kL?Ϥ%vM6͕ǖ]WJVXy^ŏ2ij}wN5K}U/[Xh6؅-Bhewo!]?m#J'/>~˧?Mh n'c]iS\?oVaҦ@ܻub@V)yw{Q/džav1B|mm=Lk#a͌墒y !X/x~NMiSgVXPpqS%;4BY=dv𚧛iEyλmk R}Vt20"a6u" 堅g*-nVJ՝y_3ɟwʺL|7ʮ8HaX/M{ >;[YnU@'ֆ:ru7lwg1 ^:nR:+ @5jwlkцi/8MB u/<ϻ$-1ЍxP&Iӄf:2/4/-|~ 0w0ITV8~۲! 6')nMP1%L{r{yIE]vo16rM-1{B"aq_o`*AX4 ͋|#'i_7-ufDͥJKK?^FP\:fܼjA@0>;#(>Y X,BȒC9992eʲyj_V*'''o~ԩ.]RSRƷlr (__˧P}ѷˢtԧ޿u>{5G M 0Fx/k.fD(**244Ϟ=ɓ'sΕ&'6h#ac$/ݼ*ٷ\'6)0+=察3uĸ VO6$p:0]R.!*}٬ߟ;82%ɍVNp'o[ -<|C[{|!DU$jJW23238lE}:;˖t/:99]reݽz?\5EڶIU㋞Kp0'\]]Z ;\l/6/ͻ$c[VWesoOzHJe2l4;@o_V?}oM4RZ~gm^Jp5.aI>o^\tߗ.E4n*&=s.gk -g3jiM8k/^>|?CIeYLS|kB,_&y6>}[RwιՖ'd)>~˧?Mh n'c]^n m$]ėJ'W @19?c$8;x4E40[q~#%58X&B&O,IHwdt>QdtOw)+kDϢ+:V_$iv𚧛Hdgf:Plː-N L4X3-O$wSr&^gq:M. ʟ\5hxm>w?\!wLW:w6H4asb!Ӂ|n]he@p59CV5`gdDۑd턁-Io[l q:eɭIڠ.6H͙sTnBQϵh2K^mxG '=1oyˤ)~:ٚdlPZ" (UeizInnnC!~UMF@|~?(J ts{}#ZbV _2 آAC[i5FzU8dcBaV-LInNNCrr:MP}ѷ ^S~b3Zl6&Dn{-|*'S2N(Vc|#U:00jbÆM7R搓͚ݻpnBf\6BQA ӝoyu a{;z7j}  =ɥGa! א+}5;4?a[X1< }];<~;12v^<{/IѢS;Xx@\r̢vM=̬=Zs3Wv47{kRo9ؚZ9FzfSҳu3 3KF}Mڈ쟒B˾_4I}Ǟ_-I+S u 7j䈭[6r\.uQ#GxzJ+w0iYK:::37޾zK#"%>#to_ܚ2u'WU~g/%~7i AcvM|NJ;ן_~pYҎsJ{Nfl;-CwΎS2^nk?BZ-miޞovWW~.+?BHqANqAy߿VXy^ŏ2ijt'fK36lتce=}S'fO\O_Or通[hj.4ȷvHKO(;d*]KEZ{(W4pKOAS6BDvғ,PܻubD"'?[/a g#4]vb`lwF~/ÝLFEijG_+9=tsޜUl]V B$ ݑcg3AqQ K瀼.\\5ݹֺˀzbaAbMw(w}Σbʣz84U&{8X۵&v͂oo;J fY}bҁ_$<Ӟ}!!K#Z\*Mze7{gv ̺Q_HEem MmD%OՏ.f|36lتc#lڲMLQbڴe[qIs%wjT02D'ޢA IDAT?r~ɫ>JO|OT@LT.=jQ얖&)I@bnd4As:*}Iȅ_5hYCv㗯/ X=K1=mQ~d+{WIwbƻ4cÆ:6_ JJ~fBP8uڌ~YPR\L3eȈ3 (aIݸ%AԟR( e<_巎nMP1%L{r{y:JQ:k Z~όB%,yqc 43hcR$7iٮ#|;O&GOX}݂"_d(Es9q.K_0vWbK133xisN733SZ`eKgf٫߹Эf}W??mҲ奈˪ޡ?)4γF}"h 6KBz{_m:ڸ |:ɡNԿխ]>َcM'i\κJ_B[vn ˀ?":ovMw#:YX:91ֶN3Bgމt>>¨_&&;6cÆnDdjfvqSSSS':ͪTN%PekL- {@Ͻ (ϖ+%@),(=0@i B`D @]t-bXiQ|{/˪pit,)3TE;j4tf4tnsTDXl^xv匷iLc̓X4͡bJtu"Ȗ uʫKgX㺺<;G8R^Y0 rL˖hW.2q3o`Gt,ǣ7jcjQEN*/;+-;Ȗ#-+#֞(f蜕t’ߨEOR4b5j’/[th70Fk#GFLGٗڍF?Bp?PM/HhG ~%]g&50vŕ3,h}:Rk's]z Ӂ@`/!CD՛(J ts{j};fh@_iW:,_ֿ)C51P}ѷ ^S~bW۩#'Ks,M4M3 0X>I5b9.;6;ߘww! iޤ! kWQ[ Ĵ!^֎MN(-WӨ!ߡq + |{&ݗSgH~ %j@j\Y`Y;:˱S}BՅ~ߥ>ӚNojmN޼kM2N1`ImU5xgm^Jp5.aI陝jHԑ݇O$p?^xv匷iLas,y0z՘x^"nb]k;{t鱤f8q{ŶV+IdPIӜZE'T5d?54bYih; !WΟɅaf]mX㺺<;GFbPGŢ*2^2及ELx}I7a$!_iq 5owHxM6& ~ j̛0-MLN8_5ho3/3R%ҕ#}w !TVFFe蜕tUc:`ȗa##^,,%wSZsS% J^E-t@zh-yA^ʺI ]G-PzDDpo)aړ˃(qq.--Tce$p?i1r8.MSLG\5,{\:6^Gn5JiNQXi3Nb#:HE|3m3}oY.S9 !;6yڨOb{o@m86Œ<"XY@J9hT07ojmnrfs7QI }C ]->49tf8oy".H PK( 4FOo^^>8lN}>]Ǯ=0ЈnTU$jj4*;QԼԔWq B<Ѱ=y԰qsBX,JJ|z菺<={,h7 EC dvu0ZFҚU```Ǫ{rn^Lu,{H()x*Ưs3C#g)Т!~6zz6fKre5јP4EMSbHFӔ2vqo4cǝ/*,djjP)tЮSEiȿϢWw2"r~;{_|E#Gv Ϻ2|ݍbwmi-9=wٹ7B^|+9TRh.~*+ "VO@sdef;ԇ95iDOGhMѲ9def:d_C5܂@DmYCVvUn6'J%!(Cwi%.Y"I:/ԷPxIDD-??xoۨ1݌dF!]xSnkmt8s;ÿ2˗mPr@޶68d!J ɕ|.VR>X| SBH޳E=)QU(X4dPg^M2i =硓+!BbNDFMeZdViiu@ ʕhtJ[XeKG:VLGQtqNLEKp0՗wa ^wdl:B[p5g_w"3R+V#Y="aۣ\KXimbzBF|X'/$䘪BLj:d\4&W(.+8g|CY%W$F3;Ur7 u+eBht),V+ؑ#Hvk:Y===['6t85߾Iv>֫ukk \/w` dѤMr40cKdC6MvB[Wւ%+ d?54bI1氲S^δrk9}M~c5ώzj:܎&-ڊҪV>ƼO,D-b!^|\.}%wh;fs9\.>'@YZ4o3y9T "@]fM͛za:O -(|wi RB.X٤ϸ!ɗ|BcHSeQiEkxKt|5 2%|省 A3)]h#.zu=rE%c,}b~S&vq!7Z&BP'cThӹ7iHw y!Mٽ{ʫv%LxF}G-!djM WMyAJ:w6pibB?~9/*ͤ ϑ.o~ӿb}ـi1s@~] %sUKIO-W]5hlv4EBBHa~DqhJ>>~gy!M?Ń茶ҡNS%OglfxKo}m Wn㪉M2ٳ!<,&kJt䬱-M,B-`*A$7\#wly.J:qgA+}_0Z:yߕ7V4B?huDB!GfT/M,߭;yCV:\yKMZDPӤs7jŞؕw<:rjPfMu>D}{m4Dw& ML/r&|ށUty/%xϏj A3lٗg# p6u[ڣ7zv{p#\r+,q++ a1Vil윤%MIhթddxjie-()r;sB.4qi/!upրyJy[tIO{}ҙ}8p8lBH'suoHqguafa_OI;?n a&L2}LM}Ш`ju{J^N!ǫdF@@x!foٮ.&̐-06R=vLM&Ө`abjVʧX,`Y Ù} Ҩ`bhdTy%qSh5KLGA!Xh(V1~tŠ(C:j^㯜}`J,~wצ^@=t^&2@#XZ4o3y9EU~B5`ƦM[[Z0@XL|ƵoӘ6ǒo߱ VvUn<'u`1!TPR\tJwh).?۫ gsbQj˳@#7'nׯ\7dTfL3sKS'=X@k`*AnY6LG0;G GhK̗Z n,6~>vcXLp?Ҵu(h&@! Ou+]q՛(J [F-̟6} }vFm-7!+N_@7bNJq ),MXciE/RJzt{dPu}WEsے,fY0Tl5 4db,  Hؘ|cGGͫk\4oRځBׅ|յЭbZZ/OOkǦCmKY%Jv֔\FrSg6NODklxn rPW`*A)Y&ƏZ2IEO]%dB..鄇Ǜ&覴ڼx_nM2Kn5"&*/P@K= [|cy!KDLP;@Js!"ɪ1D@xךǒwp67w{E+͜xq87BSz@MhSsO3 0>m P0 FuѨ`dUc]X\EFKQ O3&,$=+-7RVT~Ʀ@++Ne9y>)[ 5LbIZ= fOQe4*Fϟ޼v9JKp؜|~]]=Vc:`enlb/e# t H]./kdU!)Frcd X?`+;@J9hT0uRS^]87h'CyG&zQ !b()ɣ?V9KvF qbfa%,I$ҚK8Ξ-9OP*:h˰Cs&oIRMZ:jN<Υ)L%2Qfx/(+x3ϦkLjzYƷlLGܺOunf14b9Is{GjekdakGE+s6{}LuLl/{|q燌 phfs(h)X~iJRf75^,{\:6larlORZS1Sz4.$F}Az(m'۾iNH҇4Hn<~ 72}^<T`5L'c)bnrٱn̟kK nA}}[/<9ڷSxճ}|+WJ!jV̰w-!7/jۏ,eOs l,M bamupրy&L-Q MQ,7r9CD*Ѓ(NHϙbyȄ]'sXDJ+HH_Z.Y(Y ,QsybQ\9%s+ݭ#޴3%kwbֵ#{۪/ziȄɡr5.<uSoˤɖ<硓+!BbNDFMeZdF @>7mCW}tNk:=:pDE>W#REKgu3Ⲃ{XWZt?T?"/ŔviZT{:&8g7vvv՛OWvd-KPX,$HJwh;RVM-I-c vdY;a`GK=qңV-;!dǩS:ٚ Z2lܹ*LJ̸N✗þQJ.,>`-=KnhY>GcG<=|f'#wf"[kȌ`zsvW !DύU:Sb- 9%h|egnݹW~;X,r5th^㯜ӳub##(kcZwfPWq\ճr55e^hu7 0=ݵGoqF}Қobk]6!d1kVzJ+ RR\P :=핍):#CєoS-%\ ^hc<}t /G? @]fM=x[7pPZAnE@>FzktcaB?17ސ"Si)7ζR_$)Mٽ{ʫvx QnjT0uصWrE< :mj^eΦf溺3" }@FQ6sp15_Y,qV#FQ24PҜukPkZE1Qm@]t*uߤ$2Gߤ$ƝWkbPVi޲+g\XhS֖V6P)VvF*1@u19?c$5F*BH;j|;AnA)!h O@k ڍ{ٍk3ަ1 8l%߾cW7cmth).?۫yY IDAT gsbQj˳>v~B!7f:Ƙ[>qxqL4m,!fB:[VF=Q09+#(4&%@|Hvi c8.MSLG)4a,!(n,6 C2y@ŏ|}U&cXLp?Ҝ6.`/!C3y@Uo:(9.$͍oٺdg|A-bW˪HGA?"rCLhT01oZ}ѷˢtԧ޿u>{#Arci?ηGj9E>>`)QYϟ޼v9Jp؜|~]]=?{`̪t@l;#U{[{x/ o? 2NMHWZoR=?Z(W] Naam"7vɹ{255f"ay5Uci?c==cav }j`];?dTGc6CES4M"MS,6ŽwwqZ3ߣK%E5ٔG+ZI"c%wHʝ*8!H͹G:<X4;. yemCjKN&i'4&bʵ^m%t8!rt X3(t♨._'GU~J>Ѣ'NM.;}[/<9ڷSxD-OOe59EUdd3&,$=+-7RV\?!}7 ܸ+9DBlEBv:Y<*ǐ*F`[Y=k.+YKKf Z3dWGeZGP3Nf@}F#]:gѯF:s;ÿ2˗mt! j/3mY.[Ano/OiT!MMr챋B`!<?%-)6MQ2}zhJ,BuKhZ,)4%{ "ڻc.X*WR這ޖ'UZr)"(10Rwy]r'u&%}v4ov7Mtze1Ѫb:2_k_$H)K\ShْrYh-OmY;)=tuwiO'촦ӣG[s5[p5g_w"3R/zr,.T3bMu߻ LJBF|X'/$Ҧ@{;q=c\ܘCY%W'2r |ٙ*]U4vJD!?4%w?pV>D&tJoƅĨàob#:HE|3mRc)qⰈv'sNNccf6$g=$xI=ǶoS"KZ]c-k$a/YpEκjT'"Tp"Z[jk՟Jb]u/%"(#81$~>Q{<6?rR7 HN(eg#]?}=zbUE{S3DeJTrL4 sg '[r&pA+-J6«|Ѳ[`!'Elq ,&de=aWwtoɜsJ*4x)mMQ7~ܼ4l;gCu“KJ# x; K~BL'2Zou~-Lu(n7nfƟB?/`\5EO]&$ha"K|z[.kbL)}EbT%C۱eSj5ؖS7(>`א vț - W*t=2PAFrFzZo m_6I{Jl̬qm,B%(LT]"sgN782;d3[Gy'Iݖg-1B&/Iܪ*#H7 ܻyۯ" <OSCcFC#eGtjkHsBRJ?H}C II#kWɑdfx`k9,].,Ej;cNBg#AJ^JM$t.&/I )c y3}lm$HS|z{o)yO-*ޕipT mFMmȸ 0hj! ~BD {dž• q开SZ}z6Z8p8lBwLMkD7#xܜi};413Փ~ Pm >Ws>q4ЦTS3J zՋ%y|>!J[+*Ξ$plc|ML"ufjf(Lс(RaSS3 EG,jR\Mpb hͣwfqk['v >,#mkf>WS @.& fnaݺcKE^lcP3y@MWCс(+)\BLePm0y@;eK<X/ (:S :[\3FPotG0F@oY7ttt,% JEECC`Pm(9h:;\Eas--;vDQ1HPm(9=yzxC\8x'ُmਐCw6ehΥ7ddV Լ_8^06%i"[+: Bst~^(ڔP P`@=7?uZ:4ս^0QD B @@L*P9Or:1?ɭGr&ZJ?ޝZ&xܬw?ؒjK%7(hbh*t=dl@gbƟICZhk~9b :Ή724=z7UՇLSAP)zxj6m`P+N9֥I 6ç|OQ|+?әYl{w.R;:MvEk^Rqhn씹SkT_1j@94"wE1khWBM5b/I Q'r/@@dI3xצ>>__O{f yr  9եDroGߡWo IGڱJ%EN"Ӥg RQQ9k [{Ga O\BH?vG(ŧsx^XPQYa@ cw@z\uOGwFPCMp̘(N?5,Mb{~Vh.~~h3Y@GjkzVn;p릹֚CDҸsrMӷcKzBȭO,XB HN wk1囐;φ r$sD+1Bu>|6)!]"q7(/|"-R;F_ʭmר-]m3K *,}Cq_ Ikb7d–UFmWĖMܹv.̶} 6ds`7CB$4ܒӂYk58(rw# Cv,v:yI's7#ʃ{n!W!LkK ^Y5| \^4jz):(PRzxOnb5W|W&SE>./PRYzշ;vvՐ_z0e3vr B3nP_(k^~''I{u9vXr&b>]Jc'LLG:[xWHA,M[#^Ԍ ƻw5eW 7 tk,H |QIAkS!cgH;3f '-#Tkt@V X̽͌ 14i^ B[v4 q) :QSd]?ݼQ* # ݷw[hz4o- %`!DgHwq !2:t[EQ"G~6cww߲{{̊w6!s.~99BL;%GolM/jϺ`w BHe M4T@Vܿ q eXū|ri9fm/[ΫjU5h*eBK 6o60K ʹEQw/J4K{k-9JO8?Ϻ,?h+H\?^W)~ 5#dR!;jVfI(+0:Z$w]2nk =moq7 j7^U6Y ݨKeYtbq (~%]MÍ2߇;X ('ƿ,G53HҙuJ6«|ѲA#Jy!E?{kF]m@eH-505u!/2!%\F@ ̋ =+2RO`!,c˦@۲"|^;U1"A)hw@iu8@@ UEocmBH4M/QL}Uѧ:=]Ko%񦡥ƙW= ?[cB9IsaSWx;=ޖǥ˚BJoѳ%(S-lOOߙWhѓڌ e- ]ٶ6jaRXBL"sg:]?oRVϳ$`ܴzSk 뵌N"%<~@;[#ĉ+{ CFK !DW \;P+Iܪ* (n^H|>z3)\c}FD ;nfqEd2Ûq V$?.(e؇[aM7X#~v)7 %_;LM#q%U.$9yeݬ)P"Mq&uhnSs-~: <@eO<Tk)X5~bˢ\= !PuGg辨t{뻙Sʚ f={󙎩]>O{Il$șWbBH. 8Rq+Ř1BȻus vN>ŧh߹ Pª]G=r1z3K1_ψ@Pg"eڍszl/'S̔6fϷ %gVn}l86!`QS:G9ӎv*_sٙ{oO= >;6nXс(Xy㧈Zչ§5gP>8:hl\ͷTӜG]PRB**kXIGf6nѶ}:“\G(aK~Y:ܤ*7qbAkEY: z T?+U0\MpbEw̰;C'o5; -W@]z TKi(U0 EW<,;@3&F]%Sz xB<GC@̲CP {H[/j -[~uI1ϯ9`FƦ FJAYܽyE=яM[zZ80fA ):+{;T ȁ`PXJ@;@;@;@;@UT+:IAw4p:;\EP8leN]]ܚEw4pOs<޻P{'7.xp4(/b ,_<13; W5$%QoF~P0@c5ˠܻnu{щ?'\sv~iQ~,XlK!(ePw6 :|vտ_,Qt b0O܄k+c:( /}|zq#Ss6.Q)DWYt8_B0-G5;s4#B]KsY}Zkr!E3g8bf)]0pۑ9W-8tkFs\PS ՚Ͻ&F~C&lY\_JC4|&cQ1VV(g<-*,_tE^["_>{ͽEO*$y gFj!TIJ?, @$6}j_wF4[z{Zۺbѕ_WecҺ[oٶiS+G&꣪vE{5ofТyU~MUF[BƢtqr1ol׆[%؛eu*)@MJ5D%"$](ǀW1n/sBHyOu6Ғ~R$a F7lӈC!(r8$暵;CݎAӇ˯ŏ33 74Zws :$ƺS j!x0ၒ͉82QJI ^ҠKI!2QcM(sBrsz@ty_7陷2hs+I Lo1~-Lu(n7WQ=\]ݻ:N9ž>ǗXi*+rcEb(ft͉nRN*R *ܶEٜb+2Hi튩ˌ(gyDsM-\fqO 5j@4gs3ADgg5 P763gѽMc{ϢDsDb[t:]t;{{/]cNIӥ˯*q*{$oqb@O_7S_I"şnw>OE(~f^.]lUoU=]]{g)J*nv$8} ”PqQ'I/ Ny:G@nӹSb}X,BȇKpXpbvIEEINבIm SW޹t:=2 w T^6Nta)o`tI%,8{쒊DZA."ݹӂՔʊXwYۥd  &}RN*BRHzwdk@P0{{=:ɷJdO?6BX"22W.V!D8YJ!DY*%)xG#֪F~0CIտQI_!2bcAPoAyuO:nHAI5k2$Тm2llO+6_]0 8C'zznvMʰo,˱̀KfAtbBp=dQos6.\:R.+SFgj5͘#_iuE'K*菌ՔʊXwٰEw\2l͘5T2':=7) ƅisbG`t {{7yPk##ajLW V ,~F?09\*}?[Ŧn+^k鷦=5=|DQD҈Ba-5PT~:C 1;xU[>ͬr7m3p޾wbC`qHRF>s!d#=0lqCޢg1Jz~P]~.M)2(>$Eiwߵ79u&{.Q>f\x-#GA˻%ϻmY᭹IݖO@i@ ǫ9@C8 CTxrv|m̈́ࢪڽI MQg#{|B_ww11uGt7Y@L,^+: (jjf!2>+҃cZuM=>&Θ(+-6!4~X[~iEEi~ʚ ?P&, G[rb>,aCmbϯ"e2HD-`,R[Xns1b>@]l#cSOos k8;3br͎&\;͈Z٣p]C,زSOڿ=43ۢ/xkۼI `o2ऱmFF"g5 " (x"6sMȁ"g5;x$YiJ5G;O+kҥm9V(WydH494Nഅ߄H-$5Vuj `4bfIҦO-oIüV,%wd]ۨ7"|' 3tԷlA(J}w`Q=@ ;@;@h|ʂ{)Aq2ёk$jx,6;yM#,UH'(9tX,BIRDORxlٞd(",dzCvg:uР;OƟ%e,">?ӧo]8p|K?|t2ݓHv"8D/toa6loO_O{,Nкec+BHiN.t6Zi36mjԄn2o7jJA* rwy6g*ocd,bCw.zˠF Ptyśջ*BKiF]*˂c !,!~?RrzfFݫ&U8?Rzkoz6/@J!"Ք,UlS7!x@Ãx,-_xsWe޸%W_>3abEU}u-퐤BJ|]}#=7 ]RQQ?9uZUA!l.(/y2$ l2{B읂7Uek "'.(zN1_{Iju8(?td, )qgw^={M: 6 ak#wllO+6_]0 8SZt^28Yc̘'/|DxznvMʰot凥Y}.%gzix,[Z4xfo$cwe @PϰvAwAwAwAwAwAwAwAwAw?:+!ФZIENDB`nip2-8.7.1/doc/html/figs/snap6.jpg0000644000175000017500000015304613414613100013514 00000000000000JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJ:?S@ Ã*}:k?{빇ďEFT دJw,k|cUvBI%P6!=woһX> OH@FҜc9M٠Σ?_ZV pe1IW7⏉Na_G  w;{׊KPk !i`odd䑁5mXɕ?:i Ey=#+ ֬\spGO|lo-ܥRq$nPh @pA3v}Ң{kKdy$P2895R=H}i,)c6"'s]==j&gK`|7>^\![kQ~c@2}ץjX0Kin]])'sӏΰz?;獯Uo*+Q?'z[Wx-W1Eto*N_k|\w_?;獯UsPO ޫjumD ss*r$}Kyx|7y.0ۑ )s?5M[^mر HG''?J=xdn AquN8<4P63M.@Æݒ5rp.NTϟQ(fIIEΎUH?x F0\F"XPIv9~ě)R,dbcm=rWc_]\[Bzg߭Is[p0D c,F@ޘ?gEvZ.6Cs=Ί;vGU f6vMq1O t<+=RJr^Z0(SԭR51pC=jψ% &!%6>u-qҖ KvsW<+ydQD,:VN4o.Y6 $BWP[Q]=1AtmoQ0N9b FWӤLsu&(,HXO_J}rWu}jg]@1:iH.fgXCk\ -8Yj u9+O-;UQz9県T]ZT_$N@\+ۓ/bu]jYYDo$w3?mq}RF?EfШ# N^/]RmJ{e\nBٶHY$AI,r0=XofYa(eT/$eIcqWRdy3o,1<Cq閗Oj"ۨp9=:TKQ]7ssclc`x Ьeg? T/+}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>yj [+ǵvo+jm>N[|ɝ.U{~:V~:WyQEc[[c[@koO v:c%;pV=4jG2y/", 眑T}ZbncR"'&6UmIdb$p? St9S\~qU1iPed?/R&Yʯ-+&}k[\ꖖg">٤P[' tahGPe>|_w3Xf8aJO riM[;^[Kl. ŰhX \g ,{co"qZ8q"،-R@֗÷o21v噗bNNrA95WZt{xam @ߦO5QMU u(Z} > rF;^6,#'qvw4l[devq<ʹFK%łR3&sG=? XjTH]o5p˙W!{YX薫bk \6ޭ-'q_f'ޘ(nA tUI-鶷Zh.c-$3Uvz )Jȏ9f4C}\f'#l=GZὤ9.Ir4fjE 0Tv'qڙc=NB^-O13 z[AjܷF^:ఉК>UTgRX 93-O>nmau B.:lkKX-?6vy 6!p1TgQถo/&$0I9stP m ϱmѬtncYLI`l & DHRLdU+` >f+w{_#4v]4j&iBȌ{A4H"ĀF@Rn3k KA~mKy }EN8\AWM HLaQw) 03ȮZ_Q=Mc^K e>$ cASj\\G(R |q=Z>Y7xu9oVثldojиWVTQ8U2RX:娦7_=\A}y-dQ*򋓞ʴ>e?p5QR迴?n?ƏpR͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_YMifH(QRt[qOo],(OV7) Dw:'VX'V]8QEc[[c[@koO]YZ#,u:>lʡ2lڿrYw~7y1ݎ6>\kV\dG~iЍp *[)G37;|mR1 ix$6KuຜAy$hǂB$A[6-S2<0%@Xh6CgtӘw%RwإnuY[<ѠS,Yk _:G ##W'{+2*{ZVvCj1v%Αq<0# _?ueyV9M6#a=;sY\9N|v=ɭIkcibWxdf2|8eC H"icbWnSVl*$J0K''D$xceN1nJ]WBKW\lqĖ _(}8ǧ^T]Ji%~5fXb0ΜOڸ\W\z5mn \G*Flc$9c~+$Y1n R?ӂ1OH4fze/?!*֐Y oZ? jrѲ3E9y8׽<_(Ә(((((((((((((((((((((((((((((((((+a? o_ocAJh|COXo_o_or EPzV>zV>oFt-]A 5AjE$Q"0i?h=t5?y6={A 1IFZ2(8ag5)}kO40dU٭Ыߞ##'ygEws?Chzve-* cO8\tjA)^)鑟u~كFGa@NO1oH9'g?~TT1ds66iA $PX| H zrǎH4BNO棭RnraEUQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQERa? o_os4>KާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ7#[O O?h=桔RX>wE%ͽ~,[Csnk~}k%`1D[ eI'.0Rfeܺլ}U +> F%a6h'ˑ@; {i817=rG҇++@T!1P*T` )`I ۋ5=F caƱ zm,X[+n ǎQE{g7 ??]Fuyw^a%`/ԍ)66_hw|ℑ1ۨWj]-앯s;??G/¶ΥMc#W/vewP3~w,F"&VvUdvTnBQd}'g(O~Wq*DrVv\wyuKK-BQ3_r6Ҳ*v!Hp Gr"`I >{>߳3'\K\䚑.gh +0ʕsbc?)WקZ#O~Q T:m܈ͥF m$ 3qYgDH Lsx|$qS}FK ??[Ry`ZE{q^#\UL}hJ5 \Uڪ׊@Qs`I >{>߳u:r<ùeb@7J$Z.MnX.nV</fۜ8j>;]%ߨ{`}}'g(O~V}ru2 #A,Nqץ[֯Q$HTR@ū{>߳}}'g+jPUlkؙnDd,#ݹ[ԽZ? ??]MHΘIs6ALҨc45A> ??]?SQ>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳R@ V1.euk\SP~o_o_oxQEc[[c[@koO uZޱ8Ǡ=F3Lv,<6`db#dFGj״UL| wʀ*Lzj&+ kXG# 2\7)#p.w]?p)mutKV{{9,A#`cnHBk%EC r7?ũ_Zr1&*ʭUrTdz <Ѝ`}9#Pj_'*[5ٮb HG* @TaWu Ps}%Oyy!=;Ocuy?U{<P\ko,Q%듟¥DE&x7tVmE)ߠsWycc{ʡc`\#T%rs|^iOCto..VϷp(F8OFU!>Fp0)SN6yyIU$F=}sT{Ӆmyv`qE??^ٝL<[o"Ȋ NVcMtBcEHNu s#O ut_gm>+4&dUm$`ҡF҆23AB)i+9zV}Fw{g !reE;#oe`Tmwccq۴@3?EQ:X 5mZq2"T%؎SިM j7(U]yl;? 9,r1jȢٿھC$tmb\Ÿ- *Fͤp;vo*KAz|£dgpzkSW}-KM7k}-(V*_*!qM4QH$d8‚x$rMsR> 6vip"w .ƒu$W/t"F7*)ެ3ʐx'=kle>LnK;;ًn$>Է:fSHvkq"(/{>Ki}yu-FGj??qTݿI??ۺoK:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq7~ h:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq7~ h:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq±S@ V=l'hQ^:#QR~:V~:WpEPzV>zV>oFt-]p? WQj6k\ Fw:HE{B5OSk"G)eoϽmZǹ}#@}&sFFME#L*2Oj/5xƜe&ňdRx,ykӭ,ͥ!`%RŲX'Mdx_Gx`쮫^Le'XGG&[wVmMu3sz_[iWְEkPA`*"|[J-phM{ gJ_÷>DžOӤoD0Iw.H,F88xc/dgr_!\X=Ƞ{mcPN1xnJ`229=y1⢡Qmmc[jiK5d4,1VSi,u}B|Ԃ`CI v;K 2O^9/o% ΪXb2I^sSk omla?J9}j/bq5*x_}jQWL&Gv0'u5Zm^BJA# py53b8i11 ڝCuȸ!d3C?.kXF+CiI|E~Y!f* '}־ioO |K<ohD0ODw'@pAsxj_NFgߴ0e=zȗo4Fsb#Oo I`nY/7r?׀4,@#u3H|xS*om)Y3.NwRtٶVI(@8#؜k?Ο ?2R#pzrr;㞇D?ƯW/]Gu|QEAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPZ+&$ Ps_o_oQEc[[c[@koO wtQi?h=t5?|[J-phX>'o(Ig#os==C2lV8#ڽGРb+Eu9G7lfm]Y*}9#G>]]sR 0kYbL 8r9] "a \|S~u3V~ Ar?Z4a?֭g)o&XKįp`ʞGz%柨q k^ll{e8z`c*emwTԿ_ Ro}Ʈxk{E3!HZ1'k Y-DN謉+Iڏ;/= =G}?/juԬnu'>KncL@q:ֺhemddr +qڔգcTbK Ro}Ə-K}}Χyumk[[@JGP@8]MaoZGFR;Zn Ro}Ə-K}4vUڌ^"̋ra6 ,8hzid)pXt\'֥ji|F1/hԿ_ʊFe~'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ5m'-69f =>^տFRNY$EJJ1: J+|t J+|tH(}[K}+`}[K}(mZ<7#[ -?GЍZǹ栖'xq}ga3>\qX0LgX>M.͏X%dMDсYե*2q؁217eYQc?UUq3I z֭ -'e;Vxє?Q$ڧ4k#o -n`M Fѐ<Ҫ]F s-ݰd1 |%\ҺњoMD[hcp@COI>_[aCҺ\7wqYu6|ci'dJco -'ݶLc)xz&UBI!s{n~SmrV\Gu\RJz,IZF3]9>wqZm5Mr3+6wmVfc5$-p,G4-d)CS{0m<+m"R])9ƒbp_\q3e8`0rzJ;+9ϗ m#`d >M>k=H$3$!+# A#1R\xqn`WHCAmΗV\Gu\RP4}<īHm/ ˆ A“#-zɨDŽm&˜=H>OoG,QF./ zn6ʭshD?, Y5m&܌%~U-^Ioi}gq<~8Wer)$x{GG5w#z۟|S-m"\Aslib]N>».y`[DX`::*m}Jwڳ:vn|=űcm8`*yt.3͸25?URH'EUw94[v5 719m#J00;DB?(xX `š0Ȳ-ճH<'144}*XIYnI =ۢ{w_1;ye>2 ݻ#Z;k5 ۘԓOֵbm";`?(W1v?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯S^yj<?#SX*lNi+6?Q®\@A$hKo0 O|< 4mR1v?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glgd 4R4Ѷۊ+4)ϙw_o_os EPzV>zV>oFt-]p? Ww@F-?GЍHj jsPKH`tE9?R]_gCC AfCjؖ+ ۳:1 #E$8=zV-Wx}r/o?|Ci?PGUE3Go>i?PGm?(?ʿȾqپ!7(]m?(mCW?>W?7?eپ!7+mCmg*"fxol7?evm}^__s8 fxol}~\gw }~?Qx3}|Cx}r/o?|Ci?PGUE3Go>i?PGm?(?ʿȾqپ!7(]m?(mCW?>W?7?eپ!7+mCmg*"fxol7?evm}^__s8 fxol}~\gw }~?Qx3}|Cխ*p.noZhr%良؝1bw4ulEﹿ7<VUmF\0~Hp}O=jm?+yN/ sKb/=[zz}~=b/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տGa-qlNK[m_KZ4R+FTvWάZ?ԯҷJ?ԯҷJ(}[K}+`}[K}(mZ<7#[ -?GЍZǹ栖' rZ7!tmFҒNP3Rn30β~k'Zf mB3qqEeU'MkK-Ԭwm:lNhV7f `S(e9dk)olM̛<1v(C'֌ZJg}o~5оF0pEZ'֒(݋ :񐸂&8qPݵb]Arh5ns/ΤxcLWm$sVvwW,PZJ|hzwcƧ0(Ѧw= 35%EvDSbހ.IpѶyY>)56UywhAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAy\A~gW_kؿ?Ґ'VX'VL(=+VRJ=+VRJ7#[O O?#EF$59%I}igl"֩ >Uw+9-{`q@Zmߺ@Z1^MP1z˵oڟ]Q-1aw7%-'q<^ۻsr%($tm^f}kmFI8,22u93. ֪r;][1B94fI|QdUD".[󃓊tgl}#g9`֖+k{5S+n'vсAǥY. g6OYw+9!Q &?om s]rٱ-vWYM 8KIO%8zl]ǟUأ?5)W4-q!nV6V.cx:LIm^qnJ J 8 2u93u_i- |nVaB$b[H?"8SĆkO*A뎘VV:eAn,/l;/54DiwVRh#5N nk}ErKV0+hXcEDPaNj hy4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@xŷ 3mC\ߋA ggP3WDRJ+DRJ)Z(ұo-ұo-O5AjmZ(s]B4Qi?hCPKSZ@D֛&')}igl"SnaҘEPu &Fumnj|m A?[OmqO)a97Om]m29x涂<1@Eύ_𥿾Mk+R@$?R*UQύ_TP_?|mٚߕ Tnu%լl EHCs@eNC,J*fX_AXylše Ҁ,EQP^\էM> s㚞 *.eb1NwWk}m{MD )\u@(wMnSq(< $՚(* l'}Z#y=Qu(,W(O?|mٚߕ +;IbBG g t3%HB2(?|mٚߕ U؉kq@ ύ_3OoV ٚߕ ?4+j_[iR]˶&ύ_3OoTIw,FiX^7:VPH o]\E3n[qrc':`ύ_3OoMUieN#Zg֝.۶U_?|mٚߕ u].[9d" dHenFFJbXKV8w1@fim~W(TZc y$Ӓ#Xy2x@MKVzq,aayύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ _Pg͏8)l% M~%ݲ˝#jP:wE;_ZtKsjFY#8Aiki. (U[3aս}i%+w66w}ea¨=Ijב:ePq r3-|idMmlg߹w8kRVGo|0xѝ6}o{Ίj Mӝ-?$W$dO@~~u;&Ԭwk<[Nv.Aێ+Ҩh@xGo\+y?z$]$|LVDn6>tSOk<[9bA03tq#Cs}9kmRMƝlk;e Jj)tX?a[xRLo/ aÀs1cNa:Iǟ83^T:9n, n`t}wc5lؿٟ{8Ǔߜ㞝i/.LO{OI.ֻ*z]G~_yi5}:K cHf0Ѳ̓Mo Gj'L$j?Zz)_~9ZvM5Q ~I,M8k,ptvsUۜ:WAa-jWv{s7ruqKuxX5̯ګ@lqB=Nm5! U3i6jn-<u\g=tPl2IJI ZOӡӖB|p8fJק_zZ0YKu * O[~,o jks\$B#i%Ny=뭢9.u+m5g֓2%@r0P1*ΟZ֑-VѶJA;M;^-t#.a.-Ia:VNg>[~hHe܇xl`5tP6Pz^I~q{oiMk w-~?S֝~>)o+E+`;lһ)o[ Ũc2Ukc߽kC~uOMo *JAֺj)ߨX(@QEQEQEQEQEQEQEQEQEQEQEQEQEQExǥWS\zYihW[`hW[-Q@XVXP'wuxoFt-]Zǹ(s]B4!%A- "OM?g\AX>3A6?@U ֐0|cr;!ǦA丆I%b+ɞRSW>TU~W>TU~W>TU'usdOSGs M rK E$dgh(_eˈXxOyldo*(* ,-ZDKu8z;%XcZHH(<##?K@Q@GkJaӲPm=wns@a7FJxO0ǞBǦjZ(9UF6*sGTQP^^Aaj7.R%  [sӣY9U"23PQEQYh\i5k6\`ޘs@QEQP\AhaS4(ANMOEE7!71S0>()KҺqgf8 RhUiu X_8R >E@]/$7uZ,gwL T6ޓ?g\K]hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@r1g-@Z'VX'V@ EPzV>zV>oFt-]p? Ww@E{B4!%RX>3A6?OQ44?gO5׋$i! CXg:ph]-_U edVrU|䓖 uK 9LKHͷ;޸힔洶w&iG!( u>ǹ\uVVΗv%[  9Sެܚmoi#Q,İ 08zt}2b[:qmdp*ɪQ%pFBO`>x4[[_!/gkjڒivtm5fVmAZG,AmX089HkZ cDFr}AP14M:{Hn@q)#KtȐS}DM[[$kpȮ @rjPծu z4FN#9M2G%\S}Y1kوǓ単җK RѼCl3FEov9\)^--"T m#Q!.Һt}2lB Ɛ*А IqX76VPĭA#40qwizmZA0i'l#ZxiW:坔BXݲPU[;{CD)_nq֗7^n  L1+iк[+M&ܰQph Ha@hM{+Iaapt` ޼z:Jclإۙ_yU5eW@bfEZVٛx/ Y \=U`db,Jd >[0@|gL̓q-"T fnmkPQ7i# 9ACۜm.e5wrsܙRldSWKޥݜq 9k oO&gQX@|0 6? yvW7|W'6?+e,m#XU-`U,`%}:}ϏH8I{߭ =__|A k)uI#G,m89Z.5s\6 }c`# $#9ً;QыhDsҨA XwϽC&L4}KB^8)t+nPMƣ,ֳ chr U_3l$_yŒu]iW]4G1bW(}FG4{ӧZߟ]UO o''ea;imByS#|=e[9Jv8!J }uޛgn.DaD4Ug眜TΒ*y7s,R#2(躝wI2B& tgɕNzc5mo \*m/OH,-`I,P9 o CwrgGx핹cn*ψ 4qďܤ6AaiM ,t`ÞϾimloKU gK?>]iYXxiP{/8|⠱}^=:/խMF?Mprك>ۍ:oM賷d`"_0MG@4:um2 KyX;,jڶA3 :t w4/nU䉎v $E 񧖌eWÁǰagi,}3MorRqZ>w.\筞"Pk*F#>ڕŔlFru?ꥵWh$c6} J*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[Gl45xxn9T1 -J+|t J+|t(=+VRJ=+VRJ9#S'_vԆ.O'Q@ h4P7SIE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :|^IKLkwܴx1@z'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW5ibZ]-??P~:V~:SQEc[[c[@GYn,}g"eC\ꗇ\]рHR+*ӥ~NIg7' rG.O]''?G'?Qj}f]}o.OG\5}.O*O*OSG7' rG.O]''?G'?Gթ_kw_r#˓?' rGʓ~_ʓ~_~/뵻eC\˓?II?|QI?|Qj}aܿOteC\*-OaRj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]t_nSW QeV۟_۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬W?xmDGYNFOoҺz_F-W[`hW[1 EPzV>zV>{FIֺ k]M!QVEllBwۓǯ\dkG\wYn^2=R:\'} w"l cgq$n"i@c/?jQVA>s{elb$J%,:vyI.o6uM%&f|x<:{ bY#dda?*]/Tk{Qū*I<9lä-"d$w7]GS|wW/Y˷˴aw63"Fn."4urK$%.:s‹^=F;m:9f6h2`^qsU WI]q$C,S"4e!sowa=OXd $ds~r3ߑI_sGnZIuɪYi!hdKM:wu9;I;F-{l0JM%`vT:}Ԗ$K^x^a|TߟŸ_} SuQI,΢U.m*@ Su6"ynA'Z4Ҳ*Ϸoss Kki網{o, {I>_ΠK[YNA[kѬXZG6y蠟¬GgaeoF#-geiZ1r.dF#s#960}mf^ ./H~F[DZtQ!t[}o&To\shJ{c{gm|$dDkʹt=8JZ:TrzcGkqx [=–-OZj]_q+}4ź{KՔa݆qT8[c0cVaB ' & *+lN;tyWO_6{wmb uGJ5?9c*qj?iIoovL#GP GYky ,BǴ\ޅz%0[\vҩ T=9;j_i0ߛ)/8Q\R9mg]W[K?f1l b&OykV:~b J/ ϸ~`c5=%^C,r3º~OzKo}K׾(Dlɟ$rFYH5nOiZGs,J#VHum*S@ԥ=$] ]x$qW5{KTӵ?۸̎KHDRlaѱۡ4tw]ZJu~ک,sSڐ\'h8ZM ;MX/h#E`GFխ=.Qd'[[޴RхB~qۊ<n[KpU+{Lk ;K$Q$RkVeӯ$k6-h2H82j}jUFe7^to# -E'cq%& 3X`0? ?#z2$g4-OWmoTtxfa%f"'c`1vVa2xI6rnH2rNw8_W] '6bq]sܯ@?#^^geGrJ#ז͸g H܊ӯ{: ƹ ]jچ<\(D.V`puV ϩtJʚMMfr$aZ cҀ{\)QEQEQEQEQEQEQEQEQEQEQEVw_kvW #@O+Ұ4O+Ҙ(=+'T\J֪WoB(Pb6dڻ9=_W!]K$2pq\ωV C=KOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=e] r06QRא?x_PQ^C^ > ~@Ey ~@Ey ~@6+Xc =Fޕ*"ƊQFT`+ ~G<Z^K /\۠ =RI=%CX 4Z$\ ~= RGsYo'#3r:[YfyZI;8#f8j}۫Щ_$ʍvPěu^i^lmBHLrO*'֚z[ Lbl(䞨Nk{ޭn.[릞C3a;TA9S´C(´C*eǕk龚յ=jO]?HSA5˿>ݦ>al̙\ǂҨr^åi^[MqqwtRvcy{GGn%my?oN{oߵ4ind -@)[/bTXJnF uԠ|E^tGty.JɆ'(JǠtö3B;]J6BGU-#Z&ҽ<ɱI5M#ϖ95%օ楧%iE,7F R RFM&=&H[w<{!nN75VVg\k[y4 i-'fՈb<`=A Pؽj6PKrXw;p9#ac2=ˢ db6œ(#> zO} zO}O.S*czro_-o VͯI;7r((1n8v[R'ۇį*D~~~mێgqFTk+O??+O??ª~&:+yiU5 FRE[[ep['4aф%I~$ڔAEVĚMq6I>?5=$Ur_=u|H|Ci)YCgNȥQ=p1/_CڷG^I}vB2y&V1,YTx[ZQƓg\AcAԳ69'چ _C' !p| <<3`K`Cck;~4nK#Z6p 큷v0I,U W~X_oA|֟ufռFNk[$SȰiC̈Bqu-O~޾A_ݠjx9oΩcmsOdkx1é0oj,@#Yڳmc/iiI9%U TpH[|1grMJmȱY+HO|c޳/ZEK7Vʹbǖ[ cAj7aHu[ic 6ckqPY{6c[m~mu]Q;7R$zS]/@nƲi eM{02 d` ('[Vi!IQUeʱR'ڞחZ4MLItd$+ROZl֍7[]-.XZbd !]Ibx7|f蚼3u4``$L!<⟥h^*žm-J9dԣ4H;F޹ۙ_z W|I/os*Kq6O#5f9h:9[[!+ieR HV?Ľ6.tTT9{ n[+F 0wS[/# ]hGkr1UxC^n_jFWx6w;x`03"K]?]N/xZM:Iͣ[-@Bce'WK^ CJMCZv =G^ <{vHBpO5]"BT#,כZ5]CR5Ƶm㿂 َ A](͍jo4 vn5+{TE98RM[/ekRD)kϕ#UFwlu¨$U {"xšw]%[c*w+=; Th?j+bzJyk"RR#WE/?7.++FAmoCƨQ[[f_Οe<5ax_~o]qQ {"Th?jUf_d?_X^\UFAmoCƨ0Y/#WE/?7.++FAmoCƨQ[[=e=K?uA|qs{\ C!T: OoCƨ̿?ɿW-潅gr x ,wDGMeiEk!BBU~VP. !nE nIZB8z]۲mvd [Oeq}Z쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻w_D%3aieq}Ԉ*SɻTu$ݪ:Lh(C5_|m}+kzI$ {Vq(|Wb[uԭIki&\Tn}{ s_=uT 埅ER<v4E%. ?Tz֪W=iS9[VakoջBTS\A i=7Υhʆ '*<ǚ@܅vP?1-oZ{@oG֞[h帖,,`rKci\ ?oG֌<)4HѲAE?u03͘*ےz iHC+pA4)DrWef(ꖦW"27+j5Guj n@?Qc?>۬?OU-ݼ[@΋ !f*W$\z6(((((( _EIëd8.>VHFƊUzS((((((Qԓv1) kzI7'Ҩ/![УR-/![УR)tE%. ?Tz֪W=iS9[VakoջBT:+7|O&LX7?qކ#𖡭sg\ZEJB K$n8_ xYkz& ĖjvЩBb$ ]3x_@}i,+̑F7?Sh6N$8jig6zFWllt%'A$bܓԒqҥNm%?sa M'5o3]fJ iEWsi+Kbgsdw+kĞ/|Aki&DrŻpw 奰%}66I-ץOuI_N+mgȼ}fچXd:M_i?؝Zk)MK|B5[T𸹹frvqPt˩[latuk-N; E@<0FHYfGP]&E55M2k6xmmH8Q5rVöֵO/_io%LdankZeկ͆k=ۥ=ܬqc# 29|[kV5(t%?!W28rǾZ95{;}4&6ӄJ\ln8vքԚOW>'= /8,l6]\ 95GPi5վ] X U$F*J #q\m_K7N:(]wBT~8>[zlՖӇ X\Lw7? /xgXc[?4 u]o[;h籸&ks eCIT +2IZhdm\}XVD9<|ed {?\ ߜ;k~KKӻJ((((((((((((Qԓv1) kzI7'Ҩ/![УR-/![УR)tE%. ?Tz֪W=iS9[VakoջBV:呖a5M3`켂ǦxO.bI"0n ʀFwu@MGy_?mgk~W(/Qa P<?vKgk~( }u;Gu@MG~>?|-s7%ۤ !8 ^ҭ䵱XeiK<سc,qVN`Y[`;)#Ǹ;\OES(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doջXZu?EnІ _שj&,n?s#Ww4n&nhyqd q!yj1o>K $NӚMGŷ$:}I,7d pu~mc꺬RLf#2WMou5F i |zPP00([ |Y-V5t}]Rk$"q 3AkF9zm݄x]Ob3ϵ2߫ʑB'k qQvFyNv7F\V//yY\|Ϊ62H8Emx;EþӴH3 83!Y$D~_o/oX֢(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doջXZu?EnІKms>_Y؛XI| HJ3b9Pfnal#QRUD<1V:rEM=]~mycy!*F27d}k6Ú06>'XkAiy?xx1e"2#)c?ֺv|%x@-#(r `ڪD_u{=:?j~yisms&'$S2@Ao,t!d{_4Nq|0wk]q^OGVcXj7̒F(`o)4kD Wk'U\~,NX)l`"ܠvw4RWq6wP MQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ڣ&QcAERto]\oOQ'%_CڷG^^[_CڷG^IR_ J]+A6?L Z\Tz']^s趭ל-v0(/mlR[[m$[y#8*IaCmKvDXs $dki9ƝI4O4 Oϰ~Q}ùcN? i[a]~Q}!uGP0 iGA;ks/A ?"~QQ kX6;-1?@IwCIN ,mK,laP3}f55 ݷ*GZJ+d`:nRT"%)(((((((((((((((((nI7j (WǤJ|m}*9/տo :*߂տo :*HJMpORR_ `JJ]js֐:u?En Om[!G kԕOG _797US?=i<ćT]ރu-m'p݀Ot3xt;#V.fI^Gp# sx>> B%wollzx T)YZv2 n^ߧ/O9{R[GVEONz0ڴY?iܷh2B:rgKi{ KIdbq@ÎFoZu {岼%̛ Spe aU'y_?Zש>,Ad&D.S&"EiyFRu$cL4|b* G=q-xFۍIyV( {q G^)Oߡzqgk+`ƒ9%'p8U~,Z]^&kիB@}fK-6ln`2jt } jvsB-m VvK OY_X#oe,pxQ]RO6%'V3Zw4?YKYʳf9e @PU\wPZ<VFXp8Y"zlQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ڣ&QcAERto]\oOQ'%_CڷG^^[_CڷG^IR_ J]+A6?L Z\Tz']^s趭ל-qPI 'bNق{p{iYV+# RXP#Sii`QZJă遐G@?'/Q1c>:7 Wf|to/@ɼ*<*ѿ\Uώo._ʏ._ʡf|to/Kŏ._*'S$"(3p&7 4J<A5h:XhŇ }/?\~U~_:&ҧ$2 ( (((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doh&g.& N!x su?EhꚦĒznU&X@Xv:luƮۢv'v[5ꞗizAmplL' KI1[Zޯlr`3[@ $I 5"|9=DfF tve @ tE]Go&yXH<2>%j%nCn|Sv9ڈoQ^gZG ]~O57'>5"hƮe@Wi_~:ozoon`O.#i$|Tdz ?}6[*մBɫ-RD /98k{KoW^ZԡNt%VLq$~dK+ [~63kBdž5,5 <2[Ťe9O1J5 E><^6P 3 `qY mLwsv&i5 !g*j7'koWiHeAَQ]˹ _{N>m?5=$Ur_=uU=uT. ?ҿg\AZJ 2u7jm4e!$$_wu?EnІa+Öі) w2\vj})e" [=?|ժW:e4'FHc3!z2ކi=i=av[76F#smycFO"Ǵڏ gǴڏ g\v[і4{O.{O.cf 3Q Oi^?B4lJ9z_VhƱƊU uQLAYnkaj2LmLAU`I:(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uz@doջXZu?@5B WP\ù̆@$0 p^Cpcݙ I ּ~PKk4ڏYe ʿYҵO-֓ᯰ1RU!`PTsw=}_?ߖZ\ug Z#m#*FAqU=Y5`\\)hˮӀHWEq6izNKN_-ݮl_h 6H5;%׀|?>wiwRM=I䍆ȼт %6+DSj׶Ks\܆0[. ;#?Z(rhUTϭIldQ+$r:M_Kx.zJV>Cc3vSl:Bp `F( ŷ18ЮnMv}N{5FԠOo#eQA#M']GmmN5KBSeC8F|`#Io}iqwsirOjTOZ2*s}ses5$d0Hk Do-+ex-Hlۀ7F,9=">..}yH},Q]m޸`c[CXg9'9퇂'77kWߪꒀRW]11hw=F{cjV֮4Io'YQ77.)ھ׶2鳬$0!c\=9KmgMfOC\k}8+H,ch$qq q:Zɧ-G Q+A.,srK53X#YaYu)XBEV R=(vnׯuxmG7,$(t0]P)8+qu?xS51^67[lg!#89)_ٿvi~Q\MJW_Of, q誤%;QHaEPEPEPEPEPEPEPEPEPEPsvITtQEj5=$WdtoTI|QשWQשR@Wl"yB(BrSSR{v+v?Yݷ/?nu#AԸg0 msi~iQw}uwo.A gbF{*kKO}W1$O@ǭ-bGRz_ۺ/ۺ/jZZCguaI< ǥfx'S-7͵ޒP(\sִt_ Y?t_ Y2;Lx~T^yEŪGbĈFOt;-2]>^6OAޟZZnJT_Vg[hցW"V ]LP: DI İ4_Ə_ƋhE=c "gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOPaE>EQ5 WxDA681?Y!_cDCSQEnip2-8.7.1/doc/html/figs/snap13.jpg0000644000175000017500000014237113414613100013571 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"(((((((((((((4ATt yJRQK1`SH *[q"Iۍ~sTԦPaR^kgQČ9Ϯ}J{0+䜟QF_ƙHj6*̨He֫akl[ErY%UVpiQ"oʸ8r,]C]\UWWVf$O]L )#?'Ble_`'TTE)8ꋣMiډF>\9S.d[%x?lTB cs;ri-7i$vI}KfH>[7mF A,"䤡Crͅ9P@ePNO'?joZLK;ߵq~P`]m l$oS!*Q lV=y^F֧^,Bk{2X֣/B nX!RS5E Mm=w785 9/}"D,A(޸=p+6Tkj[[_:KFBc+ZVo-ս̈; Ÿ~9z%'wpU:F4Ǹv̄2p>Pq7cG7x"Y1IU |EJR[_$RGk:L/wsoJIuki˞O6@T9l@X4S=7CZgPxK)n5 a{I!A``@j¢SeMp :c`t4-s3Գ1'sR+[_=4H\,ԅ-NO P$R[vH#abQOt^F{[m G)O2===ġg"YGem`QGԩ?k#hm+HnA̒3c   t-EFb2qdBPMPAuxVtTŜ!E<[2;;Ym~tJdB71Ģԩx{Y, ]˖8VbzTk}$ #x g{z}J?k#t6689]e&]-K7ʕ`IrÁvjj\~S$7[FHyKsu~rӖU7bԴن4TN8`GRk:]{{BKʼnI-}sRx*O{dk7GEexXˀ;G$%mv]\HIG,#+S=6%@ir6+#`r`gߴa mvi1An=Hj)}NwGçEPU4[\6smrr5ER%އ$0Dm.]29WU8j6@"0-o$~P 3.W$䞾E?ûڳQemh !Gxah_/j+ZTIZ$N[pQDpQZ2Y=|]ס]5":k\SA=Ae _(((((((((((((= -!h:tںE1FR@*{ %SͫĒrj]-FV0&nHPvt?SRt{[,"2)g`yp,t#n%N>Xq滋#LdY/KAiW zEAywPƛg4pD@{8)-oq]Rдt{k%K^IǠ⼷A_#X?׭-X-mIāT~2+ky[bl,f66_^k®HG9 p_?&-*}հHePv2|G6#ƶ TV-Rp}s)!Rbچ1?.xsU˳Ԥ~U߇cVz٬*B+WcO`+4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (44O /rEocah&ڷ|1Gֳv5IEwQVC.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRTBO_%ykOޯx 5+ʢ͸ncnq#jbN0A+{uJPɺ%!pӞkE$EǼ"1a$dY0xjTFi-drBQx̌]pӥUK.Usfr匮o!|afS\g[5i$w,;㡮 re)+h9mlQEyQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Z'sEncah_ջᏺ>Cy|4 ( +uמ>bЮ՚_wV_)ZzV 0$|RRoEW.?VT}RoEA$ T'Bp} ( ( ( ( ( ( *)bv%DU,4CscuVR>@EQEQEQER4H:  }\:}\0'5 *cPҐޯο\y2kޯ,Ο-޵9H?peXF!\m[\7莼WO?;>࢈>ࢺA_y/ν Y=|]ׯ5m#Om:+}}4)!;?8 z7kwF#I#!AMZ9ٷ[7c/\qU|5MxrNhh#%I(@L+?pBuY׏j4^eGOZ?EITo|;j&t,gHgUTqf%/ާo#3k?|憎>o2T!ϛLUs⻯u?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_w]6Pe*'z 3Hc!JWkg8QGČɾ2$c g9={3_^@Qsݘ'uF\ۜ3|[}&ho_Sy|6D[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6מLO8ls4(調ACu *:tZHo-$/ژN9d~qޑq]ưNPqA&2G(jz}OYȲXyv7yWVUXK>KDF@ rݑkhג+*n-D T.r@@Ǹ5{=`S?`Je/WfEn;u3R\j7ej_h/'c/ R 2N}cÒ5{=`Q?ZemByZ˵$*Vq_#;M?#\@ʹ5+nɯQ85{=`Q?Zzdiiqt*-]UҹwϲI'۷#:;UGY]}ĸBױF ЊatF2Y;ܐ>qAg%uG#1f[Ԭ]y4ZA^ ^X?Jѭű,Fzdcڴ<Ԍ ;v'W[uѵWk˔rʨ$v}rm7A?G#WXJ)(2G#<ҳ.Hq ӣ׀Ns@ zsUMg'6NşF ?G+xSzzõm$k=ˢ RKYmw}v+CKG)땑#kP\Tz}䖣Whkh;Zː0[i\uǠ1G<i sZb{ܞHZ^X?땕b7F9 u cWGu4 a,M:*1`T8kMG=f(>$D#<]\Y^]QNF ?G)^VmZIK۝vD$=TqրS\[┩;rq$g;Ӗ*Sv2ɾ+gL\Ojz}iwXBCI>p{}Gy<[[̖0,mӜ=**z?O$m{ ?G#WGh#wJGNsth%UKѽ;3QX=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=b]?VHdf0!$ccZ~L/Az>ס/YAq Vk|E1EuW_y/΀;kCwo*h-0b,b H=qhvvT ÐpkV]ffH݈Tܣ.8;ۚȢ]?c7$۷~qJ}bTGD&+%xj),_sn=v+.#IVv"kd 񴀮q~p~E?lMY\k>o(mL[ҡ9 PexJ(ߋ07!IK#wO@)HGtlt5E/P_Ňs}|I;(wcxˬA,)L@~^O5E5~,=1kVZr.ί&ʼn'9^y4Ѫ%]8dQG(_sY5M:;wM`PX5<~ qop8 <_%K7Ȋ)x.KkQdAV\{}*1YGۑXSxJOul'{Yv9]j,ŴĒ G 2 XRߋ1Yw6VmEkt9XҊ}S. X&`܂k>G=㽒]c03}MY/Z)<}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}ke&A"vhxc!\m[>aڦ 8]5":+f_t_@66tZۈ,>c|$`*ޛjz}2k4[9y0x] ;^gԏ~9zs7̸ZwgÃg1]eK7o;U;JP9k>#jw%sF` W8kt;+ޯ|Um~5T^V+m0;R5QnϽ(IŸ8|VFIiE&3FfY1$p>7G|"{Y+8^?<\?v8E4nyV_>lþ֥b5[QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!\m[>@9[Vz~5Cy|4 ( +uמ>bЮ՚_wV_)}qOTQEQEQEQEQEQEQEQEQEQEQEQEQER4H:  }\:}\0'5 *cPҐޯJ3Q5{?4bЮ՚_tWp̿n-nLJX{H9#mU9.(Ikv/*5Og-QEQEQEQEQEQEQEQEQEQEQEQEQER4H:  }\:}\0'5 *cPҐޮ_mOt"HaY<AWt~y'=FY'ϐ 7^˳"pbL~c?֘A3OÁj9?!ެN;jN9#5$z⌷c< guws֓v #e'B:;oB6fZ ǜxy2>rz=ED18_NCC|_zOE!7/j>rMu"*HC(3'5 ]\_&_*H297;S|DUd( c94='b3WPM,f٤-R|lOntǂLi-[xH}йN=9>t]81Aqُ oYo'ע!(E@ nڜk;e@fvMK>/S%Ze%\2.V!k8۩o?KWc& rqqisoȥNYE M&n+gl :wu]mb8@-Ee}oh __{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_[=SwOrz֓?k7=?UgVzQvGuQWa˯f_t_^uמ>b}qOT"(((((((((((((4ATtE4N'H|$e9WhU:^jSK{qm4ff;2LzcҺX_0+?z_%|z}ClvqJE)C[+6ݞ1K#L;9?p5ޑiOFS06LԢմ/I9rOH[P!|Oҝ8r\9>"'?,3ԯcmϽHG5ǒՊ\^FI ըFOXxbjk$'ܓ[x.Ȇr VzVc>abkZ*U(ݱN[T;MZ, BC31zUO^' #+ _ a&n3ϯ5Y E6QJO>GWn[aP{5Zާb4ȿ`~F3ׯҴfLkV:sЌ;S@Q'uIi6#{Սp^lʬ>uG 0dvA9.G"]^;GCK -?QKO4$3K' HqLuE5{Iw5 dVȹ-9'K{<O5GCK -?G$`o|j(i>楶qinC p8zT(?5E7qi.%)+r[i" 1$QAlU p:EGCK -?G$cQGh({I5\;nV$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}ΏO.o.GGL<#_j\!ER趮?ֵ8V.MwP}E}EX]5":+f_t_@՗",k\SA=QEQEQEQEQEQEQEQEQEQEQEQEQE= GR{x^tUa6c@|ZF-ܦ) P{]?^:xoͩ/ ]MI,gUt Wm6̤Zi࢈>ࢀuמ>bЮ՚_u:>5F$¢hՊw=ElU{U Z$' @Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARi?S?SsPҦ5 )\߈!8ϒZ#"鼴 X u:⢚K/,yc$ӏOi1- NI;ӽkF*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:tZl?7sOl?7sO2C/J@W?z{;ֶ#Z1I973zWЇWFvX]\F,K 83:(ħ4?fGF⩲xQk%\#G Yk?G N/n'm^8L`W~劦=Pg ڎ"r(Hs;]]Mp˰^**{[>=Pg ɶKT!ĠHpy##t2bI_* ^3+5O1p~*(dr= FAL6~P}=X;N1R[L\tm>?I|tL.c&)J9( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (44O /rEtB\m]wP}E}E2Y=|]ס]5":մ[[Xn5 He1ƻ$U`#&eU,$M\s`do+;#)'šVTicI 'g+fc+5ʡeW }jt;[2 70^yҹK;FTh >aY rp ֮6:-ݽZ)c*sNi5..[[.*@luDZ77Km3=32(l-yVc۽J㷌ɴrv3{j3\K՗YBkSr2EKè.OT6Z~ `dy_Eow;[fP4&)$dGFsJ~֯9cImt(bk˓ Y8S;YEҠ7R]L x`A092Um,,[y,Vt_%v3pHSVXX -DPÐ :vu]{V WKyX+m`k) htȤ7$xb%Xڝ]H..!CsK$*NW+/+>n -L%y`A4MW;X.u[F4R`2z՗Y=i{(cF-8-N>C늟]YRŵĢC&}UʦF6?C*9=g { TN3:+5stvL혌6~{uZHQ[Y*:H j >z2A]OQ#V_YYqǭZ _^v@~3:R[WV}-}6UJ/˷w_{֏iW|l5e=gUxt]>{[V\T7{l|M0G.0oUs8 )u&ITď E *bnF-YH~a - MYy$B+4&Y8^NzU-eFRƥ<{|Q3SxȦԻF:hh5e=gQ՗XJeB&K|obqP >ԥj d1| T uo?C*9>In/]qj&1hq2,d[%p2Np+h_>Uϓ4aƄ{.NyQ*M3-4}.5 %N~R*?Z[-O7TbV4^K̐4  rzVk%XS,ZH.HZ50 o9ZmQ)47C(jzC+ NiXdbבY<1| jqet}:.Qa4ݝ6u*nv$ؽePF*@#V_bڵi2)%!)XW',c@<V͉)H 2d9ҔRncE "{ O0*䌒@6-D]71zN=v:ёQ!#,nD+WHӯ b[(EXYn#vuj/]&Р+\|щxj2OOKȓ`A+fOrug#}о[{;x#]>ǤY<+ FҦjԟ[ _YY5e=gV֫1~oF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZ̶ib F9B==S&U/rozM;sVOC ( +e^{//BVk|E1EtY>*zm[y0@)ҕ'&m@h3[o?g>4f ]?.T#?M@Q@Q@Q@Q@Q@Q@Q@Q@I$C8O%2HH|N!B&*s˹{4}yƫwO]MtbY#i84nR:rNrk*D;GA.台[/x oʃpVW7H]n[yX>O=&=> xDfg=P 0r1—L%/^\'ƺj^•ʾ`Ms C>g,Mf t8#keǃDp=UTgRSnU<" 52F用o!P͍3J` T;Q &=&y?C%6-I47 &=&y?-CcWZh Koj v?H eo&Zm[5FXHީ,6Ze HO?3[<<ܿDݭ# 4*8\7M|>ߦ >§òu?kό?M[|aio_G7Qa}~%6->/oòo>0K4mo[}Io_Ge/ ߋ1[|ahL|>ߦ >c_]c-ѵ o&}%M}Iܿ.~/o[kό?M3K~(|>ߦ =;/]v_F%g7Q}%M{v_r u"lEYOb|5kfkIOcxkx*wP}E}Ejd2Y=|]ס]5":.tԷimKn?_&oUcuH3 j\޿qb͌C7NA֖FWnk\_ݸY>n?_&Bz^Um-fHrИp;G>hN@D3ח_ݹY|pȌ`qwg7mߝzEm!7^0CT Qt-ipoU!*' wmX`"~FT}Ikwͳ[Jj^>ؿgp[ >zZD:usbsMm5ԓ-r\GE Eo_Þu߱p'-zsUu "Q6)Έ9\2qېHoU4E/UNTO"SܖA67RI/8,8Q*F 0@VշpY%As!Yv qUŚ=qne}m,oJ<9y&Gq ?1@#;01Z~}>Ehkoo"OVSOr7bab噉9RE[C}}!:X<˵@V%;m SbI O6#]I q=OjO渍$#e;@ e?w5}>*Tzph/畿o"WOS>~?h>˵MtEQ_+EW y ce*?J|D]pWt~Zƭ'\w7L@pJp?'JרV ``3qWC`mfGp3_luKKGo%mU۷KiiIm孥(Ea#AzPͪNih&xpq09>2^\Y+;i᜕ɏ@G4r_3lM#mPOSTMmascwn,;G;@q\Eb!Shh.$b'(Bg~ݹ>j1 X(kAwwiV\eCu[~ZFbdaFeFpIb9(#SQmro\mKX(,DS_G6!n|ӭdox:AA˯f_t_^uמ>bPhgmHUfGGcS?d?oZ#vY`о́xfPǦj񳺹4Wp(\²KeЛM+5TrllddlF(>t[:;vbiƽnկMB1K}C@.qf;{4AD7IZ#wB641#;``8rI':i$ 2ź`)W/l汒8rbF#={V8u4I獧φT2<[Jg_xH?L|Lߕ :;|bIKduPK,I,cT֨ꫭjg7}VH&H,:U4=JÛmVxJtliy߃ZU9,0W++:w!p/pU~r\2O@Ov{m6LLw_$co5ֻ{cA֓{mYJsPIK$s.+hh|r3¢U%#_hSE ,Mt2_%=UEZC[E6Sjc2 ۳Goֻ{cA֓{mYJsW5I;1e$ v 28X꺤${hINB @w.nvr٥Ĉ:I`~GE_`6Wswuۋ4qG ]VA.PcSWCۛSo be͞wƂoL2?vNu^E&[j̇Ɉe^H'h8gj[ko(E+շ UVmZvo;A,[ÀˎG#Ұ tabadfib9տE}8[2{i*͒NrIh:7WV?p$9QM?JIݗOKXc͘U uF՞TѮԥf3Bc9 9b23zѵë_l+7 p%NN!o!8TH2t)GaުŤ\M{hnǔ9*1\[OGTޱA3˵g;cwL5ii-XmhK*U0NPu7e¥%8L*9{U[Cyq{˻%pX.vd-/ȋOֵvM2L/*,ve ~CY=wwRJ8\AZ= u#AQԃa6Sa6桗LjzRԚ{?wF5)Ԛ{?wF5-Utlj?b*[_I$#HC‚ 15-nW\ђ U/zZ[˛P_HLj]u pA[f'/Z νͪdPH(ALmps8PI䚞'I!Vɭ__khྵ}pmi[:? 갿oRZ8k"f $z4ChI**J`RaAV[mf×iL?'9q[Rs,^l"Y4Q| U'pި}mbW1r^UB!K{2: )?./|:,D0K(IXݑ>If˓Ki]OiSIftFDʿqʐþpG!ӼCh[}mІH9~Gc㊴ZlZ5լhBhZ@'5@u`>Κl2B#bU$Nk<9Q![+pA'i1(åZH5=2NcdY.8ު ӎ"/&i U]d_M H0F3;(;;[04H5 :k6]pk*mW;ۦ+;Yӵd^NkXRD``q(C9'/͟#8-ykp ixO mX_kF`L:uwKdM&ȍY yU|`@':UK(5V+B=f $C*6H@RZ]Cz]gwQeW1ƗSLʶs)W mq7rkOj쨡iz_`6z #1#$uuߦg_G?7_ӯuSNO㯴mLjwh]J *Qb9':QzαtID2[[_D!° ]ski<9zV NX tI=\7$՗藦IRthoMA,PCzywi$u\БZ_KSj`LX@iC`劓+KMԦtu+,>qZ4Qp9}MRǥd DeF3XP1=Nj+M^-K][]+1HdTLG-UK4巈Z݈B]iERkڸbK8gPÜr@k:TL[Kui]5LT0=-ωᴊ +i!m9UCܖ#a@XۢuK- ̖Y30  Sݽ֗"&"5̊:*=3bد爐{;;J#E8 :5@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@&UoQmro\x:` e^{//BVk|E1Et2V&2!TS[n'm'Z|I:llp0#+,ׇ Lp*&ôcXr|.4ž nIP~F My\j663K9%UgyֹgYO$VrC,ZB ¹-OMY VQXFelkѐr{uZS{'.^[K=Xvp9K;/c:\7/(,UDzM{ڮs:ʥ?++PoAmy9$G]9ƐjwE|i%1!Hb=qnqU/LoʙԶ]>d1@} uS#ԕ̀PF;sկ.motyP`yl9nvzEZK[ "pKg`rZEyo%c/ ʥȬ]X͓&\cgzD\_V;)mCd %[n+8kVS$=H3ޯjZ{l/o󅵌6I &)/<,.jFe+27.wiWC,VK{gr@P~cg}Վoڝ:^c(C31皖]%ikLQ(y OZ˸G]O;W!-yNXry<PiM:I#!16MKkq XARr~}mfx.m$pV1Ն ֛Mm>̷3 $ u}k4PAz<9b2{aCa7,Okz>} K4<OQqRWbww+Fg'n 楧eB]rI VyTyh?G*Mt:XQcyFXN}ƞckQFyoh7wsΏ"NH̿wZ@4.biD1 ]ݗBk7_kKwօɂK8vSUmA i Zjͬ}9d\J@n*vJ6 t$izyFG}7Q3M6pGq o*y$dVF\rWդkei nU#Xyeޠlt&8V1.BOaӭ7]D]+h`mJѽA,F"&$mB5=7[QHaEPHzZCu *:tZHo-6" E۞-)9dȨIH Rio]pOS4lG\? ]E5>\oKqVe\kp_Bk$Py@.qE TnG,R ERʃuvZ|χѣۧIìxxV8}몢MTI]m,dA)9ԣP&䶖!ۜ)#:uE\K q hGC/q@10; MaE{V?3{+KR[r'}B6SvUS͌+:X:((((((((((((((((((67Oxun*7sQP.՚_z^{//A?S_) ( (M* Xa@j.dM/L&,Ug>4}mh[&mIx6`v ~(Q@Q@Q@Q@Q@RHu&{D3!B88j()CKHzGR MxE=fE0 6v?R 3?¬Q@dYۂ:>{ DHudT[cVOjmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@7 SƦ&˱\=s~u\Wῼ?΀;>࢈>ࢀuמ>bЮ՚_uRkVMd0#n;Y)T2ؗO9FsXz֝ĩ76ri1ݬ!%*r\]}z*I?L,,sayCH=GR{fomA'x>Xb3hsˑujC4wG^!Э5m;L6QuwX8ǭ^>\Y C6Y#ogluX?ؚ pΥUUmLql-v*"U:U:j_nj_C{}mR$@&?,? /Wu]*WX.E 2Бӽb \]u/ݥcp?m?"%GehH,MRO?"At+>lWdmɀi~]H,Mi_}GQ.?Eخ90/i#z5K]?o?&w#z4YY_& G Qsb 4.YY_&mkp^H㍤e&@X SUAt)hz\-đIRiʑ8?]7ұXnfƣ,oa4$C"3FTq 8jV7oˉ&\qFFIlAbѮJoG¬y!}<1 +BnJ:4hriOC@ԃ@F4Z)2=E E&G#Po[ ?UQU"#!E qiQT'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}Ou_]&UoӮPM17̘{15xs7 ( )˯f_t_^uמ>b}qOT"(\[K $ #jZ(T/l}}!m Q*J(?_ϵ7Q4p!rvʌrX ( ( ( ( ( FUu*HpE-RNɝ YJAV袀 ( C#) (((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#) (((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//ăx*zX<,$ p?!/[y=!tVg[y=eo\ :+3< z.VoOG[y=mR]B+em6x <Ym_-?֏[y=eo;5zӬ8'3ZC+e?+7-c>RT"~fg|W@Ot} Z$Hn}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏gi}.4}Mh/A>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?2[PzoGءƴ9zcV^ҍҫ}Mh?ޛՙvJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@ 4[ß}?κ0?lf5xssQS˯f_t_^uמ>b!m#$Ikocĺb Y`* NJ"I%1O\|jȆ]pd1 Kg5_B}E%iJ~s?^+2Zu-}:qA?Bٺ5;\#`Ҳކ״񨽀y#X@,h]_c7F\ޠӊ+Y]˅8⋫,u^{˛:qEpz+7 p9'RZ7Ί(((((((((((((((((((((((((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mc•~" qn?zMr>\;Ut@6v59GOSQE0EPZ4@ƃ FOv;G5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5J<5?p~UkGhiQ[6֢ 0*@;S0(?nip2-8.7.1/doc/html/figs/snap14.jpg0000644000175000017500000015071713414613100013575 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH;Ǘ[YY#VxRN}^c6c<4 |Dl.Ȟ qּeb>?)݊K \ynu55{°;`Q@g:Z:-S|d^u dTCїs(}O*K(oh<+Fc10bI>VD\p%04\p~Yndb\PQzt^֖&3 <YTw^yDw =LR-W=8vv`wc? SSِ ː,\/AКնWDbU!ܴeRNޠƵuא*bq،ts\8tD{ڊ((((((((((((((((((((((((((((((((( B\m[$Q딿-{ ((]5":+f_t_@՗",k\SA=5?j6Ղ('U_[pqҫ;-5uU"W=ֹuo|y]>uLX?Q:KppX߄ y؊cQNΈF.7hs= A'P 5rpijA}0]s CO]Fx7-帟z1K<sϵkY\iz~ L2c'a/B`դO8d70isBՋ2v F&sr|w(`qӵ7[9a؜xv3p *#8I>/fi%0-L!E]ՎsOdڅ̶mk"]9%|qޟkmE!9;}8Ի+8d˴nmR[ݴ*@'89&I2`h)۹~ץ #O{Cbh(㉈ }xwᤊ6KDQfRsW.(eGd2qyNp?*H:<`\\\"I+IpTq8~ !#" //"{y`W/u}>"'ˀdMԯ&ơEw)ԣsImK[g@6!{z9 Zk|_z?׬y-fNRHfEAPI'I5k?!YY e@OCێIo$; _?^E!롢~{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_[=SwOrzZm_ }OVuiMdwp}E}Ev Vk|E1EuW_y/΀;/EOPYg:|Es:_j3fvy}Go^}h rrcڣ6?§_OiM{q ܓ>֗?¢kkBodVO.գ IA7Zw[K#O0g#>6Ah,^E=BDFtcǿ[gyg.m`o\"$gt۞b sw)NKDΑg|VgcBƚaV麅Vp}zs@o~VOڝrHķ[Z;l%T`yC?CZ0 M̘OӀ+9B,מYQPܐ[8\GթZܡ%ЗƚGkCjN rzeM~,?|* ]"2BI*q Ps֗h({I'~%m.C2n#V"z$VVp\mF 3=rZs#@(ϯҵ;y#if6#8ޔ}V򇴟syA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}YZ)#+u]C)̶QpA ۘvf>$5E?RCK -?G$cQK=?(?4K{<O5}V򇴟sg[ƪ]o|!Gc`EFFk I;sg[o|>q$3FK!*~Sg5E/PlK{<O -?XQZ?}͟Io?%P'k>GCO|IxA܂0~VHCs IP[$hUB:EU%yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCO -?G$cQGh({I6%P'hyA|j(i>$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCO -?G$cQGh({I6%P'hyA|j(i>$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCOтHIcW<1Gְ4O /rEock qb\ Vk|E1EuW_y/΀;/EOUm:0 EsV>숚3Aߘ?N@:Cc @>X"QuM6U#ܳO b,Qc +2O=Bâo~ !:?QM0dx.2^j5&$ޅ{5,-([yFG#Mk^: U1C?!p=s@"U'DY°(x+K@ݑ@xH-1m#:ϻ/qn[vP85㒦>TS<',$O3 zvwqȯ,e'c}0y?Z~E}jT9H 'c((((((((((((((((((((((((((((((((( B\m[X'Kڷ1Gր;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?JiQI47Xݗ愝?ʼF5rפK4s陫SŃasL  !FpG?WiVl70FWp$ b2 {nq 38sJZ|lr^#ۡ7c&r~{P6_>2Wa)? IdEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ딿-t}kD)[V>wQP.՚_z^{//A?S_)s`u5"~UէU[ 8oy: D<뫃X؆-〸CK2xj-ɪ@~-'O(uۋ&8c`gv#8zsYz VMvV7e}ϜzzuI`I>!eJ ۞> 5h;K> Nt>-4P|x&+5J}(((((((((((((((((((((((((((((((((KDD\-wְO/jA(LRT췏((Q_y/ν Y=|]ue _ /EO@ _Zj!o",@A>^?CVHU~qU6J@`kvj.LX*,69ְ̣zlm|b}y'ZZIQTWҴw6WI F(nG^~y:.Z+{ilTT+I.f!/>hߟzZnҸ8t6OA"BGR5g<یn\Au{iaز<}gkcg}:cevlJܬnH)խu;(4'cm ) QJ)d[i!1ޭגh,d9dt4kukA P6߻✫IfVƃsiŐ&FDU|ZN< p70\Z9coo_)R+eYt|!@ q1qE[{I l!3g(=*U,{LJEPa+<:ԟYY`W{x PP2 pQ(ᷱ?`*HnQ*+G՗PhV\%"Fv ˒VMŅȆ) sc(#{W/H8ۜqOttAnVP$V9^OZJ{4@ʕoƝqֶ\M<j] OAS^C+.7&9Ծ;G'Ӓ+ =XRL.B-מZֿ 1Chxnɔ0|jz}{DXtWBsc>nCۭQ{M5Vfl9w֚UbQc{/??F ɒ]tь5!\6G~$|$n/fI̻$ S*Rc؎I-&%Igp!a>-΋Il$K. vM^-̭b]2̫T"93=ź]#'˱*$dQTv"AC(jz}k}ӽh<##bS' NײZHo.ÿnn~ү{t]>. pO[pc5e=gQ՗[4QoF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZjz}/??¶hU=;YY5e=gV}jc/??F ٢V`pc5e=gQ՗[4QoF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZjz}/??¶hU=;YY5e=gV}jc/??F ٢V`pc5e=gQ՗[4QoF ?C+f>[ñGcLF';JᎃL/Azz~5`$M1܉/((e^{//BVk|E1EtY>*Q,fV: ʢu:)1ij6JLy:c:)raTV. ;:gmUo֠u1FgXGcP}WTڴږ5Ì5ᔶ TtbQ`$WUg#%yU gOƫi +cpHWkFQ 7NW5/w]bQ=3zwVJ ⼵ekems`qk9R'yE?JMlA1iF2ž(yi'kS4 PY=y~Xm#:70YH6? ^—<5ω+w8J$Yc:qکؙ@ٍ~ BqeC#64{_ʾsiu_Rm2k+-P۲#O=:\v}Z|v6^W#,0Y@´{ʾsZOjї?j:/OE)=a1089'yVTUftTnsվm3' (}9ڽnl7vprW+|qjzM}c, MpTs/-W18La x—<8G??gQGA.??ۺE—_Z4[Vi-m-\5{z"`{9#ӽk~\X4i:n]3Iwo6.a)iH!ԅs95&a.Cp`dsr:kyUVHZi@!p|>$'5s)eo c5>4D Гgt c AF𘮥3@KkB)*wV3܃ӎ,Ir˾yWK <2B[fgu`:Y`Y_c,x;}jE%ԁeh"2BB=r)13pO8'54q l 5hC8PRͽT2E瞛R~P媟uA]~ I?@X,iU}RLY3}Iyi <2s\7#FFv}?@v6^"pV-^e "DvcOۦF, 9 QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEih_ջសah_ջសs~:_ ? 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@r>:æ?5yPݒ[#pAzL: 6ܘɭeTiEW=vq oCS;'q^޵<к&I`s giv$k)~a6ӷj<7l$G"c@AjS:$*<=x[\3$pG %7mA'{f!ʳ?@qi/iJ1 zԩ#cx#\Iሴ}NKv̩i9Ǹ[(((((((((((((((((((((((((((((((((KDr趭 kDr趭 k׊iguQWA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~UesiD$&h p#hy*yw6k)dc4!`c,X {cLOm>h;X" (*VA?AfYw00TڶfT@8קF4v5lxgyf6󃪑C:q~29)ɦzzqӂImKˍ <^V*rUZRknM4v!\kQZ}`8:ջk-"M[m$h n3֡ j2O<]ʧdz\Ջ4*("#*s'sʬNZ-Eu_}$go4$of FA'8y[|i\}Gj~6vs=^y&%ؑ8U8i[sCh׉+^d\7@)mN޾BmlYh6 $K<Ձd[]kk9-).t"8U1']Ēh FOA'8*jJU(fKm:$="bPdi$*q ltn RBK mcsO%MBۭu>l^5W /˷e?0’x{Q*I{iopY #9^ Cwh/eٰ 2nE?>O>d/.<;m2i  0zJ s`E:ȁmn;= 5R\}:upv$J)V'9㱧2i;v_o\a}\i6̌pxQUCk< 4k\Oߦ $p~lc*Onv G{ ѱ"$Xzuf *~?MdSXsӑϽG{x#-U~vf 3R{$kSoOjB \Ҥk쒼mogtWn ddu⛜Y)4vz<9DkuJ&[r #8|6m-EȑRHSv7B -Zo5Ea3|gaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGa(+c$õ'Hj ZoR'Mfk׭ʛrwj ( +e^{//BVk|E1EtY>)[ltk;*O=E-:u8skkMI/Pi˒OP' yR$`bOS4]*(ď_5S^ԥ4֒K]a4p3ϰ43Zq'Q42~+%G8ڡSyogjH~_]%Bugn<ס(5-). ,_|+.5+Do=kҼK+<"G>n,ַE}i&r<2=EK^ӷnĬ{tс}1.|#3%4nPED5Yq"|4nl){8v e)V]NZoeIv.s'+*vu~nµ~%- (ʑ3{8v MmǺ@w翸؁99.p{VZ[LlOqoǽ˼OG$s93>88$3Y_x.)nbe2QZ'y&G\+#`}KT v1Ufr9Y1vKK䷝IXӞ[4&@P@\屟gvi}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(pfys.K RYm[^B\m]I-;>࢈>࢘]5":+f_t_@͙ƝlNx: Q˧IwrPdy9xM:."2[KYcon2r:{TvLnbt- D:a@EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ딿-5_/j<5h ( (_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐YAu~&.1r}}\ԋʟXri#!GSif vUPGQZ ; z殭4E/¹#Q~-CPNkymx28'T^eTM!rq3W{|<{j{16(+T5]XL6Xul`~ռ$ۤʈ\df>Nhƶ#1YĦf S=Oi}F6%XUݖHcay yJRԯzO/byV^wѠo.3y#h(((((((((((((((((((((((((((((((((CD)[WAᮧ\!ER趮]Oƀ;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?Ji<#J2#Q`tk1Ψ_˒Uz\QD 7˨BbN a\ΫԀwyhxQtǝ!\|+ Po0aRv"GҀ6X-Y>lp~z宼A}9:Too$:-Υ0RrXR> K@$=ΧZ5iS`A,ޕoerf渐|SZvsRach(((((((((((((((((((((((((((((((((CD)[WAᮧ\!ER趮]Oƀ;>࢈>ࢀuמ>bЮ՚_wV_)}qOTo֬ΒfPNђ3qS>ߗ {9tj 'H FE4Dq::X+w3L#ɇHmS>S fdVFDlK@s{a4DmG|o*qq #zM{-F1ɷR56bTa9$p*-/[M2XXvJus<7sffAh!6s9zU"NX'?(\1ׯ59+hӯikMFs4[^4&+vfUQ 79=*6V^~S<&`g3{hu%; " >fq{GȐ2~h1ۙ>O{6Ld~ruk%fK?! 0R|#溋&-:OF!# $9*Jof9PYKK&1  .qi}ݥol݂d89*[}:5/0J h!f"V$\1zY{w{v I/Q<@9)j_,Wn,-nn,7,QQ0 j hgO>N>D+uQO} k &gD\I'n.G\㟭-Նw"ؔhI6]0zjQ ; zMa$s#B$'np=i{cfeuvP1mxg#k1ݻ)+sc<', ?ZukkfvFٝr9<@U4yiIiv҈aXǎv皱M;M7kgoA8&t[Bmd6kfywtsV/X䴔nߡy_!p$mۻ=*=V\\\ fH++8,0@384K}<+o'ۆPC_P*|y%W8 rfrq qޠ8mۙ n\ 8R{T2zzM#Ȓ|s$ |F"q] l{5xw*%x8I8?zbhb ;cUWF)Zpncޣ^GZsa,N (w<~$Vi,@a-$8piFQ{WZE9XęڍfI۷v1EhҤ^?4̟'p=^InE\@Gܱ)*gsagڬVV >?;Fͥj{;hĬT'&:Ul~B>%yYVkydV u,{B+}FqWmDkdNسNswm[I;_~W6)$ʱj3{jMY߱,[y<@ji%صʏ*%mǨqLmnn>%+ 6 zRF㽻CK40`ljͷwa~\w(k nű0~ve*7ےި\hZ۰Yc9n$0APK0x9 ܭyS1=]%ߢL]B{&Sc|rfn,p 9'2y"JhcgkH._s ncuV淼ԴHe+0"J K֖B/{є%@Rƈc3n),J ii8xOP~SQ&x%ݞEtJ0K#\G4gԖB$,fRd(  (->\[A 2JÃ>*Y,kXm#)'`#G}*^}\@ Dg% ~]Mjx+.}} c(A~U+i>e>߱}} c*{I ",?YϤXi>dWA~Q /Q',`H? >e>߱b=__G,?¬QGp+} c(A~U(EYϤ`H? E}ȯ /_V(OYe>߱}} c*{I ",?YϤXi>dWA~Q /Q',`H? >e>߱b=__G,?¬QGp+} c(A~U(EYϤ`H? E}ȯ /_V(OYe>߱}} c*{I ",?YϤXi>d@v,('*Gj&U/roc/mwG-uipQDpQ]#.՚_z^{//A?U֬n5iK1==?_, +6 1Cm*VL P$Tq?ZyoH_\Zimձh @[k(?IT k?&O*eׯt TjVMGm~:sMеvl QG*\̍Ăg釩5[M :=1$e?#\ Υ]3#Aw1Rx|9{Kɕ,v`a _Y٣~q>\Nƫ2? 4մW?xXm.ON;UmOċ&;l(9i]_3ǹ;gpF70$Qk{r0i cojsKh[0?tĽSOrNuU"W#9Ƿ[v2 8?9x+N؊HLmx۽eϫX[Cosjs} kiq j\%n''ɬ]h_M4I@=r1h *ޛ w t+}Ve`aOJֲ褖RXX>2?z࢈>ࢀuמ>bЮ՚_w6gu@([_Ze~'y {YcH럟 e _GYŨKS(Wu Js浟x~X/w񺭬RGI=kA?j=oѥO}&,6q\99ptht..&k˂<ٙB8d[ҪZaAG8?ΫZ,^(*pH<zS_m{$U8$G4EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!ER趮}O?Q딿-?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUn!D,2uGH,h=:VK*D<*GV,lbI=L b}qOT"~\X5]?jUniUWHgvǶ}PwL;X Wϩv RM=2av&p>B0=zSB<C~OK!3+' OU2LAEm/ʣ}1~6 X|3}!UC2kk[Ė3Hݏm ݭIMG*TsYLIyr1@-2yQ$\N&pÁqǭt\[MdˤjywOU0G=hWdf2+A\F4/2{vIlXN1^tk@`K2ѕXjv`}"ka4qGMo|ʮs:I])$.TVt{khgGP? c@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEhh_/j|7=Q딿-?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃUrJ :~T?{*ir\?4&C.7?] (^.%$r밵k|*?}l'@]ͬ,Ds!THP;s v-faow᱁Wu]o'U7hVg-J$P[I6@@ʒ9$U2Ds"\TqxfY$mAwJ &6z{Z:rY\̊h'zwyA5Ni&yw=сͻ*`RČ'Pb1 ,*"6sV-t}VN6")',9-'5x6pʤ8 STmOе7-40\)GӞ[qVB2+ީmZp\8HS|, ץtVvzop'W1P==rjjQVF^]_6U q +܌QꗷI|SMnP*43ʾJ~z&}BRԪ$HwqR3];Oq0U% 1U>9CGe u=1+WgZuomky*C1_O n9 rN~j|5$\tGG-*FI$}qI6Ob2^[I>c۰0 kۯg XeΥk Z2\I@ە1m:H5BZ)b'B`18s!zVfd!`Q 7XDΠȠ; Ժn㑢K+A'9O'׷jFO6ѫCnU 3֚tޥC[iǕ$.NJ3 F=>ͨq]\Z,ѫv|pLO U # P2p>l&izEf-%v(HR;)r];=u*zZpR`ڽFB(_S?!aHܸ]ͼH!}HwI{hR[XGوdW,w|* Ԓ"m̖Rkc"wSṕW[}I *NXg=ߌ!N'yMcޫ?.,qqUFq͌ =ZNеId^lX^F3'߷h!xf]Dag$_j]:Wy6^4H;Yxx\xAcyRY}LHۈHq5%׆nm$kam2\Q> 41ǦE3PwpsqڨQxslppyYy#/dF\{}/Ek;kgyJi%""  7{coNzҌ#~7ּ,.* u_h[9LVB%ØT~3Нz:M[=т{ ilwq u5WVuP2ҕD@ p+@Q֟ѡ&mוN#yFݱO9:zdu'd_ne8 `篨SB5Cx >G+v<՘tBmu$ӓ2܎}%I[ZƤwVw6I 3N##'75BI\x Y8qү_is qDgYՓyx-a g?)\ZQ_ϡQnDB2*J 4 as. n*;vU|=@4I2O12F1rxKቖha>I1׾5~r} g SZ_-*9Q֥iq";UBXwck\& wdoLՖo4h-Yy=1R,VUKp=9gW ! pǯzԉ[؇ɜFҘVA9b3duy%|7%<Уo_ziụ!vH<9$I?=_GGo;Y2I ŴfGW#i>Z#6̨$ :YOF'EWUVI-X6ߛ}͎{]]yB+*9$>(8?v?G2&s]'2&tGEIy猟ɣ?G`#<Oy猟ɣϰ]R}'h<O.>?4}'hsDtTgx|>?4{9 :*OtGEIy猟ɣ?G`#<Oy猟ɣϰ]R}'h<O.>?4}'hsDtTgx|>?4{9 :*OtDO?ZC*A34n*k+x{zj9k` 1uמ>bЮ՚_wV_)}qOTQEQE\MqSDwlYsjk ؚX7_ß}?κ&UssQS˯f_t_^uמ>b}i!m3Ch3lr>~ZC%Q"@np RSۿ3GL1 1K/33^*e?>ZC? z>){"~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoON[2}n?֗Wk}.x^;Xd3 y4C;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qunYu8aa!%8ǶkWib>5#ʭ{T࢈>࢘]5":+f_t_@ i$MS]K{%x<dFb;OPjv׷U̾zI)zw kX}G& #|y= aF:voNQ%GKX,VSCtrFI}RFͿ?Vrh)o@m'5=o̱G9'W;_[+m@t#h$q[XZk:Vpl2,0Xۂ34^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U}?UfJa:JKa2G¯wk1YAikwt V9E#p)-cz/:u[Fk.RK4;8ϷZ\69H"$:r6P&W❭>Y#?;VL=~ltAգzIY]R4;Y>#+w0Hz1Pk?]LwS\aHTȡe!>\kIۚtP˫A IȰ3g8K;+5KMA-y-[W' ;T:oqoB`vӶן _gSq\GAi3+Sb ryrQKY<_;[i y e?Q5`cJm/ky Onl-!8-z%zm}o˯w3n%-.{Tr^G?n#[ K?%Darʖs hZEy~/Gx]?OxuԬAf#,@xK[]zMc.ymÄI5ğ6Tn\8~W[ipxXRk|UgHOz;m3R]Inc)\JfiT5k$lʱ6JU 'P]5մe ʨ,wе_woGyxOYMo P%ü ŀO?))'Ӯ-E|Ջ3/nק<❭XGEe"PҰoZj,z¾Fp)e /gi6r"P ztu5BOi1[[\;. B=+#÷3kԮd:|eiL(MctRC6їQgAi؟iOwW<n״mfqt 2yYiwٮ"$ p>l泮gMF #! "%𭑐N;(Zz~;w;&FҪ`@'=;Op![%Y67[I5隇7KJI(8أtj-OϘc+< o׮fjΦ8ĭB} Fu7#ͲKpIԂA:kwo\j:oِf_+ HdneoY7Gn\#_βv*Gh ]w+5ze56hI }r4M&Ģdٟ(lڀ6n#Q]XBR{y*^ l~G| 9+7umΤڥ]`x]WkHuɼ0Gjsb2F@8㡪/< æ]KQV8>#2z OMzMmz[+'̭VQݬdZUOO![ӷ;h!mJѰFAt=R+d@76~>+ E{ Rs9 zI =wWh7I?.-?)ŭ2g\H=;V- R/Ll|bdGocK [jV!S\ k./iKHܨ+lWL)*;ƸA!wOj+iP_,f5Gdiv66@f.7;x`~Q"\wN3V՛^d'{zyt63Ȭm#$z_ibM p:CʬNN zxj8??ltSa'v76XӐ.t+9KХbIjwM 98ѷT`~jΩegqO6|Rq8r-ws\l"MpP9N8Z5/]X-Z `Dr- [iui[qm*$RgOI cN֖_iܛxsH3A{xdsOcp/5fMt]k-EZiB\S玵RVĵ-bfTF[h7:e pI< 7W߆yvVxcz:wuM6Al.'f-:$b95,}?Wi};x/3$$u߁5vR^kV 2`ҹ}kX m;IϾkn>LG5F}FcHλDSa4~u --nM0\2z,5=JGKonAIf[(|nBĖ\f ncHmAkmm]NEY!,q(lY-q\X:f͋8};.[qީ]&O9<{G?ugkEy]^hQ}9c]^4#ll 8 WvQn4_4gk徴BU)Ul#H<"9?8Lj'[JTb2h((WNyOc{8).Gry|y%M[dc,O6Clq\#ּ{m.0E7 H]VvM>!AwۧZv3j}x: ,nL-®38$~ko((\5"S4νq5e`2Atve?tvvO^wf ioTug}3OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OJۇy'ڗl}?@o?I^h>"4kp@$o7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ck藖{e=sFѱ^[ht$HKu6@{G,mc€;%f!)ͮa _X𱵏 <+ck?o(Ms}4"Q(g_(09qk\=+ck?o(`;4nRUsy8>z_X𱵏 +ck?o(Ҫ KH,mɲ rO$z^y X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@E="!] Cjy,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@T.uGd}q\',mcXwt:p;8fJKH}BmdF?.{ck?o(6( qQcib8bPW?o(7PQ^k X=o6@{@Yh]_]16 2pH5?o(7Pdx)dm&%}oQT/ָX𱵏 +ck?o(ҩF8*X𱵏 ,=+Kh]DrN6@{G,mc˜Ey,mcX =*_X𱵏 +ck?o(Ҫm},F8@N~W X=o6@{@Ey,mcXzU𱵏 ?ck$d=Utt>+8 GY9$RI5?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )hnip2-8.7.1/doc/html/figs/snap11.jpg0000644000175000017500000010253213414613100013562 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH%?pB+ O\"ФZ/i]H"y*;CiP͂R)w>p "7YoW%f #m)fo_ __kkG~f~fw/=7^\dF>[ qӦ?1%i#5BX08`P2J(((((((gALpNO 'ٵ/ U_m~Gu/ U_m~Gu/ Ux+"]0@ A@Q@Q@Q@Q@Q@1@BǢ*c!rB1:)VPy h(kSߥ2Š((((((((((((((( M A?ɿrw}E}E1 Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)+.\jM6~A ehR:t1ZEITf 2_Jp>05$8@jUҒ <PO iӷϬEP׭e,]dv@= RAƋK Ym!$ ٌ<5FOڃc}s,M Eb8cNk54m^H;./0E0Hay AtGZٽ?sh7iaa ^1 pPpk|Z]v<6$uealnvrf[a HNXsARu! OL6lm7n 'U}÷Z]ū,.ih pӟ??,~&];Y,gP˹naAUw Ek}kk4S9BY <kZ\TtVwwSY$q Y鞕gkMXyVIxKp=M"oK+(d@wWI'WāMK ^ؓTm> ;c4!q$v'Mmgqey '*N$gYtVY͜׮JѰP@7/'zhd!1d:R[vK=Bkƞ%$QG>աmn c|&"hL@ Fw> qA=k7WV1 E`Y$ cf6Mmt"ɞݴǎ\bv( _s5e:Ht"xord1:$]]Տ/A=]KfU8҅tMwR.0ͦH$V.3lqE/uiedLqq2Akm-#v,$N8_u^M&(`꨷S$2n8;FIzmȍicUem61z*_v{EJBv_ :|CkΰIWyX ,@*ӸpBJ^[y(HqΧ?/MO ]Qtmg>W_][CC7?&_*q];9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/tR;.(2A xqԓ׽Kyv\ƅ1I+3uPz(FKYd1h (BK asf{.m>]->~k4hMݩ<ESy| _->~k5j D WE?j8K85S)ҙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UcuWMZ buמ>bЮ՚_wV_)}qOT5~\X4֭?JiRT263kQB.1G BS)*0+#>wHК1?s(7]~qtyυW luD-fHc!\R{W(((((((1#mwLŷSQ@~-3?]MECv[;u5 E!ΞEy]2}~5PEPEPEPEPEP&;Z)T20a%% 0@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr]U*|1Gր;>࢈>࢘]5":+f_t_@՗",k\SA=5?j\X4֭?J@Eo!)_C5ZfHZ[Lqg,pæ=jEIU2]Ql#8Us8U ʹ_ }((!_y/ν Y=|]ue _ /EVZզ#71.H#~ΒfPNђ3qS>ߗ k$Tq?Zyo@tj 'Su$'H]fddVU ;}ҮU;FtٝQUјۆ ʟήSFWmP0O>ƀ ($>>ƀ ($^>ƀ ($^>ƀ )v-WK4d`LczP袊((((((((((((((((kSߥ2Š((((((((((((((( MZs\W+ᏺ>A2Y=|]ס]5":taLSAt{k!e}SFN k [!k,)sހ:o֨OH-ܫonHn@-U5SƧmq~#mdrb>rIsH ]F:mb$q&e0\wz4rʛD'Je|!igmjp5v1 fO9mO1O*ݯ*E[TjB!`󁓁n?b+oRD"B zkY"DgiT,}N8-EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\:uWMA((!_y/ν Y=|]ue _GYŨKS(Wu J}"~\X5]?jUniUVH%?pB+ O\"ФzJyJE.V\dT&?mj!mpO7/Pw//5f%h3ߒ4}Z>e?ֿƴ~7Mfo_&3e?ֿƏ_7/Gُ/@V\+H }n&'ǨP;@QbI0i( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ()L0(((((((((((((((U|Ӧy98n1}{7:XiAgYR?7B0P ( +ce^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`E!ͯu?Uj6跩6hA|њͣ͠ \x];:\[_[- .̱<5y^iz/b ԕ|XM Sh!hϩ:mܩ HZxM:W]kb$3,'**2szSwv:f㨢(((((((((((((((kSߥ2Š(((((((((((((((W[JសXiAgXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB+ O\"ФfXĢ"$`X&y u8~tz9-dcYf=QH i Ph ض $4lʣŷ{G-(I*6?OQbϽ}I*6?MGo>? ?Ə[Q4#J-ѥE$bm:ġS %̺6=jeeXv0N? b%ɸߣRy7/u&{E~K\hhtʗi$nVQG~?RPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U jƷ#L _=?†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_sU&W1bv ϮMm[J%1"7d}V]NMZ`\o@jT؃= tOQ,R[J+D A$z X#7vp9wֳRB#pf`;)0.GK%k+ .՞xK8G\UYQۢ;ܹ,ŐIX&\[}L²"G' X:RҵMLKno*A6vOChjиf>(Ň~|7ǒğ)p>خn ji0:j gɍ۴Has&1k}6_8.ʪv^Aяз/ JL>-UI?h4x!hx>[=p{f3Fhkͱ.3ɵk*8ReXP#ÑFMGtf?5!d OݻR &?V-x7XrY ((((((((((((((ҙO~C ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9]oF?* Z[J?ְDub_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%]VEIWik]OhI٠J)RQ@ E%ֳ״?5_k7MlcaL3Q'(5VѴYerZgjeyorpU>a~^w%wx]J{+1f o: d 22Gzh:9lQ,4h 3P:OALo\iUTo,[u#Bz{ Koc2n4Bgo͜hR={1Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE4^oPxkbMm/V࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]͟u?-rj|YSަcHfFi4њfhJzI׬?5ZC 6?5 5[Mz;dtx~cp9[XI{D[+[+nc_K<њ NsB ե o/GOnk-mco6*zA?SW?co֬s`OҪZ*uvEIWjRU`W?[Qşv?-XHf14њ~h34f'³§y*#rV##O~\oyk}~-I=E{v|vųu-ʹwvo.-c~ViDm]daViaYE d!z=I'}Z(((((((((((((kSߥ2Š((((((((((((((( MSA?ɿr4AA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФJBS)*0*ŗv?-coLs!h34f3L3@4bn O4YE-Q\=MsZ\%b^<9bkfPeׯm"kd7[]Oƀ;>࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]K_跦?Z¼MK:sTYY) \0i|ݲQ/ ?E;o/l,yv@/ ?E|ܲP ]3AV?U3i7_pF:І%N*+[jWny68M̗ 6ю=*?06עKgSwcN v[[MhdS7=>]Vh7P]-ե*Ȳ۲U!p;v[hֺ:nbh3 6s'hGKxn?*Ъpɭ(QEQEQEQEQEQEQEQEQEQEQEQEQE5S)ҙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&Uxox:os\W-ᾧ ( )e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`E( ,*` Og*6 Y&O=@Ҫ+Rp=(hpޭkz\شUߔ@(r9qW!tXy ,^1ڛpv뎂:1^A5G*%QI+5:iD1)mzn隦77$-MsŠCƀ!oBGJקO<qk|Ajw[țo$rL׬Gmby}N=( ].vR"LeMUs%.%I?Kl$;‚ԅ~B92_(z+$ڭ[=P DOD# t#U}KR[[xtĬ'`q࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]{?[_e +EvJ G9ڵ.RDxxRqgMBf˅He8-.->[$ XǠSuiy-#+2PA<ٿ͛|.8t]0cM6i@wxlvs92B-nشW_IJ_]lu6F1i^]:{P<;} ^u|=ČUB[+b*7]~qtyυ@졊 #A I$4yΙj!PnVR#&pnom F=1L KR}z]RSBшI̾R Dxj{mUBP tTPcb#AE uPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr ( )e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*vEIWjRU`W1k^جҘE(&,I sSK-<+TarX[bbBt'J騪Z^gH*tu8*GeG|Mmeo gNL{gt3N3܃tTW=ksWu_)#*TuUGbЮ՚_wV_)}qOTo֬ΒfPNђ3qS>ߗ {9tj 'HBs)(N#v޷.1ATs5#"h`q~rƝỻ;*i'ݮd+v@䀶3)V8`mQ@ZF-Zs0e[=0k:?Aiiw6s\1䭌($pr8޺j(Zë\Pi[G[ B*֕bt&e6{ fQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr먿}ro\x:` buמ>bЮ՚_wV_)}qOTQEQEKQ[Os(=  $(мZv;>WB/~)*_ *_Tow0}E}E1 Vk|E1EuW_y/΀;kO)o ((((((((((((((((((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//]V; E>a_38qCު}_ ZKEnG8+7%Iߙu'3>ZC^*e?+7<+K}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo,qJ=w}iϸ̯xWk}.㵆H0ǞN?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/_JVӵc9ڴvJ(7PzoZ<׹9s˚,>m>[PzoGءƨFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhuFq\~xsRp4&o}x:` buמ>bЮ՚_v-d@I5Mu-~ؗA A0?A^iVZ$R#2$=܀zgk amP"f$%]$ڒ:+]FϴIJ# ?#9Yl`lLune"Iba gU-bX[kM 8A')H]6eߗ1-۟lՋ]:ϻb!A=IrO~}ZTV{x`ciy8젟utFX@dY)"&`6gitC^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U}?UfJa:JKa2G¯wk1YAikwt V9E#p)/_1[k}Z["FO٥rWoc޴ӯ-4mUgWdV8;࠯=i'ҵ { OSB#Eizc;GDlvWڝޒW IB}@"NIM  blOCƝ37chԑ#+/0h͏55)mM 9R!^#Wꢕ'%GPqȧ m'U}çvRVmtQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEsa\>w0}E}E1 VkDh?z(kldU~Roʼŷ@," ?HgoʍW}?G'ڗl[ktUj_Q @?z~?y'ڗl}?@*6O^a @?j_PoʕU_JO/G(R €=*=p*|EhHK X=oJ6@{G,mc€=* :Ks܍wnL>?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )hnip2-8.7.1/doc/html/figs/snap15.jpg0000644000175000017500000023031113414613100013563 00000000000000JFIFExifII*JR(iZ)( )( 02100100qC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222q" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BqJxRF@@L7 ;ךxe}% u,d~S°1"'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=IGړּSQ FI(I^) FI(u@$\kRzu@$Ѻ|.=hRz׊Ѻ|?h>? ?EھԞ}=kh>? ?En"_jOZ>Ԟn"Z7?OE'jOZ_Z7?G- [{Wړ֏'x- [E-Qp=IGړּWE-Q B|"(I^- B|"(s>K.=hRz׋й%./ o7E'jOZoZ?-I^- B|atϹ%~Ԟ}=kſgό?nY?7{Oړ֏'x, >|at\iRzs>0K?gό?n?jOZ>Ԟ./ o7G- [p=IGړּ[-s>1K.=hRz׋й%./ o"?jOZ>Ԟ./ o"Z?E'jOZ_Z?G- [{Wړ֏'x- [E-Qp=IGړּWQ FI(I^+ FI(u@$\jRzu@$Ѻ|.}=hRz׊Ѻ|?h>? ?EԞ}=k?h>? ?En"jOZ>Ԟn"ZW_OE'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=\=fS޼H|S O ?E^zN 6=TQp=04q^42E :kUNE0Eex^>xOW9<=ɯӮg/?L2t\|??̟]|G>g{hx._϶~d??̟]3Fkr}'G._϶~d3^ ߙ??r}'Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2.fׁiO9G._϶~d\|??̟r\#m7(3^ ߙ?|G>oQp=4f/M2?r}'{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2t\|??̟]|G>g{hx._϶~d??̟]3Fkr}'G._϶~d3^ ߙ??r}'Eњ?\$m3 ğߙ?.fׁ'iO.\$m3p=4f/?L2t'iO.5|I>g/?LRt\|O?ԟ]|I>g{hx._϶~O?ԟ]3Fkr}'G.oϮ~dEy>*mQ隭vE,Df$Nkӕ hl \ιyFI1 p(O@ 3r>uB.ꑒ{6z 2Y pXcqqYt^jV Y%.y$D\Ω}`:I;ƶ僰G<'xbVIm$V\4sz A{WaKKڶ1dCwvd9c{ϖQsf+Lipц9ג?iI'8bBHWpt7whdeH+g,ONV,w &rǦ,1v#<+U ~t쒫&.Ewr?]ޢуmB^F_%.`4Dj3㸨Ɖv$+op8+յ,7:ͭ_:vB7Eb:@odž|/ Kd tk;v愵uie{v0.4|VR*滼RTPh.s:ǿkxvp:an^*mAn jQV5 ,4uMPHqeqf/>_|tk_1?H< q׶j~-53b$%s]&v=#YH#<#>j]޷6MF""6負pXq{_ޫ&;ǖ`̏w8jԴb.ޠh|[$9~}kNt?hj !#%\s/PjqLGhϦGzy=dq~#> W]:;f%V:ƳuM3/Υ^y7f1xluI^ϩX} G32;_Ӷ֬:_VkH fhCt)ƣ W2\CwvK9:WCk Oxm!Ll=Q5 nysH2ݗ=OCBh/9{;˹+[;OqK WRߎ8Y~ IoSKxͱkAB7u4l:)4$p 6N;dc%dP`ZkoO,7:.29?^GKi4[;[5q>>o$3Zd|[@(oܴP8*H\u)[jPiWgQ,LaUPS?55Kuc2_2qބn:f@4GRgAXP:Aaw)G:kլnAgZMy ?*)l!~ܷ3/oZ5Z+C3 #붳d<2nr=Z~!M}ޗ-Ũ[{ x Ar1҇K[4E5By v_-6WB'0XvQ4#[ Hٗ["lT-GlU+"rCjil_#IQ-/wcM3R4օEr8=wBRBаs\f\+[ 0R+eic}%6XH̀9}\Vͷ5J*|*e^xu#5tSZH&1OMU4[[閖>M֘&#,9]v_#Iiz}-$^<%m8oåDe[Oq"'3}+5]:|'^B WG6+\\8hþ#n*чZPF:+ j~ڽvTiP 2r=i t"Oop.-8yfZs|=xk~2Z^3Lb榵c 3W{H$obG=y)կn/((@a(=R]}911%͝孲n6¼=]Bt[$t+c<vjݍܳg8ReC{vx}j݈֓$li`pl(Ϸґlf)_-nx黭Ymɖٗd\ [}I Ғ43%Ѝ-sfC% z/\R.oΥ(`{Pta$qr:F en~^\X9Ya.]dq ;bSœ;{fp NMI 6*\ s.ʓGh)oOu&{ [+RU# k<8?t0ΰ W~L%trDB=?:rjֲ$nGntJJ w0bG  'y.de#rfPioE;̢L2zc{w`x%_^mMt!r% I>Ҫ0dvFe$Zyi5΢1Hv'Z4I)e$+g =i4:}>t03G?sL*'sU{mNIC((r?BK&S[ .e]MU\<wVB}scޤe]ni޸sYc<~7S)-īI,¤hYM8K4daܶ=,ϲNб'i^zlcYS*zNnQ@Fe>(UFc7QY8unvT$ 2Oa>~7T3i\mb8m#zj~c]+44.A%Q8jԻPQE?uZKŶC"?3RXwzksyM4M hmG }jnT^Wih]Jq*(۩wS(u26w>oa,ٵ,F' d9PQE?uXn,"#5R.ŘzM(ڝ}fسEP䜁Q@[xrо nX}!xsPCSoo:v Q@FeL/ks!m0¦|Gij7BuD=~ʢ(L[wvwVM :8 gTPQE?uPT`ZEL%J/n=375"^O"ǩVUJ)4dSMq2Flt* (TU9MIݞNu6GҼwc}{ b'-o#͞SMszjL(4[yK,LG`gz:W:{ZW"݇!@[o&S?JZ(SXśdF|A 1I(|8sOk=PK<{t"b\A@VVUQmnӜ=˜n-Q@2;";_>6(($te8#@Q@29EBQ~ mPȨW<M(UfV U 1f'$i(((y{fscE4vePYade♚( ???WZo{ҾU?5a_B~ЋQE0"U뽟USORUI"bU(IV,z4I,ZM]m܆A"D aꒆP>Aq+K6#H`2/Guj G#m@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6 جԏyy-0 tr)Vdj?#T#2@z_<[27#W|SӮk;L2v#ry'8m#0E[Ym:<$$}߻nٿJķA ybr$J GQ GR{O!Fr Aש^V/,?*V/,?*Gn.&`QL0;?Y/TL-: %z4[HU?[x?[x).c{xo]&RJ9QiagΪSNdгd}p'Y_@YU_@YUW_o@4h]ezV/,?*V/,?*5ŌWu H+Q9-f$C1p.I7i7|݌۵c¶eT¶eT], O挒Ow{o5ݽ$OV ®N3V]H.:t7BLy#9>ϜcqX_@YU[//͹Ca@.eT`gR֟ןz^_qGWU GQ GSV/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*0t X_|i/_iO0ʲHTTIF])pO]pO@4 Ep8M[Ccx׶͘HΫ`g {5\M AmEo+ y#?V'ko uO2 7prOJ-ΥkGpb|[qSmnFYL͹ą86#[$V>RPқ{~13H̊w(qp2qTrcۉWa%q$X<lZoi )]q*EcxEb2[x&V`IeX].EdbK}Rc|]:opU@;sF1K~g]esu%GI:@9KRͷIZ)gbH+ ~i-IJӦI +1X?0uBOEK,N:̽>?-%ͦm")@wo4\x[Dn@?_j{t!99CvA$]Lѡs[O &Gt3XۂWqnyDy;zU5=ŷ//4B3"i"+6].J'x.<3vRwjK:lRBVd.&Ca  y;!ݷ#]3PYvb܀r3NHvJIK0S!fa~Ynm#+Es XkoQMiWiww%W:zڤΧc|.ۈGow^")},Pn /Rcߗ6zc޵n"n "q=x\Fgr.VٮdPҨ73<:V ˦[ڴZ : )#w8"ΝjJȭ$꠰8 dOTxaii>9?snyYn&/LW͔2A=3U촽Vig.Vnݤd\ۆN K΍uH7 C])Rn7}ELukz,n.HmAbWzvRRUS'ݐTi-ΑukxWP2 ˺0:VP̬ W!څOo30$;Xq 3^Դ;ɮnd 6,

kx`hmf$q(~y[OcoMQ{y,M###$=$֢ҳ+\m!*2b}OaYzM݄6A d%A<)*8#yj8tMV_M"IŹW$s8 @kqoo^o-f 20O~Emeb@ J졀^}$5SBK漞Rna~i]hAcMN9H=SDinD"mb_[+=?_ծ֡Xp3=5n,ѝh]I 9tAe֒76DY4෷ s09ҏQzitKk-"#&a6>S ]ے=ɮij.3>K5Z%մ';b:IԷ`qu tO-lt3{wC$FDq { O6\Eb>!8djzZ{K[{Gtѩɬb:kZrum9##>=]xR[kp9R{vq5n~cNk=MbҴn䐪~^;sS]6.[EI#gC׽,GLkM/py3Nh_cRǮ |0ȷ#d)uFLt^ .Ź7,tQh%C$|x+VWkixR8-d;PZLj;{_6ݤi| ^9Bݏ4fP v5Cj9ʩOƩ;umi2¶WVK2Ss;GZijAO;F-ٙn$i~O4%{/oLӥ[YnYx<v]J-h#h8#=:U$'Dɓ1V&FNilWVq3z9sK}ֱZX-]3 Taw`>1SŖ%Ԓ1Uƒ29577w!M#>z$t}RYfT\ y|`ESsa*8w>a(~Pw ~~/)t5-NT1#.{d[_Cme0iY vۂ8zk_4/LW7pgS۟kmB#84\}Llƽcܺ3U),CUZI$7p0|ۏzu?_oqy,j,\#svӡQI O=I,$c;S]>b{2[sB飇Ma(H?ǻZ٩M~I.VEv޺]3PUa$HHlg}E AksrDv鹉H{+9|QdAu曃j-^k6Z#8@Bd u&F1D#ܪv?'r9_i4cN=Aʩ;Wc}#k 2MK_K߳PK1&x=Zx8k{MRKJv| d<&틿:foqh(((((((((((((((+?Zmt?`8ӽhV-dT+i@R I>Pu]vHKfS$1%ww5fMNų.aiT;g92ú:UMaR0] |?W']Nݡe%tARYJww\bաjvwz`藗tM2oO4u}2 Qw؞u s9CL} 2*Kiq%CQ߷Oqc PQKU!*qqưm<>m͔nb*-3FUE'Z~RdrSM_'_qERQEQE3#K_T}EOeUIW+dlV-ݞ G0#Pho--?[Z3 Nx0ti^=V oss$PPO=GfAOua Mi"yQʹT$ sSx{Eՠ)rd#i'Jk) ((((((((((((((((_ SO +D6ILc>#[tY c6r$9!F>zp-irA"`8cQ`j|̺Y F%0}G\I( r\ӵ`¡YbxTÀq^)Ѯ]+vh]U~+`5 u<>[9 A pҡKOP:xx¤*128݊/3_vFD[O 6@,^x=GOkeo0laU9Q彪-CE'OXiSò U=*Vö$f$ :*y&Mm`iﮡ9HKb6bc|C ̑J!}[ X6F]+U RWʺq Wo5R/*S>gW*:"sbAo$r4r[,Q,`|ZZ^]_][xF1#,{VlZG`Ht%ʊbe9FG'zT'Eԣ#Y&W iyG89Zn/tfXLl#p<1ޥӵT,fxhs*kMBYk?"{ڙXe'ŗ7<[=qñ#zG@mw#IS ڤ :^LձI8#%pG8{WWJHN>GX.8zk-O1ރq>=:n׌~YOahm.']7=TKbQH/zg/z" ڽMn30#Cu*-PhVmFt8 g+A>FFpܬ5PHmͷ9s=oC;2}<_+d [H;;۾ZN"쎠o>;rl6A"bđEeq (Ŵ6s;;̃s=o2}<_+0YUhg9FsGҿ'~fwgvG\n>;2}Xexf6Lld)#¸9G\o>`2[9s=o<_(/?OGl9{;xk8} ͳmh|_(/? ?%eFv{5/%!;Cso>;2}<_+>0W,H%ݞ}M<6*rwgm}S@y>Ee/I$ٶ#wgm}SO>-[vfsumh/?̼eO8bt2Nrs=o|_(/?8 $O\n>,I/Y 9ݟ h/?̼ef1mEg9s=okV-6AG\o>;2}<_+ͥY 趍{v{5'#o:v_/?̼e/res?GӛNGs>=?̼e2}ef8oݖs?GձC*%-s=o_(/? '9wgm}SWSıλ,vwe34Q^ϲ\kJӬvsv6:ʾu9g9ݟ h/?̼eO%;o_e;,y?GG^ϲGy>EsRG5'w4I_v31um}S@y>Ee/ᕋXٝb}MF,l1g9ݟ h/?̼eu oӬ9ٜv=}SJup۬,vs4yQ^ϲ\֒]۬,19ݟ jfcf۳;oyè\<Sv2V.sjl9}s?G6fwg99m}S@y>Ee/ζ6m1{>-ٜ99m}S@/y>Ee/Kvf۳;}M#kY1m}S@Gy>Ee/˶gvfwǜv6cvtGݜ:v6̼e2}ě6);}M)}۴299ݟ h/?vM$);Y+;-#Q--hi9N]dž _RM.KdPLOxH.(HW3E ԏY:ޝ\֭# :6ŗ;XN*ιc0Fծ|6nx֐;o祿=mVZj--Hj?_ ] 6K{+ꗙ#RN#_  6K{+K?u†oGI hJ#y)V;P<~ύfv 7Z?mQz[\j3W>$@: 6K{+>$qRmQz[\.GOSڸcv;o祿=mW|I ??-\dP]z[For'ĚcĚ4: 6K{+>$ԀDT~;#Psz[Fop'zv3\'ϛumQz[^ wA~R?w^=/mǿ 9~'x3m?)l 6K{+Ǔ⧈N7~(d`?^=omǿ 8>!IJEϖeܘmQz[^a/.6R^ xZGhK{({=-- I6Lu@ ^=3mǿ 7_'H_=mǿ ?@|Am 6K{+Ǜ⟈TEGjH>)q/#4o祿=mW[T=)'Ĥ-܈lH$Uk=)tbӭ&6|Cr)l=|h7ut,nmQz[^u:tW{z[FoymFqˬG-߻:ݷ 6K{+G?_|He,}"?U{.oo祿=)#, ?dGj9>&Zdƀ=kmǿ x&k?iU!+S9r*栺w:ϘJb)sZo{ҲeRw<#12Hm7=UuqIr2QL) _ꞻ _Ꞁ6%VzyڽbݿUjJq+>Q(RCd/!GSRRbϜ՗R)s1۴u4X{ԫn0Y4َhXP9*(c`S14@岧9'2$II Z(PGz7bȀ2jy76BL@V+^~\g4/yک zqV ҩOgKKjT/݄ʧlq@VAZüO#1AֲuQZGNx :z ZVgvu8k'@q5u7X\)ڰo@؎2kjy.R"`}"U=XnZ&Ϩܲo~A,! P)jrLvY6CW]̜ʹUIwzS%r#qgJu(X`9Tz0=MLv㹠Ts֤2:u>"q~{uXatm]]yߝˑe;~R=*ʃ9CTc@RL[4N|Ē*l _ZcMx9X|IZ|r0 @5 ɂI94{fyM! p=Ne\ C tTK qDWY( 8F3@S[;wcGC.bGL֗jߝ}qϸy?Chx!]+f{J9 { a3VW~B73 hW'@DZxᓞEeMn#2S)-ȬH m' ew.j)eN M2c4 vg;V]wA0*BR6@ MVPXO4OSqUoAZ=Ug`s@c\IWhUb!8#ڀ,"\ d 3iHR?KI9I@@FI [i0ӓ4^"Zt*$)4JQ< -4ߍո0XqVV5(N,\dWoy sՁ1e<>-ɮcebp{5j4j(+&ݍNZvo-Qɫ}Aaɠ||dUk0j574~r*z=ؤ\pցg!A iRx5X"G5t Z܋R}3@[I.TGzET@EcYwHOh ڀ)iW0 f-͓to*O"$hp(hEʮ=1Sr՟5P 5~1ۊ來\BL¸e*3><+ u5E1jp7oA5KћU2{G~2{G~TE_QVfE?5xS{?5xSݻĪwuw^W}^8>Mvw6YoZRnϿgq~tؖ8*'֖SLCp1U_sҴ*(hdF` Tnܞ*9]ڀ, yZJdV6 Bs⣱-<f5Zdr}*ⅷ<{թ$>Y=)2qAĨ4fUP?w0ZIAIu'&s@<$?ZgB*A5"K (NM2W/ H4d-'$fH+B;UKvۓP? V@TȬ 2(涘 cv$qg֬!IWi$'uP gVь cZ49uYSLPc1%9 (SciG͜Pg`⣓)X4sր)֗Noݏ#?5vp@~m;-y?C?gx!]+f{J9 { a[Cv_#O՗tFgڠGHU<}*l ☊NzgZsYwnZ`; (M瑚HB T6#w'ˌ?w/-3d^gkVնqY5 #pa܊]ïUdRR0WoCYcpB@*(yY"S.:v+"87) P\Nu5N\HoWp(qm2[0wKlJTb hBЬUYoӌRidm$TdV3s5VVI_85$nȮbfʮ( m),2k/JʹS5w;)pil;aV0ۦ@ěT+Tbbu0zgie y<%= r 5 `Q j9B{ktmZ2k*—7=ekAǺ+ekAǺ*(e(̊kWkW vUe)lFp|~USy^=zcҒ.^.%[C,*sڪ3mn iҘ@psQMp"'@jptwesҀ,HuS6Iҵ:}۳ZA4ᴊV%cqD3@y!P2<$nP8 ,qWű vx Ux'cdɩ#godc#Ҁ?зLj(^QG{L$^OJ' G"K"n`Yy8T8ZO7Z'J06 15 հNljOpC!'ozтu T ʶkyq>9/B(iG; M3t9sJd<2gs֬[d$8( [LftYV= c(,Vs@JP%1@o"[X3\֣4;FK̤ޙ!pA&t!J=+]Q gڣ >qp 3H<-*zVF6`qyNv1֜ y959ȩ7~}XsJNUxm9׊:SsM`p񻨩Bf0Ijq4=ڝ!>ؗr@ٲT6kBB?/M42di)b{ ,V䞘>jXF1R8}LGA략:әc@ x2q b)3ޱ/k{ N1ҫϧҫPQJS zAFc.vEH rKrhI'>v4&Nxc1PUG=*+#E;xzbHi@+"?5g܀QSE2TwJ)hI˰XaMd\\oShĮpf ٫ێ[x.O~㩧6?y[[$uZ  IՆ*ȅVXhj:u7|;@u|>I; g5I9X[UtCL7#4H[Is:UB[֮<*s a}QpFj5sRpYcBT0 HR`UaL[,"Lۉdzq]n*8(x@sWsp9Tf]jqZjU7T*Xv-L%'i l5UU{q@֢zc<֍m,x ͹rj5+o,N܊Ηk="D' {#:,n1ޮGdLp G>2հ#$EJF_#P6>ЩI4w9gr.ֵ4ȁ]A0!FUmdXi8L54:3 RNA=1J'5\K*L(e3OU ʒ$I-)Wq@ oZzz;Xu y=iBNԊC=!qtVf>#8Oeb;c{х$K|Z~H@ ҢJp @.TҦV}(Wqǥ!^@4/z}CWG]_3= lԏq_3?vGҺCCv_#Rjz[Tw~pR?:V\S#i4`8qrZ7pF\4~J$VT*`$P3߁ދhۜSV|S-۱?hJZejf##oNSy}i̿+61L䷠ ׈K 6EfnTMY$?+@"e#ʓ[n*Tc9x^5*Qo0Ji.ư}@"&ֵ-pIPS {VLYOP گ:֔RfS(/qkNYm8<ۜWcLF8"<RYR9z":֥|YZ;֟B=)/ %sT:1/sKj4, WpW ^k*Op{sۚ.<$NHpN2TTPJ&(݁5_&GWַ*B>u_WZx=ǽ cJýV C5}R>ʻ[?#]!{!/?[mCv_#M׎>V\Ricvi6)Ͻ1h {ZqQԓe?ך0@O3ʛڧR `MHqPܜ~㩪ۉ㠧7˸ e^] 1 &zO5u7;3JN({,͹YsU.b)03ձqE݄_/Jg 1kb9tA u|qLR[` =*KȒtQ3@ 6Z02⧶&S.q@a1v~Zn꒰WfZZ;6>jm6ݣT5+T(] L8ZZ9 K4b[ץkN(H%.2w ; #Z`EA ~^c̍Кu* bSP}ѷB\I)n|5$y'ehj '$G޳OZ)&Ta Es]˱6ȮB|t wMH$9&;ⷬ4d1fUgqtTҰnach3zZ`'AP2gRCOc@>1n1 c5pR=6$ېaaP; 9?уxt库ԏʣc 5vCcI*p5Af0bhp=h9x}vpD@w`foΤx>$Oas}^QIXx@n*$)Jsɧ\PJR'^(,<5.}k[6qk[@/)z3|/3Uh[:o{ұUh[:o{ҪˆV]*ȧ/zg/z۷oZRnϿgǙpq^n*]l8וCר"Cc>Gjb,nGj{,84w4A6,jzS!vƶaA*2DocH\I֕|GJ+I!V0pqҘѴjGVc$\TEgĨ#=)q@be x<y0Ҁ&T$u5u <`H,ۃpyWbvOZk;623ZkQq@3qR;yc- *zw%'ڀ,C t$TI#D8&(6n Ќ@UqkIqP22Ĉ|܈<`8xAV\ւB-eM XIXTH#5Jī_npn>AS,!m8#~R{sڪ.]^(m@ۖjgkI;%Qq@w.~y5e xP.q&-[Å|*c;gv:p0+ *m[~wcq$>C5}uUJ_]ǽݗvӵ [nj'!|a 6TN.H-hۇ8Ive[b-;2N{P[ åV`?=AŚp_?*R8݃ KC0ր'R@BNj$eFk!FmaW-#2L\'BG&AÌu %E^Xtvq$eTT |ǥT H]gҠhOր#Ӣ/7ZRE[M].{ҽAQ><Q6tyǃ*RB(ekmTu5чEV :r{qZK&jC: |;}!-E_2v=(=Ne>ǜ:<[UV6ˎxٞ XqߺC=rW֭>MXV4>o=1K1: CY*k>8g b+"DI.`*kze&tǥFѯ=E[q;rrSjo0|UA8)kV[LXB'2>@++WCk(g5<+[Bs[ ^ xz3"+gMuV1VAǺ*(e(̊kWkW vUe)lFp|Ч\cMh ˃X6;Ud(v5fXߺ1Y;XkjEMsμ[NߖG5CP̏1@bZcү1O^+?I6'K,'(n~^OsQfRy z "` [ + Sf3^Sⵡ\ rjRzʐ=jNLXe,pۀgڲ+43V 3 +y;bZ$%T=j̬ȁ5cMs( NnҨXڙNZ:x*#c4%k$S4YBsT]ۚ1F 7-nx]vrط\lss@J^{uPFXb6|U`HȮOb8N,Tʫ7s@ɒ*m&il(qmiڒJ:kGX=2+uqu ڀ.c5Vʦ(=w !W::}<Gx_E[ۆ:Wq}H<;F!ֲds]Kl-oc+2nV#=ʴDgVtx[+:ݣP5B(:( yj"v[]wdt_ 6-voqGCWG]_gx*lԏqGF{HWAcnk?Ƙ%h^nj}l*C89Ht*[-E5$8#< E*m?ѦcW2s%H<'ڠC.]t(ր:e :w<-¸y pe(+qlMwcͽ涮sg (M3\ľ!Z<2`~fLrmvFysDC@{WH1%LGnMc>Z ʞj]OJ`Yw)q E^\NDU]m7篵hXZ${I :]@cMY)mJ4|ƫpU ]+f\w+2M'ֶn|@(,Q8 $Rj=O(+\=jq`D8!A@bu$UiL r3Uv1ko12dm"9ַadwlґ@)YZݖvǥ3WIP^ł8CCU 43jBSͧ\|\U g]iAڮh fߟ&Ա5[R nMe_Rf_~g`h[:o{ұ״7=UODU߫.EfdS\=w\=m۷JWw[)N7u{g3MrEoZRnϿgg#i!NKYa3ySZS4WPGj95|X; -_ P6SN܃ZfR(m^GFN[""[c\ZlQ(cCVH8TH0Hh?E+V>C0oOZPrpOLUȇSqTdKzUX@ot^Ezrs(c'zf͞tWKV~p0:TWfXNW2I":.pC=/?1Dz!8t׵R+iPZJcSwA(X;4%ݐOlcֲ|;mͧi!dɀB``]/jA>O+ajk0zV'"Ifc6RxBpұhXq(2:# 0([epQ˦ۯJ$qheYc5C+ߛomwc=)kz]_\yWh2\ϡy?BʻK?#\YR>r6{GW7e]5 il;L!@[wnqVlfk9Okw$S\n8ػ+&h1]kNeROJcbE^TNW3XqRPü5iܛJ| 7&|W-KD ;HS6OB{Yz6qk3A$؈m2 Ho.CDpPn uѕB]SAB9n]ġ_eH=z{I.RxuF~`KKF$cᱎ;Oӡӣ!ga4;o 䁁ҟ =iiuu-̑_O) 6+5K e;]CG:BivA1q$S^G`1"`TNr=q9iA$P]ϭg5[pY}h{$֮11-i$k!b9y'5 1pk6`[Vv/^E@c8,}hګ95dc~+>;(6,y85nU&UjkXc+}i|8P@Mk&Wװ漐H$UH˺Nր')-Q3l*v @iY@xk-L]b=h1/ٹ:w(6Pڀ2n ȩH5 b/A5q%HV}i`0k^쨅F;Pp{ U0]Q_Bw*8I"?gjʻ_߀zԁe%A"r5YGp=8RD t-x hJ\k - HQV[Z3QS|zdW4d88Z:Lk h<O \z֞r%"SF)z3|/3״7=XEX??VΛ*o՗h2) _ꞻ _Ꞁ6%Vz0ȯ_oZRnϿg68̛k ub8"(XidlnHAo(/JD!Q&ݳ@'Қ!l:ǥ(g 4L~}8jLP3cs@mX ~w~b@pqI1ƻ ̈9i䤻Ivzʼ{y8phaRϻ`A,{(9'=3Nq1PI<>]&@#iZMv(2빇$X==+LD+U+bP=Px cZbt vE0sFrV1݁w,Ri 85mbG5*Z5Sm5 q8@iͷ=*;7=x⩖ & ݣk"n&Tkv->[ɿzNinP5Ɲ[@[rCJICҧUm8 sN#8e˳uћtsVmk!Sn5Z7lW)-yXjݛX lYm;?JO$(v6bI+l [fs'a؆BlN7L1v'zxJ|b }Q}ǎd D_*OΉNOZ[,֥ v4.uܰ݁TeXVf=יcq}>/TSu#P--|w*xP1r+4q^Z[\K 8Zh|Gyogwp[oOAd+e`<-sڊIk#Ѹꎸ#5w/$xZy9v%dVykaگ޽;r۱v:?<,6sl x4nke=G<u _ES#=Wig}+?3?vGҺCCv_#X_e9MnnkllbJC9= nVR̅9=+dmTiĊ3-Z֋:VM7\浬/pMg`mgzU[<.z&)qV5^m5ܷV"* }֨[iI+qZ;13ɠ zvy wEAY'r~ojkZU$.*qEA m[ wx9']NQgP[vVG*OEK=.96:%1o8t|Aԥ\,V]췓W8=2:-@*\8a彄g\M@nݎ3ZmMeRF>و@wAҮ^G, d+Ffi+ @O Ս@F{`VuZ(siOxzgӸE=jEI>o$+ VUx$s3裎i z9JK[hM6lyF8VD}v**MH|O“RNN1$Z=+ZS zk*{2*>bYFk5O34xEr9p(X&YRAiƻMM,aY(]ER1[M H{gjvuڀ+_) *DX4 ج'4Q^-]t#AbM-szIKg(dbZēF[4h Sj@0 2B>ڃf@J~sjپ_`GP+&vl\dŌvGZn(qڟ kX@-&Wzf{Uy.^FӊmMX:ktơu]<*Ż[ۮ*FqҀ:+ddEszeaگjl`{W#$\P!A 9e#4˘#C2P? @e֫\۷JWw[)N7u{g38$Ce8Q2.: $$)`W sW1C O4Q\LvV<׏u.o,".0qU*jY(Ps@ E‚rMG!A&vdtrhXYBp3OciTgp:5`9AUb<s'Fr!}*y^D2285H+n ycֳ5$9POZƺ )\Տjnէq0XZ k˟\ 4&JԱ$]n^VS1޸yHkEzs@=1z8j7('Ҁ92D pFje|yX60k&F,&i5 u:\"+e'ӥr+ C~ Xo>fœɻU>Vt$c 'ZdAeGjѱahu4Mi)e*. VF@@1g =kF&޸yWNq[Yy|8т]Ѯ JhzsޒYҀ+HnpZˇA3Wm|w0p Jq֢^V8@#|D\݉uܝEtrk=~lހ0#ҥ2ح-;GH:~y3SqPIDˉny) x~`9';nsZp `WʖFj ?*Jf,pEtp.#Kkk)s@V,zF8fh_z`'io,m(l3?fj#]سRk5Yw.(r䞔FCdQEjWC5}?QR>ş~Wig}+17e]5SŊ lf?w ;g=݇Hgu*~kQ,::N=*8{~!`sRnm.1Z7A`8J{n0p(RXԃگlR:cIf9SZ)Ƞ Ra7 Cg$Q= cJӸbKԟS\y3*ӉzVKPHjm*qW9.jx J㊱cl$; >(!+ cE7 =WۜPR $A"4HebZYy`95G6>_4XzL?n[3O 2B/e'>r\+6RJ|A I2yaqGkL\QKg7Teoz$D>lT7Oހ-H'5MsYo#*VOIXz7G(hbt =4j|wbOJʇ$hf aldUQ'ju(}xmGM6}:c4Md(nz(@&+,k3Vksǭnyb}qGJy&&7{+NQY&dEgtkؒz;f^K{goS*E'9c'N&RxxzڲNFҵm4QYFy'ok('@{WyQ71Mg$>6Ul2J;bjB8P~TjmaG'xWhʛO"0K.FO,L N&4X2=h[wF'U6#VMNvW{ĖAoӭgQ֋ oϾkfd8==-ZogH95 Һ}ND Ԏk@-I{H}kZ2lBBhXppsހ8 B@r.a"x64o TqUA䄍I8tye +zIKp QWIӖHqa" 'ya@ pڎrq+wooX玣zGo-w^q^[q2=GCWG]_sʻK?#\Y+R>r'N2|[Z>aTygtZn#6ߛjK/: Vņ< LG1"yNb'm Yɋv9R#]b紒Lp+ӧFb(Ib K4x.@ )y\z_6Y0kI/Li$(0(l&8ł ҴuU 0+InRv+CHyGQrj@Я:Sd-HJXM2T=EHwPLX(!88?R9xy=S+sX1<@la.eV]?*DZ\XG4IIL!>T8@LY"4v< ޞ &㠩b# @QҀ(l 3YU۫Ggaӽ!F2k5H9k3kI$@呤'"qUڜ3 hƣ1}ULc5jD4v/19KGRaJY-b.}5n^01qM[ Yeğ{4${eRMUkW],A #XdP=>э dsҩmV$0P]ƬNETW[*HSZD֚$|PfK3萗h=}bL qE8F9&im.(M֜Ҁ1ub&VT:@"\ Ս=ϥfu`9|XPY:К傩>=W3 *9X8=sRƀ5DBJGe 8+,B=N̑Ҁ{l ] pz+b8>UP#ya%xAb&K|㫟q֢yNE\B=G<u _EFkHW3\EvGҺCCv_#I vgݗvѿ!<#U+WyV1b1,TN:֍߳6{ ϶wI\yT"h'\sKkPBR.zJWTS1V-.M%鑶F2iS4IGGkycQ] [P`LxɠZW` o -A3Lcpjb8Dr2{xj$j2e tǭߒ{zTP xHq@/ڸbDFS֟!dub @Op7RKGAˍ/W\㰠 EL"6ۦ ;wBWd9\ΕwLl X>5녵b4Y2y}6 m v@fH~ZU ϥU-Rҫ mNB5F`MY2{`J ;%{/5gԚڄA1Ҁ&z⹍^;ڴK(ݕrNsP!){ pMjX>ϸ@XNw+rɇoJҐf*P74 ӑKeJ]פ:柧ߔ Ϸt82 * qSkX˓MֲSj];@`gqlbY @ Ӂi z=wҳBIZSWb(~٘,SK9L6΀4܈ڣ4^ 8U^Z1:S@s P~BkOmvG^3D+p٬s(+J}._+%*皪H>ncVGSVR4}4a:ҕBzaXb#\VU/Fo<=Wz+ȩ{'+kMuV+ȩ{'+kMuUSQ~7˴QEYpO]pO@vUSy^=z4@-W۷JWw[)N7u{g3qۼc8$6fprkFUW,1?ZJDxR7GJ6?Ú/4H'Zp晜?4.Ҁ8`IMǗ 2ww=iF>cȠ 34֧(fBW#8DxUkxs}jYumNim),z犊Q@< |q@(MD+V̉  !ֲc9>̪dəͳ2H\4֗WwՏ"q U[p|cw.2.F. S|$.2U݂GlG$bY3Z0 bqI S!(Ze&QU-4}y銰@nn#dy8ޅ@{IHb PX(ңzҳhEn 栝^?Q&XSd =((TLc?AQ=3R+f>h܂NnJjd4gwR8=;ѷ֥LF8Uku1q]3#d*BG'Ҁ1aakX!vłFNF(W۷Z!sR}E#B }8<in tv>^ 6KEZ@F3ҥp(( jޓҟ}SL#;-= sS<ؗS;!ϟC$>C5}FkHW3\}EvGҺCCv_#Oտ[S/7e]5.2 7386FhdsOLdV q1TES $a{O,+ Z#G֮#>nX t7Wꍁ4jiV8-ֱgIjΚkFs=+ZDs@,v:ր#h23Rcy|cFM.2栠?tj#x?I"=~ !@2aHDF<Z݉TN-.W> n'TI^iZ PhyY'UGCojh !ҀI;| ~aoQQh1MjC&-gkmT~5.-@ʠVVK&kc;۫JdpMiIT'ҏt#uZ| e/u6WcT[7Er ܂~oAɠV6lrЋM6j#p i!O ߟZ@ MNGҵ dJ>Fx8$  }hl(MYG {}mu5FC@b,9=rr5g6[?tֲ*5;E6h#t@^pj=qקyր$7Ϧ*aE sGuy'@f-rbj &R>Oq-`T֖9lBܴ8  F֟ sր% Ɨ`8`ziobDM y21M^s:RxS3ЏQ=(b}PۛFwc?<u _E6+R>ŷQ]ǽݗvv a5`?JC31|{"`"sb'.8zF"1TGU ^bQI-]桷y{sS[Yl$b5 Gml欐HPlu}aWFڱchfj\vDTpyҬ;Lb>@]JR/J_2S6 ~֐lOTZX3@Ce$(CKr/&xF>Z݊y(a^).(=@}O9W9'@,Nsln>j*p1gd<Ⱥqګɏ0h Ѹ2Y#yjn:Vqɠ e5308k.f+^*VrkBACTZCҀ)|y{vƨKIcw#(s;c㰦y}*lHp4k1*[wGjGe,85; q@JzuBi >=+IrrN~Y`]w>daSPנxr#̽KT!`T5 na֋93 \s@4Y jV 1@ozvWހHPc5[Y,(wI\t&t(.zbA ~FDq\CG@%rni4@0qiuȠ>Y-g]:P{t櫥zVTr&6y+2/8oj?qޮiSрG 9g";]dtxf?/zQ!>=hMlGiE׊jh@==R#V\E:A .ڧbIuOAOFSpڀ.ZYNoj܄&MegʿLJao dEmiJodEmiJ "Yv(3"U뽟UnݿUjJq+>QjC7S]-Īwuw^W}^8<@zRCbzTYlM<Zb#8 > jC&~U`!cz#<ܞMkF \tt! <7 -VUsOa!"to(KRJR|܁TЄץhG5ЄPP%?2b`iFQI. >nX+F>8b#X?)N r'7P~bNy_ծvprT(ƗJAzU隐`)H8VV-rMp#I.,:Vy2r~m}E@:zPTr}8=3:$#=wsho TmjGvFwc?5l@gÍMHۛFwc?<u _E#5Wig}+o>K?#]!{!/?JuF0_| C1 G$2y^yUUX|93Ňz8d$G(2+Uu*0ZnQ(fFqڣYT*Fu,A f_ by5T7S8w; T23HbWZP[ ӵeݐ< t,&QO@#^)zI-5F.wFkb&O/G5z*kxHT:@eaTvN˶'8,:֍i 7\|¹$rjʠ:{S\n'G&,z;EVryeWiQ U;I OJgJcր7t8‹c"z hƕ V| j[l$#J&u:4#~ nOletv۱jn'ހ'Qrqݱq2']E"+NWր2bgS屝E%OZt=jơj:q@{e4su@b=pՔW.%s$7IiaNli̢UF$޺v Ֆ{a2%`8ZTHET̏׌(S95$ƥTmoĥN {G@W6{T{ ;V8؊y&X**2n%5MP沯)z3|/3E8??[Zw{ұ[E8?[Zw{ҪˆV]*ȧ/zg/z۷oZRnϿg$OJm%Vz9I JTeFOrxb^)a*EsFs֦pQu@F ɴzVݼf(b* ;Py$A7 i\*&P;RwNZgkȠ em# )M)ڀިyx-Fyp8uk.?- opz ]éssNY bHSLN?*$}iQS֘dĨq4|71+Q@r\ƧL7j!jȵfB>ڡU;@ L 1(y!Jkm^LQҬokMV)XqҦϞqQ.&28힕rt*Y.p mM*n#\mZ͝ǘFsQ' ,vNy&3eCgޡTZM3@3]rl»mڱt 6 4/s](ǿJr8VWg4ҪYL&lĞkfO@&TG'ȵd(e}ϭg &J$UovھCPK*+<M5+=ylnT'p')bZY\ q@Z{S@8$~.%$15SN{ԑb{棽ޝչHЃ@XO ̢'rz/jV {U5:Չ}*4zBېOjkGL]>^:!7M0hK0Y,=ͽߌ\C3zWYvlր9}{O;G5ͧ+}{׫S̋@US=ZRpc<\hee r|Vր4т?J"dQA7>M`G^DK$Y lHF=*n.{jt6 DŽk: &e@k4b=kQ_F:se_Rf_~g7pײ"_bpת"_U?W~EUO p^*T p^*Tn*]l8וCר+:6wwUSy^=z`pi!oz̅R]&*nnjkUR#SR1%t^w;[u0}*B{u ȩ\_Jm"@  Ž"]I>X>8D8y@#1VX eJqqj/;1s)v۞*JqTe#AGuAmS15WmjpsWKq[Tvl}'ΤUNj`ݔ?J$SYח ],S8}FhAY>(ن</[jz,6>қj6$bNHXu8*fHd@lJ֤P_άN $8Ƞ|Ua8T D,yLqT^v=hi$ ;O>'IHגJPSV0&vdb9SC&$|#L~Qԋl/JFhK!ŧ P_}j`/{Ԙ:Pq["0 +Km#oD9>-U65#nn!ݎq$>C5}憷Q]1fԏt=F/MݗvoGe6Y?RTvr =k. j@s Ri)#)niyf2AȦn ̇oZŁ1O!$㊡-A zROZWʫb R rj0(G,n5)/^*c?FQ" }J(P9暀9Px<ʩRv',*n@A@UUmf_5ƀ* WEWR$1 qڠ\s]vX-V?"E%&YZ8d1nzW9j @prM[A*v5,~`(Â[]>A$-ٱ+x X3҆@1[^Ymb<:[fŠ1_,r:V}Vv?nP1-ߓ),(#+ I\3K6k#P; Ò ][q=j7.18ΎJՎF:PU9gX"XՕN+E1zB mcV|1\)ݝh dpŠif-㈟ր:  ڞW<<$f1pI kgPzQܨk#֒J瞔ajosלT 0|@ x_K_spb'֘JDץui\M5sh!NI1ێ+2&;,dpZf@@lT~bW56EzK*.wFydY<{?i!,:4kZ_Lx:JUQ;CcUی`b܂: jLsLDֱKttQ^(qjz^sK#dduVzKP[# o :퀋j v "_2PǧJ3ڒԄ\:%ت*%;ՒZFTSH8 :L <#W8_Ymk: I9Qןw3ZM{x!zg5;[D"6X c֔ÌюiA*{l77<Uk+@W~*GZI@XsU%B3ֳm-cD8ր5# 3z MtlE]Pd>8!uo` TND R#U@u6Q&Ǯi^?1]uF"S 8@\̬_,ɑ9=qWm-]GҀ9Sp)R3qךd21|쭦|#$P9$j Em.`˂N*熭fEQPIF,O5b?}q]l$/TCOs@4f/G{/&1^k~9E#閚 ӆN~ul\)W2:JK+ɬ<[s mrH9o-d]-r1cxi I"ϖ7ާmmDwc?9o9Z^|%nf>}CWG]_fԏq#5Wgg}+17e]5Z2ÝiU{!/?y`pO!"׷.r9fkk8yJ\zb1.ulޤ-P[ڳr fuNJ۳5~?n ShV նμm636h=gCj>5p>E]GZ8 iT_ךOZ]'2^_-NA=kF"k*X*}GVp'ζCut\zT\n>5kl6=(|wzbwtXWjOP/3^Mi`Dk>O$#5ɠ&v@4RL~Mdf-91ex<\USj}L@etZ}c;m$;p08f*xEd(Î=j݌\PJ;W9dS[׍r7 Aր(XD:pkv+Wm q?Y' *f)|@XחkN S۲80oxUOsK"h>zZ*.?wڬΪo4mK268t%+98Z m^4c+_005x}VUf<@r|Mՙ5[ 7;F(}5L_o* 4rAϵS1U3jn湽2atn@<܈~FMʷ 0p1Nbis5:,Ђ#+؞%o!sftГ$KGNIH'ҵ`3[6& ff:'BQ-`&"?&A*=8mc' ={n!VQ׮([8ɞ0AasNl5`fj'Ufɭ5S$t}.r-*c# DYW_߿pת"_bpת"_U?W~EUO p^*T p^*Tn*]l8וCר6`+%Vza9!ZdMy8 ZٷQLDf'UsS$H:lR+6\aҥDm#Jr¹ZQ^5X[zP4jRh;M`̣4|wfF4%WB((XUJpy qȪ8RzI68Sֶ$;Imdeq֝, y8@%@AM8AGpk9$!q-/8+e`8{Uk$6:QO*=i!ӟ41@\L̻YZLIZi$U@X (q]ą\e8m@dfm6H𥵽]5z~-Z52G-x=jgz#r7Cֻm lCO<($wVLbq5c >]Υ >g?`DZ6c nYo kMtop8Y0_!Ṅڵ.v v.`fOj "[Mx\oε0E!PTHNޔq"3ȫ˃z}(8X)&9#_DBucy@&@ݑS.+T 8)oo:1Ҁ0%:fq08VL'$1޳NZs|Zdq ('5^zzi ls3PfC `O\P"I!KxarG;?#\cqJ17e]5gdgVF#scHg5ʪ2yP mXHp&nbQq1ߖ>r&#EF ։q&*=4n ʾ U$ SI#. Y)v鏝quWE O@c#ڨKN[kŬEcpMhE,G4gR&7b}"cƒPt4w%+o0?Z{]( `]IfP>O>)IFk#.+"M2$lx@ͥK ~ Y!Ϯ+muJ Ű8:1iI$o aqLac`i%Ԗa{C 2 3N0;չU7Փ<^\گۉ}(sU^MI954 slzƭ<;jLP2j̶;զ@[5\1PJ>@ ScSOj۸3E5t&P[9 n`@4p[wV9J<c-d1"1JޫmQTџZ~UPJvU.Wdǃ֬iC8 n*'5-ʤGm,ƀܘnjqUVkEYDDG(2٦Q4/ֵ|+]4.@zњPdDUlb#hǹ5XS]S5% M~g?Pת"_c'ᄏ9n\(;=UhɨӓhEUE?5xS{?5xSݻĪwuw^W}^8>E*cW۷JWw[)N7u{g3kġi! ֺb ǂLCLCrAcҜPR^Y)vigH:ՋCU) T1 VDYKgꚉb&S5FNVnOl#w0RF}h9^KjWPhẼ;x8 n"p@Yrsq[j.8R7r%bu p_U[P+ֲiKc2+@wvb1=0ªG,:w>ڀ7c "/5 fA5mvU5g,S}PuflLJNx* l۱ZD `ӂRC] d U dP`\(n"kyPUyl؎NڠC dUtfv1Cȇ~1@oʸfsk}^@"2⼺8X3VtLwR}6.*.pzw໅IX =}y=.qv6-W7ulu*1? [Fi;?#\c?Wgg}(Cv_#TZ {!Wo7e]5[aX*C8ǴrĎ2#Mn4X<Ι-b3ad .Ȑn^Tv55=)ʌ).* 28Xր!-lmN].NV,EDy )SҔO[eVnDw3cށ]pT맚71G\ջF 5.r5ZM)na  #Ҳe6cVc %ƋRj̻ʧ55.H4|$PyrOՋ}B[,JlbBk9X?Zڶ֑E`\{񊣙M٠ SPL Vt8WvNrk*ٮ [Y :Pӌ&`b|[;~)t-j| rZø3ס3=}{;LV(v2$W0QVvq$P M1Za(-|#lqY:"(ur\tz+O5E W/NE6f+Rlqk&r{ֵ! 93V[?9 V$zg5V ^8kͅY@_P.sZ7AT k0q[vaְHŒwmnr={s@*3m= IޑA M#88;Eă-kWUFǥdBwphaztT5IAmf)`zV}nkfiNW~=z0x3V2~RBd*z kRIZ)ύ2*PK/AWWÚ\qJgbcx 9=:T> > #OTSWSTw^M;ryHG]46RX#WlȐ̔<$t⸝^.AtX^qTH#!}R1Y>'yy5]`Bv7ҽn?Z3cz+_ZűzK֠%|Tz߳qұ'ڽ=< [OM1%p1D>ib.;b?ҥ3V m-B;kh,:u&x7YU/;b'JûA>'KGh;"ae p@>G))83 j~oM$V_ҺKqgLojRJ=tUi,TWwx/ViCx/Ucᤵxy4ܴ;[&Y|:`$U_@[|OAjU˒3ޛimz(%U<':|VxʐXdjh>aUǂ<@ ;Z!@nT ͗ 5vDH|-}| *5:> Ռpu$^ԕtaRp:)m]?"|U;y`¹xP?J;YZ<7z%ylRKD.(/{TrÁҺƪ)\?[$aF>ZE:})>qC?4 3tۭ&dڅ爩W>Р(EvvGҸ,Wei}){!/?&mv鹇gtY5 9V?-!jX!xbǦLE+rJZ? d̄4Β8Zw8@ql}­=8OP7F8̓mǡGsqo2}P.,02x#HcX7޺ ?w*OPTsqfAOYdOǙOR?%dDs * F~PsW-KRncQ~F1')Y{VxrBVNvWipF*3Ҳfx#iJ }To$3B夘WLS[ yqB$5_lf9هkam+ƱN ۺ"9+Cު+x$Y>xX21TnZ;w?b_dƹ뿂7wnY*<2?4q^ 25臿ُM_W ӱʬ/~Zx@z_'q⪭˛ע_oPZvRV$$!OW%-u5Ȳ;T627ۉ#،K WُW5q8b3Jc"滨Ok0ڰskq<t/p18hGQ=+_\w/JIϷD}>U[f^ uMC.crm@3j^$̏|n#@ic"(ZZ+ WCnaXi> `M I KF?fgPHs9AkWo CUe̒o\C<ŶeۭsvR~^Ǩ6Q&?Փk! ܳوKBa{WQo܂5x;y'j|;LPx"ϭtnQ{ygj~CП*NUFG= ̟j8|l;K5FrzWmm˗$4lA=itZ~=k OD=}n-N~wRvKb0zV=qW]x"6%P[|?}nPQ{"ʵt_fj(bО6V ´_$2QLDrK_20ȬA( ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oE2 Hu #*uQEQEQEQEQEQEQEQEڻcY רהkn#/8nֶvG۝ǕEL0 (BG>TH9ڀp3P"խ{gY$aiyx~YF$ V9꫷u57$:,efD1<JdS-}w!l<Pr?,Zuāx=UvSMf #a_jJ(2yF?tI)dyn g(I:+g/X窮iPqy$l1c+Mf2$&~錓TP$yn goeƭzȷycTQE(((((((+<{Ia=veU WeS ֕YS4LSHWzӿ»׿綝o}a__f?闙v? 4"kwxCv64I *26~Tt8Tn?Ԩ8oWzӿ»׿綝f,g9RDk /.ۋhݍ®VYO/|37wgڏVR?]NQ ^w"kv-w- vXqX]Ja.+f}]"߷i}A,rQT{G+{{i?]NWl|as}-ܐCk$q.-20T܎$c<C=ߝgyʿ1mջ8Wzӿ»׿綝N+h-Ya"R2>T}zpǖ»׿綝޽=Ez}zpǖ»׿綝޽=Ez}zpǖ»׿綝-jNysf#3m*^w$Y%y G }wl]Zl>h6hdGRxZX:IM*'+ʹ?j2:޵u{5C},6mȌp ö ٯI?g\Aaळeuk>`TQ ?*}3AV?Mn H{me}dOn{=CWsk]M/!In%PJon@?)~:*rvcs=\\/icpU#"ۻ"|9١?ѽhm۾s]}utzYQxjMI|"{n_{qr݌.fajxRO nnRTvQKi`2m,*NFp+-< As.7Eі@dg<a 6XU3FaE ͞1Ju( h4Fy2JD H( ( (!ylqcG =*hVeV;44;O+BmSvVW&+h"RV4bƭǥQ_"-j?Du42š-AdP2Nr@qӵ{4iSTVǑVGRIKJu M~a)_F_UIB8# U>>ϱ}93:g\eyi˿#g1z+)kx/rrɝmg5%:&05iJ%J+QF>qڣҭ'Y%-bq'_1)(ѵWUe OY8Y؅UX!$ NA?E?ECGyex0 IdJk}ZIWKU$ NA?EV7}^}_f%:&0SboX{G*oW NA?EV7z_ʃfnSboG%:&0V[F$`WpcG=_f~1-\K~g:M28Ʀ;]&fN_h_ӿ)?ƏIt/ G#)V_-gJ&*$ǛmffBޝI4KoN9`]K]>Zja oU]_Mi\Ius5JAw,QE# ( ( ( LUpOT> ?q%ޝ_6cyh]B1o-5Iد&V9v@ O/JߟoNse៲i^-??mtw~I-Jj6֓zݖ[YcEI)}.jê֞3ӭMVR㳽xɛlo&eFrd'53RkW947!x}>\ :SNu(IqKw&\JUeӚB b3+).8nhXxP,b,wJfʫ0ܫ tY{S-$AkBɥFX*W >rPOrrsPEPEPEPEP7ic1 )n8ϥgxw_ʱ46ӽ sL 0#=Vkq4Sͅdc*{zNӭ4llaXmD_ԓԒy$IyG˹H <#Z7F>u*"@P\ ?ZA{ IxAUb!3/| "(7S)MJ<5VU嘲bR g=3kw0)刲#P.gt5ikP5ϝAUhSB>?<͵ 7I2$Q.ݣؿ>UʊE +5rIb'/| "F(?0 y͞}`*mZ5bؐH:ikP5ϝAP-T$r<}?(kK;_|oTkK;_/| "8(g+FOF(??(ӏ|utvWSpARkK;_/| "8(g)tѴH I ڪ9,OV#66NȠEaI?w5P*׎a!+5Ʒp?؃DGUGVV5$=DѼ}JӮz1o;}RH5##br+5ѥ[:?ڼCl A=v:W\g'm?NiB*ZOդb(aDYOq1O̭SVv,}V()%dBUA#K}r_+4η}F-z!^6eH_?RQ^qQEQEQE> ?*}3AV?Mn+tW>+ci?z\GK 1ϓ_V>im=̳:vBWd -q_`GDx-·6e{yȕqݰG%/Ibzg{G 6 u˭p^=*W;(Š((((9+{o3Xlp<zVGu&IG4[< Hꇷ#f&ycT ݗQEQEQEQEQEQY>)Ӽ#_ZIXO4Ov u?5/gݢ5/g`j_7k_v=[n+407 (ʊ!|Cv~CETy6|]Z5eJ\3J5##^'WM.Fw%Y$?~w?/._k=:zѩQݜ?!$K?'_qߛ/G#WZ6_G_!}BO%_]w:z?5uehS9}֬漴,L3IEw6Kgdj8_;Eƞ-ւ g\ʴFi+Dߢ5/g`j_7k_SvԿnֿ՟#ݭ߫?G + RZVT5k]WFO3kK`v­\":(O*'* LUpOS[[L4.M+tM:m-fEi5P݁3Y*;+Cka^tǝ!M:j*ai~簒EaAv9R'*[oYX69Db2`xF9\1;q[PEPEPEPEPEP7vkp r(bR0FG"[ADCHpIEd[뼿1j]эST (((((^"]jb].@wh&w,bi#H>d8w3Uȅ/覨MsYhGNm"If3y 9Uu EmGŗRkŢ:+{IXl9 ?B@s}&f۽͹K4FE`hNaמ*[Z]Yk$=gw !;8@y9U4&g1-D*!eT~@2I''$y/5;gR#?WK; k*@jĚ/l೵$7%yyf)C T[|2~& .B21*>c{.6V) +Цʥnʒ6u##sbNm"i[8. BD)cyZ>w`w7sg˝S[ ?,OvhKaQvǁNN9Vk/~ y۷o͍wsz_-HK: n'1 \.Dn@n*!Zu/^Ŧ%Ņ\;(,v]NUŤyOoz6Cë)ʻAPz\y';UWt) *yҁ^#QZMYlvUIϿv(Tz$^eLq82>\u*=ڂڃ]^VWWdyyI c9N : ~AVݤt]ZAfgَuTQE LUpOT> ?<9M/Ó_]˩ֶ_I#4 ;<@=B;֍8<)ņ'F̰&Ky@HN8缰4k HkhSq;Q@ 2y8uvEYc-#Xt)Xy9ums&^Asɡvd|3hml(۸ǥ:ޣSPԓH2j+ڹ6xc'$GaY'9-fX^-!q _)A 7r9枺u@mMv; =@402|?⋝{Umn$s pyLn2oQT Ѵgx-R&+Q89U((((~ɧ\mDIC'Os{Oc2!"t/j̼G#ִ5 i3Hߙbp#o㏙V%fLa ,òi7?UM>7?U2.ύU7eTBMEQE ( ( ( LUpOQE5 4. 'ē,*+39 *zT?h`O̞[0A+E00VOgoEȕ|b U8GV P6=ZyϥU+4Q@Q@Q@Q@Q@v_/j*QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEnip2-8.7.1/doc/html/nipguidese16.html0000644000175000017500000001164513414613100014222 00000000000000 Histogram

5.3 Histogram

This menu groups operations for finding and transforming image histograms. nip2 represents histograms and lookup tables as images with Type set to Histogram. Histograms may have pixels in any format and any number of bands. You can only find histograms of unsigned 8- and 16-bit images.

New
This makes a new ramp histogram. A set of sliders let you adjust the shape. Use Map Histogram to apply your ramp to an image.

Build LUT from Scatter makes a histogram from a matrix of (x,y) values.

Tag Image as Histogram marks an image as actually being a histogram after all.

Tone Curve builds a tone curve which you can later apply to an image.

Find
A one dimensional histogram treats each band as an independent variable. An n-dimensional histogram treats each pixel as a vector of n elements, where n is the number of bands in the image.
Map
Looks up each pixel in the input in the histogram and sends the found value to the output.
Equalise
Find the global or locally histogram equalised image.
Cumulative
Use this and friends to calculate a cumulative histogram (integrate), normalise a histogram and match two histograms.
Find Profile
Searches from the edges of an image for the first non-zero pixel and returns a profile histogram.
Find Projections
Sum columns and rows in an image.
Plot Slice
Mark a guide on an image (drag from the image rulers, or click File / New / Guide) and click Plot Slice to make a histogram which is a horizontal or vertical slice through an image. Use Extract Arrow to extract the area around an arrow or guide. Use Plot Object to make a plot of any object.

nip2-8.7.1/doc/html/nipguideap1.html0000644000175000017500000002454213414613100014125 00000000000000 A Configuration

Appendix A
Configuration

Click on the Edit / Preferences to see all the preference options. There are a lot of things you can change (probably too many). This section will list the most important.

  A.0.1 Calculation
  A.0.2 Image display
  A.0.3 Other options

A.0.1 Calculation

This column has the options which control how nip2 starts and how and when it calculates.

Data path

This is a list of directories where nip2 searches for data files. These are any files that nip2 can use but which aren’t loaded at startup. I usually append the main areas on my machine where I store image files, for example.

The default value is [”$HOME/.$PACKAGE-$VERSION/data”, ”$VIPSHOME/share/nip/data”, ”.”].

Temporary files

This is where any intermediate files will be stored. It defaults to a directory called tmp under your home area’s .nip2-xx directory. If nip crashes, it may leave old files here.

Start path

This lists directories which are searched when nip2 starts for any loadable files. Anything that nip2 comes across will be loaded up.

The default value is [”$HOME/.$PACKAGE-$VERSION/start”, ”$VIPSHOME/share/nip/start”].

Auto-recalc

With this on (the default) nip2 will recalculate whenever anything changes. Turn this off if recalculations are taking a long time and you want to make a series of small changes.

Update sliders during drag

This sets whether recalculation happens as sliders are dragged, or whether the recalculation waits until the drag finishes. There’s a similar setting for regions.

Auto workspace save

With this tured on (the default) nip2 will save the current workspace to the temporary files area a second after the last recalculation. If nip2 crashes, you can restart it and click File / Search for Workspace Backups and nip2 will reload the last workspace where you made a change.

Auto-reload on file change

With this turned on nip2 will automatically reload any image files that change while it has them open. Handy if you’re using nip2 to watch a file that another program is updating.

Maximum text display

This sets the number of characters nip2 shows for string values. Turn it up if you want to see inside long strings.

Maximum heap

This sets the limit on the heap size. Turn it up if you start getting Heap full error messages. If you left-click on the space free label in the bottom right of the main window, it will change to display the current heap statistics. There’s a useful tooltip as well.

Number of CPUs to use

If you have a machine with more than one CPU, you can make nip2 faster by upping this number.

A.0.2 Image display

This set of options control the default image display window settings. Useful if you’re always having to turn the status bar on (for example). The maximum size option is handy if you’re using nip2 on a machine with a small display.

The Auto popup option makes nip2 pop up an image display window automatically whenever you make a new image object.

A.0.3 Other options

Other areas of preferences are less useful.

Display LEDs

If you’re using a theme which uses bitmaps for widgets, you won’t be able to see the button colour changes nip2 usually uses to indicate state. This option adds three small LEDs to each row which indicate select, busy and error.

Default image format

By default nip2 file browsers show only VIPS images. If you find you mostly use (for example) JPEG images, you’ll save yourself a few clicks on every file operation by switching this option to JPEG format.

Image format options

You can set the save options for the various image formats.

Video for linux

If you running Linux and have a capture card that supports the V4L interface, you can capture straight from the card into nip2. Set the capture options here.

Paintbox

The paintbox normally tracks all undo operations. This can chew up a lot of memory, especially for flood fills. Reduce the number of undo steps to free up some RAM.

nip2-8.7.1/doc/html/nipguidese9.html0000644000175000017500000003245413414613100014145 00000000000000 Image view window

4.1 Image view window

Figure 2.2 shows nip2’s image view window with all the toolbars turned on.

If you press i (or +) with the keyboard focus on the image you will zoom in on the pixel your mouse pointer is over. Press o (or -) to zoom out again, or press the number keys 1, 2, 4 and 8 to jump straight to a particular magnification. If you hold down the Ctrl key while pressing these numbers, nip2 will zoom out by that amount. If you press 0 (the number zero), then nip2 will pick a magnification or reduction which fits the image to the size of the window.

When the image is too large for the window, you can use the scroll bars to move about the image. With the keyboard focus on the image the cursor keys left, right, up and down move a few pixels in each direction; hold down Shift as well to move a screenful at a time; hold down Ctrl as well to jump to the extreme edges of the image.

You can also drag with the middle mouse button to pan around the image. Use the mousewheel to pan up and down, hold down Shift and the mousewheel to pan left and right. Use Ctrl and the mousewheel to zoom in and out.

Use the View menu to add extra elements to the window. You can turn the status bar on and off, and you can add a display control bar, a paintbox and a set of rulers to the window.


PIC


Figure 4.1: The display control bar


If you select View / Toolbar / Display Control, nip2 will add a bar to the top of the window which you can use to change the contrast and brightness of the image you are viewing. The left-hand slider and text box set the gain for the image: each pixel is multiplied by this amount before display. The right-hand slider and text box set the offset: each pixel has this value added to it before display. This is useful for boosting the brightness in dark areas of images.


PIC


Figure 4.2: The display control bar menu


If you click the left mouse button on the arrow to the left of the display control bar, nip2 pops up a menu of useful display functions — see Figure 4.2.

Scale searches the area of the image you are viewing for the darkest and brightest points and chooses settings for the gain and offset sliders which will stretch the image to use the full range of your screen. False colour tries to make small differences in brightness more visible by colour-coding them.

If Interpret is turned on (it is by default), then nip2 will look at the Type field in the image header, and use that as a hint when transforming the image to a viewable form for you. This is usually the behaviour you want. Reset moves the sliders back to the default positions of 1.0 and 0.0. Set As Workspace Default makes the current display bar settings the default for all new image windows in this workspace. Finally, Hide removes this display control bar.

If you select View / Toolbar / Rulers, nip2 will add rulers to the edges of the window which you can use to measure numbers of pixels. If you left-drag from the ruler, you can create a guide. Guides are useful for lining up other things in the view window, and also affect paint box actions. A right-button menu on the rulers lets you use a mm scale rather than a pixel scale, and controls whether the Xoffset and Yoffset header fields are used.

If you select View / Toolbar / Paint, nip2 adds a paint bar to the top of the window. You can use the paint bar to do simple edits to the image being displayed. See Figure 4.3.

While the paint bar is very limited, it does have two useful features. First, it can paint with any pixel value, even complex numbers. For example you can take the fourier transform of an image and paint out the peaks. Secondly, it doesn’t operate on a memory copy of an image, it operates directly on the file on disc. This means that you can paint very quickly on images of any size, but it does make the paint bar a bit dangerous.

Normally paint actions are live, that is, every time you paint something all the objects which depend on the thing you painted will recalculate. This can sometimes cause annoying delays: there’s a preferences option to turn off automatic recalculations for the paint bar.


PIC


Figure 4.3: The paint bar


The Undo and Redo buttons move forward and back though paint actions. The Clear button wipes the undo/redo history (useful if memory is getting low). There’s an option in the preferences workspace which controls the number of undo steps nip2 tracks.

The slider sets the nib diameter for drawing operations, the black square is the current ink colour (you can drag and drop colour, or pixel values, from other parts of nip22), and the text box at the far right is the text that will be drawn by the text tool. The paint tools will ‘snap’ to guides, points and regions, so you can line things up easily.

You can mark regions on images by holding down Ctrl and dragging down and right with the left mouse button. You can move the region about by dragging on the label with the left mouse button; you can resize it by dragging with the left mouse button in the border; you can get a useful context menu by right-clicking on the label; and you can pop up a box which will let you edit the region numerically by double-left-clicking on the label.

If you drag up and left, you will make an arrow. If you hold down Ctrl and just click the left mouse button, you will make a point. If you drag from a horizontal or vertical ruler, you’ll make a guide. Guides are useful for lining up other things in the view window.

View / Image Header shows the image metadata and history. Use the search box to filter large metadata sets.

The File menu contains two useful items: select Replace Image to change the image which is being displayed in the window (you can also drag and drop new images in). Select Save Image to save the image you are viewing to a file. See 4.2 for details on nip2’s load and save dialogs. Use File / New to make regions, points, arrows and guides without the mouse.

nip2-8.7.1/doc/html/nipguidese24.html0000644000175000017500000006166713414613100014232 00000000000000 Syntax

6.3 Syntax

The most basic sort of definition looks like this:

// very simple!  
fred = 12

This defines a function called fred whose value is the number 12. The // marks a comment: everything to the end of the line is skipped. Case is distinguished, so Fred and fred are two different functions. You can use letters, numbers, underscores and single quotes in function names.

You can have patterns on the left of the equals sign. For example:

[fred, petra] = [12, 13]

defines fred to have the value 12 and petra to have the value 13. See 6.9 for details.

Functions may take parameters:

/⋆ A function with parameters.  
 ⋆/  
jim a b = a + b + 12

This defines a function called jim which takes two parameters and whose value is the sum of the two parameters, plus 12. The /* and */ enclose a multi-line comment.

Functions may have several right-hand-sides, each right-hand-side qualified by a guard expression. Guards are tested from top to bottom and the first guard which has the value true causes the function to have the value of that right-hand-side. If no guard evaluates to true, then the last right-hand-side is used.

jenny a b  
  = 42, a + b >= 100  
  = 43, a + b >= 50  
  = 44

This defines a function called jenny which takes two parameters and whose value is 42 if the sum of the parameters is 100 or greater; 43 if the sum is greater than or equal to 50 but less than 100; and 44 if the sum is less than 50.

Any function may be followed by any number of local functions, enclosed in curly braces. So jenny could be written as:

jenny a b  
  = 42, sum >= 100  
  = 43, sum >= 50  
  = 44  
{  
  sum = a + b;  
}

Note that you need a semi-colon after each local function. A local function may refer to anything in an enclosing scope, including itself.

You can write if-then-else expressions:

david a = if a < 12 then "my cat"  
  else "likes lasagne"

This is exactly equivalent to:

david a  
  = "my cat", a < 12  
  = "likes lasagne"

if-then-else expressions are sometimes easier to read than guards.

Functions application is with spaces (juxtaposition). For example:

harry = jim 2 3

defines harry to have the value 17.

All functions are curried, that is, they can accept their arguments in stages. For example:

sandro = jim 1

defines sandro, a function which takes one parameter and will add 13 to it. This trick becomes very useful with list processing, see 6.7.

nip2 has some built-in functions, see Table 6.1. They mostly take a single argument. All other functions are defined in the various standard toolkits and can be edited in the program window.




Function Description


dir any List names in scope
has_member [char] any Does class have member


name2gtype [char] Search for a GType by name
gtype2name real Return the name of a GType


error [char] Stop with error message
print any Convert to string
expand [char] Expand environment variables in string
search [char] Search for a file
_ [char] Translate string


is_image any Test for image
is_bool any Test for boolean
is_real any Test for real
is_class any Test for class
is_char any Test for char
is_list any Test for list
is_complex any Test for complex
is_instanceof [char] any Test for instance of class


re image/complex/class Extract real part of complex
im image/complex/class Extract imaginary part of complex
hd list Extract head of list
tl list Extract tail of list
sin image/number/class Sine
cos image/number/class Cosine
tan image/number/class Tangent
asin image/number/class Arc sine
acos image/number/class Arc cosine
atan image/number/class Arc tangent
log image/number/class Natural log
log10 image/number/class Base 10 log
exp image/number/class e to the power
exp10 image/number/class10 to the power
ceil image/number/class Round up
floor image/number/class Round down
gammq real real Normalised incomplete Gamma function


vips_image [char] Load image from file
read [char] Load file as a string



Table 6.1: nip2 built in functions


nip2-8.7.1/doc/html/nipguidese18.html0000644000175000017500000000467413414613100014230 00000000000000 Math

5.5 Math

Basic maths operations on any combination of any objects. You can add a slider to a matrix, for example, then divide by an image. Hopefully most of these are obvious.

Arithmetic / Absolute Value Vector
The absolute value item normally calculates mod of each band of an image separately. By contrast, Absolute Value Vector treats each pixel as a vector and calculates the modulus of that.
List
These aren’t really maths operations, but they’re in here too.

nip2-8.7.1/doc/html/nipguidese25.html0000644000175000017500000000544013414613100014216 00000000000000 Naming conventions

6.4 Naming conventions

You can name things in any way you like, but we’ve used the following conventions.

  • Classes start with a capital letter, words are separated with underscores, subsequent words are not capitalised (eg. Image_file)
  • Private names are prefixed with underscores (and are hidden by most of the user interface)
  • Functions from the VIPS library are prefixed with im_
  • Global utility functions (eg. map), public members (eg. Colour.colour_space) are all lower case, words are separated with underscores, subsequent words are not capitalised
  • Constants are capitalised (eg. Operator_type.COMPOUND_REWRAP)

nip2-8.7.1/doc/html/nipguidese8.html0000644000175000017500000000712713414613100014143 00000000000000 Printing

3.5 Printing

Once you have assembled a good reflectogram, you will want to print it, or to use it in other computer programs. The best way to do this is to save the final image in TIFF or JPEG format, and then load it into the new application — see 4.2.

There are a couple of points to bear in mind: first, like any image, reflectograms look best on paper if you sharpen them up a little first. Click on Filter / Convolution / Custom Convolution, right click on the matrix button, select Replace from file. Double Click on the second or lower data directory listed in the left hand column to enter nip2’s main data directory. Change the Image type select / option to All FIles (*) and then select and load rachel.con. This will usually produce an approprioatly sharpened reflectogram.

Secondly, you will need to try several prints with different contrasts and brightnesses to get a good match between the paper and the screen, try Image / Levels / Linear. You may even want to fiddle with the gamma, try Image / Levels / Power.

Finally, you may not need a full resolution image. For almost all printers there’s no point going over about 300 dpi (dots per inch), or about 3000 by 2000 pixels for an A4 page. To reduce the size of an image, use one of the functions listed under Resize / Transform / Resize.

nip2-8.7.1/doc/html/nipguidese15.html0000644000175000017500000002052613414613100014217 00000000000000 Filter

5.2 Filter

This menu groups operations which filter images, or which are filters in the photoshop sense.

Convolution
This menu has several standard convolution operations (blur, sharpen, edge detect, etc.), plus the option to convolve with a custom kernel.

Two menu items are slightly more complicated. Unsharp Mask transforms to CIE LAB colour space, then sharpens just the L band with a cored unsharp filter. The Tasks / Print menu has a version of this filter tuned for typical inkjet printers.

Custom Blur builds and applies a square or gaussian convolution kernel for you based on a radius setting.

Rank
A preset median filter, and a custom rank filter that lets you specify window size and rank.

The Image Rank item does pixel-wise ranking of a set of images.

Morphology
These menu items implement basic morphological operations. Images are zero for background and non-zero (usually 255) for object. Matricies are shown as 0, 1 and * for background, object and don’t-care.

The Threshold item does a simple level threshold. Use the Math / Relational menu to construct more complex image binarisations. Use Math / Boolean to combine morphologies.

The first half of the menu lists simple erode and dilate operations, 4- and 8-way connected. The second half contains several useful compound filters.

See also Histogram / Find Profile for something that can search an image for object edges. And MathStatistics / Edges can count the number of edges across and down an image.

Fourier
A selection of ideal, Gaussian and Butterworth Fourier space filters.

You can make other mask shapes yourself using the Image / Make Patterns menus, then apply them using Math / Fourier. You can also use the image paintbox to directly paint out peaks in a fourier-space image before transforming back to real space.

Enhance
A selection of simple image enhancement filters. Statistical Difference passes a window over an image and tries to match the region statistics at each point to a target mean and deviation.
Spatial Correlation
Place a small image at every possible position in a big image and calculate the correlation at each position. Simple Difference is the much faster unnormalised version.
GREYCstoration
VIPS includes a copy of the CImg library and you can use two useful CImg operations from this menu: denoising and enlarging.
Tilt Brightness
A selection of tools for adjusting the brightness of an image across it’s surface. Useful for correcting lighting problems.
Blend
Blend two objects together using either a third object to control the blend at each point, or a slider to set all points together. You can blend almost anything with anything.

One useful version is to use a text image (see Image / Make Patterns / Text) to blend between two colours (see Colour / New).

Along Line does a left/right or top/bottom fade between two images.

Overlay
Make a colour overlay of two monochrome images. Useful with Image / Transform / for testing image superposition.
Colourize
Use a colour image to tint a monochrome image. Useful in conjunction with Image / Transform / .
Browse
Look at either the bits or the bands of an image.
Photographic Negative and friends
A small selection of simple, faintly photoshop-style filters.

nip2-8.7.1/doc/html/nipguidese36.html0000644000175000017500000000754713414613100014232 00000000000000 Calling VIPS functions

6.15 Calling VIPS functions

You can call any VIPS operation which has the following properties:

  • There must be at least 1 output argument. If there’s a single output argument, that becomes the value of the function. If there is more than one output, then the function returns a list with the outputs as members.
  • The output arguments must all be one of:
    • IM_TYPE_DOUBLE,
    • IM_TYPE_INT,
    • IM_TYPE_COMPLEX,
    • IM_TYPE_STRING,
    • IM_TYPE_IMAGE,
    • IM_TYPE_DOUBLEVEC,
    • IM_TYPE_DMASK,
    • IM_TYPE_IMASK
  • The input arguments must all be one of the types above, or IM_TYPE_DISPLAY. If an argument is an input display, nip2 passes in its current display structure, it does not take a display from your program.

When nip2 starts up, it loads any VIPS plug ins it can find on its data search path. You can call functions from plug ins in just the same way. For information on writing plug ins, see the VIPS Manual.

nip2-8.7.1/doc/html/nipguidese21.html0000644000175000017500000002257113414613100014216 00000000000000 Tasks

5.8 Tasks

This menu repeats many items from other menus, but tries to group them by tasks they are useful for, rather than by function.

5.8.1 Capture

This menu groups operations which are useful in capturing images, or for the initial processing you might want to do to an image captured from another program.

CSV Import
Import an image from a CSV file, with a few controls.
Interpret Analyze 7 Header
Read the meta fields for volume layout and calibration from the Analyze header and reformat the image appropriately.
Capture Video Frame
This menu item will currently only work on Linux machines with a compatible video4linux capture card. See 3.1.1 for notes on how it works.
Smooth
Use this to remove texture from images. It’s handy in conjunction with Flatfield.
Flatfield
Use this to correct homogeneity. Select an image of a piece of white (or mid-grey) card, then select the image to correct, then click Flatfield. Use Smooth to renmove texture from the white card if necessary.

You can select a single white and a group of images to correct a large set in one step

White Balance
Use this to move the white point to make an area of the image you know to be white, white. Mark a region on an image, enclosing a patch you know to be white. Select the region and the image and click on White Balance.
Find Colour Calibration
Use this to colour calibrate an image. Drag a region enclosing an image of a Macbeth Color Checker Chart and click Find Colour Calibration.
Apply Colour Calibration
Use this to apply the transform calculated by the previous item to another image. Select the calibration object, select the RGB image you want calibrated, and click Apply Colour Calibration.

5.8.2 Mosaic

The items in this menu are discussed in appalling detail in Chapter 3.

One Point
Join two images left-right or top-bottom with a simple translation. Mark a point on each image to be joined (open image view window, Ctrl-left-click, drag to position), then click on the mosaic button. The operation performs elaborate tie-point adjustment, so your selection of a common feature does not have to be exact.

The Manual versions do not perform automatic tie-point correction and are useful when joing very difficult images.

Two Point
Do a join, but allow the right-hand (or bottom) image to rotate and scale if it will improve the match. You need to pick two points on each image.
Balance
Break a mosaic apart, examine average pixel value in the overlap regions, adjust brightness to match, and reassemble. This only works for images which have been produced just by mosaic joins! If you’ve done anything else to the image since loading it, the balance will fail with a mysterious message.
Manual Balance
Adjust the brightness in a set of masked areas to match. Useful for removing shadows.
Rebuild
Use this to mosaic up one set of files based on joins you made in another. Breaks a mosaic part to component files, performs a string substitution on the file names, and reassembles.
Clone Area
Select over- or under-exposed pixels in one image and replace them with the corresponding pixels from another image. Useful for removing lead numbers used to identify X-ray plates.

The function operates on two 8-bit mono images. Move and resize the region on the first image to define the area around the white number. Move the region on the second to overlapping area. A section of the area on the second image is cloned and blended into the first image. The amount of the defined area to be cloned in defined by a slider within the output image.

5.8.3 Picture Frame

Items useful for mocking up painting frames.

5.8.4 Print

Items useful while preparing an image for printing.

Sharpen
Sharpen an image for printing. This is a version of Filter / Convolution / Unsharp Mask tuned for typical inkjet printers.
Adjust Tone Curve
Adjust the reproduction tone curve in LAB. Most useful for offset work, especially from transparencies.

nip2-8.7.1/doc/html/nipguideli3.html0000644000175000017500000000611713414613100014131 00000000000000 List of Tables

List of Tables

    

    

nip2-8.7.1/doc/html/nipguide37.html0000644000175000017500000000236113414613100013670 00000000000000

1Since programs are referentially transparent (that is, the value of an expression depends only upon its syntactic context, not upon computation history), you can easily do equational reasoning, proof by induction, and so on.

Expressions are like theorems, definitions are like axioms, computation is like proof.

nip2-8.7.1/doc/html/nipguidech3.html0000644000175000017500000000700213414613100014111 00000000000000 3 Assembling infrared mosaics

Chapter 3
Assembling infrared mosaics

VIPS has a package of functions designed to help join many small images together to make a single large image. They were originally designed to assemble infrared reflectograms but are general enough to be useful for other sorts of image as well, such as X-rays.

This chapter first introduces the mechanics of infrared imaging then explains how to use nip2 to assemble the images you grab. Finally, it suggests some printing techniques.

nip2-8.7.1/doc/html/nipguidese17.html0000644000175000017500000001665313414613100014227 00000000000000 Image

5.4 Image

This menu groups operations which apply only to images.

New
Makes a new image. Region on Image makes a new region, arrow, guide or mark on an image. It’s usually easier to open a viewer on an image and Ctrl-drag.
Convert to Image
Try to make an image out of anything.
Format
Switch between the various precisions.
Header
Try to change or examine the image header in various ways.
Cache
This caches an image in RAM. Use this to save the results of a long computation.
Levels
Various tools that change the levels in an image. Tone Curve is the only complex one: it lets you adjust the image levels with a set of sliders.
Transform
Various tools that change the geometry of an image.

To use Rotate / Straighten, mark an arrow on an image (Ctrl-drag up and left in an image view window) along a near-horizontal or near-vertical edge. When you click on Rotate / Straighten, nip2 will rotate the image by the smallest amount that makes that edge exactly horizontal or vertical.

Linear Match takes two images and rotates and scales the second so that the images can be superimposed. Drag the tie-=points to mark common features. Use Filter / Overlay or Filter / Colourize to actually superimpose them.

Rubber Sheet is useful for fixing things like lens distortion. You give Find two images, a reference and a distorted version of that reference, and it automatically finds a transform which will map the distorted image back on to the reference image. Use Apply to apply the discovered transform to another image.

Band
Extract/insert/delete image bands. Use To Dimension to change image bands into a horizontal or vertical dimension. Use To Bands to compress the horizontal or vertical dimension into bands (small images only!).
Crop
Crops an image. It’s often easier to drag out a region. This menu item is only really useful for cropping large groups of images.
Insert
This takes two images and pastes the smaller into the centre of the larger. The two images have to have the same number of bands. If you open an image viewer on the large image, you’ll see an area which you can drag around to set the exact insert point.
Select
Draw elipses and polygons on an image. Useful for selecting defined areas.
Join
Use to join two images together bandwise, left/right or up/down. Array joins a list of lists of images together into a single large image.
Tile
Repeat an image horizontally and vertically to make a larger image, or chop an image into a set of tiles.
Patterns
These items all make useful images for you, from checkerboards to gaussian masks. XY Image is the most useful: you can use it to build other patterns.
Test Images
These items make a variety of useful testcharts for evaluating spatial response and colour.

nip2-8.7.1/doc/html/nipguidese10.html0000644000175000017500000001203213414613100014203 00000000000000 File select dialogs

4.2 File select dialogs

On most platforms you can drag files from your file manager directly to nip2’s main window. Alternatively, if you select File / Open in the main window, nip2 will pop up a file dialog, see Figure 4.4. The open dialog has the following extra features:


PIC


Figure 4.4: Open dialog


Pin up button
Normally the file dialog closes after you have opened something. If this item is checked, the dialog will stay up instead — this is useful if you want to load or save a series of objects.
Image type select
Use this menu to select the type of file you want nip2 to display. There’s a preference option to set the default image format. The VIPS file format is fast and accurate, but sadly not very widely supported (joke). You can also load and save images in TIFF, JPEG, PNG, HDR, CSV and PBM/PGM/PPM formats. You can usually load in many more formats, it depends how your nip2 has been configured.
Image info
This displays a one-line summary of the selected image, plus a large thumbnail.

The save dialog adds one extra feature: Increment filename.

If pin up and increment are both selected, then after a save nip2 will attempt to add one to the selected file name. For example, if you save a file called fred001.v, after the save nip2 will put the name fred002.v into the selected file name box. Again, this is useful if you want to save a series of images.

nip2-8.7.1/doc/html/nipguidese5.html0000644000175000017500000001210413414613100014127 00000000000000 Assembling the mosaic

3.2 Assembling the mosaic

The tutorial has a section on mosaic assembly with nip2: see 2.2.

Mosaic assembly is normally painless. There are a few factors you should bear in mind when you are deciding how to assemble an image (particularly a large image):

  • You can open up a mosaic join and change a few options, such as the blend width. If you want to change the defaults for a whole workspace, change the Mosaic defaults options in your Preferences.
  • If two images just won’t join correctly, try using Tasks / Mosaic / One Point / Manual Left to Right instead. These functions operate in the same way as the usual mosaic functions, but do not do a search. This is useful when the overlap is too small for the search to work correctly, or when the overlap area is very smooth and contains too few features for the search to find the exact overlap for you.
  • nip2 does not do sub-pixel interpolation. As a result, each join will on average cause a positioning error of about 0.5 pixels, even if your input images contain no geometric distortion. If there are distortions in your input images (there usually are distortions in infrared images), then errors can be as much as 1–2 pixels per join. These errors accumulate as the number of images you join becomes larger.

    If you join a strip of 10 images together with Tasks / Mosaic / One Point / Left to Right, on average you can expect a total error of about 5 pixels. If you join two strips like this together top-bottom, you can therefore expect a mismatch of about 2.5 pixels at each end of the join.

    You can minimise the effect of these errors if you assemble your images differently. Suppose you have a 10 by 10 mosaic to build. Instead of making and joining 10 strips of 10 images each, make four 5 by 5 sub-mosaics (one for each quadrant) and then join these four quadrants together. The errors will now be more evenly spread over the image and therefore will be less visible.

  • Some operating systems limit the number of files a program can have open at once: this in turn limits the size of the mosaics you can assemble in one go. If you are having problems putting together very large mosaics, try building your image in sections (top, middle and bottom, perhaps), and later load up and join these larger pieces.

nip2-8.7.1/doc/html/nipguidese7.html0000644000175000017500000000607113414613100014137 00000000000000 Other nip2 features useful for reflectograms

3.4 Other nip2 features useful for reflectograms

You can use nip2’s general image processing facilities to play around with reflectogram mosaics. You can make false-colour images of your reflectograms, blend them with visible images or X-rays, search them for edges, and so on see the registering and overlays_and_blending examples for ideas.

There are also some first order mosaic functions: Tasks / Mosaic / Two Points / Left to Right and Tasks / Mosaic / Two Points / Top to Bottom. These functions automatically rotate and scale the right-hand image in a join. They are useful for assembling X-ray mosaics, and for fixing very difficult joins in reflectogram images. These functions work the same way as the One Point functions except that you will need to define two tie-points on each image.

You can mosaic images of any numeric type: 16-bit integer images are handy for mosaicing X-ray images, for example.

nip2-8.7.1/doc/html/nipguidese6.html0000644000175000017500000001127513414613100014140 00000000000000 Balancing the mosaic

3.3 Balancing the mosaic

Like assembly, mosaic balancing is normally automatic and painless. You may sometimes have problems if the image is very large, or needs dramatic corrections:

  • Each VIPS image file has an associated history, recording the operations on that image since it was loaded from a file. You can view an image’s history by clicking on View / Image header in an image view window.

    The automatic balancer uses the history to work out how you built your mosaic. The balancer knows about left-right and top-bottom joins, but nothing else! If the history has other stuff recorded in there, you’ll see unhelpful error messages like unable to open tmp/xxx.v, or more than one root.

    If you need to perform corrections to any of your sub-images, do them, save the image, load it again, and then build the mosaic. This will make sure the history of the image you are trying to balance only contains mosaic operations.

  • On some systems the balancer can run out of memory or out of file descriptors on very large mosaics. If your mosaic is made up of more than a few hundred images, and you are having balancing problems you may have hit one of these limits.

    The solution (as with mosaic assembly) is to assemble and balance your mosaic in smaller pieces.

  • If your grey-card correction is not accurate, you will find that the balancer will magnify any problems you have.

    Suppose your lighting and camera set-up always produces images which are brighter on the right than the left, and suppose, due to some problem with your grey-card correction, this effect is not completely removed. You will find that when you balance a mosaic, the small differences between left and right edges of your sub-images will have been smoothed out, but they will have caused a large difference in brightness between the extreme left edge of your final image and the extreme right.

    nip2 includes several functions which can help to fix this problem, the most commonly used being: Tasks / Mosaic / Tilt Brightness / Left to Right and Tasks / Mosaic / Tilt Brightness / Top to Bottom.

nip2-8.7.1/doc/html/nipguidese3.html0000644000175000017500000006054513414613100014141 00000000000000 nip2 for nerds

2.3 nip2 for nerds

This section sprints through a bit of nip2 programming, see 6 for full details and a more formal definition of the language.

The insides of nip2 are built with nip2’s own programming language. It’s a pure lazy functional language with classes. It’s C’s expression syntax (more or less) plus approximately Miranda/Haskell function syntax, plus some basic class stuff. nip2’s main window is a class browser for this programming language.

Click on Toolkits / Edit Toolkits in nip2’s main window to pop up the programming window (see 4.4 for details on all the bits in the window), then in the edit area there type:

// add two things  
 
Fred a b = class {  
  sum = a + b;  
}

This defines a class called Fred whose constructor takes two arguments, a and b. There’s one member, called sum, which is a and b added together.

In the program window, click File / Process. This makes nip2 read what you typed, parse it, compile it and update itself. The program window should now look like Figure 2.11.


PIC


Figure 2.11: Programming Fred


If you look back at the main nip2 window, a new menu will have appeared under Toolkits called untitled. If you click on that, there will be a menu item called Fred. Let your mouse linger, and you’ll see a tooltip too.

In the main window, type Fred 2 3 into the box at the bottom of the current column. Press Return and nip2 will make a Fred for you. Click on the down arrow to the left of your new Fred once to see the members of Fred (just sum in this case), click again to see the class parameters too. The main window should look like Figure 2.12.


PIC


Figure 2.12: Main window Fred


Click to the right of b, type in a new value and press Return. The sum member should update. nip2 keeps track of dependencies between rows, but it also tracks dependencies inside rows, both ones that come from the class, and ones created by any edits you do to the class instance after creating it. You won’t see it in a simple example, but nip2 also discovers and tracks dependencies which can arise at run time. Click on the text just to the right of the b button again, type a and press Return. Now edit a: press Return and both b and sum will update.

You can use Fred to add any two things together. Click on Toolkits / Widgets / Scale to make a scale widget, press Ctrl-U (the keyboard shortcut for Edit / Duplicate) to duplicate it, and finally click on Toolkits / untitled / Fred. Open up the new Fred and try dragging some of the scales around. The main window will look like Figure 2.13.


PIC


Figure 2.13: Scale Fred


The scales are classes too (instances of Scale). You can open them up and do strange things with them as well. Open up one of the scales you made (eg. A2 in Figure 2.13) and change the from parameter to be A3.value. Now try dragging the sliders again.

Try dragging the sum slider. Now go back and drag one of the original sliders. You’ll see that sum no longer updates, it’s stuck at the last position you dragged it to. This is because there are now two things affecting the value of sum: the underlying code (the a + b inside Fred), and the position you dragged the slider representing sum to. nip2 has the rule that graphical edits (dragging the slider) override code. To make sum update again, right click on the sum button and select Reset from the pop up menu. Now drag one of the input sliders again, and sum will start updating once more.

Classes can inherit from other classes. Go back to the program window, click on File / New / Tool to clear the edit window, and type:

// multiply two things  
 
Jim a b = class Fred a b {  
  product = a ⋆ b;  
}

This defines a class called Jim which inherits from Fred. Click File / Process, then back in the main window, type Jim 4 5 into the bottom of the column. Click down once to expose the members (just product), click again to expose the parameters as well (a and b), and click a third time to expose the superclass member (which should be an instance of Fred). You can also open up the super member and see inside the Fred that this Jim is using as its superclass. A5 will respond to both product and sum. See Figure 2.14.


PIC


Figure 2.14: Browsing Jim


nip2 has about 20 different graphical classes like Scale. Whenever a row takes a new value, nip2 checks to see if that value is an instance of one of these special classes, and if it is, it will add a graphical element to the row display which represents that class’s value. It builds the graphical part by looking inside the class for certain members (for example, the scale graphic looks for members called from, to and value). When you change the graphic (maybe by dragging the scale), nip2 rebuilds the class by looking inside for a edit member (eg. Scale_edit) or if that’s not defined, a constructor member (eg. Scale).

You can make your own graphic widgets by subclassing nip2’s built-in ones. By selectively overriding default constructors and adding edit members, you can control how your new widget will behave in expressions, and how it will behave if it’s edited graphically.

Make a new column, load up an image (use File / Open), open an image viewer (double-click on the thumbnail), drag out two regions on it (hold down Ctrl and the left mouse button and drag down and right). Your main window should look like Figure 2.15.


PIC


Figure 2.15: Two more regions


im_insert is a VIPS operation that puts one image inside another at an (x, y) position. VIPS operations work on VIPS images. The value member of an Image or Region is the VIPS image that underlies the nip2 row.

You can use im_insert to make a thing to join two images together. Back in the program window, click on File / New / Tool and enter:

// join two images left-right  
 
Join a b = class Image value {  
  shim = Scale "Spacing" 0 1000 0;  
  value = im_insert a.value b.value  
    (a.width + shim.value) 0;  
}

Click File / Process. This defines a class Join which subclasses the Image graphic.

Now select your two regions (click on the first one, shift-click on the second) and click on Toolkits / untitled / Join. Alternatively, just click Join and it’ll be given the borrom two items in the column. A new Join row will appear. Open it up and drag the slider to set the spacing between the two joined images. Go back to the image viewer for the image file you loaded and try dragging one of the regions. Figure 2.16 shows this class in action. The thing in Toolkits / Image / Join / Left to Right is just a slightly fancier version of this.


PIC


Figure 2.16: Joining two images with Join


You can change how the graphic widgets behave by subclassing them. Try:

Scale_int c f t v = class  
  scope.Scale c f t ((int) v) {  
  Scale = Scale_int;  
}

This defines a new scale class called Scale_int which can only take integer values. The Scale = Scale_int; line is Scale_int overriding Scale’s constructor, so that a Scale_int stays a Scale_int when you drag. Because there’s a local called Scale, Scale_int needs to use scope.Scale to refer to the superclass.

Here’s a version of Mark which can only be dragged in a circle. You pass it an image to display on, an xy centre position, a radius and a start angle.

Mark_circle image x y r a = class  
  scope.Mark image _x' _y' {  
  // get rect cods for our point  
  _pos = (x, y) + rectangular (r, a);  
  _x' = re _pos;  
  _y' = im _pos;  
 
  Mark i l t  
    = this.Mark_circle i x y r a'  
  {  
    // vector from centre of  
    // circle to new position  
    u = (l, t) - (x, y);  
 
    // angle of vector  
    a' = im (polar u);  
  }  
}

nip2-8.7.1/doc/html/nipguidese31.html0000644000175000017500000004442513414613100014221 00000000000000 The standard libraries

6.10 The standard libraries

nip2 comes with a lot of little utility functions. The functions for list processing are listed in Table 6.3. There are a huge number more, too many to really list here. Table 6.4 lists all the utility toolkits with some hints about the kinds of function they contain. Read the (heavily commented) toolkits for details.





Toolkit Contains Description



_convert parse_int l, … convert ascii text to numbers
to_matrix x, … convert anything into a matrix
colour_transform_to to x, … convert between colour spaces



_generate image_new w h ... make a blank image
image_white i look at image i, try to guess what white is
make_xy w h make an image of size w by h whose pixel value are
their coordinates



_types Image i all the standard classes and support functions,
see 6.13



_predicateis_colour_space i test for objects are in various categories or have
various properties



_stdenv logical_and x, … function versions of all the operators
bandsplit i, … break up and recombine images by band
mean x, … statistical ops on objects
transpose x, flipud x, rot90 x, …flips, rotates, etc. on objects
rad x, pi, … trigonometry stuff
sign x, conj x, polar x, … complex stuff
rint x, ceil x, … various rounding things
fwfft x, … fourier stuff
dilate m x, rank w h n i, … morphology stuff
conv m x, … convolution stuff
image_set_type t i, … set various image header field
resize x y i, … resampling images
recomb m i, … recombinations
clip2fmt f i, … format conversions
hist_find m x, … histogram stuff
id x, const x y, … various useful operations on functions
map_binary fn x y, … mapping over groups




Table 6.4: Useful utility functions — see the source for details


nip2-8.7.1/doc/html/nipguidese1.html0000644000175000017500000006753313414613100014143 00000000000000 Quick interface tour

2.1 Quick interface tour

Start up nip2. You should see something like Figure 1.1 (the exact look might be different on your system).

The menus at the top of the window are very ordinary, except for the Toolkits menu which contains all of the image processing operations. The main part of the window shows a workspace. Workspaces are split into tabs (across the top) and each tab is made of a set of columns. The current column, where new objects appear, has a dark green bar across the top.

Click on File / Open to get a file dialog and load up an image. nip2 can load most image formats, try it and see. Check the Pin up box to have the dialog remain after you press OK. You can also drag files from the desktop or from your file manager.

After you’ve loaded an image, nip2 should look like Figure 2.1. Double click on the thumbnail to open an image view window. Alternatively, select Edit from the right-button menu on the thumbnail. See Figure 2.2.


PIC


Figure 2.1: After loading an image



PIC


Figure 2.2: Image view window


As well as the standard keymappings, nip2 has extra shortcuts for navigating images, see Table 2.1. Use the View / Toolbar menu to turn on other features. You can have a status bar (shows image properties, mouse position and pixel value), a display control bar (lets you change scale and offset for display pixels, click on the arrow on the left for a useful extra menu), a paint bar and some rulers.




Keys in image display widget Action


i, + Zoom in on mouse pointer
o, - Zoom out
Cursor up/down/left/right Scroll a small amount in direction
Shift and cursor up/down/left/rightScroll a screenful in direction
Ctrl and cursor up/down/left/right Scroll to edge of image
Middle mouse drag Pan image
Mouse wheel Scroll up/down
Shift and mouse wheel Scroll left/right
Ctrl and mouse wheel Zoom in/out
0 (zero key) Zoom out to fit image to window
1, 2, 4, 8 Set magnification to 1, 2, 4 or 8
Ctrl and 2, 4, 8 Set zoom out factor to 2, 4 or 8



Table 2.1: nip2 shortcuts for the image view window


You can mark things on an image. Hold down Ctrl and drag down and right with the left mouse button to mark a region. Ctrl-left-click to mark a point. Drag up and left to mark an arrow (two points connected by a line). Drag from the rulers to mark guides. Right-click on a label to get a menu which you can use to remove or edit one of these things. Left drag on a label to move the things around, left-drag on the edges or corners to resize. Figure 2.3 shows the same image with stuff marked on it.


PIC


Figure 2.3: Image view window with marked regions


Clean up any messing about and leave two regions on your image. The main window should now look something like Figure 2.4.


PIC


Figure 2.4: Main window, two regions marked


There are three rows visible here, A1, A4 and A7. Each row has (from left to right) a pair of up/down arrows (these indicate that the row contains sub-rows: click on the down arrow several times to open the row up and see inside), the name button (left-click to select, Shift-left-click to extend-select, Ctrl-left-click to toggle select, click on the workspace background to unselect everything, left-drag on the name button to reorder items within the column, right-click to get a context menu) and the thumbnail image.

Left-click on the name button of one of these images to select it, and then click on Toolkits / Image / Transform / Rotate / Free (alternatively, if nothing is selected when you click on one of the toolkit menus, nip2 will apply the operation to the bottom object in the current column). A new row will appear representing the rotation operation. Drag the slider to rotate the image (or type an angle in degrees into the box to the left of the slider and press Return). Pick an interpolation type from the option menu and zoom in on some pixels to check the result. See Figure 2.5.


PIC


Figure 2.5: Using Rotate / Free


The same thing works for image processing operations that take two arguments. Left-click on one of your original regions, Ctrl-left-click on the rotated image (the box at the left of the main window status bar says what’s selected and in what order), and click on Toolkits / Image / Join / Left to Right. A new row appears representing the join operation.

Click on Background Colour, type in 128 and press Return. Drag the shim slider to 50 (or type 50 into the box just to the left of the slider and press Return). See Figure 2.6.


PIC


Figure 2.6: Using Join / Left to Right


The Toolkits menu is large and can be slow and annoying to find things in, so nip2 has several shortcuts. First, you can tear-off menus by clicking on the dotted line at the top. If you’re going to be using one of the sub-menus repeatedly this can save a lot of clicking. Next, you can set keyboard shortcuts for menu items by moving the mouse pointer over the item and pressing the key combination you want to set.

Some systems won’t let you edit menu shortcuts by default. For example, on GNOME, you need to enable this in System / Preferences / Menus & Toolbars.

Finally, there is a toolkit browser: this shows the same set of items, but in an easier-to-browse way. Click on View / Toolkit Browser and the browse side-panel will appear, see Figure 2.7. It shows all of the items as a single long list. Type into the search box at the top to only show items which match. Double-click (or press Return) on an item to activate it. Scroll to the right to see what arguments the item needs and what menu it appears in.


PIC


Figure 2.7: The toolkit browser


The box at the bottom of each column is for entering new expressions. You can type stuff here, and nip2 will make a new row for each item you enter. Try typing 2 + 2 and pressing Return. The syntax is (almost, with a few small differences) the same as the C programming language. See 6.6 for a list of the differences. Try multiplying the joined images by a small amount (eg. type something like A9 * 1.2 and press Return). Normally nip2 will pick names for new objects for you (like A1), but you can set a name yourself if you like. Try entering fred = 12.

Click the down button once on your brightened image and left-click on the area just below the thumbnail. You should see the stuff you typed to make that row. You can edit it to be anything else, press Return and nip2 will recalculate. Try going back to your original image (the one you loaded from a file), open an image view window, and try dragging one of the regions. You can change any of the sliders in the rotate or the join rows as well.

Right-click on a thumbnail for a useful menu. Use Save As to save an image to a file. Use Replace From File to change the image in a row (and recalculate the rest of your workspace, very handy). Use Header to view an image’s metadata.

You can also edit the insides of objects. Click the down button next to one of your regions until the width and height rows appear, click on width and type height * 2. Now open the image window the region is defined on and try to resize it: you’ll find that the width of the region is fixed, but that if you change the height, the width changes with it. This is a very general property of classes in nip2: you can use it to join objects together in complex ways, and to modify the behaviour of interactive objects.

Right click on a column title bar to get a useful menu. Click on File / New / Column make another column (handy for organising a workspace). If you drag from an image thumbnail on to the workspace background, nip2 will make a new column for you. You can drop thumbnails on to other thumbnails to make links.

There’s a useful right-click menu on the tab name. Duplicating tabs is a very easy way to try something out: make a copy of your tab, try changing something, if it doesn’t work out, just delete your new tab and go back to where you were. You can drag tabs between workspaces, and you can drag a tab to the desktop to make a new workspace. You can make references between tabs with thetab name and a dot, for example tab1.A1. You can save columns, tabs or workspaces to workspace files, then merge them back into a colum, as part of a tab, or as a new tab.

If nip2 falls over (I do hope it doesn’t), you can usually get your work back by restarting nip2 and clicking on File / Search for Workspace Backups. There are a lot of preferences (perhaps too many), see Appendix A.

There is a lot of stuff in the Toolkits menus, but they do almost all have tooltips. If you let your mouse hover over a menu item for a moment you should get some helpful text. The toolkit menu is organised by object type. If you want to do something to a matrix, look in the Toolkits / Matrix menu. The exception is Toolkits / Tasks which repeats many of the regular toolkit items, but groups them by typical tasks instead.

Operations can work on groups as well as on single images, so you can batch things up. If you save a group of images, nip2 will number each image sequentially for you. You can use Edit / Duplicate to make copies of objects. If you select lots of objects and duplicate them, nip2 will (fairly intelligently) rename everything for you so it all still works.

nip2-8.7.1/doc/html/nipguidese4.html0000644000175000017500000005415413414613100014141 00000000000000 Infrared imaging

3.1 Infrared imaging

Most museums use tube cameras (usually called Vidicons) for infrared imaging. Although they are relatively cheap they are not very stable and they suffer from (sometimes quite severe) geometric distortions. More modern solid-state cameras are still expensive but are becoming more widely used because of their greater stability. This guide assumes you are using a tube camera but almost all of it applies to solid-state cameras as well.

Whatever your camera there are three main sources of error which have to be addressed in order to be able to make successful mosaics:

  1. Tube cameras suffer very badly from distortions in the image, usually either ‘pin-cushioning’ or ‘barrelling’. These distortions result in alignment errors when sub-images are joined together.
  2. The sensitivity of the tube varies across its surface, causing some parts of each sub-image to be brighter than others. This is made worse by unavoidable variations in illumination. When a lot of such images are joined together the result is a ‘brick wall’ effect.
  3. The sensitivity of the tube also varies between sub-images, partly as the overall lightness in the field of view changes, and also because the electronics in the camera change as the camera heats up. This leads to a patchy, unbalanced mosaic.

The first two problems will be different in each Vidicon and will change each time a tube is replaced. All three problems need to be addressed to create successful infrared reflectogram mosaics.

3.1.1 Setting up your system

Mechanical set-up

It is vital that the optical axis of the Vidicon is at right-angles to the picture plane and that, whether it is the Vidicon or the painting that moves during image capture, it remains perpendicular. Obviously, with a seriously warped panel, this may not be possible. The lighting should be carefully adjusted so that the area of interest is lit as evenly as possible. If you can, arrange for the lights to remain stationary with respect to the camera.

An easy way to test camera alignment is to image a piece of graph paper, move the camera (either left-right or up-down) by 90% of the field of view, and see how features in the overlap area move. First rotate the centre around the optical axis to get the centre line of the images lined up. Next check the corners and adjust camera pitch and yaw.

Video set-up

On Linux, you can capture video directly into nip2 provided that your capture card is compatible with v4l. You may need to adjust the nip2 video settings. These settings can be found under the headings Video for linux and General video capture in the Preferences window, which can be accessed by selecting Edit / Preferences from the main nip2 window. The default settings, see Figure 3.1, are for the Hauppauge PCI capture card and should be changed as required.


PIC


Figure 3.1: Recommended video preference settings


Once you have set up your card, select Tasks / Capture / Capture Video Frame to create a new video object, which will appear as a still image in your current selected column. The captured image can be updated by opening the image in a viewing window and then pressing Ctrl-C (a shortcut for File / Recalculate Image).

You can create more than one video object: this can help you to get the overlaps right if you have two open at once (one showing the previous grab) when you are moving the camera around.

Setting the crop and aspect

While it is possible to correct geometric distortions after the image is captured, it is difficult to do the necessary modelling accurately and reliably. Instead, we suggest the grabbed images should simply be cropped, since the most severe distortion affects the perimeter of each video image.

To determine the area to crop, set up the Vidicon as it would be set to image a painting and capture an image of a rectangular grid — a piece of graph paper works well as a target. Before capturing the grid, check the current video crop settings in the Preferences window and ensure that the crop is set at maximum: left 0, top 0, width 768, height 576 (these are the dimensions for a PAL signal, they may be different on your system). Also set the Aspect ratio line to 1.

Create a new video object and look for the largest rectangle with little distortion (no more than a few pixels). If you create a region on the video image (by holding down the Ctrl key and dragging down and right with the left mouse button, see ??) you can compare the straight edges of the region against the distorted lines of the grid. You can then expand and contract the region until you decide on the optimum area. The settings you need for the crop box can be taken from the values contained within the region object, which can be viewed by left-clicking several times on the down arrow to the left of the region object name.

Finally, you can set an aspect ratio: nip2 will automatically stretch video frames vertically by this factor. You can measure the aspect ratio of your capture card by taking a picture of something you know to be square and dividing the width in pixels by the height in pixels.

Move back to the Preferences window and enter the crop values in the General video capture section. Next time you create a new video object, you should find that it is cropped to the appropriate area. The settings you enter in the Preferences / window will be saved and automatically loaded again next time you start nip2. See appendix A.

Choosing the usable area of the image is a matter of compromise — the smaller the area, the more images are required to build a mosaic of a particular painting. If the area chosen is too large then the amount of distortion can cause serious errors in the final mosaic.

It’s possible to use the VIPS rubber sheet plug in to detect and correct geometric distortion in your images automatically. This lets you use the full area of the sensor. It is a bit fiddly, but see the rubber sheet documentation if you are determined.

3.1.2 Capturing the data

Setting the gain and offset

Once everything is correctly set up, position the painting in front of the camera and experiment with the gain and offset settings on the Vidicon to achieve the optimum infrared image on the computer screen. Note that the appearance of the image on the computer will normally be different to its appearance on the video monitor connected directly to the camera.

Repeat this process at different points across the whole area to be captured. Although it is not always possible, the aim is to find a setting that does not need altering much during the capture of the data. This seems to lead to more successful mosaics.

Grey card correction

To counteract the problem of uneven sensitivity across the target area of the tube, it is necessary to capture an image of a piece of grey card. This grey card image is then used to correct all subsequent images. The card should be a flat, even grey, of around 50% reflectance. The Vidicon and lighting positions with respect to the painting should not be changed between the imaging of the grey card and the capturing of the mosaic. A grey card can be captured at any time, but it is good practice to start with one — you may forget later.

If your mosaic will take several hours to capture, you may wish to grab extra grey cards, since the sensitivity of the tube can change as it warms up. Be sure to note which data images correspond to which grey cards!

In association with the first grey card, it is a good idea to grab an image of your grid to record the scale at which the data images are being made.

Image capture

Open a video window, Tasks / Capture / Capture Video Frame, and when it shows the desired area, save the file. The choice of file name is a question of personal preference. We find it helpful to use a format that indicates where in the mosaic the data comes from — for example, dat3.5.v for the fifth image in row three.

It is helpful to be able to see the previous image to ensure that there is sufficient overlap. To achieve this, a second video window can be opened and placed alongside and the images grabbed into alternate windows.

Capture tips
  • Make a new directory for each painting, and keep all of the image files for that painting (including a grey card and a grid) in that directory.
  • VIPS can join up images in any layout, but you will get much less confused when you assemble your images if you stick to a regular grid. This can be difficult — a good compromise is to keep one axis fixed and grab in rows (or columns).
  • You can help to reduce mosaicing errors later if you keep your rows (or columns) as short as possible. So if the painting is in landscape format, grab in columns (or turn the painting on its side and grab in rows); if the painting is portrait, grab in rows (or turn the painting on its side and grab in columns).
  • The semi-automatic mosaic functions (see 3.2) need a minimum overlap between the sub-images they join of around 20 pixels. For safety, you should aim for a larger overlap than this: we recommend an overlap of 60 pixels (around 20mm, usually).
  • If the overlap area is featureless, it is worth identifying a good tie-point and ensuring it is visible in both images, even if this means increasing the overlap for one of the joins.

3.1.3 Correcting illumination

Before the mosaic can be assembled, the data images need to be corrected for non-uniformity of illumination using the grey card image. This function can be performed within nip2 or directly using a predefined VIPS command-line tool.

3.1.4 Correcting with the command-line tool

First, close nip2 and open a command line window, (xterm, mingw, etc). Move to the directory containing your image files with cd. For example, if you have made a directory called raphael inside your home directory, type:

prompt% cd raphael

The program you need to use is called light_correct. You need to give it the name of the grey-card image and the names of all of the image files you want it to correct with that gray card. Suppose you have saved your gray card image as grey.v, and your painting image files are called dat1.1.v and dat1.2.v. You would then enter:

prompt% light_correct grey.v dat1.1.v dat1.2.v

The program will run and print messages explaining its progress. It creates a new set of corrected image files, with the same names as before, but prefixed with ic_. In this example, it would create two new images files called ic_dat1.1.v and ic_dat1.2.v.

If there are a lot of image files to correct this could mean a lot of typing. Fortunately, you can use wildcard characters to abbreviate lists of file names. The example above can be abbreviated to:

prompt% light_correct grey.v dat⋆.v

The dat*.v means ‘any filename which starts dat and ends with .v’.

You can use this technique to correct different parts of your mosaic with different grey cards. If you have a file called grey1.v for the first row in your mosaic, and a file called grey2.v for the second, you could do the correction in two parts:

prompt% light_correct grey1.v dat1.⋆.v \\  
prompt% light_correct grey2.v dat2.⋆.v

3.1.5 Correcting within nip2

The function within nip2 used to preform this correction is Tasks / Capture / Flatfield. A set of images can be corrected at the same time by joining them together in a Group. A group can be produced by selecting all of the required images and then using the Edit / Group command.

Load all of your images into nip2, and group all the image except the grey image. Select your grey image and then your new group and then run the Tasks / Capture / Flatfield function. This will produce you a group of corrected images. Right-click on this new group and select Save As from the menu. In the save window type in a name, for example fred_01.v and then hit the save button. All of the images in your group will then be saved as fred_01.v, fred_02.v, fred_03.v fred_n.v.

If you want to keep row numbers in your file names, (see 3.1.2), you will need to correct your images one row at a time, saving each row as fred01_01.v, fred02_01.v, etc.

nip2-8.7.1/doc/html/nipguidese20.html0000644000175000017500000000560713414613100014216 00000000000000 Object

5.7 Object

This groups a few items which had no obvious home and which change the format of objects.

Duplicate
Copy an object, stripping off any derived classes. For images, this really takes a copy of the underlying object (using im_copy()).
List to Group
Changes lists (see Math / List) into Groups (see Edit / Group) and back. A list os an ordered collection of objects. A group is a list that nip2 will automatically iterate over.
Break Up Object
This tries to take an object apart. So a multi-band image becomes a list of 1-band images. A matrix becomes a list of vectors, and so on. Assemble Object is the inverse.

nip2-8.7.1/doc/html/nipguidese2.html0000644000175000017500000002526513414613100014140 00000000000000 nip2 for reflectogram mosaics

2.2 nip2 for reflectogram mosaics

This section quickly builds an infrared reflectogram mosaic using the sample images that come with nip2. See Chapter 3 for detailed coverage.

Click on File / Open Examples. You should see a directory called 1_point_mosaic. Doubleclick and you’ll see a file called 1pt_mosaic.ws. Doubleclick that and you’ll load the workspace for this example.

If you’d rather make the workspace yourself, click on the file type filter and select All files. A set of 8 images should appear. Click on the first file, shift-click on the last, and click Open. This will create a group of all eight images. Right-click on the row and select Ungroup to unpack to a set of rows. See Figure 2.8.


PIC


Figure 2.8: Loading the sample images


The images have been named to match their positions in the mosaic, so for example cd2.1.jpg is the first image in row two. Open up viewing windows for the first two images by double clicking on the thumbnails. Move the two opened images viewers so that they are side by side. Adjust the zoom (using the i and o keys) and the pan (by dragging with the middle mouse button) so that the overlap area is visible in both images.

Mark a tie-point on each image by Ctrl-left-clicking on a feature you can see in both images, see Figure 2.9. Move a point after you’ve marked it by dragging on the label. You don’t need to be exact: nip2 just uses the point you select as the start point for a search. It can cope with misses of up to about 10 pixels. To mosaic the two images together, click on Toolkits / Tasks / Mosaic / One Point / Left to Right. See Figure 2.10.


PIC


Figure 2.9: Ready to join



PIC


Figure 2.10: Joined images


Picking items deep in the toolkit menu is fiddly, so nip2 has several shortcuts. First, you can tear off any toolkit menu by clicking on the dotted line at the top. Secondly, you can assign any keyboard accelerator to any menu item. Navigate to the menu item and while it is selected, press the key combination you want to use as a shortcut (for example, Ctrl-L might be good for Mosaic / One Point / Left to Right). Now whenever you press Ctrl-L with the keyboard focus in the main window, you will do a left-right mosaic join. Finally, you can use the toolkit browser to display a selection of the tools in a pane on the right-hand side of the main window. Click on View / Browse Toolkits, then type “mosaic” into the search box at the top. The toolkit browser will display all items related to mosaicing. Double-click an item to do that action.

Some systems won’t let you edit menu shortcuts by default. For example, on GNOME, you need to enable this in System / Preferences / Menus & Toolbars.

Join the rest of the pairs of sample images together left-right. Once you have made all the rows, join the rows together in turn to make the complete image using Mosaic / One Point / Top to Bottom.

When you’ve built the whole thing you’ll see that there are differences in brightness between the tiles that make up your composite image. You can fix most problems like this automatically by selecting your final mosaiced image and clicking on Mosaic / Balance. This operation takes your mosaic apart, examines the overlap areas for differences in brightness, calculates a set of adjustment factors to minimise these differences, and then rebuilds the mosaic.

There can be some problems left even after mosaic balance. Use Mosaic / Tilt Brightness to remove any left-right or up-down graduations in brightness.

Save your mosaic workspace for future reference by clicking on File / Save Workspace. To save just the mosaiced image, right click on the thumbnail and select Save As.

nip2-8.7.1/doc/html/nipguidese13.html0000644000175000017500000003026113414613100014212 00000000000000 Command-line interface

4.5 Command-line interface

You can use nip2 from the command-line as well as from the GUI. This can be handy for automation: you can build a workspace and then run it over a whole set of images, or use nip2 as part of a larger system. We’ve make websites which use nip2 as the back-end.

In command-line mode nip2 runs without a GUI of any sort, it doesn’t even need a window system to be installed on the machine. This makes it possible to use it in a server or batch context.

These notes are for the Unix command-line, but they should work for Windows as well.

nip2 has three main modes of operation from the command-line:

nip2 filename1
Start nip2 in GUI mode, loading the command-line arguments as files. Filenames can be images, workspaces, matricies, toolkits, and so on.
nip2 -e expression arg1
Start in no-GUI mode, print the value of expression. The list argv is set to be ["filename","arg1",..].
nip2 -s filename arg1
Start in no-GUI mode, read in filename as a set of definitions, print the value of symbol main. The list argv is set to be ["filename","arg1",..].

You can use the -o option to send output somewhere other than the screen. If these modes don’t do quite what you need, you can get finer control of how nip2 behaves with a set of other options: see the man page for details.

4.5.1 Using expression mode

The -e option is very easy to use. For example:

nip2 -e "2 + 2"

Prints 4 to stdout.

nip2 -e "99 + Image_file argv?1" -o result.png fred.jpg

Loads argv1 (fred.jpg), adds 99, writes the result to result.png.

nip2 -e "Matrix [[1,2],[4,5]] ⋆⋆ -1" -o poop.mat

Invert the 2x2 matrix and write the result to poop.mat.

If the result of the expression is a list, each item is printed on a new line. For example:

nip2 -e "[1..5]"

Will print the numbers 1 to 5, each on a new line.

If you have a list result and you are using -o to direct the output to a file, the filename will be incremented each time you write. For example:

nip2 -e "map (add (Image_file argv?1)) [10, 20 .. 50]" -o result1.png fred.jpg

Will load fred.jpg, add 10, 20, 30, 40 and 50, then save those images to result1.png to result5.png.

4.5.2 Using script mode

With the -s option you can use nip2 as a Unix script interpreter.

Create a file in your favourite text editor called brighten containing:

#!/usr/bin/nip2 -s  
 
main  
  = clip2fmt infile.format (infile ⋆ scale), argc == 3  
  = error "usage: infile scale -o outfile"  
{  
  infile = Image_file argv?1;  
  scale = parse_float argv?2;  
}

The first line needs to be the path to nip2 on your system. Use which nip2 to find the path if you don’t know it. Mark the file as executable with chmod +x brighten, then use it on one of your image files with:

brighten fred.jpg 1.5 -o bright_fred.png

See Chapter 6 for details on the programming language. This program multiplies each input pixel by the constant, producing a floating point image, then then clips the result back to the same format as the original image (usually 8-bit unsigned).

nip2 takes a while (a few seconds) to start up, so this isn’t going to be appropriate for small images or simple calculations. But for complex operations, or operations on large images, this mode can be very useful.

4.5.3 Using –set

The –set option (which can be abbreviated to -=) lets you make changes to a workspace after loading it. Suppose the workspace test.ws has a row called A1 with the value 12. Then entering:

nip2 test.ws --set Workspaces.test.A1=45

Will, as normal, start nip2 and load test.ws. But before the first recalculation, nip2 will change the value of A1 to be 45. You can use –set to create new symbols as well.

4.5.4 Other modes

A set of sub-options let you mix up other modes yourself. For example, it’s common to want to run a workspace on many files.

Suppose the workspace process.ws loads an image in A1, performs some processing and produces a result image A10. If you run nip2 with:

nip2 -bp \  
  -= 'Workspaces.process.A1=Image_file "fred.jpg"' \  
  -= main=Workspaces.process.A10 \  
  -o fred.jpg process.ws

This will start nip2 in batch (ie. no GUI) mode (the -b switch), load process.ws, change A1 to load another file, set main to be the value of A10 and save the value of A10 to fred.jpg (the -p switch).

nip2-8.7.1/doc/html/nipguidech5.html0000644000175000017500000001003413414613100014112 00000000000000 5 Image processing menus

Chapter 5
Image processing menus

This chapter is runs quickly through the Toolkits menu. See Chapter 6 if you want to understand how the menus are written (or want to add more of your own). Use the Toolkit Browser to find stuff.

Some things are common to almost all menu items:

Tooltips
If you rest your mouse pointer over an item, you’ll see a quick description of what the item does.
Grouping
You can select several objects, click Edit / Group, and then when you click the item, it will operate on all the objects in the group.
Any type
Almost all items will work on any object. You can add an image and a number, for example, find the colour difference between a number and an image, or transform a matrix from LAB to XYZ.
 5.1 Colour
 5.2 Filter
 5.3 Histogram
 5.4 Image
 5.5 Math
 5.6 Matrix
 5.7 Object
 5.8 Tasks
  5.8.1 Capture
  5.8.2 Mosaic
  5.8.3 Picture Frame
  5.8.4 Print

nip2-8.7.1/doc/html/nipguidese14.html0000644000175000017500000003453713414613100014225 00000000000000 Colour

5.1 Colour

This menu groups operations on colorimetric images and patches of colour. A colour patch is three float numbers plus a tag saying how those number should be interpreted as colour (for example, as a colour in CIE LAB colourspace). You can drag and drop between colour patches, and into and from the inkwell in an image paint window. Double-left-click on a colour patch to open a colour select dialog.

nip2 has 9 main types of colorimetric image, see Table 5.1. All these types are D65 (that is, daylight) absolute colorimetric. When it displays an image, nip2 uses the Type field in the image header as a hint on how to transform the numbers in the image into RGB for the display. The current Type is displayed at the end of the caption line below an image thumbnail.

The Mono, GREY16 and RGB16 types are not really calibrated themselves: they are usually whatever you get by loading an image from a file. You’ll usually need an extra step, such as applying an embedded ICC profile, before you get accurate colour.





Name Format Notes



Mono One band 8 bit Not calibrated
sRGB Three band 8 bit Screen device space for the sRGB standard
GREY16One band 16 bit Not calibrated
RGB16 Three band 16 bitNot calibrated
Lab Three band float The 1976 version of the CIE perceptual colourspace
LabQ Four band 8 bit Like Lab, but represented as 10:11:11 bits
LabS Three band 16 bitLike Lab, but represented as 15:16:16 bits
LCh Three band float Lab, but with polar coordinates
XYZ Three band float The base CIE colourspace
Yxy Three band float Sometimes useful for colour meters
UCS Three band float Highly uniform space from the CMC(l:c) standard




Table 5.1: nip2 colourspaces


New
Make a patch of colour, or pick a colour from a slice through CIELAB colourspace.
Convert To Colour
Convert anything into a Colour object.
Colourspace
Change the colourspace. The stored numbers change, but the visual appearance should stay the same.
Tag As
Change the colourspace tag (the Type field in the image header). The stored numbers stay the same, but the visual appearance should change.
Colour Temperature
Change the colour temperature. Move Whitepoint just adjusts the ratios of X and Z using the CIE standard illuminants.

D65 to D50 and D50 to D65 transform using either a 3x3 matrix which is numerically minimal in XYZ space with respect to the colours on a Macbeth Color Checker, or via Bradford cone space. The Bradford transform omits the power term.

The final two items go from XYZ to LAB and back, but with D50 normalisation rather than the default D65.

ICC
Transform images (not patches of colour) device space to profile connection space (LAB float) and back.

You need to be careful about colour temperature issues: all printers work with D50, and nip2 is all D65. Use the D65 to D50 interchange items in the Colour Temperature menu to swap back and forth.

All printers also work with relative colorimetry, and nip2 is generally absolute. Use Absolute to Relative to scale an absolute colorimetric image by a media white point.

Radiance
nip2 can read and write images written by the Radiance family of programs (usually with the suffix .hdr), commonly used in HDR photrography.

Images in this format used a packed floating point layout for their pixels. Items in this menu pack and unpack pixels for you.

Difference
Calculate various colour difference metrics. You can mix patches of colour and colour images.
Adjust
Change colour in a colorimetric way. Recombination multiplies each pixel in an image through a matrix. Cast displaces the neutral axis in LAB space. HSB lets you adjust an image in LCh colourspace.
Similar Colour
find pixels in an image with a similar colour to a patch of colour.
Measure Colour Chart
This takes a trimmed image of a colour chart (a rectangular grid of coloured squares), measures the average pixel value in the centre 50% of each square, and returns a matrix of the measured values.

Use Make Synthetic Colour Chart to make a colour chart image from a matrix of measurements.

Plot ab Scatter
draws a 2 dimensional histogram of the distribution of pixel colours in LAB colourspace.

nip2-8.7.1/doc/html/nipguidese33.html0000644000175000017500000006636513414613100014232 00000000000000 Controlling the interface

6.12 Controlling the interface

nip2 looks at the scraps of program you type in and execute and tries to show them on the screen in a graphical way. The sorts of display you get depend on where in nip2 you define the expression, and what sort of value it has.

6.12.1 Tools and toolkits

Definitions in toolkits are turned into menus off the Toolkits menu in the main window, and added to the toolkit browser. Toolkits are loaded from files at startup or can be made in the program window. Toolkit or a definition names which start with an underscore character are hidden and not displayed. The toolkits are always displayed in alphabetical order, but you can order the items within a toolkit in any way you like.

There are two ways to write toolkit definitions. Function definitions and zero-argument classes simply appear as menu items, built from static analysis of their source code. However, if a definition evaluates to an instance of the class Menu, a menu item is built from dynamic analysis of the value of the definition.

Static menu items

Zero-argument classes within toolkits are displayed as pull-right menus. You can nest classes to any depth.

nip2 uses the first line of the comment before a definition as help text for that function, so it’s a good idea to put a simple one-line description of the function at the start of a comment.

For example, if the following text is placed in a file called Fred.def on nip2’s start path, you’ll get a menu in the tookits called Fred with a pull-right and a tooltip. See Figure 6.1.

Banana a = a ⋆ 3;  
 
Subfred = class {  
  // add two things  
  Jim a b = a + b;  
  Apple e = e ⋆ 12;  
  Harry z = 12 + z;  
}


PIC


Figure 6.1: How Fred.def will look


Dynamic menu items

Dynamic menus give you much more control over the way menus are drawn and make it easy to reuse menus. A dynamic menu item is a class instance that is a sub-class of Menuitem. It needs to have three members: label, the text that should appear in the menu (with an underscore character to indicate the mnenonic); tooltip, a short hint that appears as a tooltip or in the toolkit browser; icon, an optional image file to be displayed in the menu next to the text; and action, the function that is called when the menu item is activated. label and tooltip are constructor arguments for Menu.

So for example:

Wombat_find_item = class Menuitem  
  "_Find Wombat"  
  "analyse image and locate wombat" {  
  icon = "nip-slider-16.png";  
  action x = im_wombat_locate x;  
}

will appear as shown in Figure 6.2.


PIC


Figure 6.2: How Wombat_find_item will look


A dynamic pullright menu is a subclass of Menupullright. It’s just like Menuitem, but without the need for an action member. Any members which are subclasses of Menu are displayed as items in the submenu. So again:

Wombat_item = class Menupullright  
  "_Wombat"  
  "wombat-related operations" {  
  icon = "nip-slider-16.png";  
  item1 = Wombat_find_item;  
  sep = Menuseparator;  
  boink = Wombat_find_item;  
}

will appear as shown in Figure 6.3.


PIC


Figure 6.3: How Wombat_item will look


6.12.2 Workspaces

Definitions in workspaces are displayed with nip2’s class browser. Each row is displayed in four main parts: a button for the row name, a line of text, a set of sub-rows for the members of the row’s class, and a graphic display representing the row’s value. See Figure 6.4.


PIC


Figure 6.4: Components of a workspace row


The text part of the right-hand-side of each row is always displayed, but the sub-rows are only displayed if the row represents a class, and the graphic is only displayed if the class is an instance of one of the classes in Table 6.5. You can subclass these if you want to use the graphic display in your own widgets.

There are three separate ways to set the value for a row. You can edit the line of program text, you can edit one of the members, or you can manipulate the graphic representation (dragging a slider, or moving a region). These can be contradictory, so nip2 resolves conflicts by always applying changes in the order text, then graphic, then member.

When it applies a graphic change, nip2 rebuilds the class using a class member called class-name_edit, or if that is not defined, the class’s constructor member. For example, the Colour class can be defined as:

Colour colour_space value = class {}  
A1 = Colour "sRGB" [255,0,0];

There are two ways to change A1. You can open A1 and change colour_space to ”Lab”, or you can double-click on the swatch and drag the disc. When you click OK on the colour edit dialog, nip2 searches for a member called Colour_edit, fails to find it, and so picks the Colour member instead (the default constructor generated by nip2). It then replaces the value of A1 with

[needs finishing]




Class Description


Clock interval value A clock widget, handy for animations
Expression caption expr Displays an editable expression
Group value A group of objects for iteration
List value A list of related objects
Pathname caption value Displays a file browser
Fontname caption value Displays a font browser
Toggle caption value A toggle switch
Scale caption from to value A slider
Option caption labels value Select one item from a list
Colour colour_space value A patch of colour
Matrix_vips value scale offset filename displayA matrix
Arrow image left top width height Two points joined by a line on an image
Region image left top width height A sub-area of an image
Plot options value Displays a plot widget
Image value An image
Number caption value Displays an editable number
Real value Displays a real number
Vector value Displays a list of reals
String caption value Displays an editable string
Mark image left top A point on an image
HGuide image top A horizontal line on an image
VGuide image left A vertical line on an image
Area image left top width height A sub-area of an image, fixed in size



Table 6.5: nip2 built in graphic classes


6.12.3 The Image class

.

say supports mioxed ops with real, vector and complex constants

6.12.4 The Colour class

This class displays a swatch of colour. If you double-click on the

Pathname caption value = class {}

nip2-8.7.1/doc/html/nipguidech6.html0000644000175000017500000001423313414613100014120 00000000000000 6 Programming

Chapter 6
Programming

nip2 includes a tiny lazy functional programming language. You can use it to glue VIPS image processing functions together to perform more complicated tasks. All of the nip2 toolkit menus are written in this language.

These first sections just describe the programming language. See 4.4 for a description of the programming window. You use nip2’s programming language to control the user interface: the link between what happens inside a nip2 function and what you see on the screen in covered in 6.12.

nip2-8.7.1/doc/html/nipguideli2.html0000644000175000017500000001276713414613100014140 00000000000000 List of Figures

List of Figures

nip2-8.7.1/doc/src/0000755000175000017500000000000013414613110010726 500000000000000nip2-8.7.1/doc/src/infrared.tex0000644000175000017500000005006013351443023013167 00000000000000\chapter{Assembling infrared mosaics} \mylabel{sec:ir} VIPS has a package of functions designed to help join many small images together to make a single large image. They were originally designed to assemble infrared reflectograms but are general enough to be useful for other sorts of image as well, such as X-rays. This chapter first introduces the mechanics of infrared imaging then explains how to use \nip{} to assemble the images you grab. Finally, it suggests some printing techniques. \section{Infrared imaging} Most museums use tube cameras (usually called Vidicons) for infrared imaging. Although they are relatively cheap they are not very stable and they suffer from (sometimes quite severe) geometric distortions. More modern solid-state cameras are still expensive but are becoming more widely used because of their greater stability. This guide assumes you are using a tube camera but almost all of it applies to solid-state cameras as well. Whatever your camera there are three main sources of error which have to be addressed in order to be able to make successful mosaics: \begin{enumerate} \item Tube cameras suffer very badly from distortions in the image, usually either `pin-cushioning' or `barrelling'. These distortions result in alignment errors when sub-images are joined together. \item The sensitivity of the tube varies across its surface, causing some parts of each sub-image to be brighter than others. This is made worse by unavoidable variations in illumination. When a lot of such images are joined together the result is a `brick wall' effect. \item The sensitivity of the tube also varies between sub-images, partly as the overall lightness in the field of view changes, and also because the electronics in the camera change as the camera heats up. This leads to a patchy, unbalanced mosaic. \end{enumerate} The first two problems will be different in each Vidicon and will change each time a tube is replaced. All three problems need to be addressed to create successful infrared reflectogram mosaics. \subsection{Setting up your system} \subsubsection{Mechanical set-up} It is vital that the optical axis of the Vidicon is at right-angles to the picture plane and that, whether it is the Vidicon or the painting that moves during image capture, it remains perpendicular. Obviously, with a seriously warped panel, this may not be possible. The lighting should be carefully adjusted so that the area of interest is lit as evenly as possible. If you can, arrange for the lights to remain stationary with respect to the camera. An easy way to test camera alignment is to image a piece of graph paper, move the camera (either left-right or up-down) by 90\% of the field of view, and see how features in the overlap area move. First rotate the centre around the optical axis to get the centre line of the images lined up. Next check the corners and adjust camera pitch and yaw. \subsubsection{Video set-up} \mylabel{sec:vidpref} On Linux, you can capture video directly into \nip{} provided that your capture card is compatible with v4l. You may need to adjust the \nip{} video settings. These settings can be found under the headings \ct{Video for linux} and \ct{General video capture} in the \ct{Preferences} window, which can be accessed by selecting \ctr{Edit}\ct{Preferences} from the main \nip{} window. The default settings, see \fref{fg:vidpref}, are for the Hauppauge PCI capture card and should be changed as required. \begin{fig2} \figw{3in}{scr21a.png} \caption{Recommended video preference settings} \mylabel{fg:vidpref} \end{fig2} Once you have set up your card, select \ctr{Tasks}\ctr{Capture}\ct{Capture Video Frame} to create a new video object, which will appear as a still image in your current selected column. The captured image can be updated by opening the image in a viewing window and then pressing Ctrl-C (a shortcut for \ctr{File}\ct{Recalculate Image}). You can create more than one video object: this can help you to get the overlaps right if you have two open at once (one showing the previous grab) when you are moving the camera around. \subsubsection{Setting the crop and aspect} While it is possible to correct geometric distortions after the image is captured, it is difficult to do the necessary modelling accurately and reliably. Instead, we suggest the grabbed images should simply be cropped, since the most severe distortion affects the perimeter of each video image. To determine the area to crop, set up the Vidicon as it would be set to image a painting and capture an image of a rectangular grid --- a piece of graph paper works well as a target. Before capturing the grid, check the current video crop settings in the \ct{Preferences} window and ensure that the crop is set at maximum: left 0, top 0, width 768, height 576 (these are the dimensions for a PAL signal, they may be different on your system). Also set the \ct{Aspect ratio} line to 1. Create a new video object and look for the largest rectangle with little distortion (no more than a few pixels). If you create a region on the video image (by holding down the Ctrl key and dragging down and right with the left mouse button, see \pref{sec:region}) you can compare the straight edges of the region against the distorted lines of the grid. You can then expand and contract the region until you decide on the optimum area. The settings you need for the crop box can be taken from the values contained within the region object, which can be viewed by left-clicking several times on the down arrow to the left of the region object name. Finally, you can set an aspect ratio: \nip{} will automatically stretch video frames vertically by this factor. You can measure the aspect ratio of your capture card by taking a picture of something you know to be square and dividing the width in pixels by the height in pixels. Move back to the \ct{Preferences} window and enter the crop values in the \ct{General video capture} section. Next time you create a new video object, you should find that it is cropped to the appropriate area. The settings you enter in the \ctr{Preferences} window will be saved and automatically loaded again next time you start \nip{}. See appendix~\ref{sec:config}. Choosing the usable area of the image is a matter of compromise --- the smaller the area, the more images are required to build a mosaic of a particular painting. If the area chosen is too large then the amount of distortion can cause serious errors in the final mosaic. It's possible to use the VIPS rubber sheet plug in to detect and correct geometric distortion in your images automatically. This lets you use the full area of the sensor. It is a bit fiddly, but see the rubber sheet documentation if you are determined. \subsection{Capturing the data} \subsubsection{Setting the gain and offset} Once everything is correctly set up, position the painting in front of the camera and experiment with the gain and offset settings on the Vidicon to achieve the optimum infrared image on the computer screen. Note that the appearance of the image on the computer will normally be different to its appearance on the video monitor connected directly to the camera. Repeat this process at different points across the whole area to be captured. Although it is not always possible, the aim is to find a setting that does not need altering much during the capture of the data. This seems to lead to more successful mosaics. \subsubsection{Grey card correction} To counteract the problem of uneven sensitivity across the target area of the tube, it is necessary to capture an image of a piece of grey card. This grey card image is then used to correct all subsequent images. The card should be a flat, even grey, of around 50\% reflectance. The Vidicon and lighting positions with respect to the painting should not be changed between the imaging of the grey card and the capturing of the mosaic. A grey card can be captured at any time, but it is good practice to start with one --- you may forget later. If your mosaic will take several hours to capture, you may wish to grab extra grey cards, since the sensitivity of the tube can change as it warms up. Be sure to note which data images correspond to which grey cards! In association with the first grey card, it is a good idea to grab an image of your grid to record the scale at which the data images are being made. \subsubsection{Image capture} \mylabel{sec:imcap} Open a video window, \ctr{Tasks}\ctr{Capture}\ct{Capture Video Frame}, and when it shows the desired area, save the file. The choice of file name is a question of personal preference. We find it helpful to use a format that indicates where in the mosaic the data comes from --- for example, \ct{dat3.5.v} for the fifth image in row three. It is helpful to be able to see the previous image to ensure that there is sufficient overlap. To achieve this, a second video window can be opened and placed alongside and the images grabbed into alternate windows. \subsubsection{Capture tips} \begin{itemize} \item Make a new directory for each painting, and keep all of the image files for that painting (including a grey card and a grid) in that directory. \item VIPS can join up images in any layout, but you will get much less confused when you assemble your images if you stick to a regular grid. This can be difficult --- a good compromise is to keep one axis fixed and grab in rows (or columns). \item You can help to reduce mosaicing errors later if you keep your rows (or columns) as short as possible. So if the painting is in landscape format, grab in columns (or turn the painting on its side and grab in rows); if the painting is portrait, grab in rows (or turn the painting on its side and grab in columns). \item The semi-automatic mosaic functions (see \pref{sec:mosaicing}) need a minimum overlap between the sub-images they join of around 20 pixels. For safety, you should aim for a larger overlap than this: we recommend an overlap of 60 pixels (around 20mm, usually). \item If the overlap area is featureless, it is worth identifying a good tie-point and ensuring it is visible in both images, even if this means increasing the overlap for one of the joins. \end{itemize} \subsection{Correcting illumination} \mylabel{sec:grey} Before the mosaic can be assembled, the data images need to be corrected for non-uniformity of illumination using the grey card image. This function can be performed within \nip{} or directly using a predefined VIPS command-line tool. \subsection{Correcting with the command-line tool} \mylabel{sec:linuxgrey} First, close \nip{} and open a command line window, (xterm, mingw, etc). Move to the directory containing your image files with \ct{cd}. For example, if you have made a directory called \ct{raphael} inside your home directory, type: \begin{verbatim} prompt% cd raphael \end{verbatim} The program you need to use is called \ct{light\_correct}. You need to give it the name of the grey-card image and the names of all of the image files you want it to correct with that gray card. Suppose you have saved your gray card image as \ct{grey.v}, and your painting image files are called \ct{dat1.1.v} and \ct{dat1.2.v}. You would then enter: \begin{verbatim} prompt% light_correct grey.v dat1.1.v dat1.2.v \end{verbatim} The program will run and print messages explaining its progress. It creates a new set of corrected image files, with the same names as before, but prefixed with \ct{ic\_}. In this example, it would create two new images files called \ct{ic\_dat1.1.v} and \ct{ic\_dat1.2.v}. If there are a lot of image files to correct this could mean a lot of typing. Fortunately, you can use wildcard characters to abbreviate lists of file names. The example above can be abbreviated to: \begin{verbatim} prompt% light_correct grey.v dat*.v \end{verbatim} \noindent The \ct{dat*.v} means `any filename which starts \ct{dat} and ends with \ct{.v}'. You can use this technique to correct different parts of your mosaic with different grey cards. If you have a file called \ct{grey1.v} for the first row in your mosaic, and a file called \ct{grey2.v} for the second, you could do the correction in two parts: \begin{verbatim} prompt% light_correct grey1.v dat1.*.v \\ prompt% light_correct grey2.v dat2.*.v \end{verbatim} \subsection{Correcting within \nip{}} \mylabel{sec:wingrey} The function within \nip{} used to preform this correction is \ctr{Tasks}\ctr{Capture}\ct{Flatfield}. A set of images can be corrected at the same time by joining them together in a \ct{Group}. A group can be produced by selecting all of the required images and then using the \ctr{Edit}\ct{Group} command. Load all of your images into \nip{}, and group all the image except the grey image. Select your grey image and then your new group and then run the \ctr{Tasks}\ctr{Capture}\ct{Flatfield} function. This will produce you a group of corrected images. Right-click on this new group and select \ct{Save As} from the menu. In the save window type in a name, for example \ct{fred\_01.v} and then hit the save button. All of the images in your group will then be saved as \ct{fred\_01.v}, \ct{fred\_02.v}, \ct{fred\_03.v} \ldots{} \ct{fred\_n.v}. If you want to keep row numbers in your file names, (see \pref{sec:imcap}), you will need to correct your images one row at a time, saving each row as \ct{fred01\_01.v}, \ct{fred02\_01.v}, etc. \section{Assembling the mosaic} \mylabel{sec:mosaicing} The tutorial has a section on mosaic assembly with \nip{}: see \pref{sec:irtut}. Mosaic assembly is normally painless. There are a few factors you should bear in mind when you are deciding how to assemble an image (particularly a large image): \begin{itemize} \item You can open up a mosaic join and change a few options, such as the blend width. If you want to change the defaults for a whole workspace, change the \ct{Mosaic defaults} options in your \ct{Preferences}. \item If two images just won't join correctly, try using \ctr{Tasks}\ctr{Mosaic}\ctr{One Point}\ct{Manual Left to Right} instead. These functions operate in the same way as the usual mosaic functions, but do not do a search. This is useful when the overlap is too small for the search to work correctly, or when the overlap area is very smooth and contains too few features for the search to find the exact overlap for you. \item \nip{} does not do sub-pixel interpolation. As a result, each join will on average cause a positioning error of about 0.5 pixels, even if your input images contain no geometric distortion. If there are distortions in your input images (there usually are distortions in infrared images), then errors can be as much as 1--2 pixels per join. These errors accumulate as the number of images you join becomes larger. If you join a strip of 10 images together with \ctr{Tasks}\ctr{Mosaic}\ctr{One Point}\ct{Left to Right}, on average you can expect a total error of about 5 pixels. If you join two strips like this together top-bottom, you can therefore expect a mismatch of about 2.5 pixels at each end of the join. You can minimise the effect of these errors if you assemble your images differently. Suppose you have a 10 by 10 mosaic to build. Instead of making and joining 10 strips of 10 images each, make four 5 by 5 sub-mosaics (one for each quadrant) and then join these four quadrants together. The errors will now be more evenly spread over the image and therefore will be less visible. \item \mylabel{sec:pieces} Some operating systems limit the number of files a program can have open at once: this in turn limits the size of the mosaics you can assemble in one go. If you are having problems putting together very large mosaics, try building your image in sections (\ct{top}, \ct{middle} and \ct{bottom}, perhaps), and later load up and join these larger pieces. \end{itemize} \section{Balancing the mosaic} \mylabel{sec:balance} Like assembly, mosaic balancing is normally automatic and painless. You may sometimes have problems if the image is very large, or needs dramatic corrections: \begin{itemize} \item Each VIPS image file has an associated history, recording the operations on that image since it was loaded from a file. You can view an image's history by clicking on \ctr{View}\ct{Image header} in an image view window. The automatic balancer uses the history to work out how you built your mosaic. The balancer knows about left-right and top-bottom joins, but nothing else! If the history has other stuff recorded in there, you'll see unhelpful error messages like \ct{unable to open tmp/xxx.v}, or \ct{more than one root}. If you need to perform corrections to any of your sub-images, do them, save the image, load it again, and then build the mosaic. This will make sure the history of the image you are trying to balance only contains mosaic operations. \item On some systems the balancer can run out of memory or out of file descriptors on very large mosaics. If your mosaic is made up of more than a few hundred images, and you are having balancing problems you may have hit one of these limits. The solution (as with mosaic assembly) is to assemble and balance your mosaic in smaller pieces. \item If your grey-card correction is not accurate, you will find that the balancer will magnify any problems you have. Suppose your lighting and camera set-up always produces images which are brighter on the right than the left, and suppose, due to some problem with your grey-card correction, this effect is not completely removed. You will find that when you balance a mosaic, the small differences between left and right edges of your sub-images will have been smoothed out, but they will have caused a large difference in brightness between the extreme left edge of your final image and the extreme right. \nip{} includes several functions which can help to fix this problem, the most commonly used being: \ctr{Tasks}\ctr{Mosaic}\ctr{Tilt Brightness}\ct{Left to Right} and \ctr{Tasks}\ctr{Mosaic}\ctr{Tilt Brightness}\ct{Top to Bottom}. \end{itemize} \section{Other \nip{} features useful for reflectograms} You can use \nip{}'s general image processing facilities to play around with reflectogram mosaics. You can make false-colour images of your reflectograms, blend them with visible images or X-rays, search them for edges, and so on see the \ct{registering} and \ct{overlays\_and\_blending} examples for ideas. There are also some first order mosaic functions: \ctr{Tasks}\ctr{Mosaic}\ctr{Two Points}\ct{Left to Right} and \ctr{Tasks}\ctr{Mosaic}\ctr{Two Points}\ct{Top to Bottom}. These functions automatically rotate and scale the right-hand image in a join. They are useful for assembling X-ray mosaics, and for fixing very difficult joins in reflectogram images. These functions work the same way as the \ct{One Point} functions except that you will need to define two tie-points on each image. You can mosaic images of any numeric type: 16-bit integer images are handy for mosaicing X-ray images, for example. \section{Printing} Once you have assembled a good reflectogram, you will want to print it, or to use it in other computer programs. The best way to do this is to save the final image in TIFF or JPEG format, and then load it into the new application --- see~\pref{sec:loadsave}. There are a couple of points to bear in mind: first, like any image, reflectograms look best on paper if you sharpen them up a little first. Click on \ctr{Filter}\ctr{Convolution}\ct{Custom Convolution}, right click on the matrix button, select \ct{Replace from file}. Double Click on the second or lower \ct{data} directory listed in the left hand column to enter \nip{}'s main data directory. Change the \ctr{Image type select} option to \ct{All FIles (*)} and then select and load \ct{rachel.con}. This will usually produce an approprioatly sharpened reflectogram. Secondly, you will need to try several prints with different contrasts and brightnesses to get a good match between the paper and the screen, try \ctr{Image}\ctr{Levels}\ct{Linear}. You may even want to fiddle with the gamma, try \ctr{Image}\ctr{Levels}\ct{Power}. Finally, you may not need a full resolution image. For almost all printers there's no point going over about 300 dpi (dots per inch), or about 3000 by 2000 pixels for an A4 page. To reduce the size of an image, use one of the functions listed under \ctr{Resize}\ctr{Transform}\ct{Resize}. nip2-8.7.1/doc/src/Example.def0000644000175000017500000000036513351443023012731 00000000000000/* Gamma im gam: correct */ Gamma A1 B7 = error "arg 1 is not image", not is_image A1; = error "arg 2 is not number", not is_number B7; = Convert_to_unsigned_char B5 { B4 = A1 ^ (1/B7); B5 = B4 * (255 / 255 ^ (1/B7)); }; nip2-8.7.1/doc/src/html.cfg0000644000175000017500000000070113351443023012275 00000000000000% configuration file for output of nipguide as html \Preamble{html} \begin{document} % stop the mono font shrinkage we do for paper output \renewenvironment{ctd}{\begin{quote}\tt}{\end{quote}} % make a label % in html, write an extra label which we can link to nip's help system \renewcommand{\mylabel}[1]{ \label{#1} \HCode{} } % supress " on page xx" if we're making HTML \renewcommand{\onpage}[1]{} \EndPreamble nip2-8.7.1/doc/src/figs/0000755000175000017500000000000013351443023011662 500000000000000nip2-8.7.1/doc/src/figs/toolkit3.jpg0000644000175000017500000004651613351443023014070 00000000000000JFIFJExifMM*2:(&&C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222 " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?LUpOT> ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEG7I,0lުvIzZ( ( ( ( ( ( ( ( ( ( ( ( ( ( ]sk5Ʒq\~]oX|7zk[Ns ;#Xmʁ"xVD۔rF8HVnL2n8LPܖ~5UӍgY4K~f3ٿû>}zp ^w"Wzӿ\xCEn&7 kmh ,~`]Ìu8V u![7xYO,K c@"VR?]NQ ^w"c tnY#qqm,Ou $`y?>Ufco^>G»׿綝޽=Ezu][Eqo" 92A"ջ<޽=E+ԨջԨ<޽=E+ԨջԨ<޽=EIoUtK˛4')opP?Z'i-ΈZ8Kpg֪զaFaSC Đȼ28jObm3AV?V ?Uȶ:7zhwZy,-ELȹœz /ZF,ogD3ڈ2H#vwEnfPH7K>,xyA b5H-lo洏u%Aq0q&*@9jn-o/./"K1"\AB" ğNsIm=F{wviр@,p@CL]Um®(R8<եy'W(l$yce ?a½ϲ'|y[|7}wc=֞᫹m쮍֦UV(r%@Z77 eB9; \{Xm|4* b mԑL>?ڿhy{6Yw::X=U(5oq$`yt/ڹcnn3]0еH<)}׷7)*;(%˴RQ'#8QG@p ՄN Lt¢ 2J3ʞgW,^*0Y[[wf%\s:P_ i]#Oge %K"$dAZQ@Q@Q@4ԣPlMz]բрL[I 1NTqSk(/?鴙mw)ͻa3;:( ( ( ( ǗF-axJ:uޗ+˩1i[b7?.x8O&d`qmQR0(((((((((((((YEAS kp9/]h:5>kN10nt(.I#8TOZ hc/7o*4xg'/=7^펧<^&{?xIL7w$ĩ6mi>٭e4Tbv:Ozi;[:4Em)^;;׍ Tg FH~3[5&%wN sr'%@ӡ47RĚri%ĥV]9 (1bB恝55 h+{gy*(,va ʹޮ7@;ybD,Tiup-z''=QEQEQEQECw3|8sVwuAa,Asm;>TpB:ۥhnK<[kF2:J!EI=I'O$*'*Q;]QZrk95ܢm.G\c`pэ `fSԴ=Z`ã$`) >[5]>Yw$ivQhAH)1ݡyc,ms#91P[9gK'&{i|/f$ V{u aU H*OI@--ux渒YH^2] ʸcH^mbXH>A84佷Pd1G4\)NLo{@6ҴsoKK譍Rq.60&>OU~]XKd2ϨQ ]6y~a#Z :]E"Tyv$ TPA%<}6wP\-.xC ga\hC ( ( ( ( *h ΅c o-`qYץ'\IlG3"'ޜqXWW&C_(Au=[NE`0 Es[H$KˤiD@HتU~nⅰ3I&sk>\f/#I9?oK~1ip~cc#<ӨmHu ck+>$˖7Ldޮ<ڼzՋ;:5P9Wn{,2!u{hiVXh$҄6H\_Krr9ڿյ} Z ^]ChDT5iG[и7]C&/v"ĕ<ɫOgk#m 9_G4<ϩ׬! ݌ U}: ıĪ ef((mbыW*mpŚhbpI)= B+ <O&dT?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4}T?h_s4w!wUFI6OEPEPEPEPEPEPS ?g\AV4 ;K`%N[K{ZeT.7`c Vd~ l=JE41hbpynSi鎚Z_y$E&2DGe3]TI#Öv: rNc6 ~W'sVQEQEQEQEQE ݬ7sZ)hfCTȧAVG$Pơ4\*ARQ@9ksgo2|syozʹs˩6l\"HH2i6^m h ½ %N548iSM]O6Ga{'w&7`w9jYc2 H)0 UXA,Yng9 NGyiO%&F-IJ4(Rd NL5| fȗL!p8;~E5,`Q8b $sש}ݣ?dk٭T˧@֒\ r+I5MđOq!pcf&-Y[R^Pp BPI})vib/_ֿ)ZFQHRX'8k[Q"tkx W l{qIokZ[-ЕV}:<y=0nl>k>Zϼ?yZϼ?ֿ)eeAv;ֿ(5| oGE]5| >k>QQddŤ{0k>$,$ļʸgpڋn]Zܦƶ3;~5kMV_+)+Xm*Xݟ;x?4G2m0H?|RQ^#a`AWN+HsHSc$g*sO#9i@?J$ѰI U+H(싕9R(=6 HNt/?T&HM y*J(9$tl,H1JR);"ciz)Ԋucc`<~RмxSWj (QEQEQEQEQETg"YE5i_Vo i~]OVIMytdJ޴l|MO,7=ܺ5̾e֡42\CG%wq=兕XZG[D›ڊQe?7/viu,{N7Qޫk)7OM '+Cn^[g̡F=/Y7šAW^ɵ-g<9' 8 ι9m<7c5ViˉJUu݉q44԰ӬH4 hW "hd\ڬ+o 'O/v$e>qz[=j5F d^: EPEPEPEP{M:&{h&:Icnucx7Su] #ٞ;{>8I?41\KU2=A@I S[l. V&TqZӴ4\ҙͧH;Up0.~רehVLq4f1;R} bV1(J)s<*szPFZ5+VFr5`H?أiOPgû<+VFr4ejO&c}} b)*wgejO&[׬}} bYϤQ?A[#Q9?YϤQ ???ݞO#Q9?< kx@x@ 31Rx v`H?ؤKh!h*yoYNZK rROb v;[gN/Kg$ }J~xh |7u/b!Ż-lx%]~(ZuӭFخH(qX3֑s,Fu#ڹNod11X40cM zjgWׯ4Ki&t(fXD @> /<5kmLu[CEPRnBsȡ~õ@xكۂ=i ֏ƺ4Vb{縸NJCRU$')Ѭ.1y!yuv#8O FR@^a)v)9t+M7M4{m6\HІĈB.R8^E]ӼAs}/Nmuv 򲡖Lf8n66epv&`KU *o/GKѯ|^+Y䣕+c dk^v+=R2bXmD:r-ݞ>i12_XxNPbKh✨c!qm}xñK*I~NL҈TbMdl-NQxO3nt!<hDz\ZXw[ZNAgwFR]CZeo!vK{Y-͜,~lC{$|b+etDH3ʰO[3ZC\3[,>KxeԮ.kkK*02~^fkx4rȑuV 1IUu?^MZ?&QE@Š(((((?g\A>n(-"IRHPWx 1Mn+Ɨ蚮._m|p#ķ[5v\Ao=Zjcs#Z-ܑy !U0A|zmS=(Gv4)&6Q 9??cV+]sv%̟``%-Ͳ<|0Bg!rFO8ne-lVy'-eD+Ὠ(((((bȼ%ѻ8ك==9k`ǚc?:4j]эST6v_/jaEPEPEPEPEPEPEPEPQEIQEjLǛ>:oPqcX? P}}`c(~PTcX? >k>߱=?ϬOEA;_v@P}}`c(~PTcX? >k>߱=Uy\A4Ϭ3SUp (aEPEPEPEPEPS g);<`W$QүME^Dm;"Uш%WJ@Y;H-C{ O j?'/>Tu gKLCRԬ쌧uyFh<)h((((4[BO*EjY*I'@v_/jycT ( ( ( ( ( ( ( ( .$d SH5Y%{*!Kfy՞.çڋas2qr,GYxֵW}I/:; >}gxvYf`s2q-Ÿʺz.u;B.d23ף8Uq80*jRWgmn-0ɶ1{AkA4Y$7)@o5mNq0j ,8JA :ӻt4M1}Q1IW}97N.ڳRDf=r25 Ua)fx]'Vݥ{x tPn3'ϙN!~ѡxe[y-רFhC~f%̦4Do'̃cֿ+ҤS\}DBƮ@ `6Kqմ p3=NZ{7t?K8$bi ac2O4߳Zϼ?FֳHbx-q" Pyc#$;t+'̫+n*q^^a=Z(=ࢊ(((((,DdY"QцC ?g\Am|p]͌ۮ~|89=5o]zVT-Qz핃ϭo^sj)BB1Ž94emFgEm+#FOb\s~Fkgʀ=DD$gAXSjzEkz5=4]3ċ޿!z̟ F"kp(s#kkQE6$QE!Q@Q@Q@8뗚bX  r{3QҴ/#Py-wo$![GWCEd[뼿1j]эST (((__j6lM}xm[UE&B'1׹}şQ/$v'?5_I,֋&7h/xZ/ %> h(hv'?5_I,֋&7h/xZ/ %> h(hv'?5_I,֋&7k?X{&$,JOL2j<$e $?AAOIy9!dMj^\\c ӸvUh!xEZۮşf͙}/9k<=I?&oC$j>I%ʴ%wg #Q9??oj?']7?!I4cx$U?BχvpZ5+VFr5cx$G7?!I4iOPgû8O[#Q9?AAOI $??ݜ'V@GhտMw I'$x{MST+VFr4ejO&oC$h<=I?&)*wg #Q9?h5W[A33OGߥt I'$x{MEL|-J$wX_dg_K4}şQ/$ nX_dg_K4}şQ/$OkEDGFbH۱+J@mu%ZNokΊed9q*\é!Ҽ} 7w^eیq'9;c #i|J}ek{_"O1HLd-[WLNWӈ &˶"Q(qWח| 5Ԟ\m,pՙGyWqjԺK>XŠKiys;G b$6vMhxNi4"Kea6#,UQi_L:EPEPEPEP7wPYupa 0RP2N&\J"IAE6I[{sq2!hlp< Gt &H'I4\q &8胷'&ycT ݗQEQEg#Io^rk[EoD+EO#(V! QXia.<o[q:9;f0[{(4cRM6c_UХ"oqk ]2 2_s K.OW>G?{Nj/t[5h4t@u7 LiZusms1.Ei9K݂Is {]WT=i$|Xd_t}MFiF_8Ymmۿb2qtɮ~6Ge3!ˈ|~{]9u1|Wm c*ZO{ cd\|o3g'cYfm+UWodK VSp!H|/q'LdCgy7}3*#&_?ӳjz.l.4 R] |`ȸN#ٷsxN ^V$!]A s^MZxk%Y*2my Ƕ3J ]_ZjoVK3,688%v[qFE-wi[sJ8"M8e\1cp:Y-a{+xf,Ve$;v7o-BaJ$\$6pqV?/'/M?^g3lu9DkKk 3Q`K{h ˲W-ӎFs#%x{4sB~HnF`3sĶz]Y\[<\/1F{rH5_;H f̭ p{@.W$*3? 0]$ 2II?V-?Y%.U!vU8/,^JU۩omEw2.Ac1: U9m6[;\O{bV",6…eB3#u5[-ÄrVEYXv!V"+M;XԥM, lC*( {7m iMǹ~a2sPKV$[8b %"t.͸=i,嵱iQ,D˻sXm'wR1<{.,׸z*zmP;cዛo"}?R./$Y%t *MIs]|ya7%y}~Pv𮂏kϤ[\;aHnXkZoZ[n舧d-\e냀2mK6=/XKyaӧKO0Jw 9:bm=?&+Ao<#\8>nA :Jy]3Pn5\d0V=_O$^ OK]fŊ7;w  Y~&~IZKKid;8GLMxNZVM,%]U6 jlCMsȞH3']f K$q~y5sqk@s:~I54&[$3iv: ׍D^c6-9mr]Lɢ.c&]gȬkYudui4ClO//qz-KҾ]G52BG6n~0w2BRax'D/.E-nM $mQ-ՖTp=PvmWhӰoPQE|eͼMwjJL#uz] sy4xH b3ڬEXNmvmWj (i_NmAE;4i_(Oa?Ə;5\ ?a?Ơ???Qp exу+M)7OE((4Eo 7ۙT:> h(kv`a}şQ/$OkED[P?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2otm;VYy`Ŀve }ñnuz$zgA=-B72V}iiW:׆%-/DjX! 垟J_@8m>S LK`J aCӬR 8=y<j6C}GAEEaΊ1FES'cZ8n@H{+I&^[[fZ,6A}A dZF-lj+Hq mM£ Ygƀ/8 nFBđ1 v>WS@}VRo-ɲ]9m$FAc: խŲZ"[U1+I pyPx8mk :ۦc~ycw1(p+3s2,2#|uuv3r>iBM3W2~`G>թkگ䶽o춺Kl df}3{`-mp6 j(]B' P>QM?$Z- lQՎ:s^oj^ѭ443^'tBF$轸s~ԧm_GXfz KPZ7Tt6w7B;;iy6?Y>(^5IbU,3 [ZW_?-q7U]Bř.-+!?\TSNdte7 QH &q8[黟WԣNF$Y0AsۥP/GssI;}XhoEȺky1U: Y>hf9V4/$owp#3J 9c?Iu^_2(™g#j5 xyV!0+ББU mvb|+6sҜu;/s3y{"qw4Iq*6PvJPqЖfY} #c8IV(Zѥ* Q)l|p“η5ЌHlc 4[BO \ yl49V7}ʤ\{W7V5 tTc4/oX`㞴tbꍡa-K kcqE ]6H'\'EӭWݽ%U$71, s*n,\f/m$h 9y#4]zx"{k褗)t r{4z_֣ I#Vb_5KVG7+HpEK}.;;._>[,xT,H99hOaX^M爦Ǜz9R1۶;S0 }3qrc"VcRWr0`dw=1XkjwWnDh 8$-l8dFQ;Cq ^Fͅճ^4m)ȁ`@Xkogec$ktѐ#A/HVٌZkZD6"nF|Lֲ5V]D@-J B&NORI$$wKo(E(((((((((((((((((((((((((((+g)WAcpJDRJ+DRJ*-Q@XVXP}m/mf;e\38_A(:V?-JEYWc:H],q@A'9OV?A'@+Vu:;{۵ ev} kTԮ<`1yDB(e,{SEs k,vRpAkѭ,2hNZҾ?-EWÿ?_K8µ3#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / ע2?4(Wÿ?z(#_K8E|;@ / Ԛhy[lqwlg \ ).B`Muc^hBlX&t6k2V ^q:p?*5kx K[.|=S$r6A WǍ~/zu#R<ihW[`hW[hEolop5kv˫zTQ`\χ>; W iZ553]0Y]7 !vZWcԑ9Ȩi ]mtӳj=|][r}5} M6JVEAO >i?PRQ=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@P}~ZPTn?֟=ۭ?(uAOEAO >i?P@,.-whc8#8kfea2 _V9ߥun?'IO;|ݍkxщ ImiHNw>2 _bx(%5ʠ~|[$siMו9qJ#F<iW[`hW[nEoloqZO]\/GU}:jߍ2vW*>o>tV^yQבGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^EE=k濭y{_ GGTQ|y濭kבQGmzy^smC#.esHK\yLk濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭k(G(k濭2yL濭yͪLk5_ XMUp95w'VX'V[Eolor~? Uˏj?iOgm?ZΧȩJ\Hh=aRdD2U^ Nuny;[ۖH,zUufW1r nyȪگEU~S˔vN)LEq %]zCIC6?סמxgF_kliG (5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( U5}U k+ ?S?hW[`hW[tEolor~? Uˏj?iOܧz+ JǑQ^Eg|̽WGcydHbyd`1y<"F%U¢fj Q_]gh ~?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?yڷGhsgQ^w@-G!tj Q_]>?q~:k xduP)qA5fIh5MXQEc ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( T5}U k+ ?S?hW[`hW[tEolor~? Wr/ZHcb ( zѬȹ׬ )|qA+x#NuBjy zӿjeq[KvQE1Q@Q@Q@Q@Q@Q@Q@Q@Q@4׌2:TidUr֦0*Š((((((((((((((((((((((((((? o_ozMyAJƇ:v'VX'V] QEc[[c[@?iO!k/ZjC$dz#Q*:(LQUoiVL4alfwFl7W6 qpnZDT,W.݁皱}@+V5UWbW_.]EBEWbW_.]EA#2?]uj9_?Ge_]?/ur/ʿtl_ ժ(i_/uؾTQ?ȿ*l_ }@+V3?=~?UؾbW_.QG+g{H"̫}@+G?]ZW EWbW_.]EA#2BUڵB3eb~R@(W袪133 (!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^lR&? o_oa?CTz;}J+|t J+|tZ(ұo-ұo-Oß4Aj/ZjC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( d5}5 k+ ?S?W[`hW[tEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW'I6O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((? o_ozMyAJƇ:v'VX'V] QEc[[c[@?iOW_vԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE k+k4ɴ: 6fg #QJqn_tSU Ž]S?ԯҷJ?ԯҷJ(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((// ]J+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݲ|Jݲ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((/? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݳ|J髙ݳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ݳ|J髙ݳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+ܳ|J髙ܳ|J?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((?}? MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܳ|J髙wܳxJ?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O}O MJ+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܴxJ髚wܴxJ?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O}O_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s^.+kriW[`hW[1 EPzV>zV>sFt-]q>? WmHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\׋kwܴx1@z'VX'VLBEoloq:.!yL Y2 ' rG^,ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG{Hm⑑.2jpkέzU"Y?أ_*z+CY?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?خ2$ ߥt_ [?ԯҷJ?ԯҷJb(}[K}+`}[K}(?tֺB q3,؅''_ι?֎뫘&2ܼe{pt,N3Ku]bK'm7}Ew8T8r+JYbi-3>a=+ =FMYu핲d(NcҴ/.Ak}M?3"&U>a#m<⎁ԩ Am5퉆fPiڜWwVoq Up9Z}WᥒX\Fc@ tUNTk 9yC9n cL] YLEv,? .{m}˝y>TX5]$jֶ-w ĒM Lї GCfϤ]݄G=a4%I~E%}멹k%փ&!d,)@#2:-7 mDWdTX&R _Z]x*[7ڛR\RXh,Y{iyR~ }~"-OiE$:T嶎܁N4DLbyhƒǿJ4>2[Y-ssUfȰ-RDA'~c:,so4Nee9lMҮsSڐ\q֧()F[q_z7r^`!r:-5}ً!u[nO͟ӴiM4<Y}T0h4{?G-S8>U& GRBO6*B~qۊv_~ (խ /tudqǡ5oiQp֛ Frpyk G]MWku)dYLИ9 9:xY'o/JQq`8i}:彨ӖAF6?($p="Ė/=6;r,~8҇=]GO=?IO-Q7,hfaV'rsxY9%n^QA<{u\Pi6zwA6a/2GqkRK3}`{s2#BI\zw͠C{}&&[ $H'uFp=|wFdF@@})uil|:ut_-$1ppx8U|Io%?d:Sno$0Ǩ3TgVƮۀNN=Z>KkSwMџsRZK8O2Q$NWH+Rѯ!BoE=x͍ϩ^x/}XzToi^c_OO\fD_P qEtg ie_^XG5j:$X+{+c֕XZ0(S;qQh>[+k>͛h2e MSVv%;m:}>3_o/˅8]4ʀٓџsXڇ+ϳz7\㧽TjW$fբT4IaNp{Q:->{wW٢:nL5]ۛ˘t(^El)fDU^q O&<]9CJ=*Zq{[_OpI茅Jb:3/FZf*{p!`y+82{USXoEҚ?-Ulx'bܮC[Usޛ/ȉ>l ojCeeI\<,R&s zA٤-pdBiK@N=뚓Dԅŝf-dr+)ϭNxv.lU펞$sܐ{SWo&7rHvwq;!A {Zp H0==[cj)kws rBZޛwB `~Rֺ&dDɡ%$˼X ~@'߶ <^I^ > ~@'߶ <^I^ > ~@'߶ <^I^ > ~@'߶ <^I^ > ~@ήp9FOk~ ~G ~@EyB``p푚e+ҳ!:SQESC ( 3٣ (z ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PAEc(ǃQEz ?Q@<x=PIAet(hqRQEQEnip2-8.7.1/doc/src/figs/snap10.jpg0000644000175000017500000012101713351443023013410 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qquMe6pΐǒe5 ZήwQa*MN7_Te$/k#N7_TeH=-;x+Q \wWfwQEEQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@#L W¼Dk4^oU/ †Պi~l 9]5":+f_t_@ Z˙875LRurK9%2\T$Oz !¬c?aV LyKi͹'MuԤ<٤b;8--.LV-jYۻhp,pq#;32YvqO2)-2t{nw,fd@(P$e-Dd J :hFcJ tEw_,/R:dV]b8}*ٶL}h[x r%~s ݙ^@۾aBCg%l0 ^H4($}j1gcvpXI4H^_0*9㊉di]@Yc6篥[RIii3m;t;\\*#2,e݀&Bʯ!l(ǭ9maX0 ODCkE#`t* ǎ,hZYH8=Ti(UC,NN P{u(rCrEtRnPCnl98) pPB`Pbm1hQ@Q@Q@Q@Q@Q@Q@Q@S fN31ޮT7V^@beO igY z00z0j srirA&23S}r}ꪢP@sJ[w%~5u?ޟ‚(,((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>bum9!ف5AV=?k}qOVe4mcGyG?g[{O? Կ罧Mv[BzΞl?(q{O? Կ罧MvceK]쬿/Q'#V=?h+R5Ř%6+F~*@֟-Q* !pj_o&B/i}]mQKo{8{O? Կ罧MwexQ\ VKkƥAQ'V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!s.to7n,=rmߵ2++#H+ )((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b "ǡ1HG$C+-AOglO+U޲4ãLD$j::tǮEt\cS[6+o҈ )' =ȭ5gҭ5Xu KG`A-g<ץ 1<;˪x~kxuv7c~͕ gk ĹH͔}okGH6c8PYi:BivA1; /vFlX^IZM'44fyy9si:,-n-g]S]t#\moӬqr:Ҷo_%B:;TWB!?88$cZkNơ,uw rᡇYO| kptQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE5S)ڙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WZy%WZ†Պi~l 9]5":+f_t_@՗"D \g e"~\X5]?jUniUVH ]OXpvҥ7q甹4.)OP}23֏"_54 T_ݹY>n_&~ƏE/oFڢ&6[Rh]0I,J$>6pcRg,4%QL(((((((((((((((((je=S) (((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH q}'5`ƔOji9 sFjG@^K\O`fcY.E, @Waz.?ſa3q)}Tf]m ߻[w &Et,ֻ{cA֓{mYJs[*kRe&ˉ:/Ǟޅ=(((((((((((((((((je=S) (((((((((((((((((u`7d>c[JᎃXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH s73R#rd98Jڅ<[Ҩ#&r.:gs&{(ʁo_G/֏ُ/Gٛ~fFw/..[{yYƫ9#8\ُ֧/L73\G|`h%QLAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U tZy%WOưDub_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐I֫`wF@ʁ#ff ="Hq{'FO%ޝ,Zܗ1]#as cEf6Wvur-9BnV NpzP^xI5r\Jrc+?qF.`V&5^7c3Җ= S5JWH̡=5_4bM;R8O,(X$$ 㑑ȭ3yXp$I%;]Ķh[Rez~g=ӄUr9cw8>\NkP_ŵǝ,ˠt-;j( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (L0(((((((((((((((((,.dcͼvkVz~5_>7W=?AEuҥG5+pQDpQVd2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~Uq3 XW\n^AP!)_سk+bORb_l6?OMQύ_liҡ0Sⱴkn?#=QL(((((((((((((((((je=S) ((((((((((((((((( ʹ_ k}ro\z~4A2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФԵK=&'k6rX(& O\"ФFi13BE<~bd>ՆmmmC8uŦgw&jqr)#J-Y)f] nPn_~6=k?N#Xy2yg9?qa~%[ӐZO<>ݸ5I%Ĥ0۴H蠓{7uFiCgpZX;#Ѐd{)/uA쨤BJ)eHzREPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\z~5>7[=? buמ>bЮ՚_wV_)}qOTjRl1Hrrcژm'=iJsҘl?iO R!O˜~D~uvD4V%"ب d c\ݕΫ5kVU`prFI&|3$X"K-$9֘?$oQ u$lL$HyOsFwjazRiש>vg6m H;~s۹ mBy2 zsY+эJKIt'oץbTiqc"\vitBgwڡ+GoVb6͇0sjuQ)+YUcE .4vj(;djj^źerz4a6pGzcI ! UDr~Wۗ{.c{mcl*9'WCՆos:~\wRBnp>E.t{մkxO!7qp_°4zU{Yy#1<|QŶay4O,_)U>)i,욕 qΧ{?l-͆i] ?[whmCM 85oVuku q$'\21!$Co˩[ݪ:(d:X)Oh\j663K9%Ugy X^ͥxq,Fgdn aO5&qjif#kd6Fh9=0;ԸY9y")ڤ?Kc9#2D/7`p}+BSj3Ha{5$˝nMג`8P>ƦNqWz\CMbͼrƊnc|#*y k*M'QL"8(팞5Rkmzɭ; j2, B`A[KTHn ćdcUvɾAERVuƭδAMэ@KPH˩ZFpUPGo$7ls̤} $rdB.2?u1?_? ѿ+ehF_ ?rB.2?='?8/GA A[/I  "#?2.iO= ~nSYsz!y'A&fFp%6Wr0X¬svsľ&xTad ᇥOjRlXMp.HG]g\ѲGC}"?/h?ة> > F~6_*O'?'?€#ѲGC}lQe?Pb,>~c(,>~c(? ?aX2R<*?'?žEڙO~C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (+>7[_ֺ&UxkuQS˯f_t_^uמ>b`@ X"_k"k8ϙ[~`v=9鬿k\SA}k-I:5J#q 3tf줕#>P0wVjk٢a`Υ8@Gb(ۥ}Gۥ}Q}Ro>˩շ?UKs}Gs}G_eԿ*_m~@_Qth(7glt?Zoٵ!/6aS3B=$((( -.YRC}0KJ`O ( ( ( *˻/ϷTK7 4( (L0(((((((((((((((((*5Mu7M4AA2Y=|]ס]5":ӭS[_ZjI~N\hrz9l4bs gEfxFG؃ҌO@!LWu)41DWXm~# w>Ԯԡ2IY:&ټ#i|С^aze8MFO. TeN>S5}NFaL#О?Ma\\0uj@/kdwGtYm5<x=@Y&7Vr)n_v+By /asJCÏ0늮?Bv0TA0wHxОj mnOZsYM,MmnDɸ@g  ohhuޝcr.[1(q?!K߲[$fUT#0)l{k-zVz"nбXk{)]ѝ)sj{/_Ӯ Ibm WCz55LJK+YbI#tF=hj&']ζX# 3dӜxX#x4fO{օݙC'ho2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2Thx_2Tr⻯.Y^$U0]\^ڬ萻ƒ 1, 䎡GT}Fò28r4x<#DMÒcWYhM7WvmO)7W#q,jivA@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr&UxkxuQS˯f_t_^uמ>b}qOU84mbmR8ȞQ?*ԁ؞35rA?Y&Pb~Y}OӐ E_]l\.86X;U|!S,&pHQgg,z{Uf<П("Hܖo?] nxc$8i?Ҧ%| J)~m>[ϼ?춿*+cVXc`h 9J( ( ( !)ddO4q$e20ðb7mћvj(ŷFos?6]:'$2jJ(((((((( 8.yr3z{TQ@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr5>7[]Oƀ;>࢈>࢘]5":+f_t_@ՐNdSA^=IE=.$BYmGB*{<g[`|'\Rer%i'QՏӦ=r(_Okښ[},@ O)O.=PqEl/~\C>oqèJ]&8 lc9)i)w]a)3 A6p8ROҠnMZux c2 ݰ‚q4h5+Hv uj4-/.].06 qNX / JT%?pB2\S5[&\\YSޥi95[̣4Maksi-Jm(h؃\b oO0k\b.ooD-w$$~dͰšmr$ woÚΥm}1`XpFݴqd躭g{}mrgi&Hr zCF^Sv67l(9qߛ'=5N~זo:ꡱRGQPݾ..-`x`L0\c5T#s%Ϲևחh_]O"[fU'>*ƥ։0&' }w kWrew-{gqٽ7wRvTh9$0튒×Dn_,B`}:dvB:K]K LW6q̷dګvOk;#[{-` œ8n{}]-KlҤ#@ʒF=ꆉORDø-sϩ@ yvE~,S. s;V業G\j7W3:EnNI@;%WJy,^NYc3YgZ$ҮuXcR<fBO(uu.bK+˫#L襣NbX{QkɦHikcnFx?ōS\4LHpTrNF+7X𖡩^]iӵMbSӡ1?r,2Ò`0ڧ52 `IY# z M/JPl3ʏ˚H*^]z|-p3f(8M7WgiEh>M6('<0c5+$Դ˫\Dђ:f#T:ޭ- "ܱ[d pן{^_E-gIWla`i0),7QxVbïL^;Z_oH4xT Ht3`FxSN״cYNXճBwi#!vzAwiSA nVbïL^{:MR! $ |p6nGQTt_ULtʡ8N3Z%ͼ,XC>VWXkm!]s~`I$hXi5/nP(*[S^A_(}K#cn<ӥ.vdCyVS#xC 9:sx_PD@1wPnhA;ve֢m5fȚLw01sX%I --؎ﴺ?x91Y[-ޞ\)o:Ȍgv+>qG=*%? o|.1mjN|Vp]$23VI Dz_>j]5d9}~O}̻Ӧmc\wq=i:Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr5>7[]Oƀ;>࢈>࢘]5":+f_t_@՗"D \g e"~\X5]?jUniUVH%?pB+ O\"ФxQ Rn*:U?@n'4M\FWmP0O>ƀ3n_&E۟C/oz[is4!1rWwx`I8C'o[6|nUef,'%QL((((((((((((((((je=S) ((((((((((((((((( ʹo ?]M*7wP}E}E1 Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*R/ JL8@jMR8ELdf~SmLP<1^hR_XJ`KqmxMvX5b%֨'ΆKJm8']mvF-6Iق#1N+E/tNIgl^3铊bBN8Aɮ[Zhϣf7.؄峃iCz_nexnd|@|m$zUgƕɧjivK >]X7[p_,cfqq֩YZiykŜ3a/]kuv:Hl5 'e*3`esץX/n?ޒ3dI^MRWiaDCe9.;.Z>VvW*aԕ`IQ*0܈ixm"dBA#d8qRxPv˪隝6jIȨ\Xk3H(6©q{4dRc8c Ac/H=6@t4oYji\-)[a\6FrBkcP,t.pbGSA81kk[Tf"ӮfMd.wdq-A-ܗmn38აNFJ6_?_нt<.g`.HܯE%οYGoq4B@2}A>Eaê5%;{DFIH@*K7^uJ{k[ْWHbQnCsOo=S\[;;V`PS''4y>w au`R2Aejoc n22?ȹNdX}NnnRU@`iFmPU\]_Ak}&l|&n~؝OF B=MVXӮ f}_͑W -?뗺?pOW̟ L=ȧRi|(RWyXXFݪ:jw3h7zmׁ!Y$]8'oagJĺuƨGo7TAcC 뜃9@4u{IXiIdynXX`W绂5 5Ա&: VKݪlhc?w56Jǥ\*;ȬL4t$S6_9>lEe}s~={uop9mlnU~9R3TMH]6LiR F㸜֣{m~+mJԮc(匼ݒB du?jͫ[N[ih&xpqчQ*u{bOkkY)&{ʫa֛ k{] xLE2O-)*͸Nk;R.oeV;vhNܼ`sGUv:ֱwim۵=VU M,uKk{5V")3sS88KLaA[;ScS;r1;SuiM JyS#к\Rֻ{cA֓{mYJs[*kRe&ˉ:/Ǟ޺ (L0(((((((((((((((((*7u7MStAA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФJBS)*VKZtR!uJ`66`]ρȨM/YDBHA=' ٛ~e(;_kh}Z1%h1%i/4s ח3`Ĝtƴod_iV FN ( ((((((1GS$wtImK~_캗[߃Q]K~_캗[߃Q]K~^&ȹ12F~PEPEPEp f|gdh]MOEG Nt ((je=S) ((((((((((((((((( ʹo ?]M*7sQS˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pBƤڃj7pdV#'Ao!)_J_hs(e4 cRCO]^) q/ 0Y;~[ z]BA/KdЩU$Lhj@Ml=Tdm1,6724ФQ*n&#<SF㺂Vw`9f}k{auq%fUr c ;TY_ Ԇ d GLdu?1v o `q ?ƺͰť:NɧmKqp[nH^VW&Ζmj&kauДdW_][CC7?&_*q];9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕZz]6Hv;A qp{UD4? Bī,jXCK9'kIVO|+;KئvmH\R+?[}&jԺ 1# s3z֮q"9_->~k4hMݩ<ESy|b)hMK:]<E/`{P_2QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\x:/s\W/ῼ?΀;>࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_ z~Ћg'C/ JL qH)"O)8R3&3LOx\quz>_]lu(7]~qt=GëHW'iU(((((((()LlHz629&7mP9oo.ŷSQ@~-3?]MEBHg^@bmg'AߵMEQEQET76N9P* EP)h ( (L0(((((((((((((((((*7Q ʹ tA2Y=|]ס]5":k\SA=Ae _7kV W_OjU~iUg+ O\"Ф(Ѭ-#5Bc[9c1W/ Ji`Ą򫜁}ܣͧծe[xF#;N*Lj1G-E=HL-cxVg׉pys/}.zL[b.K2-ŝ@.-g61K/ass#I4K3:vuh1o ne>\r)g8LSumM_Uyh쭕fx2r zg:dh.vHy<^Ny*z_?KbU73\%>T dGCXz.yk_j)./in~bHcAV0 ( ( ( ( ( ( ( ( ( ( ( ( ( ( (L0(((((((((((((((((*7Q ʹ tA2Y=|]ס]5":k\SA=Ae _6o.tk2*vsœoaS:O5]CۏP;EwᑑYV4 0HR8JTmP*42pN="[ ũin Kw`I 3 *;Eg}+t}+ts~2FOO0k4hx.x.wه_̿Eg}+t}+ts=e|+; ;_ ;_a/hYdi ]di ]f_#F'?NW'?NW}{54Vwӿ9f2FOO0k4hx.x.wه_̿Eg}+t}+ts=e|+; ;_ ;_a/hYdi ]di ]f_#F'?NW'?NW}{54Vwӿ9f2FOO0k4hx.x.wه_̿Eg}+tdi ]d_#AS*ԗ1ʓe~R@#؂ YjEمQLAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UoA?ɿrtA2Y=|]ס]5":k\SA=Ae _((/U_JJ? U-ECE%KOa *?gGlQEfAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_w~jTu~V( ((((((((((((((((*9먿}ro\>w0}E}E1 Vk|E1EuW_y/΀;6EM{kO)o(ǽǽ2k$)͊Mw$~5o^7rRQV;5 l+k'U){5/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/GfA[_?rmʽEy=/^> K!Y6`jEI$''vQE1Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s\W/Ͼ]E*9 ( )e^{//BVk|E1Et\Ka`th+y®?{OxI`TH-(eo9;5z0^DofgڼU@_t}_ Zeo}SE}iϸϵxWk}.)+7?֗Wk}.xO< z=w}iϸϵxWk}.)+7?֗Wk}.xO<e60IG/2]jW-ּv>f8ib=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC*MZ_7N(q/ sj(7PzoUN.^κyyvJ6J(7PzoZ坧ҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛҍҫ}Mh?ޛ>+ol 8iYMrtA2Y=|]ס]5":[H j[."3a2 SҭHFeIL{83X>5DͨIK|I 1ӵ%~u6Wi(<'GPAcPmoFrFKz#i>٪:=if 0wrD+L8ZαbjO 8.p26O'Sꐺ6m {M7?.cF [>٫uw2Bza\ep6L:qA?g]aiZ±Ȳ8RDLmbnlԼS0.s#'k6*1FHs[֓U5KH#[&:Oy-&՗JUqn8#_gkp{ͫ'gMlwMđЮvZI4-#(,'cڲ!v0>TR]OK*@SFoe!$6 3cy9+lN thP4q2"7?6 Ha\m/~c ͕ &\u>G[eeH-Ǭ_9+M@Z.TcpH;q:,#~" ;Gs~5r[KmV?,M. };֟S[,X&y6J: 6/ﭴ)/.9@ Pj[}(2|i"u?7bΨ$'˟'m|)|:ѽAbN|Uqh&!nV_Ij-tecwNL HղO>`2qҐ,yJfj'V:X_vgOíbx9-K`e[%`~_,>uTO7f͝<Q}B;iV7dUvT V3U$ w\5 jaR[%+HQ3'uM2 6,.!Uߴpp63֗AsRVtѨ\ m0 GN?[Ivic7l #Vs6_[jY[E)LY9ڽc֛]Eu絿ԆKRhž*c?/&Qt:(Š((((((((((((((((((((((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mc•~" qn?zMr>\;Ut@6v59GOSQE0EPZ4@ƃ FOv;G5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5J<5?p~UkGhiQ[6֢ 0*@;S0(?nip2-8.7.1/doc/src/figs/snap9.jpg0000644000175000017500000006676113351443023013356 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qquMe6pΐǒe5 ZήwQa*MN7_Te$/k#N7_TeH=-;x+Q ԑE. sD0vbrriZm Xôo?He7}~ntF$d{ЭpMu)ۙ|KI#Kd *:a dDL۝2q Lw]JC͚HY(ýaBܱq"oR֮5'r2:{A3 %is"]c,wGz}̖oMN8VR$F@ OHDf= =?WAtWy9%!#?I{El.㍠p98ҭhJ:ʻnnO'օ (IRXgG2 -ٚ5 z*-$6~xrZvʡ#BRI֣p,F0aOJ.J.9 8H^f=k/nzU*y<Ƙ.;ӹqC*¬;3"Xh jͤ-olŽzӖ J :|q$IAIt6 PO2==wLr@,xRƅ%9D*`ߵL"T8 o w^N҇$7$PwHE,6Y  ?ld6fsšl(w AjeT( &*jɋɳi vX :V'pчh?tV^@beO &g$Bc!c<8''ުIY ˑ#P`u gW"TP0u gR Ď(((((((((((((((((((((((((((u`7dV5`7dXP~:_ ?͝pQDpQ] ˯f_t_^uמ>bum9!ف5AV=?k}qOVe4mcGyG?g[{O? Կ罧Mv[BzΞl?(q{O? Կ罧MvceK]쬿/Q'#V=?h+R5Ř%6+F~*@֟-Q* !pj_o&B/i}]mQKo{8{O? Կ罧MwexQ\ VKkƥAQ'V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?h+R5G{('!ZK{mwE!pj_o&B/i}]{({O? Կ罧MwtQ' V=?ko%ΏoqèJ]&8 lc9)F]S[è-ݣ>>~l\I#zC\:v.5 `Ӯd{ ?U<{S[C(((((((ju5P(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9]oF?*>ՍoF?*>7莬WO+gwQWA2Y=|]ס]5":k\SA%XJ+8^X,k\SA=5?j7kV D*uOҪZ@T7-w:3Gl~)<=٤?qM V} qִ~?fwڢs5H}e4}/Y3n_&4i/*BI`:V!w<ѳ9`@ɠ (`QEQEQEQEQEQEQENjeQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WZy%WZ†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Uc?ݶѭ[4}-sVIK3U<4zJ]Z{6*r.>x`8LrG» u-sᛉMݳ6Knv8t7ۿh_A4/=fRMUȊd N=N+rMNQE60\)31)aNd`sBFutQEQEQEQEQEQEQENjeQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP+y%WA0כ2U tZ†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@S1)$*V,FA4+0ϩw>>k3@T }Z>e?ֿƴ~o>7M3e?ֿƙqw̆5X1@:>odѽM0 r;s@(b ( ( ( ( ( ( ( kS_2(0((((((((((((((((((((((((((iAcՍoF?*z~5 # Ar Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnN/vF\uH42T 31IJC>5}^).` cuԊ+7{lrpcК6OٮU%ݗpۖ=XSH1sv4$Q'qZfWԢtFe%FO)/"?2iڔ10ydB! lEo^&F[$5O,pDy_j/_%B:+%u3T 6aR@nj֮:{MZCpd[i9BcEPEPEPEPEPEPEPM~kQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U jƷ#L _=?†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@R;n&s+ jˍ<*?%?pBtbelILKFٚߕ ?4+P_6>t?zT1fTٚߕ |V6>m`$`Ҁ')QEQEQEQEQEQEQES_:QE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@#L _=? xZy 'g=?Μ9\ͫUSQKwp}E}Ej`2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФԵK=&'k6rX(& O\"ФFi13BE<~bd>ՆmmmC8uŦgw&jqr)#J-Y)f] nPn_~6=k?N#Xy2yg9?qa~%[ӐZO<>ݸ5I%Ĥ0۴H蠓{7uFiCgpZX;#Ѐd{)/uA쨤BJ)eHzREPEPEPEPEPEPM~kQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\z~5>7[=? buמ>bЮ՚_wV_)}qOTj]Y :j3n4aJsҐF?MGZ\LU #R!O˜~D~uvI%l;,Q$ΩCcq9k٫EeCc^M/kaW_jY_rh7Gt¯բ!M /? o&k=_qEeCc^M{ V7G$6?ܼ)=;ƭ /? o&HlyS4{XwA*+Z++^MrhUWVW$6?ܼ)?!Ma5hHlyS4CcúaW_jY_rh7Gt¯զjúM]tg ?#MN2ٓ*sM)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\u7M((!_y/ν Y=|]ue _ /EO@Q@Q@z÷oBO[yu8IEz*UMWB/~)*_ *_Tk??Sb(2 ( ( ( ( ( ( ( ( ( ӿVqMng/ԿEUQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s\W-]M*5h ( )e^{//BVk|E1EtY>*zi6?SR-KEEERգ̰HEdX۱*+NOxbYZif%e't4=2եEftTdb$6MϞ5b->sS__o_&HmS E9/ /G$6MXOW|?o_&QEj+Cm>zK /V(5?!=O%h|?Qi? Ϟ4Cm>zKՊ(OHmS ?!=O%jZ}$6MϞ5b->sS__o_&HmS E9/ /Ps$oiaUۜ{(Qw`5kQVfQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr;>࢈>࢘]5":+f_t_@xEMPǍqOTԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr4AA2Y=|]ס]5":?*j7[}OS ʹo ?@pQDpQLC.՚_z^{//7[}OS ʹo ?@pQDpQLC.՚_z^{//7[}OS ʹ tA2Y=|]ס]5":?*jbЮ՚_v֟m\SA5Ci6?SRQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@xEMPǍqOTԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\>uMo((!_y/ν Y=|]Mq.0c !U>ZC%Q"@np RStºyyjW-2]iSVoOK?>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? z>)A>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? zrٖ8u%;?>~fWڼU@_t}_ Z$Hn}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?+RjvCy~Y=sVU4}MkXǕZ9.ysZޅҍҫ}Mh?ޛY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC.?ҹo}x:Vs~D-Ͼ@pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5\ki_is0R R4K0WQ[$/Zfp08ϥTV5յ,@iN;('>_Qtiv/6ݍNXPOR}+4خ %p@tFX@dY)"&`6gi-kYOw\|jȆ]p,].+^ K[ @J. |Ik__1C3XAr]@9 '}m`+ QğQB\Y#tJ8yD5+ #VΊ7-Ğq$8[K1)twPQtыiXc}._cyK.PU[lUIڹEjW#cOԟA#ݼi?F$wRH#Ғ{Z( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( 9밮?ß}?΀;>࢈>࢘\5"S4νq5e`2Atve?tvvO^wf ioTug}3OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OJۇy'ڗl}?@o?I^h>"4kp@$o7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 U1=5upuV:[}ևhcPH<pQNaEVBJEh r rv |5?p~UZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZPGWe寥ZP(`Wc寥ZP7mDaElZaN nip2-8.7.1/doc/src/figs/ir4.jpg0000644000175000017500000002555213351443023013013 00000000000000JFIFExifII*JR(iZ)( )( 02100100p4C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222224p" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?GSWa#M\El 7ddu(9s4dspI u=I LFp'o{|Hdۯ)>}BDF,r@8T5"["o[>gO4Iql-c,[l aޟ_ŷUDd=>hϙ?]e[;u[-ړq+R*|p@<vJ#.W4޾[zo&-Fi *(USBXO>\Ɍ~"2ЀH?\?_-xrI鸕([Q5R HȒPOP* >@2܌cP*y$T}?w TU_'3 Hϟq֠ TUQi] >ȟ߻P*#[lJSgw?f-#!=h}|@(g nԞ\bV\l ES4޾[zo&%gt -,u̘H-#!=*٣Mgp['W? UF[or[ )>hOzo&me,'d?JESAh4޾[ U?Ð jOMĮ1JЫmKu¶O[?_-h}|@(m )a<s&1R x{B rh}|G['W? UF[or[ )>hOzo&8pGj8`#QK<*;(Vޛqj[λ<(Ңt?€4<v/7M(t?€4<v/7M)Dq8' e[;tFcY;lc'N? YFDj>jEV[Qk֣Qk֠ 4UoG=?ZG=?Z,Uj>jEV[Qk֮w^%écRnVmYw1=(sσ?r_>O:+/KVѬH$H.u 3ՁoxA@$v.QTh4޽[ U?G>hCqi:0FOjzo&GES6z@/vi7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?7M(Nt?¥;k|ewB{/c\Bxd0v_ҘM\M_+5q68[ yÁ5o+:'t ׍-EѴS?kC$C9 ksj B"+rXC`FHnAz>pH0QHeӱҮ 6tU5wsmA1š<a $-xVX!q#1ycj+Z\p `[a>bu^iwx7# $%Ew3nmӱ?Pon4Wn/` d>n:.獿?MGq/n]6k0_9 $RJ2 ?B¢ c2nSN?4 ^w%!nS:P鶭<=`?$+o6?S%.r"B[.{Y[kZkӲbB΅##*f~{_5J>G1v[=$իFo*FIy`Ӷ7g5SL+GhFX\ڽ׮ζfl$W%{aj4v<>;af\DjRp[Kxc.8o'#.GK$ï?s\y3% d6vi{K68^P)9$"1NrT0#moFp2 2xVlEq~6TAd Zg[: ]ƶtkXL-Xp܌JWmřO0uAM, +g=㞜ՋFo+{.fFqcqg\ZZ݄ikfvuQ8^qsyqMaˑr o۠DWے#o;u]=wѦE,QGSU \\yPbpGީ7Lb=L?!=8\'ԌzlҶ," x2 <ƕާ_c3ܞ`k2>:8^ְXm1,85 gН(8tfO?*<` qu^us[[K[&+nbQ%ٝve8o痡뺍c Kw% 7.X8'7`y;ۼ Ἔ\UGRlda`p2p:{viw1AuxHk b9Y~ *j,3 /]HH2EԏA"b|3G\. lW wWlJD*4&r{&h#EpUl=vOR[}fS{QQdh~]TnQp= dNL @1XAXRi.|[v\ 9e1O@ =a(PH 5=~ҭݥDv!\8Xz?/wyT6ϔ:{]U|=6%vJ/P g5Nӂ!چy7A7OXd8C4湋fԚ=h1 o0Tbpyc6^]CȁaaHTEQLG{z>D:x qcWӮba7ːr8tϽ!V֗0Eoî~p^\X=ۖvrbW+>`^QR`|Mg#͡.w2<gz>hrKq ggNN̗ST+ `{S=smM.^4kAʜ-_ΖOK{ud|DڅLBCfxxwP3$lVR8;LmCxhewCoZ&"pq p`GsKv_c Fq?jЄ묿SbDDijs:2M]؟_ʪ+7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*}%ŤYd$c~`~U~jlo@W+V>wBk/c@j?ꚸ-Wmj,o`lNSҀ:PؾSmY5֤om{Wac8eu nMqEE8?PTb&vWwkk!8Hw+ǽli6ic}5/S )a? =rO_ƀ.Hl-m溆8WUs'֢򗵾 G?熣MH0Gj6 <1cEusizN@>$Ͻrzd@-h8 %?RO o$udfS]: ?熣U:@nl'كOޒB -}x┠ıGdic+-ϱ2=rO_ƣ򗵾 @X;_T7dd+1Å{wQT+K*r$f.pO:BP TFl *=ǵ  ,^X_ih(*=}6msp:hH5!Fjm.AOIϽ@0#4VOMGϽNYJAeq(N~4)GSS<[kky{ƀ%uX%Ulld4^#DI=6ms{NΥZvR0AN+Ld[v_8߷b;ȣH"Hc`S򗵾 G?熣⨸X|nz{0KnؚsϜ='r H\FigwAɹ=2 /a&;3:$rXmI$U( GQuԃr6FI?]_RokYf/j0F D3l \o7P_'lRۀhz+bHŦ,ہ~PX]\^S;nؚsϜ='OAg6?>j)q3k;܇T~P jHwu 7r6FI?2-;!;$h[Xo7>CHЭ12M4cjo){[z,? yCxj?_*(Z0nE#+c'VŻbk>p8؟jƊʜ#}pIˉ{Y7&8"Vmu+Թ_4a%#砧j: ZM:FqLu㠫>PQTڸ&֨uԀO>$sT+-ϱ2=rO_ƣ򗵾 @~@_V] H ykRd$`ΫyCxj?_*cEusizN@>$v׋|q?,.渽7,A8x:ZgwAɹ=2<5/@-- !"T`NFݨώqj}\#P!6Gep9$$RO$Z\^ ̐2yp ~K4>zD{zwڤq|Q4\!yI(j}.?EVTq|Q? 4UoI>j}.?EVTq|Q? 5俴?EK^?w^ƏũE WZ*ସ;aoJ;緈_jP^#b; |2Ā$c+K yior,+TXJK{[tC*eUB){[z,? ԆKc/_/)M,-V)`:dcv<5/G?熣Ԗ)aM΀qQZiZxaeemmynsQyCxj?_*( GPvVm N*](Z*'ɳv1n1wQTyCxj?_*'tbߍD*84CrYH>`c C[ Pfn pȡVp`Puo P,qty@5gSOoU>'>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[?45Srϭh\s|_SOoU>/>? ښ[quo4syrs 60)k}nH׎ZuSfYJGe+V>Ejl?pQE UYlX3liM1J) 5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm"Fpqfw=6G㒊5ۆc3ߟ?_iM1J([Hnn1~~r-k 7gso?t~9(m#]i3;}ȶ4cMx䢀vzm5l3)>t19ᤍOz9(ofYJ(#nip2-8.7.1/doc/src/figs/snap4.jpg0000644000175000017500000044632013351443023013342 00000000000000JFIFExifII*JR(iZ)( )( 02100100w#C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222#w" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(;mSL;6ZV\̱BXOpWwf ?f=K_Z<%?,g>]_ZOZ{G R}/(.G,g>]ּ_Z_ZvyG N}/?E=}hּ^?.Zvy.yG?!tӴKp=k_Z<%i>^?.^z篭y/-;O]?!tyG?!tӴKӸ篭zגӴK J}/?Jzמy^K J}/?G-+O]ּ_Z_ZVy?iZϥC篭zגҴKҴKp=g_Z<&i>]?.>z篭y7-+O]?zϞy^M J}.8?hϥE=}hּ]qtѴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-_篭zדѵK?.Zwp=g_Z<'k>_]-zǞy^O B}.8?hZϥE=}hּ]~qtеK/.z篭y?- _k>__]<_ZZu}E B}.憎.yG-]~qt\X֏=}khZϥG- _篭zדеK/.Zwp=c_Z<&k>]mzϞy^M F}.8?hϥE=}hּ]qtѴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-+O篭zדҴK?.ZVw.G?!tҴKp=g_Z<&i>i>zמy^K J}/?G-+O]ּ_Z_ZVy?iZϥC篭zגҴK N}/?E=}hּ^?.Zvywּ_Z_Zvy?iϥC\Z֏=}kiϥCi>p=k_Z<%i>^?.^z篭y/-;O]!t\Z֏=}kiϥCg>]ּ_Z_ZyGԳK?.~z篭y'-K?g>]_ZOZ{Gӗ⭐g{Gp=lH 8כ?4뤷>LOA8k@("Zy&&6"j7K-cG+6|Ck$kRKXꗉicOp@@ IUxZ+}7zw9Y\ZB(c=G =8,cԷu2ClQӜfg,vs{KHеq0vf/=C+h OS~/y>n+z_ϧquuqmp"0=ycZvܛsO_g=ܖ[J@)'JҒm:;7ق.}1p8py&x_^E*pї;WAjĚm.[KIˈr\G&Kv9 }& ʶ@$U1(ٍ3d`73J5jE$Rpk-@KOhvncFd7 Q}N?#Q%yVYG1N\𦽦YIy{46{ldpWYwXE]Tsorڅ^R۷2|(`Ǎ6vxgC;?(0HH;aA''AG=MO=gFn~֝ͺ+kavo0nvqJ}Bz^^Dlo&Hr}H=C n>`_yڌ%0C3j=: N][NL'in\r rgk]]~\g?0;+Ⱦ{5-RGp{o[Sp֒C5GηƘ֬A!(`^EUB0)8 W83_܄hlj$8 BkGP k[76+ Bs֦_㶶{Vzޛa6Xm˱S#s=5_jm-dkYu֕v^B(''?9 vz, ZV< |vZޝb/n٢8S56K_ҭB;9 ㍻Cӽ.[Aͭ-v.x. EX}Akc޷X6Xm˱S#[IsewtۢZmw;exwW3=ܽI5 וBPNxPn47{<袷ݱXt9*@iL }3^ . lGwlρhfLM9ΈtR9>si7do? [y3HdR=Hc/=}dnݏV:_|:S`OX y$myqXxoZgӥaseB:ZZewi*=.<J/Wŗzcg^\u%9].rua+G2IQIjw0YK{K>s|b7RO]iF{X/48 9VN4(a[me± gsu߽MV7Uu-nQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuKk <=OVZz$̫'?Ҁ.7o2tV$4S4.%VS9K8!";ՙqq2a@ b\#eΟ76FUאڵ[5=6\-FMU$bEF[Ҽ5uۭ)ms0~5\(&2Ź82 S+fV#fv9aPc1?QľVqიIgݹB>^>yeM^cu{߂.t[&9wԜuW BtALz"9QE21E0'=+VRJ=+VRJ'e7uv̪2IDqFRm;t1h&OCHg8@2~gi+Lbibh\nתYS.!ԻRTu'.G tiP4zesRZ-.XvÅq$UpEMhx/v}*WpՐGr\qJo-D %D:.z~x-7h\,*H98(Oj7ELӶ8=q=)RJ=o\xm2klt(P=َMsPE'VH/G>!AֹPFPGZM-bR ҤX\͞@>ՑEik:D2',Ӎ/$m9|sQ<: 7S(' 6y #9ϭ2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(u2~7S(,It".Br^j1H9R{P&E#ՆO}t,Uh (5I-ؘ 梺&ǘ~JKڛ^WxAV J bF[QmQL c[[c[@ ?-PdFK-i:%Ӑ22W!eN{37&:&(G4PtI?ͪj":FI' )8v'Ү6k^= Dr3*1@X/͓+L gNʜdsj-wRKi#*јmO09& o3GHѣ A3G<15hdOKF+6йX&4f0Z[CFPΥw-\Ν^i7wc9uLai3N k{DFec 7$X,pr@Y\rsS9\ܬL\!PҊF?xW>5Dȉn"GeS+YG#5 KX&3#s-,KąeKhXqY-חR9i\OSQQQ4|}= qEl%\~_\ kmeB餍tCo,/@qָo'I3 )p>]'ޭůp5\X\4jȠHq 2e؛FKKnPX@9#8izC]岶iY݋mPHubFq9sW-v|BΫ`:|`ccxTH%h6]0##&]N~( ((((((((((((((((((((((((((((((((((((((((((((j O+kھ&hG[QmQL c[[c[@6YCe?d}뻃ʝˉ#PN21xJrBonOy` >$$dRn;?&(a1m*Oaak-Ƌ끏W|0,W^]>KHV ̙$9N^+y:foP0$m/:NŸf;w;g4Ci7@݅krW &Mb-m$GeJG \)P^xۼFVx#6r;m, 9on1s&pf9%ĬDX(UԚζнiC BɰyRu?!muoO  8"a1<'mgr\1o  QKh7=qm&wBӌCAa1Qx~T a<+amV[Xom&-TiCAG͐pSm}-em I &)LiS5 ,:]٘ϙlAz4ѧͧ]i.,]D0T7{Ǔa>L_ 7;]acn2  Fj3 R)hĖK( ff-/4oh2k`mxd"8+O*+pPU[~\C\qȩ*29ߐu+jh#U2-Rf@gYY,]@c7699qXR[7!lo-yiob iN (`mc؜>_]Z,]#"fr3~RYaim6Tb;`gy0Ogy0Ogy0Ogy0Ogy0Ok{_,?ѩH[=pBqIoy.>4geۑtk$K#p4X6FGnG\ӯmƚChErU@,pSTu7Wo܍ÀI%UB 2VܩBi7fLi(0(mwVOܒH~ETbHKEQEQETbHKEQE ڐ@pKEQEQEQE U X( zrih ( ( (č#,H)̄(1(cXAQ@J}QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVR;'ʄ~fqsZZ]8I)K2ztֹ&i|tua(  e-ޙy7qu*?bO kV^G?n#[ K?%Darʖs j=I^5_񩠏vޒ?RvLr+KWk[ElgRGJ%K=KWH[Rp|]#mẀAqKCx"W1/ebBfU#nA#wǸvPhK `l+zT^D" 1즹TT- 'i! sK[ &Y؃q(< $Ӿm|#<덹|zWB-կ 2[!TD8  8Lkڕvc kkEp/oΕwXon=jeogeF!E]NXobzV>zV>h SŒmQrEu1‘j3_%2*I8mǯ8sT}"#f$UT !}O(Tq|UO=GxڤK⏵I>M9ހ:{/ K(Z2r(U&aIj}.?z߃Q=G~?I>j}.?z߃Q=G~?I>V$QYQc,NgzrsV&Y(UG& VTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?!M0UQN>tcDnd ~'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*[RϥGڤK@'\}O*!'rRs?RϥJjdxX)gRĜgGb)c*#Tq|Q?>Ǩݿ?Uc*#Tq|Q?>Ǩݿ?UcGKcPj}.?>'\,a F%XzH?5%VTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?4PoI>j}.?EVTq|Q?7p]F̣@20e<A j}.?>'\f?RϥVh j}.?>'\f?RϥVh j}.?ɸҾx&U(Z(09qk~?RϥVh j}.?>'\f?RϥVh j}.?>'\f?RϥVh v|ӌrZ/Ff\VƧu]-Պ(V("XVXP+g`2ywN49ٻv.3\wfkY(B7+223!sèoF[c88mR2pxQ߯ՅA2ȃ<}hI.!+ೕیrxϮM11O SxjK+?\yH3 Aө'>l\#oV4z¿ʥ|9cܤi4u&V~ؐ_}#2 ~:i'NH-9b |g׎/uGk=,lv;7 `cn ^_Wru[* ﱺyf@sA։|U'-$cu;7̀nWSq>b}cx6zQ/u7k=,lv;7 `cn (ﭿW:}SA7Uoad-=I$&j wk [F$e=e{ip6? ]Qtgi>W__][KD7??&_*9q]=|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|2&vu}E ]Quo-|eKD79q]|14n_U@K$*~lm'?_K. FdS[  OqY6,H2KsOZt- /W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _n_>K5wq"y|I>/W~_(Ƞ _nn_YDGBs<E1SS7V֡*Kbe*:FSKqYYk0٨-{slm#hGkZ|U.I3 ]]8rAd#.VIN <зq?/o%SV՟[}+E͂\%bI )'i緡-TMkDԑ b0 ~5y뉩I{5b0n21ȭmKMDQ̂0'4[ EPURm7jX";kz?nZo՚]" 9"jͯӇt~7S|憎?3+/.%ϛLUh/Xr⻯t?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.L?h/G"Z'Qˊs?_?3+/.KV)#! ţœpxlDO `Al1Sjj8FWϴl۪@u:ҨGr` wDTV#Ij憍]V 5yej?zV>kFiFxȲ̎ppA=wY]Cm3ܖBl~B7^ϭ7F*[[1m=o?&hIg+HFp3ߩ9BVЬ0<% ?Ex ~g'w1>&hϙ?]e[;u[zo&[D[otzbX/̿oo.hC3X?!Ih}|@JWSp$zdU5S4c^M/D=|nh{7G٣M\ hmn@W?8dptP* >ȟ߻P*#<ې} cQH-#lJEU"~?G EU$[wyQD€-QU~ȟ߻QH6Bj֑"iw2f׿4rh}|J--ͺV=1\b-U !nP[4޾[ o98==F:M/٠ϴO@f׿4}?_-*6X s !nP[ tU?G>׿4rh<3R}?^M*٣M(6X sET6І*%fBl~Bzo&.QT׿4f>>_0[?^Mh}|@("|ۥc3(6І*%fBl~B-Th4c^MB2}"-Ny=ğjU{"F@V9G!Inq0?̿oo.7'" /̿oo.7'" /̿oo.SPfc ?XhqII9'&Uj>jEV[Qk֣Qk֠ 4UoG=?ZG=?Z,Uj>jEV뺵~~S)g9ǨNOjYJ8Y=Nyӗ,fwW ։[⫮kHK4;?V>rWVŪ*٣Mf5rh{|G٣M\?^-h{|@i;Df4xGޒGd̊EV>UVAhYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?iYnAQ?i7?J \fu$0Ox.p;V(Xc[[c[@fk 5"+3tvI!_/JcK ʱQ#ʧ@H+tb7336rkODKּ<G4|6$swc~n|ֱ`$ Ŷo_gDT>$:%h[Fldz zn}W la15->9&X^ge}Iŷ^Ny B9 sA-+&IRw'w<`E++닧Q-"" ǻfynggH4hpxQُ?Tx͌WN)qۻe+gh*}4@y ƍዾќg؏Γ̻0M흒EA6۶"v֢ݥ,f2Wkcsmkʲ٬`T`S)SO?TK.q$_" (#k:IN~\ #s4Ƥ20(CE̿Yv@\*z TY4rJ1N^>fxF;y&OjӨ1-QIz1/f^{_dq/ʇqO5~#ݏŰ= Ac*k=.?5m#8I죹 jD'K^5Ҽ2IJd)(9#Siu oynʒ'??y!1RMZyⳑp`0 qw#G#&u‡-K'GGo{M7>n4ũm^wMF8y6)ֲnWP@}:U5y +4jWG{R̈p[i8|hl>jtt+{mb0I=jЭZߊC,Ӥ{+o00 19*k_Z\^Am-塸%ak q-Ľx(-'nY2Usө Y2Rog Ahdi#S)r+}D-H,%CFOaUy˝&Dp"lv 7?^iT6'Ͱ xYCo#?7kD 5}&n$RIG=ֶ<+pU`mݺwEvcGOgSj4n7ϡio?B.umʆ[#}x yrN;ki^Ie|f 9 1{ 5vcGOg\w5N=nL{Y2NX8=I]nЩN4/5",` 3yɮ_iBYId;o!1$U?֍"4kY$(i2rp j]Q-6+kiU`T@c)%h8+!J#6Qcsmu;KEy5xEJ0pns[W:u59X@.]V1)v ;qSZ^W%_cP-nⴸ_p*IɤSҠK)|lPE'&_ZO-:\"%I*(Sr1֮ $N" J #c>Ryy ccdxѕ"ݤv$DV6հF@8=EbƳ2Dll?'zˎwao=(EHT(e9uku?կRC ؟_ʝE1 ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@ ؟_ʍPv'bq*u݉؟_ʝE7bq*6'Q@H B9l g1θB?ٿvKG\^!KΐEzV>zV>kFiF-g<ڰ|)R GKTO>7?eGqet.D" 2pz Y?<<5/G?熣B[:jܧB? q Z^3BqS4U @ȋ"qi 4^Q_CϽF>Jʱ@ޠ?Jd#j%rEBۛ !f-KOR?L#QDXj ϽF>Iyv3lF8#`^oOe7y{ƀ%OJREn@ y{ƕ\%aж@\6ۋ2H#_薺]]y@Ioݶ 9#_\թ%3FRK)OPRUX20AQ^?:yi@o( GSUA g M'f&o'L𶟥44 )cAG~EYV=Le?]fREQ |S|2A ;(ׇoZ Ѽ &9o~*|/nUA qǖ?熣UXmy2é@[R6Pï_ Z^3BqD9sixz˦~HX11N(`cmP8q~P_vom^3l1jz|:m֌`òUVֶ%Λ eDnLܻ'椱y'ۿ>_( GSUA g M╺'of&eK uUa&w}j9sixz˦~H7QTA&$M'*a0y;8<玦~Fߵ?ϊoQU&SMJm3ƗI E"tak/K֏ܽƛAk+ RGTXQTYu\EͿјȚPGj$㡐鸜Q"\^+2韮3@1x'D76mn#ǯ>rIT(*?熣xj?_*-[r EOxn."A,l j8cX㲝Qz> RF)"kVfU-PGk8Ғ՛sB09+94}_ 8>/m;dm7O0Mj9!Xpc֝4}_ ZmV)+yp $:{H++xa%V o[}O(Eqn1>U>Tq|Q? X]I9 u82{OzUTPP0U'\}O([RϥGڤK,U'\}O([RϥGڤK,U'\}O(0kWׯ->/ݷgv3+-/;חTU;7/Z #+-ř$\ Z_uowILєvSt'K S:NM텭_g_LI+x籶RB`T^XQUzciK;uA *Ġ_~Yy}M @( GQkimcgkyc3Qi:C{aktS;|U2*?( GQEҤM*>\mlS=p1jgkgkmokK j (x{[ݒIO@<" L(^ZIu8 }AU>'\k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4oSOoG?ƪ}_ k}n@44jimj[4g X՝FX}~S\~!Kκǻ||ӌrG.:wv[SXVXP+gVKHW䃟p69 ?s?[dl-nDql.?!) 6ݖߏOEvW̐ď$&PsяOA1rM"^3-S '(lndޝ>qхkB۳s]H:?1^]+nmΖ) Dau'sscop˴mpօg<8u}t`kB۳s]H:?1jօg<8u}t`kB۳s]H:?0 > K* 0gߚ@ZжR/O h[vss]ߗ?F-Q@ZжR/O h[vss]ߗ?Foyq `ֲ#J+jUkB۳s]H:?05m9.w~_xEUkB۳s]H:?05m9.w~_xr^F@7QĎrc?X h[vss]ߗ?F-99ԃ h[vss]ߗ?F-99ԃ{PȆ%ITPU nyqu օg<8u}tbtNcȹ;2cێF&kB۳s]H:?1S ?:ǘF]"}~UYg::\жR/O h[vss]ߗ?F8~ut%Q0^PGBH\5.@/>J  D{ t$ []M#kB۳s]H:?05m9.w~_xuz~s{(cM+$($ߊ@ʭh[vss]ߗ?F-99ԃ h[vss]ߗ?F-99ԃzm{e%35 nyqu օg<8u}tbU nyqu օg<8u}tbW{0kYDO%Ï4ִ-99ԃZݜAwыTPV-99ԃZݜAwыU]/#}Bk ̊(bG9p1Ҁօg<8u}t`kB۳s]H:?1jօg<8u}tb?9L"eA(1F4+&1MR}.5m9.w~_xжR/OseK^6qSGg皭yw{᥆XΝ<.$2*(`럺9<:Q~v h[vss]ߗ?F-99ԃ}b7:t8~8V#ú_^^EUO3EW\ї1ڝ}/t3kB۳s]H:?05m9.w~_xE!ZжR/O h[vss]ߗ?F-U{>PM+$($ߊkZݜAwс nyqu Ū(ZݜAwс nyqu Ūq2[;#Fw(] nyqu օg<8u}tat=6bdQ"`#J@ZжR/O h[vss]ߗ?F-Q@ZжR/O h[vss]ߗ?Foyq `ֲ#J+jUkB۳s]H:?05m9.w~_xEgKC9du2+9:5m9.w~_xRiZжR/O h[vss]ߗ?F-Q@ZжR/OCs%h/̣kݎN?1\_kWHem -99ԃZݜAwюJ)u/ 7CQ)9 ר֘w_"LDd)r14}+_ZݜAwс nyqu w_"LDd)r15Uty.&[#h6;KN={KfZݜAwс nyqu Ū(ZݜAwс nyqu Ū K9@ kB۳s]H:?05m9.w~_xEUkB۳s]H:?05m9.w~_xU/#e1V8]m9.w~_xжR/OZ*m9.w~_xжR/OZב}졚;xW2HPIǿִ-99ԃ$1rAwOOO[(6ŒV'o~3R7݌ϸ~1R7Xobb,olorv[.ݸF6\~C:W%gIĖv!$s1RzmAҐΞYǨi6RX"h+hz|Ώ}鷘K:|1*vFGִc]Dv\%XpYԓހ3|\K+pF sVn8^{pGUN~?5y2\usY[@u5+ /\k(kKܒ3Tf4+V4~? ǧXz柧YEXX䐠u7?)yGۯoxWtBEfƐ Te?+zK6z^eE`USO|ݜncSӿ^z#F5gb+"I֢K[-F?OcnK-5k2_:{~~?ټAAM;ǫ<)~ڿT yXVG34-r{SV-s(aSӿ^z om-1ES,-|<.j= izj^Z͖(a#ҧ7?)y/-{2Pw98nʏCG)该돨Czuk6(G{P?Z ,[_zu;W/٠,TN+mmrz!:RD=(N}OoSN{U?:\,u iv.4r{I_V m)1 (aSӿ^zٹRJnG35hqjOK5Ԍ1/+k\K/\bV (ۧr?L-^,>#xQ2=yAJ ;V% g4;[W#, 3nMrMlM4A\G#8y'iεn"iZ'ZQ<8j.[?;p}3\r%ơ,c/\4)ukMqf4Ʃ1_/4'?8>_j9>7?)Ac~me`bbB{B}׊͵qf }ƨj^!ס[Ԃ@o_f4,tsOլ V,H[OrHP_,OgwSnF>65Op>f4,r-ZK$v˻92ƾMo9Kk>}sT?[?ƙ֟f4-r{SV-s(a_25֣O4HcgRf4-r{SV-s(a_3k)ƯxYbg`ټAAM;Ǫ&,Q=.F?}?xJZ/?!ƣֵa+ރӿ/u\p}oSN{qoNa(|au_<\uk}E֭_].5 t/<6l}k](X}oSN{qoNa(|au^]%a'n0p%8ty|sJi9w=!4 Yf$mNA9Or ޕu}rGOf̩#!O7~x5 w$#=딗ZFQuKݻ;Cr;OV]jyG꫉G^99oSN{K5 >]ZEqDt~5#R[_]i:sяsؾ i/=GټAAM;ǫ~ߩ>shԁf_QQJ][?OV1[ı!m=!@?P<#u_]ilr-Zoą$ ?ټAAM;ǫF|O}_/8(}N]N((k,{.[t #P{Ө^˟O4iCrz[Ow*jet!8L jxw W?wDg5FV>f,-۔>.zr`ZQ+O|St֧7?)yMcwrQrZF{՘7}hyS(.&&5լo{/\4)ukMqf4!}J<_o5 G?>.}ӿ^z?OV1[ı!m=!@?y/p/koꚐtGO/>v&?gcSi^մi =1rxsc0gYo#ڗQ]{s~ i/=P>> լ<آ%9Bs k{WvqjZ?[Gb^kK}ӿ^z}/\}BӫXyE$J?r~A%":=tX^?2O.cÕ Ɨ\i+24%9L9+JE'xI5D_}ӿ^z)uk,r{([tʊ޿x{ū0Yn];ד^4f4/4r]Z*n:2Ŀ٣w?/h~ i/=P_iz桧KX"huĿ٣w?/h~ i/=GټAAM;ǫξs?fĿ٠gi/ize +C1W6{p:!Kδ<9+6h^BY[ӧG.:Պ(V("XVXP+gݛLT ;Y6\ m`}J3uV 5۷D1aqHe=3H{wy2,[/-U$=$桳YOhkfXh&,ԩ(N9*-SP2-V#1$&<] [O6b%pjlS>ku2鑱ԑ_5sf66THò?1Xi EhGn8QR;>|Ggf_HVny~f͟?vRi֝V[V=v3ܥG < λēK놙U[L_M]ƫck[XMpuu-/.qO-dŪk_zc j9n2 tAKG[n(w;_VqM׼ j{^9le!CXzl, 1y;Dx g@5r3+ڭ,LT!SVNǃ.\THNkw< ޹.ks2OXd ٍp) T : nl~W-wg\EtF#a7wjksdN*qe5NWrx(RMp:[5@a)c9dU\V7ڴI5NV眏(1hϻ'V<.o$nop{㠧x{6_g4w0>_Kg=j2x9xD6e'?ֹ)uf<~fFHlM[)#8V#4y2j14-^Oմz^m:o/NoPnkO9Mm7r~UtO ̍>qXYwv,D;pHx)B4`NiqE8gW?Vo>hg c*{B+R4"Iҝ8"zL1"Dt}F&9ϧ?ʲUK}Ja㜜m>}Pel20>t--4H@5ȧd+ q8?Lf43N |ܿZq}+.⮟7dlbVA#4؆-ǿcnB~>RnA{u*3@2>}ɑ"oc8=0p)zi xɧQ jqPdb?Vug5T*nc98 TI BZĒ=hbB 4=K@֚ ||S 4¹뎽9;P!BF=6MBs3{$˖:f6$Ҫ>*֬f3wP*@;vŤy7åz1VF2FNaH6;H`?vVYbJ3Ehdv dFҽZWPEPEPEPuƉh7c71g?N⎑!KίxeZ Ìn~FӸR73V(Xc[[c[@fk]Ѯݸ! }J|5#4#]Uv m8n\~C:RjxҼ=A g8?Ur18v @Rj̐ʙ>N[x?2# Tp*.sP!tKIS հ=)߈ok[^#2R@$Y\ ,8=k>#Xy >^18dsҰ Dg@pG;Rc֬B00r٩5hɗjE*!*TJ&ק^*t.Zӏ7=?p3g+o!Z'ƌAIyqQ <2TrHtTe' +n ynǫ&STխc }RZbw{Ⴍ=moR剧gk"ue#s?ꄚ 3cxU[s'WZ%dDń9[hldlSXW7ԧ`X}ݣsA>KF𾣮B?R1 |ƚ61gmK@qoݷ#pF;*՜Iq׸7ܞ3!pՇ$OR/)4OOlsقc3W$rzq9}EM5R<ce#Aힴ.pzc@Dm(RF{~o'ғe$,#jE1LV)3s~[F?jqqOR3JaAˏLR23ޗ'84z~І0I{~JI~|SH$uڝQ&GGZq7M' Gi6fAGҤ^JhNXҗv~ 9ErvFv67l.?!) Xvk:{ p@y{p8<VϗP6t5ZN{;Rb%s, L:X9?֮L3~uZr2?0nUVj/$K@_Ϗ4`w [Kr-du Ut3 0#^;Y֔N>?m]:W<{Om^Y:uŤ1MFEr/Еr8Y쵠:lʼ#,nI_,R+׫?~7llapy _3~BEXDf),n%vX 9[<Ƚ3RAc9_ c㊸(2>N郟N+`0j!' 3bA‚}O4M@(1R!BF)\6:#ʫaH.q]J;~Ζ?2iFA$֌\Pчg_n[dP=6V?m*˔NmV9OJvV2T"_+XGdd&e[xwK ;t*Mbnt+hԨ* JP+K :եka97$t\:k<4F>L[n~)}2רW=F>CIK1ZBg#MvVyOiS^^ecT >~%= v5 `ݴgTKpZr-dSp\7xw1ﶕT#_)fA 8@H.w#`N㞤v?!fKwL*ƘemIN>֦+&gR( ]}k{y7#݄@cۓ՝ ԣu*WQАёI4GG#0 k{PymGc#؏^kYM #05R3P~aVdfwOPm[k*{hu㡧9 ?sw~x" r303ޜU8cy  lI_|TD8I捹d n3 TN]q֑ ؃A·dwEA J[`gדRSo?7\v4@?n~4$UO28|cӁVbP#i%Kzz/˝i'#9g4q{daҐǯj,"2JsNaӌM{NI>6p8N špyT&pxN-7sQU9@Mi?ʘH\HX{npqG0=4HE[2Mb>3~ptۏN=+u&n=uI ۷?x[N8!܉W]5ỵHii+ ;P)hg#%z7_ dFҽV ( ( (; 4KAq?wt \fu{-nncv37~#B?ٿ!ݷEX=+VRJ=+VRJ|5#4#]Uv m8n\~C:W+gmkn cn1vAҐUgğ֕w76c;v>î;Fx]K ⌢x)f#s@ 𛳭r 2GOR k[YAsmm VDzF#./rw]m9nL>OK`/ˑ"G_Ǟ*7 Z+Cܫޡ|ߍnQEGSjfY.}Q‚O,Jx\WUhnu#/"֍XWi>1L>Xc ɤgJ ё1I^;ᾔ aR?:`8:#Rv50(y`Uia``~ pžmļFjmGͮ:xlrJK?Γ_֯X 7Cx#l~P!_HU,ͼp .=!Gaz͙Y wtl=ʼɝU 2Bed[72Kn2Z²z՛V,J9Pze\ܩye#8 }G:G(?lf' -`r W뺜:k8ǚOG@8ZMRH D!Ǧ3&إzmƿgf[^9c~-P4s RyzظU8=1֕wuJ^8`Ke>Fu})4,Q`tm򬋋n3O4z?u(<5mi^VkJ#B:62Gyyr[Gʃ `S^iv|vrW=v]Njlnw3عXr@Mv9m:xL%H'Ҏ?Qk3E2HdxsV󵹔l0{>Eu(*z9Z?g$ʏ|Hjb9֣UݱpSf %DkO=.A ;h~4j

Ӆθfj!xF}) F[1`?Xw4Ьt.nnt8BDa =I},c7e;/Ų?kR-$e˲# <竉G mgQْx2½2泛`%7Oxφk%(T>Q+F.99q}w'sV^x`cU3stWJ56zϾkіF@#>к>aj"6΍o;)1YK7nv7N9)$0O0 ^io9oԁys֡j:q{<*]wHx`GBGN<?++Owƨ )1@\u#B|7nlwMp?sAo?8ǽt$?HYd*€35?`O~ ۶|wv1OD38*~#{YJg-T?7[>/؟3~tnݳ;b$;UI2F Yeoݿգ" iOvϛ@)P3GoE?b 'ST,4{o>bCӂIɢ3[>2؟3~ytnݳ۱ثJoc޹{6?c#tg#|q Ђ1WӼS40xr]!~#|swm^O -^K?eE.ـ~u=2oifp1W,q4Ŋy:FʋإGx7Ů0U$q\`T·#dtnc=1UOH6XplaOJ[n4<%ok}5Jiַ:c=|]hӝ=ZQ!LUx'ݏ|WYjIg dB FG56*^1G/S6y^o&bþSar[}F𥥩4Tb8Z{cڲ gpUˍ?Ӵ9;}o/j|O?xnݳ<#WFy{^͞FRUk۟`gf|Otnݳ۱ح,RH?c/< t86kp&1suy?_'_>oc+L][FP8NrO՛y|x egPdUPo^WL+\E=sKbf|Oytnݳ۱اiqysI!>[cm9yE=N{UMA61]#6L>7?n(HHr+-zq,$rZ3c. QF쑐>l] g ^}1W(rK))$g}嶆8H\e_AoY|AxWd#>5O#_3Hpp?%5Du@*<-omB;ǭIzGJYS?\Nƫp"hriڒgv|{v1ۭ]4*&FU"Y \YjGr$[?#nps_˾Gg'Ƙ$}Ĝw\c%q/㑵FEHhzLq,DWab[nޜm楒ͥxm 2PpAGzc<]񤚴ݮ@q^'u~k?_R_'ݻgcZFaf8U Y n+}+g[cޯwΑpt$>_'O>oc*W[6/dnz[Nk$֚O?j>s[P`|v/1F#??'ٿJ~1MX=kJ53ĻZ$Ů?#P˜M' ۶|w8|W&-_6r|Xeo=?8ǿXuO?7?' ۶|w8|V{;79ZFg3tutSP|Yϯ똾={T@_'|7nTg?5OC_/ox7c=ҫ|Gr{}4TEPEPEPuƉh7c71g?N⎑!KίxeZ Ìn~FӸR73V(Xc[[c[@fk]Ѯݸ! }J|5#4#]Uv m8n\~C:RjxҼ6}|pcFJҚvOctw$RQF*(M7R/B>ƽsúm%C/>4IVq\ʇ*?j.7=mu]?hg 3$C(O=+=)$6/7L"=}F{UΣ0sv=_ cc^^fݮg;q׽?Iu. lrW9(7 |=jǙ.}‚O$g5eVдȑFYpk|]@DX[۶o_V*QS*m~=Vfr??>O0~"ݴV θb+ǖALM*im#,OHthxv=a ƕo7=jFN[ A#ʺKmMѷT1%,R0χّX1OF'504aGE(v= n}*B.I>ǿ4 K@)vHE< A"6K±t[GI$F8ߞ:kꚮ$52t>0x䜟ֲ.4M Rb:וqI(-HSֆڥ]{zU)5G*yb~T/EO-Kf%׼`!pX@a)ǡiE<2p;Ȑddm]+hVG cFT~D5\@6FǠe9 ⺶݋C2 #'?97 9++1;^ qזi҈HP#yEXeIog1SWduyaiw;m),l91+=$qnV۴9gӒs\HcX0,?hYZOkB+q?( wsS9hg7O7,OUA GTn&KMDPt>¾vrOZ)4ĒHi@ZwauF~)7݈ TeT56:91drsN O^Kj L~$Ԇ, ~mb9늶WɨlO81lp:tI8wS{bbNr{u!8G#w ;rs*Hr/ n1cڞX UYYzdX6 Rb$g\ҩUPn*9K s8)BTgnE.aؔ1=HXARh@q?j<`*0۲TOZx`z.Oֆ6v1](P?C`B?J41W%r zUd ԑjqhq ue$OCV!*)~wc2S9'`.9**mMwCddlY ]ьVqoN^E]Gy6%*QJ'hhծ[_iGalG<Q@Q@Q@׆[%݌8goq;:Gn:Ɖh7c71g?N⎑![ΐXobb,olorvFv67l.?!+3uV 5۷D1aqHeóYOhkfWhwXFU$"c,}H> ҥyRIo%*Y봑Z,w2!r}^Ա<L}ãoÛ [Enp $|zGJWn:*Yi}1ԟR{v- [4y\.(Wsw8?,e_NɷP݊?\|Wtʌ ާW>1OR4}Vb3evZeʷKrx;CXU)+nua n<uS+nXY'#短w~ espB +4#dxmLK=~;fN #5Pch]qPFP+'Z1vlRmhv@jO4f|;Wq;`:5jFn*N*k y+FXRSu8+5>2Ux?MT -i+ZjS[1II9p|/+*N<+џzAN\'zQIFhR .v#d!N .~a?P22 Q^/H9kѼcZr.?i//H$/ z~9&˥+C-GXW^$u2@SvBۍ{dsQ1ON Vzޡgb #-?CHf)Y6a\i21iYPK9ZT)8?zT\D \*YWvvml@ۓ*u}DK5M$:E^[OkNp|e} L=v /USa@6_w93ޥOF ͬ30H k[q6~NVfY.|;MLlHh} _4S>u;hN2K7nf,H@#%y G[,w'A+oOw?Kt9qQHk0:͉Դ[5@,L#RxߌU{8ėW@4gkz5RMrܧ[}3[QVrNli7<[-ćE`w']y$ӵy/tXC3q}c]xUϛ5B6Oz׭GOV9,=$yy"rP_J ekFO?rjS>xc>hC̬?S?J0ֳ_yx'!>7ծ19BGʹF"bP3aXzb+($hT\;q^KGGRrVzi~As 3$U=ca@$ȨtTΛp\eVoAO>)>\ Lqʏ+;:םv{ \iˉd9YiYjpGmkgh*2?ֻ`qʲc/Nq,! 9YBAip R 2sEA {q֥)9c~])E$ab({6LJ@YC>yKH1  U=T>Q8cjT9xѶw5E#8j_꼚亄se[^|/f&@>p[[j0s6OڗYb&]y18';rF0ZA qi\z|GM>Bs㚏}i6'$Z7iG'␤I9?C x#==qS+*BN: fw2j9lgT Sg 09'q {֩˲aܞy''޳56eb>lWꑄقғ%zv3V,u=WZ6l| vЖ|!ݿ%QE ((2-f7c?#{GQ?+s] 4KAq?wt Vtwv[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC-VCZWsZtϐэ]}Ҳ4^t[n)J_x$~F5ܑLRh@2]BUd@EWeh1PYdkq>>~ՙ#[R(1\kQýWVn>{orWۺTS G"2ϲ}l"vzC7F)k/ڔ7MJ[kY$7BN=7zn)6}1KB= c-lg`ۚѹ;{,ܓܚu L^]\Zkn\QRHֽ1cy_-gqfZ]ٟ6s+ Ez66d|Çz` 9 y<?뚵583zrg`R/8n~MZH`B Nt.}F;kt.}+ԡЗL= >>aiZ/FAY7wr0RRTql\F_J_Ǝv*Oʞ7g]7LJ![k& $|W+z:|oIjޗC*g) ) ;^3m(K=z?iz*5u"ۡAx7<ʹ3b V7).ʣ;x5+UWRqW?F7a%z`\jУIzP>n9F:1cMGi8pI?Jǩi'cCԗE h! 8q*Co4V>XUߥ3ĞÐټ 3\o  ㌞:̮ȩ%u[ $>UbOkX8۵lx~uix-ѝV%lsק>8V2|5=msPNl֡w!uWc3w?_]i^ $ǿ;G[vJiGOB/q^(㵞'a]rcWj̋"d:q.dS?.?2?*|%Tdy|+.Zt|_TmR+f{'ÇZ,y6pOo=[d-Z/7I\6n?OR|_e͏MGL|61q\uK~W:-ѳma}mҡ̟.J5,?KJUjOg-M=6z:ڹ%n''\ipH\^Su4{#PacMW償kq{M:=e'r;SS%_$j2Z&R+k)clK{bfIɄK3r>}S~sӏB+FQ#?Sdac4"swG<8vtH% by¿ʡC\niM$.e-͒: p]4\"i"3ҩџK}打n揘7={ۍ+RT1ɟVQQGg2ȩtl;ǹ d0݃) ?N*äɓ$.*]Ƌ ZktRHr=;֥qu\jqA `<1@Ty"ILX9x2}lWRed=HN@ַIz1w)xNY$9 6 -00$< R#T H落m" -K? zAfFUI%48Uq𽔗LfI88^Ag#g@R ~ԽjT##|zk%mV-,@cV ܟZ¶:鸣ZxZ9 gښTvʥu' \_+ÚҮ=J|GAgUr~JX(U\cGc.#`k+`vXuSD%׵t^,.5YnaE“'ߡ'=s\H"ovJ#'*O La}>ƢPOl[UxnL4Џ-jC {fuil巑Xm# λ{FP[ m#rswz4Yc͘ts< DCSi#љU2ǴH A;g2<%kixVc2(WN2A# JA?XAmJӥ?0(xg3C5rnB$fpls< ֽG:Nߤk FXA B8w$Nܵ>tʏant9i] ͡#*EWxzչGop8?z|6qG\=h/SF8;גvq2A~YF}'²|Ii|^.NS|캷_֧>*(v",W ORGbYzzO$ 'mQGW>coH Ҳ3>iy'Ȟx }7ֽN1WDa)E\ތA=т!G??f\9Ӟ?J⫘G)Tז޿̹Q.$2@CzkIc9#bIAWpn$iY;I]'ICm/1vq_Kߏs Iocc9cH5HH~S} ׭2X`'5=D[,}HKrFZd?̯ԏOnc⡉Cl2U{I0Km\ ׁU=͠w3͕22O56 AG4DNo#~B3%/FkM4o.K7,ZL_ޫ8ǸP?g '8FoƧ[˔8ϡ5rRtgcrI>HG w`ίr2a׹_9kp~,HxoQI\F74rEmh3aB{J*r!jOsH%npO+޻;W8g-t+ LO9)8Pu8MpXM+N$֪9mIaRt;2i$092PH|87JޣH rFG?{:99C\!iXdg Zt{偈:9;WYi$zs56"M=r1\I`sbhT{``ЄEwϡV皑I^qZ khtVE֋d`H!\VFG,[3Hi`oz90/F̟}x .?:ՅơY~'z=:Ŀ{\'#1 H8A?2wVHQEQEQExeZ Ìn~FӸVlhv3p#(? Պ(V("XVXP+gmkn cn1vAҹ_ ?s?E힛ci3pr: C4g?m&?9\T/S$NN-ZR rV4d>|EJҺ5 mB+7\g}GM4ք4&Mo$Ly#ۨ hk:WĒI)ī` :'$f>T!??:UvR{ҞVqddyUXpαF ;x.mRQ†S3#Pi`-/GX'Ixd)E'-MOoej f#?;z! p@}5 ;1 k{^z~3+ٜͻܽC T BI@?*?Ih9Hqֈe=+`<;%,LOn0'i<AĘg3NG=*Ē-nϼRӢ5=xH!dܾKR✚GwQ|/U<@q6_m̨ m¼yanIe F ־GU^;a$A\wz/EՅgS{y"(rW?)<zW>kju`#7N0{w]X|k^K8~ϕ:3]Z0qc) d(X܊ :܃XD"F+ j_<׋#->ع2>IqN4!i2H+T)^f_}OB19\5]«mr>[@"㚵޳4PAViVV?[ꪸX5s%%dzp*zk'r"@Ο0?@gYWַIJV?U)j3~'ҽ8_e EAv#hl%xR7eԞM5"Fw`% n`@Zb?!o1qN/?JkbON?4|S'#h鱲 CCmAxR( `GӚa@iq7{6<> HI_J>RpAqUAcHH#i!`ISEeazNsӏ Rǯ)\,! T瞹梎/)JnzRF(fqcW4=qƝ5@n <[R5頰)z hraTB0i1$Cq*@%Ii0n=?E*AjFppîӌ ACr=2F>lLd9s)V.}uJxP&l r Mp0( GYٵ8hsW^kWlP bҰFnם7u$2kmKMI 7d*)p 8Zє 㯯_LLA>?QkIsß}zy4IK* 1#5Vyn8H;&@ ܢ+3U݀]J\R:H4yIˁN~{!^=&j8Q0l~ Qu${zGT8>]Us^jZVEUQEQEw^lhv3p#(?[%݌8goq;:On:C;ob-Պ)zV>zV>kFiF `f!8]\z 3m] {H㷇/󀠨 mz/beZԢ!sRY=juCU|?-3M%wȊ/WX%O=RW0^'9{H2[8#Lyž%DJ9,Gjݍ6{ }}Q2O'&Œ 6GM:׆2N}*ʸg%wkm4׃J™1Jµ9鸐O[c_1yvw#9ێ_MboW;#8S:=sUk{{rCHs *:g V1rWr]7xP7g! Mowʼd--"38]LsxnՙP>e.x-So|?0̅cJ7#jpFTS߶r%̴;IN!rqpr+~1hH3#  1SIm$q&,'="?@zt>5'VC_C2A8 s埕c}H<9j|+Z Jy0}wGeJHnD c4װƻW Mt1f?ش^ds}  {eYkٴ}FWY#(W,Fߌҵ͟bG8t\_Otv1fVDS&6W{gֈ 1=xneŒ3 vIzSf2@>07"} :?_WAG+n td@7Ӷ^jS_tsǹi:Xyv8f9 `t A]׭ɃR#=OjRM F-M|fs^z3V9tzN1zb|#A;fG_+~SR|#A;fG_(26:7=qU [>.oup |Py'דL@m `=m:nQL̃Qtgץz#O7Ht*m~S:PZ/~jdJwCM|Epw \&sfŋpJޫ{%wA*4Zz3PW '#~V4 ћX( 2ƝX#˷}?8y&<~ϰsiU@,yP˒?d=&A@&?:i6CX>O`.=sLF-Ic<_OZjNTIw.t4N1'a硦: (d2i;}Jǿ$V2鳱ݝ zk]wْ NYarzGzHn\ps*5ɯ]++1I*hpMRr!0UT]ҁVG3ψӑڐ1 <ԏHl_XҼ&X͹'ro\v6n >WWNRVaEUQEQEw^lhv3p#(?[%݌8goq;:On:C;ob-Պ)zV>zV>kFiFu)|5B^XRQKlm@t 3h3k:[@. {i m H}5]jen#;n,N@֥YOhj(MxI]ͱK7qR7pp>5CO͛DV,nύ9'#v(-J+*#|Lm7VcxO12#cw^ZͫjwRzn-kfF;VFﯵU+i'En'(.[C4< 8{W5h[W" b%84N}[9%mÜmn=+5&MjJ$a(B~Ss_4XȲȤXqצxo]{xm/鿌c#ɯS䞻38U0e煵9%|toZtc#LXx?}D_tho1Pn5"f"O#5ҡў?,R۴R #!׃Һ? d(gn%PsۿNx$u 6nw?-|r+>t)H&w2:%z/%Yv7q$@v\VQ#H%d8E^ůj3\NJ[[fc٤ `r?Pڏk.`MߋVTCzy}ioM&X$$^c`:w$d~5Z^,-dc߅:5+m7rUz ];LL^ w?;8jQ,w.u0:ӖDS_Ja 2^g]r\d{B"b(z$jT8GdtV֬RM}ý2y,oЀ|?KT}1?S5o*sD م)Ĩ?#d?usXVϴDTB2@vn>g]TW۟~*aIG8 L$/?Sy!6Ϟ+PIn~8y|nA ÓOr(0e :Kf9%~R϶*|!sFiT8_'yb:?<?u zZw4{BTZmjKHO%  O*.yUSbO=ڋ٭4.U>汚{O.@5J3gt'Թv5=]9rwy\FO;We&~4Ȳ[JC!Nœ ǥx[YJd1-O?vx"{kY$[#*ZGl)ݸ|RP#hnΟU|/YmtkvfʞP8LXo~[k48>߇DyDrR՝4iDzaojo5Z4 N1#ԆIYtbcQ^@U$t[Pqӿhi U6ۄJy服t:!-9*\.s#8ݪ60mbD\}Ղ*i؅6D=V>3lEH?Yra8uo0`alscӨ>=k҄ZVDs"3A=It)L}p{5>)ң̎>X㿦+XFH>KHotLßCA~`?ҢVc¯rk|C&l+܌ukU'k.[:YV Hb,pxyIӣ5k2%E};qԞ#Z=QFiv\,-3}=cI}P!2wSSxOEDcA'{VޛXV'<$##=z=J.>Y\1C1K(m*!SMH=T$MKӆa[oy|OBVgn^h\ #%8'X:Ԯ/TM#:[I2胠5ɠP6W)YSܹu]\Db}wo>4Qe[ |ϼ؎sIKmHe]GV&:frwy*AtyyY~An̑€þu~{FJ7YFHnz$]?ĐCx8J^rj1,ԡDU8{7֦[y 岏j[:KI |wZeٺu22ΌOO'NkT=9ޭxت|b+K`:1A<'ӎxvs7d喸yX Q\gO?OlVJRzNӏo{ք%H;BNFNKs?,{Ujo:x~Uϊ4^آ$b)$jI vUoz:CcA *4?VgGYaq*4jҗUR .ğIVR[ZUBIliO)o8.OGR4v^H&se$~;цAMzn2jړx&+e3d t hZ) aA76Hf'yO |ɦds&A<U6!OT"7:S@=^\_3k\g*?+RƷ.Z{g@e@Bg55rW݈k+G*~`O@v`:)|yc I*^E$giL6s^t$ @vz5մwsMRcגZIm5_.GR97u+њuXY'pTtu y;()$o$w7@mA݌9Q6;'o\- 2Q,Õ@Sh~Z[zY{BNb1&=OC]=! 6zdW.P.ɑ6ߜvydF:},sMpCΔ81~.pW.tSo{#\B֎<Hp0ںGMyS BAd$0Tt)ReFȇ 9†9Z,Ҿ)51y9¨lxf\qu3W5v!<<(zǰLQZ2hsʴ3 Yᝇ+?MKRse8d2}z$4<(G+Od +6~q OV麔N-JqW q_?I QyrLAe6=U ;M!5 3F,c}.霅 9gftylrG\veVt,J8US'4DR-ǵBt0>R>`P`s=4ϧ I֭xH-%f; %;'޻b:*8z4bWØC1I=n6_ZdIi& '9FSӨȭH[d+:s^գU/h8gElLE%[Cڽ -=B\.^Ja=ZԳZU[uSn>Y/4#"$<ec-5ˈnIF$֥Cbq5Xb-n_LfmA?ڤe~TǍ/ݓ`#=p<{n1쎨ylY(Tݐ=+5ϱƑ uPJ~6zԝpUVz҃Q'itg^^m'ƽ&;-Š($((2-f7c?#{GR+s][ 4KAq?w VtwV[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC'5'u*J1SG kJKT1tpeoI?xBN-K,(#¢78/#<1]E $Oqy<z$-:{5Ewu >gv ԚօMLk>Dl4v@{awzl^u㴓|9WT|S~]J ƿ@y?[;_P]^IK>oN~J0~E*񼕌xnocPI4jj]w t_ &Ž"}" O>wc ?Z/u8w:q9 #'Ӯyҹ(*;:?٤7:ltEsדҹOZp[ H0Fzgvk< Xƶꦩ7[٭JhBF=n׺3<#ֆ>j=V8Գޣ՝ kTZd Hņ1gҽEuXX`nKy8${(Q tE1,qFƣ 0hGmB{`Sv ^k[vTڧ.9:7O40Uip~"nqz^@}QT#7i0bUl+*P>lnzGj%4Qn,参7Bj` ~~.J0ve_~>IlJcv?Zќ%ǣJfAگ6l:2[m*ծ.]O/~]r#F=OB{n*#wz9|).Ro[2B[FVl1ֺ*'4c#;4h#i"339=t^ċː<={Wk$#sw^j%ԯrw2R}|agv`/_6ƺ'\𶣧XIg~d711q<+c܆_Q2GA/m"M $HgFK1$.8ϰ+|QwiA}KNx A'ԷLN3 u+h,bد+4>\1 L4Ga'<`sĿv_$?l\ƠzmzjWHE{Z(+1@0Vvg~~ 1QaK2Fx r*f`@?\u/١C5S9/9W{kQl5ĺڣU@G" L1`Xd7JzՎ[@X.S *|yRxqv{JRӱƴ0K!P%HnjKTٕ :V0CP40'az_]-nfIxWs8OLJ%ۦK?;q*HBs`J2˸qxqH As(d:KMX˶@~H P[RwTkytۑ3BOC^qpN*&QI?z/T|AkOmV[h?.OߙQ)*9-@t6Zd W1N+1Wܺj9{0.m+Cm=GlF,0L)mS8G\vq+%i#G ֱV5fjn슌ܝ<3϶ gZ둥ђo2BFЁF{=*d\y3''>ꯔKgBc=Ysymy-6=8>v{NpԪ򜎕G > thgE@@'[qP1n9_~8kl%i`Q//3p;^ƶIO 5bhr'*}#+\I5O"HYc#ӧ=+P_cQ6>f|%x~H|3x# Drq;(q3n54s۳4h˓k _"SMnr ,fV8< u`<X^=uq<ʀ c5NdG,Xï\qսBr|w]7W$kEr{:L%V\+DX~χ[ pDdLU5[F͵cr2=+\xReR`2#s]U=$ULlФ91OSZhDc"eE NNwk&2Y2mAlײixLQ1* ;kq_WIEb"-%Uc.'FSR%o^m瓒8TdMNy޺IF).]6dճ!+&AHr9j܏iQ= 9L 娜U5jmU jU;CdpFy+T 9{X;GXSLι^/k1ux8cqz#V!"{#Wך<VВ*;-Š( ((cD݌3qKIuoW|2-f7c?#{GR+s][[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) /4oyr3"Hza#JKT1tpeoI?x}J]&9,<kPiȟT9c|A{ Y~c)>~GjtңKgV'0?rY﹐:Tpe1xy͟iȉ&FrGֶ޷Ps9͍545Yo[i`OJG~'WbYF5;kۧ*@c/5="M[Ak9 ˹hr 85?4MF;kXd~%NO[aS5H#}==Ӿ'[HkXg?(yoo濟̐tUz >ց@g>EltIi=<$iM1w94:ьzg=rK"9#$G=}~0oy08~$K &9hʣ.rg n$#٧X9gIWU7)^6ۮTLׇ귗$`4 }I83q^Z(5pҠ!I]r̤dsޤM'uu;p ;n.UA"?:.mxՉV|3?u /n̟= ߉dEJ''c]NO*Φ4ixl$W|<8Ku2Pګ*QxAz4")fnןy_ΩrFSԲ۩jpMGgq$M) )+) ՘4wHlAbRi ,CoOsޅ\7` K+g'5)BMxUmsYI>讃MԱ(Xշnj=z]K^|~9gMdY.NA5W '+5l#0surImda R>LEE${VZ~Ynyׇ5hd<sb.0Z<8^|Ѱ^Ύr{֕9cU@:n?F8μBvGi+{_"[ ` OHyC*9ǹ]N[YU€'8g#aYJM9W6p:w6 NgwӮ!ԒU hrőcHRFI' ޲u./ee/~]cY naխ Q=yQsSQ84-xRT*Ia=GG"3+Ԏv0?}-3 fňPT`m85an) g*? .6.^ۥ˘sE.+*=bHcu[b'Mjזnjh:|G;f{v 1~Yk~j~.n|3.Ӹ|}WxJw1wKTkyo `8E׵ᲳUA,: +b\g[Gd;ʧmId`kgMN,oj4 $䁜w5kVk.9{2u8ϊ/Ѵ9ֆ؍v`q h#VB$uiYxG-g<929Ct髵,6%T%Gdv/mm.*2֮[pUTݟJ|/Gr/$lN}ftUbG_%ViY{ѡF>;',wO+kTX-쀍iϯ\{{XCZPj视N rRRqB֤',8o\$giUOw 枣lL@9] $*N\˕SqjXs@+DY8}$Re3Nk Ԟ8]teӒԢL9ݞFkH.IOlT\& REtr޸"2rA"]*jgy=<#,gMk+6xdt`G519zqַUrXIMR2bk(ˆəBRsse a[UDn n늨[*?:7gt.sՀ PNO޵-4{IQmjp]$=u:[qje+]ѝi^ΊjSо@ވpC~MOy,yNkM!UOYj7i\*K;LY:]mT c.N1Z)QQ62Fj%}X);hRд ޓzk)8g WVIN1Գ=ݳ%<+`q+{jCI\EsSXC^ѭWa6d0 0@ZE4˙yAU+M[TMt~e,rdgl~ ,, b~R/ֱtw5UV*K2!x`#c*1{'f;F{qh 8[}Q[b?Y/!⭛!usWm՝&va,.HE8;W5  [zQCM3k8NH?V14RXd6W5qԘɧ1Ժ}@Sv{%ep^<-_jD2].'%8 s\c3J/Πpso¹~!nXې +@v2޺QA#+AaʐUOJfe\(\~A>7On1򯷱> 4 7u9-1|F`'S8#ܖaR;\}:X:x:ȼI#VK r_#afQ)fFrg[YYoN5Af5 8!9N o$k5ƒ9*2tlD boAFN̹RUD OC~ōBS1\@osʟ>:"uc8v8|5;}V(d_xm8xz4:?R,o1\%l880N}RYj VB sQjUY{|rq={BSKASHOCF?9b?*RNb5إ ?Z}~"{PY䑆 Hs5 b961Gf>Q,go5ʢH"bJq]wK H>T@ zqob |>o~y^ >Ym.PV.J(-w[ӦӼ5Z9+ܜt8?\t(|O>pnLT,Hd-#iQ"0!?t7נt"Y p28R}\57M"dpg?dKS4K13\bm._qY>1=,фp5~9$;-2᱅,j?HRhTr>jZ#6߼Qٮm\J+u6䫂8 Je #S V0 l=I)4tVMHK?P͐Gp c )5 *#SH"CO+>_PId/ajb*ytJp}+~[/jApI9U\\<^NAz<5EiܢˌEi: I2 *MɦN,~\ؙIGC)S!%4yQX~YJ,m(AtrEJAfQRs *]]c6z~Y G^1 J :͏G@}3>,r,q0j1O'quMBseku(dp2? ed58Rmٴ5ja)3}Zn!O#tG^g.U=;ic~"%B2r?Vagh5Pqn%PƀFvp?J]n06\?ҸsUuNЈ4^5Suh2q}?۪n\LnޕiCla H3rq:N^R %pq[=r"~& JJ.KLNYf0[H\P7;tQI8+[9&*Ob?$œړXW+8[S؂ONT9:u̗M,zɬYr0wcpL>Z͌|ݽű72onw(mT3H0xǵhXb0u|4gK^\Q_W٭#{vtE!^EeOZ=,vG+4W` Xs7rW?. u)2:OX/%F~R8ۊ[xv -Y$1{_ԖX8s1'#8i- AvxNi TxοIJW4QYOPO5Z[y}SkʫOGN9ɠ]mg V%P H2{s[zdK.ͅnnWIcIւvq]F _ѐnDsJ2@Pr*04 -;Ͱ1z'z htis~ ץ`<7\yW,o©~m _ӟofpy)V=i[K$exsǷf| {vŴC4nzgG?#LWb0]ACԕ#u/iZ2s>⹋o\$'>LȽXStHkr}Lg݆{x%@?YQYZw$1{:.4B3:#+v!W=edX2\7>V (?t{*Iycwb ^j^,5>8oqopg9mN˅,  nFDAV\]=Ho")(ѶӵJ $,8g_?ʙxLUӬe.f ,.̀A9/BeIJ6)7 \Tʈ2$njWA{v'Q0R1޼w^Jg.rS3ܞ# :+Iub)TU)X/үq]F?0z1霎6,k8`*sZ&ܓ9"s@iV´~T˽#TݡRBVuFNSQjGjw78Œ-ڵ$-O66o$d-7(NAc]^m6mr ;I# dk-d(r ҼM%KmsWiygU <@϶yQyT˻=jIo䴴u1f,Ov3T q2uQ fZ\,L@^1ڒ[h-nZѶc!rלgW%Uu}@GT,w6q=9I] SI $_xKQ"l[wܙ~8$汰"#[aѬR1 cJlOcUUe `F},S̸XWi tB:qag)]%c"]@F:|ɌF?5I5rn`@(;MKXLW9 >sZslhiEdl8FYd|B㯽s2 \NkkE渘|/^UedxkE\vy~')v&mG#g-ߛ>mͳS {UHPXg/SKݸWD6cW>v _ljO;]yΥ.[?ËסXg_J]IqҺday#zYʼ hM 65 ں=G8}+r L.E0H֗-#fd >Uat܇@I%bxsZvpK 3ye:z2FpW:r;qu3ށq4Iⴁ0B~fxQSE; {nd!uR6 x;r$`88:&gXc/"KcQI>$o8䓺8?GnʩY.w431U3HHǯDyx\tK.2&!$.'޽;rYI;('!`Wמ+6#u2~~Wi?k+8J#mpg&g E9>=atc,\Vl`IoX|?>E?Ʒ_ltxhr~֋iq@B$yǧo˧Q%)msU6E<̹79sL #䙙FC:t-U`YIc @``wx nbZ{qxPs~Ra.GNnk8DR! dD9o,0{RmJ#U`XƻCҰ\‚pIj2ݤ-_azWتu(~=\)SC,ؐ"<6WsXtdc!L0;~.-'8$ `.G@FExmiz30Fp{Bt%?ˌzjI`/=oʪj6>ʲFd;089?wr *ltZ-g!P?x񏟽q̆i.$%|Dl?S]ww߼m'}דBœ?ϽE:r{NIsuEq$n 1'5h`cq̻ΝҥYvFp+MKyt_!G5rI<;39#Doqv8<7@2K?h{3P&rF;gִϔß x=\*ھY(=yQe-ӟ:/ӽhYZ|s-Nʯ3TVRj^huX'}*Kb2;V [%98A̎fbr+Uy- TʎƜgR-c.&m#9G5z:6ZF>d2QI&r+xP8VV4cnAZ\r,lǂAPIa#ιʎ52VCďf,|ՃZ%eQƲ.GkN9h2k8Ud+r9+GGPR-Y"`GNyL :}j,]lrO<@I1Y:*nw C-Wͬj:=Ϯ+'Qm }~I-Y2zUw7\fb}.Kuo10zgs֡:%r+:LLK#q .VF4Ee1T_?g[އѣpĘ?wxYrM}%8F7YV=anXU,ҖрxRu> iݭdy_LUkI%+Aۓ#Bk^H_)"dU2'nwu 5ec7?lS$E ʾxGf?}&wRGar+ p3(T@ް/oy3G| frmkzZUPE¨tm$VYiR6"& '\cY9wY~ͦI.@gohgS5b&gG`t>:2-Igsg'?B? ۖבާr"Pyܣg-m$ $zJCތbrGOYդ_qR tjw6Fhr0Aߵpzb2Ł =jMrH&ganѭ#厹kI|]hs Jg&ILLs@w[0Y%l~F}/ýM@*p\^% 0P[K}q5ܣ71>"y.gUqq˨@K<(8JҒoo"#dSthUT`_]K{o׭A-i#:Ƥc%fim!G|I >Ԛ{x#gU in$LH$sקN~ qoA+]p+?_aJ-"P:7?ª=ܓtQdvx&+p`ߴ5i."ZXzzgZJK8kNTEG.Z0^fpg' `tZ6i`fLG,xA5/Oϩ!d$ qo*2)@H8ӏ] Otg{*Kֶ ,Fj}Նg,]&YT: <j/#N ?7_åS; YNݪw9=O^Mj}E-# oi>NIמ4bzvr*e =i9cBEEYRhA=5ww-7O,eY?8zM'M˰>tҳ|6rızwűKh% }=WU+1\yC#bFʹ|V,RKpAHG=q߮kԯ# }z. DO*_ j{oj^ǮYDYJ RFݤ!'[\)5=w/[j epFq5g4tsSITꕞefva1#S=*NJm;V[8D-鵏B 7Ka.le7)q֟=Pynp8P)cT%h&EW珩jhzqZ^2 6 A-%2+8598nA N-!$Iun>dp:SDG]p#55tyrUw4vG=i`8ɪ0'ک5f.fzrjmkwuQ[]+ ;s=jXWz yvRdri DHJq?wF@m93۷+ӵ/H/bq7mA';>{-BkI@Ybb93qBŜ@SUMC@ᣘt}zҷTCH=sV-ޕDr%5pI\R#ӡW].0+ *64퐫Ԋ4@I?(VwC+)<ʲhس c5(> w ghe>}}6N@,`m2Zv>y?)<7Za19 '9?8MVô xX߈r+ݔ,Ȓ>V+=K:O 4s0ϯtmIR3/J~<I歰#Mѓ p qbᰖM"*/>ƳȞe?d?ϭP6ѫ8RUҳz׶1Fաs qY}(O?u\"x?j]>!& Jg!0N~MD4ȣO H sl{UdҴpڸhG֡8FҸܛfsWP1?FA)u#jzzpd|cl¢E"4(zC\"BxsӭH?p>T?Һ}(#3\OSAӘVGB1 t:=7mӃ KF/K 0\a$u\ΦwVb#^{RW qI~mnrx== \kReb=5fHfP9}6cջ?Hz]VFO1L0Ckr d+5|JIyǸUhW>0FĀ硦3[[Y?+/ѫ*m*FA=k6:?0\׫I^^i?Oo +ĽŠ( ((cD݌3qKJu5w-nncv37~-+B?[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) WhwXFU$"c,}H> ҥyRIo%*Y봑kg?m II-QSۊcGjF$/GM;XY3>R:mO?Rb֨614 :m.2Dy篾k+^3<Tzsz?ЏFcG.g:INg!hU 3mo,^+{měШv8#`2p1Ұ.'\ЌzczΒ擱0R>{fbLzp;RGuqmaC2$zQ/`֒XHIcGCx2|DR{3DGϧR~i$2f"_-0~P@8OkFQxRkMI$#'?]úm:[; H}|d3g/sv!y~lʤ5Rs3YۙkE[Ts`>X;w_Z!)m%%bjJӷk-qE.:u >/_fgi0sTTΘb#dBm&4?0x }VNC{I(c2Z]PqRFOƺ @< aXדI@$`{#Xxiq[+U3vY-ΫkcyH?OV/$FH@qֳ%٤1bK?L֜1\c-d=sV3$o%''bŲ! ~]$<.ىYW5-KhҰs`qbsXF.)AĬH%YK[6`^'*3\'h}j"1HS~Ղ 3CP\ZVWk07&9w<,czuZ懴QqJU^%gnT4Ƹ9EpMoݳnU/0PX9"8Tm:`]毭ǭʢEi#uP6QwSb [+(RfخT>Z1Q\m4{%=Lc3OWN?JNYVy\I| r>%}kY:z"$,#d$g88*gNjiJm^\#$:ޙL뚫-ح.f*$<~5^ۗyAe ::wqR4yыVklm;gG5ƅdF%\S +"-%JV<$63khYđBg^z\8L[ւwmp@9 _%\(MII\\Y@Z#RH9-?!Wn-3{ְ?RkZ1\vuaI~xz=B+,g!69ymX#tL7R>0N35I-g bcw*Ht[^3$ ;f?5GbMŘ]iCb.Z۸lmu k .c ~5bB]R+̱heN>0O#z֧p۴׷j*ǡKdwC.O }U:v8BzrGO*-YNszz[ l-#+͋-N$jȜ:z}Gzn%K($q+E$WwEwzdi3Hw⸷W)Ӆّd8@NʱdxH +:MC"1<RV9M?'׫I^\,[ٔn9]\v3EUQEQEw^lhv3p#)i_eZ Ìn~FӸVC;ob-Պ)zV>zV>kFiF(#-DT;s(A۝3tZq}daČJ`R?!) =³C_1I :J󧈤Kw7G1JTi#4x>!EH.F g?mض٦_Pբhh%+ uYf~ A [<{$ծXF_|胯3URюް[JXʨ€xC|./ao/#`pGZyZ(I+,傁Y$SxZ8ڣ =8J%RV[ KVgY4X[,r`1T`tZą9l^yJ < I^}:˖gFRI<CZ-3S. ff]ǿgUm+$'\FO{HԊ2%fgi ^[P\u>up$y9 ' ĞtiKrn@!@$Ϸ?9(4M,$FIU7pO]>=f$)x?`hO*2.vFzVKo#CqV}v[9}58P'VHmn;ʱƒ}qW|83PA=8=Tڠ]rc*?>3gnjp:,8n,rsIo'#OǸ=G? Y'h򧟭z޷ ^kcH#%݀Ba^;|2ݞ Yarx`o^V;wt?L2jpE`}S+ρbjA$QrǞO8GӬ/NҮn#1)Ž2IL¿ lIxT_-ڡ@ivF@϶kzKT.gF,rzޯymߞ͔:pO$vES##xznT0F+Jnrh.\D`{k1Cwv'zqhF9HeP $q=+:kn[#bmB{p:ք#OG2ȡ$HPb3G'kAYevzfh:Xi͉6;}O&] Z(A?9ggУ۪\;|#лɴx]ťf219?*4.)HQǽz Pe98Kf2ۓ>4K4iʤȬ\ c~U \m,(r1MHpٝȹ!aG$*S8G }+A(%pƣ*;EghlKk!ѯ^#y_k ^dbw1+֙|R&ec PĎG#ֺiǞVG=YGN׺D)FLrS-כU+韲E,KcwS1kq[+[Eq2orB?tFt1UZW WaحEsӯ{ H~og-gn۷uG<[bƥGcMtmr@NPoF9nocBWWE9xI hAZ[K !uc[5XdA,sk,U8NW>~U>d>k7p]F4kFy%%Lp iwũViIBe2A+pGZ4_BF,ȻK#~FeG7{՝݈, XElC*3CnI81׃5&6D1VpY218CD7y2~yG9rv/\/psV&:7͸ro'Nx1N]J:o lK)O>?4 L7s8,H(L -6Ĉȣ%AnIϯj^v[U"5$g9?k(B4:տ;UOc^Uህ>f~ϥl閒&w 8$瑅 QCCu4̓[4*O˼=+3vo(Ҳb b1`tFџ5k,6,Dk t1͸ĺrAZ%)j-ry$yi/@'=eXdAUdw^[[" *eKUvu:o".D7pc)lx?>N=K˕ܰ@qzNn !<̧CooҮ_xMgk;,zM9u"̷T~cN1W-#ɶ!#U|,}.3՝;ڭeP \aʬkizg}&{fVl 0y' :fX͎X$PAU,m4*)ul2=Amz5Z0țvO5-_m˧lZن(B'!ݶMsqjeek8ڻrۻ[*t뭨~Qg*ߕ2F1v8SU`[}: @+oTSl?،D;2FJتzBm&o"HSMR7D*|ߜÞN6YåBXva:{a%̰L `1h&avhևWe x˹;IdWUaKv86[/%$ ʣ?kEk툍h،CzG:zMic$A}j[k uK}GQݾL6 w/W='E3\$HޒKjtb33ZzStmḕ B轎huD'L<~xk{- _15>c]OF'dL/nS[?a5ʍVy }i ]G%/Rf,^^[_oz>'Vҽ.*ȉ;)((2-f7c?#{GRҿ+s]M]cD݌3qKJu4wV[S`}[K}+`}[K}(3lj ?h򈠎( *':V7fkbN[ $GeK .G<IwwvojGc ";NIl'"JKѬtp%orAKFYy%E̍I'-I'ӎ*[?$Ks$K&MՐyېNxojߺ|olF0Xj(VO>p U rI\wyPI[m08vZ˱R$k;$pbВ#6E*Σt9b~ R斁-[>yL)1b1tCơMB!["BUPr;q(Mc䞹?jN5[3#F O?LXh4)nE83m'PN8MQsMվ PIpDh{Mj R).e7#A`s$ s:e[N}N?*Ӷǐ#FwZpEK ڳ5X4Xs4Oʻj>!|DQּCg,qܩSA_ǿֹ#~Ye gyFq׏Lvp@.z%Ω$9 lz9ZiJ5V?\ {P3H <tHT*-:6νq )H{ZGI(˹SAҟW"Âs2\Ȓ\}kV(#cTE_8 5Sӄ9^)](ڪ #%kx]?Z?qmى& N;w׽ww 6vcI iʹ(XF c,SQKTһhHr3qvΠPxzIi$M"8ϯzUE+7kRW8-tyn =}x^3KjtX'{DKuӡbvz}MRyЅ.OLFc'{ZZB:桔qWKOifqoͅjUd/vڦI]r{=+1(A=\J<-xn/"b" f`9' & gsn-r|,|1I#/X->" Ypq5xS6DR_’\JL A 9R#O"A#~>⺭+Tu=-oEfe c-3泂8 8T ?ٴ>SSYC.9=\+-<&jHE9~_5l1|Y< ~ۑ8ºΫ(]>$Iw;{ds7[_IrHDl=ѵgQ--ⱸK5b'9ӌ-ވ[}ӈB]އh/⦵ͽNq+=d WY5ƪQHxRj>xCuǖUc(%5N3'Tgo4MIdR g=H&$1W \^bgmjs:}kYŠKr721a76׳v5!/^&$]~@~;Ou |M\LpX/K}\YٝL{Lc_"8U%vJ1P~G<9T##)l(t>PJ(H#} I,edT#$9fXSex&+skcr"9>&ܤfi$su<=,V/S!FS+=69qܞ|]WF̗ɨ̒Y2Ȍ,eUE`2s9xubY Q+N`8o]mʧpF{ߌyg 1T$zdqԑϡĩI\0/*]mbe^?㊻nUQBl4s[}NFWVR˼׊K0ZF )Ez>ދ18L~5{jЙ.s"DTQNVT] I,9">[p$IJFO՞+3lV#sʬj)d q)YDaOS}NEӲg1Zok^vJT`t'&BNBq}{WED[`re3c?*IU0>SӎGq]46}k#ۃ՘nI2c$[7:SmpsƢyG,KKw>m 3{hVu> _amL}vy׿5KTEIf@;6ҧv9@w`''c?ol0 >m!%H`69rFg$Eo ~bO|1T rzn\S%xg$÷%G'ǿLiͪGy?GU] F3$^ngEp$g=+!,FֺQlF#䤋͟Yӣ3Vl `>Z'Ka¡o9EYV1Dn^^Ro\-jZ[d קsJ{t#[IoVp|G)#z031o'xdGjܯKё &U >aNF3HI28t!_1cשnd@#q6NaTP8֮": k_>;ᩝu-A2ܤϥuayUr~er#:n[$9w\ΏjS9ڧ<~MA^edɏ 3*D[U0qW,FP0k:Z:}񁞼 9yna cZUo1_ f`)i9*2]8w <.1J iėWEPEPEPuƉh7c71g?N▕![j[%݌8goq;ZWn멤3V(Xc[[c[@fj߈oYYJN60xv*fkb+(Y_ɂ$fbT6 ~Q)1zF[^Ieʈ f9;H1W/S$NN-Z4$.tkK y5FˍՉ+؂=y⥳YOhim;Gc-Wog RιAU/jy+',/װ9? mޝ+[0ϳ#{Q]5; M+tFz]YkэR0;~5iplllg9]R)9iJLВ4r@13<Q49cW +)Z7f*M۶@w#?wkB7c%, -4;"$d5T0zA>^jby[9Ϡ ֶRi7q+yWrRGQ\bf[WS߈a9E\Ҝ 'bCʻ ̸@! ^}(PvT˯G4dԌT ֈ4T@윈|5ۮJ3qެ*EGD);&˵#ò,>Ps*:S (b0OqW%tE~H*g‚IՁ;@V8geT$d*.*ǙGՒ8L-xRsj4t%ib,#+1f$0 } aV[ h%;!#0FxqZxQiVw$p}ͣ*0%W) 4~d<\3XVg,+X$>V"*S]N'hSE}Y;`5N-TE \q[0=am qrı.ۋ[6gb6:ZVJVTnFXb ]1{rz2n stA32?J-VI0>?BO 3tݨݑ-ZGQ3KȬ|1O-F_KcذE{lʹIXN\~Az/ћ/r;{6Ku#fI['~ry$HF%0pݵspqӨ#DKM%KA nFzgy:"Qw;yWmw^VVG=EnYnʌK$<ܓ9UdXL%c,8a9$v98#ﵨMJC[ chrɍfLVgݯL7oyf9zZU7_6 r9G1v9ӌ7I:7&vȕߌy$3`2~Egw=vX)þ wRiIvU#$A,r{0|A4Iqi[ mv~kIkh(a%\d|푁5xz{>u ?vMە!iVhw"Rd)'kmwOAooq.G~lLH8=֥))=ASh<KۃXeuYDg}ΫIp1N!Vw}1ʳ- Tկn#f$HK :#Vd, st:e,r##sH,VBrO {Ri6\ySj%0H!u#rOZ3=, ڢGyhݺCl^1ҴVH6 $I'R;JJ~8+^G HPK(l\r}N]V2`w+=\"{7aҹ14]N7"Ў8w%c?S޶~M!$+d~8/i=ʜkW!1nd''CY>|#nXC'ڐsWc)I5k"nˆv*;Ǟҹv&0$̜Ki_ƒ g?=9P[uN]VpT07Y[)ʞQ8v1U}/RfpQO5_ʬ:Hq95-w<%^xgߦq+Y/ F 8k}F@_%~P?5ضdcYQ\t cǯe 2'Ԛ؀?6}r sM4- %.H9 {ҬEq".܎^z[k')ҨbҒ$g;S.DI;Xs96[ ?jJqZx h+pl*sf$G}0=zun[r6$FWxgDd52!_*xqe<d}0I[MV6pC} U#_$G>`):ǿoWTg̎IF&x/]C1sr!##۹0Op`}_WKpQ| ȎnL^&x,c+1+~c-(o^s덵%v$8x>%cO!wrp=F{;6t3Fsk7(FONsk%㕔>"]Rv%y43_s?UO8+U#R qGO`7]F’z} tJ׹:l^'25=kܥ|Hv^+qqтoHP1=)R9`QMudqҽ&KoN 83*Q@Q@Q@׆[%݌8goq;ZW멫lhv3p#)i_Xobb,olor-=qQ e:V7fk]Ѯݸ! }JC3l, kY)<\qƹbŘTZU)gx^' t5gğmVH.xp?(~t`2U'#;T%&+簏h!:\&ye؊)?k:h{S^0 =)5뚯mYI&3t?֚P݅n~gkJIMN¾$79̨H ]Z]},ogN Gjy`{+&p۔ޮ|LR$&i%u3nc ǕZEl_dD?Ҫ۵&[9.I`y_ZӬѴ湚u><#394z42OAk9٤/cc]#?V4sUC7-GWݢNndŗQ3]p >3N0Ո鯃 "_bA^O?1]$(!ֹN/Ŭr!60#5RZXQv$$+1Qx$Wбڇf žmm20e3@{޹KaH bs+%?xV'< 0(FgUr==75]qXk( d'v5c¹ڳs+ st, jw<*a[r3֢mgj[ mؘGwf)`?z\ns֪Db1IYzWx+DL<)A<ѤmVu֣h"q6?@=L.Gc,OE^留3#}yFsrNPhv ±@`6#aFhܻV2Ļ򵩼pɮd#TEg &}[WgOW5T(Z1g^vvNsֳm]YeJg}=aYwpF=ǡ\ZZ8v+G83Dmղk o\g_]d ~{th$ٴ p#Ҝ q,~Sݹ=J*wԴR[8Kq$cl])6kU^'Ngz+]>`021K)U?gd8=njadNv6/5{k$n"8 ?^p;8}.tSivn\[;*A8볉t *#@W +@y4g|B=Ml|sA&L`gE,xcjz VSo6]=zq ڼ1^j BybsMyuoL11=k\"q( >xf3N4s=@u^A(((cD݌3qKJu5w-nncv37~-+B?[QmQLEұo-ұo-W_3O\5X.hnAc>rvFv67l.?!) XvBl≕rO PƶMiisS71 yv GE? 꺅y66TLvKۙ^qq+6±=? -@|SFH-aD #v z+n"D-('?ӯֳE[0MiYir KRqu6 Ixqӌgs]MFJ 5Fkw%{נi]Y#ğ(ПZ௵8 B2zU9uXtP1]9osqVFN<lI'&P"GE֯Kp@Sc~sP궢=hDכ!v/9!Qo}ͮs eI',!a\5=Ȳuec>$htKxa3,; u9@ fƔ&K˳jbSI_ӟ*-F_HUiy0b]@y*孹9o-`2HuK!!͑AE@C@^UVcЊ`heˋ @<zqm9[+t`ç[=x 2+C_IL5 OH[rɳӁJThtpuI缝bHI(S/`"oFI s+(F9e9vn%6\-eYU\';BxMP dRD;ozDzR0Oq;k׮#B6fX uEw4x  4^Cpŕf1HJJ'Ne)VIoB +js5?0`'ic>*`Vc4Dz3zu5OY-QYq39< z 5 ajf$Ӷ}N[an) UbGsKa8F/g?mkoinRP{+wL]pC)ʰA漣ƾM Ӯ6&b||6!<ǒxܪֹΧ%6ruReGT`.Kn{ڸ.$Ҧh .g ǔ,rv1Uo6d׏ SJ(XpÓ }0XًYwj䟙<,&.PLBRqOv\d]y.#`8NzV K?*m=Џ1n1c^'v\;"&=7r)*ص5,W}:݌N;I VoBN@0= j?eas'“9ox8',zszQ=*CG-B-wMY'gN)є|U-Hې7>8Qߥ4BFgZFyF6 sO}~5Ax`vTf8'?^5 ?,k@-CP+++$9=)tM*{p巂A5uMӡ~UHO**/{K1Z$;q*@?SZ5⣨IpIlhdQ]g5kZm$wSN<،cs(wwoNN:w-+SGq<(yH P1ʭ]lq)d 29OL+1- U*y$ڣn {j9&rJ?bKFxc}*FIL&HknGؼlKT;@V6vkK9jxԧ+K>d@󭛈"z"ݖ%3goT4иJSFTce" J6ċGEZjWD3|L#jS::Le$rj5)e/pB@B}Kiͅ*3_µ%XݙXURz9kxFi{V"XĞ S6r0~k{5.8 nt饃Puv1`n0}鰬 Qu"WٷhqִU@ ÀJvZB1o`bBK1pG] z =ǚc=Fd&TDMÌPqK;s8밖SD+1[$[Il `{c;W35׌-U@eV=V#?nZKui;b`bsi\8=XT6kjtVde[3lW4H+a&#Et`b`rrf_.ryp+ҕd^@)`;E|cz!#ABڵM%blrXeHx{W~qN6\'91ԏL.9z3ůq8F8i0IqxqM^-z p@QE ((2-f7c?#{GR-s]M]cD݌3qKKu4wV[S`}[K}+`}[K}(3uV 5۷D1aq\fk]Ѯݸ! }JC-VC[2ƳD1`IF*p}q`Vj"6n Y'4Q"i|^NߨiۙfڋxaQZQ"8M:$/oΒk+K#5X?ڜ&\3奎h ټqj%2vf<)ZE#$eõn^QIhz.^?#9ǽRCg]M!sU ;n[ɱ5rzv hR2e0duێ`6I!A~j]h&?дf`F*>UaV]Y2͂YExq'ҩj6gH`~~Wr^yJUN3VMܒ\yVJgivzg'齌.ח)jp8>Kq+0Olzv+O%R,3Ҹ=b4 *rf{Fݚ,4EG18#z@ڸPi^"hU$1@= <~tQ ,$t+Xd2GB yY$}\ }28,/6I ?t9l%b2:&O;zO\ڳ/2n,.CC. sҭ!gC$B6TNyϯOaDPDe2>f-g h́q:/ Xiz}~~rP|s~Xlj^%(Tr?y/$^28c.+uyez`T7i[REdeg1)w=J2ͻ"ig= %w??6:Z?hk4Xb0TϠުz^YŎ"e$ƶ>cGued #,@#'?OӓOF(nhk3G=eڀt\yr$y QyOM灟]z\\@M;=]$bĉObOXva#Ϡ+©Q/fy~:DHx,=llU1Ƕo7E'\?#޽5ẏ|,[ix``0?֨ܺbcR2݀E:j~Fʤ獵\w\eѰ 8;?t=Bmq@ ȯXMhI MvRt& uH+H<?^j*eh+ŭ8yIKWhY3B>xUm|#$l\qZK TdwvJʄ-~ {B:oUHZ;\߇oՕ홗pPǥSѪZu9:RpZᬮ/3&_L}/Kr!=-B=kRV ,KMZOؖzd,y=E]6¶Mڼ/eGPT;FhWϯjbt'?#Uʅ?V.wW"PZš l+KaJ%1Ϧ:Ɲ]K~Y3ZLKpî{U猁VS٣%J T5Sۻ&byGҩxXF(oY ?*[ >t(a:{ T42".NUI)uw7ar}3Ҫ ʊ^;OW!.;cf=4`19*ZFSlUݔOj;idf'?21+Ǜî rd={"dnF?kͷEwo#26˂ ʏC*\’?z@rx(mHVn- $ߐi$id_u ~5EºH|(ak˹UVA~}Es$I)gld@֌$dJ$㌌~~SǹrY U1c#k.pXpm!@AcOYe#NVD h@khg5 5(`^ K"17Pw{z4{YݽoEzckG?W\s[V++_E&Kѩ<(\^}pkWEӄ)(-2H2f$\c\+PWrCn?v`O'RP5;:MY"ֿɺ6`Ay%gમ>Dr~lX ;E[+c 叿'kN>~FX # @g]%Ɨg Wح 1j'Zwm= Elb.N 63>sskI$yg=3םmˊ#!Y,ÃϠҳdmAnE79=>kQ׏#>gG\ ʠlmKoCtH\S7:aUlۈH\3z {՛j6cpoL9ޕ;XQׂ;OD;'ZҴ..fuh F܇r {nϦszg$p^m''r+K~(Ӡbd+yE%Q\pIWU;ŝͭw20Bk5/ڮ,gi#3)c?.3Мz\<Ҿgtɟp\g^fwe5P#S! ߓZapuD Xi>3nE @*`eI#wry M  ""=鏥hk7veAL1  W{UhX[DY'_}IԭkWNޚIı\o$FA9]|T4jTcSc~̂A?qij E+=r|N1UW:p_/#_''rT1E|TDgT/SJfFtIB;'#pG57^F"C@ӿ+ŷ4RRFGt2#O>`r s'㯩銂KJqFÀ&@CWMcjl[m@#89o@H<:Xn.%A"G8axL qPc(_țU4mD+pޣ\8#IdTe;g_fM0yז<`1LsیB,zEմ$=`FV1"R<寅vP؀ $Îdd㊳i.>Ԁu1Ds"K`Ic;GoZWcY=NR ]w亨Nv@cڝ5>K8I{\,-ŵYrxI9}2`cL:f@i]''Ii#9_rc?q)c $q2v֮eS ,1KO9(\w5^$::G-*/Sd׵POz)*z*Gi'!Ӛ[fԢ~{FU#  REqm/dcpMIF*זe$gI͉ispQFϥe]YHTOq{[.2ێ8zcĤ4dn-\doƄ<͇>I4ǰhQ29$ǵha@P JT)M{V{:I8S%Iq26Aq[:)%&fco#Uu]8[,M8?ikF2۲eIi$Kw~ GaofOxpc ojx+;!9cUJKJ8 :4UXu68DTA%INYW?6:thB4MD0TsbXhά#a7##366r?5D 6MeRMDR #3ҟ++J*fXg kNiETsg`o>5B쥊(olWMRfS0sk#+f$tN"Qf3:O ksqfЖ֧ kh(QEQEw^lhv3p#)ieZ Ìn~FӸZC;ob-Պ)zV>zV>kFiFmۈ"یpݰtW_3O\5X.hnAc>!iLQ@'5gğxvvʱ(Y%8$$qM,WLlyXn6g#c$ӧ@a}"O"+2S,Z_98`^d=yS&$Ĺ@&2j J۔F"gP?w5f-,9a ߭fA-.vv4ʫs#PԣK(!zZn -PEqpT 0p22GsRԴ4)ƮYr0@ZQ|BF/nH,S&rǨITIsjdVQ$[&7}yy)6]}Rm N՜Ifa U=W Fx!6zJaCt=:Y3g O>}EBډWILcI[cy=6Oz[B裛oFLl$:di:H+~J>4z[Hw'P^FCasϧ}MY<;c .p GI6"NsҢ>ݑ" W/Y:=2{? v{7zg!Zn˷lۙ L72)B@ɤD*N*zƅi[w1fUJ ik&zP_ 08Z2G֎t[w#$q-I9m-U$`kg`W&L4eXg){XW,fT 'M\F)hTz؇FKR9ݓa<-zl9+/g7wtK3̛ULQl=ٖtIcr9zK B8Q H-ڴ-:R6sx8?vڅ堏$gqQ?we y1ONIoM$f#ڭ[_\[9x&91#1Tc#֕gF5%-|e[&nsq! dRs NU?JĊz0{qY-IۋźX:r@8ǥ6}o=:^%*R\KZŖ%U$§;'kkKy?f*\:,zJWK{ 4"{rîGz|}Y.Ɉ7 zj7 aH%YWx6sp:m&gYJ,3˧xCB)%%݉n]ҹ~g^4ug4h_ys8o0*` #=6XkS\pp<׈aO!Tg[0>7}kLʶhIwkRmoOҤY_0~D'@W$a.H#Dwߵˋe+†-3U RޤdSG!sLݔDXn19Tż- >pூ*ޖ79Dr==.kmmR)V_aOOzU4j<НozQq&p>f̀1sslB f6eӴ]JĘr%mU2x'ի5Re6I{m8 picr`wʁRBf!NMN(Q# _Iܷ^I97x۵fiwna潉ei8ʧ<æMMN/dl&l\ f Oҡդ*=0Nֳu3>,M1UdbĖ,F۫a<`ch6cPE,4V]F۳J-G›~9?Ҩ\=եܐ)`ʑA= 5b1G?WOq{t-<@K ($8A=N:?#Z(\G~n=p\)}ɺ%8`{#cYqћب3039#䏧8R=+ jQًHcI!U?P PbXX{曎1֠p?icUËyԫx)J,tHyw?D!Ԃ0FG,iv@}\ n:em?ZrS5 )4e|{+Z8*q\q]q*C)ГҹEUkWW ԕ=?+ӵmǖ_gVT ckP ,4Mn!󧾗-X!Uw6\zgVHy=8=΄Gک\Hϵu8Q~5^}>+gBN053pw8i85zvz`7`=A~HM8p}GɔYOO=o[ʎ FsMU:ֺQ3PfY.?ov$=TNSFT֭M̿6d=s:d$@6X#v r/Z+f!$\|1aǩSmZOL5 jصϹ"iw^Wk7̗7@oUUPB '4FSkLF`S[tFaQV%]] ?(\1Ԝwx9UݜeNG#޵.O zJ qhM=km[PM0'bַnSuZHFAKWܵ&wVf3Ѻ5j}.1hLҼAXqz6}}LZı$쥕F#'jU-4{??^vYp;`]GzKIn3kZ⿄n0'<`(xGѐ-3!~:!p1ЌMhPpWx5[k8%¥U!?{$!gQqckr4]ޡ@+^55U`:ˍOXm9#$uǵte}Iʁ"y4xfIuq4f=S[DH-]q ?z`j5ΓB"zd-Јݕ=sj;du{oJn'5Q VooXbBHϠVTX٢lr.#c :i%9] <ƬЇva۟VO@2zUV8c+-kY7IlF&=ʪ FFOq۾=n=-= QЈ[Jk Svz]*VWdFޅy.ͼ*c2]B<)Rw#]sN:cV~M=jň_Qz26$IT=x΢l i4f$pq1zV1FPV[ғZf ND8M:k}ͼHH0p? ֳ3w 0U'֠OIdUQpxSߧV%Ջ%uH2FN8aysOMv,B6}rxnmS y g54Eu$մ!RW9Su\FVT(p8 瞧8Lb1HbWGʩ>:ݔ>a)7O@Tq} ]YPq^XQ޳[V`ѓگǪDUTs|guњ*zuvo$!S}qJ̒+&@!QqcYxd:X<ҦťvkY#an' {Uƴur%lO.%HW:&cۖ i *[=Z V8;P}=jf d[u+!uS#Ҕ^Ot`R$rNTlW%Pe6=^1^{[;P*]˩[[jݗ :u%4kn1h0{[G2ay}?՞x͟Wu=X"IU*@\Z#T%S(#ڤ#"; 2~(+Nⱝ"`j4}j 360WOSqILE~ *wk6O*cRhGO;i858Xҗ'bq$Ҟ.3 +2=BE?:XKqRٚjǴ5k)L668:r fAiw'T~Z0xךNKAHg8[ Ls鳺JHU?N{+c^3p}E][ 69#4U= v@jRI?jmK*,N:a80Ҳt>6 ;?*B09J[x'C¬KmD,1RDiS6T 3Tf!˴-m,AKa c„좵Vg:g@Go~i ]L7NzlqwЌ֊3lNԋAL7wO)eϯҴR!b2G N=U`o,+](f`}*6`~Ts*99B ?:]۔ֶy{}}*ڀ0s"ёCVnqYHnr1T&Y"ʡ':%L,q9 ک .m*11I'~~F ngiΐ@38Զ팞eFءoR ;9n%*O$ PnX-{~\SWzj J %(qN}I^\\$-T@?Vy%Wg71@F?+s4iN-f j篻w+.y8G"W\뷎ǿckH8K2)U隗Mt-U= ~'LᄑXZҴ2k,f2[WAj6+p=?JыsK4?nJFQm߭CZ~"hE, WďW}lm4iUnM s03WKu 5mS.s/2aO+xtX+ + 'i.?K@pb+7ΝnoPٷ-b y=IЮY#+'(899~0y 7+o-G6f|xaddwo \Žuȥ*1siMzHn*6r[#[vm Om%~LgtXerpuZ&731Bu$~VPGuk8K[^^xb1$Ux,${S{wwz^<@rwP:gȭ0=Fsyɪ,B cj駡NG=\N?!CF,3'=0Y!Ac5Ryvh)Oұ?*a@h1r3w-eǡIUE_D%~VBwlsPٔ Xd~ `AS_s?LݬȪ ǜ:}AhjvڂAo)VNY% WE1rDr2Ng֩3w,-X!H(p=W۱Q^.EHU-ā{g a-pp2 W,5]F& "223I{ck RMgxn68rzֺc{ٜL Ȳ;ES$qh-lG Jv@ܹ铀GbA3"\csNddqۮN23ZRPE4o U$Z( k=3Đ]y\8==\`9b(gAl=@OM՜)7̙$ }KN35i y&uw9JQoA:I>bwH-R5qr:?`NzsSEio%mH\dfrsXwuazD*D+$LU<3"T6˦K`OMݦ>mĤ/BRH9vǩqi#$*]l" @NA#?z *`]@g?졃(G&74F|1FI'G݀ᕕzWq֛sJ!imY^I e>5Q3ms{i~dqʲ =I ֆ4sʪKTqR c30žJ1%ũk} rz^]$7"0 }Azt\\:¨$dg=?_yuQ#ލ^xs.~ת[iL$q:o4]y1U緡}~ktý)X"hr9 V{&ѲN1Y(G\zF#'%!py4Hg wɧDd9ܮ.ݍ[yNH)Ey:К-b B%p%'rǽ,/E?=NeB ;v8#^bGٛ-wx$[wo k4QE ( (; 4KAq?w \CW<2-f7c?#{GS-s] !ͷEX=+VRJ=+VRJ|5#4#]Uv m8n\~C:W+g6tmk2C帔6ND|c6ҐJóYOhi~K7& q~)SN#uqLnB?T=|ɥr@@#44hL?n7KR]U|1L|Ekj+ٵFs{<299iqk(<2]wD8PI䎂+\=l_1gF3O4]lb 8 h9269*yn\0籪Ү,H"=i"-e(cKLb NsK֌PA52]L5OZ_{>[țֳO%O*)I!PcXr 2]L.^]MJE'Q5>}EXK_m>⥧ԤFYy+}i$*T) #PF8u@`F9a5|y{֕"`YHkc*[fMaݟf\i?-H m?9?Rk 9X_ʶlHUI[u7$^[Ao8de<3m v$Ue r3hkvJnⶣe#2ܷ[Jx5BX!e^צ`輎 uB\-x>ƘmqxڻthdmDFI\:?ǎgp[8gi `aZϗORŔ8T aZ&=%I?.,GсXWOyhۻwCT6C=Eu%9' ӑ"U{]h/9r[+cA֜CL_7^&F"#Z)'[%թ ߵHQpyP z4-Ǩ#TJ[)`08ޘOOxhJCp3 =!sП«:; \z TW:-H2(b+t$pj<`FLSrH<h(]zՈgr 9#ӨJ;ۑ1RO1Qҏ(Ӻ!aB ثclOǖ#"g#=)1:Ӹ:8um.;=X>:8ۗ He~bb~sr)嶒j/Ԛ:̏ l+mKĂ|Iq,[D0Sʁ>z M"UԆ`ִ3Kk2v{gxRJNPJoDcrji"@ZqRX ;q/#223l_C] k^[_xjofR$z%5z^oKWhu$[P+:Trڥż23,.d7Rŧ]6u* )z#e95R`:֓ZǓ_Fcv})wGOjܧLo$T}̣#2{(+n\Ǭj8n?ҳ=")%kW=mm,6nM Q85~>-J*1M66kj/Wih@Pgu1RZ)F,K+iRU@>k6Z p=O g,1bG<|}LʮG;m$̺wn]E>cy|==3Z)K3>wVw+*cϾ}S"W3t4iJi_B'I xBR0/'=+XU7:Se@PFx]MkIRCH^=vIyzwEJ<\oҳekFӽIwHHRу#Xy*y-n,C@aYG4:Ԑf \{f7^:YD9Pe탊n85h5RN(昄(f(RE6wzJmv1SOS=% D85KRRf~T)'gR:M^NȆj@' Ac3R\} ː}k(s֥ޝQ> .F{Y74RE( p>q1lH]P˃?íL\ -8֗;/c6% ROZw>cbmV?ָ>Lq%Br?^˺\cOYM()<9Bӧr&Ii7=EKY-ٸ% ??޴ 2#S`V;M"2I]%X$k'yb:.WdzKttlr>E%"IDKEuCǒ͟ڂF<bWGOUc :m s]17f.l{V+hȷ!ǒ#1\: uA$ܐWssK;x5#h\@8Php#10P'`Zۿ" WLXDRd`rx=EJM]NiP2\[[0/I|fK1GFۑMcV^Mlz5r-$- cG_-;L,h<{T$Tɨj1;z`)ډ:=b{?)YOk>9U;QKI$èU_\n,?i-5-%(E Zǔ&tZvK:4`x=TlPHav\;V]-?H' ZVY#IbǷsJ7Ӱ+>+GJpzۭQy0mW]s궏 l`Hv?*m޹HÇ1RU)讫Wi׃A6;c= Ǯ;+֑ 1?&v]1S 9-G5`yǒJ2 H>e]QؒHHIIAk7hmg1x?8U`1w?謠 S\& GNƕc 14ֽS:?ja~}^p?&=נR (Q@Q@׆[%݌8goq;z_롫lhv3p#)Xobb,olorh ʶ+W :VfjRa$JW G`x:t)1O {CO׎9?Ϳ%F眓֧YOhk2T~+t;Bq™3uv\j+Ξ"Ky-)R]%4(.sԙ4fqH~j7g[ҵCÚZq{7yrW۸<0##U1[~&>)~?olڌw#9ێE';Rbi!<@) ;E!R`q@ h1Hi{b(c4iqK4@ (1Gz1h=hvn)M%%/Q@ QE@fSH>:^N=5(&}=2/Xxsܵ=)`bx  G+}sv^>l@ݼ㕐t_rjjH%l~< d- Z1dvF5Tyb# UcghX䔂VQ~j]bKYUc0&t.)#magLV|b&@:m|~me'+Oi A8= ghR2YU^64mu-jve}>'UʎyJ[O-]zګe%fz\6[`k¶)T%_UƮA2boEtl:dx_QVq A?DdrM(|E;Z~+ KDZ>k)?x0mHpw ϵuќZʭt.ܴa?޴bpFzedħj&OMh`_o>4[orHkО2*?JF( *OTRzMcfRC]bܯs#?ZLG(/+WL݃Ni0y"G晑޽3:/r|>נsGo k4QE ( (; 4KAq?w \CW<2-f7c?#{GS-s] !ͷEX=+VRJ=+VRJ|5#4#Z_eU1Vv ^ӠY^ٴMZCpceRЁt2 .]/>ًtfQIR.QzuCRXZxחOBە P$II*pI)YKFX?OhJn}ɤ)@B>zw> iq{<2]wD8PIҹ1O'N.&aMfM"'SKv 7n &9ԣSjFN21Q4wҗPbf{PF)9ϵ8(ǽ7E.=h@ bPá鸧@鸠F){ъAGzQF3PO&8(րSM8@ JE'4")%.(4P jd>=( QbG88)c%+"\wfysrM<+:F{/'dn;1 (?8:纟jʏVpr85f=N EKJF9lPƬ˘PܶzJώ{y~S XCzERKf^X&.ٍiiF3.NsΝèSS;ⱖ5X-@!L?6sݳy~?1?OL2ǝSY<+_ 4X+&a!*3a`R9x\Z>zrX{?:N/hMR$bdžR8ntn'0 ?^;}k̠dGWL;1NJI po|93uCqYRA]qF$g~ԺwSHӆ>[N]$Ҏh#vcHg,JQɺʙmXvܙ8%n#xۊhKYA剥5&瀐%pv:m.$E{{wME(-uۯ F"7';IZs˪'U<|/ 7\7œz K+$3Ԩp=ɬ+ ȠD%G |oǶS%T7*]gthG>q!5JH W +Lt&MPyޟYS*km/^^iQ"]TrמʒbBii߾`BD2G9ڶ8s=&a_*#cwn|Pӧpr[ Q^*R\Ҥl2?\m҈nd#o&煎۳GvZօ06ڌF?JX\g8D# Z3E=3;m=* &My]>RF+רBA ?u]5T~5Aе-nI.~'ޤg7Zf0\1V^ p2~?zf ٭䑲w6\O <:P?{0 :rE HaJI=Mc1G4's@r{zq9MǭI@ۃb#idQЁF0h0qҀ{ѹh1J\sNHLSM?oS@ 0E9cE&8KތPc:Rb\vGJ)R~N);QǵQKAF-%RI2@j*(j3.g|lCȥ.T>fo iqUϿΟ< s)+r}*yGn?fp"]L⦗+kp?J.$UuIF*](KRkfZKGZ4`μ.gYkMm]8{]"gZd *UpUʷY<4Y=nrkf ʠ~u {& d2y> {#(wۥ^*F~SBjW{3ןDѮca=B_²<j6:2qkz]kfUCIg8sSxa>Q%fo'a9e brGQޒvTK\`ELc 4ǎjbHu r$e SݰX܌/ [ 2Oj.c6HSɧn.fOyGv/ >÷^A岨¯9vYZ%w8>|8VTsǿҌTUe);1hj&tDG\Hzy=Kk +* 5a00z{sEB)^py%P˖خ3Ϻⳤۮ*$3`s?sJJ< rq k+9ι72Q cck9?cG, kVk&D]`Ano>艻w ۜ7} 7@5'hEL]`An47}snsn4X4ֿ7}7n:*s cv-|CC6@`ؠ Oֿ@=Ic\0 7g47}wn:(ۜ7} 3@5'hE]ۿF0'ݟi[ᾌmsq> ZrƏX4o.EscvOo2tQ;q> ZrƏX4o.Escv-|CC|7W;698[> ZrƏX4mأnsn屿ho2ntUۜ[> ZrƏX4owmsq>oEscvOֿ@9hw(ۜ7} EMۿF0'ݟi5'h9?c@o*698 |CC|6WvQ9 7g@oo, k?`k_Oᶊ698[>ɻqWnsclog, k?`k_Oᶊmsq7} E\:(ۜ7} 7@5'hE]ۿF0'ݟc' Uݻmsq> ZrƏX4mأnsn47]7nscv-|CM9?cG, ks|5vA9 7g@oᮈb`N1?'`k_O Zrƀ tEݻmsq>k.؃nsn屿i5'h9?c@o"n698 |CC|5vQ9 7g@oo, k?`k_Oᮈb `N1?'7]wn ۜloOX4ֿ7]7nscvO苝DscvOֿ@+|5v `N1=oᮈ msq'ֿ@9艻w ۜ7} #|5;698ai?`k_O Zrƀhp0'ݞ7} D]ۆ698ai?`k_O Zrƀ苻p0'ݞ7} D]ۆ698i?`k_O Zrƀhkp0'ݞ7} C]ۆ698ai?`k_O Zrƀhp0'ݞݶ7} C]ۆ698i?`k_O Zrƀhp0'ݞ7} D]ۆ698ai?`k_O Zrƀhp0'ݞ7} C]ۆ698i?`k_O Zrƀhkp0'ݞ7} C]ۆ698ai?`k_O Zrƀhkp0'ݞݶ7} C]ۆ698ai?`k_O Zrƀhkp0'ݞ7} )kFI?تW9 cv-|CM9?cG, kiKinsn47ý%wnGsĜcvO`k_O Zrƀ$oZB8ۜlo֐>698 |CQֿ@Hݹuۜ[>u.w>698 |CQֿ@JݺMmsq>ywIbN1?O`k_O ZrƋɛ.69x[>|iK9j17} W9?cG, kVp"0AT.r6n屿i'Pns |CT`k_O ZrƎU9sK4fsqn~>|.PuU 7gm|CY5'h9?cG*Ϲ|;,a-ns1c'ҟΛ@sF1=o9?cG, kv9<,7WsOxLkmw85S@5'ir} 9wo҆1ݟiOc^1?O?`k_O ZrƎU9rv#ns׌n4dlXϤ&N|q?O?`k_O ZrƋul_9ݟí^.sGݞ>ֿ@ˣVN.rݟi;+98|CT?`k_O ZrƝmQsn屿i$V+sn屿k?@5'iX.h7V#ݜqc'xOنwE$cvs>ֿ@]vJ4ݺ] c;c'ҟRn.ģݜ |CPֿ@=Iеlli! pfDU8$ E]۵k19tak7@5'hUݻVsLn>ڵۜcv{5 ZrƏX4UݻVsLn>ڵۜcv{5 ZrƏX4UݻVsLn>ڵۜcv{5 ZrƔxZ'A?촫eӭ->[nջ7 q4%KO+{ѽ?Uӿ?_Ɓz}:Ϣo4eZޟ_ΫjZs^msE*na2='^>}Ϣo45};. P5=g˵{8Rde':$ l'<^ KQ{[smfGTŽTepnezo/NVVkz}:6eIgpV7.mwi"aR5/MEhC06Mkƚ"y$ky2\<.F⵼9`bM#gf=XIzo/G^>}kz}:͵lE{=@ "FX.I=^>}Ϣo4Tִ=3U[n?/h#>Zޟ_Ϊezo/GKkz}:7zo/G^>}ޟ_Ϊezo/@=^QP+E)XO( r23-&~96;OO^r=K-+& Wո=;xXH28 :zFiwc<~[\wA# X3tW:vz +j2de+aEA<$q;$jh%PЯ㾴Y4`. G#dƩró^Cuo-y+si^5 NeķіXقؠ*z:S//R'oWAՓJյteFeu1™T`|)jɥ꺺[20%s2:X= Oj6:=VGHt|f l"GQԮa ;kZՄ E{l|dVOK}Kuv=g_υ4-Y4WWK{TfSĮpGU+'r3]t*2RÚG<7kV&YɳHBǁ[#s^{MNm9˅vVn)7m72"[CَIkz}:ʷZ[5iLccӭy|0 1%<8grOԘIpbkեogOz,% 麵T-^oOFuA<5?痆65O/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AK{toO^= _?Wyxko3Gױ?/AKz: b[_JmKh;W8Y>Zlaȋ+ eg$ۇ^k6oMjóO9pAcyMFu-e[Mp(`|{6?"O*GOnF&ߎ534{Y@Q8M槮t) ڌ[x[f pv~*_}K;6 -"CW{3/8 ]-~J5[Xg=B r88ʁYZ^-7X4'.jI%TXkWP 'Y:'^-D%JqN6Ib[|淇Sk:ҟ\YYC p<]/u]v+*o&0AA6re30pC2\8/.4ohD˹Ҳc`QI={Q%ӻ) ((((((((+7]% oiLኞsZU_U|/,Z8`L:0:1ҁ35Hl康yUC! +8`H V`Pѵo u߶j6|4(!AZt|Ct@Z#{?ҼAc?Wx=^Q>''lH}䵩Y~ ?o)Q^_PSxZmi:݂] bHG8HG[Ws㑦ױ-ڤjhA4PHA8ⱴ/TۥԷ~)yI$>\IKo=Bۂ3zESjXܖ ɝ@w_B\/(Š(((((BvMZ"ZR7(ԀqPj__/k|s..zl/!kY㳶AfbGUu_ iZ-҉$ସCm=^O".'G =A dz+t*?S6J=G ěn$Z՗{_o)ji~0X/&ТmdJT0-ryU#ڊ`y먵iZtucy4FX 8<%ZnfݴW`Up'1Ӛ(V8H>EFQ̶$NŸa30ہucҵ`3D\py)"A2qSZtSz-5G#kZJX-֏mH'Ӕ835WMͳi { J6V&,uRxAdWqEwc61Վa/كYD9#/zsNIwkY(B/+ )䜒yҊ]-t$> uMMu9usu}omn%N|I$]S(0(((((,-kh|v6C޶+֝]YYۑ{ EG8<Nv/B?UWօq]yj*Y\JA=x\_JJ1^/yN%B{_o/gKomWQK ;5sq#s s}<+Kg.e'nf\? 83yxMx.4.Xi{|0`m_^'[&:ik˳Cmb'+뉸Khc3[j&IO@29oxկ#ƿxt}sBԧMF;k$d!VR lZJ'}RΑ.e(,#g;}mu._YGg @9 Cl$p8nյkoYHoyыd6  tOxSMN5 .gäd7r=}O^1hP$MKE0WUfH<7iyu1|(n]05XicR-`#?X޵-6@Ͷb${G*?J?uɾ u3bmMy۽NSԣg["s+۸v3ڷt^}_ (Š((((((\{K BkmZ[[F^Iw(pj/xg\n^"fsmF'@j:h"ծQCqw2ŷq'n~6]][J׭#ޫlAje_ o&PjpHdz+t*?Sz: b$z?}ZԬ}䵩HVָ- \}1`3A =(nJQ^FڿKޣsukCsqwGm;#p w~/m.ē^:oآ7p"A6C&6'&ߟj3+eGּ~#/ ALQчJœlg$Z.$xWV*ٴ(2HMX`J*ERQEQEQEQEQEQEQEQEW?JoFzEy$mbyE;Ts: b[_JJ1Z2QkR=/֥"9<;zUM)xEo8$*ҺԵMQ;) FEb }Ĵ6eG,|m3qlQ H K^{iq2DD>{{KX.#{Rxղc,2昌_u!]H.i`:w٩n<1MךET(2q$anV BOk{Kt 4NI@B` *۫[+Y.nanY" $J AE!ECowkq,[4̨mv8=uK=kO%}PvW['QZ4(@QET^_]Akm̓M DAX*»i[/i8 (ĺ6}qg\p僸DJ,B1עii2wg"l}XP^ ب5l }29+?h%woU{_61i=|M&h#4} ~"gW?T,~odz+t*?StkR=/֥"űmS_T2z%l/6(q/^f:|9HjW:=!̖qhpymwŚ u+HЈL 1Z𭝼IqOl!H␛ud2JM Dg}SFӯS$,? }΍\PwU Cs%4d~]j7WZ%El-kFX2Bt뜪Y7z.Դiڽ.V58Q*߃9P+ⶆ;‰Xy6.'T=jo=2ΐI/h9 qڒ[B穅 |-s[JeXnCwWko%m|+ooo}$yۼa^kovְEԎ4 =PŦiOgi;O ¡%/.0ZwI_Ցvw+;@_ϦrMwyxܸ 8wmQz=3Lo&K[ֺi&e&NH݌ת4ǰk1lf1lTP<:g\:Mvn,9ٌuBӧ馟ISީ߷jQ|g{J&_1FHL!#xwBԴsP8-$#IX͘Q;^-PKm a {i3qֳ|/ᛨúDƲYFY#O$4y_ҳ_~w.X'm7Jñyz1fsn`슥5 o 7%z$q>#:X*B=+Լ~+֧ic}X-v"X8-:k_StmR;]OI/q\[$cMKG~KhΣi>ֵmB宮0q,L#F-dڴ/ޝLlaVkg}~K7BUGiJ)8'9ICgғJH-^ +B0?*þB糷Qo-m_ Z/~ .']j \M nIL8^6~okng巘$9ی+(5mi p6 o RX6<²;tLmX!&} H~xX5>th.o\01,Lg9'9<&l?vfIuyMRXZI)B[l#$e צšhqjEiɨw] x9|g0OJo%| 1~xg_]uc,Lon{?ҼAc?Wx=^SP+?.o3kGl?;r-jR(fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣQ_T(e~FߣSm{'?Ue~O_Tm{'?U>fߣWѹUy Eq]]|Ť|EdfVV."gW?T,~odz+t*?Sn̑kR=/֥".ܒFl|A࿈!a^OKf6wd#)(@<G){OS;k4ltcw𖇬bm+XB!c.csօko[::(Š((((((((8WxF-z=ywK$oRo=[#}GwZs_JJ1^/yN%BY(Rnn.wέF9ҳ_j:D wDA?xGvg?S|s_ ZE~̷H̡Lr1 +)Pw4"ԺΖw̋4MW}@wMôFc*pڦ :BqλQP>?Y?A?BιHVY?K г/.OJhb :B?Y?^(D, '@? ڞ'*s5g^#/.쐴wj?S\?|= kA4;װ:\ŏuYhI|'=#w%0r>^.j)*Dnip2-8.7.1/doc/src/figs/snap2.jpg0000644000175000017500000007771313351443023013346 00000000000000JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJUs}}謽=syy#k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZzV>sFt-V|m.?e? Uˏk: "r]*!s $KUU{X+u9պjonZ0V!#SбV*՛]\]'r?%^dw]Y*;0Ռ;K6kL0 Ř7Cᵂݘ F_7`v, n|d*]WuQvG%Oq<{KFv fQ+HA$j)Z[xB j;C2ŻVT6 F/Lcm`bg@<`v$| 9wxn?j#Y6vҘ-$VtJlM8W@Ł.hX*Ҙ8gm;:fmg~$hCX6+IWPm=ʖ*],G1oǛ,ݗm1*EQ1>Ro"Wj>RiVyO.S;Cm0VR!(Lɣ@КKb7k^Ʋm\ڛ4pj ݎ⣂ɣ %<4$ı\<2cVcG%BȪ2F8'ןJ[hz…j:M;/VCI9fCqGv+q?ik,F- Ď _ג:cSzp&f]cT&%bȡCyŠ((((((((((_I4V$5SQk7Kf{S[ng;W~xeOa)pcpkm8)sj@52jЩ:٫K?ljkZ ?QVXQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWJ5O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Z\U9#K;]XRWV<֖4dWuVsp=xMzp+?ce|"sɺ|W'M0t{/0>g^x?.jW7*c$L){/0>gQV?,+) |E8+$ (5v-ė<9oj=~BIyTVk/hb(Dc&9$``O^co;^ʄn[(Qg73(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO3(?K5IYBO6/f;k+8b:aZ5UbQE2(((((((((((((((? o_ozUyAJƇ:w'VX'V] QEc[[c[@?iOܧz9#K;>յ4E!E&# ; "Eep3*8A6LϩY*jv9Xd2!4\wdV5~> d }lU^X.Yaw ;s蹬-CLto&FmgY(#jpzxo_HkrN1 Y'W:K<:$@ 1ZFKxxk3Y$A>v$cB*mNgYؽ[p?*]uCk/¯j:UI&F(݀,q1*3XZӖKΕ.eb3Gw=w:ΑY8qڡ׮FA8 dX1.J|*8Ljsqa׹ $Ե'zӭ&F)Y7ss`)[R`g@+@jao=0FF+1Xђ$gIhQsOjJTJUbmwL[Onmn[lIu[=B(%Jf;m '^Jӂ-Fknn';3 +g:^iYL\H6|u; -՞P!eYa:qXA:׫))_=S6,v}⺴ͭvK04Q g=꽼B.e.z@kInM,wO ;pFzʝ5@Uی:Fm~33«Er0CfW8T5PDۑp3K)l[Vuu3tǥkwdž8vWg\Ñ̾MuQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEzWYmZolV!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@yAJd5}uRwO+Ұ4O+ҺAhJտԷҶJտԷҀ9?NxsFt-]w3VŮAvGdzc^U jF*Zo?!LELnLnVN☒C!rC:Pz[u^/l96 󃎾3GwlM"Pl;ٝ(fkzXhڥ-_ke@p  J,zy\M*B)ʲТYKɧȇ`2@o'9 p8c!`D"1l3$䁊[ 2Ĥ%1!BY'${ſ3-/{:ێrqr*];۠KR< GEH>0 OJGŠ( (((((((((((((((Ҽ-"͟Cj׬ ȳgڵ ((((((((((((((((+͓@ Wכ''h|COXo_o_or EPzV>zV>sFt-]wß4AjS!]B%G7O"Ѧ7Jy7J'Z&Mib1+@'  jְW0UpNXd[pGzLg'K]Nf6$c#$/Ccv;/ fIn"l I ۝l|$zq~&&h"  #+d H+2}~=E"> I\q\ʝ󱦒zhvi @0 $FC63PK$2_L7ngV[$ny}4eZO{3tK; #^kFⷙf9Jd}Jں5/!XBi3,pO,q߽Zi+ɩkF 322r;K{?e{\樮mYU ]`)b 瞝Sm-AS,.r@n> /d֍3F;pQq1r=Fƣ>g%P̛.7ln*)~]Z颴Ѯf[-2%<8zǭ*[rH'hX!>w=sWT,hnۛaapvYh0ۥįBrF![sG?w2rWCom\h5pa,.7Ln qM_GZ//4Bcf5b[-e CPN/?bSc{u-pG<ɘ~ӌ>yߏ]_0/Q]>eMdԝ?Jei- iYpg4,}7k'9+6j2}w~Lgv(s3 ɵi-!+xn#`X31y⳵˖0av*nqp}t ?nt ?nic_pA.-vp0iP c c^qVmE+F/ޤ*C-#+z6k(6k(񺧇n-?*-v֬sC/<ÁzRL/&$Qٸ]`xǩk(6k(񺅅Vw}fjdDi#$h̗35ё$198$>º͚t ?nt ?n_z34 "OuBc7ˌcO=̺6cn"X{8f@]?f@]?0ӯUr\}L֫n[xQNz7l*;P[& 1 ܈G]#:u555 M_޿ o'qk-(J"3HϧyAxݤk0fnَ;G? Qtl? Qti$L}o޿oݧ[kgM϶PŎFj\ڵʹ֬*MJg,3y;WAX.GѳX.GӖRVobJݾg!^mɆ[]\>39|tQǣL,#͜&$ bN.sy]c7Fc7O?? k_piż1"\ƒLUm߰r;jvmjKU0#!)f)#ۯw55R+~q~_z3/ZyuE[HayAI\ҝ={E<^b6'b0C]c7Fc7SykOʦt<+geb3 d8"qrՌ :j3L͑y={xf@]?f@]?iO[_q'NԟGӭ4R.BgEKgh^+k 0Ld|}Ӝn"Ϧ?̾}+2!+YL,[_sZݽ ń5+*H#*H8xwQL9$oVi#1'haÿl? Qtl? QtU5~z30j66e+UgC dcHa+ir f{0/{;Is޻t ?nt tkg0je?u5W02Dpv0V+Ѥ#i;QVHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW'I6O[)XOU/zNDRJ+DRJ+(}[K}+`}[K}(/Z\7?iOܧzCESQEVw?\O֍gxEOdMLiK㏪}`/k N_n[-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEaiQ_EGW: o(2 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( m+"wNϻn1Wq\NjT%')NJ.+g'VX'VV@QEc[[c[@?iO)9ß4Aj pp 7Z7Zp}aqhUf$uTPVX%lXs:qd&^>gl/E?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|kL?kL?\G݇_ʿOzi'zi'QW)]M3dt}]M3dur9v*e?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|kL?kL?\G݇_ʿOzi'zi'QW)]M3dt}]M3dur9v*e?LnLnQG#/_̧w}4 w}4 (}{E׮Ϧ2>׮Ϧ2Eh_2?&O7G?&O7W(aS^>g^>gr>=U|ʶ6[3#Oq1] `g 9TQTJRrwaESQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW1e1e_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s/_]=s/_@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3eW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>/@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3gW3g_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>.]5s>.@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3iW3i_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>.]5s^.@z'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW5i5ib4O+Ұ4O+Ҙ(=+VRJ=+VRJ9#Kڸ0((((((((((((((((((((((((((((((((((((((((((krtxZ =J+|t J+|t!hJտԷҶJտԷҀ9?'ß4Aj ((((((((((((((((((((((((((((((((((((((((((+wܴx1]-s^.(ODRJ+DRJ)Z(ұo-ұo-7GR$1)O뵻eC\˓?II?|QI?|Qj}aܿOteC\W(W(>ߋ0n_sr'?OuyR+yR+}Zo}vu/9?k?]r'O>[\5}.?k?]tY?޻eA =Z>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'޷())r,@֭W QLשUZoK u}>e?pb1 u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}>e?pb u}S"O ȈK)WOX^+\_J+|t J+|t!hJտԷҶJտԷҀ9??Ak**1RȭX.{rx?hk;ۃ-ZG GBː=~wU.2vwW|x Ls"e+f<.ҰcdՐO\[*Id 1}+BTd2*beS98s(J0ދիFTrd0qW4N[E*Ywt״hYD]WrGRT @\mD܂&O1llŐV-'ێi4Ro&]`G, q\=PykwÂN*O\ͧK{ r|ƕXYO8;/BfZjZU 2C8Кѷ8kM 98<5ګz5Ⱥ,hLpGPp2q}lմ9`6r9Lu9S<],HY slWf^Xiyh cr#q`q8imKXŝi9\ pgiC.ŧi(ɖ430+na񓎹֏@^eI,z^גjn(dgrǞ=^x(4=B;V0n?ΣTՎef=u$NpGA=;fn=\a-$Vl:VWZ_#GZt >;x2Jr# N>>:@/8b8<u$)trȂ7gcfizǁ}PcWmo`W'' }QnFu%юHrhϹ-|AGrܜ['('Bwa$pyhcomuȏs]fgԯZ,q*[4o뱯L'm.KKxI"x/ G:U4IJ\PF#ؚVMyMJe-P)wOe-x͉@2m&;iOe6q>rgBޜf}ZL@c hϹOmCzg\ǽ{JqުxHֵ ˈ3j]C '8=a}=ƻl7&Oך:N/"sIp"R㪯8I[xVHѮOU]HJ-[A -'{tFB%X1yw-3O`ϰ<DA =*][j7A"PMuϖq6z 1nWUE!-*䁌MKDhF6bmg{fٍ_z5!.xR9[ =zT^ pO2! 4 'IjBK 3`2FO9֧ki<;zV*OX tz~nH=ɫ]|KCoo;];O=ȭ8fHPrWz-ҵM9!hoM?yC) ]f2Z]GAdmfec,H}zsE]A>BͦcPvFw_xJn~wtPfB{V`]V-{.;)_`{WVzư-t"-!W3'WS^:^2up?4y0;A4]KHKhO2!4PN=U?F,<"Ғ[ӯJ4_C[+6 k4)2+Aݏj/&HCS,@ fsUA'U-Q1[%XUz8it4syQYXv*@ E[.Xg=\r#PNNAZԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]ݬ/./J+|t J+|t!hJ17ҵ[Њ))8OWmj6v򼶒 `W9qsecU?Rrzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_OYgWh8| {Ե?l_O+FȊ* B"ƊQFT`+ ~G ~E",haUF^C^ > ~@^+}?EyM _#϶x_Q^ :Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Eyڟut- ZO]~ڟ}?+b_~[.N.?(jxWֿG,]kEmO oX׭o.X׭o.?mO >ڟu[_]u[_]>ڟ}?+b>?b>.}?(jxW}mt}mt\xjxQ߆}m.}?(jxW}m?b>>ڟ}?+b>u[_rmO >ڟu[_rX.}?(jxW?k~Q Xo9EmO X?b޶ (^ Xo9G,]cڟ}?+?b޵ )?b޵ (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>>ڟ}?+b>u[_]>ڟ}?+b>?b>.}?(jxW}mtֽmt\xjxQz߆?b^.?(jxWֽm?tֽm?t\yjxQӧo.X:ߖ^ ZO]ut-p=GS¼.N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t>;Yߗ Pׇ_cEmh 4*T'?N+t$#AL Z)Q@65.#QՓCZÈyg?SBPuHmI5inȘS$Hpƴn7eip D?'p֭JczwVm7[ʴhڜ^6w [Kw=-j)J֌`YI+h;{TzZ4g P #wM9$i*g `TrzJѼO`[Owyc#5硸h&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumgO:ז\j7;Cu_Үir}Fƀ7[Dҙ6[z ?sX C;0.r9g?dXG)ɑsN=7HKWuY03юGko#Ik0;˫!ud#@Ҩ_M <: .?mi ZIo*WѬR4dD"-`V j1e@>lq=/Zli #;c%}o0tm~os| vϡة9J?JrtO{ԡ9AE2X՚/1I=,,ĸ:g^moLJEE@S ?uO+)Xg_://'WӴQ`>g@MOk2$bKi[bdp=E_N@1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NET9?EE@S v,_://'WӴQ`>b__?OT9?¾""r:XuO(__?Oh|G""r};E/EE@S ?uO+(1//'Q_NEjzIqoOH8] UQ-%ҕ|759O蓱LJJtQ[m%߉$$zi!'ʯq;Z1//'Wx) xv:ᔎ 55i??oЎXobb#V~[IV~[Gʈ RFO֐?MM!YfoX%Ͳy<㓐W"vF/NAS%ςmcrp}k1ܨ۠?wsi5 +3}?ʣ#R1?J= gZ&?MU!者'h0[B\o=قR|G8N)s.(~U"ʹ_4 [ui%n$X* f*iT?MU!Q2mQ&G0VL MWE 3MĎ)fl pjEbX_'i wu>]ϼ5g̨2'Sl#އG]ϼ4;9H9۠yZ=u?P( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ⴟ 7jk31V(X՟y!39+o՟y3i@QƣqBJcJ/'r|C:?$PK|Rtc:91Zr0Pw۩r4xșn.nnI`! 9 0Him >LyXlv?Ӫ~ٽX58c2IUMȚTyp]jV8bIR9 ,r9DI.;[jͣxѢ++FLSFr$L3YDYb@?\uhIoĩpX9o#Qƙ\&2gex?#on<ן[ RsrMMFqm/&=#-qnlb7)C}Gd]bԵSܦm|f&"< 689\Oɕc,˓Ʊ{ż{;vQĥѱ f3ԠsxP(ɝw,Yt4^wy o)Xռ)+kkw[Bxٌ0co^8揲~ٔ,cn9tT>IL79=K-T|G/vCjtB٪( ~j%_ [ *\kmZw6׿ekCnPdÓӽ"krjd`{qVf@8joZ7fYVh e?>7fWyf(r 5j<$ss> (?-- (?-m ֖Y c@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@qZWC5nwV[SgĚp<+V~ OtTqC דyG&#LoPqTN.iސɾg>߱MOwbםiw3X]kss|+lmLm9 L^"]AΈfwt3zS/#~bX?خVŷzLTFkB@$S}xumRMl>cM$hf'#)}`bYϬW +>e4C`4=մ%*@_e 9+_2z>r}QL.bX?أV&7R?YϬQ+?u?YϬQ+?u?YϬUh##EE *-]Tכ?c-;$2OjϬSlN-??׵;/\h^K"[\c9uS+?>g>߱\[+Lk{g[%H%g~:C5ֿ\GQVv-AVM_ ;v3 ~aX?خoI5ΖڂYSyDUCmbI U_wM@wFĴZ*)p3uEη6}}`bȣ"}}`bϬTdPaX?أ6>El( ~OFEA?>g>߱SQ@}}`bϬTdPaX?أ6>El( ~OA<`PaX?ب,R-a! ǥ`YxZYђ9Ȕ}-GV?'N眊nH,7}}`bV$fn#ݖ w I2fQ6g#e|\ P;oYϬQ+?5=fZRJ1kw #30|d>2Q֢KXa[IFPYĀl98sIjC~bX?ة7Q#~bX?ة7Q+gh-"B~g>߱Ipdko j[LP"HC)f GCFج(~p4n=jnBC"D7xVֵ;ۋ{-(ZwSMt¨ G<t_bX?ئAlISW78tt-ἼYZSq!c"u 7XU2g4%wotl}`bYϬWGX܈0&̥Upxq`֮]x Q8fb *_޿ٵ)fU$Pm,C-R2pk}STȬRKKb}X `u5 kA~g>߱Qgh-"B;FV<kj<kjiA]ZI$pE.<~֭l'dL 21\嶉zܗpOw: 8'l*<}htgoiqyq*'?~p=|wFdF@@}+7F;4n7hr:"lrʣcbxkWK[<6¶OSu.LWoV50I>E[}"J_ pn?Z;)㶟*"dc*w+_"I-.cc ~fOA޵p=|wFdF@@}+:m05f`"Ef8X%QMD#<4K˸-ψ2j.GE9,yۭ\]V;Vҩ!xoqߛvf: WwQ#؊ͷQo s͜vͫ*iVVpah ?m?&O*\LU&7Qo cg4agCіB=Hnu/m?&O*\LU&7RfzdͷPn#kc6'Ua4-H14 O kgNMIhC|FK8Ae*㓁;AJMکbfE1.{v9fs ?'wyۨY; ?'Ѳsknud{DF?I4Փs ?'7VN?I4l{D@ۨY; ?'Ѳsknud{DF?I4Փs ?'7VN?I4l{D@KK;α Vp,@Ohoi?ʳvA="OXOqz}hxE䜉 `0{dVA𵤐-AIKFܪ0@Ϸz%>g=.?"_*?ծ5u[de2"yB@sNAP{[t_:Kh|~䂤K?qT}z\DU @$F%%u?YK%q'T:αa=.2ĞZ%]]`U&YW2~J_ 2ژ//mfh$P*A_%6MJ.H1 #؁9ù/,M=Y î~$s AH-\bo컞Ns1`+[%%z3u2o*yN뷏9d?k76r:"Ky vdbRIY$Tkc;IK?qTn{V'rfO8# m<.z QK?qT}z\DUIq'QK?qT;"2\zKR;OOƱoZ%JrA=JvEs+1Aw|/OM7_UܮIv::+L7_T`7T{z}Ò]9?U''Z__tW1 ֗<.KT}b$=u?:?UX.OP^ռ3uYP0 :u _Ntw|/G)0rKy)<<ͣv4-AUolUNTM"9?U_*9%#8cXEHaUFSok_*4s!(؟ZԌݢq?#]q?#V#V(X՟pϧq](:xcZk|w㻫C]+A/N2`Տ?ud<_}[}s?*‹gԓ{=M~|g¯]|*O۩90 eITwv hd89[x9 G#*Bϖ ;4Kksv"ہ.b;Hf1`Pj>/ k T\kY 1'i%k7ԧ2.+&ƊD  Nl4c0dҪXڽR\ܣZ8A#S) H '$c֪_+R̚Nu+ihy.LQdm3)5S][Mk^ %Ii%vba!U gRn]7 3+[jZܮ3G1H ʜ jq{nitXe@DlNޚWן /JmehdO\֖^G.1]vb+֧cs}q.haVڽ9NO%oGyEPYu]Yu]-||*d~GlQO ;V$ʪ2WUAӴkߴZ2Zui3HR(0z)~PwteBVA-~Q]盧2a}Qr=3W.h(;H}V4-vC733Hn}F;x:M[S¸m\[ٟh3UzLZ z)|m NjKmsO{+yIX_`+o܏Lo?gZET3fUtPO?gZET3fUtPO?gZET3fUtPO?gZET3GqlfU=p*gZ>V fUngZ>V fUnsleTfUoTk y;0]0@,A ^M VXCc֮cWPXt(.8HmŰrv@TBj->ƞ\9FTvsZz?=_@֚K5Bmy$czW+fOӢL[EW?*}=_F𣥃̡CvM;=G߻o<zu/mƹ1N yt-LkbQK H}9;M/YCdv׉2ynd.wdqZ>GڿkksԮ-4ۻioOR .9SqZ:C\i$t\FHNpѨ%x_~}֒,QUGڿh__~}ր,QUGڿh__~}ր,QUGڿh__~}ր,QUGڿhGqG?Z_jޢ֏*ڿhWX֏*ڿhW>=fqeuvhKq,Ѳ+̻jsu7K?Z6,XRL;`vI\ͻOBYŬj[YC@iG;OߵL=\5fxԪH@ܠ dQ.k#U4~6kl 31V~csCYM[yvȾ]5L1F7',TRTJln5}P# _915FC$Em<ͺFPsdrp*__[[ܛioku,IVĥS;ra9Ϋ֏Z+CV`mVTW dZ_~}֔*$N<k!Z O{G$? V8H|HBIׄu&hԆ4 hBO78QԜ i%7OȁeI[ cH }P(HXc$dP1#XlØ<Ew<1kzOLY>wu,X28LḧLLdpHfڍluw=xϰ2xvay#^9w zu gYZ3**@Hw_O^9sHEGqަVbP>1@Npp=&SCVfOG`=+'evЖ3ҺV_o kGFUv=F?;_/LNXobb#V~O#>]wwҸIg븠\*C+5 *W- qBN3) 导Ei$ҭ&GlqNJ% ovEq` Npzg\EׅEw,Rˤ^P,Gypr2=σ|9Xx9wq#hđXWNx5tsکª-.kwGi>?/DZߝS47p;7lQ=888Y6$ni ȎBse3ZmƯ-L?e,L˳snhxQmwv_J~[Oڕt]#3$QXx̖Ƣ9YsbA t֞=fۙ4۳<3a /uz,1{oxv2i~|3a /uz}~:(Š((kBhvDݡ]&M 8Tr?h~K ȹ,Bc)!Ӯ^~.u%gF$^{$X`@ ŸzV~ gmDH̿jDA?6ڢjol6 O*hW^HNyo5 `t4罟rqН7k6vQ[m2IGd. F'R1ЌpixiF{{;OKg 0K~Uizk/iMl-K UPrFQPUЭm>=:m9;BG9Eu\:^_KZ}3O"XFzFPI(X#eQe4rsP)'۽ n d!zg/[7l"5hV̎ ;p}~ͼXtme7#s sM\֥ ΗU@RzKIl7QEOsLJ WGiP5Ux@P-XW.ܦ&dv{?ӌU]n!O9bi 6%sҸ[>[yTMK7qq]o-/{,k!Ϋ)vЖ0+z Xv_B5a!ר`v[S+V~O#>]w477Jꈱǖc9nxKO jwHUchIdRWvGM_g<8nEI?׵練ծ F59Aµ<9jxJPy3>>L=TѻQzr~2JեiP78Kv./L*[6'(H0zɸբˉCMDe+&oK::_'QdjܵQZ(°(X8U ']-bP6Ӭn<C„یc֝Hԏ2Υ9S+~̞Gٓիб[G-/Q|ӑמ)8#B-ot&V -c:.ufOV). {od"ȸ_XڢžnJy،cg`Z_fOVՇk8u-5l#-qawo8Q[xm>_쭚v?op9c ·}=Z~̞Gٓժj('Qdj}=Z!2zfOV~̞Gٓժj('TWiyo[?_ fOV5ٓը2zMECdj>̞SQ@=Z'TPKd,ܷ?ʥ2z-z*R؟7;Tw8֓v_'Qdj:?59.Mq$iuv4jAeL`cCS&<1S݋l- y(ygoK_-mufOVYǭhOKK+K47Ny*)|I{aj^^SI%buYAP%j?2zfOVw^#JiR57 @/ \@5>{bRnmS5˶,q-2zfOVWT 7z}jHw!ZkUHV"ݗ/q'һ ~̞Gٓժj(.<kq[z_르(?*>!+6ndk y3M,M5N<␃ppzZ5j,Ԡe[)O)ZbJ:@'iy8.sJ$8⣑4.쪊2K=ii8nq래r΍>^J f# 8 9=sN~Č(.B["ZsYU_xH7<qkSzjWRoXNL8gX]_J ePl;~ 6{,Q(y#5Y݈v@A8#xֹl :ݥV +nݑG 'pq/,& y㓓=OzTӸ՜Eې}%1}+`H+Ȯ^u=wX˿v$c$E;QE ? ? -ZOt7ܯIpƸgKBe7sQHڊmavQGii롍B.0 P:B^bDN[g@cԊڕ_W|ؓ=3JKC$+)|? ֝8ӏ$v1VUf-~ bsdf!of/_'ؽX&㓞q[||YKR]%VR7wnlJcwxK>}^^C['nѴ 2{v]G'AG'AI_!obhe.[?`WY;%vcXX_6[5}JOh| 0?iQU7y\{.T? O~>O~.T? /QP*'AG'A@h^||]y{y{b=fqHFTQY3Y~o=IP:Mèl$paܥ&yc=vپ\AaQ1^]O'AG'AEht OGMrf9`IJ?m[iFvq[ h%s V]9U$epE;ϓߠm,nahz9 QeGchҩa8gp{AkbJN~v߱*y{3~s1ӽ=$/$9,S'AUqX˽5N1}#ܭhVܪ_q:N+^||.vQPs_X>64? VyA\V |/ԆpTQE1Q@Q@Q@Q@Q@Q@t 7]'37{a!c\u#HgomQEE1?J'O⻻g\$3PsT5gX_͘ZYzͅtCvcyFP:V&1Fi9SŸa!s3#6b@+GC {!KqbT׎s׵1OhY2ymل1ujI[ gVw.dg[fAs޺?FO omٷv}+ PqflM)OlZVmW⛻.#YMy${r0C#kfX|t3Y3ƎQT[nu[FRmm0D$|Sf.tV_](DNsߊ;EZ'^Oe& ^jI$[ ˓铐Hj}SZ77b6QIDY{* A1W%Іo{:A}-D1 3z4 ˧xbMݵ$:wlr9N–1_̡}{k>m?Sy'TL(p~7z+]N9N]>q)r +֤O[Gsvݗi cgt8J{g.)u_7_e}Zo3$ڼѬVD!.0cJWծVXW7%*ͻdVlxcuƯ"(v*v#5ţGssws%Q,Һ~6=+~sԳ[Hd'- e,OXwV1Gأ:L>տ2JUQF7sJ.ӦNMݦ]Htp1CiK="muu*̒ 9 dvZmtm@X#(ITLJOajKk[!]QEQEQEQEQEQETsǼRTsǼ@QEQEQEQEGqCCsqf]S-Da9T/S#֓}?%UԒ,i7!DIʣuߨEMaer6v -]w5-B,JqK0HMIUfmi wQ5$q\;~`dxq5歬DHXjՃ>{ú~#(bRK~zW q-,qmOCPZ^[uk*(QIYj'Onw2gP[a@0E#2`~P2Gpy腔0R13ɥ:7^{,添419A(=*ψEaw֧OO/QY%vu/pLOM$7O/G_ʝE!QQ@ QQ@ QQ@ QQ@ QQ@ TW٥=GqiiSiSiSiS.cO/n/_ʙsʡԬ,^[}}Gz}}7epE-?Zq*tVᯆc_=$Vģ7aI'?wo9 ދ"O mUU!sc')t`].-/գ$+Zq*,.5ߧeixو0i?G=Tӯuhޝg$g$eX;Z-]wsXZG1v?qV~Ӭ"B<[@@R;|j[!oH77\>R0`*S}i[zWO/\?ش隤z|vBIP!$WuIj7iS O_z<kAjC8*(((((((Ofoo k?BZk|?5Wc!i Պ(V(";g\$3Ww{+F}?j5\qvO& !⤨yRgeHg0 ,uK:5C%ws!VBy= jn8McxGvښX(2kA;uK\e'aE-4,rN7!A/4Ym--1O$o=@u`?Z'5SLmm:R Pq𮃐/titKa& Hs8`i>irͳx[Udۍ0 F$%\l"0cdz{dTyQEQEQEV]A-hV[W;I"/ Ҁ3olHs#рOV_W@YE0̎4u£kdұJFzjH]öeyb 4qɠi_%O4y$vV1 #;SVbNsޤ6lTXXlMOeR&+KQj^;l#82IKm$B#8V_/mÄT}yӴVooBb/e eveH\[Ofb |>QI rI+\B %#,0H@ E[< !|tWBA+)!I5@JFX`::TEgQ@ (?*Z?ʰ|m h3)((((((+OfvЖ<!ݿ%_3]q?fXobb#V~O#>]wwҸIg븠~Fժdp%Hґ b#RMe#Dw48W7IxĮ\6w96W45Yȳ!YvF`*NJɞL^q]3;Vc}jwV6؉H. g,CxaiE%&p3,騵V˨%8B,58;kSYY>}JL/p'^K]O#C˪N$jrг2H9!ĺ\iOrLVUpCrN3Ww.em_LAgyeI$Fe1U}n+hhQEQEQEȯuseuoƝGr@S q-̸6 .1ךۥͬզqs }ؙo+U,V{xm+W2mc]ޗk"7**&8"}YM2I@:q(9S~TyoS~TyoS~TyoS~TyoS~TyoS~TyoS~Tyo/T[q*7<#}ڀ4yoPhyoPhyoPhyoP7/W?/>ӷ_)uݷtWeOhP<4N0ț=hͯ|ɡX[[q02nbw- TWS[`;U 9?:?<ME-QZسȶZFCq-۽ tu3t/i~HttO0{Hg?gݭRiKnJcePXߕn c'K nB&>28K+layVA2(ko`חu7]6x[E?"?wammI,Oq ɕ[09۵XԤvKZ(yۭ\kDyե(=p{g![K݅ &(=7&W,Ilk<I e=RyotNQ?ʰ|m hO_ ਢb ( ( ( ( ( ( <!ݿ%nOfoo h>Ca\}3V(X՟pϧq](DGqpH#ET1g6OVw-wڴikޛՎs zֿם3y\뼥RƹmgCOx/Z4kXyN#r0jwu5^^-w~fNvF1ր7<Rƹmuskoa6g>vgkq-ք[-f ѹpzJ[v:)}_?G}G[]ڬV ͽHd9hF\}:Է1}E4uc}cdߕB{:\:|Rƹ7X.|Q1i4$3MV7ʁ܊Ov%6|.Ēlol,+~RƨMYu] i,/&eff- jiYIG67Zѥ=s%N}MpnH`".H+ջVY$OXq W#{c1ϧ@;F2Q=_k'|McQ÷5NOr\u ^fiq1}k2/=0'%M'K3gc9[sw4QE!Q@Q@Q@Q@Q@Q@Q@GqIQǴ@QEQEQEQEEsʢu+=*ͮ¤ I'9$ =fqs0an-PYn Rϰ$sڀ/H}P]h!vrG5nT-2Ą3𑁓Àq\J~wu@ַhB4SK)ܽH+7ڗE]^^Y&sj:񞒚ej.EG(8\`3VOiVHyaŔ˛ xY Ac.%IFl=+޳^h,~hچMY0lV#hoF]b3JM»"BYSYӗWJ7qD2傎3hj%o-89Xv_A7ybiqӶ?W4%Fk\]3<.?9]ZxSZ[IB@ NXwt{(˴(?*Z?ʰ|m h3)((((((+OfvЖ<!ݿ%_3]q?tv[S+V~O#>]w5$N.属}*zdsGoqq$ I9, O&9'v5 j53^9K1%Hzmh4#6`3SAuosȞ)v6?* dt*󃃵\kڤVSl- ݑUσPZoMFo_ ~@p6%vw_z_#>M5 A羾hݮGb39ɩ.?zE{ qks/qݜ:EErFQ&mF;dاbl ;*{ Yn+gc?skG4SnG[k:BA~ ]ujQ q֢`YFw }φ<@>׷^WG=~o^տE{;o4YD%(AV6cW.-5u'${Aaw?ۛ淼+zݳ<wⶖ ? ?3:[{cDgT>Yb?Ÿ#c̱#]qU\ߺyT$QVS4X* Vn%6,"nO5kϏߡ[9tt!Ӓxt')EEqwVV 6|\Zk؉'nj{4y{5J/ B)#:_/$;u=.v~| | svݴVZImN2IGTӅMIǟ.8 >?~>?~+Rh%Ibqt`؊.{4y{5J*(CGCT | | R.{4y{5J*(CQ\O٥>^=p*<E]hjwϏߡϏߡTP>?~>?~Q@.g|ݏKu{KU} q(f`{Ā PǟCTnl.K-BYd2Y}̰q9k x mvLW(e,. c }Dc-͝ŊŒs;@?+0ڍ#kϏߡϏߡ6/}>[stxf\xNWy[i?~>?~EŅ),Dw/Llؑأ | | RiP5UoC_ oZǔ`@-HgESQEQEQEQEQEQEWI ^-sux'C3׻K@q_uWe!HgmmQEE1?J'O⻻g\$3PsUfmjC5ij8G avaǥ!DhKRO@?ޫ:~ $n #Og+ f ?@1jnt]f+N9ABW$:>SU{_TپYkn:~e@S}V?4TfU 7ٟh3CQZ3GqlfP*o?gZ}V!3fUhGٟh{KU-FM+igELp^zUp+b/+>@dQi#m:FcVP Wއ8C\Ck6Q$jR>Z`*Mj]k6 HK7*ޕ|e5 nw/`w(,ig\ )[fYjaX1WQ ̑o;.1$eAx=K]cOƍ=$knuKE6%(ѻqF[ t7p$OGmSӭ#Oƍ=$jndzIѽ礟C64oo'?PuM礟-9$u'?µ?eZ=2G%ˉ8#=^itfҖ #79\>5qݚ.xSrwllU჆<{Gđk6zlVpLM l,+RpN=9/t=OL/5+&k&BOKxRn$/.VXw`J'TjmZwzwZGe=ȶ\9cI@>Ǯ}Rk-YZ%ۀy`R?ʹ]V_u4Pc)4>\IA|<zL]>Aey-5{z [h)tYWw[ PWy~>Զ~#k.M6\\5~#;Exz>kkgv.r ojС4.=H muR3lL|>BGYn{跰ˡILYo&"!y f PWe q8TՔY;bw FӎqsM7R)K/Mͥ. ;/`dx+-_CL^ EٚI"O."I~Qx@S[?.nn5 %ڧ r:)$=*վxDࡌW$-\[C>&v>Bx R֯緊k-+YRʂ;Kk~K#u7WHlv5$/z :ҮKCQxwZ}vk,⸒fN9sZ7v/n-Za2*!ԃ\V?kB%[jnd$$7$nleosADG`FpT ؄Þײxr]4OIS<% qsOŚ=qne}m,oJ[u)G \Í g'#wJ: ~'Niopx%H.g{myu[(C*0zUeoc#MԠYxEI>̻ܒh|*wkO(66Co< (\g 22)SCcoľl}&%mz*R ab/'f (<}転A80\'2OK>Qqya`tv:䵴̙XN:OKj;zƟaYmvnC£o4Q$oH6!(!GVÞ׵w:[o?^UjohźMg'8=)/??6Ay?SF1\] Xʳo0>] r )PЮ Lv%'ʉ:H.@w=Š( O_z<kAjC8*(((((((Ofoo k?BZk|?¸/_:C;kob-Պ)YW ?w?J'O;̾Q+ pC:ӥ63A:W4 [i7x3:_n9=(VwQW:e(;wf [ğo텘*N##D"D6Hn#R A޻ +~9zc֑IHu!Cm Xt $ley2]3_6zƏLǷhf1} QTHT+wp71AT\kiy:?L?3ok&V.VE"Ti6^+<-ǘ OLqU?Ui3C6zƏLϋIGݧTy#ӽB6upd h 3ڇ_AL~/ӹ =cG&m@cchZ.$=pA ׊I\̈b#{ݿ/b?! ͟Ld/Yx7Yl#o"ˤC}8y&@&8 rG5KQ[l`z 1H$qבDe0x94w~T%pC hv $GBgҤő@\i1M4rKX{kim4[ڬWO=DMڠ6Q8-!懈3NĖ|F+-2rR3뀕g6zư.qqHDIQTTKN_qWQ_g&m@5u/o_f_ =c\7Q /?3oj9d=yR?\ltX!< ov7? ?>o/ZMߜPDOOer 9Gd&7&Fpqޟs~_O0ܼ3Q 1#h4ɬ..;c9Hi@ߩSt15(HRHD^!"r?>o/| _+KYt{]HaAX 1>p6%04 +] $g:Rk"eoO7? #9uc#7 3nj/bI 1#&FjͫZD@$OOX~_K˰~/ηbGaQb{mo/ wAe1F7by`H$U+k$I#F䞀qGq֖ &63~?  <ͺFY\'g'¤W5=xYʞ ?2?*p:,kp::+ \*=OO/-~ooNܝ3Q 1#~k|Ƒ'Fs5uo{"Jo7gi 1#bGa\^7Tv~//T(?*Z?ʰ|m htS)((((((+OfvЖ<!ݿ%/:+|?3V(X՟pϧq](662QLAEPEPEPEPEPYu]Yu]%W}v!e nx ?{ j73]M-$pH=?Bw}^ELg7$17_HۮT,nUGֶmC*pan#ߵo{? ӿMLpxBT5ךsqZ-[sHORwg Fwv>YL9SbGui_&Bw}M+{! 9ۨƻHaF#zG:S` kcʘ2=y뎧o{? ӿM?64? W|QEQEQEQEQEQEQEx'C3׻K\t {\uY~QmQLDwҸIg븮YW ?w?RR?Rv( (((((z@ZЬz@ZosVtyͿخZ/5?0G^k_j6jV 8{h7|KZdwjfݹ1\coZYH(uqSBMi5 [S/RxxEĆ8OONj:ՊH~9@LC qG$vI|\j!7t˷]ӥhj ѯnmK 8dO+ u&QT:(j7>cX$Z7W86g@668'sW;]B7ZD{cgUt WеK]f=Vվ(fYqo0`ԓԽx@n!vY =:]mS~ɯՄ`; 3 53ڃv[]j-usC4 YKa0#i$Z5\Mx/~" @ 0F1Ƨ HUFa,k .С7pO[\=n&K09O, UDʼyȈ*>84;LׯS@{t]5fgbu$ ]]i\,K t@ pךtE!1gPct~uNËyNmѮe1.Hb9[M?v ok-gOuPNぃ XH/lA'd=A\bԮ4l ghU5/}k~_)EV|Q? 4UoMoߗ EV|Q? 4UoMoߗ EV|Q? 5/W_ Sk~_*l$E nRTt?JC3ЍO5W?_teT{S>G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{(p?У0h@~?~bi{G} >G{*9w[IR0/=i{G} _(/QE} O=i{G} _(/QE} O=i{G} _(/QE} O=i{G} _(/QE} O=i{G} d5\IB =*O(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PiG?QB(/R}(L?PZǔ`@-[i{G} >tW}(L?P#\L?Q?Р#s0hG`B<ϴ=i{G} :+>}(\L?Q?Р#s0hG`B]wwҸIg븠(0h 9 $s@QEQUcHǐ~4y[ʒ<bE h((([0Y܀Y\(>h?ռ+65۩ati%eU<8> .#0/n,,f՚WۋsZkK{j^|z5'%) j+|)0z^w5Z#ͩڥ26B5ͷ'jyn|@ !wusߵ _O3\f=bY,MG*>. vz+ًYW$鎹p:|њ|g(}D^#7$A\I)xV$MV;&[)v`SbuL?;<њtj:պ3Bd"! |dlҫ 9/qH,.!gt2| S1<ݻnE"x3n_&,adZ^+&s`.xI H0cJׯ槙]\VuiuKY$yorăV]suKCtm?0qzǯ|;,њ"҄Zc*rBqb[=rqhKYO)5.Fbmt0hr2xR]BHV9|ӄ<=G=)^!:ޘvOD9 INFk ģSHhv\H|;r3ӡP=uT)qpXܶof73\Qn&U3q<'Sʽ]UvjN:YoZkYK0nF]w4QUo`$}$2"m.N.K,qD (weί麄cpA"-QY6Rqc{k$-<`,zy$ MJ;m$1#dykX^&%+Xr9Ns2qIch\p鷢7,# c#(ZijEP$7Ios$`E3.r=2qOeƟjI$ ۄ<{{o.WJ9,o"!HfK{#)s9q3(n=CZ[f+. ynR[u[j̿z8Va.QU&t{+؞eW9NjVUtæވVGܰG$݌tu ROi$lH=Gn=RǶ31YKe}j0=AV]rH8 e, Ap\3,R JTps=@(n/$<_ö@|9%} o.WL˷0N8Pף{Fbʿ"`}pA%cj}I$&fF;q@V=Q[+W1" A8 Tt-V( %8rG~Þ:P6%[܌RiZŞkum,Z(b + HO:AkՐ 4I{V񨕂K@%ϩ[,=K*F# 9:,o~ɜyr[I- Wa*νgtWN7b8<ߟsESմˆ-g~qL>=FkS²ur(xk b $9ޯx#+8rY ˴ž[nynoisڅ %ef5[H {C$FU/x@UkmFxudK2#ڊmn#k1=|C"x7r|k#`0Zi umt%{,avdq]ƦڏM&v(' t5-i~\1rN9S4pZK>j( $fR89ObRIa;N =3P7׿O0oz-´"(d1kQ@'$$OSB ǵmi$kԹYN@s۱}U x{'ODm;K >[TP޷9=.-gzwve*y70s{iwV[MIn!WX[І 3NA>q9+d7(w1R(v}Ek\E`~p_5@w8]X<'Ζ -77n:H%4INF8Ϯ;VﰬrMԵ-5㴅XNX70sAm^ms̚-M-͓EllIʾN1gMvRc95Y<,<ۙ=:|QGw@w ]j:#6ٖY;ϧM_H,m4? \o\G4q\$KM6 i[[$Lɳ/RFE36Kav YP&e;-2:}ޚ^n^kfePHC.rq][B?9+e/?;Wş[j_U۳_? v)G$kY.Vإ!vrvI] 8pzo̐{Ē|뷥P _vC}:KlљwW:z%ӰNͩjkedm-jRRY3ж1) Se[I$dh㐣ٮҊ]-jG%jv^[ܽ [֞D;pP8$s֏k[i,3y`9$Q[2XE P@ 489|9,56H p cUJ 2Ik=֡cÑɜ # wSt]jWڴא[YGdtفY2$=8*Oh-ei}寖O&4ه t=^E Oꂊ(EPEPEPEPEPEPEPEPEPEP\:됳wo@EG{+F}?՟pϧq@QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\:됳wo@EG{+F}?՟pϧq@U[h%zM!bYz\UC"{hC9; I?(6vQx\()Wj󵪬^"fHd+;Rx&@w.᱗8sBCEdM}_j"o7' w~65z[xo LO8f6.3AP+&6.w(H$v, 0O*jV,pC@(((((((((((((((((h$\{As3szqx⩖6qLoVP"٧ߣQiUc5j=ơH_ۜp}igh4? +6>1vl3gZiWWc4䲧\PF#H f{G~G٧ߣV#uNiE9m BRK9h_8e`x4?7P7C"Y_e1#L' I^S5E9]c! i̱x4h4?˻׮%Ӵ; 󈣏w*3K/ t,?}]_\:<V(X՟pϧq](.ԴqKN?ʧ?`'U eU4h$y!R@.m$3r'ҙyӢ-XM@,,zz訦M j6oEkyO5[vsִukѪi6bIp9;ճ=GLw}5乒o,+G9ۜZ;csiow-k wOpaV 僀G^hx;,5%1QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPPzUdr$fUt ʤ$2@#M7ύ@7_]1.|1eoW:^moy!UB䎕KAf͛h2E Mu|u>7_]@?OimԞRLzN:_ZKv חOraV # G欱*Jd$yDYsύN.y j'~qtyύH /i]ۣ?/ j5."f"[*Yv'ޥ2 TeCq/{B?.2Z=KIol~mdI"u]@ ;T5msS20MfQ-1v|ϙC #ύG'~qtZw2t:VX4Y܌g?J_B}-f'ExYRǵt|u>7_]6u1[tK5}Bi]@#2[>HO++ 83[:]ņK pq6#9_?.>ONbOI2¨yύA*DVS+#&p>N??:ҧƮDh_y+C7J27H!Mr)ArRݴ2_2cjR|_]p{zYƍ/lsҴDB%X1g~EmjcN{mK]MHT Q'  Mxd+,mؕU#9,}ncj_R|_];Pf_^lѐ8EV<ʵ>o/.mKquU)+ЂV[l]{E%dcN9$hqrǧo8ԻG66)勻6+wo]}r9խ؁[ S?o) +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57R?5YOO7oTmg/?LRt\|O?ԟ]|I>g{hx._϶~O?̟]3Fkr}'G._϶~d3^ ğߙ??r}'Eњ?\$m3 ğߙ?.fׁiO.\#m3p=4f/L2tiO.5|G>g/L2t\|??̟]|G>g{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2.fׁiO9G._϶~d\|?̟r\#m7(3^ ߙ?|G>gQp=4f/L2?r}'{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?.fׁiO.\#m3p=4f/L2tiO.5|G>g/L2t\|??̟]|I>g{hx._϶~dO?̟]3Fkr}'G._϶~d3^ ğߙ??r}'Eњ?\$m3 ğߩ?.fׁ'iO.\$m3Ip=4f/?LRt'iO.5|I>g7?L2t\|(V;{""v3t5ۆiQER_*5nsfPʏ##H䳹,'74T\թ,g; ?LG"‹,31n5s5Ϳ",r1t6N0L;cU:԰(m Z6P< z|MS:!: B\: FY^K'  8UU^+o7>B}IJ4yź^gx֘K״ʼn18`+3isxZW7K_Ʊx4COӓMpY}(iW L}b|F6}>[h-`1y8ϵYԢY / n݅>vK)M͜xOlRL-eɂxϯ" y%/m*\"-9;YpC+w@Ӣ-ݒ+;Jsc5K+4RDN>ϥ%ōů(>pm9>Չ6L)(U\ʬVU+ەoیdPyҮEKB$,v늂-ݟ2n׊؆-{rlwݞ__!m?ioYÓ54H2"S=Y,^tY_,ƨIg>zϾvVGBSEv_ ˁ}EeRcGa*GJ#HdfUP>ĖQ.#Jy747 5G:DZX=ɘ#9MpͰsRZ4(˳m[ Fm"9,[]&~^>Ѵ :=z QO2?:KGO$GV1&Ռֵnc]A>ҍ[,oozu,Ј@˧,:P*[ӈJn{Kc}՜&vMN:W<'t  n=M:[qu}ms[568B$q@6<#'f}i.l[hVIxPAZ?nαݥxg} Jf}FdHve1 :\6sG;Fq0w TkdӆڄVԗ0wWqDҬ{%0~jLxaVf _Qƀ3la 9%;mg'O!BkM QB)";rqUf[vHix'@h'6La=~y3 _JYڣA|,3Z`ȷ1kb tx0F08RM1Jyf);*چ]*3?teJćvXpqa[y>2d`:y84[^Koڹ'´Ha{nA>h1 aU#7dndS򩭭$[fMb~PrEh-Y̳琬=‰6^3Krۻ|Pap,h)-`N[̃IDZKrp{ Ypy;4hfBH#d9uphkC- OԷߖݎZ-fdio;$-6?ސ lgT,)`!o>8^6`$RN+RM3tǔ,sTfZ|9lO}@qm59PH 6;F3'zIؔ &Ўi33UCw Kc1zH o:3A*@_JjE,w Ԫ%Jf}%vC02cYsE$KcXfh̋ $Ƶ.a* 11EZ[ [yYil}Iv^NJXUe#?L֭մ1iGLFnLE%,u;VKtsژ,;!YXKw8B$|MfX΋v/7p#j7QhBI#2cssŴDXgA<*F֛*G P3c$YC:38$1LdA1R=1֮ 9v#n* 'Qxr~ z1$=~dO &9#Y[8>pFv\;[D]QYF }2ĢD}2wrzzeq{4~I^O#fдn[o%OZՅ 2H89/ݾ&>Srx.(Ϧ]j);'kݪ'Ö\^%_$׌`kCǯj :;$eؑ2^GJ@Guk[ JO|TveuGmhg=EIssgykl۴M/wP=m7  4ch,,;x2>y*lݳ4yqC7b +&Zb,Ct\$ 8e=["m gE۞:nV~ke@e.$hRA$M5Lqt#Kln,."lF2 B<ԋsJ6-] UnQ(q2B`v"+x.ċ'^Sb2e$_{O;90|83]++_A@&幻K4ebGK/<nnz7[wXPFq`zc?Jo#( $]*k,#09=Mcdby%CV֐kL;pZ Y؟$ (ڥ& G|graY;qCmu25̞R>ݻvZIO:XVObj:\nm9 u[7fH8ݸ^P{Y Y){aܡO$.{^4+0ccisg4ˋKMhǻH Uu5"u pzY[`C#mq2 diXJ5nc H=Ni3m@GOL8i-]-BCvH2a[]G  ?\gKq-E$&*r@^GE*[ @?ME-ݝw6NЫ\VO,aGZkj,HP4)$;r2s֦-Hw Aӏ~dYi.`1{k6Kk Nlabk(f$2r=ԗR.f󌄘cޙ$Z4D{)A?@mFUŴ*[[A:rBg)gs [nCr9.[yY!88hOyVJ٧BZR\;TSs.xF@=(H3kw1UIV7L.ܝDZR[89TIl-Zsoe9g](`gQP2Al.?in }Sg&Tz9݇| NuSB.E+/XfVeJ>WSGd)j]U_\K4f&zϖgsc㑌CTh 2JA*F3Ngv  z Xg RJ'lhX 4Y|=6y=Z4f(R* RK#}ԍ 134fK";ʄI2@֙@hYMom93֫P倱Rt5Q(4f(%YbG#]0Q@jH'YJ7*Hg'YJtPFh њ( y^gqUp8Z4Q@hP䷙eȽQ@ I$f(H >cztPW[Wd*n2`-z~UJy幔3sNUh њ( mfr1O 'x^G?!U4f(3R$$8fE4Q@jqyph3PI'$4wSDQ(Hbޖ96+L$Y9 v*ɥq7BҖ :gp/zf$+HgdT[[#; `~uOr}3@ EPȨW<M()#vFNiPEPQP_>E#*3UO;Sh (Y+`r8"ff,Y$J(((c~^ٜ6(Ve`X3brI9&Dۢlc(~(fos9ǏΡ(*TGq2(!~YI'$QEQEQE9wf07z mPEPJ  GqIE9O9E<)]G+EDYG8f(!BVt X_4"QLojV^gM?IIV'LaV?T'ߑX:$i7eurA]3ltNM7[vjk{] حN"<<$aXiMlE>%ޚz4'ߑc cat%K]dD2m vGGYKgV9B6zqIa-t_awRw İȲ)5ooڇQ@mC_*5smMZmTQI|,=g1r|ey 8'w`>)a4Q>Z4L qNOVh~%2n@:q6Oo"k,l,dmvASɩ-/M`Z5A tM]zdU5^Kgt3E)uL62*#`:fa/6E3"|K?j@mC_*HtOʲqHuE#@&;_CE7?Ss\N y*/5sPz_X-~쮚zS3% +4?D$z^"u[yaOS 'Zt)A(cGAGj>&0\ [~}[ xowhۭ5  kB;+SN|JJ%BxgʗCĭ,V$rO"ʢ +?˜V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇP|#N'kOݯ:Wo=!d}ȥXd}Oݪ? m_k=yH-_>)z&koH<ל¶eTt"ͭωͶ ]T>ݷ]ߥh lb[n<Db%HSm#m#Xc|W=C}#9[UuQr/]W+o_G+o_BCl]h0 NџmVͬ*& O-̇$}_@YU_@YU \KCWC{NOPd7Z̊ۏ)F%vEgU)hYHv>GV/,?*V/,?* _شUush2 W=]W+o_G+o_B@Gcqomy+:$wP(圖\iGj!8a $4lnsڱ[x?[x}sFI''[MpwW'pJYտ:j&<g18?V/,?*xƗˡ Hl203ukO=/8׊+m#m#⩁]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@¶eT¶eT]W+o_G+o_@:G?Wzo{Ҿw/neY$c*|$#MuSB.E+/XfVeJ6~ѦV-#Qrjާ7L{ƽl@u_;8S>٬6oxV o}({}Y\);_O}[ya~RzT)nn.nu+]??3;݂3Ÿkv5rfmV$,O }W-QR$>^OP-jFdSC6s3k4.J .%u=w#HԼmLV2HmGY_)$I<+":z,\`U*qe_x!o5,m6niLe|L pt,zVCޟ çi :'b 7 *Ɵ|f >x^y7u>f?5 ɚkp#ߌڨn-}Qyٙ8H|GYwe-V;Yvu᝸?JLߛPYb!t&y7HgI @-y隂k|DKCrrGU7USyYhIpzA k-Łw2e#,v.^+ kqhLojX0H/u8i!RHR،<uK.mmuq RHY 3 w pܢksiZ+,vc\8z*mSJK/b%u;3vG@';]ÿ׺9Kb#p Y|“q#wpLq>s'5+;rv`P"Eҵn]6եL1Hq1gtTWԭbVfEi'U'<|3$ LI+tϴug1zdGdbl隯eCK=rv$M " 2pWZ]tkZEem=PJq*cXdu qtzA.~s^~hkZ]AwZBZ?27IX}+F/[#Zܹڂ ǯ]ΉuWk5nhDs5iutkgvISEv@J°Z?m:4Wϻnp#KRM,-de'n i<֒n\۫khF${%A8y26y31Dm;1Yri70IgY~ٜgcAimi4qv(@Q$27$ `tJO3]Fo!k(.\eqs%7OL$Y1 4 ȵB.~۶;thAu =,N2FkCwkkrZ%)_(3דtwOq=FĖhA$ q~Gkv6ofUft*#?.y#ޛ-0C*m0.Q[!z;xuROymmRJӲPʗ,j8삧wIn6tXºL&]с԰$ʹ6Gee_ '^.n{yq!C L|Mss$a>Y`̇f֗ūOzG$6*,JdʆGUZtPWXU{yM6KMNy$j7c΄ƫ,vW{k=H'ŕU~݇T{/3T2:䃁QkN[5mNZma>w,Cn=`o,d96-&}V;|Ln->S򅴖7y3H$g`R C}bxY-4- ;\nٷrzfjlNИ`[rq}wQH}WzͻA]$b0)U#-ǽTtGA{=lm\Hc8#j{q]z^< Uhc۳ۧoZK]i= !Bnz Söݣ}NjAMz։pPΟ4NY~ FFCڳt]FKnmM.;+@HlZzhWJ a'`IG0:u]?/#-mvֆ|G4^f|Ql$~sQtZPMyK\!E[`=oj 4>cAS;F6K[#2$2lB0s_b4=B)"X]:\09ni|condȎ!oaX9&눬Go1 mU#q;O@kWO{ty/cH52tV#95=^Mk]>Ucnbbs$dqև˯"jKmn3*Ot#!ԐUNӼ:fq}|pcG^ ZVq3\sT2OnjcKåtV 4Dyy{sin/&im Lpp}=jX/Yl0ֳZx&Η-dxjX]jmm4 GLjZ_Rg{{okZ[/8[q&\afbR9U /Gn:XVv8RqNrGcU4MCH3_ZXihѥ3-Ĝm/林įevt:itKk-"#^W[Aft1[;eʕWf;elKkmy & 2K78.pG>S=?_x-F爴>@,eܱ;8 YAw5bSCk#1m)FU=+O^=dRXz_I;E4=%SzإXpa8vZi$@MCǽ6bW0 0!8&5s'ODm;Kyqjz忡6!t'?BA]r:ω4Cy%\KS>حqo=  < &/?RK<|P@8*Gr jZ|bc] ;Cgv8hg}5?d{ S#in=Y9gѭ^9b6sՇxj[iQK[skn/;O͖TR{^mԚw1^d? kή5wAs*g#liHAZ\]Ϥ_,r <䎔ofGx=cTkةhնBw12p=:[ֵ= 4@]c3` r}}ꗈ<3wu7&k"fm² zkJ^@ZY4WW wc 1~rx:*O`ȭjK|kj݌ oQP((!b gVFi-Y2g8bwn+\\`,mZ dFm<ҵ4+}oY=\Dp~Z^5C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (10T"McSg%=!`H͜H`;jށ{{\# ih%pȘ$9`s3.B4 p9~$s?ܲ4AX'`yX&U=qץAtke읱Ud_p{f4 B]DϦ5N|sC/gS-l!-*0ll.-R{o0?>ľ%Ү<S :s|%۶e/yW>e'1\3ch/?訥Yi,ci $A0H+E_٤D;2}<_+o*G&]..? _(/?&wGm<'<@y>Ee/gb?x?/]^ϲGy>Eq81\Тue/yW ;Pآ@{8G_^ϲGy>Eqwgr,m ۓ"ve/yW>'* [B& hH̼e2}3ii k|_(/?&%ҩc]3ƢON sӚ_(/?RoDO$Go&&2#[^ϲGy>EpG:l_IIdpy̼e2}pJ13%@M@ۍue/yW|}p B48R~O|_(/?=⤑+)6N&1Ah_(/?5b?O?Bl€=̼e2}x숆 s>a _(/?+y]sʡ.}ue/yW? E?/֔x0B8 2}<_+ KEQ;C׏ր7<_(/?q >isϙy>Ee/u>T_yQgƀ6_(/?}Ot,zҏNG_ 2}<_+LC/?̼eSƛ U̼e2}*ޢKx@7y>Ee/˟"3?0(̼e-6[W\?#Zn5vEvzT_RM.KdYsF ?A[ՙzvns;Z7L\bF}8W:叴Vٻ9OZC,Qz[Yi\?#ݫc8u€5vK{({=-S^d?TJu;€6vK{({=-F/T U&W(omǿ Ƴ}`~? Xn; 98d{=-y˵?«^q ?@Noo祿=ɟj8]OP|K | 6K{({=-DxT#')m\t1; 6K{+>$zΟ 2EF({=-mǿ¹MLMPg@voo祿=j@s"sV({=-mǿ¸=`GtuWgٺ6K{({=-?Z;_zqvc@z[FoyCDFضG?{oo祿=S'LupE@z[FoyS$ۃ\U%kOLGhնK{({=-0EwDb%Πo> J Czoo祿=O*H"#5$8ݷ 6K{+-O@bRDyzwDdvea~Z\ _>!| W^ƺGx7z6K{({=-?ƺ̝Z :{V~{=-mǿ¼vh 8#aex{noo祿=#ȎUf/$r2C>*=mǿ ߣ5|@-?@z[Foy<_5o{DƴuXugbNsP]t;L]g%19m7=Y2r)d;H$ ֶ]v(HV^J?پNEݿy}I^i"ּJI ,MJJ݋>sV_%H"nmb*Rff;U c=@rJxO` ʞȐ!'&3gKrɽ ]*@( )2)d ^v(2s{֎6VV&QޭNdhUҤ`QA*ta?R;@ 50Uێ!SZ@֗`Ċ1 P֡aqҧ-wzvo~w.Gҡ`H+* QgQK93l;E#H(}h7@9awm$giÂ0h)+& $\ɠ0>>K*еet5Vx\LQzBɹT=klR.8Sk@Xk RV3P <,ou#ctnE>͙ jrɤ*FXS#= A"HH?]$GҴcYNqSVZMq@S3[ɺBqO@'W484"WRjϚ(ZNk\?utr_CLKtwRE! Ea\j2YC*]d@5LŘiȻD WbE$0o5?~b_vii MtҬyE&oдڸsnsBVdMUE:8ʿLJnZElJZElJ "Yv(3 ?پYz{7Ҁ)ȷ{;װZȷ{CbZtg' ocZ[HP}M1 qTe|MJpD 1T3ʨ R2=rxwjn)犱i*ɒX؁ 3ĴSqkq׊:qVdlWAҶګLU@:PÞjI$Ue'ԞhHB D)&l>CnI tFhk`~yRmU r}hxvK#Jvָ1|DsPLXkkd֕NӀ?ZAi.@УGFqY+vh""9+*#4194|1;V[yNћnEiJ9}ZBn6VT51ں-.9bJ€:RFUHqWs3@<ԇ!@3M'#P83FqE1 $f+A>5Ju4>Rva c0+;zPn}:ߒ1ND $fHzwgIT!:9RHgި@fK֭^x&YlGXwүF01zUheN8=1@PĔ(OA6q@N`|iZr3[> mH5glZ^Om\u _EgLkLk9 a[Cv_#O՗tFgڠGHU<}*l ☊NzgZsYwnZ`; (M瑚HB T6#w'ˌ?w/-3d^gkVնqY5 #pa܊]ïUdRR0WoCYcpB@*(yY"S.:v+"87) P\Nu5N\HoWp(qm2[0wKlJTb hBЬUYoӌRidm$TdV3s5VVI_85$nȮbfʮ( m),2k/JʹS5w;)pil;aV0ۦ@ěT+Tbbu0zgie y<%= r 5 `Q j9B{ktmZ2k*—7=ekAǺ+ekAǺ*(e(+/XfVeJi"ּ~떟-^krv~*RaSQe'CkpcLj k8N{U S+bFU-QWL x5S&ݚv TDY R+ j&G1Z?*\wOy#w59fd͌-S\ J9=h$MI?w[x#Ui,<օg$U!Bu=83ހdQ"zzT8m9J\ r6Pq]RBc>L6QAiiW5!KΟwP^Oɨ!ϖ3EI@ sT$7?7%Jr n~T'cҜshOENO4O^;S9݀< Ļ͗*y) ͑-TRֆN3LE"{=p oaI:Uy:Uu<=Jz~`DQB#86lbQTNInM)$һҕ昄 #8Vyv2,#ߩ} Urs5}[qtҀ2u4կ+kdKPQ@!I:YY\KxmQ1PNȼ&BMWBMRg&㞴rGsڠ03ۜ<O"[ #gai'+ky=*iFf) i#nrGJhKpzDžNqҡL;/RS8jN ! hJ{ B*, ˵y]"#@-S ꒁKb @ nO2(@p3ަ"WPZ2I"3[vAfRj]OC&gr(*d&-׃+Jx̗`"`41u⹋T^$[u=DP-#;|͒)КXTSG(~du0=4KIc Fh qϥWPI]jL#'4T\(N h]']JJ*X #RU_ڳX@s:Ӣ* Tq7<{ȭvǚ'^:`,#<ʴ4'/qʿLJuZElJVElJ "Yv(3 ?پYz{7Ҁ)ȷ{`K潲EݿyI y=⧄nNGndcQq)tL`ʦqQ8F(hAQȸ:DH֥hPBV\*xbI4𱃒jެ\ it.kR 𪮅Te,1ґ@IG0 Ww&`A'h*`<Lv(Ŭ,dU{midqD,I9^HB:``˰ qS%hhsN,Us}))$KpFNF}|Kc~}T7rXz҂EA,߃R)٨ejIlMcL2v1EyzuTs@ƥв69wndFcePNi;SZRJ>v-L%'i l5UU{q@֢zc<֍m,x ͹rj5+o,N܊Ηk="D' {#:,n1ޮGdLp G>2հ#$EJF_#P6>ЩI4w9gr.ֵ4ȁ]A0!FUmdXi8L54:3 RNA=1J'5\K*L(e3OU ʒ$I-)Wq@ oZzz;Xu y=iBNԊC=!qtVf>#8Oeb;c{х$K|Z~H@ ҢJp @.TҦV}(Wqǥ!^@4/z*`$P3߁ދhۜSV|S-۱?hJZejf##oNSy}i̿+61L䷠ ׈K 6EfnTMY$?+@"e#ʓ[n*Tc9x^5*Qo0Ji.ư}@"&ֵ-pIPS {VLYOP گ:֔RfS(/qkNYm8<ۜWcLF8"<RYR9z":֥|YZ;֟B=)/ %sT:1/sKj4, WpW ^k*Op{sۚ.<$NHpN2TTPJ&(݁5_&GWַsZZ欥F9rgQF)`A^:TLwg#(vRz**=nATWSUz,|r?Z OSҚdO= fAҢAɩFGҀ2.*=WNV @=8Hb& |c$Z]ͫo٘Df/=\u _EwLoX:gO+x9nCv_#FLEF}) p(bmSzb!u'<A9'4 w&)Y'5]`3ڀҞ3g?6?ӵNUOz993aIJSU'AOop#ʼc@DM^ *k nwf'( lPBYUr\4R`gSgv$4bf;֋^b s@7u8j☤zT$QC fegmҴ.`dOmL8]$0/`c8\S%` 3̴vm|mF1ިjVP3M0qjq"s@hJ֝P=0gJ\3V. eA@vG&/Q94UV>=ħqozS+F8rk.IO5~"uPOcZIgZRL'J@A+P珚c,m\w@'ڛ)I;sEMrwoY[i9 dcBҪc.+Z銩`H2nj;f$jnNds֤2.ƀ:|bcFlj}{VmtI 53T5 vjs* \<@;Au'GZј=krZ<zaҀ+4 /Nz<ZF8G5$s4K{P|],qX\֍@wh$ XqIsJo(<(Մ@o'ڶ3wtF!Iuw$ڙmwVa+ٮBcgW?X1$Ljgj%,dҸט}?@!Rv'dbRMAutIY26qvM>%ڸ` QӵL)s}~pHqf_i~sSL8 AavB2UuShuN;,Nk> ddʑVDH[~4䓚= C@/sV\cު[W#9LOJ S {q\|Y6Zռ!#=q-9789ۏ;֍5߈#cZ.K0I7mN3Vem%<涤PT;qhydah$sT5|oF%=*cChr{Բ͜~ 5ve w(AzŹP6c5<+ZEɠ n@&q(Q'\ܩsۚ殴ʼn[VR F}+RH5oOʃ< *KUN3֬,sV4؀79" 6}}*$O@gXNm1:@_Ȗ~E3E,5Jo}.C$`x۱4ԥ跷Ue*ck7IZfM#[x<Ȋ5O) z4Jh̙*yܶaVˆzw{P֝$~Ճ" w[G_ށ0UnLbpE<3ݳ?UUawxx4úP9/Do?Q"}k!K5N-f19=Or&b8 3ܫDFy5gGҳ-5 Z: , -^ z=5rz;:]oVjH|#j/_O+xA[Asw>kZ$kj??ʐd?3Qd|1 I8*1+&?-)#+JzƱi".|~R9<.-˗n*6vA+s]~O p1h?>5YnJ+#to[]xoG&0qL$z)jaF=kz/V7/٭.2܀7s[f/ݑkP6v5rzx,85o;۵t:SXOր,BD2ZҘ>VbFJ\HF(;6%oW[MyZ}=(Ηd'Ve d[R<{T24z([qT!RL#Ԣ1OXs0.TU{p#f"hpE>b[gcj '\H 0dp=*I4䌝 st 7>гǂ3e Þ( NN8I:{S+œUh.Gb4LY3H@gA:4`PJEfjkַi2GweEqi UT8$סAF`+'Pd¨rL|Zii.W;H@ZPc9gY u,G=Mmx~ԂB8YW_EX??VΛc"+gMuUSQ~7˴QEYV^J?پNEݿy\k-?[׋OxGLCfNJÓQgdɂ2i%̠iIlsjvZoA (l1[i Q ڼjED0ƹ^آPǎqר`р~:WWn}iyanx~VɖP)U$ր*ߨM7N$PV-O5=鶯jyQU`ι9 %p $㧥=TaJfHAҀ!V[Ji Gn*I4QC)WF;T{]J\*=hV&_29p:\y(TMak5aOY1\8F\yA@l]D]Mr7`oAr)@ rT({UT(#h S[$*Dm9VVE3EhDӊnQ[V&,'tg@L~'ŷSZ܁Ij~_PG59FLI|Eo;uZq 220*tHr+ iCݰRvzY AZk)VwM8O-$dU)lRBI5:\FGozyR\J;RKz3oVɠ5=#OO㊍Y~krRFBk鶫N\$0{{e1H]L;UON./ #j_:`*[s Xi F{D'Y Hbq9Rr3[n`g4݁ kc=bkno?JkvhT@@K*A +1$u˭RYῷKyvź~h*潧Ϫmc ,Ϋ33|`u#ƨ͖caq;y[ndtDt] {R^c{_l|Cwcwi[; rqӟjc-JVo.];R 6du*G`Q۠=˲3[M^H XʲkH_\mKv^ `C ?F_ ?vtVrFxa U ab|CmuHg<j ۸#Uie>[N9.J3ɮZ9LWlZәnԓҀ:WӄUz dV:E-ԥw;sEqA ?)(-&Ҩ{D_1(w/ KcEoijQ͓ЅV^\h孵I#",p0}@L}RK"$x&4exsPTfP[Wkct1(l}R^Æm&K$w;xX4{mRI÷8lc8NtHYM;8f9 `tB33p}]]Ks$WrH >R;w2 nzLJPA@P^&r`cS"?J ;JNqZŁL'CZ/%7'=]wCpHJnYXBS4 wZ~גsYYyo}aT֥>ko#[ֶ2*(6!f  @:WIr| +o5؁ހ"e7Etv䭋}5DvXZ Knk5F&lJ&ͳT#v0̢F2r*R?z*MHn@}igRjGX ׻*!QA6HnFTWНh;e;rqxNzHڲu Y`Pk%ȸܪp tVQjpw3@5=E!=k8yqq4Z#\ӽ\$栁p5nϯzAe8&AȪB1=E6B3KkXLFkR4 3@"FnJY2NkH1c#өWH>@Ug<֤p f0Ry@o|Nrk>tqV߈5&(cs 9 |z C g8ʤ]DV 4`wGcrR]ֈQ;c=Me^[= 84)Psgݰ =WNM8Sր$SJ Q4cIy;EuÃR,`"D•*`(<X{V f1Yq:ze" d #mqiޫ\BRA)TcaԶY#kKrUrGOifU6sjMZJ~TҠr4ێOݛHqTL@jnт5o I5-߽'ִoc (N--T\9!X$bSq6PۜqY2ٺj_:b{7q@ݿڭH^+OC1>U>Ze{{/^{D'Y-kR;aޗ:XnEt}P^+}3kxd18l >x@w *WE \j־z[ ^<(9aԯno--%IXX|w4W>#|̭僷'zSƌXψ㕲0 珖9E$ThuG\u;\xC5}掃KoX:_O+x9nCv_#X_e9MnnkllbJC9= nVR̅9=+dmTiĊ3-Z֋:VM7\浬/pMg`mgzU[<.z&)qV5^m5ܷV"* }֨[iI+qZ;13ɠ zvy wEAY'r~ojkZU$.*qEA m[ wx9']NQgP[vVG*OEK=.96:%1o8t|Aԥ\,V]췓W8=2:-@*\8a彄g\M@nݎ3ZmMeRF>و@wAҮ^G, d+Ffi+ @O Ս@F{`VuZ(siOxzgӸE=jEI>o$+ VUx$s3裎i z9JK[hM6lyF8VD}v**MH|O“RNN1$Z=+ZS zk*{2*>bYFk5O34xEr9p(X&YRAiƻMM,aY(]ER1[M H{gjvuڀ+_) *DX4 ج'4Q^-]t#AbM-szIKg(dbZēF[4h Sj@0 2B>ڃf@J~sjپ_`GP+&vl\dŌvGZn(qڟ kX@-&Wzf{Uy.^FӊmMX:ktơu]<*Ż[ۮ*FqҀ:+ddEszeaگjl`{W#$\P!A 9e#4˘#C2P? @e֫\Zȷ{'֒-YJ59vU $ 1LDSV=iJWHTy 5bsxcұ{v|aȔp1*ĹVR!Eb.j9-=3C#'#@#{OZ=[V&$?9Uj Dv < 3INsVC!qǵ,_WY@ة[wXPNι )4>zz5iJ~{Vvv;}^,c^\I6T |&Cu5.b򲜁F]'/Z+_ÚFfQV/m s֩0TַA> c3T#-5Ϊ1Xv 26&1g3Lpk[)>+XZV Ļ}(6VM¯H(# d]=zջ"Wk-\*;V s@㩧oM!K.HQppZ2?eDHAZ16@`ʼ*sx3d\C%9֌vnzTc@G֧{0>ZE[u7\<okù8 [^6P:U^;( 'ܹ'.K+'#Ykg,ii>ߚA1Jnc$H$f\Nl t1HSsg;=hg7#sӇOhcS?jT0sW``'aPzS4lac+w. \[],88]YLcGZh±c֒5Ǧk3DzA;O=(}/ghC`dk3P8yŘYz͝w-@s'$20$+Wt7G4h#8D#nDGB94-}k"}CBzć:ѿtݬ/?~t7{!/?,P[g1[ݗv'Y9?JC8U;XdQ=iחEbqU.SޘZ[so0qѽ#2U3q@Ƥ{bָBK71ȿ.z]YHEj@IU0MbC9 KzPX 1VHsҲ^*F{Plo8S uUWUa$m@IE ]cj)nRxF2I iF-rɭ4B8TQ6Кd{rw4%H$xVqEOFxC)8Yr zP,B jIȳ 8\N^N@e*h[8vA3({է&*!bɼ}hG9l<Üjy1P*x NrץO9FEK8\\$yֱ}VsۻzVT9'w@ 4GuK c G">ST'Fv8 aDlǥCm:8i k&Cs֧yG5YYc]́j^#=hs;)u#WYSIC7c@RUU,DfjָV&pu)c(FԕԆ8sR`"@j´PsrkKPn P;1lE2_YL3*÷nZ h>Gs:;ol]-(NLs[B+K#= lPR\g/X ,ԳohPZui#8+8eAֳa#/s\DWl[\܎9kK}죧#uph{HZ<)EUkRkc,Jap}=iZȡqTPȓ|^ +wj$TbIL\/'8aof@c.ɴUF7NQڀ&ѐ*֛n#ĝj䜃[#*—7= ȩ{'+kMuV)ROV֛*o՗h0c=Zdz}(q׻Z +n?o^{qqۓI &fD'^RD95^OnL sY`ym)拉U`%e gzlFH'eڣd\e~cWd9I&4Q63ָv#q޴u2VL+6I+zu[TQRO5oP [ݫ=yZWn֦.Ͻf2"6qnhl p>ar)CgprE]yZWqޥyPqhFzS`GXgyjrcq{r`I$PMLֽ se'z> ]¤Rs*nF9|Pbe'ׇ$a+Vف@ u*nWvf.y4}7E}7zT6rOYnuP*#$qZKf&Z#GF&nOޠ  ry/ N]W{H^֌,( n;Tπ1`d*jE#ր%tayYb95d?7nzUwId6:|iN}hy`I#Zܳ dcXaH+HڽHL\n/OTǼا>&)$!e=0-]D/+bF.WXiF h UGTnHHԚӇGR )"4@t9`t7j~1[" qY:y[\ 'Ono_,URaTygtZn#6ߛjK/: Vņ< LG1"yNb'm Yɋv9R#]b紒Lp+ӧFb(Ib K4x.@ )y\z_6Y0kI/Li$(0(l&8ł ҴuU 0+InRv+CHyGQrj@Я:Sd-HJXM2T=EHwPLX(!88?R9xy=S+sX1<@la.eV]?*DZ\X33[ 1k?Kbbx"?tNy NFMJe "ǚGJgA n~I7K R@^FK`d$qθE\R?;$ 7^yjE]s]GuTFy\JI'z,$<֏j>0Ns@5ݐ*c魸XR 硠 ymZZ@dg'UXle֧.wI[ĩ9 -g Ur+O#tWAzć:ѱuݬ /?~t7{!/?;[3Rni߃ҐX*m Hq@1* 'kFoٛ=g~;.Y`*irqqoG\W9xy5(!Fz[H =qN¥E+)+Huw|pQ &#m)$#ޣ<Ϩ-(0{t<d-og+ ^HSG Sc1XƜv9 =P ~5^BzIێ2FC:c֌o=*E(g< 8 m\s1T"#)O2M:1Z '@%#ٌfܗXK.qPňPB"LDH z m`T;ZtvMgJͻM6,BZڱXFlv^i<€`Wֶ΄; N3W?-*gҪ YU|6!XYsekn&{0FV%=rɳljMmBp@Jy=q\ƯuZZnkڹ'9(8&,agO t';h÷lH3c(݉u i楁2GsҮksO[ogt{CFY8{],eɦY)ӵS.03f1IɆtc_HYdc$S)+ljpj)Db@vDNqQ?[yی\ut\-JShv UK݌(_hq?!G5'ƻ#qXb8Il9ϥC>/]sUx@AJǷI㱫a|) H@ q@Zdl0ߝiJJcW[RJ}x+*—7=TAǺ+TAǺ*(e(+/XfVeJi"ּ~V +-?[גGn4[!ɭ+UV_Ʀxj nS+H*Xj\@I icfpлJ'6W_84Jq"3od$oZ34:Ś \6uU#qfPS@MPA9p*)G):2FoG4 |PZ9y3 PS,I⋹'<ec߅qy6W6NNjls@93ilX#ZlV?j#LBIR@HZ {P18$ )b`I`ր.EIh'UKiGמ|A@nn#dy8tG3PZNCEi:e0<-*HA;~4PXSd`@OJF@90STNc5*1@ $*pJ'5:`'<Ӻޓ*OJc WaaqX4cVS}*bG'Ҁ1aakX! vFy۷Z!sR}I#M ό}8<q4R:U;/՛k5rG"{djRg8PߚQZE'[?7V|$j/zH|#j/__+|>u]F9rCv_#Oտ[TwmaK0!Ґ=$x8☎~Q*g"y0=릖$`W[ʀ#H{gޓzG[Q4DX$sLfQvkZsu v;~fk@G`TqFB72h*~j Nh@ZO|=~;z3&TIcBNOwah_T7-qRҴa (Oy =(4 49Uk$V Bx Eeoć9j[Ҷ$o.UM: SR7 6P7zc71B\ ۳4J+5zո*$z{9H F#5'(*oMSC Y.͎ i N G8Va3tG5:A b]7@c\UA0Ayd$H9Y|h=F]\>*0?ZKqҸYÁ fA{[c.j$r uvfTN xa+b ـv,V*1Vb zU;չ^U/F>GCojj@N/X@TZ;GZMfS&-gkmT~5.-@ʠVVK&kc;۫JdpMiIT'ҏt#uZ| e/u6WcT[7Er ܂~#Ry h,sp/cBlGnrzVlm 0.|]A5ƴ1 SMq?JtҭANW%"|.k.2~q6'J>O'(?Ȣm]]$鴚HK"gY'|OQp:è&Ҩ|H`OQq?EuFj^Eq?GfH5z+ ɮc| .jt9oޮ#+Kvj`ey#yWy| 2?Qp=$j1ϒKךᲿ?Qqq꫸|Lu$#We+<Qp=5IiSM@58e .iF@*eP/We 7/zqԓvr?*uH¼r8 7/=SZi`^a_?‹3nn=E1We 2?|0›Dw,+8euKw[h^oq\RGL*k8FWy| .V͍Z S+It_ڪ<5 خҥ. 7>,B9OQq?EW`\i< >_'(?sH]F W@޹rԱM,cεḣn1E3Pt՗=k`dƟ)/5c ⋁7 sQԗ#5M !TY ,'+ EIM5K6UW d8 YܴW jwIl'W=88޷lfBخwQ`^L ^k7UmDPqVgp 8ZD4:Pe, Ob=sUQdb+*9DSt<Uh7SG8W4hp|m#hdT.2:zҼ3ZJCq(6yڣ5y }h䈩Z}b.sFQ" PMBomSS$:v')q@f-Iv'U{5~B& }UOP3e_Rf_~gײ"_bpײ"_U?W~EUeJԬc=@?['!Eݿq)o9I xSQeA4þ:T[i\(Ơ2r٪wQ4SUsYry5m%q$lx6zԷcZfTP>V̆< Q,H=( IrSB^ WQlSBB@*tɈQyd!UF-$PbvH \bkژH8'4xTA 95VM^P{_Δ)WjAHm tҭYX`4Ez=Fk^ASZRB[vx~!$/ҝ uHsTҽWxj1`| rdP{{WX_>[GrIe#@#ֵ55I/Mo3Cwvo4|1u1˧ oaq+Tظׯ7[)QѴӥ[}xɕjg 5iƖ/EBE[zsZ6~/Lnb.I>?iך4vb *oU;G Snmfu'h ppRA4C1m0šBwv$V go},(2:Q?Rz3^JBא 6[+&,Eޭ\4䖚e14o$``$#UCzilIGGsOO_饏CIHԒm*evxǧiw5;+;+!G`ฝ(6NX\CY,ZAI-f?'& ثq;_~CH>ةb|ޙs^J$*zW>WuOjj$KK QB" I=RjM7SmnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ&FumnwQ:] idnv,K0{f; aȒ&Qֹ{-@/)vrۗ#RtkxQv{ҵQ6sh/8"LSigPk l(4f{Z6CN.|5{ 1A&5g4fK}.[:?iLH|Į7=PR[KF1nׯ3+4fiZϩ[C{$I Y2('ҚWMRhlCay#M̍gjzhD[hM\+Nq˹#r8F*oC3Zx~(e'+$R1_a+1K/5%!Blݒ,g>lz_p_efVǫ떶 Rx>3[Pj4JPeWb; ^_}|o H$ )NjH<>Y T,biBg<明Hdj9&glWn8ț챑kE99#vYp}kMMp=hI8hv2~(9$Pw%TXq)aľlR]ia}gUEyWMZʿLJRTEmiJTEmiJ "Yv(3 ?پYz{7Ҁ)ȷ{{ OvzHl{ ;q UGAWI@i6irz:?VPZ idlaZiJpq5AmoS]cD~$KJR2`{RZ׵:GP23@5EUzKHJiGRɁ#'j 0gP'*?ZN^\x Isz/LkvHTRFazҀXq1(%Ozm#85fC' ew YP1="U߫s]Jd^zmyxlp(gz@e=q-l;t#,Eju亗n{PnUar5$xmXixgI$ðw ]>-wD #\д;1URRwEuSl{lf# s[΀0bq #t  ~cx +=ǒ$C#j1V8X+T{LiWI9GۆѸ$&kq" _SB,귏a^D*H;6Z5љ8fd.DrF\#s[?`ԮQ FIbfR1iV&,g`'"aTɠ vn"63dRJcx;Su{qme21%ߵX߽.0N+^}N*`WPv yXeF) oˎ&役涂L|·(FAOgΡ%܏c,sU=*Ȑe$$I۷Nvaţns =:S nc18K,Nn;#k`O4OY \o/e3]ZF+EY"V2\ ĩ9 :C 4sv,s(re{i!7ޮw?f6&ECp_;um]ih IMNU+492̓ܺcih6^f$C»Iۥ?/!~&Xßٟjq\w, 1Ϫmnj/l "Ocpwvc?1^iomP((U?aު*8KRV*3譃fV V̷6ݼ6rR~k# Т_I avG99 .yn yK6<ȹ;Pq@[m"C#H C<6G,$cC,6Hbrc_jM綽e-`zFGh~a0hSP~U0KmZX.SB00@zZc3]WS.'ifN#%xN=jH5"}G$r_xBH9qڴ/<7g^00;*ĺ=l +;XăKO÷ԯTci&v2D( $.wViI?,_;N8e4pmL0g܁P/!#gE`Cx4.%j r@deQg#ޱ!;ETS}$Fbvt&rq KB+mtV6W wSnt8cےDP r8Sh!뚼(%:=_pluOuR{%[C+#H'%A{ qֶ",H$KFe!W9bIa)<ۆ|={^ϧڄ?8ZF`%Fr@ gֺkq:y4*I韺F?#_޿F gSOW{k[(8ڒYgsk:q$/WsǾ-c54楨Gh 2/P<8LᢙCP2khm݂BXRWF]-yeZxHm-.~wHI 9k_\m-] #nHQM@Ӥ1TD+o>^v=H`ҭѡH`%+##=Ԃ? u9VԵ.ovjr^m V9SougmB9˛hVه*6=Iq[3V ^"TzI X,VByS=sGz}hXv%Nr1x;/lĈ?Ҟ@p\qݼ<eEv,œ~\x44[ {zH6IgąϰzD΢a$ P{, 30e@ǽ?ÿi5;tm 8T`@"FJtӭc#+ c9GқaiO #H펙f$΄3s;a$9㨨om,omXL,j@`Pmiֻ pd $nܒē6oiwhEW,ۛr{HoTAcEgo+w#I"3&ԗo bH':Gĺ_k,!c7}۲C|/pz֖!;7dH\s"9j|d1m٘8y-uRxѤxt[Y]0R[Qvz⡖RҮeGF2"q؛ȓ1  pi@WP,C(Įy-;s յ)5[k Aj,Oߙ:㏭Vuilo :$oHqq5\iVWS`mʳ3$(P qHoƗzdΊxT YÌ898zS_୰[e#@@1mֿ%KUvy>сYx\.5'O-%yn`F[.TPI O3X^50Kfce>A~٣^792h?1 7ϐ*@RX/eU,Gi΃Qh彖X^HNG:sR-|I]X ӣD8'?J>~ٳ#֩h:vsܠ3H $AK~L'N`x7nn\O!FwʓIyJX9Þ:t4־aĻĘY!p0;I|Tie)-om;GZ?%}IlH:2ߎIZmUi#gf(_MD ʙxLecmʣq8+N[+yRH*#F0({i57+yİ+!6IQ]kmp,"8bFC)lg9ϵmǣFlR쪬K+N0wK'-1/+$vO 5LJtⶇPgلE+ݷvs1zѯ濵 \nP:WO\YHE p2qۚ't|N<eԫœ79=sVm4{;.!A *"n?}?$rY ߁<*-WV$6m!A9usV]5!# p8>v]o@XrO.ulS̲Y&II,b95xe>{l [T1 9=xҺk8,<;W$'=l%8İ;lAuU,Bn~u`U-msٹʐ0 yҟ%-Xuh6XcIeo-sy849# ~U\qBmv-MQz~y[0f5F36"ZG lȎH˝`}Si3İnƑIܪIQ׌dbAERQEQEQEQEV/ROcxE=SMx?iɹjP7[ztm2iX[ːSx'CcwH9ڝhASctOj7`hIVL%#JK$V$ZE׊͉w0֭Ls@O33mj!\ԖhR ӓU Doޜ Os61k+(-d ksҹ' ۈsҀ35YTPZF@ݎ ӳIp{֚: ξt iT|뱑ki" w ^ xzE8?[Zw{ұ_E8?[Zw{ҪˆV]*²ojV^ v-^k[֟-^kywNgj6`b3kf2G1嘟V5N\XI}:;vE8qއ ctj\b9\җA&ixMuxE'\\zp:]cRKιb(r ؁Һ Yl \wxh07w@I.$R1FN 9/6udK4papcjm\FNFo=moyrn.Q?y+9my"@_kP}Wijne_Jc-#3 :Nkܿejzr?kFai- ] ӐxGK_M>}YI<l_vuku%U; _"dO(mn_Ω֢BI?:7/HbI?:7/@ E&ܿsXKKĈƻCeXp>_Ķ>mݬ7S쪑 Eo^%#k86F& VQi- .FN1 Aywojj:Eymo*ܑɘ9 Wwnpl;{[ۋ v$ VkQiQU>Mѹ?:-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-rx~tRn_΍I?:7/@ E&ܿ-qv^5[ʌCm*3|U8Srx~u-j&uP+G!~U :ѵuF˲\$5fP{1_(}@]WY$X7Wg=Gw;˻k3 哟m]]/%]9B_SGOu$׵G`5H+E)b7ֵ5h8fM/%ڠ`XA뻭A~/ಎ[e[q <:'ohW1ۣ0ZjXrI5~GnZ8 @-f~;2;Bpe<"fteHyudx/nmB![ <[oom?V\EcknW:ݳ=K9<R\Qb+V,L[]Y9#=FOk4>td7k*<5dVn=ĎG*A^q1(^~_vjW5!l N+*#XW֫|krQvy< [VR7$ \T=McH[eu@C9 dU7c+yRȋ w{V-Ɩy^Y^I#nf8=ImReTy4Ms+裰}V3v6\`)-<6\uF̍qں>2!z #}*;,?5)Lր3|y*#j82hk}4ȉުFяsQ]O^+c;sk:r$kBJc)lPTEmiJǸO+ sW>Q[w{Ҫ IQ&v( +/XfVeJi"ּnU8dn?o^8J`k,9x-|t01 qJ*NT=)U 8 'a֙(0zP}ācX=ϥQo.~:b݅@ .|*dIt~+rh5;/s^{^ dk\mr7s %$gր c ҕ:Hm*Y0H?Hty$' OruZ7\=?L_iAȣ_L@ey?+ b<#w) wf(*vrxF8iM\_ʦs]j@Mhe@B*-<+9mb#6,PĺMxV.L(lyl7mY v_v*wc6Rzyu36ج\f~;{/zdob=q쿙끟.Biz:,==mngcgF?Ͷ+#a R\sދbob=q쿙끑mngcg|/E=9\&?Ͷ+#a6ج\f~;{/zgSkIӁҋSob=q쿙끑mngcg|gOqE紷mY v_gdz7l33>AdW*sҋRob=q쿙끑mngcg|?=S+8`lVG3v?{=p27mY v_ϔFỊ0`lVG3v?{=p27mY v_ϗˀڡk gdz7l33#}ݰoe\ 4[ʭPS(\?Ͷ+#a6ج\f~;{/zgO-Yr\?Ͷ+#a6ج\f~;{/zg(֧eՏ&mngcgF?Ͷ+#ad8F7uvEpgdz7l33#}ݰoe\ N)n{`-lVG3v?{=p27mY v_ϑ]Z8;*w)'ҋeob=q쿙끑mngcg|AUoW99HN1E秷mY v_gdz7l33>V`[8ҹU 8s[6ج\f~;{/zdob=q쿙끟xsag$`}ݰoe\ lVG3v?{=p3$]Nشēҋvob=q쿙끑mngcg|Z7'jЎ Q`-lVG3v?{=p27mY v_ϒ1).浬f3(RyX.z+}ݰoe\ lVG3v?{=p3m=c8$cҋαmngcgF?Ͷ+#aaGE*8sob=q쿙끑mngcgyb@{R`7mY v_gdz7l338$ Ҡe;w +}ݰoe\ lVG3v?{=p3ɼ;1jH̿ }ݰoe\ lVG3v?{=p3pC`W|ᷓENgdz7l33#}ݰoe\ Fz5Y[=h\6ج\f~;{/zdob=q쿙끞c#i$HG ƋαmngcgF?Ͷ+#a ZIsob=q쿙끑mngcgy8($R#j`շmY v_gdz7l33<{S $J,;&?Ͷ+#a6ج\f~;{/zghJ_#pX.vlVG3v?{=p27mY v_ ɂzN$j#"mngcgF?Ͷ+#a|^ژW- }ݰoe\ lVG3v?{=p3v A;6Ӂ\6ج\f~;{/zdob=q쿙끟0x &ޕN;Yob=q쿙끑mngcg|u,q\TUQ` lVG3v?{=p27mY v_φF gڳ^7G`#}ݰoe\ lVG3v?{=p3󗕒HsҧS*g,>ob=q쿙끑mngcg~޴g߂Kvs6ج\f~;{/zdob=q쿙끟 ӓ9VlX.{k}ݰoe\ lVG3v?{=p37F9q4X.{k}ݰoe\ lVG3v?{=p3\HpN XKTOE7mY v_gdz7l33>MHvJ `R=jR( ^0Ō~gikt-E$U+2:;0`wc1=~΃:R$3&⓸mtv[=O^99{S߂<縈z m6Ҹ//r3]}j`I 93V[?9 V$zg5V ^8kͅY@_P.sZ7AT k0q[vaְHŒwmnr={s@*3m= IޑA M#88;Eă-kWUFǥdBwphaztT5IAmf)`zV}nkf ``o@< (%PM`g/uE9/!\P3il7[@dө4<,}]!>PPj`0y=LZ8 SG50()t5~ R9/E5"9HO>ԱiRygwS\}Ѽ1(;?W7Pۣ(-%Vzy USy^=zERCb GITZlLEGVJB .1UYthXvI\ |QGNw7TS?\S;^0f,݀+^ zZd^d>=kqce^Nq0G*\aGjuYFeL?v3ڪd@$ .q@ |Xq"5~OIVq(}2}qN.'5]J=hfUyW(d'Zsl׊)!d0TټVeT |Q@ hYGEe_.nTnب@nFppa/:8FaYz$ڰ.Z`sjvcO[y fS>!bԖ.N:V@钦7Gn\xN#n=z 6j3r7"+.y6%ݷSנO?~g_¯?C!k#z/X™ Nq ة_&mAcZ10?JC \»|H'.d4-S(u^kk=G֠҉01Y n7@H X>ںq?WgG?'mu? }ksuo#?V# qW2wB29^'ndU&fƀ9:]֠17'uÓһkoVE5\'8b K]=h}!<qjs؛Es[ұTW)/ŻtL":UǺ+3QC28Ǻ)!hb #/Z4#0hMfO;oAG$M&x($ =cGϟ]ϟ]ϟ]ϟ]ϟ]9J|H 롘H毁 P%A銱Osr!RFXw&[\P}!0+HyTknUX"UɎ{PDp=ǥGA;AO!}Ki1m#ڀ6<TT?*UH@SU->g9_^Vx{U¿'z{Qy$]u@rN+NH<(ݸu+TzzӞprsI Ą @99& j.jE2˞+rT!DB܎jP%yMɮ?Zc&E@!BN[BGST% 'y +$E> m\ K¬ o>d LÐbuvJմ+OeiiKBX={Uk jO͜SQ]!l?*?u柕vٰtQEq:Oʏcy]l?f@α_PbͰub[hY"D^jke1*&}(/UE.V54'rVjҀ3րe||L 9,fV'S\ -I44Y*JЅ5#SZ,N?dM:S$?ussU.W jřD8>ٛg#ұnHaCjGZ˸g*F^yTkbK@:Еx\ډsڜ)=[o$(d(P98bϦj VGNv N} [.9 R@">6s=Z `aPh^3 uOYN1@ lRyEH`{$`H杝Ãڀ!*59')&9@"JZ7ɧƥ^[⵶vTjS8# P6sǭ%D603Z T'8T'jIcڀN7qFp֑9#zSd1{2S|ҕp .XR9V:P-aPXZFڧ梈,zn1.cZR =@r _CY2$+켅T眚RHLZdrFrjY-׊D۽gn@7r:Utyv4c慰*YJ`k-$to`@+*0.\{%`;;==i@li8^j9 kJ8r_5|I>wR:toNJҖ[SZnlӣy҅u G&岺 YKsOkM[8FM <vc4LʼҀ.EsZf4ǵVe`OZxWrfzU-Y[#?Zɞoܳg[v#'(fҮ$Qsr+ jW-pCzZX`c*ӌl7Ɍ6j8p1YCZ 3 4,13Ϧ(;N%,85|s.K6JT*< RFO^9.z6٩ zMCВNJ3P':WOh} s:$p*q1bzT35.Bd!'qVu+穨 vZxp(S$Ʋ c%zۻx⁏8r gf2rnAk^`Edjv$F@~Oǥfd2dtf%Fa]Fw7H29$i :zg%2NEAod7sVnH9 w%lE)[r8=q*~er:boݪ }f8zrO@\UlqڮάT*hLPRT"f#f+sUcC$s@qFz>&p&Xd{ZmFswvnJjO8滉!\~m*@V[W)mtFv3cObUuo]>xn=z 6u*ԧһ(7_S]_tWA>(((((((((((((((((((((((/zg/z۷oZRnϿg ^n*]l8וCר](oI &xr5Ā -RgY(srAaS e1,p\g%419Kl 6iF"\y-M(ڧBKےxf5HkA4xG KoKVS$ju((P=}d秽IҸ=*cH l6O9Pޔ*35}cL@ %HzX31U;@< tCL_lz@P BHQǂs}jgm(aZiuˋlv.RZDuM9_*F'4ه}1M4 =*+3~@NLLzM+p+ֹTv_S[$яP\W<`Ȕ߽kHA5u_񚺐NHpȑ'u[ 3L!p+= yd3IOJ!wV|U q4rJ\϶n쟭Za<e<Ĥ׊0x!9Upx%sJ0JU2}hE`tq3۾*E( =ZwEcA m8:yRI`T>{paKb1Y+򱾓H1y9@],㎝*Btu`X8a@d5m8eZg).jp4{ +nJ؁{WUiA`3@ ;[u36' նaDfܪsЛFw]%|pkj4q].\$[o\At69Q@j&JE{pU<|$DA@r8XJaw9Wh}H;f\1E!eθր+T8[Wy$ǖjŴb=(ݫ3 ĎZŰ mC^sh랕[!=bDfQTԢ&(m*yW)mtFv3jgs)mtFv3/ߢ0OD~RJ OvQ}] ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ("U뽟UnݿUjJq+>Q#oF\oZRnϿgL89cI 4h#_jZl *Z g֬JĠsMH' #R}˹2fpŀ'ڀ=Z1ǏAEn+E@})=*v`ڢyq,9\"A)'֛E'5Vi7"ր ?2ROLֈ)JUSPN$ ;S& rpfjJ?գrhArs=cx9@1@YAN @ǯ\ىNgXmbAMM4ao֨\_tDT~{8խob@f Z(4a7$1RI@mʟB:na'ڸT҉ *Kp@5Bl\@MqVZews2:.yϭX{I (a.1kH*HS<{~DTQxϵWa.I#Ҭ!U'z^jlBLH!z !p㊟q a1ְ!i Wh\\FTmaT]JƝ޵QuGk@V5usHu;$Ԛ`gҀ.^\`fKt$.d)ݏAYwFy a@P"ݷhqd[ނL/Z%Gֹg{y v~=$tLS\0y'N:֘Mb*<՘ T1QhK-N+d l.Zrs@ ,mw"smڸisZi-KHM4sZR.&YIoO4,-:ŔR8ݝj`?Dӑӊ,/nMPɶ :\PyS~Mǀiۛ5-@Ӻ=p1YNg5 1@lˎ8~4<ڪN`8 P$n j[k YҤ.Ek鱪FIeHO>92}i.$E+kKNOPyPv"z{S4 ֕ "oLVI"14rۊD,sڠK9.$[P-cU53tpѶ{n7m`}뙲ViCb7 øTNkON,3ޠ#m-!8#uFFc5 υ8Rܾѓ{UU$#ͻ"@TxKph^%q U{pݴd*%v%T2\yvw -4dUe*8odpր.Kq׽d0j7"Qg҇$ –ႄ9+kFP0'fj*DNùjމr6T$(Ӛ׼ɼiȏ9NyRkӜ=Xr+h]c*x Eq:cͮǵr7ZRs2늲 ֙g$jGgTY$ET]kFfq0  ~iifR@ǽt MNcU*ȣgh.Nsy.ȉYiBր/:#+jrIZ, Vm ز`cF @1? N718X*A@]`}j>*\ɻ(ʨxP[v,# v?8ZV(Sϭ\`y-%VRZzZEz\ zTրl`:+~wqgt@Z$DYқ4#}RwfmݱZWRr[qq:y|4y;\\rrx( Xp+ @]=Mtq8 ߚ#h8 +3XLtn0:Մ\B)Mǖƀ6,ry54h3JQ[ W);ރ:V8P$;zf\8sTopb|3ހ5E.qY?)uRͪB9YVMik[^ڀ4MdZǓjqF2h(k+Po/<ҹny99up;x ;#sUVЄsji qր7ʥFR.(n ̄1t卶3p2+9Ȏ=ѶH9xm N\܆d#hC'W^>R=z O6@OauXWA;Y%@8'z˷s3$<}Miɛ{O0ǧ5e+GzR͜AI:f9ZCfLsYtL' a Z ^m56y$q\Y[L*z`PKS\@5x@r[<\:QT6{ǶQloZ9$L'TmUfwǥrʩk a^zִj+hCPZwf}MT>S;O56+Ӡ3PӂGjO1jڹ#ڲbgmTlRjlBxPNьK "+l*8M=t"#M={R^\GD 4۩6D/c$HOWv`ISHp-HqjRq@ KeAcӊBj%΀2[!G8{Y1ްoOO>lvIPt^G$N Pn;N=3UUG5#(9%d0+9v &ɨ")mtFv3D/Q#5R/Szwǿg'_EaW5>EEqRJAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{?5xSݻĪwuw^W}^8>g vUe)lFpxӁI YT"s'1xByt樱(8*EjHT󩐨"/A֑aRH=mߚlI 8uUf@'%^;P9:IR1OGnp7zVO-QPޮŅU8-1UЯ}*BA&h.q*z[!*Qm޵SV;chz{FXw?AUڠw+>cej72G%EizݶR j;띲NҀ*jD8Ia*;/<֮G| @^Kvei*I!nތ:b 7@'4x V`Gֹٖ .I\RYIpqt"Omf-~oZ&$u }vE|y'3b>j.1E"؆ldB3]yG"B294x pAo:K R *3qV1FUbOu`9#ӎ3+ {U{E0(Sju=d] mj3/֪Ag/4q@ڽ$@Jnej UR$@ x$ g֪CkqPIqq)P2_zU;M楲P]-#6'ڲn"(uAZ&+׊]C|2EL41WX=2h0*&Y7F-biVȩ.r HP%$w Q7<էp!+ҢlŌr*yc?3=dRG=(ؕ>7-ZU}OL:89TFeJsRCRt4b#1RI@ JcYEFV$.@Hc'S] hO8{&W4Er)C;FH`R<~A 2Qs$w;K}kǭlr_.94&Sڴci̒kqrPsڀ3n6у?sc$Fq]|J"\$ǻ8++p8VZ߫=+o.}(iJι~dJgl@@;}m3'i؟hAdbL *8@ oբ1YMƵ ^N}<y(7Jy z|C'ր-8pҡzO&,OA{xG&Qm77>٭)b8(=`#8tXx!, !q@al{u2Z p }֫6ph6D [x( tѷ _Q~u:u{lw⋋Pd0`ji6wzeWo |ёOѭ #m۩ZdR>Vg*h Bjr~Pxڀ qLqJyh9p8ccڬ*oJ6R©${K(LIQޢms*ǃGT#μbd=Pba+jf!9n_OTKpz#Fqjw G!~Osڪ /J϶($)5 ?tzԶ?Usz'\FCoPjtBz!$%H4E$2`ڬۄ\8ϥYK2O@jéOlQ =9(,+>QO^a!7AO|ҽ=)mtFv3Z<&]fOgo^=O^9</͝ $E)/+Wer((((((((((((((((((((((() _ꞻ _Ꞁ6%VzF2Oqn*]l8וCר+ $6h IlX:BYT)572 U!oϥ1^Ktrҋ{pK, o}:H=]>Ҷz dQ:s@U$`f%;G Dx!%}x ˰Py:%=&kFŌPpLF*EB}AySɥO) 9 ÒyV@"!ϧzeb⢑ r V/㜚)qƳ8Z $^ct/_AP{=+,xzP7 ri0;ꢱWGD993}3tAw CdIo.X߮?Jѱ#mmU\MY!d<-R٥xʎ2^ ${U]93=Ur;R:cNgʨ t qL$'޷,/5i9f=kn28#4$TA0#XMZ:kAʃYl/OƯZ4nU Y:6@9qp4z] .AmA@j#^Iհ~*u^R,MXYr) Ǹ" c?Ҁ9T}j\6E],VU$(Z:LϭZ4F@U%TiЭivdܑ@59˷`8mvYi!5lP@R[[n8i!i.]zus׀)u $z\50*K.)gP_[]+/h%§h6RZBU#uKr `fHV9y[5t AOZ"Xv J#QYZr܃ֺ#95|dvLIYIek9HNjqݳ@6qc"@`}*]J>PY@qRq_j{s@ ɥu j"GNN@quRMS²;} ZJ*~A$Ur58\ְKt ;9Mi2}(1֠2c@U$|9'OZ!6; jqI39Ö8#4$d $-dիɼ+݆* rKO1쏦*rp# ~S{Vض2m"㟭sȪ h6[$sK3pFq[ְQ~j_׆SנOFb1]ïSŶ׆SנO?~g_¯?xkJ}+|5>EEt袊((((((((((((((((((((((kWkW vUe)lFp|nhdbI W[JWw[)N7u{g3BA)k4X =* Ð3N3 b!v·"GI\ hZzj#!,;w'j`M͓ɩf;S8 2ر#4ʢ<Mv بu .?Ji9i _'x 2p^i$;QJ3K&OA@VNE,tI^S->VWU VSfy7Zu\ƽG&٤3Ҁ"nԩ#漷Y+'zݜ ,&椆_)u ً =9AEsӢ,ナ#XWa<^ v'E*: iz8^\TZBVY@"Ypj{mML]"M`Y.ޝ - 9Z1 ˓ S͞Lگ-U'ڮY8$sNW1֮1 *ʃ|jyXn r*CTo ]% E]J<OAsOĚm!+E2hQ?jq"155`w]07S|9wI phLG[Ұ)cج乸f H'ַtVH7 {U^9^'[vFq1eGJ{x#JXOPfh%̙`*ֆ8bb^zӒ`\ibb5r`Z۸I&(J8|N [Cis 8Gf\ @84rqC8YA:R1׏5Y{ve"6~d+(i@ tHc~5'*՝\$~v8NN1RM AT1=3@&lgT%8' YjH# ."<'@^xB[P~'ry5mXG!\{֍Z ƙ4#+}슂LPWyyfr&GJ."f=sf,FNhll V= +[ [l\ml!׆SנO+~n -#;zz~lU'"/ OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCר7 <^n*]l8וCרZ|RCdaGN*G4 2㰦"ċsUC&UP@aM'^;80< i=zP][`QK0wd4ˈǰ I%T !g'@Y0Ҁ4-\WmXweNF&e]2Tis&3dq)I +[:WB(dX[ ݻf/;m(דPjE@qV?C58^饜VW5$ҙ$,{tu4ήBu8 p:TF9IwhaV8/Whm#:Uǟl=> # F8J)9J95^òVjb{^ l3޳7< DžuK:l{b,$(ާ8*Hk)Kc޵{W6=aڲ-͑[r]xwefZ|AcaW #waY~3b., ]Sgo^=O^9>r85οOxn=z 6u*ԧһ(7_S]_tWA>(((((((((((((((((((((((/zg/z۷oZRnϿg溛vUe)lFpy8\.xl*F;S|LDre qZL Jq8l5]#ڧ$rEsX>)v$Ǟ8~ ly j{m#0BEdG tnN9*8dDC&[=hq\q։G`:L S$w2T`PK:;nNy4CXFynxFjwl䁞J׊[iwk2x5@X;pq5L 2jF0.9P oT3Qy+(s}HYJ8=) $(J{ӷMTܑT&bS4vPDPsIn'$f#3ekZŠ 4kn ֨G v@YۖI(j=|:\F=Evo֞̓@d>#90$HYS;|w&'׊`=}3+v"l1dbcVl,jlG5 L:s,ZhQVn_uzc#nU2H ]$kRyHTl-85rSGSR 0j̤OTs rcbSh;՗?)DqJ(G4Zyx|O=*Քch+>U=kAr=j 8g EeoU鑊g2w /mrwyE*sts&r\*0>#H20]hRJxF5,Oxn=z |Wԭ-nk-#;zz~lU'"/ OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCר06I%Vz]˶@z*~PNOC<ٓe\Fisڀn=4ض`OQW d [ڀ9o&gUT 4RJ? ^@٤a>o*$ @)%3zTjᛧi0Eɠ'޵Xʱ9݂j)Qy>EVk3ր,M44 g֝Jۘc@ rlEj䊪*wXR QN:LFK>; qK֠*X:ր'!CԊULa3 MvA@9}3b=;ӥl& M>,IH[o[Fv3;OBN@/5}ml!׆SנO?~g_¯?xkJ}+|5>EEt袊((((((((((((((((((((((kWkW vUe)lFpx{Wkn*]l8וCר'X;TnX2jܳ(42v|?TAqKj98e٤qpAM,cɩ; f=q@st1&Ʀ{u _,GY9 gޭ `Vw| H1k:kYO$1׭e^ʥ >BMV1r*Kq '3@n:o,1]^xXHX3&r3h<}h}iH%$cj0I8Af !T`#Lr&T9w^;(չQJqb*ziwM Fxӊ3zn[,/ Rshx1X K1l\p!rHCn2x (wiB$sgZl%ֆ/ 2ma |nzX`ÚH8!N3ր: 0-7̓Nء8)oie^JbFs\3#ߜF$dg &ր>9+đT-j*po^2qޮqjYJ3oztۥ׸ ePzX+ր3USZY.rsVev1@%$V,ŇjHrɬ#4moVHczTۘ?EpcIl fBFҤI Tf#`U#}4*dP^G5JkLUcG[kAzmfd;u+=Ԫ s@ ƌ)ǽEEqRJAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{?5xSݻĪwuw^W}^8<,Y#ݿUjJq+>Q/nFWZKXu>6T˵<☆m(ă֮naEP?:׉v ր$A_+֬2yJƀ0ㄫtT9Ks֦d،ǩi]:k5 O;T$3֔Y6%b܏J͕IZ :Q^{q@B#p+/X qR:U멶#q\u< 8 =bvP})$t]9Ȫ'LFiҞ|@ ۶>s4ċ(^jMz%<(sfК P(vg#ڙs~V֯ۀ'9-x6Gau^gMḶۇ# /Z+ v@4mgUӪEߊ܂#Ŭ}0et69_F9N@ϭu0ϵS`L=*բάUzS3ր$ҕTnj{v\I$@ I~xFPaH\]e'jۭtvw?:4WoԂBJkԂX7 uT(\cZ奻ԙpY.4Lj#wa^=Φ#LvWbLP\MNVi 2XcZ5 TGg՗.|#Id Huȹ%k[x(tf _Ej$1}_4#Iֽ9yw%NW<0?Hz*q66AO"ր;Wx۞\<^3ۓƴ]~4җ 9 *$9?H8 fQ" Yq%MFJ=B U'ڀ-^FK *p+>Y5nq('ҭAnqs0P¬gn=S)`sҙn|0r@_҉$Fe#\Ny@yWuqR[Ci8PN}2w+qKn7$iHIFS3Dž2$38jNy"[ ;xE4ˢYz deAJ{ӊ8O-9 =*vzgjruL<*^?5Z QR6ƽݿUjJq+>Qkޒr mgJq׮x=wN\cn^;IV#\(tRsפci֣c@ # gtw.3ޣ'lAyEw~9Æ=j(ƃI-̂R~\GZ`“g_\y(đݍR'vAϩ}kS\?χ1i1949bhW`j a_$g@NLt9+Jc#hsM F@yZ[3M@q۸=FnvN=hӭZ+b9XPB|b?S=Oɮ_ENzⷤP1ߚø0w`'us `)W%H.q%cvKl[(F1@ MxH6?rI¯Bhk8a5cd@&]`Sd*BXԪƹ$7I,5%tΤe Jt"9_U;[vbGsU+&溶UBqڨj6߻@ֽ8[*]9ZtfLqW&Tl@N=+/Ox)KppI@9)M)06*U( x*WLZ63NL٨m<\bUG*GsY ɍҬ/*H"]wG" @ao\=FEr'%ɩ35^I=hE'#)t 5ÒT[X<|5YHD#o(-(;9V*{V鑲եL1@/v5Zm2n޻Ȯ$l>ŵZq}<#@ wYڈFLQ U<(߻ gBᘒka<9n[%kJ? ڈ8SlGmkYBB>}:Pceimx5W?W^Z cS$e])w!ZQ+cխρV` @u=vt @b  }quO'"X0O^jmR%dj,Axɷp͎[Ԧ)S f2mi|cO'ڍIأ*(u$g+UpXjv#vEWYw&Hhf!OczXx5418 ˻u ڳmk=K|K;UhwZNbl`ֳSق8&7]sT.ЏAV>lA`kw<sMmiVfSl,bGq涢U\ b-{5mF-7dcWR<%#cy'Rk22+`w'!249#lޭ[:\T /_@j-$go^=O^9?:exWL -#;zz~lU'" OvQ}\oԧһ(讃}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@O p^*T p^*Tn*]l8וCרlk-%Vz,~ؒǿױbݎqYiJ݆/8!FH@B**A: (7 iISO$Ԁ(#ޜ mi.q;fP[9@ w{RY)|) nLvh/%)'#ZԱXu=Vldnku z MJ!aΩFprsFGLo-N\` S QSL7z*<.nm$^MsE0xXKV'ڀ=i1_&yp1\X^FŢ\;׏q@gpYܟzk5HOҀ3b{rp);)^kL@ M'l(q;֚i ad[`XKF@O,P*V閪"IZVG# A0qaKmǎGXw$ā >sj4X@qۺS] k$;P뀡@zBVԢ?FBA5f2,oJȯzXgެ8x4henMtH']֭#4ӟ!F b H**dȘ`GNbBf(:$Z/T?)fJ>q(GwjيD!W!$N7UH=*(-J˼敭g#q_[XJI'ڀ2 џJ$jČCu<@3)eђåu/8 /3yOhnLEkX xN}#<@PҞTxUP ©ɥOp&F#k=?:JܨYU6 zvK,c&zʱp95i;M\IYT+& Te98;r7B*zqUwb ֻ̣$Sq,5  O^&+m)Bɬ{&'"=&&W7JGu[9mG\ּ ǽTU>}j"=9%HFpKʯ$ʬ:[ n:ր;;aPEEqRJ0EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS\=w\=m۷JWw[)N7u{g3qu\oZRnϿgɼ%tB򀬻h27V'bWǽ=˃Rri+:1|jIH#fzP\|ͬj2Sq=j$v⫬^3Ҁ.2~已#5x2:Ⰺ׊U0*79@pYE)4d w4y$vh`1ZʲұGzڎԶVD0oZhsL_.xN=W7(3Zf'ԋuY>^* )8V$qTghʧ6.!Ag+"MA ;XO/ I2s@eܲ>^.V%ҰpyiAI \:ڝH QDȄ1@6 +2'ڹdn5"К{>Zoўl*H}*݌ $rM#؆BqONI@c<7㊜E"(a{b8NEWYNOyfH8+d NJm5J8FS!%I?($ztRڸ4%r݌xsfɢE t#cuH{T C#ሠ:K{FQmmёӥv2۴d9NALBꠌ>EW9C0=kV}@8T2)4LȘXvWTe=Fr2Ih/tf:?OZsbY@Z[E\&AH WjgA@}e[22G85R!$9Us*ۡoOuPT:Tlx*[l9.VG`1\IbsXb{te\MϯJ{a[IaP0+@D VKM$u[+u< cm!sQxPv| [Qiܨ`I=kڹveW$\1;~sҀ!HZ=vՉXռc 65"70 rs+NY" 1ڢ%j%x\_NzD3SנOTھ_NzD3SנJcEO OvQ}\oԧһ(!QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEE?5xS{75x?mpإ$B93P'̤q^nUTxIY3#>mK[܃?{=p3Oo5E7Q!$U @uNնl\fAEmVǮ3w oe\ _{#Ka{_r*?Z'q:[EmVǮ3w oe\ 6+cgcgKAl/y}UMnW8 Wd.m=q~;{/zdmK[܃?{=p2^e a{_yR !}F\xb-]/elz7r v_.m=q~;{/zd~ܿĔD^X5; 16+cgcgFtm33%_{ g̣ú?_t;o֞> ?э6+cgcgFtm33%_{ gRfv>MkGlk՛EmVǮ3w oe\ 6+cgcgKAl/y}/K93? -P^.m=q~;{/zdmK[܃?{=p2^e a{_y(b#F=b ޺tm33#h_Ͷn쿙끒/[ _r3W ~5Y]/elz7r v_.m=q~;{/zd~ܿ"V \zftm33#h_Ͷn쿙끒/[ _r3=#?]+h_Ͷn쿙끑]/elz7r v_z-/$f#} mK[܃?{=p26l\fA/_/9rUz.?t͢6+cgcgFtm33%_{ gvUl'ڸNGf 65M6+cgcgFtm33%_{ g}f,d*AMzh_Ͷn쿙끑]/elz7r v_z-/ RFQ^.m=q~;{/zdmK[܃?{=p2^e a{_y2qIvic5 6+cgcgFtm33%_{ gZ 6;,txWM6+cgcgFtm33%_{ gͶF?_z[vY\& Vtm33#h_Ͷn쿙끒/[ _r3ⷻ7A6˰ԟL=׮6l\fAEmVǮ3w oe\ }^g`ҧ0k[EmVǮ3w oe\ 6+cgcgKAl/y}96N{R.^.m=q~;{/zdmK[܃?{=p2^e a{_yٍCSݲpGmK[܃?{=p26l\fA/_/VMn~3/zdw͵qiJNJt,cӴyH/ze0VMn~?3%Ďb_ZF Mzch8fe'c}=p2iv;O=q/zd,8S81]n`z3_^wcOnǟ_p8k k5q*7㞕iGwKtҞ~?31K @ChTon{쿙끒|wp7'Zu_L7<5W)<8e\ SDaE; 浬Aw'־o x`#ú#u@c==p2_ FI(vq3%V'qRzzWwkɛo[Hvzɣ'84g(((((((((((((((((((((((8e!PqȠ-t[˚duȬg,ywk**#FPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLz??51tQEy'?Ə=OnzLd@IoSۿ^E1tPawh7׭dGLzo.f4k͒WyiQ ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEG7I,0lުvIzZ( ( ( ( ]sk5Ʒq\~]oX|7zk[Ns ;#Xmʁ"xVD۔rF8HVnL2n8LPܖ~5UӍgY4K~f3ٿû>}zp ^w"Wzӿ\xCEn&7 kmh ,~`]Ìu8V u![7xYO,K c@"VR?]NQ ^w"c tnY#qqm,Ou $`y?>Ufco^>G»׿綝޽=Ezu][Eqo" 92A"ջ<޽=E+ԨջԨ<޽=E+ԨջԨ<޽=EIoUtK˛4')opP?Z'i-ΈZ8Kpg֪զaFaSC Đȼ28jObm3AV?V ?Uȶ:7zhwZy,-ELȹœz /ZF,ogD3ڈ2H#vwEnfPH7K>,xyA b5H-lo洏u%Aq0q&*@9jn-o/./"K1"\AB" ğNsIm=F{wviр@,p@CL]Um®(R8<եy'W(l$yce ?a½ϲ'|y[|7}wc=֞᫹m쮍֦UV(r%@Z77 eB9; \{Xm|4* b mԑL>?ڿhy{6Yw::X=U(5oq$`yt/ڹcnn3]0еH<)}׷7)*;(%˴RQ'#8QG@p ՄN Lt¢ 2J3ʞgW,^*0Y[[wf%\s:P_ i]#Oge %K"$dAZQ@Q@Q@4ԣPlMz]բрL[I 1NTqSk(/?鴙mw)ͻa3;:( ( ( ( ǗF-axJ:uޗ+˩1i[b7?.x8O&d`qmQR0(((YEAS kp9/]h:5>kN10nt(.I#8TOZ hc/7o*4xg'/=7^펧<^&{?xIL7w$ĩ6mi>٭e4Tbv:Ozi;[:4Em)^;;׍ Tg FH~3[5&%wN sr'%@ӡ47RĚri%ĥV]9 (1bB恝55 h+{gy*(,va ʹޮ7@;ybD,Tiup-z''=QEQEQEQECw3|8sVwuAa,Asm;>TpB:ۥhnK<[kF2:J!EI=I'O$*'*yF^r}  Z?dIFOT/-e92ηp6 JRJ?civzy:+FI7FVRN #Gg\!p[]RyQz,Go)lUk 挕P|=2? W;{<&W2;O##!k{%t~gVrfbN@yԄbCa pHFw{So)lU_|> @:>Z+ƿo)lUI5ާRU >}}~4WhSQ?o)lUekFQAMGeϟt_f{-_76_* j?/G|;3L49 ʥBpS@=pp?!UOů&ѿUVklgxYQH]h+:)Ӄ{RBsQHh;(((?g\AO*')EyjWwB__Elm'oKv6F9ګ^m- }GRJ쀰A0 "5b/9;$R ,@}oP׃t᳽nu. ǴVX؂<; {ERQEQEQEQEQP4sEopmt+ymJ.<Kg>a=PsxĶuu_l_%zZұO qW-uS,!hٺ0"~YM %EĻTl'{}QZ0p֍:SikG\y\kO>\fݔ/#G5gCWQe9NjVwj#6o3tianO#EʭP$q9˞@<砮=)B"gUJ=Ί$hyL]p+(?1 =YL-[thv"O- V o͈ D/ª*#@$q=j`Z*>a"Z`X\ğn\L7 #MrO3\ƭ->|`ps]]vA7YI1eo'{r y*ٱ.w6r8Izg'r'~|6n9۷n>xǧ#k=Fݙ^ʗzj>u`d8ah略 8y뚧\p[@rbLI~u֮[(bc`r 95&(qdF&Bgx5+)I8"22/УQTktef\(*ڢ} >OQte2(۵qgQTt YoT&#H g覹{ TOH+p(((*}3AV?PTg" fivzl[i֫ios2+L d`J̏VحZ[{< Y-m<1QT#:cF $ȗW rlQy;g|qMiMf-I7s 3XdއFir=?wi?zԵ;IEu$Mc,LQ9"p}* hw RI+[[{y',X+~_q xZw*VG',R,y"yuv#8 s2gm߽1j_ ӿsnW=]._}褣n"vH/LEI>[jI3 .ꛎ{(*=7i?z7xZwCP[I派Hȓ2g<ݻ7dvsZTүu R9eIZXjH.BdRvhU@;?HO7icCa2GֵtbWY~$ Iм2&FFQ`ctZ̊ URe@ŗ#BE?~,.y/ juNjt[h?Go$,lQ؅RU7/-km-̏1.B[9)~Sn3dkgt_}şo/#T>)ѵ+.̍8&\E6HI rI IVw[i:MvjSG$4k,b 9 N=E\_? _Fm#HԮ4=!$Xi E,@͸xGSSi#"])SpXڎ>v;G,NY,BU޿6ڀ;:(§?g\AO*')OjxSKrzH(h;"PmЎcmN xqaѭe,. fAP>-9,,>?.%NPNk)6}X㵶KH+c pbx|>GkzŽ>Yqiw(-q*$ĎX 1K;G*7=ٺMIg{{;Z/9ZdcGuw$DE# #ݏן?ԞQ֓T&}8]ֱ7̄SZigOh5.uh\±SE0I< j3h7X zXH&zBG =⹝;zeŻV#nGVS?*~y?go/#Qf |=ھgt_` 6e4IJW$H*{Zw8mBvq3ߊCF|_@m5`d_{V:5H5'vBܩ!Ny'&54o5wsRB%D*^PI`Z?go/#Sv֟SǫB8fE(m>Qug9:gOmG3n/6ywŞuan_QmҦ(l,`뫭'$Mg9bpco㏙ <ߊCF|_@m5`s,𮻮 m;r o1F6 dc SUjږ֏dR(#~21+1&!ί/PH?N_? _F 4:.fWq5ܶor H$l.0IU{ rYދ{vY\X 0slLu7_? _FA}<)Lk(ИN[hN=jڤ 53>d'G~*Y@]5kgt_ v^Y\lv!h啡(qsϧ/SmBU *Or5;)hFP;u}şo/#QE@\m^ܖvSKHyO3B>}ʻb#ӓns÷zv.b|vKut,p77_? _F`(EWEkwэfa(vLVݓ#eN3"h>}be=*6<90H/~Y@]5kgt_Wݮ G&8mBvq3ߊkhZ8( v'$Zkgt_}şo/#P0 Eubfn%7,,q88=W [L[pZ4Ѽ *Wi89^@5ET52mZپnk\ > ?kpsi\AwOÉ'XUV(fr@U=~%>);<`W$QҊ)aa쭼"/"6*h%W qJ$m={C󟓏J(_2WiQE# ( ( ( ( (2-_5T (((((((((((((nip2-8.7.1/doc/src/figs/snap5.jpg0000644000175000017500000012205413351443023013336 00000000000000JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJUs}}謽=syy#k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZ<"k5h_ּ={o#|Z*(A]_֏5kȨ=wZzV>sFt-V|m.?e? Uˏk: "r]*!s $KU42U^ Nuny;[ۖH,zUufW1r nyȪگEU~S˔vN)LKާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ9#K>6ioN2WVՏ"uU8,q^Gv2r {3Ȩ\n:SL7?]=W2yZʣFgh$<ā '?J^=UKa|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|+Ook(>a|ͯ٫{6ViecX+QL(((((((((((((((5O[)^^jR_=cƉ~:V~:WA-Q@XVXP'_w)޸oNsφo5mM/ cQnI;9·HmY\< ʻA;N2qPMv43VqJ2<>h"'Y#war 1)f ($uߴDCF2rAcĶ׷,V*|˖X].k*= P5>ɯYE?.,eHګ0([__,Z\Ӿ<+ BEaz㎧3Ē4=G3E `F)b.I|ЊS%w;y6/V2ʗD_KꚎzE 7`rKc z L"ִxX wAO]9NsiVD-N#evn두F2'hb-'Y#K8,_ c`ʨ#pA1S|bcjCe 5-Iޢ4IyD/<``GM zV%Ԡ}X$Ǚ漁c79 Đ3u{X[e /,,w$};sqV/"dIvD9=6%ڮ:RXi&].1ù[[2]VP EyY# H ןҴ࿋Q)۲8t Ar2x9Ηtzy{S7 9]N6@㩮iKugFTcYCtn8NVNrW养.O#*MK6ݟx3k]E< TG|yzoᐋd^3ZR[K4#Mfy69cx2rw_Ƿz\$ٕ3Gz>-gm! vz\m@0%՝vu 1Z+i_h1Ỏ:ݷ!có/)]}}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^lR&? o_oa?CTz;}J+|t J+|tZ(ұo-ұo-Oß4AjSp? Wr ռ1kj]xtQG@}>וBDA tOSh<Ua$÷Pqάr~|Vk7WK!k&vNdqC <㯥 <'La%,HTgcq#;^76uZ0P7@Ko.h4hLW⩃ 2@c<ǧPf{(Q$C?;2;An_Zr9>_)_C>>: [;-8y Cب_R0 -tNOqopH~H7܆$rT# 9}Bi"ٷq^\"(|qNrxZw>dv<ۙM,B ?0BNIr2uƴN*oO˫N4ۏmo%n#Q#+xĈBrޏe"{G3Lwl9^LwUHԌdܐyu_ }Ki5g6Tq6쏗$J$?Jpvt2(Rifh!0 yIjiE"EX&n,[ <9 b}:L) EHPp7IoLs Ər~=dgE(:2m[chS k|!3A\A5zLR^$(qbVP۵7RtGpqL``~ϧ^N*Fv㜜u*p\D+ʫCz67D!Qd1 9ҺzQ簢)((((((((((((((( ȳgڵ#,6zC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( d5}5 k+ ?S?W[`hW[tEolor~? Wr/ZHc9DЅIQS')iҞiҀ*ֲɥZheXJ#0B #Zu/-7w1UaVޓ.S & | >Pݎ~=Kqٹ{{1Py,X9(p:N-h¬jFNۿmA/d~ [؝^ESQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^fkGYmZQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE k+k͓@ V4>KާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ9#K; _w)ސTs} tOSh<*ֹx3T?uK'Zm⺵K{HeiDaa}Rݕƕύ9 zI @':W [դiD(*9I|u)Mf.c\ҸO~W|},xc+R . mrH?qW1xS3=Zf$P:.kX' x/G)Y݅]CIc1#׵K^#VR,󜍤Ǩ=zW=綴 A9,4ݝNׄU "ڭ$ œqnj~M;E5V:-CH׭ZYFrtҶ Kt-;Ep!U %m/# Fq7A?1ӏF˘㷳2Lc+ssV^}ge?wzИtbGFI Tx:v) MI{#srALvw~8<;?_skm e-P7gnF@=;4,]*h^/5$QqsޙG,,1`' = ^O薗Vn-m@?C_bO{ZiVOcOyd ,sqwD֚Jjp ܎R;^1^9+[}k?>m"X Xry~} Py 3EuLю,Gs\LyaQDZϙIm/3&ˍ }sh4ko<.LtO+qJ9dIZ80O?_b -u\qDZ 6q+ܑVO_=i5|k2ǥXK=Ky;[\cFsCW%E-EtV?Ь!A}پn XAnex#pB<|طh%D\?/~f>OwnsG?=rWOYi|>qg,'u'sҙ{ki~-CD>ZV\`2y Madn ڌf'o>݊$OI-4ծp\|!_trWEŢi,0f 33­Es\Io$rY~9}~{{\讲O6}ɇyy}O5A[G3m2!ͿmH猑Mc?N[ |) }.c.I?"7qw8մsq嶙ty\3|8rG}η,6zA0vI"{ժꌔg`*(((((((((((((((+͓@ Wכ''h|COXo_o_or EPzV>zV>sFt-]wß4AjS!v J{x'#Dycer!FzdZbomq0Q[w_KUqM6?4_F uc#q\OjH?\h28{9Hp@?L 9"_SMm\#~gp GiB$B#,ʎ[o^+ ֿ//5~[;nɅdcg9z~X%9I5a 9(?kx,O"(-${ e  kjSuE; KHJ= zxrfF$X]@ኩ۴t@&\~{?s4QkUt.^M9@'H$}y[ѵxʼ z W 8=#??GƛŦtjw=1 , B1m8Ϲǥ$mq}>KHJ= zx{??Gơ`fdή iww2|4c@ϴ[KhĒEsHaXo>{?s4, =74.HDP '#=Ses.|f% =k}U2kZsUk mo "#pQGs y\A"}&!;Hdu8VokQm$'V/XKy=YnaDQGF}84 #_5Ƴ0vp>oKQ$ѽiI]N oΛl9Z"kiYSϒTrpX g vc??GƉ`IYU6"Kx y0Kq봫wg/8isY#u Iم}=+/??GƟw_/MċmsI3 eV ~Î9mٵ.ZV4KDHd n_??GƩa'mDj_is<-¤F0ZK-dKԼBcpJdgWPm};@̙ߺB/R}KY5unXiEtlxqa7])`G+Arvߥc~h}ft:-n $Vp$zV>sFt-]wß4AjS!Z-uk滸W *2w*H瞵Po B.|Ó } mn$IbyKhf%eܥN ǑLEKx$V jYkwql[u\?'' `:V^ 4gfb qcx_욵 ]&XtR {R?s[{;xcϐJ{gtA8r?&Mƙs%d95LxFMcLmBH#e]zVW$Ҿk7hQԩ;Ty)0@!pzǷsM^)ѼĒ.o-ʅ=y^Es>=w6VOe#FrN9݀A?tVVRW2(A{om  @;x?xGpW*|?jy<X-XoDt%.We&E'T`H(>-q:yvi"K$|f gn%NNH!EczijsݶƨF`/]*ǚ+C&7[j|*F$ &I I ' 4[=-YTb6G׿L֥rKsER(((((((((((((((((( ȳgڵ#,6zC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ~ \kw!L |=IEo8̙}@}0qɬ@V(Q,i߉+ח;VhTeW-wyiN^+<=xozPԝV2ƒG|W-5]yP2z.y_ũ6yhɐǡ 9=zUSƛtU;v%F- G q8Zs[M /vw0i#H.$, $d58 ㍹Glt^g(ǖ;qnfZGE+Pg^ÎB5̘M0}+*~u&u (5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (=+,6z6? ^Š((((((((((((((((// ]J+|t J+|t!hJտԷҶJտԷҀ9?NxsFt-]w1u?B]BZ4O4@dY— $Zru_hs5ch ;Խ}O գ[Mc퉚ONN@ ydunPI9AUbU =3*K.n47$4 29 wst=FA#5ޥ.c1-h:'mJ#ڥ6s<;}Xb,FNґ9sN9uxגKŌ~dg'^2wjXZ@T6:3V=r4>D^KFI,oL <ITbR쭮hgXLpNH;HiA'+{kw;yᐴjT)Q=z޸*4e$93J۞Mʍy_1T|s5h#n^8D]x%AO8H02`NI 4 RTU (Š(((((((((((((((((J6? ^<-"͟Cjפ0((((((((((((((((cv+cv(WDRJ+DRJ)Z(ұo-ұo-Oß4AjSp? Wr uG7O*9DЅ11S1k+\tLg)E pdMkH98e28 <*$4|9%h.Ky=p{=D޳pu&59nm )Zk4{G*%xrpz'b[W3\y0 :xG+3Ǚ.vA3aPpyZZWOs*if6yHyݾӢ߲,P-]ds5_hZ[It-KVnU}v!Vp׾֯4i

fouq-ƙk I"lhړR6Re$Ty#QO˯=]>qgBϦ[q!Œ͜tȢ[8k ib yc"pXp=uCi[]G:Oej'f8R :VҢ[Cm;VذPz azTh+ە>Et^ ohn MEb[郴NjM|l+s6JK60Hi}9+;ox㳵"3Lg ז<][b64QdR3hߊ=5~P:9EohBޮe q>Woe=HG+*3Q,zQSо0 gwp]8Ǩb&g,q;Xӥ?/P{3s=ͰѴ<`xR6/'Z}ݤ7ATϥ)cUTo⨮_G,?§J?`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`%} c(A~Q`-"͟Cjת|i F7aT`MXK*]̚QEB ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( |_l?Һj|_l?Ҁ54O+Ұ4O+Ҙ(=+VRJ=+VRJ9#K; _w)ސTs)1$2=pANZo-ne%axGz M\cNP}2@LCXL=?ҘװzO~)b?5?q5^lܕ)8HS@?ş¬#?"O*|IY r΅]>S u.<˗[k+ *aH>}h} Ve%yRgSw*le ~TWxbXmOe$v tK0q ǹk1xXi}=?]E!@Z n 99]A9j-Zdfm/7<}k;F[^ٲGoāGFxI\?6>Ovǭ4ڪ=WRMݝ>w=.HS7"h  gSVBW+n#YE`y9PG {krb1~S[Pϖm EK!еf7ky:Ju$FCezV,|m:J[lw8 O\-ܿ'/VSkP^I )9D(  ie, $)fNҸTz~QRչ#GIiiBnd 67>8,sn*mqu °!?qSxܿ [dt7^[-Fq8(Nvl`9IҤn亙RHZxy*2m99OQOSu?lYx^^?Sh>ĕIϪCqj"iP3(9(P = 6p:whRZ[UCu.TODgno'"_Y4ڻVCIT*I냌?%}O{47"r0%l 娥ks~GcNig2D0ӓz Ԛ]朶EchJ:b/\<j_GWiWfE*H.70 A סQw nc 1n‘ sQB+)~AOfӭ5;_:yic ֭Kc%B}pTno{#<3߇c:+(3߇ǑtWQGg!#<~CG^yEٟ?, xn =7WKy0b 8׿v7S7mF<@ƼnQ3rVtP mceݲ e%Q^Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\ϋWM\ϋP~:V~:SQEc[[c[@?iOܧz9#K;^N$ٷDO@]B%G7O"Ѧ7Jy7J'Z-̖zLHbDb3 ҶT5 %&Vcy4:XjWKAL vJ R89]QA +wEe'-t)t4* ݝu̷v̻_,Ut=y&fRt+tjx.b?t]8Z}^k[OuXYH{,Q*_Mlg]dg=8jWP+ż*A-=ֈK2 F0t? Tc6z-GRkdYdhxJ35̅e W!r@yV5K.{ВII=I^vm!6n=B#0@D8ǖc 8Ebu ~kInnǮ+Ѯ_0^x&[ f^PJs׃>Is4\qҽ# ^Z/Fvģߚ؎IRYf @Hռx@iqȩtf I mVҋQElsQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@olVdx[E?կHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP\ϋWM\ϋP~:V~:SQEc[[c[@?iOܧz9#K;o?!RTs} b-ctcPY:Vq1KgXZ {7NJya%B =IӁ*-Jksrx֞MB$GjAHnԗ[aE$ʣdn“EsC4 XHIݳn8*X#VA'9ǵt\-˨$qU1@.y]c\` gW1WyS.u ԵvCO#U@_x튘j\\ywi Pktb\4J\(Sg|sbRK)"A= 1'z.OJߘÏUxqӛX 932j$EGy"w5\F@]æsbSѝ~dU1\7DpN霵R:p8NU&bcsrpkVwMyd2Ur㎞mnm6LIJNfܟcNXc;m&fN}jާu4vLSL@%3 ~WI?+]$VWl@-Dnyo95b-R%@ֈ(3I>Z:K~?QM+EuZ.ӆxQB%$8 ^ZZ=ŴHXϯIڗ+qWIy/oնYyby{9@GZZc,z[,H\;?I}Ƿ=qWiK*;v0O?*Y5$]K)H;m$NH' O?gEu]Z] 0X}T6F'ŭ[zF'*ytQ}_+OWG2 ȳgڵ?u5zPzV>sFt-]wß4AjS!J ?ҟE1 7OmfϱO*n|?4Z(O!?*)c D`J`Ѫڍt۫M\FNr\̋-ĉ,N"9@z늍,Vk"̎ ;n=kvXcH`ܧ7rx?طP+[7vm~?qp躸mM: .5X7$[mk#lӱݽFpW}~b~CQ}AM[^72Od\CRYGNAg_z}Os իJh UFGp9ob~CQ}AS7{zw(9d@.&.Z"H9b_%U]A,ΰ۾X+9 [ߨ?o?y~)Q4~?sv5k 9F+w?*&;N'T 1ž"cRK#7Vٖ*y6E#T)=hjzuֲqm2KwzpN9"[ߨoۻbRƻSK˧yDK ULdwq'IgmKw5B aH{"[ߨ_S~?̿9d[w%u'dF-GYk^ \-H݉8WA}AG-??E?;[W#ۻ'[$:nW$%{)$U djž"ߟa_Ŧ mU𧊒A!e`EFHF+ž"a_+9+e`Uю'^? -MC#H7Y9KdI>8u?طPb~CSxY> F u;~SOӖE햔D$ %r:[ߨ?o?y~*~?9̿9q᫱?~;fq=6>5X;yx+0 Z迱o?y~(žsGG3q˙eDX$̘<sڮ*_mG?s[?طPb~CR}h25Xk&`h`8<9NV5oj"cT+["[ߨ 2E?5"[ߨ?ןaο~?P<Oy猟ɫطPb~CQu"2&yKgpдc *zTPIt9QEdQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s>/]5s>.@'VX'VLBEolor~? Wr/ZHcb ( zѬȹ׬ )|qC4eVbʾ#'ӭ\r@>r=kj؉nŠ( (((((((((((((((((((( N_~hVtjQVdQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEYtYjhW[`hW[1 EPzV>zV>sFt-]+/ZjCڍ(Lڙ*.]5s>.@'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW3iW5i_o_o-Q@XVXP'_vsFt-]!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s^.]-s^.(ODRJ+DRJ)Z(ұo-ұo-Oß4Aj/ZjC ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ]-??WK\׋?ԯҷJ?ԯҷJb(}[K}+`}[K}(/Zj|9#KڐŠ((((((((((((((((((((((((((((((((((((((((((}O5ib4O+Ұ4O+Ҙ(=+VRJ=+VRJtu-]CGe +O.OT[\5}.?k?]tTTV]}o.OG\5}.O*O*OSG7' rG.O]''?G'?Gթ_kw_r#˓?' rGʓ~_ʓ~_~/뵻eC\˓?HU[1Оڥ~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG{Hm⑑.2jpkέzU"Y?أ_*z+CY?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?أ_*z(Y?خ2$ ߥt_ [?ԯҷJ?ԯҷJb(}[K}+`}[K}(?tֺB q3,؅''_ι?֎뫘&2ܼe{pt,N3Ku]bK'm7}Ew8T8r+NIRݞDҁ_nՃ{&}:PŲHK'wpXt1Z\mٌDJ&L1yu(vwfc͑8gЭH8Zv5WeMO1Y p;䖚[ͤyۉ;rv5[OϪ^Z\GH$GSҟ| ]\Ei;wIJ\uUZzv6trmet,5 k[I&XDhC#3T.{#SfH$g"ܵ֒ATBі jts"+*,v)v/Q[-. ^ټade-ěJM.t,4H,pB?>wt״hYD]WrGRT @\mD܂&O1llŐV-'ێi4Ro&]`G, q\=PykwÂN*O\ͧK{ r|ƕXYO8;/BfZjZU 2C8Кѷ8kM 98<5ګz5Ⱥ,hLpGPp2q}lմ9`6r9Lu9S<],HY slWf^Xiyh cr#q`q8imKXŝi9\ pgiC.ŧi(ɖ430+na񓎹֏@^eI,z^גjn(dgrǞ=^x(4=B;V0n?ΣTՎef=u$NpGA=;fn=\a-$Vl:VWZ_#GZt >;x2Jr# N>>:@/8b8<u$)trȂ7gcfizǁ}PcWmo`W'' }QnFu%юHrhϹ-|AGrܜ['('Bwa$pyhcomuȏs]fgԯZ,q*[4o뱯L'm.KKxI"x/ G:U4IJ\PF#ؚVMyMJe-P)wOe-x͉@2m&;iOe6q>rgBޜf}ZL@c hϹOmCzg\ǽ{JqުxHֵ ˈ3j]C '8=a}=ƻl7&Oך:N/"sIp"R㪯8I[xVHѮOU]HJ-[A -'{tFB%X1yw-3O`ϰ<DA =*][j7A"PMuϖq6z 1nWUE!-*䁌MKDhF6bmg{fٍ_z5!.xR9[ =zT^ pO2! 4 'IjBK 3`2FO9֧ki<;zV*OX tz~nH=ɫ]|KCoo;];O=ȭ8fHPrWz-ҵM9!hoM?yC) ]f2Z]GAdmfec,H}zsE]A>BͦcPvFw_xJn~wtPfB{V`]V-{.;)_`{WVzư-t"-!W3'WS^:^2up?4y0;A4]KHKhO2!4PN=U?F,<"Ғ[ӯJ4_C[+6 k4)2+Aݏj/&HCS,@ fsUA'U-Q1[%XUz8it4syQYXv*@ E[.Xg=\r#PNNAZԆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]ݬ/./J+|t J+|t!hJ17ҵ[Њ))8OWmj6v򼶒 `W9qsecU?Rrzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_O[rzo$g/ul_OYgWh8| {Ե?l_O+FȊ* B"ƊQFT`+ ~G ~E",haUF^C^ > ~@^+}?EyM _#϶x_Q^ :Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Ey ~@Eyť#9fܒOZ煿?M煿?MEm|?-SC4c1 Ѓʥ?TжM?ɫ{sxtSB4h[|&o΍ .lf1U\вgkzCkS tGޯno΍ .lf1U\вgkzCжM[? s`K""+Ax/ߎ*Dݟ0-w7Fl|>2l8\gAx>֖[3π>G:77@* 3g 1ڰ ho웑 D?g~:77@?-Gj?TжM?ɫ{^sʀ"жM?ɫ{sxtSB4h[|&o΍O om|:77@?-Gj?TжM?ɫ{sxtSB4h[|&o΍O om|:77@?-Gj?TжM?ɫ{sxtSB4h[|&3y`:'iHsn}ʀ#жM?ɩq 1 B4h[|&ƫ<-hƫ<-h/ om|3ȭks 4hжM[? ?ɣB5osxtno΀*h[|& oսѹ:m|?-V7FhжM[? ?ɣB5osxtno΀*h[|& oսѹ:m|?-V7FhжM[? ?ɣB5/`󼟴ټg7@?-Gj?TжMF61$de=o΍{Osƍ.[iCXOE#̊/3ѹ:tQ{۹-&sEcqac~+qK x!`cPQ8-ѹ:IGi"2ǂt\㧵E"[9vKH3:77@h3sir$#ljB@⤝4{U@w#µw7F4 ZD1 ORF9&Hkg>Ju:֦?P6"s8Udb3(k&eV0B9Lp*?P80]Gz Z[Eյ$hX6=V3w€25>GqRJ p^*T p^*ThX`W0EUd08,}3}QYhv`jڈAo%wn!~{`R&t{a,úAf]Ji#SbcmXFʀ9'zշg 98d9?1CVOx>,#}A @ -<iCVO,cu7 +i`xNpzPMkHl7W3,۽O- 'ڲ-M1kg!0!ewo9c;WյocB\麁+s:D\褆$[Z̷RxJ1%rbX[K}z ?/񃥴I0l&4c8xMYmP]qjm/l 0!2 ̾u'>ī}X&%ŴA': locuKqm62cD@2pOy[?+?pBku o4 HzO \"Ф}CZ<1H"e c<~UW4wI;'z4UYO&G!_Q͊LK"%ZOdhI,MS#O?"B4(vAɀi~\I,Mi?i}}GQF?Eخ90/i?'z5O?/?&s'z4UYO&G!_Qsb 4.UYO&J??B4(#O?"lWdEJ? V=gY?F?Ei}}GQ͊샓?ȹ V=gY??* 'T?/9]r`?_xN6l;3m %q[-<ݖܜc?ZUA#Aux%0O`~No!꫕ǮFG[u_#-K V\bMIڅ STvoQ%77G@I#*W?5wˇy֦o7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇyo7oB~[*ϗѣˇywDu9S-]Z蓀 F 0/I!伹ytMdhɏ0SO+CY֦lwKU3`rCɮwOu+CnV+]4݉Qw ch^E{kɤfnW ’ T~6tMY54]Z Gh\cIV\Xnt2SzWW2K6vmSbAYw购:OE!"-xdˡyp}2'z5׃.ndqTu 98ʓ'EF?ErJXF.U)\ V=gY??* 'T?/lWdW&s'z4UYO&G!_Qsb 4.UYO&J??B4(#O?"lWdEJ? V=gY?F?Ei}}GQ͊샓?ȹ V=gY??* 'T?/9]r`?_?* 'G%ZOdj!_QG6+LK"%ZOdhI,MS#O?"B4(vAɀi~\I,M1Cay[740:pXfH|)o`Ow,ȏ 0'5Q&+8_,~Վs4kx#c@dgv?YӡԙüI ᜑQ;B~[(Їߖ \?F4;dkJ}+ |5>G1 U뽟UmDdo e[#?K#y4]vtOit/e".pN?rR*;.\яMߟ?P q>1Lk,B@UB zbsc;.\яMߟ?Fv]ٺ9ţ?O Ztn#:+.$;qv~{>EPgeݛ3Z1˻7WGqRJ p^*TQ@l𵤬y=CNעC K&lmbb)aEwOG4y)Ɗ(SJz?o<Gh%=7䧣(OG4y)Ɗ(SR&/b][I*%TzqE䧣<E <Gh%=7䧣(OG4y)Ɗ(SJz?o<Gh)E6nȯⶆU"G.҃z|Jz?oJz?oOG4Q@OG4y)Ɗ(SJz?o<Gh%=7䧣( Z%KK{i%@93N*hhSP0SJz?o<Gh%=7䧣(OG4y)Ɗ(SRmՑ_m D]<E䧣<E <Gh%=7䧣(OG4y)Ɗ(SJz?o<TKؗtJr U$gQE.)Ə%=7E%=7䧣(OG4y)Ɗ(SJz?o<Gh%=7䧣( QM[+HK瞟 jhhSP0SJz?o<Gh%=7䧣(OG4y)Ɗ(7~{IPGSnip2-8.7.1/doc/src/figs/snap7a.jpg0000644000175000017500000023006413351443023013502 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVk)i9'GYe]G9Ep  Sq^_, %8?URAu=5C*"r;pG" 0'K@.I$Iޓu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Shnu6v7Sh xbXzM/}EEH&`0 *S_ʢ,-܈IBPXFiKIQJ3jvǤ?zCDpQDpQL]5<]rk՚.?4]թlp d~E}Q ř!ti G+_!OƠ>2*iױç^M Fdmdcºw?5?]xw+i`O[ox,gx ,zV]x_ᯋ@OӞ\˥E71f0zF~ɣ s?*S0Q+#&ac?]q+Kꏢjiq.3\%|e q5±?f.V>0GLQ۹A46;r uǑc^j̀D(L?隋?0t±?f.XKGsFChYYB:0>`@mLiY{+K,B9]qTX3G+#&a70Z/9mMmZ0[Y,]o+#&ac?]LJP>-Ys[wcީ±?f.V>0GL..SD:Ћ_˛F3}zi=.'IMEu418ݟwcTc?]|a@_}։ W{aטY0qPf ,LVGP,E9UI|a@?0t~!\񮩨Ky>$ q1_ڪ±?f.A%Eu|a@?0t䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@J?0u^HЏ@ ( )˯fǟ Oz}^a㱝6zX4\$BaR<~ xّOb/5I5 7V^j+<5#+lY鏥 :gXe]hO?>]j֑̋^E7X(l6ӆJ]KK{hu Pn!ʸ%[a94a$Qk/R\xWRI=qZuEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE2iImƥݱ2MVn#3 6 $@ 7][PmCOW ǒrYѩ';#۵Wtv0:+bHßWW0*tMWnӒyyC+}=kzCB2RJK@ ( *e^gQq?J˯ftRPEwuEo2[eG_PWGb@u=EdMJ~\G ֽ" E--{ }ryobizD_,pv @hQ@4:69vNH)b?UTr,0aB@ hw<by[) 7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"3}"K!`4kv/ ѴKrqln%q'%Q9kIhxWq+3Pȋ3RRr_bu"Xϡ5[ :r߁*(QmԓXL/b7myAj΁p^jilV7zc9 \c{zD "Eih%?:/?*kHLPED#Gc3==N? t}K) :k0[gikK^0IDT0^+NW$q;VΡqcX>r$18#L쓖PCEr6rT6ܣ!s֫$XL~h6ש@y_Q\⋆ӯuY-`id'h ;d*56I{T i:PgEfj7:|w:ڳL" x39>V6$QE!Q@Q@Q@Q@Q@Q@Q@`<͞ls  ۟ʸ  5&Ux_AA˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pBƤڃj7p +GԷ/ J/4hgxdHS1i!ŧu?Uj3)oR9H ::͍ىUkU1!cw\v,쯥)(Ւ wNx5 ^W'F\\;mʨ F8=SZZ5Adi±Ò~R#q>CŖ\*Z^-b[E+ 988AkWsl90I($=Ms:ܲiז2n&ya>@ݐ+Z7j0"e  z8%_K[.ŨOlַV0Cr1Vm$VI'zt3ɥVR8 þr7>V'fぜ3C1Lj>&!?![w}.zmQR,›JDdg<Y,4on?7Ry?h3nW}NHcaӞ:go2U?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_Zuj61Ǝ&p;;zu6N8fD3밁CGJ TBvbz{.m >]C6Sqr.c*͐ON28xvXf(|)#qZUdlbo̰gv7P  =v^{)-$F>Q;_@'#+j>[+ x.-m>[ϼ?7]~qtyυZdxG-P0 ?.S,&pHQgg,z{U[ϼ?DWDp*L (YMgcsQE?_#׍YF2HY 6(Z)~m>ϴ?(%| JqI^C;r*oϴ?( ŷFoU\zg#N*Z7mћvj(ŷH"IKQ @ 9Χ ( ( ( ( *%EA= $o[ϼ?(%| J)~m>[ϼ_(%| J)~m>[ϼ_(%| J(ةQEQEQEQEQEAyw wP~ 7rK=;O"[B$:;Vǽu,5O ZZ 2m~5xgNcC:]ۆ_CWM(^ ]O[6z?hF7lFAA+NEjf+GfPX MFm"ZZ¬ZL.B2r2>´`{H DcnUaK eS. V1"/WZM[n?ei%6Gx?ȣRQJ9r?}?1G֢i[# ( +C!_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%5="IGҬYؖfkt$RqN/ JùUt#\Qo'+qk]՝9V)4}G.F%70G?\j!?h_0 Ii-jfiӭl e8#4-ת[ĚmszRŴ}GoGpmXqnj6zqS9Ԛ]>_%u4:w}9u 2!pc$Q#ou #CsŤlPqjM[iw+f6IxHrҧ>"Ԅ7Q\Nl%J8=T,(k%+:7/6-˛fkKKpa6*.KX^:\!!w.ьؚ״>ɩ7n͸ٵv9sÞIm38cssн?kVӘ%`A=ooxe1`*&O}h: /-RdҮg3kē>xR{c{C"6ʟΒS6œ^wRɊhSuuw%:DwЛyeYH.EPrh"iGw#M~c>dZc)c@WSF;mDÇc1|Qh"e˦4Ze+{8$idrz[W)<>? mwl$w[xZXMKYJ%@`Fv|sK'闖koٿ:g=kYs2nm>VVT`}:?3ڬk8naY J̇ E={՚@E O(אk#V8ĩ'qqϫ U\%Ə^U^ãv;3潰i]Ě71v9,U]XYHy< .J#c}> -)4)s!dA_,_>c)SÒyn%g㌜67z6[_ɒ" ڮ,ͯ"xC"Xpa4T+Uy ioRn2`|qמ)>lr[hês>Z= ˍ:SY0)KaKdP+o#d G,6[;csxFw}P[8DnTnk \nkBiMy6PU=r*߳61{c8K^U|Gikuh X,e,<(S(ϨQOϨ>T4}.\sN:K$ ?3ZYygPak⨼Akyf@X31@8QG}Ec$E.r,6[|p'$V~yYK\^77R6 '5ygRoγm\R0Kmm6""烐852k~Q$wrH)PBOn?:67N!z]紽GÚLglT2qg}C} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu w$?} ֟Vu ?tfyg&jĩO }Xgd3Mnά9ڹ }*__oC ( *̆]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%]2ͧu?Uj6跩RLњu\њu\\coRAΥ7qBzy#:cC*P~`QN2Q`FԑЂMOE0)}>E&/[P^ϵF/[P^ϵF/[PkX$Gi`ay 8Ԝ՚((((((( C03 FG;A$q}>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^)|U~[p?X-UYngnHFE'p\'>ԟ>-t\O0}O-ٗT4NpK=M,ʦ@dȮrNմ}rBm巚/;gAPLlf6_ \hmũhV;$rq9C^#k[d@. Xw^mR/VmX 9K̒MR:Ym6'*ݕص-(Wjw7ho9L t]38k[yesY-}F+s'5sup%y{'խxPד2U_ }(o?_xVwp}E}Et.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pBşv?-woHǚ@;}.4fo}C3@sM\#О ,':/ J }MuPjx'Gt7c{q .zdiڂyWٮmc9T$2xM7wWیq~ןKm?tn8{m>o n:wQY ^ |W[$Ą*#`WÒ+j6|LiKc8|=(A]:TxdkxZuf!caZK7iu&hⷈ^dYqӦ ;xol@[x sPm4;K'c-#HW֦[漽df1c6N0y;knJrs.i_b]>I7  #hZ)D6&Q)qEZOM;ͩj+cO9j/.?ꐉ^ly,E i .ן%gDQXErRY| rq8&ݤZۥȵf7j&ݝ]J9wV:$6i/$E9|i֋mY,Yo%vW0 8=/Do3x+]Y\ib |gK1$.1;WV8Y꠱ iӁ t+[ki dm䁜%׾muqss&%>׆#@8_XT[0 ]Bdc_ AGsa>[7'$j[ 6m]Ew,Xp#? oܭx!փϖ+QI (b>f8<zj76Qiz̷t,^- rGM_ C,70$?gYDX%w. y(4Y]JK5e[O֚'~Hu+hI 7Aݵ299:n͌X8&[p @e15{Vӯc>M߽vj;H^;w3x)|K{kյxch0RU癋m'nricmg~Y7 kxFhc1xRQKMy#`r!}M>}{PҔ+$V^ݬ8Ki,mN_]1P;)C5ѳp1(6vzψtWщNQ2G_ۧݛ߶ycOc=;MyR{cg}i$HMk:å_P4KԎhP7b1DD|}i$jIw/oXl Tcלj \]yR#x i(QsMngoZˊ[ ]b0N)ϩWNծۈnhdW 8=5Zϴۼ~Vۑƫ5΂-MV)L(pr^'@n rm#) eu+(oa/S*lH=y5K=btֵ[hIa4jNmO>rʫdeLn(X@k{| ⛩nKIxb2\j,nl8䑏nx }'3[nѳkyTTrs!.9T K Xc97K sU@tvo~c2n8zwC߇nJK-\Lh1;'}]FݵiUYo(mh 0MoS\blu4}N/1g+EhI> d 6),@d-:^_FzdKVj9nkOMo!QC/P qY>Im5Kho<1nCݜ{S-;TBSDbE d!sT%iBB}Iy$mgbIsW  ?.x[EOթ_5Z'N<ӏ+iۻȷυFw4VVݦQ!.sP]j t{33\F~=z֦o ?.q}GՋ-JSa{owUk6ź=ܗI}mm5E$SΊ!lgz,q}GѾ|.?n J#ӃW}kJۉ5;$7 4QЯ?7@ ?.q}GԺitIR2ebS_ǥ%ƷZ]KNC%«IG|.?7υSjurgkpq#C2O,uM?SWk [C0L>]?m.u+9;uf\u"Voe-'0L@ ?.q}GՋ-NSG{ kC V@YZG,/,. [xH']?մ/]B;wD\gִ[ųlI\{?}\Qu IR`yaiR NO#OgZX,n/?rweuPwυF5=f ?6)-e^8He0bMWN,eK2ɢr q}GѾ|.?M=/VV̢B=9t|.?7υZTPnq>]iQ@?}\QuEf ?.q}G֕|.?7υZTP >(̅?cMCᎃW|G#my?xc= #((e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`WG<@'*F~j$\.8Eg|.87>?]hQ@ ?.υZPxQ._]Mil'2 3OjEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEOV5{To_׼ )|qE? ȹiڙZo-?UtNQb"S!sҞJ[ɯV<Ic#,$N=Q'{}yݥuiF &4:Z}Pr,ޟ)~Wwj>ҞMz)Y[GVBԍ͍84UicP"kngJcdsؓݠl'$t)}=C< cYm#ɪ#y .1uSѨJz5%H:ܚ)}=&Jz5iOF ~ҞGSѨj*Qj)}=9/o^O^>o_Ir3N9vJសs~:_ ? 9]5":+f_t_@՗",k\SA=5?j\X4֭?J@Eo!)_M<±/b}+g$`/ J[fԆ!h\>FUs0:[T> ckҩӵ;k$jQ6<2@z]㲼[F-r@#6Ӑx泛÷maq5a|㍂EltޓRM^K0 #r>@lch[^_C]_bѬ,̃x'psnʑAHXdw"OZ1c&s'H,H6=##SXh+xdpB)oUo<;wqc@'8 y_jzsy'[/N7V+^ѣ1" ڟ0+V_h6<3kI,lUѦPTYf[MjӮڄ: zIo~Wq?ѹ v_4^sDgoo\ 'TIfQ' BK-DQd}Ĝ }~wk 'Mx?1(m㑑_|K\iWm76tAzEϛT<;LE=rKH{R>^跗ivӹpAL&"x1sf-yl>-A',h[1䬄i9R@{',h[1䬄i9Rq]^Y?yn}‘--7\QZ\F'rBH 0HG֝k1ayq y%U`u', VLMfMF٭g1!ly}ֲ j:O$ZuKf!)po'9xVsux& {k馈N#@Jz1,@sYwZZ3ʁt[s4]SNӚYEvp̊vte` x"K9{Ⱦ 6Xʝ`p:J_~x ȹiکX}>p"".vs9\? o.!ӥkv]Ts Y>_+=e44ŵml GCK+UW)Ga?sך.kwod {q,ܞzUw[Cqp$rAovm!+:m3՜KM><[LHG $!Ts*κں)qM+ ONf5 {{Ԓș^D,kC4a 7Sިu 3ۛXzĂ~pHr(T] ]NUy ,rMWnTe6Kn& vNϮ)eMGP6k%ԩm83<==F9d-Iާ^=/tt&='T5י)O1A:`zu:baxpJ6=X6\!H%lcP^yҨ:.ޛq[ `eeٗƁQGjo{ ltqxG,/3bR"}9POj}eiز+\G&>΅5/ٮ[gGYB îN@X׮lKA $co43T[mbky-K ~jxLkL[ZȊH"r7(PkM֭O HkhzY^OV/""Xҧ # Pyzg/yӛjxNF]Jy$"| Am^ӵ[-Zo1Q8*QXW8֕;i&+*hEΝ1+yv 9B;%n:sM_}m.5VmyM7ܲ2Jw#f] sauxҭe;@ `xitymm }:hnaK{#τ)0 O[5Z+2=j $C*6H@Ջɍf ( Jd ֻS (Š(_YJ=?YJ=?硼DuYAr Vk|E1EuW_y/΀;/EOPY>*Սƭ6rF8'go.tk2*vsœoaSX&HRSq͔>`#'P5?ݸi?'P5?޸?@s5#"h`q~r-.#tf9 20O~Tuݨ =ڊ %}mE|E}E|_ iZ$xF7fT19|9%rzt+\ow{ipd_> 0ۀ'V%D7N,&؃j+ȳל?xfj+hffj+hffj+hffj+hffj+hffj+hffj+hfzOגҏ>3Y/> ȹiڶ~Xr[ W?)~PqsQCp^HWeo?l ZC0b'9 {gZmλ53b`JBfs#c_J>TtzRѭ.]E IpG^ՏgX.uD ͑1c}ҏVt'bԮ,Y͂|cT+ =Eo+.H] ?R}ҳMm6ćdCe SS񕞗wy 77Ƭ==\V( eob_J>V( eobu3'?W=??mK=?硼DuYAr Vk|E1EuW_y/΀;!:Ef];mYc}iyjѳ8ӭwEb;(;cG\w?5>"+& }w*ے3c ~y?k?T\_-mu[Y#ܥ؏{1]z?OpFi/ٮِ+Ivw4 Wk^jjrlH*v|޴m:4%+@}rG".a`cn% sypG3(QUG =_~,P"[.H7y= Wm-OO҃ϩ\xXB'-=nmk)/qGoRMmqӹ3{ ?#h$imHYrq[޵`3DdF@ːH=#Rf{! "zsCV[#N-:i+:mgYx89+>&/ӵ \NT ה|M_))&*t \/p]H*>nN:dqX7vg`$@ M{;NӭtkX-##BfnY7/UR5[+-L#gޠH-f {2Yq''^$am$Җ{ĴX}>3]F:\ܼ?]crQğ1t}܅$'Ku~M6R  pk/egJ`9Q1\ijڳV 9S־n9ڼt=oi<,_+|A <ۮmc1q+ռ="Ε^p*u#QsE%iTQEY!EPEPEPEPEPEPEPEPEPEPEPEPEPJ>R>3Y/> ȹiڠM3j?#0,#Pr;z.Z6oP/j͜DžgѢh-;ۼW}q6FSj~[p5hw3|=q3]_hK-j0*EΞ,KGIePNw:nVs-EL[{ JیZ>E_ÏiE&]Fjڊ}3kb@ F-yhh9]_hK-]ixyrhvR 11H#)Zj/,r$cwq>ZPZlbj^.-+I"$N9cx.H%[O5wLG8kK-iEקyj'nouasoqo%֞wP[ c5^MP'Vu1$1<|gʤutiE/_+_c#%%\}b+iH;+.o ksiFK/^I#0%B۞1߅uiE/u7^UJi s$O Ԏ&Uە@|x;wp+ˍ㸉c-)Wqٍt_iE/m-Z~Gm ͻ)mgM/^{m5\" ͸HlWmU>G_h`rS/}-U>G_hS/}-U>G_hS/}9o^O~ՍvC''d= #((e^{//BVk|E1EtY>)qj-H~Cҟe _7kV W_Zh'U[Z~U>/ ? <m,|$`mAs^}jmE.м2<ݏ{zO]MgwZyNc< s׌ׇk$DvqB!9$m$w'#T5Ueʠߺt=qE/nVZle1r <pFs/'^Ӭf-ZD c39 O,9sNcl3(ff)VX `HLu(禮.YTqnɎ5k9tX1dn\r&/^A}~LхlO'۰!FjĠCi<1;_,Oףyj[N~v8MyK*I ou.2.ֆ<(#dž#SꖯΨ[9AsVլi?pNv֮Z,y?ˏ(QP٭n\|?2Y\^.$olßjOMRXW ^ٝ@Zaȓr Wq 籪 a= -e).J)Jwu돭qT~Kcա*u,"֝;{;$S_U=Ϸ l#Fېd;zW?1X%O> st88fARU{Ra m'h.z>P ՖͨI"lA3$vISh wX\PG# Px&ωbC82 vLiK㏪=7.Z6ж}(fq7^:qo-?Vw[SFwhIDGDPN:Q>E⿍S_,/ݦϤN` GT2^eLj.6noq1p1uiNY~h&s9kO$$Q&xR{`O5-ϗߜ_c/Xnt4GF$#{-{X[;k;B.`4͞ U[%fsLv:ō}:Y&{W ~}31O_^_G\d;w :OPW{$Rm4i Ix>́ +5]|-P;1)̐/yTg8 u}%lP.BJm[5N#CӘd:4NC2 ST]֟stqk5ĿieʻyQ^xxhID#mݴ!qU{ }=u~׳V5LysC`Kۙ,ot\Hm9T %ŋZϴ`u+Vxe  1 ~C4?%mjS_j hѰc6^xahOE麌wX9'<*5O]_]s^. cAnO'RKۉ9`ےRBg98Jռ0v}8*d# מHۭ>vkIw-kx')Eo*Ul"%w3d8|M?έR ( ( ( ( (9}gF?* ZYJ?ֹo?_xVwP}E}Et.՚_z^{//A?S_)s`u5"~UէU[ 8GsI6-`Aq`H|}|b᣷V[p 9z90s.#ص6KOCVo{x'[6_&=cyxP\[,|̳G8H{Pfg"[ٷ3q+m.gO1|uu=ܷW2't[l Ǘ {YҿW׿x{E+lrTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEzo?Zm[DM`OEOLIn)wq 7|B[ nl#h#kNVGGh&纣w prZe&q⛻;[aqڅw |/vlP#h#kH6XZ*zjՃU?co֬UVVUn|pQ\''ZE+]\].DRR%Xܑ\unTo^汧̯s$G'Z,⹆żO@j73\Km)XW;+o~g%~_^^8_"OúZWu#״y ֍jq<ҬXЛyT@, "+~?خ?*@|M@_D1y250PAU֒5veX0=8''K\^T$&gG_ѭid[GAz.uG{hZ%ڸ0HikKx 6Jc:g `t=@K?WsؼCg"sӤ ,k՗a{MA=+l̪ %uzZ+Q]Jk! w45Ԗ(m[Guvr`q:zob9;<1y-:K*FYpI:y_@c5 Ws%Wh y$c}zbz!?d3g6]c洉܃dry[5A>]n_IyǖZ bh(đP4SrU WƩ㥪1EuA,wqR#`3mpE/I&\ m_3~7c߻s__~?خ#Etz~C[5KMSS`$O2ܠ!qӏ? k9Gwe_υ2xl7qYԀ9Ԟc}:<~tZÖv\Z70SNlVf%I4p,X_%222;dSb*=KbCGo΀/T<~ty$C´cE|RywEal7SRbO8?o΀9o^O~։oI' %Ck׊i~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@PFUE,|=e|-~J7l NX8cm%?pBOk85ʎz)sTϚiVo`KaCCq石YJ!\c'z՘t}R7o"'pP WQ(I #qMKo"M뙧Z^bNB[no8Ṕ+:%ܤI3Fy?ZwvO|7o!Rdm!zrn_exGmSX+}Gk{ YItlDHReOj]Va)tG @kk{DR d([{GP d(x+~[t9.'I2-*džV(d[,V68 dp vexGmT-c·  $[k2 BNTFyRKUڻ)bH%ġFU'8*Z{'i{iėi$w,#?:g`/rK17 Wآ֊_Q72@J>Tp "8;wwZTw[KFC @IuK U4;{nnO,1U8Aqˋ2]HK;У;Gj(o Zx継Tf%6`s¬7\;Ab8#ֻ)}G߂my%Ϳ٢7Crޠú.Ϋ -.r[,Hz=A{+Ac<2>«\w+3g1!֔:XKٟk4[TOV’[ΒKnaKrŒ*/Nzzn(m|Vr+BXygg9] A| <1$srhWݞ̲7wco-3HMdgfXpAJ,2U++%+{ĐIF$mȭ #9[MԵ=7i,mg[bgP(9qQk~Rw0.u`iڎ$wmT>`OVok"E,/j82ƒ>nߗZDځˉF)}N_oKmn5 i7zmSzr펵]>i6W_cJK,5vcPUW/lkPG Gj |)>Ɨtl}C)~dfsy7W9][CskH+FF1[>+4/3L#*oޯ8P+Z= L;UXmeġÌ$z5fQ!,:FGr)_9YIn!{o/liiP[3c8qT[SӴdSk7h9}۷##z[@ӝ. F5y`0cz#5 m_8Wd[ߠt2ukSJj7iQĻ"I~U9P^kGWVɧYLK}t}76$?.}i[HFA4R`F WMNBH;I :G Q@Vw|'t˿s媳,>Vm#o-+r2%Xp #-IA;,']Km:T(2`OTzAkk[=L*hw>q+ѵ}P\^hmgDTdH5GX0 ËqjT:/_׭6-OX,c1[v):橽[_ Kk[93k`K}>}DPE!F1Je.JkY)sZ謼1iqZ:Ia3nTUbJqZmei8[k_{G`:4XofVur߈.^豕8Ѓ ? _Iy%wr5//{Z,`ge2$ZҷixVXI&[ h'>?AӴˆO9g,+p (@wUolZȑKڬN"Lࠓ׾qT|G> ] vW #邐vq]s:w 4; 1)n]:K.mVA.8d19$sGo{&҉.VY̛SEB뎂{RKVY,nivw`p;3eHٮ$2# p햟iY  s$I>9M'^V(&MW1ccs^l5xFX3D* w95e#NHFXuڥ*K麥%lWϐ#r7 m;s5k6;RGq,*r]b|5ΓneE̎yG@XnsGaw2FwHرepvɑL5.#D aG⟯OO+guQV ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB$#V,K35O8[J%a hcFF.17s2O 0:9N.-?J=zE=@Y=h=j7֑JVHJ2:1zޫeofuD4i{C1\AqI,>R:b rrE$kf&tFBP?AIKEÔu IP_bƬ *iivDmu9tw7WےM"mI!=@*:=7 :ŖYHs)-K[ScE0*㓁MuJZ%tk]7-?=TOmjZvPOg9Xa\ 90{WO;f[?[~a>i%QEgY7G)*M 5ⷷ3 m-R22PQ1N>Z՞k[,vY&<=;{{[n-[fP O#i/j:RZM]%ҳ;T#9Wzd#05!!e,7vkOwki-,n&u ۔҉7ir$#+n\%dw~bgdZ·_PXM3\:lf9]FIXmYj[;{iewxy۟;,;E$ _WNgy5B{`[OJ}>;;PZŤmNY$jSz/wF-[zEA?3ZF.!XY*>W% 'W=ZU'+v:WN6>gs=s=>dW??&[ϕ<c~Oc~OD'֏|_Ihrlnɍp1 OZҺ0 Dž'.sIY>'MC4Q#rSںJ-dpM$fW) MlTJH۸drFך5]`QֺADxH]rgZ5 Ţ;ˈOfl`w9=)UO[h6%o.-> VF,p͓qXvw-sإ,,>F sBե\5;{mJMus@ RX[6qڹx$V*W88@=Z`6f)tOSxr9u+ ڄSu wo<7 H:_= ]@o >#3LG SƶMwu 2hS0n2z֟&yuL{+ LM#Sxucu+M*^D.v$Ok6) NI$KCua2nW ,zex[Av%+$;It*4N,nQhe3I"''GZ_^uy$-T L'XnYc_9L9>橩$Պ"iWW Ar2?SpQ^mejlڸ4{o^ 28{q=Η^j3O\ܸʯ"`OJoMmt3:Ѣ׮-W84&YuFlJr|!tt/8) zStco!q JרsS'#3H#1=5թkY|J.~@: ig@- Q3psi-m?oK Wv"KϬZiih;Fg-=F*=Ƥeo# Еޕh {MxNSK͸]*3 ]+_#IT5jm'RU? u?硼Dvb_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%Y0DgYheU*o3EIXw^!Hc>[B\pqzwEu-!nWOǩVrrs=dc)׺NX8@qw=c)?1w=c)?F.'F.'Z4IQIUJ =۳s:џռ#??|њ@f[r$`b1${Umo;Ͷxn0$3DH)>&Am $`*Y࿶v"{\gSA4Epȧ`sN0Y( ?(QϧV oizzt;RH`Eg=#FZvqqbm-/Afl1,Vyh$-;E+1Xy #SYXdF+ [[X`\ |^Q-Ǚ1n1WoiּMݯ֒k 6'I-%K HKhk6a%?xP0? +ߗx=1TYiZF#aach0)a@'CC6_m%];KKyW2Iĥ]V U/4kvNN-Y0 `9Q@lt is*zjՃU?co֬UVVUnBS)*R/ JG$"EY1;~=r0:yN.m?f<:DO3­D ^[7l\fkkL7vE~T3T{-JimHh7$sftB+QQKY qiIezc%1 X{+(nڌc ANI$[]ֆ%>{K{6ȄÒϽQ+ŧ32H납擑Ԝgi[j68ǖlԿzoؾiL<ٟ] 9q{$ֺzt[k.dl#H|Sn jZծc-lGV3Fܼ"{UkXq#(1ޭ۵𳘔63M?/s4KlR T珘Ό_[-ʉncʃ[7O$tVrBEX(bUO| 4Mt߼@zY,Vmxilgw/Nk-v?-궫ǪOiqYK*0sHHhnL{+01"29rp`;Uo^]0yP@u +yPIrhDlowlmApR6i#HsZ=۹7bc~_z[1|COjzat >Φ4bB1;G#$ ֹԵxtőԮRƫg,~`:_jlW7ʠ;Ā1t&ⱋSиx."YbC9|\``x^:,[dr!w֭]k:j";#Mϰ9 4gs|n% Zy q fyyn.T%vY A;]yמTXlww<Cj,iy',X 08s[7 |{VQC0>;zdLVC#`9N~_V"Եm Iu;\p7(R;xvtχvҩaol2|p*Nm[h|<.< *y ME]$+Kj#1)e9qZW1ukk?9t$HEp ẁ;T5JC4A U!$Gu I A5<)[y5-FH*] 8Ii׶Mu3\brb[VY՞SdV~F.7n!H /rAYk,QƂM6;;ČqKw{keEƱ,R e2/|;ms4Assc,0 1t`}*z]/&VtP}-]^'l嶕\0Nfo淕W;^[wmVC#`l5rk0Ed&f}s+裰_e(_#=E3FvI_Lu5noHT٦(ҹ#cI[7֑\YYc6`ߚϿW˧{wnl4%9;vR3nW9uX4QI%> nX$1rGZ~Iy| @Wh N:;wpKdmnFͤp?]44?8.<6wcU]QE!Q@Q@Q@r)YR/V]/+K圭o:2{څaў}}lj>o gۏ>x={u[FS%;o"O"O:{+m'7-C98@I@sR^?.c]>WɒхGʖv r9Q$($(Z4ŷce{Zl# >c#cjԑnhnw,2zc~DEDE @-(1]v~DEDEjHk`ۼ#|[>"'gbaIQIQ_m&+iź@B$ OJkte]-',V"sWwyw_JP$h_P3e~\)HT_bmGO(%b0`eu Cg#8W$($*ܕ_N)ۅѬ໊hc{C#QiKw$ |$ɮȓȓ}8 06yf~lbGn$xs{yڽȓȓ3CfY{q*]-o Q^̷ BRLX3^IU;u3ykMYssۚu@{qGI "In2c2v0g5xP~chGOfT|аux'j/"O"O/l,}oY+k4fP$4!"TMb1p;;e =g(OO`SXDPO-QEQEQEQEQEQEQEPNOJ*)@i`FVR}{}>o=\:Q(Us4f){}>o=\ jb[xW3Fhڭ_أV/Uњ(Us4f++d`zr)Y5X>a>ds<}ɩo-B/5G͗4VVݦQ!.sP]j t{33\F~=zy\UΏu&u4_,ǃ dvxխsM|Xy+NM].mv]^V/  2 4=?륁kju#$t9$x+3UEfk<2X lIu{ 0y[v {?$Rf*i݂F|z_ Ti6Vvl[C 6q۴- G<߅qu]ʶ:3@0#85d]F-[GN, ٦Y+1as ;- yfPerzUSiK`/Χf,3Oqcy{i[%M:[ƲI2 qұCe=zȟZ{yf!#Am铎ON5]9 _ڵ7e1qT4]~-kR!x&x98rn<8+>$D+`u3]*kz hZjHo50P(9慭ޗu+ 5QmU3ʨ j;kJ5ANXzk>u `G2؈ln%t8u k[c{yݎԺ__?3t>$$VLdU;=JH6 C9#WiCL{ۘ[IKT j=1ed+;bMg2Tk/$V+QE!Q@Q@Q@Q@Q@gm'RU? ?W࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%]VEI\֯8@4>cnCbwQLSO%S$OeioOg9֍֪4o4kxiU $ [ 2QCiz fӯ㕣k"|*Sg͌xzU]Bxn[F Zܳaw͵<-~t9!c@4_;qvF-KIR֋ l 67dm֍'V<R707  ( P{6m^Iogk 0[{_{G`:l" Vry.z_ZSFyi]xYhբٖ]& ,r48 C1fQ3{SHBjݝ#E Y3 sHIkb Y5kKp$9d_zh"NO&̸{iIP7PwH>)$Auiw-2H9Oܜd.yӢz}YCy40#a8%@`p}Y ;q(_07cH`g5zö$"y3 )g1_-L{2 >+5 tpYwn'ezcZ]FOZ¶40rq:ömm} a噰x?D~P{[t_:Kh|~䂤K[d?xi %ۼ&۱&̫<76\):9`\oöcshd˸[!T5|;W[Gv]P0]~\߮3څ X<"??gy^v88IQqoy6(]`u')QH((jrqqg]zƱ]Iiߛ$BvUT=zT"v1-WR\,Qp2`Zo$Bf)a} 6~M?Bċ,s"BTAW:H tjm,q#cn2[Y4ڼp+R+FXyֶK˖)$ sQ]xvKL1< #p7E ;5~E~ɨ']J[j.'rB/Mf_KkQ%wf0#(m@6 z].;kk/+)ܻdr~ zvZۤ[F;$$gn?7Z7ZѼFUw7zѼz],=s3\یDYju.v3VPR$G$'V;Ѹxj>Ҟ\%!MNF~F(z)|m؜_\Ukۨǝ?Ə0:?Qju?W2 Dx7\ʰi'YmŔңGMqp\g9)}=VK-D\#ӵRź#%,NB}|@/SѨJz5s%gӼ=5Z0 hmr [SVofbT}tn0ē_@SѨJz5rm,"i  ׂIWqfOiqKM,lcҖ N`(3PCj>ҞU+_&+0%pgw>٠)}=5:-.xr}n/>mrKUn[k#vFp.0rOhJz5iOF+M{N!YJ,FJGBGP\xNɎ,\#[;X$2W}=W8b}qOT"~\X5]?jUniUVH%?pB+ O\"Ф=(ۑc$~5{?]\)}~->{?]])}~->{?]])}~->{?]])}~-_"~-EU_=fd(Dڠr{uTQ@Q@Q@Q@Q@ב#۽wJuQEQEQEz(Qѷ#HjZ({?]'P/ůGP/ůGP/ůGP/ůGP/ůGP"WX:R$:ˇrF:"66մ=yk*+'bݞH~G(EA%sȈ5 .qiS~s_tSNXRE*HGs޻Q_Jct[:6aUm =OLUҮ&\Ix9*$6Ⴇt_Q_Jm 4IgK% h@#k8KrO_ƥ-k*Sh|ucJ9<yq_J>KưԞQmLR?46DP1c#285-V\a% zҠHI۝ČqץңM8c{}=IR}h[-u<Z6]_E^$Gc4Ia8ns oZ:6xZG(ZxJ/ҕMEl\E"cϡȋ—[$*lm'LPiXucuD/eom} KbŴ 8as*@O<f룭Ra{il$ZP0=q^_J>TJ8XaHaQBNp>ҏRЭEY/eo UQ_JEY/eo UQ_JEY/eo UQ_J㵟 7d7Սz?/p ;%W?\7莼WO+gsQWA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U_Z~Y4BS)+?@O,ԡGnRNAQZ0N%-".a,MnPLjuE }5*/E;w w {]rI'WxfGi^8u5ׇ,?<'oh]8{s[kl>4GP:֗W(RtYU*xU.F570G?\jݬmo.em(@PY|w>T~\ܐ}Me剃>._O24F]n'[[c/x`mOjl" 9.x'Qdlt[qr;&Mf̦.0?\Sm8Yfږ54)dVNRikoʃW,vvf9<0msohzj#y,E[wgr){[cjo'(i::|vQuv"WU6ɻ;zU;kwJR–3I,,1f ;w>²_WmP֗lFĴ4+UB60g޵ +H5}EbEeI$8tť کbfE1.{v9f[U XY-V 3}0WYہ},O2c!B5ݡ@3̿UmԵaw>ߠy57*iv&8\HH߷ 1-y`nm[fz~I<[Vhמ9WFCnHT5-(VW7a#)VR0s֖Z=v3Sծveqʑ0%K֥uk-Kxohi#WV%wg3ڮhQVVKIQhTmۚһ͝ܗRc{D A^=|4֛[ׯZN.^7RO$۩4At8:\"Xo_ Y9ܛr\ VS@:-vMSPU3Gv0_`fMy̶=JTn8ݽjv5=:[]E-$!YQU$9=/vQ|#`(V9EdK>k O;u\\4?1u*Zƪڍ,/M/lJf9#+?GPG~HH 6G=;>pﱁ0U:)ֺMYndipqG]ڙ͆[j7֍E6/NxoB7mZC!#qo*8/i&Fѝ `d_IN6q}w2̥v($*z)=\|?1?"MZ+`-፩SAw&sPϨ.,]uE.VC5#(8䏼za{YS"Kd(r1~CT–o3Zh{1 nM8=ח Oݢ)QEU-nL q,>}p.%}G5v\ޅA2ycaԨmZ0G&@9Hޛ?nuٮfR7CI{ jk}E=.Zwyi8lҦ-{x5jlfD{wnیfCkWiwewn(m0H#:{?Ζv Xl[حŗh, ݹ]cGMu;JeHioa0:]q}o-}6-Jŝ,큷9ImbaLܴP2n@!Rm2 k7q(T8QOsl^hZ%3@mG=~_6jMV}[V_$.r+O+.#(L(L(yp#rxv\2 -^i!u d;TH04=cMY7.fHeeR{5\$0f!e;\J=[T\F0'A~DK]>,ǝBf@8]ڋl.LncfiBH|A&oD-,YL(\⋻+IaEŮ2++]{zDf{c>"cpp8K-iE^oR{[5TrRI]?qQM8")RG48񎤓F1G_o_hK-`i麍$TtqCU]֟stqk5Ŀiav(K-iEwOng;qs[":G-`se厳b+[KKN8"-N/}%KMOMK"[,ͳO}`3IG, /3FH9n>mY]$ocK-iE?Q5%'hJC:H_29)ώmBcY3#8ː>cK-iEjr_kiQl/$;$*rǴ^zwkkO99%ն-=K-iE^ėq\^GiMۋI]P9D$ }#MK-n{+cr~/},O]JKv?w*[;J<+힋̦عf۹1'`;﴿Zd}4}&s~p m\d+խ侊]?2!=[GA 8ֺy+T#"-}4PiE/ 7_hK-CE3PNR M?]5x\&Uo((]5":+f_t_@՗",k\SA=QEQEU?N.O@jӠ((((((((((((((((((((($O,zg%̒鞜u溹>w4uL:X'56M&s<֞H,Im̢Lo,mÜ.r>`0zyw4yw4Oaiz=[ |y $I5a+tEŅt0%KJm ]o  E?6i73AbKneg' WWE^PXn- ŊknxcҺo"?"?8#w m a8 O Isa%֣߼M-jAUTȏ2[ڥlurAMޫ?vmvyJҲLKc8+SȏȏhDMDMRw4-c"o`Z*SGS@wq\W3ῼ?κN$].򛿵rtA˯f_t_^uמ>bb,-G1OTϵWo vFMQShVe9 Q}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUMECXq2T}?LUME:% PXݘ5i)4ME.N$f0r=U~謭zQtx ?f[E 6q'#=ת3.:Zk1[xwꏱ6vsiԚ]NJnmj1 =Z:{\ޭ VP L1H@'My{+?2[4Y~S6㎃9 m#S[5ahEwjŗX+ް~ 3Wن vrUbMj]T4|nTj`q,{[?a^,W4ZS v6\{Q05/5 F1k^r]J Wmo+iICYLaSwsV:*i#/>֤n ).=j>n.PQ[J. q [|y_U ߀&tUl Fvxϯjx\$O6BF 6>=CEtc>mpHB@U{ YݦK8*Ox\.F]--fKw0"*3 vybɹޤPH+Ls] /'{/nLyzgajK鰜riu?[}|tGnvِ~n$`cGqEΞu ]~۸n ?ڭ˿ X^TLӑ~n Si+n<'d%;TtN]Gk^x~ZN)Z6 <5ƝrNn"YmF2ObVxvt1-dIC9tSX[׉,MuB(A\>CA˯f_t_^uמ>boO)Š(((((((((((((((((((((((( -@c\,~cMzڬxH$l6V[.oΣKĒi!ZX"JdddvȮ*ZߢAgvЋ%J#!n=F:qNkF<$R+(98jo?Ygl紛B7M^[GqT[cM֟Mywqo yRq~W/3?_Oe:silWۜz85`^ǩma@`B')'n;T [[xn.(2>2p9>'oι}oSo&I4pI8]̙`AYާG?n,CzTqpySsn$nn ]Goιu['Q7M<^W@t#"TTBxӍ"rA#iקoΏ1ߝp:<:m:{DEtU )Q|ɧ,nq`%NO懧BNקǘoΑf-k7ܥwWΆTXT:f=Y.;{eSa`Ivhz_Zu?\ci^jK_%SeMBW9=9:vŧƦn[y-^P(T3N/;SG~f=o1ߝq^#Ԇ ^i. ,m=;]45).KtHL@|xx_ח^gjee&@Rek.u8ߣܤR(3Q_Y].Uw8ۅp@е?os?.[jY5䮐lnfp0q㡤TյkP}=[I[ >\p'LRo _woΏ1ߝq%VyZ# «|FHsR֡jWL7]YUf߰yzo@ZuS%&[! OiA@# rz֟ifL6HB8;O sC:1ߝG-@c\,~cMzڱK wlE& m 8'5ګMeOdcyl,g+#@֝Q_KoΏ1ߝpji{Lگ~aM?6sԗZ-֯C-aBD2Y-x#%6d^׾D`̉G#ß}?ΫikwD#wj*χ>$Ojߏw0}E}E1 Vk|E1EuW_y/΀:֒AC4?fs9#j^*e?X<,$ p?!/[y=a*M?t"3>ZC^*e?+7<+K}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_ufI{nsцG{Z+7-c>RSTZwR&̻QUHa$|7qӾ5Y}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC\Q\fp ánn}Mh?ޛNgncZUJ|mQ :1Ԓx*I|3UwwDOWvtb>5թ_vu/0DŽvPMqPrwg'zd^ ^XwIDAf=I;5(7PzoGթ_kw_r#E!"O9[w ֬YnmJ᯷ 2M7?)>4}MiƄ"ɞ*&kdw1m@J w@epP?30ߎ=1S}Mh?ޛ9M4 #ogI sk? iz{J$^I3K$gpxb>4c;b+؝D1ۼ?gòvp19lTXXlMOeUCbb;BҌ6W##펙f$zf4ص ͟4 c0ILV~4}MhOO𾕥gQYbuC{ 'Mђ7Pn+3ʡbpq[?b>4+ Դk=^`Fċ AR<6#Cm9&e2ݙ$V~4}Mi c3NIz#:KqNCFM=Evep<_T+CPzoGءƁ7Daќ9OA|Zƻ}$~9ی;PzoGءƁC[ʇo#1|v)מ}ޏe}siss 5 czӾ4}MiV*3 [aj+ɼ3 srtӥRh]t6:nP@l{V>4}Mi ?YۤO6wןzGxcKէv3G3Y?drx5oPzoGءƀ>kqu @^e gK(cp.TqbrMZ?ޛ(7}n+t ok5Ag2.vsJi}] y j}+nn*ksPzoGءƕI{++{! $~Iʑp 3X^uԭ!` +0[ß}?΁pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5ޟdg+9m4lb6횣i` ̷w$I,_23`qJ_[+m@t#h$q> f״~,1`s횱{k[s,Q('>IϫXj{o Wlm 4çnuΕ+( #$D v.}K˯e=ߞ  W=>R2*}aN[r4m\05i5]#[X8JM9%nzqRi*RmY~$W0Pxڲi&tȷtI^ lmnij~yݜ/J)u+"lEŭ18]0=M;kygc}}h7,V%*I~U^on:: dMkzke cbGX*fgkEynaҹ}ݜto21@ j汧]xhC\AѢ"-ȣocmf;JkK{KH\%U+'$bO>.֚ MڒezNV,4:c7I 6?K[y;Z+tۼxs{yUc#linssO(4Ozvz%a4OKr2&Y}ʽ=+y)db#1=QIju!̊W]=S"Y>W/6$Zyc.KFu?( [5lgIǠH {a.Y'@}.oY\d| ' MumijEEOq?*v/밯Q4uFDwcM?Wc{D@3*VoSPΟ:btUI#@?dލ@IF:C T(?ь E%~ y_3kP& <HB3\"Eg;xmwiϥȰ3g8548/g aHIPwH9$rh~l?ku7cX@ Y3[_eC20p@ poS;PgӠ mq <vO.=ux,k; jmJΓOA(\ ²N3Nn&jvNn0ۀ@pɡ+:nHȎ59,z\>amem[Dz]ۉf|~U[u;Kehxi9 0ЊK[[Rԣw`xf#iK6YjwDhr.W ޱd흈Is "m6s?0=mfͮCVvlYuhBvr0O^Š€͌dHFPO.1  ˸G?\o\#-)5c6j t!ͮ!gvnPt_KD1[^1ZE p㜃s֍ ; ]@\Rb[-s}_gyEq#tJ8yD5+ #g[K/[rO(Ɍ#YblgN34;}+ŷV1,gCpH_CfU-&Ta_aW厙/tnۿ1"U#r7qjeek8ڻrۻ[֏۱ H<~CoKuu{?AgwWv^ :1R5=""ƊUFyQ@Š((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@M<ȝnn^{כ?o(7Pmei|/fXh.b *=xp=ͳD3[3c÷rp#;7Q X=oL2M^pG??hך?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckUu\\ܼj6P[Wۣ'#6@{G,mc€=6IF cs{?!RW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7Pou\\ܼj6P[Wۣ'DL0d X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*eѮe]{S3<38ck?o(TmP  c'57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€=*_X𱵏 +ckXc{qm(kꭟu[LƠ:x>࢝Š)2*՘Ѥ 4$Tj2~j<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*?_J<7?*Q_J<nCHŠٶVڜE-nip2-8.7.1/doc/src/figs/snap8.jpg0000644000175000017500000007221013351443023013337 00000000000000JFIFExifII*JR(iZ)( )( 02100100/C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222/" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?qQ{LT|kGUQ%̭%nԟaEvozB::XLG5&Z?&F? ?c1'/r߸.1xQ| A9Mp>я+Lu ~h^?&7h_<cN_G&:q4\cF? {r߸?1׿%/} 1xW?Q A)Eo(я¾y^E} 1xW_k-{R\cF? -wReJ_?"/h_=eJ_?"L K|GQp>я+L K|GQ A).п1xQ| A)?2%7EF? ?c𯞿2%7G&Z#(BhG&Z#(]E_(я¾z\Ek} 1xW_k-s3\cF? -s3eFo/"'h_=eFo/"L|EQp>я+L|Q A.П1xQ| A?2?#7EF? ?c2?#7G&Zgb(BhG&Zgb([_EO(я¾{[_Ek} 1xWk-o31\?cF? -o31eF/"'h_=eF/"L|Qp>я+L|Q A.П1xQ| A?2?#7EF? ?c2?#7G&Zfb(BhG&Zf"(\_EO(я¾{\_Ek} 1xW_k-s3\cF? -sSeJo?"/h_=eJo?"L M|GQp>я+L M|GQ A).п1xQ| A)?2%7EF? ?c𯞿2%7G&Z#(BhG&Z#(]E_(я¾z]Ek} 1xW_k-{R\cF? {RcJ_?"7h_<cJ_G&:q\cF? {R߸?1׿'/} 1xW? A9Mo(я¾y^?&=w4\cF? =w4gRO?&?h_<gROG&z}5 .x_I~kKKY]#]L.ά@E \5>4N;hG"Sȭ9&xĻ-:}+~ L-`rQnu!W/ey;^UQQ N(犱4餸<|/(#`,W!ı#Dr9vεMjLӵyȌ)s4><-6>զK39KEԧTr!B }*F\3=vI{7gɫ_Ӵu[KǟJkfP݇N@D^(ӵ [Mz5齌ٲV<;wEO'tj!9YHUO&m?Lt.&b\ ,{*)ck}sI N$H, FS>wu׶/`) DޓGO#VƭMÖZѼ_oe9f )^2? jtTFy.1FlpGqkLumI&,6@Lz{⠲մ=7 {c6oo2y>n cicA+ E~MFx8{-+I]JGEf7fl$DmU9\KM_Zиa r>կqG_UT1Kb6mn dr6ĶwQ-[YN6΍6:=KY?W.gkzqj };\2|0;֯ԵU;EW` i_ |3}kv; A?@Ls֝WQ줺K9 :O4 z$R]VIivFPvC0O𫺗4ciyΩ*r, O$Ċ>mlev2C[D3ğd^MoŤsIo4fn3ۯr5ֿf{_'WYҵ]$=R-O!OSYzw|&T}j\jr{w0\gi4=i9Dhێ1@5=2KkqnҬD gL ֡q6mn[TF  2wq᚞O \_[Og{r}o1A ۵^O΁5Ң32 t8EgX hᕮ-53{`#/P3fxbSOk}m,.t !Uʷk ۧuhYmς 1㿭H#ЭgmZé`$1#?3)fLIu&Qiװ-գM7瞾:2ƫ ej>{a9%>Fw_fd;|䳛_3`ք1/ci}e,6Ig-B1$w:z+[.v\|=ii o,(895x@.-ضtgR.>},Mxo#ٓx;psi$..ӼU}iiAe3X5h0F1R&7 (Y{#{+Зu-n.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@Z]_]1",oAk-1͌!}B>iעgp'Ў֟dAnr"~4ϟN17ʹ {[qCqia$#׵aI|_QK|ԎshEtIHgkhxzPMV2A0ϖ;3t:~V5O<yWr!=7w:6ۖ1{񭸯aԡTkqUq%([nS9J]/}֞t"ֹտ_mc%J3L3d9?NyouVR 8STs< tNdHPWxUiPV+L[K}+!_Z[K}+!eu\uY)B<U^uIR6<5.p4Q@eWhrKkS?uGPZ{-[G0E]͹pTgf `z*af7RV%}ckny9i-fuY]6{.KF.=~ }@uާg"`$>0?ա%CwCafG'Xk:uztsј`crwuڧѥ+9˂q|9}(;uhlo.ak{Kd̩ `~4kr YHQeן r8<847RXVnHW*BF~@ եeI{^Zsr 63n޵ޑ{g{BeU *8?@RF˛Y`٦Hv .3j7\K;|g&!Fw)dlWvq=#zO+mwυw f+u%ZO3!1!ぁy[uio{4W1_rhcw0ٙl,0t⇠[Vbu  m;HcX UZ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(wQ]nu(FJ(ۨ )P/)Pf^~TtPIE{W+ԭՊ߇ bJXox7?:Wk^w9cI.;(`qQG`]\7 N&$Ip,FI ܤ (’/i?O7G)/du-_cZ}ͳ[wiϣ-fI R2X"i`;$O\fR^%'%_nu0NO<ֺVo oQpsg/{%_nR^%'%FM/ZUKEe]\)SkWLwP9+V)/dt’/i?O7JC9_*j0mry:"R^%'%_n8·XJmw8T's`5x#=r[[=>g$"?Ix'IwjQǢOd4ub4wxbŃU *='\mY^/X3od@ "Ix'I}@LkX\ŭ6%CXȨzW)/dt’/i?O7I+g/an;8[)K񑸌[j`Ҿm<.]"20\ewqҴ?Ix'I`Z^w3!領]:Kޙ,S+;s׿/ltkf'I#1#Y P3%_nR^%'0W.$ub-9+|?gxJ..vp&q?ƺ>)IĈr~F2 XMKZ! FU \i3kBCmZgXDq\" WW KĿ?K?ObL3]1^(Z+V%tjcDմ[l3,8Rfv ǧsZ_K?O KĿ? \i̴-3÷ ٥YB y*?kԥT6A$Ѯ1$?*i~kh-t0|w|yIx'y?|Ekk5e"Fv , UkeWzjpx$sڕzy_K?O KĿ?Q'^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?O^ KĿ?K?OAA6 +ob2 [Wh\%K) =IV)տԷҼYu#n+_-[i;-ӂ^op4t$,XDp,8z-36-< aqH4oYDY)'Y (RMh-tXrBXYl$kKr"GZ,.SFkMkaq/89'iS<)~UJ1 8v"77^o;9,o#hKH5[r[ ꓫ~ +vCJ4D* 1$ԞC˦n],@[;0'lq[Uh7VkuqkumG4r۵ G0[57H  ;O95JUѮ|Wwu=H"ʪ22{[xB9s^ո2,s+!ԙy&u@ Wj`Ÿן?JnWSkWii푑HXs޺qֱcKI{ww$kLm#U@[%nտdr:kxZT&4ep0bR߆暾8 Sv5Hv{f\u܁ƷDHu;{ۨ}xRHti7S]K!sw'>dwhO=-Zz.7Yϝ!M쩆iש閷ѩTeU=@`?Z|-k] _#KiVu RGR+fcP$QDQ01v9˩[m>-ss 0u`qVZ1:P[[[}4QZ]2 cM上P2ѶH  .6^_ܵ\ya)j>~'GSVӮoU'&:nRPx#w>7mJɶY$B6Č3޵j7Vw\_l"l%6 M?+aiwkqot% rO|sғ Z:W5WѿŪZ4LK1UmMMݬIGb ݂H_Az"-!IubtZA#RN98+7gYӢPӬoZV&W ?gzsi'^_?"IJX5Α·VnR%%@rHWWXP/u_leYt)dحEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPԿ[Կ[or]L},d:o->MZCu J8+u@giq X^M,&X[dVq?P).4=:kim!iづr 1@Ǯ\=],ڄvM.}6;GUcn*xx[O,`:_`ûI~tϳy1w2*ŗ$[6=_JfoS3]-6$_ԵHuy孄ݖhԆ$4o5hRk_,v[D\9cc(ZmWv ( ( ( ( ( ( ( ( ( ( ()ki?Xvlki?XvsG/ɓ77jv.vm%K$"t#j]}>}mjvo*|< g޹3iutڕkhaIFH Fy銽w`gvAa0YJeQ˦93U?jϬv֑]ϩYm7Uu+;EٱieUCbq\a<>+#}>. o n@`G v梋MM1;rƛj.$扜XƋaxt@t&SGCu%}œnBYc&i8eԓ\-K e-I$PBWGM-{(c87@=n_[Ԭ58K kSh%Y>VC9f}=Svb3Nڻj&{n/Cy&O=Z@q^gVǣ^[ê'ՑV1#+9+(pz;jP'q#gu֘HxAʺm:i`So?84-%ͽ =A rJU~Y]]SIJ]mB 8eVT|Um+K;;%&BAj.[úYZMO4v+`GjNe]B95Aͽ$zjvm%)4} B;->E uf6*$c *mp|[{;NM0![`u@Dq}*4ȍSg]k[j6Guv_"/͂j6x3uL-e-bJٗ̾ͼFߞszb\XkZ_IfRqP@q.` P3kVL6Q[ڭǑhE"11#Ft븨lr((((((((((((((((((((((((}ՊlaOmmP~jwZzQ_:.m|fӭy4 PvONz~4mR=kGbF'M^Jm;Afݹ'ִi_@AER((((((( KA5mVƱ KA5mW;::Er/mdg{XJnj8a0H)twbLD~p#=hZQ^sH#SI]ž SNBk' q{sr'-nϔ$b@p8qBUyigd!\xoI[mRt"0T6+O1ߕ {]Ewk{Ė̛S`²Rz{еv=&+io-aMհѹ&U ?)Nz@MV<4)9v)lZ+y9)=>båKC[[iA=uK~`ή|;$k֛VVKFehݔMz)e<+4)5uHnea,R -$ $3'ҏ k{uk{eHc9vF jh(((((((((( KA5mVƱ KA5mW;::k w%uUXHp~Sj/ˣ )ibi$ YFH#qK] kl\tL.}<+&ߦG:m\+(NY*E,V6фs"F#  @\" aS@Q@PCn.^}.Y߇љEAR@Csgm{ ,:5^O,`$pFs1PM%brI,O&Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@:}ImՊaOkmP~D% º-[K}+fUKJUw~r)^9P+xbɭe2l_ܹzK X>p|H̎N8#ۢ.<+:^$kZ{ІA$S`T'·7Z^+t[ˈqnCj#&pY0%zl-RU 3ס:Xi S݌BTM?\օPEPEPEPEPEPEPEPEPEPEP-c@'k.6c@'k.6wu4uW%2ӯfbsxmU$fwK0*n0 ԾX4ْX67׎\T PkVcŠ((((((((((((((((((((((((((((((((( FGЍvqV0?'kV(?VRJ..,bYH.qqFտԷҹ}\?a@WJT_Gq}ɪ?k&OI!HWM]Z=ŽE <֎]sXtжK0J/Z//g習;b1o Yg >qu]ťͺ473*K9$`U 躅ܗWed"W,1AM=UVmq/cnܞˠij˪4 /PdIc{Kmem"ͷ]7#9?xZKSF((((((((((( Z/O??]m[/O??]m\h_KgKEWAQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEpV0?'kV+Q?#]@W3km|A}-ĩb]FKO ~5j[^{>uAYY'Dd cxZ.`Is41QdRISolqҚ_3"i)倁*oGr)ld8W+[?u)ܲ+ 7 k5-E owr|8^8-m\oآnIHM;_9A&tx]%uQEQEQEQEQEQEQEQEQEQEKX%{I? cX%{I? z?k~Lh9((((((((((((((((((((((((((((((((( FCЍvqV0'kV(?VRJ#-pمt:W'j6NL$*#"=ȠD巂v9 O223yX%D7с =Aj;m:K1C(@\CиG"VU.tM&nn)e:`xHnM3"'}T8hkZEML $`(Yt>;٬mxT}_/ /t]sq]16J6/'htbR%ѣYHYZRvMwW=o(k¾2CJ,v迩=ɨ&t$&r]"RV0*ض@Z:Rh ^9!`v+FeHG&7.{3-sub^uK/Hce&v۲d~];Sխ;s}5f-ח3!N_57ÖMK4JGBOsUFGDRU$< 6hL˱u͒^G.k*C.$QF9뎵ui6]IfTWpkRAC{Bܽ$!B'olqTa J=Z sN&>\prٝp/M<^cmj֕my_hþu_4ry+kTm/֗ 6%Op4qA]%uu}&QmFkhițGd} ?$ JZC ( ( ( ( ( ( ( ( ( ( 7֫UVo@(((((((((((((((((((((((((((((((((b?OimWk#_2FKob3o-{2WCoqfs^j֖_m m3ae 388J? xW  NF@XP /nO.L-1rI"`0N?Pc6:-L!U՟ ˻k DGr . OV۟x֣ykyF'6d"Xb:柨Zկu k/8&oyBTS2,!zunZ?_Bvg;yZ}pfnVIJYS*9muGWѤL&Upks}jom-qqm{Z~)qR2E9F"5  ,sRxBBX+s}j@v+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}sv+}svnZ {@^)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEŨFKob_imP~xx^CWor: ƻy\un2bWkR[} ZGp1}$w~uo /pY!k˒>f$r@= aKoZ\ijOg}c)<bI'))[YIhc{+)P^|/,MhDx22;? 1 -lKqot!GN:us:e|C. $-hʖ; ['rut_QuDM7R67T;@nuC67T;@nuC67T;@nuC67T;@nuC67T;@n1*ns?΀4袊b ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8;_imWk#_/-ՊտԷҹ ۭψoQ! o-?SﬥX!  WOos€;h`y0c. 3iQCW--ɸC";8'k cy9kBM6]~hR/mGг:6 Ԍמ*{ i~T tՕb.>n91BQ{Wԯ-K :FqG'v7QEQEQEQEQEQEQEQEQEQEVoVZ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEŨ:-Պb?vg[\?e0VRJ..,bYH.qq^[xL+ |%*/>E@Qmlln5<H̋Ky(ƴjXq,P11`dеv$JS=7-dVym'J5Cr=)-ZCxcI^TX=\:J{ {A Ə1o0>2x0z]A/mᓸw8}/mmo9XH]VSAAWk{jZ]ipI$PF+>F`T(w+PU3n `Tՙ)Z(Š(((((((UkP( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8Ko]\ez|X [K}+f[\υ!QUw.>}T55d|ϵ\omXH[ϻbqNOnn3дۑ~&YQrm6mC KZI䐮rs^\HP(<)9s'm\ľ^۶N7ʽB^_p~`A-lI,c4.qlPA b8.McoRK,xZuM~"m?s8qG`2[ZKjRΗLFht,XAo i wurmXIvEG6(nHֽy"-{Vʹ~T/wrb8MjFkd*'< uQEQEQEQEQEQEQEQEUYֵZjEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP m#_/볶V+Puoyu֭egy`'I VRJ#-pمkCA40] #uX}p=MfZ;S6LahUW~*3Om[ds}pu64Vٖ['u/+j[1*3?>U{/= ioc}wtZNkE:CyTON'Iu͐;2b\.m4 PB HA* .+8T:' GRӤ1{bPՐcXU{Y7&f<5n=SOb{,d_"^oX%mĖf=$Ud"yM帍$¾qr@\#մo=B;e2 u4r((((((((((UkP( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (8K]\ez|?X [K}+ћ_4ո98ۻnɑkտԷҹo(<5r㱉pfCIHIij7?&XzaĐZMa=̲G FV.9=p8Qh j-֟>!4gxX1,2ۚ.K3v|&9.ď®Q`8 7JԴ?>q-nK0AiAғF/V[ƀxa/G@I瞕SCo"PN~ͬRlFfG008]'l^IZ)$tgid$`z] z^QEQEQEQEQEQEQEQEQEQEVoVZ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE[Ǩ:ՊmTz|?X znԿ<1,[ˮpO.O=q\EHcShxíP1~e8/'ͷ¸ ;?Jr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;N<3Aoxg6ߙ ?_Qr?Ҁ;hfՏ6/-v89h<h֬ۻ<5wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ ?8m3wxg6ߙ /65l\G!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3m f?\!<J?_P dž3mS58[W/i`D(ZV}Z39&fS+AYuۍp(fhQEDlbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('EbO(IGؓ(tQ$袊>ğ}?('E9mPvc ڤnip2-8.7.1/doc/src/figs/snap12.jpg0000644000175000017500000012313513351443023013415 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq(merD1ޟ$L!uCN?QQxJ f&mjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5EfkjA?!4jA?!5LIcwtI29+yͯH?'?ƕ5(^E@e bE4S$D 285b>b|:.߬X[\rZ7(HUAǭoWj?#S98$:Lu|G&ZwWH?2ӿUi_*z(k#N7_TeH=-;x+Q b|:^ab$Ѝz}y!B5][df^\=Tv0=zmF4"4^­R*(UT ;V:XK \ܰ;m);?~AZ*vn;s qN.FV$kE$p0pɌ"P`QIfş3lrI9sO1Y#>asՑgn1?JU%>l: dU\JafVy'CQo^[jೀIn1(z'3qJ.t᧘`p:V2N$* EY62)0})Z'ce%T| ztEyodZBHC,H +0Q3ҭh\APw{X]QJp ]NI#ne\y8R}*dYO)nO tI K+s.+*ċtGw,Y7v8o4[x Q%p㷩 rEx' o0!y $Muc<+97,>$$ܸ򰪫Crx 8#Cq#/N d>dMETQEQEQEQEQEQEQEQEQEQEQEN0>FUu*2B(3eW p?o~YL11MH bKV-mbEŽI=I5暲4VF!%R趭 }]#BK\m[^S^=å ( +uמ>bЮ՚_tM<JZsߋ?Zv_)ʌ_싏"~g+j,.Tbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/ߋ?[TQ`F/EQq3ETbd\~/>-.xG/8'+^4X|7%C3g矖 y` I='-QR Կ罧Mj_o&-#ĖżJќ[ZMAƨ'dnDE!OBI=}zT(qj_o&B/i}]ѲX?ب|!q_j_o&]"a 毤JWpIv1ʻ<}#G"\|Ch2{RiW?^(qN'Ah[o$:}>?¥]7ގKyU4$3C{F~@* t@)Qv!%snO G#rOL)|_.~O?F@$_IZbQUpЂҕFƓ?j?4 V ?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&Ɠ?j?4 V {(?1OZ!A'ՃE!oa i?֣cI`G{(CO'X4Q&\f tGg׊Z? ?뜿-wt}k,:݉V5՝pQDpQ]'(˯f_t_^uמ>b}qOT"(((((((((((((4sBJ$ndqЊmڻURR2wLYk}:Wp**?7ڹZΠm,`Lsk>iژdڅզX<:!n?:UnK3.47V8feۻ8RS]B=Ba d9r,K.6ʹWg#$mnU[ݟNwbС$p+$(oA,_J&a(P@O\G&m]b9%QO'ں=aRD I @qX"Stvv֖ő%FSv93]}?kYuZLβRK$k mVf/(#aǭ.ZK By~U&$l< Ƶ%(۳7.*[B6,Nzz#di-r9'oi)ʂI$g%-Q\g@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE@9[V>!\m[\7莼WO?;>࢈>ࢺA_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARM#G#Hۜq2}NCs4mNs4mL C/J2s>+,Z+X 9Y'o?zSscĐ SJ7jYLйaYǥ\i^ z2<9 Yr zZ)RṌfwg VFGder#X\*C#+dpH#Aʖ2G\V[F7n=0Nj%w+̽N;覍kAyQ; BL**ǜ_zlǧZ ĀӠŊ((((((((((((((((((((KDr趭 }-Bڷ|1Gֹo?_xVwp}E}Et.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRL[?j3ž&)B=&-?HnrNje\³hE Ǧ;U}Vyʳʱ\ sVϷXKfPɀ1Fv1hmn GhݸN:? ۏ,bQ#SQGn9s[VZ1cQz܃=p*` ~zڇ#t*1P%M6EnQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEih_ջᎃY@63ïlV:cJ..W8C((q_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARi?S O2tE% +^[ kWvHHK򞿍z5s::{S3NGf3ƽG+;3WO0ُZ 8;7;Fs]ˤ\_bS!Ppڽ9֝6q-6ehc$pϯJXڗb_SOaے1nW>d.O2`v1QCbx(hEwmⴴ{6yчۜ#i0\PMÓK[6^"*K?յt9@?{|Pp{OPno=ͼ2T {4ZN(=#f?/^ϤtKLldO|#FsSOB[ܛn%h~B9?]{sO~Q akΫ%D 1eG'=17zTN-<6`qtMc*Qd}}'g(O~WO=Ǖc,Y ÎT+-w7^L@ 2T }G U*QS??G/º F[[4"IFټ̆$`u&E%6[ch# לv)}~7+sO~Q y:k{ՍR$Hn#,r2zw^Z$7!A\d}s1O볽/e\~{>߳}}'g+gK]n2Gq5-Յ^sr$`Q?'4Qo?b/^Ϥk%dR xZQ[Ã#9FŝP$M+MXP#mק:kw[1In&2Ŕ6Ntʑڶ*G}'g(O~V>%an./,0D.ʸ#M1 &+*PXz{C ??]=׺Qk)uQPEade+4%œ=H/eӯq(2~{>߳}}'g+y5{gէQ-N߳}}'g+ro5r-ݼ-y(%ʌ {u_-Gݺ [pNt\k={`I >{>߳,k ILpх-n?Z\.L"uo˜xP YhWW~{>߳}}'g+_EOkrNTdx<+. ki>а*tG([;F1ZសvѨAIZI$;>࢈>ࢵ$e^{//BVk|E1EtY>*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:YfEfnTR9c$m9MsJkFX于7|z}+U]s0 :sMX7jQސ?jɧ<FkFi4Z臚0v;PpwdW_#yx ^+$%RxYIU+)ITk3}\5@ "1#99\j fե'ͺ6V ӌm>p;yZ)G1dɌc>R좲iYˡöHTqtcd8bD$RQ9^}y ׃x"ۻ#~Lt壸{Y#GMf ԩ{.Sz3*ͩM#(AVܡp kǵ ;9G F?QC5̶-d9cn{'BhԮ#È&{ dƢPg^:K*᠑5 J$ݴ H#۵Cxt̓D+FʜB;@kK7%kVK'|P*VLM+-pBϩEWk]4,ƚ[Y!DbnrGO5}j'؝Њ(,@u {Y_,hB:c}j?NQw#R/E C;EJSlhkt᜻9wfyMk+_Lu)WI*F8AzQl!6ݵÖϘ#UlcF}9Goy5R*w?xs(;>K%ƈdzzܼp(JA7]fg$z)}Bw{gޏ;3j72 H~Ev$‚z۝"[gnc0İUI 6WZԡ j/j2;F$^LJNx9Sy<Ӟ]ESw(<ی|>A;E 3?=} WG3jw27 pAsU#0 a&h)u3>Y co'YSX(%klB=s#ۅe?263/_t;K[VVa*r A899\}K3gI32rpu@=*kk%dВ;~_`Ga ϱњ[7W h68*;[LjS1cBNA 玹 :(;ھƭ'YhP`DNڄn!`p+0}_@tjkEhdE pK:O_zucJy$Xڹz*^_Om#a-t!oKOƲJzŽ}jh"[5+YV] *@P a`TQi7hu&Y$q,k| Mۤ-ɂiH|vg9"Pg{Wb,KյiȊPb:O_z4UE̒,d!!fbxQ,}_Q}?=78hK!BQ$ZD>_{6B!&5urE?CA_c:嵃+x^*z~5%ORg]qFrww;>࢈>ࢴ˯f_t_^uמ>b}qOT"(((((((((((((4ATtO}c>YgaOhƽRwPےBCPK}sQ];[TL Em%̶ͭh[2?^H`0Ǡ5/麥]E)Sđ hED>LFT9Vi-n7M--.4k;cBqW|I $?ֶXClRH%iğּ4aI$~y[` ٩c pJzh[{PUvPwm \Ϯi0E7A^µ49UdLkYCA5nbCSZYٯfA=03{qWk*dT ͻ~8?j׫STB+WcO`+4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (: 7YKOƢu_ h ( (_y/ν Y=|]ue _ /EO@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARqM>iڝM>iژ^1eH W|E\b鼵'W|E`jq߽|S7nELH83kroY9ʜUB&&f*p:k9e m=Nn/.cS2O\{RװDbgɆ\cA檔_VW7qtv3{ULZh1LH?1Nq j{JVs I( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (: 7YKOơuo h ( (_y/ν Y=|]ue _ꍷ۾mG JTvj_ϭ?MY}mh*%wghSU5QEQEQEQEQEQES%(|$kl ")|R$`E>((((4ATu )oͩoͩ9eS^~xQ~'oo-{ <[㌲ >|2p68#DҮs=w/Ӥѧ(3HBh2no,Yͻp<09?A [іZ$VR x{֫VWE 6X1߾O^ cSjE+tFqמƺ:İ9$jA7'Z. 5e#EWnQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEu^n\=MPKAr_7wP}E}E2Y=|]ס]5":wOϦ1[prހg'qS~(\{tyX7WЛ۶8&Vfe1t~:gӵQΙ]:?.n'@Z?EITu:< TqWgRVFKJ{|n21TYuwI;#z4YY_& G Q͊쎾LK"%GehH,MRO?"At(vAɀi~]H,Mi_}GQ.?Eخ90/i#z5K]?o?&w#z4YY_& G Qsb 4.YY_&K4?/At(O?"lWdF{o~EY<ɍڤHҟwSOcỏs,PEۙdIį̤NqZIpy(21-#.6^u%|} -K}?/jkRŲ$ȥs岎2N֦+/2 ţ\2D:#lC 8sj>_agaj_Ϸ>]{q'bmdZ!\m u5ul;cͬ"]1͑cݒ_@Ϸ>G>oi^iz`gXc^*lIgPP5&yA+f|㌬Z_1:p Ro}Ə-K}ۋ K$KGS:sQZ̚t!7-S;p6i${2?/h_ %I!LʊP\HÖ,r=*nw;M*#ʅ?n֟gaj_Ϸ>Z]]n[wVXtdHTn;2Kg]LVsn?(=2=j2^6L Ro}Ə-K}đF÷N֥x$GAYYEcϷ>G>Icj0\I"'4fp}`"^Om v G8֫kԿ_ Ro}ƺ'y-gT&88%ݱ2 <6pQ#2J _ Ro}Ʈ]ZyvWWB|R/#8[\O8 N|,8' RU{[)aj_Ϸ>V.>iznfg.Jz6kk$`,8!cŤjYaj_Ϸ>Z]\7vZ5\G.i=u{+NP F{Vg<}XqZ4aj_eEO^2N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?&w,nl_z}io5^MN[qQAA.՚_z^{//kXB-1SGmhkoo"e _?_ϵ7G/(bI O6#]I q=Oj(((((((X1J8Qkk(I=X(((()CKHzGK, wE-vu4$\[w9A5KJhu >%fu HںH@dqSI5]\$e{itij2<ʄP m>;XI$ʪBN *Ԡ^W'oKclOBcY9eUp*rOLjIXI@8QWݞ•G̈n5mk=f8mz]GPFKr#ͺRy㱮}JJg}cdq>s}ngd,7bE- 7rA|Dz[+Uf,~C/:W%lѷ鵎;ism)]nۿRԶwo 1ZY4Cw{ bPW6[QV !vuýKI`-L[#3S[H{As ?.y]#ߜ_nsJƢGK^Dv/vqU[@X:),%?k&tks,#Iq*Iv>S!lb{+;[660zuE?RHܸѮa-bH68h~m<?@` â{Vt6ͅR\;eW(P>MwMY ēmUQK4tlS2A8l8`TQӞXvG:DD?Z)%eoYlRWwvRK1c#j͠郫3HŘ67ehڱtWdmE6gh/=Ǚ3) |EX]kMK3k4EJy ,Ir xY-HM۞(>lREqVef[-. xb ]$v$qXTSx:mfxik:;H!w`܁KǥE1*v1|? ¢ԩdmEm0򒲱cԖ&/49m6w 9z{zĢ7mK/0D`5@G' -\U[/??ƏIlh !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgU -G$_rQ !u_)4Ke<G+EPgjp:n䬋37uo S]4ƜTc;>࢈>ࢴ$e^{//BVk|E1EtijiAk[x^K[rǴ9Yk7ZiXE3BO>Yxmr* eא4H߽R87t'|TՕR +J``C@2O xi2h5A^ΠZq?W1/%Ի[ے`L݊9Z6+E0Y^DdR<2U46M=.`4uD>YS=밾4FENtVr$T7zFsPi֒I.ۻ_4gic/Cn U,'${WU|Jf6*I!oHS%y'^JƊ 0[djkKW[:>9>~0id[ .=Md&8idj2VI#a}gkp#'V6qֲePA'OFJ|h=!Y4&V_X>láԬ^`) (((((((((((((((((((% g/z_>n\=Mᮧ@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*z((((((((((((()CKHzGR M>iڝM>iژ^1eH W_?Q5{_4-qo*|I|5V'dy1zVZÜUԚBڜ}3U9\ u4&oRE@֪ZD^F ~#Wk7uAERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQExKAr_7C/?4AA˯f_t_^uמ>b5nn#$Oͺ%bDVP>#PnK3mzO~ ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRk֫s+ yb(@yݟ^⻉#EU(ٲ;9 zbnfEO䷊;{g>Ґ\qSfp zTH)Z]}3F l^Kbx1L1 #*H'8.&xKk4&;O|i<.5{=`Q?]%X—S*%PrUӭ`iv|352Jn"PZE/ʸ#Vwo"-r/F kxzdH;j9luGbF6wfϿJ‘[z*[UN ';Xɭ>[bq/#W0zeXŨ*HHM$}XKNʌX8Ssp{q+I4qy2Wnl¬_7"y>4Xv ׯ?[}b#W^X?Swg[eR̀(l`ay{9FҚ3C(8݅ uҔuJ R?G#WE`t[VqOL'9fM-N.Y V$l =xTU"TW/#Ʒ9x5{=`V15gdfeW˴:٬厬g RG(jz}𮪊+G(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X= Z6sFdC =zz}O _'W RU))K'5H e^{//BVk|E1EtY>*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:tZcǹ+8rO?7M41m$n?P׺m‹+D"Epr>U]VMb]C(FFSTdӺ2I͙c K/\h$yۊCX'XWg?V+ EleYw8'ElD+61w'⤋M፣{fʨ bq*6')7va$s+rm1<PL=<?uQ?/k.2ik!oC XmAuҴ7K.#@uQ?S~/|3~kmۿ:9PϦwRM"}ב G=VCoǦ3Us,WnD @$& ؟_ʚ]?adrqiDVmgٙ`ʼn'9LF$p?6'bq*_Saet;sa* # =}7|;$1Lh0 ]TlO/Ma).094&駏Rf5m /e֭'bq*OEae6Nl?'?ƺ=؟_ʗԨ/= mG?Q*k>9p~chaA8?15O/FT}J/Ϲm6Nt{Q?R0sl?'?ƍ]TlO/GԨ/= mG?Q*k>9p~chaA8?15O/FT}J/Ϲm6Nt{Q?R0atƆ&V s?κmY6b-%/3}ι ?]G;z ( *2Y=|]ס]5":k\SA=Ae _(((((((((((((= -!h:tH: @-QL(jIҬI] 畂D#t.T jQU?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhSSOoG?ƀ-U?44jimhפ+SujSt,qʬr2p3<7 ( )˯f_t_^uמ>buX}9 =@@U4#'D7r?UV(((((((((((((= -!h:\ZJ) \SFO'ѓi(4dJ(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒ]ѹ:J(w7F(?󤢀sxtnoΒM?]E*7sQS˯f_t_^uמ>b}qOT"(((((((((((((4袊C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (+>7_xuM?@pQDpQLC.՚_z^{//A?Sמivww:ܓþH."bNca}Ƚ=+mr8M֠hk}2'>;koVMk+R@$?R+t$:X3ɥ=5f n*{ M%#G (˅u-~sU_p[.< |\`=q[kzپg bdieݤ}cm|qӷLQ s(:,-a" íKÅQvW[_?:QEQEQEQEQEQEQEQEQEQE= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr먿}ro\x:` buמ>bЮ՚_wV_)[O:Y*YO"Sp~Qj_\6O*-QU~s@۟?>s@۟?EE`pTQEQEQEQEQEQEQEQEQEQEQER4QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UoA?ɿrtA2Y=|]ס]5":`EZOkz򇐲:)U'9rdSx]R++>o"+|sw=SkKMƒM'>H,L_#k u&QZ@LpWN+?EP?EIQjvN# I R:V%`j}CRDe08;tue5]P9JedjAV A[/\!_ ]d11?~?_? ѿ+ehF_ ?rB.2?='?8/GA A[/G$7ls]d1uAQ1??:H4o ? ѿ+ek"# ?riO= ~AV A[/\!_ ]d1{LO~!p_ _ƏH4o c("#bcth4AV?EG9G!_ {s#F_ _ƹB.2??c(CYj[^E4aI6_):z,>~c+C"?/h?ة> > X!bɻ$cO= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@aly>e)Vt;/EO@ ttP $H{QQ$GV=z(((((((((M sJ5JKKYL!X}>EQEQE= GERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@Ӭ:tq[ hG/B|*.nu>0ż|q'Dy$XH ~C_ zWPݼ gTcd3c5K< zi^&JPPsȩ+3< zw:2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]m_-?ֿءƏC;?>2]l_-?ֿءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_u`o$bHw'lw?ޛ(77~fLVSVQKY}(}*ءƏChbY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏCY}(}*ءƏC.?ҹo}x:Vs~D-Ͼ@pQDpQLC.՚_z^{//؅ &<a2#1f'5;k* DDf_=$ǽ?S5a>\Lڄľw˼0};R_7~'Sek#RpAuA5ޟdg+9m4lb6횣i` ̷w$I,_23`qJ_[+m@t#h$q> f״~,1`s횱{k[s,Q('>IϫXj{o Wlm 4çnuΕ+( #$D v.}K˯e=ߞ  W=>R2*}aN[r4m\05i5]#[X8JM9%nzqRi*RmY~$W0Pxڲi&tȷtI^ lmnTzU±t z;(--n2*($n%LoE_QcsaIu4`'W+ _\1Gg#E 2erNgxU(tF+#Ԯ2cԎtOZ;:+ܷxē< m.pHwNxTmAEkF-?kcϹֶ~ZU.nAUoݱU'fj#\u>R}0vH!qߎJ# JKkah(((((((((((((((((((((((((((((((+o¸}x:` bsןO#?:9Pٗ4ګ}/ڥ?yߋo혁YEP>=A O? O/G(OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O?*nj_Q @?zU{EU%yѭ—6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o)W.7P#÷[?Danc[ZA#t}E:!SXdU 1(9H@4\h1I*dWcyk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~T5]yk@o#Qp~TQ]yk@ݶmj"8(Z(nip2-8.7.1/doc/src/figs/snap3.jpg0000644000175000017500000024221113351443023013332 00000000000000JFIFExifII*JR(iZ)( )( 02100100g4C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222224g" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?3A#'.4̣p-/GkWy&_ RHk+Xŝ@篭zגԳK?.Z{Gp=o_Z<%g>]zמy^K N}/?G-;O]ּ_Z_Zvy?iϥC篭zגӴK N}/?E=}hּ^?.Zvy.yG?!tҴKҸ篭zגҴK J}/?E=}hּ^?.ZVw.G?!tҴK?.>z篭y7-Oi>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-_篭zדѵK?.]qt\X֏=}khZϥG- _篭zדеK/.Zu}Ep=c_Z<'k>__]-zǞy^O B}.8?hZϥE=}hּ]qtеK/.z篭y7- _k>]|_ZoZ6w F}.8.Gm?]qt\Y֏=}kɿhϥG-O篭zדѴK?.ZVwp=g_Z<&i>]?!t\Y֏=}kɿiZϥC?iZϥC篭zגҴK J}/?E=}hּ^?.ZVy.yG?!tӴKӸ篭zגӴK N}/?E=}hּ^?.Zvy.yG!tӳK?.^z篭y/-K??jYϥE=}hּ^QtVu$8k,>)iSN̗6oWhXנZ^謌Xdr )Q@ \y5L~C\?+@%HŤ=wT*(R.6[pjrںYNbԞvßj ^ݶXTr]?MtuuPNlȔ/c]:UoI.c*H+-t&GN<9XZ>'5=RMixLPsi'Z\mv_tB{)lcbT MyK0d8B{סpgAFڑ&?0؆r OHu|w4_/5ys:SZDp[Ex8w'*;6FЪpT^y*[I,|E7/$euIϔO4ag8[}> eqmsgX%$@$9?vc?mS%q!s/5F(5ITm5tK߯4OmyY@ 2#ڽa[_x= [Ŭ)ه0MX?̻|汈F9o'qVcz6Hٽ*s%-uB7vt3b \^״ Aӷ;Pd:OOƷ?"NuIĩ+"r#@sHVf VAI{}wO9͐EV&MkEմk-*'i nʯn?G&m/t4O ,Wq)]~?z6be-B o9'8ペ;mn+ 4-ᣀ嘂a1ҸiiP[IJNA96021hǧC;u-nDQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuK7PQnuKIHR9¨PD!~LnsZ% Zvpמ9z]rK-@v"Hǫ3VKB;_ Ki\k2zb:}Μ2mȽ >% o5 L&LrqU[Pi ݠJ)]یh7zfc2[uc*}Sw:u\GpP/v\dy|8.۵RO=~Ǔ$1vϩe{Xe]4^Ku{7ÝFI|(r *+3B&U뽟Up(LԌh#Rb_<]=G=EW2Hހ$ݚw_%Ld[x1mAہR,d$Xvy<{:R7)Fz@ 1JRA(cwRd?=T~Uq6DL&G@NqZ$ dzRα=ޏeȑyl w''8Pq:{;227QQQ_ʴ".!Ц#Hi8Ssw:mr@Sh ='Wyi}p<9ŗ27~},T-վW8?EhjG'}۲-[܌j@;OP _ʛEZ] kk$Eqیr23Z>,n|L"v' k7f]ym+]'=MZ=ApG8 ˢ4(Q#2~G<zenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@Feԡ Atj#řR{z(wĻQa~ֹ28iaUh 5$d֋R{uFgYn\bk*~IOΝk~6?֨;/CE_Ҋb'U뽟U]NK]K=rԶ,P7c=j{>|1SRVht:[|ܒIS%4++"&gF]esS\kZs$qنQH1cHǭ8kʼn)EBʧV u_gU2M3S@~#ERvwW泏AYԡ:{cnv;Y<8CCLL-=wZTe<;56:j_Y @YiW&x.綆(j\ Qw(!*ιY[X BnC:M^ nXy]ֹv{Im.'m=sqOb*姊 y $ lP8# kFn2pnW)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW6l*Uk oMv_Ҋ,O?5xS{?5xS'?S)%,Nߓی~"_KJY<-n19U'h\d ?ϴ ie$;R4ل獻I=z\}mnwL?/R&]LiͫNI[9C6y?l:u#3 ҩ\IP֙`(Z$=CrdREiSY= w=wM-l^p׷<4kå2MQc[8mI0۷yA򜑞!:92_xc*w6sn.b(]QgcXKw&k&&]ZO/n : [[O\[v"63$2rI#y`Zt,2)|_h}SQX,g}Unmr"8̝c9󞆝o؛IWTѝh-NqLIsٮ.#c\dwNIU?؋ x[V/uRw185[;IicW,|Bg'ⲖM;A-ew7M;L ^@ tKI5&;Hn4)t '`u;S_]#[wvEKWG6ʹ+p.R_vZmWFeVGFާkӉ.巻]?`wYD_嵍Dǧܾ% kx `B f1#<:;QQ帷[2f26{к;O&(a15{]jK !iJl#*|W:4Ifҝk}l#9=Cgogs8 y%)E-8Գczz (>Dc#81[I~ש{ n纵I$Ne$sL+7s= KeHT7D9ߑ9Moa_Ky0\},vYWjW"Yd1K1:U /IԖi`Ծ$r,1s={R[Z%O5!Yyk HjX<јو츒5#Q\-m.f'6# m,|dj:(+=_%R*Y,KEHTL?/W:_XϨItl<)T̓98zfGcx4jBHQe$&YN>c39WlzgHʥŽ9vuj@4-G{Mɧuo5@J0>j;SIӧHn(qN8Q2p*lbc\%M8/8ϭcjvԤNq 9GW'/t7toŔ19eOfX OI*c9$tN5Qswl ZuPux52}OUXCo4MICFS'jKPOu >e9{:l5M/RUUChi@uq\̺NMly}4ZRFp\SoSWV{ dZ<BF ;h^Ϊ5kvecy6)IZe{D_fy!ٍf-9 ̈0R zg?Tլ~]R^"@Kv'?4>Zؚ-oEkxPܫ w W'=9V,u (b:؊Z./o-m vl`@gy0OM.!(SvH =Y|[4/ɂѝG6KM%ƣͬLIۆA9zSz6-6?"Ҿ/~՘LW}ٍj֟jhK@w ^MᙼwOUԗU2XNWsן ^_wuGQtɝqA8zI&"h!bpcvw$RcEEAgov{1F‚x%NjI".J\{ 57@g_ڿ G,ǿ'H`-ӮVe`$&qtQE!Q@6HX9] B)P{K =>3ѓV(UQvb(((UjQ)h (jߴn3qKEQEQER2VPz2)h((( ia ;7H8)iGQxȒw3Y^.;49wɪݶ [Ya3}a;9#= IVӾkXh8w8掗=xlb L8=zָ>OkK8^l0vTR'$2ϰ|W. ;;K]MdM29 }q5~n;REKyFxФ(cw}*ᣍ/Pŀ,i8'S~`vWi֍srbRHE:[.< \`rxp[͔rRT9淑ִO}- zSM.#g$jo3nOb-YZDPZڗ Ϧ +^ ^wWhW 9w?>¦D$3u AY^(o /$Qk+F̠;#ң?vf?fo[pnǧ_’wv4TTLkldX$a'zu_iڭ4Yڛ:]2'00wS#T>Qe}( /zg/zղ; [X\ZM,/l1Z;je;@e?Zf,C|Gd= #5 L?:͞u ?1-sTq|Q?8N}ٳqpG]qхoiͻ6w8#F<{a?gXeI.̈?+`Mr9f :n>?0]=&nqpîFx wڤK⏵I>rXɟKߛ=.Xu?F'%8\OgI?RϥX']K=.uxчj59.u?Fx 3N$h2y)$?j}.?iYj1KovHDw-.H瑌lcw~9=ڔXg$ >_ qz&;I>j}.?ɾ)#.fxMgO~lw?FЏCTq|Q?=Z1Gsj']>ӏ]iNowv3Tq|Q?NO}h e8b H'?N?0ټib5sutbtuj}.?>'\Ńi’H#͟F^ПwKu~sMdU_j}.?>'\{A-j6sw?1 CvDRluݟ2VzڤK⏵I>yS|oݝ3ZI@뻧?F7O !!kv]ӏ~taj}.?>'\3QkYlc;x~3ycc#>'\}O+?9ӵ=&]щb\(A9wӏsҾ'\}O+ fSq9wqш⾆dxΟ|uO)5X✝z/ڤK⏵I>yŷŭۦg >X}ƳN,Kwt?Lg*㤙j~'\}O+O\$ wtF(LX[@s\}tbV&H~§cTq|Q?. 'Z x#n>qщOR>?0}f>'\}O+d6z\w_i-CK:n>?0}j'\}O+o:[n͖3|Avl=.뻧qх?§cTq|Q?(L}ٲs\wOO8ӟw9.뻦t`oi6w \0>qуt=Na?Rϥ\kMuݜZ/c󜅜֨0{ RϥGڤKq\%d7x0?1#66z\0ߏ~taj>'\}O+>4ܰ69.u?Ó6kH,ETgvNwq1p,Uuj}.?>'\ȟi %͞ :S;,>{z\뻧?F֨0{ RϥGڤK#==f :hS+, swth8?§cTq|Q?+.F}Awt?·=C#7G>GTvj}.?>'\Ʒ4;=.ѸkxLbj8#7x8?§cTq|Q?,L|P:n>qс{6T=Ni?GLmRG˫-,˻"cn͖3?vls\wO~t`cS-"[9tTq|WX-C'9uxC Iݛ-Gw\}i0{ RϥGڤKSI`Oص=.>qс#-6Z9.>qч_ƧcTq|Q?$i8$_6~uxskBU96:ӏ5ZًMt=RϥGڤK0bvsw|}Q㯆U[MֻlutcE$%ŭYTq|Q?#o>m5sJ]ӏO#|znΙP:}2O]7l&p=ҹ9=u8?u(X^."1̀36r<`aoNWh# yB;{/CE_Ҋb'U뽟UnUjzYJ3+ޣC!d)@5VQ9^:dxF-3zƮȴta&WzAdpW4YqZ,ږ2KGg;c't)G&*e=gpf׉tZ- d D~]:gO-S%+xݏjT dnӭvsmF6I~{O@}`S֝p>ǭcGtqzzTC?iTЧ#V@B8Ӌ\Sd9>Vi&[՝m2}q} CFw+PJ$S MI[vczm;R63Ir1I'+[jB'Ok$yӉ攨*a 3Z1Uojfb~UݰlJj{6TY[lg%W$v+Yb>|/ .?c[ (J؃^{'ASAbv J=*;)ڬq}[Z-nWE~9'wK˔yV23@GXacY4P>B1WDnOsleBxsUtl-2\QۼɅԀ=R6s2 p?*(kRV5ӫm+ rbw5G%/xbY9ç85cٯa/&xX) qWaw,pG?&7P023OQ5ut-A1J4wg@GІUVe{2_ZR1{PC eH縥9;Q ${8'6^UCCZO|x!EZ| +.1O?ysMB#'=n#0s֖& y?$0aϥqiyn@ zvsL`zq#c!3& $?Z'K9ۇ_KaϽFG;%Npr=i'ӷ=s <Ω 1 g'ۚa9˚Bö3GLCOM'q: 2 )Tz`>qdE VhS$ 0=Rb*g9WIr\d+ׇZ܉EpvFN0~tZaLܱNkӢzF})(-ns\xIwi#n6c7f .2ma:wBPQE/zg/z۷_ZޖRǷ#o>̑^n*m,ӕoQӡG+ifNdxr)JZA5e=CA⧉ָ͉+NϯҐZ03Rl- 4Bݢ"[yciO=#cQf@q}UfcND!qi˰]c&d.Eq#FVƬqJLlB#ڭCgP䯦?kY7n+ST؁"hdy/RcFrPW7h12G)ԭ=¢mBض<|^E5i# =>aSꬤkE4SJudU34eV߁+'!8錊^%Rq^i/.ĹK{D0ڥ(;˖JzQ,?N8X?~ 1[xzK䂽O#Uc"Tarjr3TfN=BVh^ۂ>ңK9ҒUW>Zr (NaC1]nNHS*ZqiܶCI=`W,ꘆ:V20[ĸ2q!kŗS8t$#?_–1X\i1NʲP.9|fJC+ZJ9;?$dĎT kuӡ \HM+cy!*׷0ܤ 0U<[I3 #cn:s|Om 1JICۏƵ8OUNRK23l ;tRZ?B ĝs׶=Ͼ3R3ʥ3ƊHh!̟zyHz}A!` z›t홌[de w瓏¹y5 Մo$?|GQ@^QwA?X.ltA#`JӅazUM^2xxk 0?y{;*JNN:zκT⮻O\V|uxUb/x{&p ~?\R(jkzj.$2A@N(p{z6 3i&6xV9qjv+4Ã2Q `T}ZORB:TA\A桿b$SfzdFԀzTQ+9'tⅽ&=~^~t3Db:ti%cFH@)zri`pZ^qMWa <ԠJh;oƒ:xaT263jv8u}k.]\ҩ(㎝kХDo[zԜ"rsXsZQ5VT.f7qښZf(4Z,zqTaR+P|TdMH\hSZ;N}i}ۢWeAy,CVuNl7]%[PjhMi\I|?bRʇ+>kKӛjä6[8KH{wiɶiy%}s0t̴DEQ*?CIZ嬙[9ۀ@Mr:mZ@->a礋Ϡ=={9~_.6WQlPZz3S0"p zJwZxb,K:C2 f1;q㋶$Kְ|L!+ s>⚧)ik#u+.F\[Op{|Glf`s4HA6z YoIT<7\r@=r[eMhʯ,vעR哉fE.n(8޳ﵭ3M.ݹz|'-(t@eGRW鶬u Jlp|\~/ l< ޭHȖ͘jJ;LNNqܹ@ 8Qk!|G> ՃX0ݏoʳe Yl¨(VlqFf.">gjtѤLD7BU=x`,;c'5/wrGkH`{-֓4XgHč`zFqh9#Q"Hqǰp(g'J0AvGLќ'\[H{JLM$/VX豣 ݜ5&;T):sHOqڷ+[+l-$xdhvmpq':k޵sfpAl1Ec7$`Bfq=״67-t..$h}x?{W睂^W,qM a)UsP4-xeQ=9j:α۴Ē6n#c޵sj*sZsA.o- 2b@]8IZ搡yYomr$9 ݴ{ .?VntƄ,Э)l.dY>d,ݹdxբ`ѐ GlVl>᫒-p-\օpn4ffNzkj^gҳRF(S0Ole`*@$!GM_:=kj6ORv(le+ 4yĖA1@:)sߝѢ Rk,Z* F'<iWbI.]v+x/mMyWZ`k9.W2'G=rs+)荣wVʦx pG z>?@L $ueC331 |zz'-9zfmv2; HP|Þ!*_xU@41xҬl~9ǭmxOJ]-9LhĹ đ8T| whMl[J~~^F';J%iFkbh^(L#OIzObxOc\5)9"0k|]_oOOFbp>3mt )l&%q:|/' ^r٠|B~U#V6k ÷8k% ʑ#`{''vnjt{ۢ8n[<Ɠm(" Spw澴@pg!XN:ʠKck(.֏-P}A>BHѼ `/5Ϸ_7th ,+՟/?`?\ك^*o=Ҫ]K=זOQI חg3r~S֠kt4$;WTk376ӓ}*##t_ʷL ~lGUr]4sgG>HS6y!=>hNc],n3ǒM$V`Je 냊ʭg5bWt*ضKd{ӌ1 Mgr~@{"Mׯ4GN)/o׽KC@3IjO' ]cSLF6=hǏp)Tx'۟G$ cGJi/֕ Yy>~Gfjͽ&Y̠@F$ִmj%a^%y#2ZCKI]R,GRq@ZIwi#n6c7f{ .2ma:uB/CE1 p^*T p^*Tn*m,ӕoQӡGww7QHʲVQ9^:d| Ypdrj\JQrvGqvgd1O ݫ{LL:n[&d'߇W|D;!,{w+g_Sjɛ[ B6TDIZ8Ze`XyA`;DŔ_E H,t ljYu<-T)G+ne}rJG8O IRoOO.6/W>&}aW 8}3E2VFN_gV\YI aANϧoT 欤8G_zI 1FNXwFlMw?LՇ 3`K)?(2t?j$*vX撖]_YcWPXG [^4bϣ[:$VD0Gwm -I> !yLkn%Dwr|E''8v29$m/{2 wFx}9 @flsNxxz+Β.rypAߓr8Əwme$ &'^׿pTث,nls$}3ɮj+ Ą,Mliڕ|y^tL0=N:g~56乔Ey‘ۂZ )$,@Kds~3nҘP2`/r9`y>ƝbO s0 *$1 .f*2ci\;TgiJO,FWUȤAV?t1I͇)gN N W=2Bj8S͸;{wz5.Üiք:Rr?Ϝ;7\ZΙ҈40Yyn:$r+[aZMr]-Ă8I-r~HK9'zu81N!]'U$rUSLܞ QxIwi#n6c7f{ .2ma:uBPQE/zg/z۷_ZޖRǷ"Rq\_ZޖRǷ"%ePێ=L)$/DND:S"@=A$CXd¤v9hŘۘ\LG:~U<=fQ%лQ8*X.aA]d>[0݇O[SVGxZ֌gei2dHI+V$i4O(U4ZjS}GTQ+E,Iá #R⾂|M+1:aϷ5#2`>L=*+TdɫX }|v >nԚhD5ܚM\9:S.^U«@RryWW7Rږ$lznnJ%TQ4ކ5_xD>n$\|9o:OHCzqAnv|c'osV[`q#Wv>5G TR0ש|GO'W9LڋY;X72zxrbfܓJw.|) .I*7#5_I˰ S,ʓeXt;|yv;O5H>X.B1yQ?[isPcxf9'#MʄeT'7}3ɩxF̖``l p[L#⼳ljK3mb}F+(~k*baNn2?CJ<ȼx0{{\3 n Ia[$ȥ7˞5`YnθUT=7 &%si(Z'tW*T E\]ڹ%KhL8WE! ٗj>h=#?Η,J{mj'= h;ebfAy\꘮MXd\֭6ݣvQjn'ݩ_`u(6nX\ Ci RC*@07A9AGB)a>] R!}=i$sҮl GsHF?EJq&HϦMLxnԍ + rų؏RG\Tx>brLsHv ;ULL>mGը[mȋz~qq v>c#${O_J•ny4eO&'EmvX^sT-L-9vM##9 ƅ'f]gw[O+ 4R2N3ϭy^W g >˪AC qzaqXkq xkR/m<.0NiYߩz?ž,ͽsȷZ-dː 0gb˩%rk5 ͠[2n4z >rYY'hb62壐.YO@1pjJQik[+9biB_'8=:JבlQ:p ۗ'ӍfД12MG`dA4i"4r(dpU^j:?SgٻA+d#2Zc6ZW}(,GqՂ6+NgGf=!)i3Q<0H (^NǜnȭFQI777w"k u 6S7p+F}qXWJQ߯mRᶕm&w h߀HӴw" {S+b$"0vGk $*ENKobdSZF4V#'kƖR;$P둃2+,qC/?uqE{grv>'/Kq3}0m1zvT#1 rߘlVvD`2T] %;YgM1ׂ1-#:C 2w?m "GtǯY>&b|r6$Up<9N..$zF szf._J$>a`s^lȍݧB=sHh.g-@N[H.O4ƈc׵ ;"{{O'2ۊUtr (;C@U 'Kn9˨\t3>pKN؝8pl(8>ҋ5IpC<`ۺzFz'8g?ҩNKڍu'Jl?݌YEN Uf8f|j_f -ir+w08(~bO qqH((q=@,^fw~@!J<7r "'?\ 1r;:jn(׹)/ CתrP7z*RFȸlj E龁y/ (WB?A$W3n;Nu6Km<`)ra#H$ URp8nR>ʈ#\dTF$n-(q{1G*g&<~4AWJFde+ex)DLN|OS<pO]pO@vVQ9^:d[42+UlKuUme(ޜ|{z2<5K8MN~ta ?Ls/1څٲhBx^IC V:MnUB7 yeߌ/6yRH~Vz_±o%%wQs1XĨ- 6^҅RY) ? E/mGETM}jUs^s&QJȸH%Qˈ#]Jq`3n*ά|I2 ásJ>u] eI7VbϦF1s\3Z }N8V`OL`Ԉ&rT6ޜʹ.!V-3ʒ6;-b"vy?uBWG$cqmlӎN?|5o$cslE8Fcz s+R`Gu\c8\?zWvH] `ӽ)% J#l= [Xd*pGTd1G01 Vn$ö;}j25&9W V_fӮHڦ[as0"@{ rNN+֖E@ѡcհ:1 "VЙ*H') yEIqn wOW+,6 2 Z$hfRC׷'-͒t6`zҼR`1;-ΪJ C/Ҳ.oo/MøAc|v#[Y_/Ҿs%Gބdp9ұfh㷂ܼ@erp9,r{EKśUv|ξNIAF2|? Ruyo@vx Rn}9B JAF=SbMyquj;ɞ^yiroaO<aIu#q1ER̆ I>sQ|)pI_b9&Hk#9́ӹ}k~߭φJjԖ{û߱xO.; ο2 ^3 ~ %kgTWGQU/uK 5C^^AA*$p cu?rڏĭ"0kT>#[ql٭+!}=E>Uh>crp3#;1ׯ¥@NKh̬1+S\Plb<_e(IU[OT玺ψtbAq!?Oֲ'tm-^ $K(Wb:juP ʴQT+KЩwǺgZǖGV*;F^A;rp}xeݜR)i;IM/֜jD>Z|=u`.c]^p^axsQqu6N:t^ŏJՄg\,T{}>yU$+fDe992t, }J/[`qq^ ϕ7Բ㸔$!x'[%A8"0~j1s-r;{?ֺ4#󣚆&S,fGBدOW5qC0j+gXߥtP#Zy溟 LHĄW*N+WGdiH 8hWKLwq={F{xIwi#n6c4uUd/CE1 p^*T p^*Tn*m,ӕoQӡGϩ\\M3<澁_ZޖRǷ#5kX켠 ?c+)J-O2gdxLg#5ca}9eal,ɳgcp||0#3SS!G$GK+bœ$9K,/hFdp7.qЂy=:`1Oa2Z^Vl#,+xzv4Ҩrמ¾k,E 5/nFJ<#ZҮ@ZTs `}Oǧ\:ɋǗ7G?xӓY?+xF1nfVs>2ֽL)M~U# 9~%h7(KڸQ'I]VS`H𑰻;u{d۵Pz;q^Cu[ usFPTo8%x7n躁is |i GּW0HT߄ĹՃykb?0kzSFI'Xťi'=?b Ы|`\:fA/&O|.OY]6k)H\BqRJ#5>uMf } $ *9F@N+({l,7õzKޫi&Mf{ۖ1 Փ 8 _5gc͔\dr~$Z](P%_);'*? ٸtu?]R}n㳱nsȫjލ9^] ԫƪVHvsTrOD$Ps:ʮhuH>V?1-"M v]0-3~fn"ԡ_ 2DdU$3[m1࿖;\01ˀ߮kح,m,QkVFo/m"%ſ5b3,F'JӱCHG'$(=NsVcijAb70G\}F|Bl#v~>k@uRIhp6¸o$U# 6gڹ[tY2`Ò;8į9ǭ;4-bj dfz$m+4df!DI>qMylQפUU֭{yaw n8'VDdwH~cNeY7.MZ֜etuG1'FK?fUNz?jZxL8H9U`>rMY!o24 FdfF@zEpԑ]jv-ίAʵ$9늹k5)(Pp?3X8mxͣ o'6sʤeHӢm%_ǟUu)hоabxU `M*W?εTm2|~&%MuF*z77_ ޣ*2@¬{*f?֥яW:d|pG9TFp }E%q S|Ѕ[˘tf_P-߂ǧ?Θ6ċQj21NM{W:8IPofݎ 'qMld=3\~(?ye !_j^* Mc$|g(T tE!t`9YDG~dXMcN'n2]4˻*zvw<QQŴ򧍉jG2q~]l Řp qQ2 >@sHv9Ol.F1mF~#i]eۻ&#/u ?3?hfv_Ҋ,O?5xS{?5xSݺĪնgoNW=GN"v:c;\88WVVQ9^:d|-KJOO2OuI''$ڦvVc"8>`9 m~*ɭ]/ڎڏOzaog. Lefc==)(HVlnf`y^x2˷e, \#XSMSo\ r+wN0& [6ݠOT 'xtB =imK Cp^u'Ca"gx- Mi4\ҹHrI?/qVS#6 qv+v 緡{Ůc崢kyWr9Ops^izNKn>l8b3xp8oQ=խnM,R9)r)G V ĨԊ{ÚdR.yAH_^Iڞ$ܘ2̟|\ޑyh0R\K-طVcR?3` AxiNFֳ.4)v㕼7ZPUfOݻ;Nzs޴=6j/le9IdqL9[M.1]}q8sОTqX<\/foyZao %ّ(mH<hc)˕<0?kI]ۛ=J9<r>Jc<'$-*>?}ȯk/CTqزξj;J|PC|I}*MmP[q2"€ɓ*'4#MK V8*$cd~t{Oּ#X1R$2ϱV@K)b; nݨbUD(5sXPtԜ0O#tYU{-*o-a,Rp̀ ׹C7滕9a&;lbkaOzjVe}gTP9I$v÷C5i^搪a"PnĎ gSqROޞ Eݳm;Gi>aldN2j;&OZƠMcTXXԙJc_"_4m3myKy0 j6a^^a%9%i;hr)?=oب‘˧Zͦ˧-%h@F cQTAM 4K-n-.Q9;'~57[_= D.0 9eIl6W6ZMk1o*h7pvb<%m¤s&LϠ*񮒰u/  C }3"Z-{6@XՀRHCMVMgIZ8e:`/_Ot9^bII|+e(HB~'-řʡFڻԂǿ>zK6*`-щ8 *lP7˅|3p:5qQƜd pBJ#d=!M}GRH#i\̒12""CL# ~hKK-VKU1?4=I?z H]U:r?{F6ƓlPKg2{FHuMm|R 78<SWFױ^%7E-('0p3j͵t6''dO!92LZ y⵴+ZK8@V/Oo8K6q;F2XEvznm(?^]QUq;wqUbFob\A^/*NesM$^4>Pf&?uBv2+ ;"UB<QD1 lp9$8WT:3htgAH2)}d̵3\*ؖ_f:I{4v+WZ 7?M֓ܳB׀l'`['vӎޝ+]H'W5+<\<_~J [T'M9gYݸ>; :"Ms: n'a4_(B rsn45 3,x- Jz&k{V3Eץr1*.w.N2qU776< ؠ?ͼqs<xCHUýÌ|ĒGL{Ӆ)ӝXAld ua.xsID^;z~K5Ǖsh3E {ry6IƉUH9\E֏Ci Y,}IWAҀG]U4֨7ğ$%ymcӐk3g"X4o$qq7,j?|wWK-Z1 5ƣ ;I }nR9iO(vؚs׭znj7e$`Q@$M8i755xCO:?Xf'Ծ]eۻ&#/u ?3?;KLwq={?VAJ(T>S<pO]pO@vVQ9^:dy6X(!H9=ۓN_ZޖRǷ#c׮3$ZEĒ*O~g׊>FՎRӎq:e$QOS}zV>j:VIhAz/^ZLDj,nEUzm(SU;:fnvY$ uV l# 3еK]Imf1a0t661{ep7y>`.>9?JcKVOCROvAC.~*W?|/Zi6](em{gr2xŝՅI$lHАBs\^[FdZ^":I,ROL32g;Ksi*rt79tAs:^e[XFB=q98Q3eTo8wBFj=Yj>T-1%c#;Ssø}cHJ< rcp=k5=Lp@8v?j;_ аܥIpO=YԦENa [2@:> Lk<_lq xD<;90ʏ&ո2/|&[T]+e(rѿߺdZky޻E]Юa,`]8 6܀̬{`k YgoYlgsxGY4[h zdÞN8<՜VKGM(K6nc;Jd1# (#j/>!Y>Fm7LU#1r 1*Iq\i,kQ~C89̓Ք)bK=>±79UFͪfQuյy,vmx %q%&6#MO]>_y;vơ0P|tªâܝuTG-\M:_7 4) ,**A9ۆ rͻ`T^#֡tEn$rΆ(gCۜs;5ikN G?i9KC`XF|#wuK8?0S[izZp؎h$ֺĄW=j xۏs^\GwdQ4s@ּVP*TVS-ȧ[! S*ȳ&C98+ /krZ,G+|c N?.6$Gq#`N֨ą!:qV{=)@@v'vkԴhom)l mOZVĄc9}Rl1Ep~o0/4*~u]Y:U8_6#-rpOcb1أӡ%ީ1%:QT(?ZQwy~UkTKE%dpq-b,S>ۄj? *vD,#.k9ŵhؘbrm\A"G&J#.m^CwpN+cx>!A*,m Ќc:pLMi_˴JYldC-ԎұC:WDcag *~,ȭq~iOaySVb4pGP0]"g|\MDM$F-_c>s$KK{K̨bGe'8&ZyVdGצk8܊T}?+Ŀ36={͟[D' ^+ 4Z$ i !YN8rsq4]D\F8,Ksӑ+{TMJVaO\pwP\٤he9P⸭/Q6Č F;g~zh)>If9 Ǡ4AݙՃtfP?(v:@O{- d , 9ƴtܮl>dl_^6,@pv``Zܮw6av<-wɗ"b3u N9y\I=:q({iԒJ=K2uŧ\FCxv=Ii^z}X 8f%yPzwlr, q(pF8WxN0n*U3:pZ+3gR{"7]p(UTd+ux=ݜ6k6ldrG#8< q"Q׭m."&8+I(EQe}("y _ꞻ _Ꞁ6%V;zr:t8ϵ]9àl:UjzYJ3+ޣCW*\e>܃U㜴8![AִgHу9հkJG[\l1[!~Q3:$IQ-xJ󹏠`U sԘkwGaur=kUG ιQҚgY}8l J/<޹גk2gEܕT%d,Uܹ##y޷OZll0gvn8kWzYTO,aLÀ-]}?SWpcU!J奝Ho$ :Md- FN9=OԀq;'>oaI$0 |8sz_I.#Fx}?LTJqZ"t8sD}Lq2K o(# | qY^MgX6$Z 6R:hRÞA 玬J50Zm_a'֓0jfy$TWvuA9 2N'5Qx$}UHA*=+Zfr#&;V7 E$rNMz}x^ExV pG`OF}Qq /5ĩH7;U.74/ 1+|Mjj2Ǫj3_ YW? =eΛ({3X]@+fHR>ׅ\q{>,m܌DsP!:W/ӷT{d2E ,Fy}ITm k 9T R]2=?%[;2I9#9=zu$Z7lkZ>H?:1F7gx@[}d8;O=JWALig#!ۿ?A[^"Α.!!w"Eަ%6囁0G=O#n0A2J6”=v K׶`Bcd0]s19Dw`8?^xږ1.m\yXUN0y\Jr4xGxE54kY..&,YF#88x)JgƨQ sǯ}>`pwm ܱ=8՘ a%<ӧ)JŜ D9εDϯZMMQ`[{k+͞h|xS$T[2H=.[B6q1=n^Ooe<D&mu7*X,NAm֯#ɾ1 p `N> ~j.(%}F5Ϲd;@A]$vmg qkyMc5dN . Dp*`gڦ-ril@hʪJaxCd~~2L 1QA$r:Jn6͕)EW 5vӺBmk0 Lk@.r>^.Kec VYE^HnwI>2 co)'>=Fy$gx^5&"9:X5rq#,ez39c6Dyg1\ӥ :)שh*. dc$f!+<~$Ò֓`3_jII1< $d[TJ̆+9htcHlY,Q?i۹kcV9횥I^Uݭmv@H@pP“M\ׯ]c%Yֹ}Z/M&p[Aǭi]oyfs4lv#ߐro0IoG $` n#ҺԆtyx8{.y'99=Jh|S:{tJ惎-dLBsy@kbR HGXɾ8[[Gr{{WvVQ9^:d|ۥKCf_2dyJ;Zf ~eERqZt٥BRy`{}G FdjƬ%QrᯈSLU<'` xMb e؛x2 ;B:/-3K[W^v+ 8Q'*} #0u'8j'E.XwLgySTRV (ϖm q$;.01kigv yyeAʲ$W2,Nʥq^oSgN>g9khL7. twa '#ҸO ϩ]KV9fvkյ+t=DP%/VUcRvr~)"\26;`1큏Pj܉Ur}xDZ})o5wrTg-#w8F~ղK[R4>rTt-`E}QR (/ʝ:uvc%A۟>mD&t@R(y~C T {o$RAUr0~~[a'sήc1$x4tSyS#Tv]3dUPP3~Yk\|ҿ8 zz4p4d-Bs1{ Wy m>_^VgRr~ci\Y7P@cg-T pH=x-錩l 傁}Y <0JҸԋĨmxFp]2 9sTOXzOvelCg' b2=*6tf!`y>H85E1`:WVZNV=NEt͸6tHQlXd{3+g7r}*x㵅[tca1\3MMN%1:1z+]+,}jM ,d-#l dg[z F#U,IL֥]_B[lpoʑ  UFNEדui3 $>9+1-M7'=\xIE"I6kAaw"e| ǽ,Sew '?Ϯ*н[r`bw؃@'[řneO5HcF7w7V+vp1g'l~I<ᇨ /.Zz&**ۚzZ%HXy_W6rN<*? P Т =%OcZs˚:U9+s87}-w'߹!A믳+<. =WYYn'9W'iwbU2 WYE叐{:bD\޽#ҦH])ʿ+ hx 5sqT q9M?s^ y/Cbå AbǓA9#?vr6Inz0?BʗKLwq={?Qv_Ҋ,O?5xS{?5xSݺĪնgoNW=GNcD$5VVQ9^:dqdH6G9%Z⓱x0ENX#@TMtS[[DRA0>j5:M~Z5h-qqVL.@SQҔXvYm~`;q5OS籕=8ooDwBq@zκӹr-w7"w8=ZKbmRk˪ FK`XvE#Kyq(E$ArHðnnP)h9y&w_k{_<g!;& ۨ΢е+W|k$g(tsqrǝۙ7 O'Ғ7D~LÉF<$gʖua&)Gv%xRy{mW##VU͓,m D cA?KCRژ%[j1C\q]<јA+- .L;v"Cc"l~sq<~ 5EZ![T@vo 207`ӭ`xOFFzҜ&~R7 e' igL{luly qRHNd}]&—WP.6{ 6zp`ZGR<:r$Z>FsycK'ssyxyV!Wq{ e[ijc,/]S=iN:ؗw[~ocFvc&2O{G&*)#qmh<1WlvqʂvUHz~Fs q47-8?? 0IVF-(|{y$v=i}Xu$7\F iN˦) 1i >|nAWsxa=_*9&KkiTl3!;9wF8Pw1QǦk9I"ŵHQ RۑU8GM.[R$y$~U3NWżeOkk_c/a[#'kuzj*L|@U3Gҹxϖn2:U@9iVQwե)v.'$W:0@qXڽȎ?=cr {cj@Ugqc*z'KTLG?yAp8WO֥$VL8uķPH3H:zX.23`WMg,E^0LOqJu'I꣩`F^ 9Uq#`0+Pft vf{(J:#8nJBQ', 0z [s:z* ́FG_*[m;ytC#,~Q?yhL kJґpq?5?ؾ͸FU9#9*X$?gD\ێ95"vZNN%X}[$O\Հ HTdҜ.JQИsNv~*.C~9Zf ]wG ?ai.t&$Fv nһ8+kaG ˖M\&CKr\$=ӤP9>n1I+3rd$On3RuEu tQX<ɶ;ʼnݲn ݺL5̖a79HF0-'"U?;pǑѮ ݑ^m~v[ai݈*}g X NbOw.cԏPiJMP`2;.Bh粈"G<8ǧӧ@.'V[u+IFR ⶯!6 IJ2d.y 8=!iG39LWʓo =>QSDsOuAem>3853Z|kUxqJ?xFOOQ6M9f8đ_qm,yj;B;+ <̌dk[G671~g=FE%Ƨ Wr@Xze[Zh*"Fc=O{&W{6CpZ\aXMsXK (~E(@Kna[N6\,zS|dJI=jH`E_"RVG=I0]*k1Ir%:tck% (kHI $R{U+?H :Ep#>rdj dx#+:cT$pEsm;y|эLul33/w]eYcP&'FGjs0 K|[gvE@~FG#ڤihC1ϖqwj ̙% 2@U68 `=86pqӏsOŤ{3C[[In"ȳ4 gP,3WJzFסCp;f}? k^I̮7 ueMGH)Y}$C^V!FU)Jp9;DU˳`0;}kaJ˟+,sK_5|G;hT,mXQ2BmCSO֦^ZYdp&@ ` w䚎II׈1*7 jڊ CGpUAbq+*|om+qnSfhY${%u(KƌRU$?Q<=*/1 ȨaK2iSr\lU2tMnN gq]"YD*@ƳHFX# ݳlI0Sg"*Z \P+mEp0~a1\*0a8)km*)ԟ-}+ֺ"3N̛Iaċx»}KVٔ'kӋ%$9uv^,6qbיOBm̫7( z98wM"YvἳcWTsXfrk~jF(qQx㞵p3po!uۅ~2bMohx05[w%}cyr*}ýz7vr6Inz0?B~KLwq={?QVfv_Ҋ,O?5xS{?5xSݺĪնgoNW=GNvb$L|>-%V;zr:t8jAFB}Rl d~4ˑik$KRGSÎI"$3, jTQv [9qzJmZ9. Ks7ά^ʥ-Mܤy8N:>$h3/0 QC2t\ $YAtQ$hf1O] vm#" yjweϠ9v;pc˴ dzt isjsu lqsFmI\}ǞgA:G $XeV~?t'׈o-zuϑF{ɬox?U}Nf˱ ~wn 3t8F~Z}M -d2tH}x?,bPjuZ8c2g֙ ,;XJ׺5TQ}3JO$'7[o9,IY*"嘓u'=+~ԦdtNA={*  m~ >xs=$e6✏4Kۈ~Kǝ!{Q-*[AgfI=kJyu8%\J^KF̹N3"(8>sk#8֔De#DCD8Ao^z׭uV/||U^ӌʵW~sn7b ^8Yp?^\ 0q{V ,0[FsVY^:\Y7PHJ>5o k7]ŎGʔtbT9pQ7/*ɤxjQɂ$|*6PĜ8rH dؖ>x@ sy5r [`416鮧',$b8-f8,pk Z[@ZEYwn.x1+,aN{t@. \sXr\H9Nп1'U Ji;h[D@x/׏W&D6\+s.q"A?1|t̹,t7WIPO9?pq-ͻiT1zI}1C!=>Zqag1\uIY$ܟǞ>nN޾{F5u) d`;{ד~(՜G1t.@#zEtzP۳"(*! p}O5ijjBDk-ܷ zwf}9Ge*kV:ֽ4JXQ9<&&) c7*ngj6sA[P6eZ|8 qHK, ,Ae,gH-ߌУYd)@?{bG"6KqwT0F^r;zױ6?Hl1ɴ&,n$WiK$-I Y1 czj{ePfXs8SG8"K_"=A.S#wOOnZ͉nQP1'Or02d$mN3X\XiZ\05\AX$h냖ss덭{= tO"^)'ܱ7򫫣iyQ؀6aӒx~U7<9cim Jw<Z98~EsLvz\ik޳~D*0squkXE0^F9$׋^,t{ srpk;lu/u\]evj8q!e?{x>ՁL[i1he cqœrK*ݿx|r?*#[繎2v#"@t;{T5tE7\ls( Dϒ0d)inS F v׵sZ;&PE+<,#xuXlgGܩI?tm@dy,BI If[_\\ˤP8ے~#R+mU$PNoF1{h,nsZ Ko]ْU'\+u=.K'.\ZcΕ K,OĂv0p1鋪_ 4;Xc*LzytY[D!sBr3%O?~{89Ln|KHK6cq^U, 'w&s2)VPsN縨t땺x3R9.H {cS2M"XU 6c^y]Xgk/m Kv>PAZaHF~x^vZS^܁%Hͷ6qוc5X+tksyY)P3x=ݓ&<8?0< QȀYVf6yYe;Xq˷Oý)AX)AI k3$8ߵ1{u]kKO\Lv!XOVf4rd9QK8ǘsѴ7 : \8={V+uPrsП]y BO֕L{Rm MKן|x Y2|HcҺ *đ"^֨8 cj!sI|5jc p$8_@sVe2]9r09JǸ۫b;ssj_+/HU` sei#50_}"1/PUlJv{f`p #=)mCǽvt?nZ#p+ v]oi6 AϯLq\|FpdSz}+ҝHI9 sOםvN~"T%w?Zj c?c;RW\SQ7/Ĥ#ak|l.F1mF~#F)|$ˑwLGsч_fC;[/CE_Ҋb'U뽟UnUjzYJ3+ޣCKKWѭ,#0¯'p`_ZޖRǷ#nMY&*9iC랿ҹ12QH֚&mFA=kr es ֔ Kyf2EpƵHJӌ$ R)25GάK'IK5ؒ!'2WzA/xxi_CT<5^YDAuGl2ATv?JkIu!]A3Y"M!dt8cg yfm&q+_Gpf<,pˌTkj54h߾:%yl'<נ yZ)7"_q& c'X鑏ҦhyqM( p==Ԫ\'4W'6/ Oqsa<'=,˿d ă>vwl=kg}kV 67 XC{eƼn-VHT9VU*I͎:\ VWc-e6hQ.R 70*ngs&Igql=z~uv[D͸7wW?lt˹mIT! 0H/#ݸʢK[[he3fIO~x'Zi$he;HR%}ó8n 0R$OVOC過Ʒ_IEk];q$N;syJMW-x+LOvE5{ib3.>{z5hFr"1ڼZV𼰱$9<5ySd]L  !qs'"F.XӨ>j:9M%fHH|+%Ti$AD(7"X%%;I/Cַ-ⶍpdv\s;gZM.WZAĊYG;FsMhkRif,w;;nWVF|!5Iha@@9' R1g* ;+ٮu)/$>h;G =sӦ+`6yhcIYFA.0ATmKCNs&'' /N2p1fyiRK}t]:HI u=J[@bO*4QWY%+շcpnkAΡsS8r2@UܞD(B;AXx>#y$eD@YrKK"("'=Eyo ɇ$Nsq?Vu ]vC: b0;=svy y(ٲF==3?P+cs+r;E;+Y~L\`O=)rsZV٤ 㞟ګ^,wqB?{UM;քdd7JpJ޶bfNzfiA{쑂؞3֎4$P2:8b+{ng15uM\LUBnG'kdhF$H<} P#'/ӳ E6 $݌=}ɭkQBYfhr{hq5j["eݹd @^mH$EU!^k.F1mF~#F)|$ˑwLGsч_fE/CE1 p^*T p^*Tn*m,ӕoQӡG%R K"d.:VQ9^:dxܼڂ &Mcg} 펓Ac7NJ *S4V\g2ULON+e.o Ó\֢RT?o0g }3\P+ڝV\& H1F$It\!͐5Z>q.j̛H T$smjwb_v'Iv9+ Jr$HAy?N$/ =O=?^+a[HS#1-n`Nr+ކST;|j:Ǖ O9ں &UY y?_ּGKkKG?8>*K-۬ cߞ+N~Eds 1x֋vW'~p:=d_R+yeD9 <ұ=>lH&V 'C>^K%G9%QFT=kun&$d ~?&[ue ; ?U3J7Qae4dkg$.3}ik'RP]\}p[,12I_ V۟~²|AℵHgrQYy$3ۖThJj}KhWvze{]߾@[ dwsEN.nps\\jv z}.g!Po 1=FONxWEIPQ摱kahUӌ`chbXZZpTy=q{gSޡL+$y #ʫI>znLsd$py TI~VۮRH5bV7[=O޴l KhiG%s;g}],DFwd8Y Nc+Hq*D .@FӻJ1U.v^' ۡ")8D8~QvCWlxOrr p8Œwrƙ&/u<|.I 1Ͽ] KKwTYӓѮ5VL$`nIcSbaae.#'*\7$t8+#vǺu{QNW֬VѶ|q?~ՃNΣ#֪:Nq#zt)q XPɑ}1?!Tv"TJcgTK%ͼ$"H<-~,$^bg_dsG1i\K,mHI؜d\ .ce`@xfشj$~[G Tҥ^F,^,jFE-l4Xc4Kԏ\kFJd")e߷ 8ߍW;n isvK" {Xʕ`qۯL~o $QdLuX- .>΃ qM !ʂ{@5:=l~zRp`À}UŤd?,AD=~>CG 뀷Q#neν6Oi8P>ﷷeVI+8hIA?V9m8@8*6&0c*H+A}*o`DN>^rN{qX)NER.bYݪAT7}gU9*rYr8@:~#8+ΫB BnD6I)WmAB`He#,sOZ cC=>\ZҪ{%ܪԕ>$2?:B\Lgۃt5ihgr]bIVuɷvHiֲG8u4T)IPZ6Tn6i=w̪*NG?ΥsϽT^KP@=Jp6\te.ZVm z.T`Py2d3 P\dq\}n"ɴ˦9ecNr%ܱӯӥ[#ꣂsDZ馧Uyla58> e" ;gcc3k33wcc\|GC9~3W4G!O6 U;(Vf9 :zk@17b1㞽Eu ?-Jf{^vývp6te܆H2m68#v1&1)d[9fSvg?jBXc5 (%uI6$?,LGM~z|hOqk@՛:W#WZ sF޹uGlIir?*O4WKLwq={Fk.F1mF~#F)v_Ҋ,O?5xS{?5xSݺĪնgoNW=GNWwYv@"Q$x/"gT_ZޖRǷ#X< ePޥutLl+A=]JUm 9w{uҳ.<[mY fM^-`HV2ORg_=4o!PB9*>>ЛO{{ [^XK`DrYaFdbʨ$QKR֡O$nIxRk*,m_  ˟γ%wE''6V;3(Ņ9"(vЙ@=[[,^^8nNNb1ºcˍ94m &i(-vqʃӠ`?7Ol4kXc_8sn 8mtDby'Ӝu+sRWq`1T'2$6#/K𭔒]ʯqrA8;WIB#iU|=fԦ̶ʭP  ̅~Eei>(uoM|6A?;nrsTevrJrx}i". 2m]* J'&EItX w`ў}Ҽũ9\/jC)o -~zV[xr2^ݹY vrIz6g,}#n{~=k#_׭PGpmwzɰD XԀIrFJ:pWl}eVh0ag ϖ2͎Ӑk[D%̖1U#!BOʻ[Tc!ámOArO2i $"'`v1N3WS )SvgR.yFw5a2kFr -n?u>\ 3dq<qQKm^ΐYR̠9?Lh=cc 5E HY"aׂ;tX;xO@Zjor֖Y2H.H݁Z_gk:TУY|uHǾjM檵ؾYB8J ga8WF/>XĈH9ܧ8 `d_jSx{}ŕԬӌ )F}9.O=tar0z9xFRWl !?Ez<$1pAt1Y[6V#,4ϯz~|K$hfGqr};qMq[0u3cX9[w"̬n4+-}ӂ@M8>bqڄ'2:K\OL㟭fEuxqe*OLxZKS)'{Jh*kopLX\~uMy]uƩoC崇%\n> +h;nqS5 >Vޯ!YX882/̀9'zwg [4\!!{zNTđqϭoϦ<o.˴/r׷\7Ќl`wR34YP&o]*,G}ɪb߸ca0'&UW\NTgO,c۞C=:8`ǿT!P|\gqI'v[?)gҴd3糺6D2v[xݜS/1.Ӟ;W/< b>ճ<]_daTzWg\8;SI F8p <ҍfO9+N-ʰ}{U[(~e,qZGCb=+D*9r sҶ6QI(oOޤ:W6D$%s=O#he;vFfd02  2n%Z?%,[ Bpzt쾓0RY{qV)/FUBy3?to[r$fQV#D W&Ӳ.WPpA#Em4ܤNN*7c$:V{ZΤtQkf>12–I6ӯOܽз`OA\}jխ41°k[2p߽!RgFc-g'lɏaz I2zWEtX,%f `m|s7!{DFZ*x$N2r7Z չ`Do֪HؙE)K{!hd'ܖך-oC[)`^64GkO*JpSuGZY6Q%[Fr]yS6&d%ח$+HZ(suϹ|2kzҵK[P#wVgu_^BS&0I_ls注5Ův\)|¾0 ~@p3$cӾ!6бNF>f\1*{ 7@@@8* KIGsм?ANA=8z1-O#B1?r{vsAxCRy9R<*0 1U@>hvzI :*3ZZMhm;d*X( s{jLj{7yŠ_֙0i"$mEF&#LB{ ׳ ?%bf;?ZӮm`9 ry2AP> t1f9cN=* Fد``^I80ةi3ԩJG==]*2~[yQ%zTM.XDe%NH tWK^3MTJhLvX37m,w+&ԓIpkWE%6UG_[[iI8 MoiEt=8ݜgUSPu 9uKoY^R9A\;epq߁l _S d*xs$hʜx?\+AE{E?dujaFu[ٕ[]p:|~8Zg2\U{zr;Z LexiSgB՝$՘od-*]B~?+Y?&kiEgۯZhe:ۂH Ivp˸zwwSӂܠx$M79UK[v6[Xe8'φ3m.&ж #B/VTHQpY?НMgj"@:#'<#SGC*MQUHa^N P@=qS.se5~ӵZ[VvPl" G=3U9 VVWsc#8*GQD7>P9Jj%{ؖSZ¬mD?`NiڷXJm㞝*E{y@9 n}9Yבi~s`2oquO$ jfCt1~C 3$ږ_9'l2 mۻ?Z"7l1bd!sE]ɰ.9!]On80 ԞΨE ;d=⚒ $1~\;{] Acwp˔8#?K%ɹhqrkV반Q0I}N7Rn-7̫4XvrӠ@e #RVe>Vau5ȏa!Rn=z~[|H$8MU/]%Ӥ ƒ5 2xG]5iR,=iR= vCoڴxV{R# _5&kIwn(9=+>[AўqV4ˉ',1lq 3br,Yd_$EˆOUsܕM- ]9+pQFv|kw.oK6vά̿LݻW1F\Rn1#N_ծ4nOG5,+I,13I?Z#[Jҋm$qѿ A幅$aBlje#NvsEiY@J95 xVFXXΛ{3hMu;{K%S 28 vGIPWm #zWAi&0 \W,VNg_2F#쒱 w3y'w -O>ڇSbESYzHdx2 XWi$!V;TcU!mJX$zVOr+Ѧ2spA4s5 ѵa*ota1 < !)ƵkTod|{w<9qVQdZh{3"7c۲SޕkZids;ve]hYp@VCXZz\n>V2;^XYn,%w@K`Pz8*HYr1vSBKd^k=#'mjVa1;V Ƕq[~?m)ц RDg-n&ҥ28eQ3TetȥsB}WI֛qqvs .NsڼN9v7e}my )dt%X0϶Ed-N[ hdw`峲ĨKb^H_#N}eqV'Hf}OJzS Ƹ;J/8cRǧIci*YEry8c\jjLFU+ijB`Ecw|cݷ!UM ȐG]܍Q咺7htκ [CǮHB-Bedp9]sޜ>#[-i7V/D?QчFFU,,q/ :[%nkYO5İM !n@ſPgkos)N?\u<I㡮/ɥ0Esor)>L3ᵈAmgJmQƵ%7-Ɛ86,$>zZ۷KɖRBNV3u\e:f ռryU|d1P͠hZ%&V1glq|'tΧpAϠ#PqIYH$ /nޘ-/!(6{8W~ n:ո' [_H#1$H8p#R}'*zϸdYm2?.ڮ2MS/["䧖NTߘTt FO歇GH_̊#_aKFmщ'pHbީRq_dWP4ȲʈpW<~wy`sY:vXܮ܇fO!ߎcEp,ʩpx2V쌛]ӥr!O'MQ29R+d= :vVr. Psu=h~((=l^3"ZGcik d1̙#cl;k[m,+ uJ|Ctdo'HdIfmE4˘d`VW)9%F' tqҢ)*m A;t0B$t9rzU*zU b+PxMM3qJ뤴XcXc=ycǥr\SO[[**|2:I*C[mQ:ڹ+i8%g=M)bp@U YFAVYzXy Kĕ֩ڼJVX\ VrѢf(ZJw9 zW9㟒,Jߋ2ZFFN[v:t;jy#Zg$ISp N3G>Ҙ<׬y^]eۻ&#/uqxIwi#n6c #5Tv_Ҋ,O?5xS{?5xSݺĪնgoNW=GN$G_[[J[oK)Fv{tqsTI7jInK+ƣY5&쏕E-4#I?.i\v#֓]6EbrQaPFqZE%ԦG4GBACVA*^OG欦#QTfI1ݚuo ኟqrT`}k3!ʒ1f֮Gd9si}2`Sú-T}GZ2g |pkK`8^*@\kzkR}rs[֞/?(ccNKNplP&Q,@=G#]41m9!hrIp[mb z,݉IK :iU <~ZE_:!QH@`dx=UmY旒KulUj\-N|y\⼌LưeQd21wdN[“Џ P~\Z/!=7.3Y8JaѐDOdw ?վCs^.xVliV܄PzVњ0ZS+ i:H*GZ_kHԄKFTGO ͧmg|Uх Hj2Bp9;Ͻ]Zb`[ٌ*6eq鎕.YJz]7v8fU}?l_ _bb͗ =kēxB8=TVSʍwĨ]ISUWGyq}W~VhH4\|ӌQI!cyoab+_Or]$\$y~@ [h#ÝSӞcGuXոsv1գKjUB?\SsWQj`ԼIeE!eRU ԦK>k~ e!"s݃d885yQr*Y y-hN 1á溉cԢti4PZXʸ]:-g_v`IU6)$cTs+46RW-D |!]x> `M5Wi A=^$74JgFoT ;9͙Wu(8qן`c⚕q(Y# 294'q>ǝ^+"픳Be X'p!QR=N9^%RVG <[X:a*z`᱌ޭeܻЩ1ߎO/RBHe|q~ˠxJF-DeF8+jjVqճ~5Kmi-$IrHo>y-,KulPŔdA6m!}m\gm86;P]BX\M#\)] M%ɮ/d`˺}-?1 p8#'FUE3Bv q\XkQ,$BOW<.285ia(REH 85G-E$'ak {[ຮ@~}}Dkv wr8'89T֬1GbG8r1Xo9b}3^<(fr34x%(R A-rE.A\8zgy3Ɵ6@P۸\3f,W^F}feYV{m㐭֦QPHQ\*GDR%BvuMܲg)w>\cElF =1X>6n qV崣uӷX630L~)%L${FIQpO8CKLwq={o> .2ma:fPQE/zg/z۷_ZޖRǷ#0Hm%V;zr:t8=i `PM&i=iee/Μ.XcsRJM +CftTM+uW.#qZ#& E/AK`6Q@ SF{Kޒ~V#hXK铂CqVQR0GӚ#֊N(jLY'G*V&i,]jy{mnGΦh_=59!.pGQx|Z\BA(G PrS [>Y}Jt9tW]OS%1^Vc1ޯYfXkPKXytfDz{:*Ք|7>\q\UZx^lxHݓֲtѥ-w % a\χ,vo^r tV^0_/+]zL(_0tWVԣaJq(cb~$ՓSr6q3VatQrq)Bf-pϭ^Xq DLOlف?i^CCa7w@6yU\ +wFk8<꣙${ᅙ$Vm~-cT^ 2}5#nwqsQ4ar@ϥ gq|`vV9ݹ>q?kxMό9Xq-w峚Z-O0PA+:՟.Ҥ0w*5PvHpҳ } wjn9PpV998*#xqp}b۝9h.ch 66iq.4g?.)Ѓ8Ug~`b"q.w\PE KxGTrOaڴu]b G\#yj}1y'ޠWkXn K~0yUiHKW\Y-Hݾ2pz)}+myqbux#szYt 4s<^h+b?| *kWjR gbywxVw$r #קxѷInc\Sz p}1O*j&zs^IIwi#n6c #5Q%ݦ\b8۞=GP7QRYYJ(T>S<pO]pO@vVQ9^:d|u_bۯJ[oK)Fv{tqs$ C֔uMi=i Lނ)B@ƑLfC@{Ru>B)Ɠ%INh=(@ {RKۥ{P ){Q,!i) IN0:j1_qgQާ+so @6VV)VG˟CKc}ZXRG5:jWQ<8$'^0e585{QZxhX ~~o¡C86c)]r1Xh?#h&o0t~jÆ+y nJNyړ$hZ=M0O>px߽Is69Z;>07QfkZMH#q\'Ѫt:OK6XN?B[w>SdUH{/Adq~? o< a{r V]%U-$TkAI cO`O:q@swEZC:s?U+e]cwUFltV'樈 #ۀ s묧aUxkQ3E+cqT&/ mY͞T,?1z|DQٌa;9#oBBQ|­Z\tX}6)ՃF iΌ>ʁw1U_TNBA.ϓu2d` ]]υm&Hl*'PAyAqA&;ݞVf`PԌJhϰdRsڌhSG N 柅 (2)֐N8RwIZic sNR@ 4SF(rE/ZNԔLPQ1E'=>h)*̿CJ(wHa¬G),zQJwf]ɌI!Ub˔p\)̇*H)r|;,kPAդ2%?T8n70_ҴmQ} $|9̮k'RS*Y ⲕ=Ѭku;?&\_ yKqMNFA,bo c9c47s$! }*d[YyT7{O%ʍkjxbWe`g88kϧ5Dfǂ 1'klu[?[*]F3z~Al'g(S}$Ev s=nAhdǥ{6rNdvW𶗨hnPxRlZ9CR4L3ק4@ti5_x"ضA煕{}E>p>yZ9 ,Sp,t[a4v#<0qi/[ mQ dX%uG5ҧ+3Tѵk%O_^Z4@ vetZw Z/c8!iN?z҅>HՕ8L~]q18vL 'ao-`tL~]q18vL i. 8}~CN _;B}o˺t&'w?ߐ铁t7a`:got>O}Aƕ}WL~]q18vL i. 8}~CN ƅg&):O𯬗L~]q18vL i. 8}~CNo@?o˺t&'w?ߐ铁t7a`:got>N;ݟ)¾]3MwXX}2p.,Lbqs>8@՛_^cW_Y,Lbqs>8L~]q18vLc`*) WL~]q18vL i. 8}~CN q"(:@WL~]q18vL i. 8}~CNO#o c _[.,Lbqs>8L~]q18vL $`k'a K"+e4ߗuLN>ݿ!'o˺t&'w?ߐ铂csg7 G#/¾]3MwXX}2p.,Lbqs>8.3G_3'#/¾]3MwXX}2p.,Lbqs>8coG_3?g t7a`:gotf3:dϑs YE?W+i. 8}~CN4ߗuLN>ݿ!'g G#/¾]3MwXX}2p.,Lbqs>8.ȿ?g ?o˺t&'w?ߐ铁t7a`:gotp>EZE?Q@𯮗L~]q18vL i. 8}~CN /#/“h#Pg t7a`:gotf3:d%s*uׇo[WL~]q18vL i. 8}~CN >X];S|ѵ?*Satq+54ߗuLN>ݿ!'o˺t&'w?ߐ铅d;.bq^߆ I׮x~7Wki. 8}~CN4ߗuLN>ݿ!' 1%i醷c*Qk,/¾]3MwXX}2p.,Lbqs>8J/rY--Escz{`Um~yԬ.3W.,Lbqs>8L~]q18vLd٢WimPFCݏf¶,ιQds]o˺t&'w?ߐ铁t7a`:gotkm!C{N3T)7]tŞuz"o˺t&'w?ߐ铁t7a`:gotXx!}&={yx;^s(70M{o˺t&'w?ߐ铁t7a`:gotuэW>vC"8k)嚀n+4ߗuLN>ݿ!'o˺t&'w?ߐ铆.|cs~[*)4}Mѧ\xϔUo˺t&'w?ߐ铁t7a`:got*Iu%ovvn- 9hy -:4ߗuLN>ݿ!'o˺t&'w?ߐ铃"9Q"#w1IϱY]3MwXX}2p.,Lbqs>8^wgLQWcO#xt-'s2q U4ߗuLN>ݿ!'o˺t&'w?ߐ铄JھW#j?. {0tK}6f3:d]3MwXX}2qsS3KLwq={gق x"gGpnJ?<ro 9(,c)+X:bC$!"ڢ Q@ EP1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P1EbQEQ@(P( (?nip2-8.7.1/doc/src/figs/snap7.jpg0000644000175000017500000015702113351443023013342 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH ENC[sy%b{d AG]HC".IJiԈ]b*2Tw>l4M.~ШGiRMc< 3,PRGpݷW:²F{%٥X 1q>(AmpO迾j#"r3]C8|ϔ8+oLAwi,WP11NN0G}h΋|'S H.ǚkKl]>?) d`dOm{X~Ȓ5 P,H<k? O&{%R+WMiM"AhD UbpǖH7~3[yuyPa;X+:=]l_o?bAqP62Җ WC[5'³Go&qv[p=j^^$vMG *|Hܿw7C5gx|> kOQɦT{ 5;DӒkj>U4ɵ6gGY %ԔQ.ヌG=}(X*[_qW0i1Yڴ/b-ŕ<}qXLԞ-ŔڇB#;{^x?ȣM`&־CϮw$[f9xWVzf%;DW36%JMzw1"]mf,AP9'4#9dn6`rF܂ Bih2$Sl[@a*G Cֽ:K!rj?n筗*T]O>.KO[T${ 7tZVsȺPDϑ0i9(~<]_mcQw=lU/QO>üm6 MCph85%xWB/*7/mn筗*mx-YIUhۂ8 4RmË-UH[o/iնX#p27g#үtڬUh&)BЅBxm?Z~]s]1"fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮx?ȣGl=`Q[gx|>fۮ`LQ;[|zy'g~fۮU #Kx?ȣ6v0(࢈>ࢺL]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_?m5&Q[ 2):K O\"ФRFwKD[/٥8lv\ZS5[&N߿>)kS}VES8uj[ ˸X›Y" 2 tk[{(qq$oø.ܪcu5u\1xsoc2EwǦq-/.{+R)(ԤAA?6zs5|AXQq8su'ݳ8j>{<^!T8V9}3/Oǻ&bLF =I#S\hj}儲۪XOݨS LVDŽ`ay X"e  z8J5#,N n0f0)W8 u<`szv}=Y^S|9Jc Dzx1Vꦥ] (xX-~owCw㝉~wķZvZ٫jڵ'l*t$qg^/cJXwʓNФ0Ǹ۟[ˡnxbY6 TzNV5uZ8xKH:nid]fynqWjngb#{+S]c]zTXsޤh;ɝ c'q߽emg>W_]mjMyTe#R PCC7樱^V;(T|憎?6+/.!ϛLUh/Qˊ>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eSk?|憎>o2T!ϛLU>eLQxl ƄLm,2FEtF g t_OLi<-[ٖ'WBg0X@?Ivݝw6s8[UG-wI)̚,q\9> 7OMFc;F-fmO+CϤߚ->~k5wj8Fq"[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6KEoƏI5?ȣj8@w[+6&bop} s]n4ۜ"7!Gr^@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*tWOf#Mo!)_JY6~TsOၥw" “#?Bj4DžV(!]8J(?͛|.8<ٿ[ϼ?)>_]luև-QKo?mc-ɱ*dgo*%Qđ/ r1SJ+Y6~TsOVQጒG`㍤J_[ϼ_((%| >m>\EW(%| 7mћvUDW2Dp*ӊ![;tf~-7mdT/%FPF2rNx'((((QftnDE!OBI=*((-E| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>;{Տ[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_((%| >m>_[ϼ_( ۟ʹ }Q4ۖHcV6PJ|1Gր;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?JiRS_C$}*ŝffBI' O\"Ф;_,h>F=tIJ\ZC5gxUMt˿QF #گO-3?Rjt:ZE4pe uꃣ9&\ޔm:QĻwv3bjZ\OWL"(_ka9f6fI 2x|:eGGXo\]k52Xcw?\Ro| [?j" ).UxV'Q 6}F:tRF;:QD.5u',F=E^Ag=jzֲXFc;s=I5֟YY4ʖQUH =;~Z_ mZmRNRwfP-DpJ $#&?Iګiz<WfM=wU! 7G$iJgbYВ}IYUƌp\,cDoSѾLdL. g[̱In9wj1ߟa9{VSxWoJXo}]n 1[ZZY٧Ya,3xR}nm w_krd>tʊ?JlF)-nDQ)-=,]Nڤ,VKIXFB3H0Ҵmqqrm˴lbb q)mj[K@"Ea@&O>2 uv #NNkBx\$jO#~XzѵKˋ;QHݙBdI rA2k7[&+7R"ң"zZmf6w2{(9Y14UO4o~.p]6gm.Rm?0\3Reoί>)_m?s\̳OzLv5ZVaswҳ!lCx^fB?k:կmc6+{:*Ivsºlj/q#Wb0a]ƌyl.ZWaq&gs a s8>nVR#0O#CKg{‹o Aj \am<WϮXT[oûi8' އM|_愖dxH 8kȞ9Ƞ\6ziG"/^Hxԛ!uuχb[(眴VrZ:pꠜ珻֣B}2N{im RG"198> _/%j ^,3_G,+Q"Ʃ?#<ۚWPkdMOr7ʷ%Lkc8(ן/&7U_0@ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0na4kuh ZF<@Q0_ɿq]MOɿr@pQDpQL]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%]2ͧu?Uj6跩RLњu\њu\\coRAΥ7qBzy#:cC*P~`QN2Q`FԑЂMOE0)}>E&/[P^ϵF/[P^ϵF/[PkX$Gi`ay 8Ԝ՚((((((( C03 FG;A$q}>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^(}%1{>E^2خA˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB+ O\"Фrqqg]z{75/[1KdPᩱS'K Υ7pB)xifg2|F'#*I \en fޙ#kj_wk~sz <5L^>}_& 9:v4ow;R7{Ey/Y#GMy'5Nۿ_ܯ\˧j}دOxM+$68z.DJc ; D26pAVÓNsjzڮ'6"X=p5]yp\\ɩk2OsuN9ǽW5y4cC!0){mPx$WG|F%I sږM=kQ] *8c;HsBcw+j0m:HmbTRH cަ<ڍ͔Zf-Ū3K? mSW7 :7{Q 0I]˸|?x}+J %WR;mD{A! _JZ-RmwmLz}*⫛c%Ɩ v yvgiMk^kմ;gϓnw]s?o#N->׻:1>J@3=um^%gb@ ۜXsY߹{DZ,Ѹv>p8 ^hj^e,dܤHlaSO^76724 kn9=.uRKS@fLD/>ET~o%!u tl\ J9 M>s$04b}ӴTLa)GƠfXS:mNk^x{TZI5xΤ2AW #;F 7q0ZI<,6]K (2x'r^mԡH^9.Znb|mh[,Y:Vy wsEUӼukj6,v8Y.Ax*=Olqqm|ou6Fߕ6cvs ~&mՊA= ;|4Ã4u5[Hñ H5i_kJ$[X| ʱR1zMRX]5u8"XMAek3SiwϨ\=S  9ph 2x[i%>Z;N9$cۭ,1ILtli%x sU9=Bv3䷎:eM젒#xP9cs]ߵ̧tێ1~-vo/'83 d`xQmZenVk[NJcb`M!_SYZGg5'5:Ee3,bqc붎ח2j0G&/ՠڪ7q}[~(Ӽ5wwi'>k^JᎃXQzGV%%v_՝pQDpQ[.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pBR8O)8R3cP%?s(?|uѾ_B/\qto|.8Т3ĒpkHebЮ՚_wV_)}qOT5~s`OҪZ*iRTޥ64 hp֧Bs)* oMRx_pU@MnP'JN^( F8>lxU=v;{n-l%|NAoݵdՅ;6 `ozMK×o4SŸmx5,0 3myיv?Y}+F`C2 mRAF0j4]]=K)I]̬vЬrIb7I%:vD-4Q4d[*xUc^K"kb]dg,p:G_밺]Mbn&k[KU]Pkg 0H#ߵAVIM=ik ƀe* xMSӡRv&$+jCN e_˚[oEnt=F.Brb# qGTrxG{/XyKmMI6ŕ+4TW,; Tv}.Υ;6yn2V7/'zhd!1d:PW {;Z|Yh.&Xvc_(I`c$ իr=FX1n>mxYvA$eƥ%y)toKPO*Ee#)aGόq܊IfQ' n6a5=sF"+-Ac];H m)pOJxdw%sOˬEa0MJ]8SK)1]B5Z(Ð 'i5Яn-XKks(A~K{m,o>ӧ LdBVkh EsEA$rs)_5.3`Qu&n`1$Vψchο$Fx8|zI8ⳛͤէ]U73lu=jQTHkq EjA$26{sGEt0w".O$Z^ެujvǜd`Si&ԮmnLFky'F2W*+} Xu/"ZhEp1yTv:ݯ#6ĠQFG|S?~_E.q^iZH{J&teӭ#>l RT|1Xm-!pMHV{_3%n-N}3dfT-͘>峌cз(6mnwXǒ=HD(6mnwXǒ=H3޲"muyd.3 D9 |6CIɫM)Ӵ{i.M. w>RȤ_>5KMʎQKi6J࣯k't dXlZG;UDOnoRE{WO7W``v 25lREeg9;sE}; P FՒ0 '@k>“K\gk-lBiʜt8W [aH &qf4r-F[Ckuiq,]Y 0#Zvd潅*VԜ?5ZM255fxą$Z|5 *zA?U֬n5iK1==?_.3ysY)Sd~{š2E,zc֞l?m{'y?Ieg?aRW{c@,s{ݝ4lΩq1A{ExMWןM_(j+(j+OkM&171d0!V9+ӡZrIsH yu=ffB0`&iߎt-]{ŪCQʗ)#q zѷҧH8Q}Q:g4iG|\5l̡FEU2x__e]BLl c!?]=?J>r-a  8!YԾӅ߮y1I5;s[N;2$T #gP:unzZ\eE!.A#$/ҸKŚ`+D+|GOQ[c)l8駐r@ꭵfVU<40kWxcN"P(er9P0W8g^Q7adЩӔ-so{RK8Fc}v#8AcXXjWZi8r}&54;Ni`ligܼ;7VHlt _PSDi21z O#$18e s\xڅz JYo;co>>\twƒf^srgO#mwöՍ F7|r#y-׊ 6BJ8$བ{E*ʍx4 ]Fsj[8OZWj:ȳל?)4nPY{Ǿ@V:Wy ԍEspiQEdQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Z'sEoxgX:'sEoxg\7莼WO?;>࢈>ࢺA_y/ν Y=|]ue _GYŨKS(Wu J}"~\X5]?jUniUVH8t,4+eXv 󳜑qs=ydaqh`;+0kW[yye3F>`O$OOnUD:ޕk y~Bh ?c^qoy;7.h[C &4vPȻZpC;2=OnZ:|nUl 9׿5ZV3X\ oU9ۃ?Zmjl6@;A.?ȣECf' Utgqesm{BaK{}+O]>U7Q-VԳZuEJNb}T?>܁nAz2\,l<ǔMb'p >h䃑pq㑚mK UK6ᷨ{0dzSգ(C7VZV6$ ~\p'MM5މarCm%A⼛>$:ު݈U 1O^t@{8sKvyXTQEvEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!\m[@9[Vs~:_ ? 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@q=Վ 35 m&[ y*-@Go K)(I sjcy*B0r' yNؠ>s(3`S6e;4KRѴkA Nv!L۾ ywBWi9FzZ񥪲 W/nl"o63XPv}r>`1=]X\Gjm{_yZ?,O(lL{>Ay8߉2DHȍ+#R6Akԣ̫![He[9v'?Z򯉿 %V7XT(*J׸ ZcOk;Lk8NHF[ Iփ%͢ODTO"6mCWxW/kRi0U88;O99W1kf{NAme܉ v>LIAm4x1P:gYto7 F Ťo\HkAԎZ<練*yޥIEGr3cy}k׊X4gmp<2:^vzDnfV]@A9c{۹nd2O+w=ɬ/u/Rȳל?~:Wy 4(((((((((((((((((((((((((((((((LKں ZO /rEt6 buמ>bЮ՚_wV_)}qOT5~\X4֭?Ji0'tZO"O/rXV>R\4K8G"b)rncO^ I֏"O3Km Ys ]yc!n795oNngR2vV!{$ъJpDkׇu]g`3qGiMaQKm?6y=X#6̨$ :YOF'E'W]ϗ7?<U?*7-~be?lk "`ɭ$k%4ʱ `{p2NOO%?s渼&Ix千#aA7;AWq V dSD7 s2Mw[o Ǔs%YGq*lstJгԦ/-Ma*λvࢶ[9)cf?)o`[ [c$уǖ g85oxSTR@vڣ9?Tuy8nb$?w=?{ ms@|M@^[iӮb7\ \7ەKÃݓpxO'=w>tĐ&1}09x<쿓OVj_^(-WoL\cWKR;B%q1(Wvr^+]?bkY]zc W0SvXn&[?8r3wGևk?QS]/Γyybm!1-70'aO#~5|44j0ȸz=ivwk/d{G/(fI6c,ѓxY/#+VV$0*^` QOQ]KbIV6r6 |zfu&;Bw;cޟק+]l3*4q2*F|`:Ӣ`@m#FI.t@zҗk~?خ!EuxEgx/%Id@X׫. =6SZ&{xVcTK7=S?WsCwy#8Q`ikMs,Pۼm*7tߓw9J+6rwxbZtTdzuH ,k[5G "JH(w9:+:B ~tgm9i# |Rj}O?Q+,2Q#ޡӵi ;=9SKUɷ{beY0F3 f Ԋ_\H]2p(>QvpS;vhPrNs^u,b9yxFG^_]]jk,LT"<0.0y5^u"*4##=2>j<ܺzkMtVgQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ딿-5O5ۆkT#AA@˯f_t_^uמ>b}qOT"~\X5]?jUniUVH H]Jg̯I]29mW`DT Gs]RU)MgcsQE?_#׎j^y^ #R07, lxW8=s4K^Ih\gF{ ALzn}exGU G<72tg[{<bY GU.=NO[D*T,3CAҽ (-| kom|/tcA+:.m @lS>ڛl% Ιr$ vohYT P oh`Eww/n75r@&^2PX r%'r(-| psxVA<$mq"DIʞH=}I|5;ܾǑ,9fLc ʹ=;We,I v(ʣKU/~D^8Y<-kN|3o^ǿEi'1L-V'U'sqE/{A?d4RF4HbA|{wUatQźQe3)>G/eh,g>FXgU}S[nXyPy~RW瞵rT6p!FK gѦ "\s/E!ơkl^H{)Bp=j͉nVR$*ؒ29v"?GE!Ɵu7y 9ttvH.wqWu GpnxX! ϧZ-s5ibhdb#+X?7mj\2Ҽ'fl3#ך҂Sk c;3fr;AQISVr*wYRKyIx)nR<8Q\SO_ E q*ZnXehK, 9+_y~='5xW ٖF1.m5iB,^KN9]]Vr*2&bЮ՚_wV_)}qOT5~\X4֭?JiRS_C$}*ŝffBI' O\"Ф;_,h>F=tIG)ŧu?U©\'_4跧H ;UFz3 QR2FGQچ3\|=֑ζRH&<6pcu=;F;+.4%G\lA|CAė7׷Rl־dΙHۨ]sR\h61ۣ8ZhXrIDWY J fk[Ѱ_- <45; ݜuܭT cgom=ݬR;sy%vyȤ*y,&?ޑQROs}~Z]gjRX3M\`SREūuOR?;Z@fxUHE1 8%P`qԊ9?:\ZJx] iӧNo罏?rNo罏?r'֌Zxs=s=>dz[ϕ<c~Oc~OD'֏|{{z&O>}^?};{ߓ({ߓ+2}h>+y'79G'79^FOW??!?_9??9?LZ2}how 'Q 'WdѓG}o>WNo罏?rNo罏?r'֌Z>[~~Cxs=s=>dz[ϕ<c~Oǟc~OD9#4}^?} KI3gvV_Ck}{ǻ([Њ)I0$LE>δtY!/q1ҨR2@kRO3z?UhdѓLF~u/T:߃VO>K?ΥUFOgRO3z?Uhdѓ@ԽS*^~Z>d~u/T:߃VO>K?ΥUFOdݛ߱y|){ u?unyMS((]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_dg1T}0ϧ[J%axS!#/MoI sAgژk$@2\v=?~5[gZO*ñ^0Xa9`n&X#3?Q_4fUUkF.'F.'W/(4n{F~cgۃVL ]X O*^X O*Fio=ȒycE{IWiXm0}L(cKHI> ( ( (*e9E%̒Ȩ1>((2Pih 0:-Ā cz\LUX+/s2T}/s2Ub8S$pf^d榢 ( ( ( ( ( ( ( ( ( ( ( ( f(((((((( ڏn*5ks\W%ᮧ@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)*R/ JG$"EY1;~=r0:yN.m?f<:DO3­D ^[7l\fkkL7vE~T3T{-JimHh7$sftB+QQKY qiIezc%1 X{+(nڌc ANI$[]ֆ%>{K{6ȄÒϽQ+ŧ32H납擑Ԝgi[j68ǖlԿzoؾiL<ٟ] 9q{$ֺzt[k.dl#H|Sn jZծc-lGV3Fܼ"{UkXq#(1ޭ۵𳘔63M?/s4KlR T珘Ό_[-ʉncʃ[7O$tVrBEX(bUO| 4Mt߼@zY,Vmxilgw/Nk-v?-궫ǪOiqYK*0sHHhnL{+01"29rp`;Uo^]0yP@u +yPIrhDlowlmApR6i#HsZ=۹7bc~_z[1|COjzat >Φ4bB1;G#$ ֹԵxtőԮRƫg,~`:_jlW7ʠ;Ā1t&ⱋSиx."YbC9|\``x^:,[dr!w֭]k:j";#Mϰ9 4gs|n% Zy q fyyn.T%vY A;]yמTXlww<Cj,iy',X 08s[7 |{VQC0>;zdLVC#`9N~_V"Եm Iu;\p7(R;xvtχvҩaol2|p*Nm[h|<.< *y ME]$+Kj#1)e9qZW1ukk?9t$HEp ẁ;T5JC4A U!$Gu I A5<)[y5-FH*] 8Ii׶Mu3\brb[VY՞SdV~F.7n!H /rAYk,QƂM6;;ČqKw{keEƱ,R e2/|;ms4Assc,0 1t`}*z]/&VtP}-]^'l嶕\0Nfo淕W;^[wmVC#`l5rk0Ed&f}s+裰_e(_#=E3FvI_Lu5noHT٦(ҹ#cI[7֑\YYc6`ߚϿW˧{wnl4%9;vR3nW9uX4QI%> nX$1rGZ~Iy| @Wh N:;wpKdmnFͤp?]44?8.<6wcU]QE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@&Uxox:u&Uxox: e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRV׍lB,KEU>\d ]BҢ28Y"mXqЃnfݲU@y-цQRs8@h_>/l,3H _K/ ?Eh_ _K/ ?Eh_UmKx.ap7`\0(}_Y(DݲVh 2In'IdhBEc$v'wː{w PQ)(4H;T[p;((((((( TR2&=0(M}{}t4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@o=jbf?[xGڭ_ث4OV/Q*hSU}{}3@w}ʤ0'r?λ-PĪ77}OuQP.՚_z^{//A?S_)s`u5"~UէU[ #/ JT%?pB_qxiqAd|#<6 VKZpH=|ޞsH ǭǭUhhHҪ#36FI[yAd3$^ͧ_+FPEFTϛx-|-(2?g*;kgI" #yP7][hImrC%Ɓhv! ӠO[=[X=TSsrln9ϭNyz%Τnan -QAR6Zm&۶y` *uoŤEogA`]7<+]~v+ioEa-?l!#2 +-w?-閺MYndipqGb{f~]'W:FaZAqwf@(7n$;k3 )90HrCPEoM-qĒn}1SlHWogg[dr8]E-^KtinaGxBpJ w7/!P`o1jm-oaI'2E4(f&SoObZ#d}V?ek'pN~f-c1m&iCmg`un'm$m %3`,ƈ?V׶$tѺNI).7ojK&ӭAKxMc9a*MWXxnm^5HRtr|`w-im?qw!CLjv8/$/<1HU`\g oyD~~;h<ݎqq/"lP9fOsRS{ (Q@Q@C)ͧu?TZ cKѠ+6I퐪z5;Db[iX7o%Ǘ$e<Ҵ5m.VH,R$m ;*~9 7ZÉXEv.(ui,'Xue'xF!1j CWծdim-xi"WV%wg3ۭmc+l7ח-or.RIYw(Ңܗ2cyF4nwZk?QN\O+@7ϴ_Ě>2Q֢KXa[IFPYĀl98s[6\vz7 qn^VSw=8I%󤶍wH*H|B][ZooWyy֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@Z7ZѼ֍֪4o4kxxZ=h=jF@#7G}OO|\dʹ tAe^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWqjRU`Eqtmñ?Ƚoo.Q@{?]g_o.@{?]g_o.@{?]g_o.@{?]/{?]\*k/\LbmPOS9=ժ(((((kȑ껎O: ( ( ( =(ۑc$~5-OȽoo.k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(k(2i&D ){?ʹ uj? M?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UWVVq "/ J5.${(Q1q{VEIFé a3HgK@/@r:S[T>3qu~qeMG ` `}jZ6ZP\2(c)W^>ki`2OKzNc~kI)1xW4-/!cx;SyakYb"Id\˂y(6}s RhAiĀFxگObu {y*#wi@#T4 ^j2 y\AS6mُ#O4u]Wڍ͵9X].hWl`r9C*Fc~#G= ѭ٢mKXw`6I,Ay MfMGѧn$ynF''"UGg&ךPZ*hwꭵs vLg%խ [,s=ZSxRk\vMf&GrF3Mu;2I&k:V~ɶ.Y)13$sٶMm, YjF>S9ԚZ=/2K5ݥm$=ݙO&L(roÜ[ھk~d 9ǶEhܫ^ڠ$`?Zep]]c2 nsޕN]ԫ+fK' `рP۳3 KA-6UMfHCՔLֿ]?kgArL#;, Ro]ZK{&mZ8ZH. ]D7y洮3gw%Ԧ{;$nE"(PWA=M5Eַ hԪ $~fvDOeH'k0&Bۛ%~?ޡ='P03@ /ӠH o~QB:+ziyumwQZG{舸hYw:vAokutӫmx*zVxmFٚ+%Px]t"&yVR_](^`aXxYi7X8Uã˻q8#+湨6H0A+D3B>cömm} a噰x?Iqc﯄r1N%bڹm#:^_CɶUޓPG*~`6y;PmmuyhN%ȅ.2ƴcNkGw7&\U ?,sNËqT>l݇A 0WGjk-/rk,kN'oZONQKI."{dVT``I=qyj',K_ĥ `}ixjϻn]c9W=:jJVcm 7KSq #!B6xaJv+ioEa-?l!#2 +GO<`h"`玿(umkqyq[|\pQ@7bcnsaVڬ嵣F$Qk1,[ЍmV#-+HF2H}@}xFʴ uIgarx!83W~Ӣͦ\_]̳)G !@JOga9_OV=X>A8cjT~]ɜ37K!W]QaKb22#^wTH d7?H<}۳v33jku=S7h@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVs\W'ῼ?κGA?ɿr~ ( (_y/ν Y=|]ue _ /EO@ pE=AsTi,M31ῼ?΀;>࢈>ࢀuמ>bЮ՚_wV_)}qOTQEQEV?t:̺?N ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( () M?] ʸ}x:` e^{//BVk|E1EtY*mګǍqOTԆ;yy@}}PH2uuAt?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*!,߸?>?&O*)^@cp$Dzwa'xs7Q ʹ}x:` buמ>bЮ՚_v֟m\SA5Ci6?SRQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿru_>7_ß}?΀;>࢈>࢘]5":+f_t_@ I m!GCcC2]i,jse<&:aQ\jW-2]iSVoOK?>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? z>)A>?3>ZC^*e?+7<`Z_?s33^*e?>ZC? zrٖ8u%;?>~fWڼU@_t}_ Z$Hn}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?1ZC^*e??ޛ(7?֗ϰ^Ʒ6[ta[;OV?ޛ(7!UkƥNwt,>m>[PzoGءƬ̳QUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCbQUoCb]@6ruԭ!` +0[ß}?΀;>࢈>࢘]5":+f_t_@ i$MS]K{%x<dFb;OPjv׷U̾zI)zw kX}G& #|y= aF:voNQ%GKX,VSCtrFI}RFΆRuI[dIK}y O}rks=Kjcg'kO]aiiZʱȲ8RDLmbnl[\}l^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U{ VT+A)L69}*}-[ʐ[Y sV&ށYGqcݸW]%Iʮ |I_[ti防+{Zu$+v. w az>n]>f`8Y3PM}:K<#N2qsՊHf>77} ;P/X̞, 6DKѣ"<4=jz yp:4 b:HkX1ǩdn5efg}(ȱʋ.N2 o@IOVEM.|ҙLWix>QOkY[b.-mt2vi_}?/;4Fb)U$ H"|+v e Է@k"k]S+[(m&ܓJŗBnnOnE. {fk1jSZ[]:B9.B\ 9'y(vn^blԔ+lzu=tFhK p6 8zvxzx5;'7NC I8^@:m}o˯w3n%-.{S]}.wi۬2#vKi$"鞙VʰYhc9Ƕiy{8l- FMb@1F9#GOa~Gow}[ACrjy"O Z-ICzUlXͩڃ>lkYݸ۵0*pw蕟sf.)ݑL+qגh<-OuG1ڹv/5|X eIhΠgKqYKTwWmȚWt|zDЗmqukq7gSst>^M \.wOQ-4tFDwc k+m=_lfK4[]éX-+GHn >RZt6'5nKJYS}J'Cp PN$ -lFK]h! )Wk6mvWRdb{FZ; hW}lc'֎GW2xuXĉcN hW]l=hQzU9olI;PgӠ mq <vK\ovz%"QPuD:(h`FNch6Yxb徲0'3oSNB/;+P=.VG[B&1\ ep'+:X|6ۗ|D&Lf@qlg_@u& ~б ㍤~ӭ~%>Dr4\nU=qҏ',KO5-C^EA.?~ѿ;v_~?vS .wW\s[}_3g=:qA^-`k80 s@E7ma5¥ d:Ƣ,t|pYTֿ[+(%_5~;\t1sduִ}&݈MbDWD[]7: ;/⻶rLъ=y4TE 0- K(QEQEQEQEQEQEQEQEsa\>w0}E}E1 VkDh?z(kldU~Roʼŷ@," ?HgoʍW}?G'ڗl[ktUj_Q @?z~?y'ڗl}?@*6O^a @?j_PoʕU_JO/G(R €=*=p*|EhHK X=oJ6@{G,mc€=*_X𱵏 lDp#r޼6@{G,mc€;k-;K{5cGu;HTp9^m$ٛہy,mcXw6ZdjK<_kF6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ˭*MkQV"ڼv?q𱵏 ?ckDL0d 6@{G,mc€=*_X𱵏 +ck?o(Ҩ57Q X=oJ6@{G,mc€;{*MkQV"ڼv?_&fQ$W?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckU.s,"ڜa_a X=o6@{@jX=M-y,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )hnip2-8.7.1/doc/src/figs/ir7.jpg0000644000175000017500000016313013351443023013011 00000000000000JFIFExifII*JR(iZ)( )( 02100100,C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222," }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?3EA40(\Oui2.2!=qZƖޏEjOZOZW_ O ?E𴮿"'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=IGړּSQ FI(I^) FI(u@$\kRzu@$Ѻ|.=hRz׊Ѻ|_Z7_OE'jOZ_Z7_OG-'{Wړ֏'x-'Qp=IGړּWQ FI(I^+ FI(s>K\jRzs>Kй%.}=hRz׊й%?h\τ_EھԞ}=kh\τ_E./ o"_jOZ>Ԟ./ o"E-Qp=IGړּ[-s>1K.=hRz׋й%./ o7E'jOZoZ?-I^- >|atϹ%~Ԟ}=kſgό?nY?7{Oړ֏'x, >|t\iRzs>0C?gό?n?jOZ>Ԟ o7G- [p=IGړּ[-s>1K.=hRz׋й%./ o7E'jOZoZ?-I^- B|")?h\τ_EھԞ}=kh\τ_E./ o"_jOZ>Ԟ./ o"Z?E'jOZ_Z?G- [{Wړ֏'x-[Qp=IGړּWQ FI(I^+ FI(u@$\jRzu@$Ѻ|.}=hRz׊Ѻ|OZ7_OE'jOZOZ7_OG-G'{_ړ֏'x-G'Qp=IGړּSQ JI(I^) JI(u@$\kRzu@$Һt.=hJ׊Һt;0Qp=N<05d~T:\լ|R 07#nCҲ5K.&9v\ּBJ\+vl࢏a5"T֯5Fal~l` w1wϷ " b s^pOBWWJЮU`c_VG>Z]lnُ]+/`iVa Ej%갭7q\,I 7ny_ן?ࢳ!Rd\uA[AvWBԌ-XuEݴ[2E%I?#8pִ쯴O :[ɥ̾qtBNAD-lpa@ מWxm}v8ܖt lzecA`< O쎘n0Ad ZZɚHp0GMqEֳCp`yV9'=?P\IqۤG;ā>G}+nF嶚,'vAֹ+H[x}JÈxO 7?(>Qkt@"/>Z4 ,.q(XgѸ x v:H$_bX?{qֳ4r; &u׭-QYLfpϻ|dcڒ} me{z֖WW x 8\tWLqw-2Gb8u@՛L6Ϭ4\"p;JחW/<3mũ[ZɥF>(\X?Q'K[q ̐&wʐ"X Sa~-~lnŶ3Ǯb*_-KU(0kII!Ãot|>mYI1>Pnq/<;魚++-;HYcX Sm/.uN]/ԁwl,4WS)PxyБgkK Y-nbn9RqOK9Dծ᭗L1Al`TҭAd ZZɚHp0G^u] /><=ܼMtI{{EDȱ)c  sV Quc=R#+blwN>a_k[譍wQ_-A'5]9FvH1rx=V%_ڟ;@1r8sև_g iav-81=3ڵKmu% b ۜ\C[.n{}:=%DRLwO b>۞W=k+=+=WHYF/.>ʜ#ױ ǒA 8 Lt.UއplԁuE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.7T[@uE.U#q*SPX/ꓓG^F>y)|XILD(Zi7o̟Mf7[x Yݓ#TQ8e0RO7VWb8~A+ ^[$3˅ c%}H5KW$*^PZ.u0\\-p[ ۬,tZeAp`&dF}*Ś#I*0 :OWR3jt> ѝuÜ{^xK||Q-Ҩy滿@Az>~I&= UĵTHC+\??Ҁ>|!Lj._V^/7UET5 g.QNy>5# F~fZ/D?0Vx^y!bph7QE?uhڴ=+Px H1z}B-mLKueӯ--sB\r1֫PQOaeHètޅw/b3{/.$qg2 AnQ@V5;KŶCǚZ#@C S , ;L׊(WKۣd#_&wg:kk=n`H]z Inu rcb0^inSYwyQI&.IA@7P"҈1+i'juwPE2gX'$Q`Գ lQеN-o1m6AQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@FenQ@Fe:]Jd`=)_rU)ƋZ:eJK:N2^GU?bN_eۻ1KٯplmÝmK&MR?ڮkcmk_B9!~[reےO׎Ն<9h>ehn:ՈAs%V:sHf S-C_f>m[T61Q0ʹy=*l?OE|E@ S 5uǵng:\{b{R~GZR OJӭy͸i,X:6WbX?cADrPA-l5T@Wo/χ M K ̄ 9Rig2KPUѦ! eXOݜy⋭;;HybR)*.xFfݵb W'J'*>DO#G#!Gk(ܧ8j`[Y$1`PLI8~=Lm r93Mz%߉'4]]cZcF9N?^Y>bRJ@m;/j\iP6FU;?\mNtQo#P \dcx]4m^ yAs?uO(MLaS33< Eein:O]MsiVڴk dВ9-Ӵå۾qdKxa̙(YKvF30G5&mM3\{d_|^mffrЈ%8M_3kDP_…^=6xMK;itƷv#cH~1s"[iZ^#UKy@RF pH/±ZVc[y@B8C@O}<5XY&#[.pWB( 0Xa6o$D-3Dr8ߦGsxL.uCpfϼFX VW_?OuxFk(ܧLB!y}0kĖv M)|T$¶/Ŧ5Z^V98*i'cFY-T9$IP$SwُEk+/j'QT#"W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O("W_?O_T9?€2(E|E@ S ?5O(" ?5O+{,7֗ q:Σ{CLMs^籭x/u2SJʬ2@'HڛV`5BbQdu U ^w7Nos! x|9\fK 5QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPU&4yS[E(25> ,,XYW;=̗0q\cT8Jc#CNozGl̷Khm h/JTz#H7u#RQGn>}4aim';1+7c$2Ouڭ]33A$ C}hۨϳq;ŔWj#$Vwc׭yu?񨥶}NGsZW,ZVYd8qF{K5KvY;Yf6Vo m$d!+C|E!h=QaKl^e{K:}ثZvX:n 8yUN9Q\.umu9l&smyܧzU3t-5C׶)no(uܬ'^u{]ξM>G Nfʰ 2292jRyMme ZBZFQ.sǷ_Š/\ B[;uLZy :ejVXny@ ڡNR(];_t}*+;I/FD 3ɷzS'|rEf~L$qޏ :J+[>ޥصx%%w2mGstvK-rOE+ $6*((x]犤i[yP"'dC߿Ӂ+cR[۟6G!` .rcQoQotW?g?iiy{VGQoQotQX{i F?Q F?WH$QXDH~(H~+Ȣk!{i F?Q F?Wdg 22:=dz/%GG%G^wHH^dGQoQot ==k#(?߷ ?(?߷ (^GQoQotQX{i F?Q F?WGaz'%GG%G^wEՏOJ4?J4?¼A{Yiiy{V/m#?(?߷ ?(?߷ (=DH~(H~+ڰ=##;jHOJ4?J4?¼=m#?(?߷ FwM̒ZyE$zs᫣WfvЖFgn|5_}o=Ϳo{-ϙ#zarzN__\jW7se"K` eP@ J2;Z+>(=xolI8MOjs.i_b]>I7  #7d4u4W 5UmO2[=-[RaFiD FH#zv_uVnsu-D1d Oʸ>a}EViRd#!r%ڣ81CVvw1V>#Σq-E<%ǟ%:6ZKo^5ż7IkȚKOʍ8K~GAEs.F*u(ZRwB@9!oPZx{k{}:%yϻF\(6$qh@:+.5!v,c1GRF%8=o_M~(!`zz)Ddj-jV om7nUH֙ҝD܋zLmzmJ*6èU-ʏ %6b)%[[ya6q^?JVk0ݷdg9mɿrroELM__ڷ7s}EPݷdg9N4{5 [qb+nxcҵ<97o --{`susVL;တ[g/4c?(\b<97o i+?Qt MnK]He2's* ;ԞЮ1RPEPEP{j)/QE7M;~^|#q᫻$he;bp6v׎)֟L~u ܎Cq#IP+ZjF0=ꬣl׊BMXH^BB ш~I gmB{U(٣SQ67dn1鎔] 4W{g yB+ 0O/$v/B69턉2ɹC3B#fa`yE]6kx%% :TϖR`n8残u݂Ƙ,A\t]h%ᅚLB,Ff2,.PF zM;t (((((?foo k_BZ|p3/?4w';KKGX# A򮆊 珅i~/kFk M7{yإ$u[tGC=f-"FB~cbEa_LY77\u{rx~tå}(Jy ,TI۩PX1_Z\jHl܌ca׊ܿ)7{}F8KH#-yOV_ ɨCw:|HP&Ӏ9rx~tn_΅Sh)\^ڂ[x1NჀ=jMSP}vmͫy_ܿrx~tn_΀Mѹ?:Z)7/Fhܿ h6Mo+a'rW %Ka_%\Q؎޽w/FD`#+Q$9f}տnUۂB qʀ; ;R֍giꖴhkWPvPnAgr+Qd4ɀİPsC\τ4k{WcH ^5$J@_K O#6a@Ȯ\_0˂r9bp=}խ&y8U)'9?~ӦZȑI,,p y')~Kj);+*"j2uKQN@ ]p>涱$dBJ x(9=*{oYu wqfYELYI!p;UIYؔzhpqjpiwG5g1dPӵkgq/~_wyupq[k8u(ESy6 J;ϟP->k^I&%|(#6a@ȥ}: $_As<FM %#,0HRW1wcmm*(57W,IljOJkzV5vSYLM#Sxu'(͛+5,D3<cSKZ閦_. BibII>¸`w(JdHv;Ջ;.KBB*5*r\+g<еm{#-/ey<(Kt!I ֥ծn\J@,S穮/_OSHⱶMó)i3֛w6cm^Bx[wm:f3 fV(HN~ $28 GLkm q+~y"T?"עhNKJwTr`CB9-ϟEOmg|*zE$hUb9N6PhH=O:[Y?G"Tw$.T"?HD~' >?ƏEȩ5MHAm< u+,ҸZj{">?ƹvw߯r cFJ2ak?Sh[Y?Ryt:]?">?Ʊ..eQ3tIk?Sh[Y?XRQemg|*k?Sk=CD[Y?G"TeQ7">?ư(D=MEȩ4-ϟEO (Qemg|*k?Sk=CD[Y?G"TeQ7">?ư(D=MEȩ4-ϟEO (Qemg|*k?Sk=CD[Y?G"TeQ7"֏-fͽl-8S\}u>U`(5gn *_4w~r-H3\IXsqtw6'I#K @fܧ>8BڽoC|_c?rJ~*Celddr3U:|}~[<1>pDW>4FZ,FOҰ4;FѴRi.oOrA2H\~ռm5n L9iEJSGD$JRF4/ߡQf,y###EsZ4K1W *菰lnztӵ]bɼW- =ܻ‚O7SjWa{z͋BӠŴ\7lf"L^1W?пi~sFQΕ_$sDJsӽwt{(vA3̟F4/ߡG#m?Эj(Pg?h_ BF4/ߡZQ2пi~h_ BCoWd1& ?пi~kQGdޯ?cBM1& ֢e=_yƅ@O(cBME{z' 6Qƅ@O+Z=; ?-i`-I"#Xه2 ~j6* '][Fu($KUYiꖴk;NTZ\??ҺC(7ntOBIOA+?.=k'j6.-{ȾNpHc'@C.o4cg,G)n-ɡE8jI-H{Kǒ9UI `G_Ze  p5%I dZZT3XZ\gR:@CFDPUWL8Gnyj.QvuA$:`Rܐ38?F>€*Z(Rdc)Vv+D JcTkƮdim~(:FM_rhlv[fJA5@GL`ҶZ>hw,&J) cmjv1^ZZ[Io(܏#5c#M oL WI,ƱFb4P$`+F-: $@Qj>#*'`9fXAelSn-0q9)*S寥Qյm3E,H8.QS܊bi1$[SB1IakQޮZIdsK/i#&Ҁ(KcipZ#:rXzyMcipZ#:bXzy-}(Ҁ)_j"F/7v2:SO"\ޠ~ܫ<2pA~iSpr:bfw1"j7˦Kv2D2GJZ+{Kf@Fz <ضeZMp]A]۵*|`F3ж-t6zX=6T@f)g>i ̚-lnTt'ץ\汶CxT@6%'16p1v]wb]Eo~5rIF qH6?%0$lIS̯a۩h-`XG8bNWܼ!1@$ R=+S)xɏ̍,38KݫG o޽bc6qjńjFmujeeP3zy10 ʤ 8}Z52g}w18=E2yEӰ-yҵݎQEQEQEQEQEQEQEQEQEQEQEB׻K\u>=}3 OfƉYG>ϸ*a?: Xd _-?ZMtrZ |/ѯ=3%)&OUuf]vi%gg-oDޔXy8^soO֏-?Zm݆rVW3ZEgbcR4ȁ͸N| @(֬G֫?Zyji@`arjzS\Ojc@UU#QgĖs7$2a+|)'x=*{/hk=vSX<2`|ҙ7;;ZG9h7s^qȫ26ؾ6&oBZ=IKIsv8lQmmoamssFkQ:兺촂<=ѫ=I8uK3Qnu %Q%Q%Q%Q%Q%Q%Q%pZ}wտmWPaZѬ;R֍0vukP>`W '-W4R?n[}?W@ԬL NB;Y鑑z${Z?uȿ {RM3'>%՛[-v~ >]7OJm-@=O>j?!ymq7kljY*Bv1Q'GPծ xYaH#\'oo-QM@VMDŽ$1ӨKQ֑ܛRr tW @q٥Ru{7ھ{͕mQ?PGzWIeo5{n|U;6]:y&^͋@A !*T8HU=݉[# 0I?O.k}yArbkv|.={Xyxxk4Q *E*!YoKJL{)@ Rt YQ`R]~EuOq[x}&PknQ$Cn*@GB3i{kOs{EHW člUJ}2K׼1x>dYO`qϽTޝ=ݷw9yc,1 /"m|[ KT_HufHћYWdPX6џA ɃzU^4̸*TzZ-8roh5kܕ'Lv}V!/5#tyGgo1gipl:=ak/-L:0pAށ_M/[DfOVfKwiw pTE$d 7wqj׳ lo +@qN heei26&LECg?COӭ4Ake KcqbI9$I'5]Xt_rQHKG֫?Z/ZhQE%޸*ơeZ2o2oUʈ~OWia(v?'&bIA,yu櫚PӖ( ;lNϥtz卒3++ .GǶ?QUR r3̨OɆ#WnnZUx[ 0A q,EU>U\b#R@R[ ?XjYY~zʤQ??I\3b(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@u>-]O//{_xzS/Gkqs,~X'V$Y>ƕqk0$+GC?}'y?O4}IO&v,4BB;FqR {DѬsdgC?}'y?d7F[>:y%G넓#?)8jE}'y?>'R@}IO&C?Եѳiż yp.9 p?'GۡjZլLLVQ`>PnO5-ۡht>a3vNt&z'i^Y;;R֍giꖴkvukP^Kjz]?W_@Q@Q@Q@Q@Q@Q@Q@Q@Q@ V~f_>Y袊Koq]?UEm?ʵ)eVd_5 <skM Ī:ă>SW>>$4e䞹^/:I:Fi@aUfMJKidU[hʐYFH珥pTͮ_-)[m+9LwcӏZ]2ᘲNaix^XSI*L XAicCQ~#ԓ(U]am~a;i<4^y2LqO],}OZ:;(n #aUWY3[pH^W߶8fsr~?HsvF:[qՖ(-.*Ѵ$zQV\k8a[gʃ#8GZ:V'Ew8+:%{P 0H&Δ3,!}nw=)}~_bj> Eӥ{ChnAqO-َ=4)@jc$be;Ic ŴMṂ"HOn}<LLnV`Co{讯Y%[[u@`N}{t5ƩKYXc,,p=:Mc|E.7EuʱF9lqXun.(f71# }}+]m}etLvEp(% uIکvlI2nݲ= ~^:Mۗw9+|F#3)t $1ZW[h_oV;0H93PZ8~?QOQ]^,חv`y(fGؓT{u=*-?[c+wuܰpU|C68~4DEDEUk|dxOFO;A;8b#ӣUDd~U^IQITؤ.5WvpEzt2uzdF+m`@9*ܶ_ؿ5iQ34|m _"O- QpWQ]Y-@{IM-y`Me N=/3q݂@|m hȆ'OY$) ǙclZa6ȻsF+[AKkFv LDzvDEDE%@,kR-ձ8Ɍzs\-̺jvPQsSdbp1^IQKPSfm,$>!73>vvI6{gNbhf :[BCBț#,B$zw?/W:x~gct_;;R֍giꖴkvukP+M'IpFcfaA<+Q꒴Vecih]>U8ox#\eqI~c2fǟ@ hZZռ-K Τ+(hg۽J{!:;i٭*]RX$w93Ie%yc-J)-@K0-YN8+ykMѵ_I4[٬KxR߉eT9gVnjnoAKY۝]b>vѳAU%ܖtdsy&Đg۵skfRA [f{O.tg9t)t_Aٟ{htEck6ysܢ6=pNjͥnW0ā$2S+?RѮuE8яWtY, npI2Ȉ(@ſ G]N1&F gizέxuk};7VN:+q{<,]1beVn{ {_ÿۺG_ U>TR\Efg' {Qяk7Zƕigy +8#3jrV2M+%T`J63k^Biwq^^\I XpB;P:օy[GوΘ(9ҟ&QHaEPEPEP%UYV~(#Wx$Es# zRIU>\˕Qe?v|сU(մw,0 &CXxgPye/3FjSiW y7s|aXW,rH?fMq '%- UM,\: n/'S U& j奭V6s H,_n㞵_ٳJO&ٿ%s|I`խ=XEuѯHaXgҜ.G6aLz$>q6o \)7j^^Uh7O%H[m8H~"xngEidk87 ylܒqƻٿ%s|GlS.߂kp;$۽4)k-#2+;l`vgS k' qk#x]lS6o \)'{~A|27n a5EP FQNJ?&YmJ$( $sbٿ%s|GlS.{_#& ZUEQd,9lǰ)Zgy)h[b.H H ?fMٳJO&/{^5 6&dGd+ g t }ini8HlE哜s3M7h͛W?5$WC:.5/XʰT %3"q[x~Q7IZiK}1Hx6o \)7jӛBG'.xl/Hc'䓴epGZ4Z=<[,1:`86o \)7i}AZ߂8F-5ydg54iy! Fw*A#]WlS6o \)/ks:~qhn$rPp Gp6Zm#HEЪ6G&֔`]NggMq]Xȶ q[ygtyepg'Qq\68ӥ7c^D'~9>u8۞GlJק-?_:WZ~YZ݉ ,zW$_[cqc)98A%tMMn`(]Wi2qk\oMfM=7UTyHWi%Gƕ]B&*-Np['py>K[qqgs -H\:q^z~{cW $s]Xyɍ kk6j1Mecvy0ps;_p8e&HhTOISi({ $R%'<f]Ưc9_Ir GW??Oң]/Kq+jMmɁG% #V`Ku H-e6zasI{k_j6qgP'\ޡl_Blđʠ,%H;14)ӿ.Lmkw[vs :ۍ-lwwi407eVO?, Xj-e7s^ssLkMBocb # TFd }/)O-͑1 ʳ@ªؔok!Fk-ය'@6G'sZ|6+}-vm\4#9g|hW7vxȶiPPOYE#=ͥ$(D[[@%q)tvϫX-YݸiF~R=KV&L1+ӴX֗G y6?;&ѴdK\Ū̚\ij=qq2y3"|9z~_ :]3zķVXtsss%i.Am9i27s5 2mV3X\Zqd&hYVTSI/#[Rі)7*I vå rW7ZZAC52ȫjl6 .ho 2=0qOm$Rh-di$ӹ'ȊPYڥݰfYdxوKc  ]Z]>:P)48ʺ0eaO_ CQ]G N 1$lmmS`_ȱyָ׬_ſ,^?57bv+?E/?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhQEQEQEWphunF ( ( ( ( ( ( ( ( ( ( ( ( ( ( -j_:딶׺(랾ׅڧ_-,䳺YLR})ti+[X|"Px?`[x-P*)A<*`zWAtiOF)M5sawn],;G;4ShvDo#\'v4=W5=TfFe%e0 9N 㵸dVҬ3G8 tj>ҞXWzb st#kpA7hɩVV岛Tm doFVj>Ҟ\xPb^y#%p1ItH#A"rp\)c@=)ՑڝٹW8܆ym6^Ӭ/RgG*ٖ3j=GĺN;AytVEMɱ}[h;Gy V~Ҟ\߉{+U\0En ?b:&w)H mSy4j>Ҟ\$,` ỴZu4eye_ݰW+X@MtiOF)6}&V(n+d psCͧi34мd`GK[iOF)˟[]Gg-ˆHI72J=ZKv|uǢTGGj>Ҟ\ni/, .u >\EywhK\KNPg~ݹ>jMΛ)}=Q@|U:\?/WKokbv+?E/?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhwQڙE!FjeoQ@ xK$ɍCE&ˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E.?(\Fˏ*J(=sGQ(eQl?"#q??E>%1s4ucŠZru]cFw`W&^gh:K3r85:}nEз [ R%GTEUUSEjf+iT]h_ 0F3О㹧M/jVoՅKyFݜ'k/eoOrVefo$$Tl8 ={V[ZZ ]K5.2"2#ҏR}y }N95t[mUO,(n3g{귶dkp쪀W#'= G) <ךӯ-Mwn7ܠE׎UWs_J>Iiz=]y߈}sQ1K$FѢXCXd1Hn|PEwj+D|YXzdc9zG*n/k+I.f{u.1 ym,4I˵yKj#,C:ZSi"HC,bfFh -:rk/eo%++֯aw>A >ts1ۚ籖MsdwZ @eA xɯB/eo7îI*р&qV]?Zyϫ׷[_Io$IhFUX9}ҏPӳw!̖Yՙ~g@ ) ((((((((((((((((()֛NNb?fJmԮwQ,m'$mַ.om n'H-s;Wڗ;*."#OlK8.ۋYmEme1zu=1ҟ٭7oƾH;pHmdc6K=]5+ڜdc3JtDԬeΩ%<|:O^B^_ wMq$H q̣E׌4"7 o22ϴ0# ^Ɵifծ,1\" `vGj w,grK̨Ȭ8=yV|н]ͳGs,4Qd9[u5"Cqmsl&PFH ЂEs-i]n xemT/6cp}kkDүm SR{^nI4@BHI'N?gis4ms=QG j `Ă{c՛2iE8XT-9G5^lˮ6~fVsONt6{$ªzg%~jj!HU)dVDC8u#꾫M.!e}y8ėOmHY8'+P5+=6nd⹺ĶvP#)=G9>,}.oɪ Y.Cݪߐ .c[M,m\Z\Eos4Kua$*>#VDʒƩFYC Z$LQtP[2.<.![ 8ѽ!O c& \M$J9(V$Uu!6zwMq$H q̣KK6WK lrqחд%N5ۼjla w<-Ə/m=:eĈĒ5OAXWҵK^K vYc(N R+&afglX / kئ}y52XF[x9 xZeu{E\ !p~OڦaKu-:FD0 n#$W7$!5 =-bL:g'tl5b_JJX4n Z׬_[{?}BدBC(8_bV+ev_j$wzwӿ-h(C+\??Ҁ"z]?W_\ں(((((((((dt}j2րERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES6hf4iEW!UѴl&Y#UF+1_hK-r ={xR}H:g#+x'G҇t7b{s .zd%z}&j"̓n;OTSWާk5ySi7davsK-iE*W{]KhirQ%ʶ={]K_etA!x|+u1 SVv)]viE/赒u lH#0#I"C)<V}4d/QMmlsuΛ/}FwW@b׮~sT;Ul *w\07vPiqڭ77"A#=;Vugҁ368u6ΡrӌӶ'DR k{E څih1\fOА^_bV+S?ޝkFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z$29.T~b!5 =C}M:(0((((((((((((((((('Zm5$\(-Fldh"c29()rE.F\.Gq+9! pΥ#icK{`׭%jy11:dǙ}if+_n3}W[GGНO@kچiZͲ^7y8Y~^mugK֞nUA_]_v [jax8nnrl!d&^Yye%=ۥ91e&wdeo>2>tʏzkKu4KkYn#;2z k .'FAyEjj Zݽ]]5(%[RXڝgZYx|hehsr@ŮNL/4nrǍ qgޠԵC YM)!hI2+1lYxbЫ}}-YK@ă~n}Wwwrߪ,:NSn`ҮN풕"Z?G[hV4f5`@ֵ̲5-6Wǩj]W~N3#lHdw7dkHh:wtnZ1[-ԡ x!p8dO_>76QbYHXNy,w:)k7vv C=ο%9\'j42KOi(A d 'TG|G̿xyޞ@{>'W7Qox)r1O l/89y#|6oqiCui~RT2dy61 ŕfIe6a|;Tx>>Nkl&% |ہB0 8u隦h{X5i$ʖw u5Dߋo21yau >F|u /H.[;Yՙ~g@ ) ((((((((((((((((()֛NN;)j.e&W jz柠iIfO,QqNv$158DǠ}O1ߝqW+8.dif+Tw`A2MWY/uQU/)>7gsښW?[y=;{4P#\O F4 Xd@3t+Ny8}:1ߝc}:5^5Xg{ynDdt:Ҷqs|u $(9U ;Z]ɇWP=٦ cBNX/_"gnqθxo>T7{y%PRv#S^\w5mZOVVb' gk?\^C0֏+DТ\*TdH5k1>q+E @995Va_KW'R#bVVk7 n&oj*l/k;W[ Cӿ-hvkFAkWPvE/x6ǥuQEQEQEQEQEQEQEQEQE~gVeU6(0((((((((((((((((('Zm9:mD i>Đߑfr V-nwW9VRu=WWOGc}owj%X\#= L;UXmeġÌ$z4k5[Li7ݜqҶnByD1I˜p8yl!$&(^FyխH 'V8z(tk]$DCA}n c51?@Z|["CZ#g^ \~lOGuZѬ;R֍t_/r PJ_wm]}rKj(((((((((֬G֫?ZmQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPNNru 5};R;n I+|g#O'mw7K<2iu}d U,t-6=C{o E+=I Ԛb9kmR,c[/ H|úx@<33jeQSEuܱl1c5ދK {a ػc#Q؏jCgRDmLrI ;s"'?QoosGuq5E.Bڄ Axc뷺楠H,d2BΠ8?wz~ w5u-hۉbCnw"|=_\cn-tB1*HWˍc%-!ۻxbyWִfx̹dylpyf,M`99?/Nӭ--Ž6HUE_1%԰a /⧎PF9;[5;ssq-}hKTdhrQ:Rlt3Lm- i^ivv6PɝG +zɥ~z[GI q'̊2DdkW:E@bkY)c3p$$sW[D[KӘM7s<ի[{+ u*G808 ϯjSڛ^>ეl t=h徶欺<OrF଄aIPtw)i1ߛ[n$lc۞Tv(o"C̊lB 4\ {v!HJXa#i=1Z;MI}$0[[ʇ=y^ջ>6RZH`tHnb# lE.:_և]m)lu,ldOOn*Mbj[o6c38 3NChKn2d EW -L4P]KkKLctbO]P41,l$'!uou1?b}:C1["CZ#g^ ]Oo`OCb6οNTYw9ݮ_]CAں<EPEPEPEPEPEPEPEPEP%UYV~(Š(((((((((((((((((i@ ~V햑&~w:u7y<5 ]yO33LGcfsnwc6e)]Fsj\/>$bW?ׯ_Y;=vq.3*r.M>-(1]c6˨^:vR-S ʡy"_4iέgwE[Ƅ|oN}ݫe|f۟/~l8iҴEؐlk3m ZfDnN& T@l)eyERVNon)t_DPz7uvz}cQ$c#8Vk4}-ӵ d%ICcOHE=oxma6 Fw'=xOwluTWƻ.v3Y?kH|2bx HSxf(`U\sKl36yes?uSGfXcZ{>b6dMii,Fo#.Ϡ8.ןWuqO$pdg9 yjkHf0? }:/i_GemK 0V|<_ :+nn~(OQKi#Let m.dtkgH8Uqhv1-Q@Š( Ƚush/]?1\l/k?E/?֝kFKZ5r \??ҺC(/ǥux =.ͫ(((((((((KG֫?Z/ZhQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@9:iր!Hckrl%Cp#%4> hȆ'OiGgvER&7Hу8zS?'QG'QL8e6]N >Ъ6G&֔`]NggM/'QG'QU_i.ek4vv$+4*"Is\`q}lao'U0PK[qqgs -H\:q@wywI%y\e\Tjl/}k%guL5\p(BlUVwe}Ǩ}~U}:%[wd@ :n>e"O"Oڦ`x+nfQ!˜К-XGj[dUhDEDEWoi-+!״ky<"X%Wdrދp$$($+^ (-縎ho_+ŗ!tɮB"c+\yǮ5`#$($*k(f3-bqhuη$wZwӿ-hA5r PJ/!/x6 ( ( ( ( ( ( ( ( (/Zj̿t}jEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEM'ZڼG<+c=텴w $pehݛ}a5Aoyg%bd8yH#cO6ZApv#VE%;(98"-QƝ)!;;fQji z^s$[xD4Is'rJ@s]SѨJz5 K_P C07+C:ز' ÐF3X:AMpоf[y `oQjV_OTxre_Oo-1BZ@ rH'ZgtCw0\q嘴- cCB)}=ܔ0uKOt'e8ȑE$p2k|+O[jj +l,$k~ҞYe~[Ln;Yfz /]QUkM |"O;o[>I2˝dWvvVVݕ?uGj>ҞNeEFNỵ'1 ?@Z6uE'#ӿ-hvkFAkWPvE/x6ǥuQEQEQEQEQEQEQEQEQE~gVeU6(0((((((((((((((((('Zm9:em;HKKBh>a[.;U c+Ggiϳ4onQ b:Y&l.tvs}O[[ZjQlK׵O"tR0Io\ zVLZbKuIօSc= N;Uߦׇ_'?7_~}%&jqe7*è*~tX:eIYc &T+qV mc\XCu\q.Io͂D2sd6:fԝN5$n]x8k5u+JvLWZTy'A r7cE6zK"6KFB7]7[f,-$X#x7\%X|W!_. ZvYG,FFI=o}rmBm6Q.Gۣ<sɣQ,ZO>{+%svV]AZC'UA'AXi֟Va{.-49-4OEE/fI{x 5e `|cdQvF;k >@Z5feXWiVɮEbySZ--re ulVQ5XRZ+]khJ Fݡv9jꫯǪ+͐%00rrr#=(}3\y݇Ulʰh.lk/ wb,{ׂe+ TNᜁ߭O1 ?@Z_~lOGuZѬ;R֍t_/r PJ_wm]}rKj(((((((((֬G֫?ZmQHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPNNruiusB4runH)keQaUWASG7c☢д_*8EM @z}ҏV#MVX \?9Q)޼-c~ ksH9ׯeokz^[KwLda,14]xN!cp#*H# 0hZ_ 6>G+*v7W6̳@F$ e@Js`doI֠Љ ŵͳB##8$GB k}Ұ#sB~G+?T zE­ՅK""ͻU_ZiwQ +ϱ${hԬ F~b988 Q_JƼ񅍣ˋ[눭Y.f n27ӒXpjXZY^\R[<(aXG/eoRx|][̐L&Tګ2i.- d0!' s@8 /eo޻ m̾LRC`By8v˪3jv 4 Td+֍unb1\,rq>XO6. CN(͆&3) }OQO񝕵ĨWpI!`rX@8]?WZeo>+{ku+{VKh6)<9z֗Nm^M ](Alncz~__eo{7On.Vt[ vK6ۡԼEjisAb r8\FF:еw}mrh.ux5mhi ach۷qX<7SX-N䢓zCKfίޝkFKZ5C+\??Ҁ"z]?W_\ں(((((((((dt}j2րERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES6hnom>k x^G85h:6N@J ȲG#gHdfhzIZb9ȼ-|!Yq]mpF'qzS&d%.uO, ƺZioo@ٛifծ,1\" `vGj w,grK̨Ȭ8=yV/ZV 5K}"G[^[w! Y5Xk9YcU;/}:O5/Lu#" CN39kH4(2nD`zrNtiE/Web\zM S*L ITy:D94XywnHi#n7v'uu_iE/贆}|/v| @d1op⦹,.o2=nX$;K8\Qm}Ɲ };@Y!A,ryI%i>U1ev$q^Z>NeoDԬeΩ%<|:O\tSIԯ?cMde/ݸ3sV_hK-%Cz^sT!ycl*0퍮ZaF ;OWV_ǩ%ԠUJu;QZ>Bo[Kh:0kztmb:\K#t0 랝{gd*^R6+А?*>\^wx@?m?λNTYwkA?ݮ_@x =.ͫC_wm]}QEQEQEQEQEQEQEQEQE2_>Yՙ~g@ ) ((((((((((((((((()֛NNɺi!tm&+I/oFH.UQfy 8]Nrv\4sH~1rk|9y̗O#p rQ#۸D ={xR}H:g#+x'G҇t7b{s .zd<~ olM@_3F?| F0\c,4/c7l}+yϿJj7\5;_|q'I̐/. mxQj0e-͖&K6v=?ֆwe{gz-. wVW G5^^jW&V(sԿ;y[؛XlD |TO=zU#W{KO^byUU2=J̶p`MFC}ڒ ߍ+FߗOH$we|D~ZQU\s֟"=~K;[iuw'wmjx5[bmnؕQn_OPyWG13QU럓_ҋ }WnRw/hAμu_=3\P)x @骳2"#Ix]DX6=Rǔۻjq=:潹hu9fG8+=3wq[F~Ya{I]*qsyn]Լ}mcq4k x$R|ro}ɧE쐫(mӹyޢO ]]͆#Kl&Rʡw)6RԵkk,"Z*3wBzUWsP|Ci0'2C$Zи%'$;M$G`n\J*j^ދKBU+9Sݽmo[vCzlWQg%̷[j_ ls_#>SY>wgi+Cm-ȫ!l+w8mB/qxtf{o5s/G{$o$1$I&brׯl]%/e0%6Ɏ^o_E.a-# StV$6]j>mvdUL8=ZuU;~f|xu'VIIcA$>mb[nrAb3B"çGFmp0~7cjx$,P<`B-MemZѬ;R֍5r PJ/!/x6 ( ( ( ( ( ( ( ( (/Zj̿t}jEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEM'Z"Gayw4Gѵâ:vkeosyғ vFI,?֘ȏȏ6mn[侳7˂Htps}j6hLq67݌(Z^MmTG-ޟG=8OyۢvO𵕢Qo_a]IJZ*+-ch#h#k-qwv鋈up3v^!Jaq–OPW`ݑGG!=-uǧ5֡nAys=^(|N+!b9QY?z#f`p0zSr%w5iڞjާ?)bda0"kcOMupb,mA ϻ}Zcz}<]Foʪ U'Yiսҵ)wrB31;[@jQg)4* 19Pg<C:"?nK7(nW=3\/4ko"wX+::D  s޲%gu:YTWXv׭4z_z7SGS\-K$pįTſ}1Eo;|G̖V07$Pc}r #n 6:"?]`'&^[d]F6ݍk7YaGfZ:;R֍giꖴhkWPvC"H0m]~ΖYd[-ޝ[؟{^Q![rx~uQQp?:7/X{^Q{^Q x~uQQp?:7/X{^Q{^Q x~uQ{G\,mn_΍B31SuryjۏsFܿe_?>/Mjn_΍_ۏs9ܿe_?>/MhA^<],V\hP1xrxOW>/Mgn?&idiNQ%tbCнwCнwyh/MΧ=f/$: G$: [_gn?&?GmG}/ B=V\hӦٍf~l@֬_?>/MTa4&uiJ6}>CU/Mgn?&9>CU/Mgn?&,`0} WCU/Mgn?&,`0} WCU/Mgn?&,`0} WCU/Mgn?&,`U=*ۏs9mNrK:e ($O?tsxSY,V+hû@xd.H>5}_?>/Mc**Ny Kyyc#ºQG;)fbL<ȧ75ծ 3}EvvrJ/Mgn?&_t+m(Kݝ2R,$#&4j)b-"S9|v*ۏs9VV9eqDOԮo-//nkB9ozǵMyh/M; WzmdB+t :2pq,%$O(2ciwv7b_?>/M%XEO./m/V;Wަձ>*sz ~/MsZKl$rX'q:;R֍giꖴiC+\??Ҁ*3<&DM+a@\߃]6rߚjCmtc9\ *ʣ8ocPYƒex@wP۫,?aXk^E ,) @9JHC*Y1#<+A]Bn=seu 2A"m/>x-3lRn#<8پ<*?hݳ{-ZE=<}i<5wNlu Apof]sñ,t=- ̒(+]ZƼY4q`R4l`_8)V~?#Ryq8$z$ }wP$oPD+\ {adKw rSr +Z[jχAk!f#RۼɎsvsލXy5/8\FԗUPX-Zl ;Gvc"ȋm+n ]wWo>3Ctc&ȫ66`{'9jKdnS[tK%U 99Iko? ;+Zu[HP1PdU[ 0rwQ\Cpɖ961Gat>t DJEI\߃g|)je\&|ƬkŮ.q>yvZLwQZv;ڭ_ٽah Ԋ$8/u/|}_Xb1JtVRQ\:Z ʢ B/ɡko_G\^pksXmco-qvǖ#SֵkhmIRvl$A_ɯ5\6KjjNERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW-k\c]Mr6f4iꖴk;NTLC_1_]Ctb$L1@^ ChbyRVD+zq6IY).[trңptHg_[̳CY* UaNJӦ8e^(*A+m@Cm@C0B`0Wah۷1OUTP +m@Cm@CӾZ;%w8#ic\ӭ 2v}s渿Yv ?^Yv ?^;!mlh:Pv= L^姛gn ]ף]נM:[ehǡhNn{Z%.1q?e+Pz?e+Pz6͍6S>s -T4O3No@{h ]F;xc;s*y  |9cKʼn_,󟻌u7}北}北-H9#K$Ktr22)V }北}怒LٟbT-mGkrM)M۳{% > >ht&9ov3R3D,`rp+o@{ho@{hJӢ7ZL $Ic⍤>[S<ٮ}北}怒,m#XU-`UJu==jZ1Q݋Sf89 =湏YY;h,-mok 0s qPţC$0q! PG 5Ϸ=Ϸ=ܴ#Kv9PJlx46[\XUsgZ?gZ Y`8(,z\i``ӭs~}wc5Ϸ=Ϸ=GXxqۥ%VMXv0i7Dy +o@{ho@{hK[lm1fK:aǾԵUIJ%RS.I@+}北}怒M3Oo%{ٚ.1 açC,p>l3r7}北}怒 G[tSdKt  fN㳷K,JgZ?gZ퍍6S>s S:mi.6$*1 > >iqX6vKy"Vd8||?Sahݷ9}=o@{ho@{hH`"B`)Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@Ϸ=Ϸ=\,KG,K@rψ-j?bMϫZ[uT {hӿ-h+$v UB(Vbrweyk@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@'"p~T+]ߔyI@dD`vV햚kO $ibnip2-8.7.1/doc/src/figs/scr21a.png0000644000175000017500000007440013351443023013410 00000000000000PNG  IHDRZ0Ʌ] IDATxw\'do{c[qj-8PAUjhXօ[hօ (2d! %ysOx&{i '5!@ua343[vjNῷ,^u !OAtwo|U([\j߾R&$-ǿHe)z !{]->?o!H=6HE >o5!54n_m徽2yHR"*}z%`W.DwinIAQ*6Fn ۺ7o-:n^VNnfF"ci>WR'nגv͛ԷqVn\ӣu&NӻY@ }GԿ)@@:> GnN`dIIsE˗u9rtoQ[}jiGl?K~'zoa[˿<[?*(UR8Wa~%z޺6S=O"!i93ըu'Foϣ[|uęu?MKMZ!AugLz>M(g_>dK<|3v)OpY.!D ke''v2 ӭZL:=;Lz$/Kqǔ#ϕԼP[iSqIIMqiƃKObu޽}؂ z'ѯ'є ;m/=,/?rKGJrrB:{gVB!!dʮ5!PBҴS1!GW鹪rjRKa !4-93Ϭöײn_E#&B>sjτ*X  nmgK$矝*yN2!<|/"?&zdl*`Xф"|7}A<(`Å֝#/V}am׭I%6^!-?4[ߠ^}Oo>\iXY4L%.& ̭4z9H9H9H9H9H9H9H9ښ[?)Uh@Kq ^\Wfh6q[$يT2 *y-ܴޭGر&ELx]t,Sݲd;اo΃^=d9n:0%k]Y~Yf棉Y&B^614n/jM*fQn_9^<6B9roHhLdl_bׯ -L]\%AZtlk~yѡC,?krE۸a[KU]TmCHؖCY Z*G@⡊?LP{Ny%3-Ӂ0XԷjݮlt3o!SU_uC;tDLi,zK71O|Ya[{!VΦ̓=8DUH\=MmGǦ,2Z~ى牝ut+!yl. {o=J{_&}_a=nK۟1uP{3]/(#t0֕=&Ȅ"!!i=.!D^cBHY*,#t1TzQrQ| ì'Pdgf:Plː-Q^.t/^\LJj^OQ ~ΕK׷m1Dq[7B߆1u^\/(+_p#2Љ/,{^eL5Vuq|\J/J.*]vbѴ&,"|ʟHeP[4asb!Ӂ0}Tl}}]"GxEzrӞV@ "aW~߽>,MB8_Vq ;u_^L;T쎄;R7C~dxBfoD5k!wIK05.MSWEeyGVTcVcX4EaÆ 6)*sxNeX7pgdĻI'?zv%D߬Y.A1ޑ?#¾YuZ6._N_IȨ묞ݼcXCB: Q6_L}? V٪:3F36SC?&6Esbo*6;ZnN Q4qQulYuܨ=KnU넥{&xHʷtn  ݼz?5?}h5E4MSL0X _UN%5OU۳}mU²R`XaAO `y,,̫ght(&P45|gغ 8=iƦUh ,4*P#e/!0F:4ku?W~nv3c:.Ul6MK a+``sS:hKi>P,*}'I (*}ȹM@,,@Sw-³a3ƩjJF, 3T\IbLRB VMlkeebb'e/Τcϯ7BVOlcmn9tچ1P-X;4PanY="K 74pS'J?;dzgGZrkٰum]JHsyvUME?J `96kL?Ϥ%vM6͕ǖ]WJVXy^ŏ2ij}wN5K}U/[Xh6؅-Bhewo!]?m#J'/>~˧?Mh n'c]iS\?oVaҦ@ܻub@V)yw{Q/džav1B|mm=Lk#a͌墒y !X/x~NMiSgVXPpqS%;4BY=dv𚧛iEyλmk R}Vt20"a6u" 堅g*-nVJ՝y_3ɟwʺL|7ʮ8HaX/M{ >;[YnU@'ֆ:ru7lwg1 ^:nR:+ @5jwlkцi/8MB u/<ϻ$-1ЍxP&Iӄf:2/4/-|~ 0w0ITV8~۲! 6')nMP1%L{r{yIE]vo16rM-1{B"aq_o`*AX4 ͋|#'i_7-ufDͥJKK?^FP\:fܼjA@0>;#(>Y X,BȒC9992eʲyj_V*'''o~ԩ.]RSRƷlr (__˧P}ѷˢtԧ޿u>{5G M 0Fx/k.fD(**244Ϟ=ɓ'sΕ&'6h#ac$/ݼ*ٷ\'6)0+=察3uĸ VO6$p:0]R.!*}٬ߟ;82%ɍVNp'o[ -<|C[{|!DU$jJW23238lE}:;˖t/:99]reݽz?\5EڶIU㋞Kp0'\]]Z ;\l/6/ͻ$c[VWesoOzHJe2l4;@o_V?}oM4RZ~gm^Jp5.aI>o^\tߗ.E4n*&=s.gk -g3jiM8k/^>|?CIeYLS|kB,_&y6>}[RwιՖ'd)>~˧?Mh n'c]^n m$]ėJ'W @19?c$8;x4E40[q~#%58X&B&O,IHwdt>QdtOw)+kDϢ+:V_$iv𚧛Hdgf:Plː-N L4X3-O$wSr&^gq:M. ʟ\5hxm>w?\!wLW:w6H4asb!Ӂ|n]he@p59CV5`gdDۑd턁-Io[l q:eɭIڠ.6H͙sTnBQϵh2K^mxG '=1oyˤ)~:ٚdlPZ" (UeizInnnC!~UMF@|~?(J ts{}#ZbV _2 آAC[i5FzU8dcBaV-LInNNCrr:MP}ѷ ^S~b3Zl6&Dn{-|*'S2N(Vc|#U:00jbÆM7R搓͚ݻpnBf\6BQA ӝoyu a{;z7j}  =ɥGa! א+}5;4?a[X1< }];<~;12v^<{/IѢS;Xx@\r̢vM=̬=Zs3Wv47{kRo9ؚZ9FzfSҳu3 3KF}Mڈ쟒B˾_4I}Ǟ_-I+S u 7j䈭[6r\.uQ#GxzJ+w0iYK:::37޾zK#"%>#to_ܚ2u'WU~g/%~7i AcvM|NJ;ן_~pYҎsJ{Nfl;-CwΎS2^nk?BZ-miޞovWW~.+?BHqANqAy߿VXy^ŏ2ijt'fK36lتce=}S'fO\O_Or通[hj.4ȷvHKO(;d*]KEZ{(W4pKOAS6BDvғ,PܻubD"'?[/a g#4]vb`lwF~/ÝLFEijG_+9=tsޜUl]V B$ ݑcg3AqQ K瀼.\\5ݹֺˀzbaAbMw(w}Σbʣz84U&{8X۵&v͂oo;J fY}bҁ_$<Ӟ}!!K#Z\*Mze7{gv ̺Q_HEem MmD%OՏ.f|36lتc#lڲMLQbڴe[qIs%wjT02D'ޢA IDAT?r~ɫ>JO|OT@LT.=jQ얖&)I@bnd4As:*}Iȅ_5hYCv㗯/ X=K1=mQ~d+{WIwbƻ4cÆ:6_ JJ~fBP8uڌ~YPR\L3eȈ3 (aIݸ%AԟR( e<_巎nMP1%L{r{y:JQ:k Z~όB%,yqc 43hcR$7iٮ#|;O&GOX}݂"_d(Es9q.K_0vWbK133xisN733SZ`eKgf٫߹Эf}W??mҲ奈˪ޡ?)4γF}"h 6KBz{_m:ڸ |:ɡNԿխ]>َcM'i\κJ_B[vn ˀ?":ovMw#:YX:91ֶN3Bgމt>>¨_&&;6cÆnDdjfvqSSSS':ͪTN%PekL- {@Ͻ (ϖ+%@),(=0@i B`D @]t-bXiQ|{/˪pit,)3TE;j4tf4tnsTDXl^xv匷iLc̓X4͡bJtu"Ȗ uʫKgX㺺<;G8R^Y0 rL˖hW.2q3o`Gt,ǣ7jcjQEN*/;+-;Ȗ#-+#֞(f蜕t’ߨEOR4b5j’/[th70Fk#GFLGٗڍF?Bp?PM/HhG ~%]g&50vŕ3,h}:Rk's]z Ӂ@`/!CD՛(J ts{j};fh@_iW:,_ֿ)C51P}ѷ ^S~bW۩#'Ks,M4M3 0X>I5b9.;6;ߘww! iޤ! kWQ[ Ĵ!^֎MN(-WӨ!ߡq + |{&ݗSgH~ %j@j\Y`Y;:˱S}BՅ~ߥ>ӚNojmN޼kM2N1`ImU5xgm^Jp5.aI陝jHԑ݇O$p?^xv匷iLas,y0z՘x^"nb]k;{t鱤f8q{ŶV+IdPIӜZE'T5d?54bYih; !WΟɅaf]mX㺺<;GFbPGŢ*2^2及ELx}I7a$!_iq 5owHxM6& ~ j̛0-MLN8_5ho3/3R%ҕ#}w !TVFFe蜕tUc:`ȗa##^,,%wSZsS% J^E-t@zh-yA^ʺI ]G-PzDDpo)aړ˃(qq.--Tce$p?i1r8.MSLG\5,{\:6^Gn5JiNQXi3Nb#:HE|3m3}oY.S9 !;6yڨOb{o@m86Œ<"XY@J9hT07ojmnrfs7QI }C ]->49tf8oy".H PK( 4FOo^^>8lN}>]Ǯ=0ЈnTU$jj4*;QԼԔWq B<Ѱ=y԰qsBX,JJ|z菺<={,h7 EC dvu0ZFҚU```Ǫ{rn^Lu,{H()x*Ưs3C#g)Т!~6zz6fKre5јP4EMSbHFӔ2vqo4cǝ/*,djjP)tЮSEiȿϢWw2"r~;{_|E#Gv Ϻ2|ݍbwmi-9=wٹ7B^|+9TRh.~*+ "VO@sdef;ԇ95iDOGhMѲ9def:d_C5܂@DmYCVvUn6'J%!(Cwi%.Y"I:/ԷPxIDD-??xoۨ1݌dF!]xSnkmt8s;ÿ2˗mPr@޶68d!J ɕ|.VR>X| SBH޳E=)QU(X4dPg^M2i =硓+!BbNDFMeZdViiu@ ʕhtJ[XeKG:VLGQtqNLEKp0՗wa ^wdl:B[p5g_w"3R+V#Y="aۣ\KXimbzBF|X'/$䘪BLj:d\4&W(.+8g|CY%W$F3;Ur7 u+eBht),V+ؑ#Hvk:Y===['6t85߾Iv>֫ukk \/w` dѤMr40cKdC6MvB[Wւ%+ d?54bI1氲S^δrk9}M~c5ώzj:܎&-ڊҪV>ƼO,D-b!^|\.}%wh;fs9\.>'@YZ4o3y9T "@]fM͛za:O -(|wi RB.X٤ϸ!ɗ|BcHSeQiEkxKt|5 2%|省 A3)]h#.zu=rE%c,}b~S&vq!7Z&BP'cThӹ7iHw y!Mٽ{ʫv%LxF}G-!djM WMyAJ:w6pibB?~9/*ͤ ϑ.o~ӿb}ـi1s@~] %sUKIO-W]5hlv4EBBHa~DqhJ>>~gy!M?Ń茶ҡNS%OglfxKo}m Wn㪉M2ٳ!<,&kJt䬱-M,B-`*A$7\#wly.J:qgA+}_0Z:yߕ7V4B?huDB!GfT/M,߭;yCV:\yKMZDPӤs7jŞؕw<:rjPfMu>D}{m4Dw& ML/r&|ށUty/%xϏj A3lٗg# p6u[ڣ7zv{p#\r+,q++ a1Vil윤%MIhթddxjie-()r;sB.4qi/!upրyJy[tIO{}ҙ}8p8lBH'suoHqguafa_OI;?n a&L2}LM}Ш`ju{J^N!ǫdF@@x!foٮ.&̐-06R=vLM&Ө`abjVʧX,`Y Ù} Ҩ`bhdTy%qSh5KLGA!Xh(V1~tŠ(C:j^㯜}`J,~wצ^@=t^&2@#XZ4o3y9EU~B5`ƦM[[Z0@XL|ƵoӘ6ǒo߱ VvUn<'u`1!TPR\tJwh).?۫ gsbQj˳@#7'nׯ\7dTfL3sKS'=X@k`*AnY6LG0;G GhK̗Z n,6~>vcXLp?Ҵu(h&@! Ou+]q՛(J [F-̟6} }vFm-7!+N_@7bNJq ),MXciE/RJzt{dPu}WEsے,fY0Tl5 4db,  Hؘ|cGGͫk\4oRځBׅ|յЭbZZ/OOkǦCmKY%Jv֔\FrSg6NODklxn rPW`*A)Y&ƏZ2IEO]%dB..鄇Ǜ&覴ڼx_nM2Kn5"&*/P@K= [|cy!KDLP;@Js!"ɪ1D@xךǒwp67w{E+͜xq87BSz@MhSsO3 0>m P0 FuѨ`dUc]X\EFKQ O3&,$=+-7RVT~Ʀ@++Ne9y>)[ 5LbIZ= fOQe4*Fϟ޼v9JKp؜|~]]=Vc:`enlb/e# t H]./kdU!)Frcd X?`+;@J9hT0uRS^]87h'CyG&zQ !b()ɣ?V9KvF qbfa%,I$ҚK8Ξ-9OP*:h˰Cs&oIRMZ:jN<Υ)L%2Qfx/(+x3ϦkLjzYƷlLGܺOunf14b9Is{GjekdakGE+s6{}LuLl/{|q燌 phfs(h)X~iJRf75^,{\:6larlORZS1Sz4.$F}Az(m'۾iNH҇4Hn<~ 72}^<T`5L'c)bnrٱn̟kK nA}}[/<9ڷSxճ}|+WJ!jV̰w-!7/jۏ,eOs l,M bamupրy&L-Q MQ,7r9CD*Ѓ(NHϙbyȄ]'sXDJ+HH_Z.Y(Y ,QsybQ\9%s+ݭ#޴3%kwbֵ#{۪/ziȄɡr5.<uSoˤɖ<硓+!BbNDFMeZdF @>7mCW}tNk:=:pDE>W#REKgu3Ⲃ{XWZt?T?"/ŔviZT{:&8g7vvv՛OWvd-KPX,$HJwh;RVM-I-c vdY;a`GK=qңV-;!dǩS:ٚ Z2lܹ*LJ̸N✗þQJ.,>`-=KnhY>GcG<=|f'#wf"[kȌ`zsvW !DύU:Sb- 9%h|egnݹW~;X,r5th^㯜ӳub##(kcZwfPWq\ճr55e^hu7 0=ݵGoqF}Қobk]6!d1kVzJ+ RR\P :=핍):#CєoS-%\ ^hc<}t /G? @]fM=x[7pPZAnE@>FzktcaB?17ސ"Si)7ζR_$)Mٽ{ʫvx QnjT0uصWrE< :mj^eΦf溺3" }@FQ6sp15_Y,qV#FQ24PҜukPkZE1Qm@]t*uߤ$2Gߤ$ƝWkbPVi޲+g\XhS֖V6P)VvF*1@u19?c$5F*BH;j|;AnA)!h O@k ڍ{ٍk3ަ1 8l%߾cW7cmth).?۫yY IDAT gsbQj˳>v~B!7f:Ƙ[>qxqL4m,!fB:[VF=Q09+#(4&%@|Hvi c8.MSLG)4a,!(n,6 C2y@ŏ|}U&cXLp?Ҝ6.`/!C3y@Uo:(9.$͍oٺdg|A-bW˪HGA?"rCLhT01oZ}ѷˢtԧ޿u>{#Arci?ηGj9E>>`)QYϟ޼v9Jp؜|~]]=?{`̪t@l;#U{[{x/ o? 2NMHWZoR=?Z(W] Naam"7vɹ{255f"ay5Uci?c==cav }j`];?dTGc6CES4M"MS,6ŽwwqZ3ߣK%E5ٔG+ZI"c%wHʝ*8!H͹G:<X4;. yemCjKN&i'4&bʵ^m%t8!rt X3(t♨._'GU~J>Ѣ'NM.;}[/<9ڷSxD-OOe59EUdd3&,$=+-7RV\?!}7 ܸ+9DBlEBv:Y<*ǐ*F`[Y=k.+YKKf Z3dWGeZGP3Nf@}F#]:gѯF:s;ÿ2˗mt! j/3mY.[Ano/OiT!MMr챋B`!<?%-)6MQ2}zhJ,BuKhZ,)4%{ "ڻc.X*WR這ޖ'UZr)"(10Rwy]r'u&%}v4ov7Mtze1Ѫb:2_k_$H)K\ShْrYh-OmY;)=tuwiO'촦ӣG[s5[p5g_w"3R/zr,.T3bMu߻ LJBF|X'/$Ҧ@{;q=c\ܘCY%W'2r |ٙ*]U4vJD!?4%w?pV>D&tJoƅĨàob#:HE|3mRc)qⰈv'sNNccf6$g=$xI=ǶoS"KZ]c-k$a/YpEκjT'"Tp"Z[jk՟Jb]u/%"(#81$~>Q{<6?rR7 HN(eg#]?}=zbUE{S3DeJTrL4 sg '[r&pA+-J6«|Ѳ[`!'Elq ,&de=aWwtoɜsJ*4x)mMQ7~ܼ4l;gCu“KJ# x; K~BL'2Zou~-Lu(n7nfƟB?/`\5EO]&$ha"K|z[.kbL)}EbT%C۱eSj5ؖS7(>`א vț - W*t=2PAFrFzZo m_6I{Jl̬qm,B%(LT]"sgN782;d3[Gy'Iݖg-1B&/Iܪ*#H7 ܻyۯ" <OSCcFC#eGtjkHsBRJ?H}C II#kWɑdfx`k9,].,Ej;cNBg#AJ^JM$t.&/I )c y3}lm$HS|z{o)yO-*ޕipT mFMmȸ 0hj! ~BD {dž• q开SZ}z6Z8p8lBwLMkD7#xܜi};413Փ~ Pm >Ws>q4ЦTS3J zՋ%y|>!J[+*Ξ$plc|ML"ufjf(Lс(RaSS3 EG,jR\Mpb hͣwfqk['v >,#mkf>WS @.& fnaݺcKE^lcP3y@MWCс(+)\BLePm0y@;eK<X/ (:S :[\3FPotG0F@oY7ttt,% JEECC`Pm(9h:;\Eas--;vDQ1HPm(9=yzxC\8x'ُmਐCw6ehΥ7ddV Լ_8^06%i"[+: Bst~^(ڔP P`@=7?uZ:4ս^0QD B @@L*P9Or:1?ɭGr&ZJ?ޝZ&xܬw?ؒjK%7(hbh*t=dl@gbƟICZhk~9b :Ή724=z7UՇLSAP)zxj6m`P+N9֥I 6ç|OQ|+?әYl{w.R;:MvEk^Rqhn씹SkT_1j@94"wE1khWBM5b/I Q'r/@@dI3xצ>>__O{f yr  9եDroGߡWo IGڱJ%EN"Ӥg RQQ9k [{Ga O\BH?vG(ŧsx^XPQYa@ cw@z\uOGwFPCMp̘(N?5,Mb{~Vh.~~h3Y@GjkzVn;p릹֚CDҸsrMӷcKzBȭO,XB HN wk1囐;φ r$sD+1Bu>|6)!]"q7(/|"-R;F_ʭmר-]m3K *,}Cq_ Ikb7d–UFmWĖMܹv.̶} 6ds`7CB$4ܒӂYk58(rw# Cv,v:yI's7#ʃ{n!W!LkK ^Y5| \^4jz):(PRzxOnb5W|W&SE>./PRYzշ;vvՐ_z0e3vr B3nP_(k^~''I{u9vXr&b>]Jc'LLG:[xWHA,M[#^Ԍ ƻw5eW 7 tk,H |QIAkS!cgH;3f '-#Tkt@V X̽͌ 14i^ B[v4 q) :QSd]?ݼQ* # ݷw[hz4o- %`!DgHwq !2:t[EQ"G~6cww߲{{̊w6!s.~99BL;%GolM/jϺ`w BHe M4T@Vܿ q eXū|ri9fm/[ΫjU5h*eBK 6o60K ʹEQw/J4K{k-9JO8?Ϻ,?h+H\?^W)~ 5#dR!;jVfI(+0:Z$w]2nk =moq7 j7^U6Y ݨKeYtbq (~%]MÍ2߇;X ('ƿ,G53HҙuJ6«|ѲA#Jy!E?{kF]m@eH-505u!/2!%\F@ ̋ =+2RO`!,c˦@۲"|^;U1"A)hw@iu8@@ UEocmBH4M/QL}Uѧ:=]Ko%񦡥ƙW= ?[cB9IsaSWx;=ޖǥ˚BJoѳ%(S-lOOߙWhѓڌ e- ]ٶ6jaRXBL"sg:]?oRVϳ$`ܴzSk 뵌N"%<~@;[#ĉ+{ CFK !DW \;P+Iܪ* (n^H|>z3)\c}FD ;nfqEd2Ûq V$?.(e؇[aM7X#~v)7 %_;LM#q%U.$9yeݬ)P"Mq&uhnSs-~: <@eO<Tk)X5~bˢ\= !PuGg辨t{뻙Sʚ f={󙎩]>O{Il$șWbBH. 8Rq+Ř1BȻus vN>ŧh߹ Pª]G=r1z3K1_ψ@Pg"eڍszl/'S̔6fϷ %gVn}l86!`QS:G9ӎv*_sٙ{oO= >;6nXс(Xy㧈Zչ§5gP>8:hl\ͷTӜG]PRB**kXIGf6nѶ}:“\G(aK~Y:ܤ*7qbAkEY: z T?+U0\MpbEw̰;C'o5; -W@]z TKi(U0 EW<,;@3&F]%Sz xB<GC@̲CP {H[/j -[~uI1ϯ9`FƦ FJAYܽyE=яM[zZ80fA ):+{;T ȁ`PXJ@;@;@;@;@UT+:IAw4p:;\EP8leN]]ܚEw4pOs<޻P{'7.xp4(/b ,_<13; W5$%QoF~P0@c5ˠܻnu{щ?'\sv~iQ~,XlK!(ePw6 :|vտ_,Qt b0O܄k+c:( /}|zq#Ss6.Q)DWYt8_B0-G5;s4#B]KsY}Zkr!E3g8bf)]0pۑ9W-8tkFs\PS ՚Ͻ&F~C&lY\_JC4|&cQ1VV(g<-*,_tE^["_>{ͽEO*$y gFj!TIJ?, @$6}j_wF4[z{Zۺbѕ_WecҺ[oٶiS+G&꣪vE{5ofТyU~MUF[BƢtqr1ol׆[%؛eu*)@MJ5D%"$](ǀW1n/sBHyOu6Ғ~R$a F7lӈC!(r8$暵;CݎAӇ˯ŏ33 74Zws :$ƺS j!x0ၒ͉82QJI ^ҠKI!2QcM(sBrsz@ty_7陷2hs+I Lo1~-Lu(n7WQ=\]ݻ:N9ž>ǗXi*+rcEb(ft͉nRN*R *ܶEٜb+2Hi튩ˌ(gyDsM-\fqO 5j@4gs3ADgg5 P763gѽMc{ϢDsDb[t:]t;{{/]cNIӥ˯*q*{$oqb@O_7S_I"şnw>OE(~f^.]lUoU=]]{g)J*nv$8} ”PqQ'I/ Ny:G@nӹSb}X,BȇKpXpbvIEEINבIm SW޹t:=2 w T^6Nta)o`tI%,8{쒊DZA."ݹӂՔʊXwYۥd  &}RN*BRHzwdk@P0{{=:ɷJdO?6BX"22W.V!D8YJ!DY*%)xG#֪F~0CIտQI_!2bcAPoAyuO:nHAI5k2$Тm2llO+6_]0 8C'zznvMʰo,˱̀KfAtbBp=dQos6.\:R.+SFgj5͘#_iuE'K*菌ՔʊXwٰEw\2l͘5T2':=7) ƅisbG`t {{7yPk##ajLW V ,~F?09\*}?[Ŧn+^k鷦=5=|DQD҈Ba-5PT~:C 1;xU[>ͬr7m3p޾wbC`qHRF>s!d#=0lqCޢg1Jz~P]~.M)2(>$Eiwߵ79u&{.Q>f\x-#GA˻%ϻmY᭹IݖO@i@ ǫ9@C8 CTxrv|m̈́ࢪڽI MQg#{|B_ww11uGt7Y@L,^+: (jjf!2>+҃cZuM=>&Θ(+-6!4~X[~iEEi~ʚ ?P&, G[rb>,aCmbϯ"e2HD-`,R[Xns1b>@]l#cSOos k8;3br͎&\;͈Z٣p]C,زSOڿ=43ۢ/xkۼI `o2ऱmFF"g5 " (x"6sMȁ"g5;x$YiJ5G;O+kҥm9V(WydH494Nഅ߄H-$5Vuj `4bfIҦO-oIüV,%wd]ۨ7"|' 3tԷlA(J}w`Q=@ ;@;@h|ʂ{)Aq2ёk$jx,6;yM#,UH'(9tX,BIRDORxlٞd(",dzCvg:uР;OƟ%e,">?ӧo]8p|K?|t2ݓHv"8D/toa6loO_O{,Nкec+BHiN.t6Zi36mjԄn2o7jJA* rwy6g*ocd,bCw.zˠF Ptyśջ*BKiF]*˂c !,!~?RrzfFݫ&U8?Rzkoz6/@J!"Ք,UlS7!x@Ãx,-_xsWe޸%W_>3abEU}u-퐤BJ|]}#=7 ]RQQ?9uZUA!l.(/y2$ l2{B읂7Uek "'.(zN1_{Iju8(?td, )qgw^={M: 6 ak#wllO+6_]0 8SZt^28Yc̘'/|DxznvMʰot凥Y}.%gzix,[Z4xfo$cwe @PϰvAwAwAwAwAwAwAwAwAw?:+!ФZIENDB`nip2-8.7.1/doc/src/figs/snap6.jpg0000644000175000017500000015304613351443023013344 00000000000000JFIFExifII*JR(iZ)( )( 02100100C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(`P BwJH^YHAf8{'[ouF\P/bכz/4OH֏1}ke' /F?O&=#_Z<7ԟ'G,~y?1}hּV?R?4MhѼ_ZXGM4? /Eo1}hּ>=i?c?oz7y^s I4M7Kp=_Z<9y_&XOh/bל /G,m'{4\F֏1}kci?o6=i.yG?𱴟7K I4MѼ_ZXOhy_&b/y,}'{4? /Eo1}hּ>=i?c7Kp=_Z<9 /G,}#~&io1}hּ>?4M',#~&i1}hּF?4M4h_ZYGM4?_G֏1}k?dh/K #GO&=_Z<8Ŀ 'G,~ey?1}hּN?2c(k|9ϧے6@tQӏsO}[l.ֳ@ EwioR9m!+qm`m$p叙^+T֒HK[}VbSn ^8N&.OEu_P 7^m xmZKSK +E 𕥥ߍ,&T2H?x,+J85,VZgi3kDdn]?!>5Զ1牊:>Qmmsy!{Hcg z] է5+Zn wנU%>0լk۫-.˖Ň˝r[1Ikkկo[3FDdu8epAЃғui}GwWsfd۶){V667T;@QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFu&u#1qg^ߧ "Eӹlo4z.8*OoF2W0 A};>pH ņ{ubZ[]_Jc1y_Wz>g )FX⥲b@StQӊ Iz "p󋎫 qu:AoG8U^0}_i<:C}|ɀG֌Wwko;ѽp?\U2c u)*o^(ۑJ:2һ?ܶϓ,eȚDڱuK\d|BpJ>xwG(.70=tx㪸 U ϱe'>G_: Aih=٦o$S>RqI>]@ .tYٔ~@xU\y==b fYWaۂ9vkwp9 OrŸZmnDRJ+DRJ*-Q@XVXP|CoY~ Lh]#]$c A֧?Ĩhm+u#PnDq>yzl[KX1,M.}f$rdD-PvI,"%C H'UGyۿlUX:&8-xē@t ,q(ur1N sQtSkQT<,6|Vw#L8._AT(+TéRR6'y|5Mam=\ y78 _b[:T_3y $7}3NXkNL!d~^B:K 8KZ nn."U%S$F/iq\^4fWPD(b\~A8\qY ]ur#kf$v@aŕQ0bg889-k}sw"[O|X-^ֲ5 5,4WG6Cm\qQyoKTA$RC'M5{oPkۡ.;itFviӬ6s̭5nIbNe[M6%m{DKBILnbX9U{/Y[A 6^I,sFiE,7I/R 'v hGZZGľj$nV%\vw\<}ㆶX" Xrsт:±^GM7z*rqclvx/cHZ;Y m890z~}me !E5Daë@Rc#E*m` insL/tA*6WQAXYE$Mp7Qmq8ʫzTi.eq "Tӵ7xdP azb".""2܉CqRI=ł[\Y ! G Z:_ }ִ4lD܍>班dj: 0[LII4=dQ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWCS+0&~:V~:UZ(ұo-ұo-==Sǐ^Cq v4g px}vPuЬrZcN4WuK iY xyv*NsHOV?\uvIɷk4tYV:g\yPb򈅈P˒Y 8`,?XߪYDX Xu[*YMt$eӈ3~$|[t?&G"qkHfG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_Ed+iQZPG"qw_4$R&BR]) ysƽxыs_K8±i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~'uAn? >i?PGۭ?(z*ZQO ֟}~ oX\ZDqFq!Ϥ qevb(ARsJi?PUNy_bnv.+ ߣFϨ/?w!$ ۻV|e?3,PKkk@bHl7W_*r>֔(Fyb X?ԯҷJ?ԯҷJ(=+VRJ=+VRJ:?S@ Ã*}:k?{빇ďEFT دJw,k|cUvBI%P6!=woһX> OH@FҜc9M٠Σ?_ZV pe1IW7⏉Na_G  w;{׊KPk !i`odd䑁5mXɕ?:i Ey=#+ ֬\spGO|lo-ܥRq$nPh @pA3v}Ң{kKdy$P2895R=H}i,)c6"'s]==j&gK`|7>^\![kQ~c@2}ץjX0Kin]])'sӏΰz?;獯Uo*+Q?'z[Wx-W1Eto*N_k|\w_?;獯UsPO ޫjumD ss*r$}Kyx|7y.0ۑ )s?5M[^mر HG''?J=xdn AquN8<4P63M.@Æݒ5rp.NTϟQ(fIIEΎUH?x F0\F"XPIv9~ě)R,dbcm=rWc_]\[Bzg߭Is[p0D c,F@ޘ?gEvZ.6Cs=Ί;vGU f6vMq1O t<+=RJr^Z0(SԭR51pC=jψ% &!%6>u-qҖ KvsW<+ydQD,:VN4o.Y6 $BWP[Q]=1AtmoQ0N9b FWӤLsu&(,HXO_J}rWu}jg]@1:iH.fgXCk\ -8Yj u9+O-;UQz9県T]ZT_$N@\+ۓ/bu]jYYDo$w3?mq}RF?EfШ# N^/]RmJ{e\nBٶHY$AI,r0=XofYa(eT/$eIcqWRdy3o,1<Cq閗Oj"ۨp9=:TKQ]7ssclc`x Ьeg? T/+}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>ytQ}_+OWG3(C??gQ^E<?yEziwW<:(>yj [+ǵvo+jm>N[|ɝ.U{~:V~:WyQEc[[c[@koO v:c%;pV=4jG2y/", 眑T}ZbncR"'&6UmIdb$p? St9S\~qU1iPed?/R&Yʯ-+&}k[\ꖖg">٤P[' tahGPe>|_w3Xf8aJO riM[;^[Kl. ŰhX \g ,{co"qZ8q"،-R@֗÷o21v噗bNNrA95WZt{xam @ߦO5QMU u(Z} > rF;^6,#'qvw4l[devq<ʹFK%łR3&sG=? XjTH]o5p˙W!{YX薫bk \6ޭ-'q_f'ޘ(nA tUI-鶷Zh.c-$3Uvz )Jȏ9f4C}\f'#l=GZὤ9.Ir4fjE 0Tv'qڙc=NB^-O13 z[AjܷF^:ఉК>UTgRX 93-O>nmau B.:lkKX-?6vy 6!p1TgQถo/&$0I9stP m ϱmѬtncYLI`l & DHRLdU+` >f+w{_#4v]4j&iBȌ{A4H"ĀF@Rn3k KA~mKy }EN8\AWM HLaQw) 03ȮZ_Q=Mc^K e>$ cASj\\G(R |q=Z>Y7xu9oVثldojиWVTQ8U2RX:娦7_=\A}y-dQ*򋓞ʴ>e?p5QR迴?n?ƏpR͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_G?ƸJ(͇}_YMifH(QRt[qOo],(OV7) Dw:'VX'V]8QEc[[c[@koO]YZ#,u:>lʡ2lڿrYw~7y1ݎ6>\kV\dG~iЍp *[)G37;|mR1 ix$6KuຜAy$hǂB$A[6-S2<0%@Xh6CgtӘw%RwإnuY[<ѠS,Yk _:G ##W'{+2*{ZVvCj1v%Αq<0# _?ueyV9M6#a=;sY\9N|v=ɭIkcibWxdf2|8eC H"icbWnSVl*$J0K''D$xceN1nJ]WBKW\lqĖ _(}8ǧ^T]Ji%~5fXb0ΜOڸ\W\z5mn \G*Flc$9c~+$Y1n R?ӂ1OH4fze/?!*֐Y oZ? jrѲ3E9y8׽<_(Ә(((((((((((((((((((((((((((((((((+a? o_ocAJh|COXo_o_or EPzV>zV>oFt-]A 5AjE$Q"0i?h=t5?y6={A 1IFZ2(8ag5)}kO40dU٭Ыߞ##'ygEws?Chzve-* cO8\tjA)^)鑟u~كFGa@NO1oH9'g?~TT1ds66iA $PX| H zrǎH4BNO棭RnraEUQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQERa? o_os4>KާS?ԯҷJ?ԯҷJ9(=+VRJ=+VRJ7#[O O?h=桔RX>wE%ͽ~,[Csnk~}k%`1D[ eI'.0Rfeܺլ}U +> F%a6h'ˑ@; {i817=rG҇++@T!1P*T` )`I ۋ5=F caƱ zm,X[+n ǎQE{g7 ??]Fuyw^a%`/ԍ)66_hw|ℑ1ۨWj]-앯s;??G/¶ΥMc#W/vewP3~w,F"&VvUdvTnBQd}'g(O~Wq*DrVv\wyuKK-BQ3_r6Ҳ*v!Hp Gr"`I >{>߳3'\K\䚑.gh +0ʕsbc?)WקZ#O~Q T:m܈ͥF m$ 3qYgDH Lsx|$qS}FK ??[Ry`ZE{q^#\UL}hJ5 \Uڪ׊@Qs`I >{>߳u:r<ùeb@7J$Z.MnX.nV</fۜ8j>;]%ߨ{`}}'g(O~V}ru2 #A,Nqץ[֯Q$HTR@ū{>߳}}'g+jPUlkؙnDd,#ݹ[ԽZ? ??]MHΘIs6ALҨc45A> ??]?SQ>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳}}'g+)({>{>߳R@ V1.euk\SP~o_o_oxQEc[[c[@koO uZޱ8Ǡ=F3Lv,<6`db#dFGj״UL| wʀ*Lzj&+ kXG# 2\7)#p.w]?p)mutKV{{9,A#`cnHBk%EC r7?ũ_Zr1&*ʭUrTdz <Ѝ`}9#Pj_'*[5ٮb HG* @TaWu Ps}%Oyy!=;Ocuy?U{<P\ko,Q%듟¥DE&x7tVmE)ߠsWycc{ʡc`\#T%rs|^iOCto..VϷp(F8OFU!>Fp0)SN6yyIU$F=}sT{Ӆmyv`qE??^ٝL<[o"Ȋ NVcMtBcEHNu s#O ut_gm>+4&dUm$`ҡF҆23AB)i+9zV}Fw{g !reE;#oe`Tmwccq۴@3?EQ:X 5mZq2"T%؎SިM j7(U]yl;? 9,r1jȢٿھC$tmb\Ÿ- *Fͤp;vo*KAz|£dgpzkSW}-KM7k}-(V*_*!qM4QH$d8‚x$rMsR> 6vip"w .ƒu$W/t"F7*)ެ3ʐx'=kle>LnK;;ًn$>Է:fSHvkq"(/{>Ki}yu-FGj??qTݿI??ۺoK:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq7~ h:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq7~ h:w{y??ۺoGu. ;/7~ ?t+]Av_ۺon7WEԻ쿷t(o6?wn7Q8\mgRo#owMq¸(ΥGe8G??qQK?=wMq±S@ V=l'hQ^:#QR~:V~:WpEPzV>zV>oFt-]p? WQj6k\ Fw:HE{B5OSk"G)eoϽmZǹ}#@}&sFFME#L*2Oj/5xƜe&ňdRx,ykӭ,ͥ!`%RŲX'Mdx_Gx`쮫^Le'XGG&[wVmMu3sz_[iWְEkPA`*"|[J-phM{ gJ_÷>DžOӤoD0Iw.H,F88xc/dgr_!\X=Ƞ{mcPN1xnJ`229=y1⢡Qmmc[jiK5d4,1VSi,u}B|Ԃ`CI v;K 2O^9/o% ΪXb2I^sSk omla?J9}j/bq5*x_}jQWL&Gv0'u5Zm^BJA# py53b8i11 ڝCuȸ!d3C?.kXF+CiI|E~Y!f* '}־ioO |K<ohD0ODw'@pAsxj_NFgߴ0e=zȗo4Fsb#Oo I`nY/7r?׀4,@#u3H|xS*om)Y3.NwRtٶVI(@8#؜k?Ο ?2R#pzrr;㞇D?ƯW/]Gu|QEAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPZ+&$ Ps_o_oQEc[[c[@koO wtQi?h=t5?|[J-phX>'o(Ig#os==C2lV8#ڽGРb+Eu9G7lfm]Y*}9#G>]]sR 0kYbL 8r9] "a \|S~u3V~ Ar?Z4a?֭g)o&XKįp`ʞGz%柨q k^ll{e8z`c*emwTԿ_ Ro}Ʈxk{E3!HZ1'k Y-DN謉+Iڏ;/= =G}?/juԬnu'>KncL@q:ֺhemddr +qڔգcTbK Ro}Ə-K}}Χyumk[[@JGP@8]MaoZGFR;Zn Ro}Ə-K}4vUڌ^"̋ra6 ,8hzid)pXt\'֥ji|F1/hԿ_ʊFe~'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ4aj_eE5{/D/hԿ_ʊ?j_aj_Ϸ>]haԿ_ Ro}ƻ*(ѫ~?'Ϸ>G>vTQW=N7 Ro}Ə-K}쨣Fe{o>Z5QG^08-K}?/ka"qZ5m'-69f =>^տFRNY$EJJ1: J+|t J+|tH(}[K}+`}[K}(mZ<7#[ -?GЍZǹ栖'xq}ga3>\qX0LgX>M.͏X%dMDсYե*2q؁217eYQc?UUq3I z֭ -'e;Vxє?Q$ڧ4k#o -n`M Fѐ<Ҫ]F s-ݰd1 |%\ҺњoMD[hcp@COI>_[aCҺ\7wqYu6|ci'dJco -'ݶLc)xz&UBI!s{n~SmrV\Gu\RJz,IZF3]9>wqZm5Mr3+6wmVfc5$-p,G4-d)CS{0m<+m"R])9ƒbp_\q3e8`0rzJ;+9ϗ m#`d >M>k=H$3$!+# A#1R\xqn`WHCAmΗV\Gu\RP4}<īHm/ ˆ A“#-zɨDŽm&˜=H>OoG,QF./ zn6ʭshD?, Y5m&܌%~U-^Ioi}gq<~8Wer)$x{GG5w#z۟|S-m"\Aslib]N>».y`[DX`::*m}Jwڳ:vn|=űcm8`*yt.3͸25?URH'EUw94[v5 719m#J00;DB?(xX `š0Ȳ-ճH<'144}*XIYnI =ۢ{w_1;ye>2 ݻ#Z;k5 ۘԓOֵbm";`?(W1v?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯S^yj<?#SX*lNi+6?Q®\@A$hKo0 O|< 4mR1v?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glg`?*}Jsv?Q¯QGԩ1Glgd 4R4Ѷۊ+4)ϙw_o_os EPzV>zV>oFt-]p? Ww@F-?GЍHj jsPKH`tE9?R]_gCC AfCjؖ+ ۳:1 #E$8=zV-Wx}r/o?|Ci?PGUE3Go>i?PGm?(?ʿȾqپ!7(]m?(mCW?>W?7?eپ!7+mCmg*"fxol7?evm}^__s8 fxol}~\gw }~?Qx3}|Cx}r/o?|Ci?PGUE3Go>i?PGm?(?ʿȾqپ!7(]m?(mCW?>W?7?eپ!7+mCmg*"fxol7?evm}^__s8 fxol}~\gw }~?Qx3}|Cխ*p.noZhr%良؝1bw4ulEﹿ7<VUmF\0~Hp}O=jm?+yN/ sKb/=[zz}~=b/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տש~i?PGm?(pb/=[zz}~hIv"?տGa-qlNK[m_KZ4R+FTvWάZ?ԯҷJ?ԯҷJ(}[K}+`}[K}(mZ<7#[ -?GЍZǹ栖' rZ7!tmFҒNP3Rn30β~k'Zf mB3qqEeU'MkK-Ԭwm:lNhV7f `S(e9dk)olM̛<1v(C'֌ZJg}o~5оF0pEZ'֒(݋ :񐸂&8qPݵb]Arh5ns/ΤxcLWm$sVvwW,PZJ|hzwcƧ0(Ѧw= 35%EvDSbހ.IpѶyY>)56UywhAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAyF۟?MO3@mqѶySn_4mq4۟?Mn_5>hAy\A~gW_kؿ?Ґ'VX'VL(=+VRJ=+VRJ7#[O O?#EF$59%I}igl"֩ >Uw+9-{`q@Zmߺ@Z1^MP1z˵oڟ]Q-1aw7%-'q<^ۻsr%($tm^f}kmFI8,22u93. ֪r;][1B94fI|QdUD".[󃓊tgl}#g9`֖+k{5S+n'vсAǥY. g6OYw+9!Q &?om s]rٱ-vWYM 8KIO%8zl]ǟUأ?5)W4-q!nV6V.cx:LIm^qnJ J 8 2u93u_i- |nVaB$b[H?"8SĆkO*A뎘VV:eAn,/l;/54DiwVRh#5N nk}ErKV0+hXcEDPaNj hy4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@y4mC@xŷ 3mC\ߋA ggP3WDRJ+DRJ)Z(ұo-ұo-O5AjmZ(s]B4Qi?hCPKSZ@D֛&')}igl"SnaҘEPu &Fumnj|m A?[OmqO)a97Om]m29x涂<1@Eύ_𥿾Mk+R@$?R*UQύ_TP_?|mٚߕ Tnu%լl EHCs@eNC,J*fX_AXylše Ҁ,EQP^\էM> s㚞 *.eb1NwWk}m{MD )\u@(wMnSq(< $՚(* l'}Z#y=Qu(,W(O?|mٚߕ +;IbBG g t3%HB2(?|mٚߕ U؉kq@ ύ_3OoV ٚߕ ?4+j_[iR]˶&ύ_3OoTIw,FiX^7:VPH o]\E3n[qrc':`ύ_3OoMUieN#Zg֝.۶U_?|mٚߕ u].[9d" dHenFFJbXKV8w1@fim~W(TZc y$Ӓ#Xy2x@MKVzq,aayύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ ?4+jύ_3OoV ٚߕ _Pg͏8)l% M~%ݲ˝#jP:wE;_ZtKsjFY#8Aiki. (U[3aս}i%+w66w}ea¨=Ijב:ePq r3-|idMmlg߹w8kRVGo|0xѝ6}o{Ίj Mӝ-?$W$dO@~~u;&Ԭwk<[Nv.Aێ+Ҩh@xGo\+y?z$]$|LVDn6>tSOk<[9bA03tq#Cs}9kmRMƝlk;e Jj)tX?a[xRLo/ aÀs1cNa:Iǟ83^T:9n, n`t}wc5lؿٟ{8Ǔߜ㞝i/.LO{OI.ֻ*z]G~_yi5}:K cHf0Ѳ̓Mo Gj'L$j?Zz)_~9ZvM5Q ~I,M8k,ptvsUۜ:WAa-jWv{s7ruqKuxX5̯ګ@lqB=Nm5! U3i6jn-<u\g=tPl2IJI ZOӡӖB|p8fJק_zZ0YKu * O[~,o jks\$B#i%Ny=뭢9.u+m5g֓2%@r0P1*ΟZ֑-VѶJA;M;^-t#.a.-Ia:VNg>[~hHe܇xl`5tP6Pz^I~q{oiMk w-~?S֝~>)o+E+`;lһ)o[ Ũc2Ukc߽kC~uOMo *JAֺj)ߨX(@QEQEQEQEQEQEQEQEQEQEQEQEQEQExǥWS\zYihW[`hW[-Q@XVXP'wuxoFt-]Zǹ(s]B4!%A- "OM?g\AX>3A6?@U ֐0|cr;!ǦA丆I%b+ɞRSW>TU~W>TU~W>TU'usdOSGs M rK E$dgh(_eˈXxOyldo*(* ,-ZDKu8z;%XcZHH(<##?K@Q@GkJaӲPm=wns@a7FJxO0ǞBǦjZ(9UF6*sGTQP^^Aaj7.R%  [sӣY9U"23PQEQYh\i5k6\`ޘs@QEQP\AhaS4(ANMOEE7!71S0>()KҺqgf8 RhUiu X_8R >E@]/$7uZ,gwL T6ޓ?g\K]hQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@r1g-@Z'VX'V@ EPzV>zV>oFt-]p? Ww@E{B4!%RX>3A6?OQ44?gO5׋$i! CXg:ph]-_U edVrU|䓖 uK 9LKHͷ;޸힔洶w&iG!( u>ǹ\uVVΗv%[  9Sެܚmoi#Q,İ 08zt}2b[:qmdp*ɪQ%pFBO`>x4[[_!/gkjڒivtm5fVmAZG,AmX089HkZ cDFr}AP14M:{Hn@q)#KtȐS}DM[[$kpȮ @rjPծu z4FN#9M2G%\S}Y1kوǓ単җK RѼCl3FEov9\)^--"T m#Q!.Һt}2lB Ɛ*А IqX76VPĭA#40qwizmZA0i'l#ZxiW:坔BXݲPU[;{CD)_nq֗7^n  L1+iк[+M&ܰQph Ha@hM{+Iaapt` ޼z:Jclإۙ_yU5eW@bfEZVٛx/ Y \=U`db,Jd >[0@|gL̓q-"T fnmkPQ7i# 9ACۜm.e5wrsܙRldSWKޥݜq 9k oO&gQX@|0 6? yvW7|W'6?+e,m#XU-`U,`%}:}ϏH8I{߭ =__|A k)uI#G,m89Z.5s\6 }c`# $#9ً;QыhDsҨA XwϽC&L4}KB^8)t+nPMƣ,ֳ chr U_3l$_yŒu]iW]4G1bW(}FG4{ӧZߟ]UO o''ea;imByS#|=e[9Jv8!J }uޛgn.DaD4Ug眜TΒ*y7s,R#2(躝wI2B& tgɕNzc5mo \*m/OH,-`I,P9 o CwrgGx핹cn*ψ 4qďܤ6AaiM ,t`ÞϾimloKU gK?>]iYXxiP{/8|⠱}^=:/խMF?Mprك>ۍ:oM賷d`"_0MG@4:um2 KyX;,jڶA3 :t w4/nU䉎v $E 񧖌eWÁǰagi,}3MorRqZ>w.\筞"Pk*F#>ڕŔlFru?ꥵWh$c6} J*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[jimh/*?ƏM?[Gl45xxn9T1 -J+|t J+|t(=+VRJ=+VRJ9#S'_vԆ.O'Q@ h4P7SIE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :77IE.?%sxtPo΍Q@ :|^IKLkwܴx1@z'VX'VLBEolor~? Wm\O?iORQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW5ibZ]-??P~:V~:SQEc[[c[@GYn,}g"eC\ꗇ\]рHR+*ӥ~NIg7' rG.O]''?G'?Qj}f]}o.OG\5}.O*O*OSG7' rG.O]''?G'?Gթ_kw_r#˓?' rGʓ~_ʓ~_~/뵻eC\˓?II?|QI?|Qj}aܿOteC\*-OaRj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]r'h~/뵻eC\˓?SEV]}[.OG\5}.(>ߋ0n_rr'?OuGթ_kw_r#˓?' rG>O>[\5}.?k?]u4Qj}aܿ忲OteC\멢SG-' rG.O]M}Zo}vu/9o?k?]t_nSW QeV۟_۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬Q/=۬W?xmDGYNFOoҺz_F-W[`hW[1 EPzV>zV>{FIֺ k]M!QVEllBwۓǯ\dkG\wYn^2=R:\'} w"l cgq$n"i@c/?jQVA>s{elb$J%,:vyI.o6uM%&f|x<:{ bY#dda?*]/Tk{Qū*I<9lä-"d$w7]GS|wW/Y˷˴aw63"Fn."4urK$%.:s‹^=F;m:9f6h2`^qsU WI]q$C,S"4e!sowa=OXd $ds~r3ߑI_sGnZIuɪYi!hdKM:wu9;I;F-{l0JM%`vT:}Ԗ$K^x^a|TߟŸ_} SuQI,΢U.m*@ Su6"ynA'Z4Ҳ*Ϸoss Kki網{o, {I>_ΠK[YNA[kѬXZG6y蠟¬GgaeoF#-geiZ1r.dF#s#960}mf^ ./H~F[DZtQ!t[}o&To\shJ{c{gm|$dDkʹt=8JZ:TrzcGkqx [=–-OZj]_q+}4ź{KՔa݆qT8[c0cVaB ' & *+lN;tyWO_6{wmb uGJ5?9c*qj?iIoovL#GP GYky ,BǴ\ޅz%0[\vҩ T=9;j_i0ߛ)/8Q\R9mg]W[K?f1l b&OykV:~b J/ ϸ~`c5=%^C,r3º~OzKo}K׾(Dlɟ$rFYH5nOiZGs,J#VHum*S@ԥ=$] ]x$qW5{KTӵ?۸̎KHDRlaѱۡ4tw]ZJu~ک,sSڐ\'h8ZM ;MX/h#E`GFխ=.Qd'[[޴RхB~qۊ<n[KpU+{Lk ;K$Q$RkVeӯ$k6-h2H82j}jUFe7^to# -E'cq%& 3X`0? ?#z2$g4-OWmoTtxfa%f"'c`1vVa2xI6rnH2rNw8_W] '6bq]sܯ@?#^^geGrJ#ז͸g H܊ӯ{: ƹ ]jچ<\(D.V`puV ϩtJʚMMfr$aZ cҀ{\)QEQEQEQEQEQEQEQEQEQEQEVw_kvW #@O+Ұ4O+Ҙ(=+'T\J֪WoB(Pb6dڻ9=_W!]K$2pq\ωV C=KOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=oOWmy¼+}?€=e] r06QRא?x_PQ^C^ > ~@Ey ~@Ey ~@6+Xc =Fޕ*"ƊQFT`+ ~G<Z^K /\۠ =RI=%CX 4Z$\ ~= RGsYo'#3r:[YfyZI;8#f8j}۫Щ_$ʍvPěu^i^lmBHLrO*'֚z[ Lbl(䞨Nk{ޭn.[릞C3a;TA9S´C(´C*eǕk龚յ=jO]?HSA5˿>ݦ>al̙\ǂҨr^åi^[MqqwtRvcy{GGn%my?oN{oߵ4ind -@)[/bTXJnF uԠ|E^tGty.JɆ'(JǠtö3B;]J6BGU-#Z&ҽ<ɱI5M#ϖ95%օ楧%iE,7F R RFM&=&H[w<{!nN75VVg\k[y4 i-'fՈb<`=A Pؽj6PKrXw;p9#ac2=ˢ db6œ(#> zO} zO}O.S*czro_-o VͯI;7r((1n8v[R'ۇį*D~~~mێgqFTk+O??+O??ª~&:+yiU5 FRE[[ep['4aф%I~$ڔAEVĚMq6I>?5=$Ur_=u|H|Ci)YCgNȥQ=p1/_CڷG^I}vB2y&V1,YTx[ZQƓg\AcAԳ69'چ _C' !p| <<3`K`Cck;~4nK#Z6p 큷v0I,U W~X_oA|֟ufռFNk[$SȰiC̈Bqu-O~޾A_ݠjx9oΩcmsOdkx1é0oj,@#Yڳmc/iiI9%U TpH[|1grMJmȱY+HO|c޳/ZEK7Vʹbǖ[ cAj7aHu[ic 6ckqPY{6c[m~mu]Q;7R$zS]/@nƲi eM{02 d` ('[Vi!IQUeʱR'ڞחZ4MLItd$+ROZl֍7[]-.XZbd !]Ibx7|f蚼3u4``$L!<⟥h^*žm-J9dԣ4H;F޹ۙ_z W|I/os*Kq6O#5f9h:9[[!+ieR HV?Ľ6.tTT9{ n[+F 0wS[/# ]hGkr1UxC^n_jFWx6w;x`03"K]?]N/xZM:Iͣ[-@Bce'WK^ CJMCZv =G^ <{vHBpO5]"BT#,כZ5]CR5Ƶm㿂 َ A](͍jo4 vn5+{TE98RM[/ekRD)kϕ#UFwlu¨$U {"xšw]%[c*w+=; Th?j+bzJyk"RR#WE/?7.++FAmoCƨQ[[f_Οe<5ax_~o]qQ {"Th?jUf_d?_X^\UFAmoCƨ0Y/#WE/?7.++FAmoCƨQ[[=e=K?uA|qs{\ C!T: OoCƨ̿?ɿW-潅gr x ,wDGMeiEk!BBU~VP. !nE nIZB8z]۲mvd [Oeq}Z쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻wv_ݻY?¯}}Gm?m4j쿻w_D%3aieq}Ԉ*SɻTu$ݪ:Lh(C5_|m}+kzI$ {Vq(|Wb[uԭIki&\Tn}{ s_=uT 埅ER<v4E%. ?Tz֪W=iS9[VakoջBTS\A i=7Υhʆ '*<ǚ@܅vP?1-oZ{@oG֞[h帖,,`rKci\ ?oG֌<)4HѲAE?u03͘*ےz iHC+pA4)DrWef(ꖦW"27+j5Guj n@?Qc?>۬?OU-ݼ[@΋ !f*W$\z6(((((( _EIëd8.>VHFƊUzS((((((Qԓv1) kzI7'Ҩ/![УR-/![УR)tE%. ?Tz֪W=iS9[VakoջBT:+7|O&LX7?qކ#𖡭sg\ZEJB K$n8_ xYkz& ĖjvЩBb$ ]3x_@}i,+̑F7?Sh6N$8jig6zFWllt%'A$bܓԒqҥNm%?sa M'5o3]fJ iEWsi+Kbgsdw+kĞ/|Aki&DrŻpw 奰%}66I-ץOuI_N+mgȼ}fچXd:M_i?؝Zk)MK|B5[T𸹹frvqPt˩[latuk-N; E@<0FHYfGP]&E55M2k6xmmH8Q5rVöֵO/_io%LdankZeկ͆k=ۥ=ܬqc# 29|[kV5(t%?!W28rǾZ95{;}4&6ӄJ\ln8vքԚOW>'= /8,l6]\ 95GPi5վ] X U$F*J #q\m_K7N:(]wBT~8>[zlՖӇ X\Lw7? /xgXc[?4 u]o[;h籸&ks eCIT +2IZhdm\}XVD9<|ed {?\ ߜ;k~KKӻJ((((((((((((Qԓv1) kzI7'Ҩ/![УR-/![УR)tE%. ?Tz֪W=iS9[VakoջBV:呖a5M3`켂ǦxO.bI"0n ʀFwu@MGy_?mgk~W(/Qa P<?vKgk~( }u;Gu@MG~>?|-s7%ۤ !8 ^ҭ䵱XeiK<سc,qVN`Y[`;)#Ǹ;\OES(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doջXZu?EnІ _שj&,n?s#Ww4n&nhyqd q!yj1o>K $NӚMGŷ$:}I,7d pu~mc꺬RLf#2WMou5F i |zPP00([ |Y-V5t}]Rk$"q 3AkF9zm݄x]Ob3ϵ2߫ʑB'k qQvFyNv7F\V//yY\|Ϊ62H8Emx;EþӴH3 83!Y$D~_o/oX֢(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doջXZu?EnІKms>_Y؛XI| HJ3b9Pfnal#QRUD<1V:rEM=]~mycy!*F27d}k6Ú06>'XkAiy?xx1e"2#)c?ֺv|%x@-#(r `ڪD_u{=:?j~yisms&'$S2@Ao,t!d{_4Nq|0wk]q^OGVcXj7̒F(`o)4kD Wk'U\~,NX)l`"ܠvw4RWq6wP MQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ڣ&QcAERto]\oOQ'%_CڷG^^[_CڷG^IR_ J]+A6?L Z\Tz']^s趭ל-v0(/mlR[[m$[y#8*IaCmKvDXs $dki9ƝI4O4 Oϰ~Q}ùcN? i[a]~Q}!uGP0 iGA;ks/A ?"~QQ kX6;-1?@IwCIN ,mK,laP3}f55 ݷ*GZJ+d`:nRT"%)(((((((((((((((((nI7j (WǤJ|m}*9/տo :*߂տo :*HJMpORR_ `JJ]js֐:u?En Om[!G kԕOG _797US?=i<ćT]ރu-m'p݀Ot3xt;#V.fI^Gp# sx>> B%wollzx T)YZv2 n^ߧ/O9{R[GVEONz0ڴY?iܷh2B:rgKi{ KIdbq@ÎFoZu {岼%̛ Spe aU'y_?Zש>,Ad&D.S&"EiyFRu$cL4|b* G=q-xFۍIyV( {q G^)Oߡzqgk+`ƒ9%'p8U~,Z]^&kիB@}fK-6ln`2jt } jvsB-m VvK OY_X#oe,pxQ]RO6%'V3Zw4?YKYʳf9e @PU\wPZ<VFXp8Y"zlQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ڣ&QcAERto]\oOQ'%_CڷG^^[_CڷG^IR_ J]+A6?L Z\Tz']^s趭ל-qPI 'bNق{p{iYV+# RXP#Sii`QZJă遐G@?'/Q1c>:7 Wf|to/@ɼ*<*ѿ\Uώo._ʏ._ʡf|to/Kŏ._*'S$"(3p&7 4J<A5h:XhŇ }/?\~U~_:&ҧ$2 ( (((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uZ@doh&g.& N!x su?EhꚦĒznU&X@Xv:luƮۢv'v[5ꞗizAmplL' KI1[Zޯlr`3[@ $I 5"|9=DfF tve @ tE]Go&yXH<2>%j%nCn|Sv9ڈoQ^gZG ]~O57'>5"hƮe@Wi_~:ozoon`O.#i$|Tdz ?}6[*մBɫ-RD /98k{KoW^ZԡNt%VLq$~dK+ [~63kBdž5,5 <2[Ťe9O1J5 E><^6P 3 `qY mLwsv&i5 !g*j7'koWiHeAَQ]˹ _{N>m?5=$Ur_=uU=uT. ?ҿg\AZJ 2u7jm4e!$$_wu?EnІa+Öі) w2\vj})e" [=?|ժW:e4'FHc3!z2ކi=i=av[76F#smycFO"Ǵڏ gǴڏ g\v[і4{O.{O.cf 3Q Oi^?B4lJ9z_VhƱƊU uQLAYnkaj2LmLAU`I:(((((((((((((((((9Tu$ݪ:Lh(C5_|m}+kzI$ {Vq(ԫ~ {Vq(ԩ ]+A6?IK&')+U+uz@doջXZu?@5B WP\ù̆@$0 p^Cpcݙ I ּ~PKk4ڏYe ʿYҵO-֓ᯰ1RU!`PTsw=}_?ߖZ\ug Z#m#*FAqU=Y5`\\)hˮӀHWEq6izNKN_-ݮl_h 6H5;%׀|?>wiwRM=I䍆ȼт %6+DSj׶Ks\܆0[. ;#?Z(rhUTϭIldQ+$r:M_Kx.zJV>Cc3vSl:Bp `F( ŷ18ЮnMv}N{5FԠOo#eQA#M']GmmN5KBSeC8F|`#Io}iqwsirOjTOZ2*s}ses5$d0Hk Do-+ex-Hlۀ7F,9=">..}yH},Q]m޸`c[CXg9'9퇂'77kWߪꒀRW]11hw=F{cjV֮4Io'YQ77.)ھ׶2鳬$0!c\=9KmgMfOC\k}8+H,ch$qq q:Zɧ-G Q+A.,srK53X#YaYu)XBEV R=(vnׯuxmG7,$(t0]P)8+qu?xS51^67[lg!#89)_ٿvi~Q\MJW_Of, q誤%;QHaEPEPEPEPEPEPEPEPEPEPsvITtQEj5=$WdtoTI|QשWQשR@Wl"yB(BrSSR{v+v?Yݷ/?nu#AԸg0 msi~iQw}uwo.A gbF{*kKO}W1$O@ǭ-bGRz_ۺ/ۺ/jZZCguaI< ǥfx'S-7͵ޒP(\sִt_ Y?t_ Y2;Lx~T^yEŪGbĈFOt;-2]>^6OAޟZZnJT_Vg[hցW"V ]LP: DI İ4_Ə_ƋhE=c "gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOQE<(T_?GOSyQ4ET_?OE<yQ4E>gOPaE>EQ5 WxDA681?Y!_cDCSQEnip2-8.7.1/doc/src/figs/snap13.jpg0000644000175000017500000014237113351443023013421 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"(((((((((((((4ATt yJRQK1`SH *[q"Iۍ~sTԦPaR^kgQČ9Ϯ}J{0+䜟QF_ƙHj6*̨He֫akl[ErY%UVpiQ"oʸ8r,]C]\UWWVf$O]L )#?'Ble_`'TTE)8ꋣMiډF>\9S.d[%x?lTB cs;ri-7i$vI}KfH>[7mF A,"䤡Crͅ9P@ePNO'?joZLK;ߵq~P`]m l$oS!*Q lV=y^F֧^,Bk{2X֣/B nX!RS5E Mm=w785 9/}"D,A(޸=p+6Tkj[[_:KFBc+ZVo-ս̈; Ÿ~9z%'wpU:F4Ǹv̄2p>Pq7cG7x"Y1IU |EJR[_$RGk:L/wsoJIuki˞O6@T9l@X4S=7CZgPxK)n5 a{I!A``@j¢SeMp :c`t4-s3Գ1'sR+[_=4H\,ԅ-NO P$R[vH#abQOt^F{[m G)O2===ġg"YGem`QGԩ?k#hm+HnA̒3c   t-EFb2qdBPMPAuxVtTŜ!E<[2;;Ym~tJdB71Ģԩx{Y, ]˖8VbzTk}$ #x g{z}J?k#t6689]e&]-K7ʕ`IrÁvjj\~S$7[FHyKsu~rӖU7bԴن4TN8`GRk:]{{BKʼnI-}sRx*O{dk7GEexXˀ;G$%mv]\HIG,#+S=6%@ir6+#`r`gߴa mvi1An=Hj)}NwGçEPU4[\6smrr5ER%އ$0Dm.]29WU8j6@"0-o$~P 3.W$䞾E?ûڳQemh !Gxah_/j+ZTIZ$N[pQDpQZ2Y=|]ס]5":k\SA=Ae _(((((((((((((= -!h:tںE1FR@*{ %SͫĒrj]-FV0&nHPvt?SRt{[,"2)g`yp,t#n%N>Xq滋#LdY/KAiW zEAywPƛg4pD@{8)-oq]Rдt{k%K^IǠ⼷A_#X?׭-X-mIāT~2+ky[bl,f66_^k®HG9 p_?&-*}հHePv2|G6#ƶ TV-Rp}s)!Rbچ1?.xsU˳Ԥ~U߇cVz٬*B+WcO`+4 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (44O /rEocah&ڷ|1Gֳv5IEwQVC.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#AQԃa6Sa6桗LjzRTBO_%ykOޯx 5+ʢ͸ncnq#jbN0A+{uJPɺ%!pӞkE$EǼ"1a$dY0xjTFi-drBQx̌]pӥUK.Usfr匮o!|afS\g[5i$w,;㡮 re)+h9mlQEyQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Z'sEncah_ջᏺ>Cy|4 ( +uמ>bЮ՚_wV_)ZzV 0$|RRoEW.?VT}RoEA$ T'Bp} ( ( ( ( ( ( *)bv%DU,4CscuVR>@EQEQEQER4H:  }\:}\0'5 *cPҐޯο\y2kޯ,Ο-޵9H?peXF!\m[\7莼WO?;>࢈>ࢺA_y/ν Y=|]ׯ5m#Om:+}}4)!;?8 z7kwF#I#!AMZ9ٷ[7c/\qU|5MxrNhh#%I(@L+?pBuY׏j4^eGOZ?EITo|;j&t,gHgUTqf%/ާo#3k?|憎>o2T!ϛLUs⻯u?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_?6+/.Mh/G"Qˊs?_w]6Pe*'z 3Hc!JWkg8QGČɾ2$c g9={3_^@Qsݘ'uF\ۜ3|[}&ho_Sy|6D[}&ho_Sy|6KEoƏI5?ȣj8@[}&ho_Sy|6מLO8ls4(調ACu *:tZHo-$/ژN9d~qޑq]ưNPqA&2G(jz}OYȲXyv7yWVUXK>KDF@ rݑkhג+*n-D T.r@@Ǹ5{=`S?`Je/WfEn;u3R\j7ej_h/'c/ R 2N}cÒ5{=`Q?ZemByZ˵$*Vq_#;M?#\@ʹ5+nɯQ85{=`Q?Zzdiiqt*-]UҹwϲI'۷#:;UGY]}ĸBױF ЊatF2Y;ܐ>qAg%uG#1f[Ԭ]y4ZA^ ^X?Jѭű,Fzdcڴ<Ԍ ;v'W[uѵWk˔rʨ$v}rm7A?G#WXJ)(2G#<ҳ.Hq ӣ׀Ns@ zsUMg'6NşF ?G+xSzzõm$k=ˢ RKYmw}v+CKG)땑#kP\Tz}䖣Whkh;Zː0[i\uǠ1G<i sZb{ܞHZ^X?땕b7F9 u cWGu4 a,M:*1`T8kMG=f(>$D#<]\Y^]QNF ?G)^VmZIK۝vD$=TqրS\[┩;rq$g;Ӗ*Sv2ɾ+gL\Ojz}iwXBCI>p{}Gy<[[̖0,mӜ=**z?O$m{ ?G#WGh#wJGNsth%UKѽ;3QX=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=WF ꨣG(jz}𮪊>X=b]?VHdf0!$ccZ~L/Az>ס/YAq Vk|E1EuW_y/΀;kCwo*h-0b,b H=qhvvT ÐpkV]ffH݈Tܣ.8;ۚȢ]?c7$۷~qJ}bTGD&+%xj),_sn=v+.#IVv"kd 񴀮q~p~E?lMY\k>o(mL[ҡ9 PexJ(ߋ07!IK#wO@)HGtlt5E/P_Ňs}|I;(wcxˬA,)L@~^O5E5~,=1kVZr.ί&ʼn'9^y4Ѫ%]8dQG(_sY5M:;wM`PX5<~ qop8 <_%K7Ȋ)x.KkQdAV\{}*1YGۑXSxJOul'{Yv9]j,ŴĒ G 2 XRߋ1Yw6VmEkt9XҊ}S. X&`܂k>G=㽒]c03}MY/Z)<}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}΋sȿj?(?֮v>C}ke&A"vhxc!\m[>aڦ 8]5":+f_t_@66tZۈ,>c|$`*ޛjz}2k4[9y0x] ;^gԏ~9zs7̸ZwgÃg1]eK7o;U;JP9k>#jw%sF` W8kt;+ޯ|Um~5T^V+m0;R5QnϽ(IŸ8|VFIiE&3FfY1$p>7G|"{Y+8^?<\?v8E4nyV_>lþ֥b5[QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!\m[>@9[Vz~5Cy|4 ( +uמ>bЮ՚_wV_)}qOTQEQEQEQEQEQEQEQEQEQEQEQEQER4H:  }\:}\0'5 *cPҐޯJ3Q5{?4bЮ՚_tWp̿n-nLJX{H9#mU9.(Ikv/*5Og-QEQEQEQEQEQEQEQEQEQEQEQEQER4H:  }\:}\0'5 *cPҐޮ_mOt"HaY<AWt~y'=FY'ϐ 7^˳"pbL~c?֘A3OÁj9?!ެN;jN9#5$z⌷c< guws֓v #e'B:;oB6fZ ǜxy2>rz=ED18_NCC|_zOE!7/j>rMu"*HC(3'5 ]\_&_*H297;S|DUd( c94='b3WPM,f٤-R|lOntǂLi-[xH}йN=9>t]81Aqُ oYo'ע!(E@ nڜk;e@fvMK>/S%Ze%\2.V!k8۩o?KWc& rqqisoȥNYE M&n+gl :wu]mb8@-Ee}oh __{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_[=SwOrz֓?k7=?UgVzQvGuQWa˯f_t_^uמ>b}qOT"(((((((((((((4ATtE4N'H|$e9WhU:^jSK{qm4ff;2LzcҺX_0+?z_%|z}ClvqJE)C[+6ݞ1K#L;9?p5ޑiOFS06LԢմ/I9rOH[P!|Oҝ8r\9>"'?,3ԯcmϽHG5ǒՊ\^FI ըFOXxbjk$'ܓ[x.Ȇr VzVc>abkZ*U(ݱN[T;MZ, BC31zUO^' #+ _ a&n3ϯ5Y E6QJO>GWn[aP{5Zާb4ȿ`~F3ׯҴfLkV:sЌ;S@Q'uIi6#{Սp^lʬ>uG 0dvA9.G"]^;GCK -?QKO4$3K' HqLuE5{Iw5 dVȹ-9'K{<O5GCK -?G$`o|j(i>楶qinC p8zT(?5E7qi.%)+r[i" 1$QAlU p:EGCK -?G$cQGh({I5\;nV$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}ΏO.o.GGL<#_j\!ER趮?ֵ8V.MwP}E}EX]5":+f_t_@՗",k\SA=QEQEQEQEQEQEQEQEQEQEQEQEQE= GR{x^tUa6c@|ZF-ܦ) P{]?^:xoͩ/ ]MI,gUt Wm6̤Zi࢈>ࢀuמ>bЮ՚_u:>5F$¢hՊw=ElU{U Z$' @Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@!iiC@ԃARi?S?SsPҦ5 )\߈!8ϒZ#"鼴 X u:⢚K/,yc$ӏOi1- NI;ӽkF*zA?SEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCu *:tZl?7sOl?7sO2C/J@W?z{;ֶ#Z1I973zWЇWFvX]\F,K 83:(ħ4?fGF⩲xQk%\#G Yk?G N/n'm^8L`W~劦=Pg ڎ"r(Hs;]]Mp˰^**{[>=Pg ɶKT!ĠHpy##t2bI_* ^3+5O1p~*(dr= FAL6~P}=X;N1R[L\tm>?I|tL.c&)J9( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (44O /rEtB\m]wP}E}E2Y=|]ס]5":մ[[Xn5 He1ƻ$U`#&eU,$M\s`do+;#)'šVTicI 'g+fc+5ʡeW }jt;[2 70^yҹK;FTh >aY rp ֮6:-ݽZ)c*sNi5..[[.*@luDZ77Km3=32(l-yVc۽J㷌ɴrv3{j3\K՗YBkSr2EKè.OT6Z~ `dy_Eow;[fP4&)$dGFsJ~֯9cImt(bk˓ Y8S;YEҠ7R]L x`A092Um,,[y,Vt_%v3pHSVXX -DPÐ :vu]{V WKyX+m`k) htȤ7$xb%Xڝ]H..!CsK$*NW+/+>n -L%y`A4MW;X.u[F4R`2z՗Y=i{(cF-8-N>C늟]YRŵĢC&}UʦF6?C*9=g { TN3:+5stvL혌6~{uZHQ[Y*:H j >z2A]OQ#V_YYqǭZ _^v@~3:R[WV}-}6UJ/˷w_{֏iW|l5e=gUxt]>{[V\T7{l|M0G.0oUs8 )u&ITď E *bnF-YH~a - MYy$B+4&Y8^NzU-eFRƥ<{|Q3SxȦԻF:hh5e=gQ՗XJeB&K|obqP >ԥj d1| T uo?C*9>In/]qj&1hq2,d[%p2Np+h_>Uϓ4aƄ{.NyQ*M3-4}.5 %N~R*?Z[-O7TbV4^K̐4  rzVk%XS,ZH.HZ50 o9ZmQ)47C(jzC+ NiXdbבY<1| jqet}:.Qa4ݝ6u*nv$ؽePF*@#V_bڵi2)%!)XW',c@<V͉)H 2d9ҔRncE "{ O0*䌒@6-D]71zN=v:ёQ!#,nD+WHӯ b[(EXYn#vuj/]&Р+\|щxj2OOKȓ`A+fOrug#}о[{;x#]>ǤY<+ FҦjԟ[ _YY5e=gV֫1~oF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZ̶ib F9B==S&U/rozM;sVOC ( +e^{//BVk|E1EtY>*zm[y0@)ҕ'&m@h3[o?g>4f ]?.T#?M@Q@Q@Q@Q@Q@Q@Q@Q@I$C8O%2HH|N!B&*s˹{4}yƫwO]MtbY#i84nR:rNrk*D;GA.台[/x oʃpVW7H]n[yX>O=&=> xDfg=P 0r1—L%/^\'ƺj^•ʾ`Ms C>g,Mf t8#keǃDp=UTgRSnU<" 52F用o!P͍3J` T;Q &=&y?C%6-I47 &=&y?-CcWZh Koj v?H eo&Zm[5FXHީ,6Ze HO?3[<<ܿDݭ# 4*8\7M|>ߦ >§òu?kό?M[|aio_G7Qa}~%6->/oòo>0K4mo[}Io_Ge/ ߋ1[|ahL|>ߦ >c_]c-ѵ o&}%M}Iܿ.~/o[kό?M3K~(|>ߦ =;/]v_F%g7Q}%M{v_r u"lEYOb|5kfkIOcxkx*wP}E}Ejd2Y=|]ס]5":.tԷimKn?_&oUcuH3 j\޿qb͌C7NA֖FWnk\_ݸY>n?_&Bz^Um-fHrИp;G>hN@D3ח_ݹY|pȌ`qwg7mߝzEm!7^0CT Qt-ipoU!*' wmX`"~FT}Ikwͳ[Jj^>ؿgp[ >zZD:usbsMm5ԓ-r\GE Eo_Þu߱p'-zsUu "Q6)Έ9\2qېHoU4E/UNTO"SܖA67RI/8,8Q*F 0@VշpY%As!Yv qUŚ=qne}m,oJ<9y&Gq ?1@#;01Z~}>Ehkoo"OVSOr7bab噉9RE[C}}!:X<˵@V%;m SbI O6#]I q=OjO渍$#e;@ e?w5}>*Tzph/畿o"WOS>~?h>˵MtEQ_+EW y ce*?J|D]pWt~Zƭ'\w7L@pJp?'JרV ``3qWC`mfGp3_luKKGo%mU۷KiiIm孥(Ea#AzPͪNih&xpq09>2^\Y+;i᜕ɏ@G4r_3lM#mPOSTMmascwn,;G;@q\Eb!Shh.$b'(Bg~ݹ>j1 X(kAwwiV\eCu[~ZFbdaFeFpIb9(#SQmro\mKX(,DS_G6!n|ӭdox:AA˯f_t_^uמ>bPhgmHUfGGcS?d?oZ#vY`о́xfPǦj񳺹4Wp(\²KeЛM+5TrllddlF(>t[:;vbiƽnկMB1K}C@.qf;{4AD7IZ#wB641#;``8rI':i$ 2ź`)W/l汒8rbF#={V8u4I獧φT2<[Jg_xH?L|Lߕ :;|bIKduPK,I,cT֨ꫭjg7}VH&H,:U4=JÛmVxJtliy߃ZU9,0W++:w!p/pU~r\2O@Ov{m6LLw_$co5ֻ{cA֓{mYJsPIK$s.+hh|r3¢U%#_hSE ,Mt2_%=UEZC[E6Sjc2 ۳Goֻ{cA֓{mYJsW5I;1e$ v 28X꺤${hINB @w.nvr٥Ĉ:I`~GE_`6Wswuۋ4qG ]VA.PcSWCۛSo be͞wƂoL2?vNu^E&[j̇Ɉe^H'h8gj[ko(E+շ UVmZvo;A,[ÀˎG#Ұ tabadfib9տE}8[2{i*͒NrIh:7WV?p$9QM?JIݗOKXc͘U uF՞TѮԥf3Bc9 9b23zѵë_l+7 p%NN!o!8TH2t)GaުŤ\M{hnǔ9*1\[OGTޱA3˵g;cwL5ii-XmhK*U0NPu7e¥%8L*9{U[Cyq{˻%pX.vd-/ȋOֵvM2L/*,ve ~CY=wwRJ8\AZ= u#AQԃa6Sa6桗LjzRԚ{?wF5)Ԛ{?wF5-Utlj?b*[_I$#HC‚ 15-nW\ђ U/zZ[˛P_HLj]u pA[f'/Z νͪdPH(ALmps8PI䚞'I!Vɭ__khྵ}pmi[:? 갿oRZ8k"f $z4ChI**J`RaAV[mf×iL?'9q[Rs,^l"Y4Q| U'pި}mbW1r^UB!K{2: )?./|:,D0K(IXݑ>If˓Ki]OiSIftFDʿqʐþpG!ӼCh[}mІH9~Gc㊴ZlZ5լhBhZ@'5@u`>Κl2B#bU$Nk<9Q![+pA'i1(åZH5=2NcdY.8ު ӎ"/&i U]d_M H0F3;(;;[04H5 :k6]pk*mW;ۦ+;Yӵd^NkXRD``q(C9'/͟#8-ykp ixO mX_kF`L:uwKdM&ȍY yU|`@':UK(5V+B=f $C*6H@RZ]Cz]gwQeW1ƗSLʶs)W mq7rkOj쨡iz_`6z #1#$uuߦg_G?7_ӯuSNO㯴mLjwh]J *Qb9':QzαtID2[[_D!° ]ski<9zV NX tI=\7$՗藦IRthoMA,PCzywi$u\БZ_KSj`LX@iC`劓+KMԦtu+,>qZ4Qp9}MRǥd DeF3XP1=Nj+M^-K][]+1HdTLG-UK4巈Z݈B]iERkڸbK8gPÜr@k:TL[Kui]5LT0=-ωᴊ +i!m9UCܖ#a@XۢuK- ̖Y30  Sݽ֗"&"5̊:*=3bد爐{;;J#E8 :5@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@&UoQmro\x:` e^{//BVk|E1Et2V&2!TS[n'm'Z|I:llp0#+,ׇ Lp*&ôcXr|.4ž nIP~F My\j663K9%UgyֹgYO$VrC,ZB ¹-OMY VQXFelkѐr{uZS{'.^[K=Xvp9K;/c:\7/(,UDzM{ڮs:ʥ?++PoAmy9$G]9ƐjwE|i%1!Hb=qnqU/LoʙԶ]>d1@} uS#ԕ̀PF;sկ.motyP`yl9nvzEZK[ "pKg`rZEyo%c/ ʥȬ]X͓&\cgzD\_V;)mCd %[n+8kVS$=H3ޯjZ{l/o󅵌6I &)/<,.jFe+27.wiWC,VK{gr@P~cg}Վoڝ:^c(C31皖]%ikLQ(y OZ˸G]O;W!-yNXry<PiM:I#!16MKkq XARr~}mfx.m$pV1Ն ֛Mm>̷3 $ u}k4PAz<9b2{aCa7,Okz>} K4<OQqRWbww+Fg'n 楧eB]rI VyTyh?G*Mt:XQcyFXN}ƞckQFyoh7wsΏ"NH̿wZ@4.biD1 ]ݗBk7_kKwօɂK8vSUmA i Zjͬ}9d\J@n*vJ6 t$izyFG}7Q3M6pGq o*y$dVF\rWդkei nU#Xyeޠlt&8V1.BOaӭ7]D]+h`mJѽA,F"&$mB5=7[QHaEPHzZCu *:tZHo-6" E۞-)9dȨIH Rio]pOS4lG\? ]E5>\oKqVe\kp_Bk$Py@.qE TnG,R ERʃuvZ|χѣۧIìxxV8}몢MTI]m,dA)9ԣP&䶖!ۜ)#:uE\K q hGC/q@10; MaE{V?3{+KR[r'}B6SvUS͌+:X:((((((((((((((((((67Oxun*7sQP.՚_z^{//A?S_) ( (M* Xa@j.dM/L&,Ug>4}mh[&mIx6`v ~(Q@Q@Q@Q@Q@RHu&{D3!B88j()CKHzGR MxE=fE0 6v?R 3?¬Q@dYۂ:>{ DHudT[cVOjmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@jmUjmUi@7 SƦ&˱\=s~u\Wῼ?΀;>࢈>ࢀuמ>bЮ՚_uRkVMd0#n;Y)T2ؗO9FsXz֝ĩ76ri1ݬ!%*r\]}z*I?L,,sayCH=GR{fomA'x>Xb3hsˑujC4wG^!Э5m;L6QuwX8ǭ^>\Y C6Y#ogluX?ؚ pΥUUmLql-v*"U:U:j_nj_C{}mR$@&?,? /Wu]*WX.E 2Бӽb \]u/ݥcp?m?"%GehH,MRO?"At+>lWdmɀi~]H,Mi_}GQ.?Eخ90/i#z5K]?o?&w#z4YY_& G Qsb 4.YY_&mkp^H㍤e&@X SUAt)hz\-đIRiʑ8?]7ұXnfƣ,oa4$C"3FTq 8jV7oˉ&\qFFIlAbѮJoG¬y!}<1 +BnJ:4hriOC@ԃ@F4Z)2=E E&G#Po[ ?UQU"#!E qiQT'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}OKυG ?..T'\Qt}Ou_]&UoӮPM17̘{15xs7 ( )˯f_t_^uמ>b}qOT"(\[K $ #jZ(T/l}}!m Q*J(?_ϵ7Q4p!rvʌrX ( ( ( ( ( FUu*HpE-RNɝ YJAV袀 ( C#) (((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//A?S_) ( ( ( ( ( ( ( ( ( ( ( ( ( C#) (((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//ăx*zX<,$ p?!/[y=!tVg[y=eo\ :+3< z.VoOG[y=mR]B+em6x <Ym_-?֏[y=eo;5zӬ8'3ZC+e?+7-c>RT"~fg|W@Ot} Z$Hn}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏oi}.4}Mh/Aϸ̏gi}.4}Mh/A>?1ZC^*e??ޛ(7?֗Wk}.xgPzoGءƏ`Z_?s3^*e?>ZCCb=w}iϸoxWk}.~4}MhA>?2[PzoGءƴ9zcV^ҍҫ}Mh?ޛՙvJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@vJ6J(7Pzo@ 4[ß}?κ0?lf5xssQS˯f_t_^uמ>b!m#$Ikocĺb Y`* NJ"I%1O\|jȆ]pd1 Kg5_B}E%iJ~s?^+2Zu-}:qA?Bٺ5;\#`Ҳކ״񨽀y#X@,h]_c7F\ޠӊ+Y]˅8⋫,u^{˛:qEpz+7 p9'RZ7Ί(((((((((((((((((((((((((((((((}x:+o((!?y3MCe q s@bO]WوEUDG) Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OF?>Կg}K6 R^_ @?j_P[Ǵ_RW  )ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mc•~" qn?zMr>\;Ut@6v59GOSQE0EPZ4@ƃ FOv;G5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5G#Qp~UykG5J<5?p~UkGhiQ[6֢ 0*@;S0(?nip2-8.7.1/doc/src/figs/snap14.jpg0000644000175000017500000015071713351443023013425 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH;Ǘ[YY#VxRN}^c6c<4 |Dl.Ȟ qּeb>?)݊K \ynu55{°;`Q@g:Z:-S|d^u dTCїs(}O*K(oh<+Fc10bI>VD\p%04\p~Yndb\PQzt^֖&3 <YTw^yDw =LR-W=8vv`wc? SSِ ː,\/AКնWDbU!ܴeRNޠƵuא*bq،ts\8tD{ڊ((((((((((((((((((((((((((((((((( B\m[$Q딿-{ ((]5":+f_t_@՗",k\SA=5?j6Ղ('U_[pqҫ;-5uU"W=ֹuo|y]>uLX?Q:KppX߄ y؊cQNΈF.7hs= A'P 5rpijA}0]s CO]Fx7-帟z1K<sϵkY\iz~ L2c'a/B`դO8d70isBՋ2v F&sr|w(`qӵ7[9a؜xv3p *#8I>/fi%0-L!E]ՎsOdڅ̶mk"]9%|qޟkmE!9;}8Ի+8d˴nmR[ݴ*@'89&I2`h)۹~ץ #O{Cbh(㉈ }xwᤊ6KDQfRsW.(eGd2qyNp?*H:<`\\\"I+IpTq8~ !#" //"{y`W/u}>"'ˀdMԯ&ơEw)ԣsImK[g@6!{z9 Zk|_z?׬y-fNRHfEAPI'I5k?!YY e@OCێIo$; _?^E!롢~{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_{|_z?׮>_[=SwOrzZm_ }OVuiMdwp}E}Ev Vk|E1EuW_y/΀;/EOPYg:|Es:_j3fvy}Go^}h rrcڣ6?§_OiM{q ܓ>֗?¢kkBodVO.գ IA7Zw[K#O0g#>6Ah,^E=BDFtcǿ[gyg.m`o\"$gt۞b sw)NKDΑg|VgcBƚaV麅Vp}zs@o~VOڝrHķ[Z;l%T`yC?CZ0 M̘OӀ+9B,מYQPܐ[8\GթZܡ%ЗƚGkCjN rzeM~,?|* ]"2BI*q Ps֗h({I'~%m.C2n#V"z$VVp\mF 3=rZs#@(ϯҵ;y#if6#8ޔ}V򇴟syA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}YZ)#+u]C)̶QpA ۘvf>$5E?RCK -?G$cQK=?(?4K{<O5}V򇴟sg[ƪ]o|!Gc`EFFk I;sg[o|>q$3FK!*~Sg5E/PlK{<O -?XQZ?}͟Io?%P'k>GCO|IxA܂0~VHCs IP[$hUB:EU%yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCO -?G$cQGh({I6%P'hyA|j(i>$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCO -?G$cQGh({I6%P'hyA|j(i>$(?5EU'yA|[Ʊ=?(?4K{<O5}V򇴟sg[ƏIoƢPlK{<O -?XQZ?}͟Io?%P'k>GCOтHIcW<1Gְ4O /rEock qb\ Vk|E1EuW_y/΀;/EOUm:0 EsV>숚3Aߘ?N@:Cc @>X"QuM6U#ܳO b,Qc +2O=Bâo~ !:?QM0dx.2^j5&$ޅ{5,-([yFG#Mk^: U1C?!p=s@"U'DY°(x+K@ݑ@xH-1m#:ϻ/qn[vP85㒦>TS<',$O3 zvwqȯ,e'c}0y?Z~E}jT9H 'c((((((((((((((((((((((((((((((((( B\m[X'Kڷ1Gր;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?JiQI47Xݗ愝?ʼF5rפK4s陫SŃasL  !FpG?WiVl70FWp$ b2 {nq 38sJZ|lr^#ۡ7c&r~{P6_>2Wa)? IdEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ딿-t}kD)[V>wQP.՚_z^{//A?S_)s`u5"~UէU[ 8oy: D<뫃X؆-〸CK2xj-ɪ@~-'O(uۋ&8c`gv#8zsYz VMvV7e}ϜzzuI`I>!eJ ۞> 5h;K> Nt>-4P|x&+5J}(((((((((((((((((((((((((((((((((KDD\-wְO/jA(LRT췏((Q_y/ν Y=|]ue _ /EO@ _Zj!o",@A>^?CVHU~qU6J@`kvj.LX*,69ְ̣zlm|b}y'ZZIQTWҴw6WI F(nG^~y:.Z+{ilTT+I.f!/>hߟzZnҸ8t6OA"BGR5g<یn\Au{iaز<}gkcg}:cevlJܬnH)խu;(4'cm ) QJ)d[i!1ޭגh,d9dt4kukA P6߻✫IfVƃsiŐ&FDU|ZN< p70\Z9coo_)R+eYt|!@ q1qE[{I l!3g(=*U,{LJEPa+<:ԟYY`W{x PP2 pQ(ᷱ?`*HnQ*+G՗PhV\%"Fv ˒VMŅȆ) sc(#{W/H8ۜqOttAnVP$V9^OZJ{4@ʕoƝqֶ\M<j] OAS^C+.7&9Ծ;G'Ӓ+ =XRL.B-מZֿ 1Chxnɔ0|jz}{DXtWBsc>nCۭQ{M5Vfl9w֚UbQc{/??F ɒ]tь5!\6G~$|$n/fI̻$ S*Rc؎I-&%Igp!a>-΋Il$K. vM^-̭b]2̫T"93=ź]#'˱*$dQTv"AC(jz}k}ӽh<##bS' NײZHo.ÿnn~ү{t]>. pO[pc5e=gQ՗[4QoF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZjz}/??¶hU=;YY5e=gV}jc/??F ٢V`pc5e=gQ՗[4QoF ?C+f>[ñ՗G#V_lG֫0{8v1C(jz}(og7#V_YYEZjz}/??¶hU=;YY5e=gV}jc/??F ٢V`pc5e=gQ՗[4QoF ?C+f>[ñGcLF';JᎃL/Azz~5`$M1܉/((e^{//BVk|E1EtY>*Q,fV: ʢu:)1ij6JLy:c:)raTV. ;:gmUo֠u1FgXGcP}WTڴږ5Ì5ᔶ TtbQ`$WUg#%yU gOƫi +cpHWkFQ 7NW5/w]bQ=3zwVJ ⼵ekems`qk9R'yE?JMlA1iF2ž(yi'kS4 PY=y~Xm#:70YH6? ^—<5ω+w8J$Yc:qکؙ@ٍ~ BqeC#64{_ʾsiu_Rm2k+-P۲#O=:\v}Z|v6^W#,0Y@´{ʾsZOjї?j:/OE)=a1089'yVTUftTnsվm3' (}9ڽnl7vprW+|qjzM}c, MpTs/-W18La x—<8G??gQGA.??ۺE—_Z4[Vi-m-\5{z"`{9#ӽk~\X4i:n]3Iwo6.a)iH!ԅs95&a.Cp`dsr:kyUVHZi@!p|>$'5s)eo c5>4D Гgt c AF𘮥3@KkB)*wV3܃ӎ,Ir˾yWK <2B[fgu`:Y`Y_c,x;}jE%ԁeh"2BB=r)13pO8'54q l 5hC8PRͽT2E瞛R~P媟uA]~ I?@X,iU}RLY3}Iyi <2s\7#FFv}?@v6^"pV-^e "DvcOۦF, 9 QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEih_ջសah_ջសs~:_ ? 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@r>:æ?5yPݒ[#pAzL: 6ܘɭeTiEW=vq oCS;'q^޵<к&I`s giv$k)~a6ӷj<7l$G"c@AjS:$*<=x[\3$pG %7mA'{f!ʳ?@qi/iJ1 zԩ#cx#\Iሴ}NKv̩i9Ǹ[(((((((((((((((((((((((((((((((((KDr趭 kDr趭 k׊iguQWA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~UesiD$&h p#hy*yw6k)dc4!`c,X {cLOm>h;X" (*VA?AfYw00TڶfT@8קF4v5lxgyf6󃪑C:q~29)ɦzzqӂImKˍ <^V*rUZRknM4v!\kQZ}`8:ջk-"M[m$h n3֡ j2O<]ʧdz\Ջ4*("#*s'sʬNZ-Eu_}$go4$of FA'8y[|i\}Gj~6vs=^y&%ؑ8U8i[sCh׉+^d\7@)mN޾BmlYh6 $K<Ձd[]kk9-).t"8U1']Ēh FOA'8*jJU(fKm:$="bPdi$*q ltn RBK mcsO%MBۭu>l^5W /˷e?0’x{Q*I{iopY #9^ Cwh/eٰ 2nE?>O>d/.<;m2i  0zJ s`E:ȁmn;= 5R\}:upv$J)V'9㱧2i;v_o\a}\i6̌pxQUCk< 4k\Oߦ $p~lc*Onv G{ ѱ"$Xzuf *~?MdSXsӑϽG{x#-U~vf 3R{$kSoOjB \Ҥk쒼mogtWn ddu⛜Y)4vz<9DkuJ&[r #8|6m-EȑRHSv7B -Zo5Ea3|gaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGaw>Zo5Eޯ?${Zo4ai֍{zgaiϷ>Z4Q3rGϷ>G>hGa(+c$õ'Hj ZoR'Mfk׭ʛrwj ( +e^{//BVk|E1EtY>)[ltk;*O=E-:u8skkMI/Pi˒OP' yR$`bOS4]*(ď_5S^ԥ4֒K]a4p3ϰ43Zq'Q42~+%G8ڡSyogjH~_]%Bugn<ס(5-). ,_|+.5+Do=kҼK+<"G>n,ַE}i&r<2=EK^ӷnĬ{tс}1.|#3%4nPED5Yq"|4nl){8v e)V]NZoeIv.s'+*vu~nµ~%- (ʑ3{8v MmǺ@w翸؁99.p{VZ[LlOqoǽ˼OG$s93>88$3Y_x.)nbe2QZ'y&G\+#`}KT v1Ufr9Y1vKK䷝IXӞ[4&@P@\屟gvi}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(peoE??Uð]>{?s4}~j{8v ƏWgvX}Q.o>{?s5^=;c??GƫG`,}~h}z(pfys.K RYm[^B\m]I-;>࢈>࢘]5":+f_t_@͙ƝlNx: Q˧IwrPdy9xM:."2[KYcon2r:{TvLnbt- D:a@EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ딿-5_/j<5h ( (_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐YAu~&.1r}}\ԋʟXri#!GSif vUPGQZ ; z殭4E/¹#Q~-CPNkymx28'T^eTM!rq3W{|<{j{16(+T5]XL6Xul`~ռ$ۤʈ\df>Nhƶ#1YĦf S=Oi}F6%XUݖHcay yJRԯzO/byV^wѠo.3y#h(((((((((((((((((((((((((((((((((CD)[WAᮧ\!ER趮]Oƀ;>࢈>ࢀuמ>bЮ՚_wV_)}qOT5~\X4֭?Ji<#J2#Q`tk1Ψ_˒Uz\QD 7˨BbN a\ΫԀwyhxQtǝ!\|+ Po0aRv"GҀ6X-Y>lp~z宼A}9:Too$:-Υ0RrXR> K@$=ΧZ5iS`A,ޕoerf渐|SZvsRach(((((((((((((((((((((((((((((((((CD)[WAᮧ\!ER趮]Oƀ;>࢈>ࢀuמ>bЮ՚_wV_)}qOTo֬ΒfPNђ3qS>ߗ {9tj 'H FE4Dq::X+w3L#ɇHmS>S fdVFDlK@s{a4DmG|o*qq #zM{-F1ɷR56bTa9$p*-/[M2XXvJus<7sffAh!6s9zU"NX'?(\1ׯ59+hӯikMFs4[^4&+vfUQ 79=*6V^~S<&`g3{hu%; " >fq{GȐ2~h1ۙ>O{6Ld~ruk%fK?! 0R|#溋&-:OF!# $9*Jof9PYKK&1  .qi}ݥol݂d89*[}:5/0J h!f"V$\1zY{w{v I/Q<@9)j_,Wn,-nn,7,QQ0 j hgO>N>D+uQO} k &gD\I'n.G\㟭-Նw"ؔhI6]0zjQ ; zMa$s#B$'np=i{cfeuvP1mxg#k1ݻ)+sc<', ?ZukkfvFٝr9<@U4yiIiv҈aXǎv皱M;M7kgoA8&t[Bmd6kfywtsV/X䴔nߡy_!p$mۻ=*=V\\\ fH++8,0@384K}<+o'ۆPC_P*|y%W8 rfrq qޠ8mۙ n\ 8R{T2zzM#Ȓ|s$ |F"q] l{5xw*%x8I8?zbhb ;cUWF)Zpncޣ^GZsa,N (w<~$Vi,@a-$8piFQ{WZE9XęڍfI۷v1EhҤ^?4̟'p=^InE\@Gܱ)*gsagڬVV >?;Fͥj{;hĬT'&:Ul~B>%yYVkydV u,{B+}FqWmDkdNسNswm[I;_~W6)$ʱj3{jMY߱,[y<@ji%صʏ*%mǨqLmnn>%+ 6 zRF㽻CK40`ljͷwa~\w(k nű0~ve*7ےި\hZ۰Yc9n$0APK0x9 ܭyS1=]%ߢL]B{&Sc|rfn,p 9'2y"JhcgkH._s ncuV淼ԴHe+0"J K֖B/{є%@Rƈc3n),J ii8xOP~SQ&x%ݞEtJ0K#\G4gԖB$,fRd(  (->\[A 2JÃ>*Y,kXm#)'`#G}*^}\@ Dg% ~]Mjx+.}} c(A~U+i>e>߱}} c*{I ",?YϤXi>dWA~Q /Q',`H? >e>߱b=__G,?¬QGp+} c(A~U(EYϤ`H? E}ȯ /_V(OYe>߱}} c*{I ",?YϤXi>dWA~Q /Q',`H? >e>߱b=__G,?¬QGp+} c(A~U(EYϤ`H? E}ȯ /_V(OYe>߱}} c*{I ",?YϤXi>d@v,('*Gj&U/roc/mwG-uipQDpQ]#.՚_z^{//A?U֬n5iK1==?_, +6 1Cm*VL P$Tq?ZyoH_\Zimձh @[k(?IT k?&O*eׯt TjVMGm~:sMеvl QG*\̍Ăg釩5[M :=1$e?#\ Υ]3#Aw1Rx|9{Kɕ,v`a _Y٣~q>\Nƫ2? 4մW?xXm.ON;UmOċ&;l(9i]_3ǹ;gpF70$Qk{r0i cojsKh[0?tĽSOrNuU"W#9Ƿ[v2 8?9x+N؊HLmx۽eϫX[Cosjs} kiq j\%n''ɬ]h_M4I@=r1h *ޛ w t+}Ve`aOJֲ褖RXX>2?z࢈>ࢀuמ>bЮ՚_w6gu@([_Ze~'y {YcH럟 e _GYŨKS(Wu Js浟x~X/w񺭬RGI=kA?j=oѥO}&,6q\99ptht..&k˂<ٙB8d[ҪZaAG8?ΫZ,^(*pH<zS_m{$U8$G4EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP!ER趮}O?Q딿-?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUn!D,2uGH,h=:VK*D<*GV,lbI=L b}qOT"~\X5]?jUniUWHgvǶ}PwL;X Wϩv RM=2av&p>B0=zSB<C~OK!3+' OU2LAEm/ʣ}1~6 X|3}!UC2kk[Ė3Hݏm ݭIMG*TsYLIyr1@-2yQ$\N&pÁqǭt\[MdˤjywOU0G=hWdf2+A\F4/2{vIlXN1^tk@`K2ѕXjv`}"ka4qGMo|ʮs:I])$.TVt{khgGP? c@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEhh_/j|7=Q딿-?@pQDpQ@ Vk|E1EuW_y/΀;/EOPY>*zjՃUrJ :~T?{*ir\?4&C.7?] (^.%$r밵k|*?}l'@]ͬ,Ds!THP;s v-faow᱁Wu]o'U7hVg-J$P[I6@@ʒ9$U2Ds"\TqxfY$mAwJ &6z{Z:rY\̊h'zwyA5Ni&yw=сͻ*`RČ'Pb1 ,*"6sV-t}VN6")',9-'5x6pʤ8 STmOе7-40\)GӞ[qVB2+ީmZp\8HS|, ץtVvzop'W1P==rjjQVF^]_6U q +܌QꗷI|SMnP*43ʾJ~z&}BRԪ$HwqR3];Oq0U% 1U>9CGe u=1+WgZuomky*C1_O n9 rN~j|5$\tGG-*FI$}qI6Ob2^[I>c۰0 kۯg XeΥk Z2\I@ە1m:H5BZ)b'B`18s!zVfd!`Q 7XDΠȠ; Ժn㑢K+A'9O'׷jFO6ѫCnU 3֚tޥC[iǕ$.NJ3 F=>ͨq]\Z,ѫv|pLO U # P2p>l&izEf-%v(HR;)r];=u*zZpR`ڽFB(_S?!aHܸ]ͼH!}HwI{hR[XGوdW,w|* Ԓ"m̖Rkc"wSṕW[}I *NXg=ߌ!N'yMcޫ?.,qqUFq͌ =ZNеId^lX^F3'߷h!xf]Dag$_j]:Wy6^4H;Yxx\xAcyRY}LHۈHq5%׆nm$kam2\Q> 41ǦE3PwpsqڨQxslppyYy#/dF\{}/Ek;kgyJi%""  7{coNzҌ#~7ּ,.* u_h[9LVB%ØT~3Нz:M[=т{ ilwq u5WVuP2ҕD@ p+@Q֟ѡ&mוN#yFݱO9:zdu'd_ne8 `篨SB5Cx >G+v<՘tBmu$ӓ2܎}%I[ZƤwVw6I 3N##'75BI\x Y8qү_is qDgYՓyx-a g?)\ZQ_ϡQnDB2*J 4 as. n*;vU|=@4I2O12F1rxKቖha>I1׾5~r} g SZ_-*9Q֥iq";UBXwck\& wdoLՖo4h-Yy=1R,VUKp=9gW ! pǯzԉ[؇ɜFҘVA9b3duy%|7%<Уo_ziụ!vH<9$I?=_GGo;Y2I ŴfGW#i>Z#6̨$ :YOF'EWUVI-X6ߛ}͎{]]yB+*9$>(8?v?G2&s]'2&tGEIy猟ɣ?G`#<Oy猟ɣϰ]R}'h<O.>?4}'hsDtTgx|>?4{9 :*OtGEIy猟ɣ?G`#<Oy猟ɣϰ]R}'h<O.>?4}'hsDtTgx|>?4{9 :*OtDO?ZC*A34n*k+x{zj9k` 1uמ>bЮ՚_wV_)}qOTQEQE\MqSDwlYsjk ؚX7_ß}?κ&UssQS˯f_t_^uמ>b}i!m3Ch3lr>~ZC%Q"@np RSۿ3GL1 1K/33^*e?>ZC? z>){"~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoON[2}n?֗Wk}.x^;Xd3 y4C;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qunYu8aa!%8ǶkWib>5#ʭ{T࢈>࢘]5":+f_t_@ i$MS]K{%x<dFb;OPjv׷U̾zI)zw kX}G& #|y= aF:voNQ%GKX,VSCtrFI}RFͿ?Vrh)o@m'5=o̱G9'W;_[+m@t#h$q[XZk:Vpl2,0Xۂ34^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U}?UfJa:JKa2G¯wk1YAikwt V9E#p)-cz/:u[Fk.RK4;8ϷZ\69H"$:r6P&W❭>Y#?;VL=~ltAգzIY]R4;Y>#+w0Hz1Pk?]LwS\aHTȡe!>\kIۚtP˫A IȰ3g8K;+5KMA-y-[W' ;T:oqoB`vӶן _gSq\GAi3+Sb ryrQKY<_;[i y e?Q5`cJm/ky Onl-!8-z%zm}o˯w3n%-.{Tr^G?n#[ K?%Darʖs hZEy~/Gx]?OxuԬAf#,@xK[]zMc.ymÄI5ğ6Tn\8~W[ipxXRk|UgHOz;m3R]Inc)\JfiT5k$lʱ6JU 'P]5մe ʨ,wе_woGyxOYMo P%ü ŀO?))'Ӯ-E|Ջ3/nק<❭XGEe"PҰoZj,z¾Fp)e /gi6r"P ztu5BOi1[[\;. B=+#÷3kԮd:|eiL(MctRC6їQgAi؟iOwW<n״mfqt 2yYiwٮ"$ p>l泮gMF #! "%𭑐N;(Zz~;w;&FҪ`@'=;Op![%Y67[I5隇7KJI(8أtj-OϘc+< o׮fjΦ8ĭB} Fu7#ͲKpIԂA:kwo\j:oِf_+ HdneoY7Gn\#_βv*Gh ]w+5ze56hI }r4M&Ģdٟ(lڀ6n#Q]XBR{y*^ l~G| 9+7umΤڥ]`x]WkHuɼ0Gjsb2F@8㡪/< æ]KQV8>#2z OMzMmz[+'̭VQݬdZUOO![ӷ;h!mJѰFAt=R+d@76~>+ E{ Rs9 zI =wWh7I?.-?)ŭ2g\H=;V- R/Ll|bdGocK [jV!S\ k./iKHܨ+lWL)*;ƸA!wOj+iP_,f5Gdiv66@f.7;x`~Q"\wN3V՛^d'{zyt63Ȭm#$z_ibM p:CʬNN zxj8??ltSa'v76XӐ.t+9KХbIjwM 98ѷT`~jΩegqO6|Rq8r-ws\l"MpP9N8Z5/]X-Z `Dr- [iui[qm*$RgOI cN֖_iܛxsH3A{xdsOcp/5fMt]k-EZiB\S玵RVĵ-bfTF[h7:e pI< 7W߆yvVxcz:wuM6Al.'f-:$b95,}?Wi};x/3$$u߁5vR^kV 2`ҹ}kX m;IϾkn>LG5F}FcHλDSa4~u --nM0\2z,5=JGKonAIf[(|nBĖ\f ncHmAkmm]NEY!,q(lY-q\X:f͋8};.[qީ]&O9<{G?ugkEy]^hQ}9c]^4#ll 8 WvQn4_4gk徴BU)Ul#H<"9?8Lj'[JTb2h((WNyOc{8).Gry|y%M[dc,O6Clq\#ּ{m.0E7 H]VvM>!AwۧZv3j}x: ,nL-®38$~ko((\5"S4νq5e`2Atve?tvvO^wf ioTug}3OF?>Կg}K6 Q*O/G(R €=?ktTmoʼK6 ?>Կg}O? O/G(OJۇy'ڗl}?@o?I^h>"4kp@$o7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ck藖{e=sFѱ^[ht$HKu6@{G,mc€;%f!)ͮa _X𱵏 <+ck?o(Ms}4"Q(g_(09qk\=+ck?o(`;4nRUsy8>z_X𱵏 +ck?o(Ҫ KH,mɲ rO$z^y X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@E="!] Cjy,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@T.uGd}q\',mcXwt:p;8fJKH}BmdF?.{ck?o(6( qQcib8bPW?o(7PQ^k X=o6@{@Yh]_]16 2pH5?o(7Pdx)dm&%}oQT/ָX𱵏 +ck?o(ҩF8*X𱵏 ,=+Kh]DrN6@{G,mc˜Ey,mcX =*_X𱵏 +ck?o(Ҫm},F8@N~W X=o6@{@Ey,mcXzU𱵏 ?ck$d=Utt>+8 GY9$RI5?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )hnip2-8.7.1/doc/src/figs/snap11.jpg0000644000175000017500000010253213351443023013412 00000000000000JFIFExifII*JR(iZ)( )( 02100100-C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222-" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BPoR6v`$P֝WDowZ;.txE8Y&ֲčqYߗ\xjxQzYߦzYߖ^ \?]t-p=GS¼6N?b~[{Sx7,]o?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWֿG,]k?t\yjxQӧo.X:ߖ^ ZO]u[O]~ڟ}?+b^?b^.?(jxWֽmtֽmt\xjxQ߆߆^ Y Y p=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>ڟ}?+b޵ )b޵ (^ Xo9G,]cڟ}?+?b޶ (z7{SxG,]cu[߆\wjxQz7.k~Qp=GS¼.k~Q Y (^ Y (߆\xjxQ߆}m.}?(jxW}m?b>.}?(jxW}mt}mt\xjxQ߆z߆^ Z ֽmt\yjxQzߖzߖ^ ZO]ut-p=GS¼.N?b_~[{Sx7,]k?tEmO oX:ߖӧo.?mO >ڟut- [O]~ڟ}?+b~[.N.?(jxWI [O]޾ڟ}?+b~[6N.}?(jxW?G,msE(CW=,t#]^.,P׌x|_GoC! & }'|^it%PAQ@p/^е?]fǎG1h7QFꑗ-$ocY$$)/L'aZڧ ?Rن&:+,k)n:2I {.c6܎TC*jw3Cqb^qJq:/3:=SR;FfR:)s 턱IpvW}RFy],:c`Ed259e |_f.f|?-Au,Tg8p1oPφ;[KIXSCC>X1X]a5P90Y g<+m ]Z7:s^ņY 4uR~p [%AB] UK'V(.% ;Q%,99*@>'+Ťzeq{)$`LTǦka=!H ~ǠB-#t`v]THF`8$XW2aR8\?\b'`E 7~_Y4fKգ{+dXAƪr 1Ffrm=p?5 | *-GAaHZfYX1$gOoiKc$WyMI*Y7:a]R DP upw0/:DB!oO}^6T7Mܥh$ hVc<-Q. {n1[ީ0VtۛVW]Hc `v9SE4SlYX{#>՟Ojw6Ϳf1Ao,'cì:Lٚdmuϣv/h~m3)KD0|9Mpv-1(è 45/RkH$#(RN yikRnkc=Rz MN ]P*-'×zlEe$LSp$@?>kmTm.Y,mXܲ`cJ̻(u+52q'J#WC{;Z7Ve&x3*곪^E?// ,/t;]K28>juō?^{`ԗM٘ t9Lg;sK'H+TJ;5em&WEȊH,s1qy8<#ZO7uk-љ625V]c5=*-R,M#AIRzuZh2zy*={ä[1jD..> NrIxzg4k(ukKl }=,Ny˷i_BgcFuun QFun QFun QFun QFun QFun QFun QFun QFun QFun QFun U/Oһ$vc+/ujiWkr[9xP$ebBÖs."Bb[>d|wiȜVd7jtxI̞ÌҐa#} 68^mdjsY,L'1`։Sk4 BDCoV}n7}NACmusz5$Wge,GT uztkhNXnz{?BͿlc錜sjWͫȯ3TcA;tQTDGЍ >TZ>wfkX9%E|纽,M?Gʊ)E0uטxAwOVkxD_{DWQNQ\)T{\i*1m@wT]Ok2m4ʿvHȨ)8 ˒I$y$M(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(ۨM(C+KAQQ@  zqJ򨨠 w"P'#?RĒztRڵ0GLҊ[r꿈`=-5;9 "l{9K]vn܁i1 =Em±?f.V>0GLЕ6skKo hbL\m2K"mM?Z?0t±?f.ѶIiʓ,~P#.ֲ{?kpl#!ېp'C ɘ_V>0GLhqu>"ڟy%ڻ0GLV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*+c?]|a@JX3G+#&aV>0GL ɘ䨮?0t±?f.9*Ǥ?V>0GLשxC=!tSB=((.՚.?5_yt۱#@b-q< >ՇH.fG]=|$/ [MyX,q9go>c۽w'>0WukZF2, yhc,N +u-.-B2c*m#Ӷח_G@کGWc? Ir}]]Ku$WrHVAjE7 CKERQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEɦ 'vp5ZSȌ$\,nUSO3ư#Ҁ%Qo2J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV7F.畿o"$Qo (w<by[(J*<]+EV[+[y/$HѮp1+F.S/mNMA]V.畿o"]+Ea<<'57%0EoIkB |#Ŭ_x|G叼!%G |'nw}E}E0uםxn88EVk|H3qq}qOT"~\X5]?jUniUVH%?pB+ O\"ФZ/i]H"y*;CiP͂R)w>p "7YoW%f #m)fo_ __kkG~f~fw/=7^\dF>[ qӦ?1%i#5BX08`P2J(((((((gALpNO 'ٵ/ U_m~Gu/ U_m~Gu/ Ux+"]0@ A@Q@Q@Q@Q@Q@1@BǢ*c!rB1:)VPy h(kSߥ2Š((((((((((((((( M A?ɿrw}E}E1 Vk|E1EuW_y/΀;/EOPY>*zjՃU?co֬UVVUnBS)+.\jM6~A ehR:t1ZEITf 2_Jp>05$8@jUҒ <PO iӷϬEP׭e,]dv@= RAƋK Ym!$ ٌ<5FOڃc}s,M Eb8cNk54m^H;./0E0Hay AtGZٽ?sh7iaa ^1 pPpk|Z]v<6$uealnvrf[a HNXsARu! OL6lm7n 'U}÷Z]ū,.ih pӟ??,~&];Y,gP˹naAUw Ek}kk4S9BY <kZ\TtVwwSY$q Y鞕gkMXyVIxKp=M"oK+(d@wWI'WāMK ^ؓTm> ;c4!q$v'Mmgqey '*N$gYtVY͜׮JѰP@7/'zhd!1d:R[vK=Bkƞ%$QG>աmn c|&"hL@ Fw> qA=k7WV1 E`Y$ cf6Mmt"ɞݴǎ\bv( _s5e:Ht"xord1:$]]Տ/A=]KfU8҅tMwR.0ͦH$V.3lqE/uiedLqq2Akm-#v,$N8_u^M&(`꨷S$2n8;FIzmȍicUem61z*_v{EJBv_ :|CkΰIWyX ,@*ӸpBJ^[y(HqΧ?/MO ]Qtmg>W_][CC7?&_*q];9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/ʟYϕG&w}EտD4?  |ew_9/tR;.(2A xqԓ׽Kyv\ƅ1I+3uPz(FKYd1h (BK asf{.m>]->~k4hMݩ<ESy| _->~k5j D WE?j8K85S)ҙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&UcuWMZ buמ>bЮ՚_wV_)}qOT5~\X4֭?JiRT263kQB.1G BS)*0+#>wHК1?s(7]~qtyυW luD-fHc!\R{W(((((((1#mwLŷSQ@~-3?]MECv[;u5 E!ΞEy]2}~5PEPEPEPEPEP&;Z)T20a%% 0@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr]U*|1Gր;>࢈>࢘]5":+f_t_@՗",k\SA=5?j\X4֭?J@Eo!)_C5ZfHZ[Lqg,pæ=jEIU2]Ql#8Us8U ʹ_ }((!_y/ν Y=|]ue _ /EVZզ#71.H#~ΒfPNђ3qS>ߗ k$Tq?Zyo@tj 'Su$'H]fddVU ;}ҮU;FtٝQUјۆ ʟήSFWmP0O>ƀ ($>>ƀ ($^>ƀ ($^>ƀ )v-WK4d`LczP袊((((((((((((((((kSߥ2Š((((((((((((((( MZs\W+ᏺ>A2Y=|]ס]5":taLSAt{k!e}SFN k [!k,)sހ:o֨OH-ܫonHn@-U5SƧmq~#mdrb>rIsH ]F:mb$q&e0\wz4rʛD'Je|!igmjp5v1 fO9mO1O*ݯ*E[TjB!`󁓁n?b+oRD"B zkY"DgiT,}N8-EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\:uWMA((!_y/ν Y=|]ue _GYŨKS(Wu J}"~\X5]?jUniUVH%?pB+ O\"ФzJyJE.V\dT&?mj!mpO7/Pw//5f%h3ߒ4}Z>e?ֿƴ~7Mfo_&3e?ֿƏ_7/Gُ/@V\+H }n&'ǨP;@QbI0i( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ()L0(((((((((((((((U|Ӧy98n1}{7:XiAgYR?7B0P ( +ce^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`E!ͯu?Uj6跩6hA|њͣ͠ \x];:\[_[- .̱<5y^iz/b ԕ|XM Sh!hϩ:mܩ HZxM:W]kb$3,'**2szSwv:f㨢(((((((((((((((kSߥ2Š(((((((((((((((W[JសXiAgXP~:_ ?͝pQDpQ] ˯f_t_^uמ>b}qOT"~\X5]?jUniUVH%?pB+ O\"ФfXĢ"$`X&y u8~tz9-dcYf=QH i Ph ض $4lʣŷ{G-(I*6?OQbϽ}I*6?MGo>? ?Ə[Q4#J-ѥE$bm:ġS %̺6=jeeXv0N? b%ɸߣRy7/u&{E~K\hhtʗi$nVQG~?RPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEr0כ2U jƷ#L _=?†Պi~l 9]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_sU&W1bv ϮMm[J%1"7d}V]NMZ`\o@jT؃= tOQ,R[J+D A$z X#7vp9wֳRB#pf`;)0.GK%k+ .՞xK8G\UYQۢ;ܹ,ŐIX&\[}L²"G' X:RҵMLKno*A6vOChjиf>(Ň~|7ǒğ)p>خn ji0:j gɍ۴Has&1k}6_8.ʪv^Aяз/ JL>-UI?h4x!hx>[=p{f3Fhkͱ.3ɵk*8ReXP#ÑFMGtf?5!d OݻR &?V-x7XrY ((((((((((((((ҙO~C ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9]oF?* Z[J?ְDub_;>࢈>ࢺA_y/ν Y=|]ue _ /EO@ _ZjՃ@?Jj֐J%]VEIWik]OhI٠J)RQ@ E%ֳ״?5_k7MlcaL3Q'(5VѴYerZgjeyorpU>a~^w%wx]J{+1f o: d 22Gzh:9lQ,4h 3P:OALo\iUTo,[u#Bz{ Koc2n4Bgo͜hR={1Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE4^oPxkbMm/V࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]͟u?-rj|YSަcHfFi4њfhJzI׬?5ZC 6?5 5[Mz;dtx~cp9[XI{D[+[+nc_K<њ NsB ե o/GOnk-mco6*zA?SW?co֬s`OҪZ*uvEIWjRU`W?[Qşv?-XHf14њ~h34f'³§y*#rV##O~\oyk}~-I=E{v|vųu-ʹwvo.-c~ViDm]daViaYE d!z=I'}Z(((((((((((((kSߥ2Š((((((((((((((( MSA?ɿr4AA2Y=|]ס]5":k\SA=Ae _7kV W_Zh'U[Z~U; O\"ФJBS)*0*ŗv?-coLs!h34f3L3@4bn O4YE-Q\=MsZ\%b^<9bkfPeׯm"kd7[]Oƀ;>࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]K_跦?Z¼MK:sTYY) \0i|ݲQ/ ?E;o/l,yv@/ ?E|ܲP ]3AV?U3i7_pF:І%N*+[jWny68M̗ 6ю=*?06עKgSwcN v[[MhdS7=>]Vh7P]-ե*Ȳ۲U!p;v[hֺ:nbh3 6s'hGKxn?*Ъpɭ(QEQEQEQEQEQEQEQEQEQEQEQEQE5S)ҙHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP{&Uxox:os\W-ᾧ ( )e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*uvEIWjRU`E( ,*` Og*6 Y&O=@Ҫ+Rp=(hpޭkz\شUߔ@(r9qW!tXy ,^1ڛpv뎂:1^A5G*%QI+5:iD1)mzn隦77$-MsŠCƀ!oBGJקO<qk|Ajw[țo$rL׬Gmby}N=( ].vR"LeMUs%.%I?Kl$;‚ԅ~B92_(z+$ڭ[=P DOD# t#U}KR[[xtĬ'`q࢈>࢘]5":+f_t_@՗",k\SA=5?j7kV D*uOҪZ@Go!)_v[J%]{?[_e +EvJ G9ڵ.RDxxRqgMBf˅He8-.->[$ XǠSuiy-#+2PA<ٿ͛|.8t]0cM6i@wxlvs92B-nشW_IJ_]lu6F1i^]:{P<;} ^u|=ČUB[+b*7]~qtyυ@졊 #A I$4yΙj!PnVR#&pnom F=1L KR}z]RSBшI̾R Dxj{mUBP tTPcb#AE uPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_2)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEW}ro\A?ɿr ( )e^{//BVk|E1EtY>*zA?SW?co֬s`OҪZ*vEIWjRU`W1k^جҘE(&,I sSK-<+TarX[bbBt'J騪Z^gH*tu8*GeG|Mmeo gNL{gt3N3܃tTW=ksWu_)#*TuUGbЮ՚_wV_)}qOTo֬ΒfPNђ3qS>ߗ {9tj 'HBs)(N#v޷.1ATs5#"h`q~rƝỻ;*i'ݮd+v@䀶3)V8`mQ@ZF-Zs0e[=0k:?Aiiw6s\1䭌($pr8޺j(Zë\Pi[G[ B*֕bt&e6{ fQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ ~{RQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^A?ɿr먿}ro\x:` buמ>bЮ՚_wV_)}qOTQEQEKQ[Os(=  $(мZv;>WB/~)*_ *_Tow0}E}E1 Vk|E1EuW_y/΀;kO)o ((((((((((((((((((((((((((((((((((((((((( ʹ}x:/s\W/Ͼ@pQDpQLC.՚_z^{//]V; E>a_38qCު}_ ZKEnG8+7%Iߙu'3>ZC^*e?+7<+K}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo}SK}f}_ GڼU@_uVoOG[y=;?>~fgڼU@_t}_ Zeo,qJ=w}iϸ̯xWk}.㵆H0ǞN?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/2]jW-ءƏC;?>~f7ڼU@_t}_ [?b>4{ qjW-2]lMh?ޛK}c}_ GڼU@_u(7PzoG/_JVӵc9ڴvJ(7PzoZ<׹9s˚,>m>[PzoGءƨFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhFU4}MhuFq\~xsRp4&o}x:` buמ>bЮ՚_v-d@I5Mu-~ؗA A0?A^iVZ$R#2$=܀zgk amP"f$%]$ڒ:+]FϴIJ# ?#9Yl`lLune"Iba gU-bX[kM 8A')H]6eߗ1-۟lՋ]:ϻb!A=IrO~}ZTV{x`ciy8젟utFX@dY)"&`6gitC^]Mk)X`ǘ^RS쵛 Bvfw䉣lz$W9Iv%Rh-sӌ M'UړjwI%*/x35=ՓLEmq36HvEH hW;eckqbkxˑOYy^kBN*).|'~ )jr7]UpA|']\ge4  8$uSt6U}?UfJa:JKa2G¯wk1YAikwt V9E#p)/_1[k}Z["FO٥rWoc޴ӯ-4mUgWdV8;࠯=i'ҵ { OSB#Eizc;GDlvWڝޒW IB}@"NIM  blOCƝ37chԑ#+/0h͏55)mM 9R!^#Wꢕ'%GPqȧ m'U}çvRVmtQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEsa\>w0}E}E1 VkDh?z(kldU~Roʼŷ@," ?HgoʍW}?G'ڗl[ktUj_Q @?z~?y'ڗl}?@*6O^a @?j_PoʕU_JO/G(R €=*=p*|EhHK X=oJ6@{G,mc€=* :Ks܍wnL>?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o6@{@Ey,mcXzU𱵏 ?ckTW?o(7PQ^k X=o_cۏh@\WUlc gݍmhv5hQLaT.ĠV!-q!'`Q]{Q寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGQv^ZQ寥qGR Fv>ZQ寥svDFV͵  )hnip2-8.7.1/doc/src/figs/snap15.jpg0000644000175000017500000023031113351443023013413 00000000000000JFIFExifII*JR(iZ)( )( 02100100qC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222q" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BqJxRF@@L7 ;ךxe}% u,d~S°1"'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=IGړּSQ FI(I^) FI(u@$\kRzu@$Ѻ|.=hRz׊Ѻ|?h>? ?EھԞ}=kh>? ?En"_jOZ>Ԟn"Z7?OE'jOZ_Z7?G- [{Wړ֏'x- [E-Qp=IGړּWE-Q B|"(I^- B|"(s>K.=hRz׋й%./ o7E'jOZoZ?-I^- B|atϹ%~Ԟ}=kſgό?nY?7{Oړ֏'x, >|at\iRzs>0K?gό?n?jOZ>Ԟ./ o7G- [p=IGړּ[-s>1K.=hRz׋й%./ o"?jOZ>Ԟ./ o"Z?E'jOZ_Z?G- [{Wړ֏'x- [E-Qp=IGړּWQ FI(I^+ FI(u@$\jRzu@$Ѻ|.}=hRz׊Ѻ|?h>? ?EԞ}=k?h>? ?En"jOZ>Ԟn"ZW_OE'jOZOZW_OG-+G'{_ړ֏'x-+G'Qp=\=fS޼H|S O ?E^zN 6=TQp=04q^42E :kUNE0Eex^>xOW9<=ɯӮg/?L2t\|??̟]|G>g{hx._϶~d??̟]3Fkr}'G._϶~d3^ ߙ??r}'Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2.fׁiO9G._϶~d\|??̟r\#m7(3^ ߙ?|G>oQp=4f/M2?r}'{hx._϶~diO9Eњ?\#m3(??̟r5|G>gQ ߙ?3Fkr}'/L2t\|??̟]|G>g{hx._϶~d??̟]3Fkr}'G._϶~d3^ ߙ??r}'Eњ?\$m3 ğߙ?.fׁ'iO.\$m3p=4f/?L2t'iO.5|I>g/?LRt\|O?ԟ]|I>g{hx._϶~O?ԟ]3Fkr}'G.oϮ~dEy>*mQ隭vE,Df$Nkӕ hl \ιyFI1 p(O@ 3r>uB.ꑒ{6z 2Y pXcqqYt^jV Y%.y$D\Ω}`:I;ƶ僰G<'xbVIm$V\4sz A{WaKKڶ1dCwvd9c{ϖQsf+Lipц9ג?iI'8bBHWpt7whdeH+g,ONV,w &rǦ,1v#<+U ~t쒫&.Ewr?]ޢуmB^F_%.`4Dj3㸨Ɖv$+op8+յ,7:ͭ_:vB7Eb:@odž|/ Kd tk;v愵uie{v0.4|VR*滼RTPh.s:ǿkxvp:an^*mAn jQV5 ,4uMPHqeqf/>_|tk_1?H< q׶j~-53b$%s]&v=#YH#<#>j]޷6MF""6負pXq{_ޫ&;ǖ`̏w8jԴb.ޠh|[$9~}kNt?hj !#%\s/PjqLGhϦGzy=dq~#> W]:;f%V:ƳuM3/Υ^y7f1xluI^ϩX} G32;_Ӷ֬:_VkH fhCt)ƣ W2\CwvK9:WCk Oxm!Ll=Q5 nysH2ݗ=OCBh/9{;˹+[;OqK WRߎ8Y~ IoSKxͱkAB7u4l:)4$p 6N;dc%dP`ZkoO,7:.29?^GKi4[;[5q>>o$3Zd|[@(oܴP8*H\u)[jPiWgQ,LaUPS?55Kuc2_2qބn:f@4GRgAXP:Aaw)G:kլnAgZMy ?*)l!~ܷ3/oZ5Z+C3 #붳d<2nr=Z~!M}ޗ-Ũ[{ x Ar1҇K[4E5By v_-6WB'0XvQ4#[ Hٗ["lT-GlU+"rCjil_#IQ-/wcM3R4օEr8=wBRBаs\f\+[ 0R+eic}%6XH̀9}\Vͷ5J*|*e^xu#5tSZH&1OMU4[[閖>M֘&#,9]v_#Iiz}-$^<%m8oåDe[Oq"'3}+5]:|'^B WG6+\\8hþ#n*чZPF:+ j~ڽvTiP 2r=i t"Oop.-8yfZs|=xk~2Z^3Lb榵c 3W{H$obG=y)կn/((@a(=R]}911%͝孲n6¼=]Bt[$t+c<vjݍܳg8ReC{vx}j݈֓$li`pl(Ϸґlf)_-nx黭Ymɖٗd\ [}I Ғ43%Ѝ-sfC% z/\R.oΥ(`{Pta$qr:F en~^\X9Ya.]dq ;bSœ;{fp NMI 6*\ s.ʓGh)oOu&{ [+RU# k<8?t0ΰ W~L%trDB=?:rjֲ$nGntJJ w0bG  'y.de#rfPioE;̢L2zc{w`x%_^mMt!r% I>Ҫ0dvFe$Zyi5΢1Hv'Z4I)e$+g =i4:}>t03G?sL*'sU{mNIC((r?BK&S[ .e]MU\<wVB}scޤe]ni޸sYc<~7S)-īI,¤hYM8K4daܶ=,ϲNб'i^zlcYS*zNnQ@Fe>(UFc7QY8unvT$ 2Oa>~7T3i\mb8m#zj~c]+44.A%Q8jԻPQE?uZKŶC"?3RXwzksyM4M hmG }jnT^Wih]Jq*(۩wS(u26w>oa,ٵ,F' d9PQE?uXn,"#5R.ŘzM(ڝ}fسEP䜁Q@[xrо nX}!xsPCSoo:v Q@FeL/ks!m0¦|Gij7BuD=~ʢ(L[wvwVM :8 gTPQE?uPT`ZEL%J/n=375"^O"ǩVUJ)4dSMq2Flt* (TU9MIݞNu6GҼwc}{ b'-o#͞SMszjL(4[yK,LG`gz:W:{ZW"݇!@[o&S?JZ(SXśdF|A 1I(|8sOk=PK<{t"b\A@VVUQmnӜ=˜n-Q@2;";_>6(($te8#@Q@29EBQ~ mPȨW<M(UfV U 1f'$i(((y{fscE4vePYade♚( ???WZo{ҾU?5a_B~ЋQE0"U뽟USORUI"bU(IV,z4I,ZM]m܆A"D aꒆP>Aq+K6#H`2/Guj G#m@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6Ei;PW ? +fZ_?Guj @V#oڇPm@mC_(w[6 جԏyy-0 tr)Vdj?#T#2@z_<[27#W|SӮk;L2v#ry'8m#0E[Ym:<$$}߻nٿJķA ybr$J GQ GR{O!Fr Aש^V/,?*V/,?*Gn.&`QL0;?Y/TL-: %z4[HU?[x?[x).c{xo]&RJ9QiagΪSNdгd}p'Y_@YU_@YUW_o@4h]ezV/,?*V/,?*5ŌWu H+Q9-f$C1p.I7i7|݌۵c¶eT¶eT], O挒Ow{o5ݽ$OV ®N3V]H.:t7BLy#9>ϜcqX_@YU[//͹Ca@.eT`gR֟ןz^_qGWU GQ GSV/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*9Z+m#m#V/,?*V/,?*0t X_|i/_iO0ʲHTTIF])pO]pO@4 Ep8M[Ccx׶͘HΫ`g {5\M AmEo+ y#?V'ko uO2 7prOJ-ΥkGpb|[qSmnFYL͹ą86#[$V>RPқ{~13H̊w(qp2qTrcۉWa%q$X<lZoi )]q*EcxEb2[x&V`IeX].EdbK}Rc|]:opU@;sF1K~g]esu%GI:@9KRͷIZ)gbH+ ~i-IJӦI +1X?0uBOEK,N:̽>?-%ͦm")@wo4\x[Dn@?_j{t!99CvA$]Lѡs[O &Gt3XۂWqnyDy;zU5=ŷ//4B3"i"+6].J'x.<3vRwjK:lRBVd.&Ca  y;!ݷ#]3PYvb܀r3NHvJIK0S!fa~Ynm#+Es XkoQMiWiww%W:zڤΧc|.ۈGow^")},Pn /Rcߗ6zc޵n"n "q=x\Fgr.VٮdPҨ73<:V ˦[ڴZ : )#w8"ΝjJȭ$꠰8 dOTxaii>9?snyYn&/LW͔2A=3U촽Vig.Vnݤd\ۆN K΍uH7 C])Rn7}ELukz,n.HmAbWzvRRUS'ݐTi-ΑukxWP2 ˺0:VP̬ W!څOo30$;Xq 3^Դ;ɮnd 6,

kx`hmf$q(~y[OcoMQ{y,M###$=$֢ҳ+\m!*2b}OaYzM݄6A d%A<)*8#yj8tMV_M"IŹW$s8 @kqoo^o-f 20O~Emeb@ J졀^}$5SBK漞Rna~i]hAcMN9H=SDinD"mb_[+=?_ծ֡Xp3=5n,ѝh]I 9tAe֒76DY4෷ s09ҏQzitKk-"#&a6>S ]ے=ɮij.3>K5Z%մ';b:IԷ`qu tO-lt3{wC$FDq { O6\Eb>!8djzZ{K[{Gtѩɬb:kZrum9##>=]xR[kp9R{vq5n~cNk=MbҴn䐪~^;sS]6.[EI#gC׽,GLkM/py3Nh_cRǮ |0ȷ#d)uFLt^ .Ź7,tQh%C$|x+VWkixR8-d;PZLj;{_6ݤi| ^9Bݏ4fP v5Cj9ʩOƩ;umi2¶WVK2Ss;GZijAO;F-ٙn$i~O4%{/oLӥ[YnYx<v]J-h#h8#=:U$'Dɓ1V&FNilWVq3z9sK}ֱZX-]3 Taw`>1SŖ%Ԓ1Uƒ29577w!M#>z$t}RYfT\ y|`ESsa*8w>a(~Pw ~~/)t5-NT1#.{d[_Cme0iY vۂ8zk_4/LW7pgS۟kmB#84\}Llƽcܺ3U),CUZI$7p0|ۏzu?_oqy,j,\#svӡQI O=I,$c;S]>b{2[sB飇Ma(H?ǻZ٩M~I.VEv޺]3PUa$HHlg}E AksrDv鹉H{+9|QdAu曃j-^k6Z#8@Bd u&F1D#ܪv?'r9_i4cN=Aʩ;Wc}#k 2MK_K߳PK1&x=Zx8k{MRKJv| d<&틿:foqh(((((((((((((((+?Zmt?`8ӽhV-dT+i@R I>Pu]vHKfS$1%ww5fMNų.aiT;g92ú:UMaR0] |?W']Nݡe%tARYJww\bաjvwz`藗tM2oO4u}2 Qw؞u s9CL} 2*Kiq%CQ߷Oqc PQKU!*qqưm<>m͔nb*-3FUE'Z~RdrSM_'_qERQEQE3#K_T}EOeUIW+dlV-ݞ G0#Pho--?[Z3 Nx0ti^=V oss$PPO=GfAOua Mi"yQʹT$ sSx{Eՠ)rd#i'Jk) ((((((((((((((((_ SO +D6ILc>#[tY c6r$9!F>zp-irA"`8cQ`j|̺Y F%0}G\I( r\ӵ`¡YbxTÀq^)Ѯ]+vh]U~+`5 u<>[9 A pҡKOP:xx¤*128݊/3_vFD[O 6@,^x=GOkeo0laU9Q彪-CE'OXiSò U=*Vö$f$ :*y&Mm`iﮡ9HKb6bc|C ̑J!}[ X6F]+U RWʺq Wo5R/*S>gW*:"sbAo$r4r[,Q,`|ZZ^]_][xF1#,{VlZG`Ht%ʊbe9FG'zT'Eԣ#Y&W iyG89Zn/tfXLl#p<1ޥӵT,fxhs*kMBYk?"{ڙXe'ŗ7<[=qñ#zG@mw#IS ڤ :^LձI8#%pG8{WWJHN>GX.8zk-O1ރq>=:n׌~YOahm.']7=TKbQH/zg/z" ڽMn30#Cu*-PhVmFt8 g+A>FFpܬ5PHmͷ9s=oC;2}<_+d [H;;۾ZN"쎠o>;rl6A"bđEeq (Ŵ6s;;̃s=o2}<_+0YUhg9FsGҿ'~fwgvG\n>;2}Xexf6Lld)#¸9G\o>`2[9s=o<_(/?OGl9{;xk8} ͳmh|_(/? ?%eFv{5/%!;Cso>;2}<_+>0W,H%ݞ}M<6*rwgm}S@y>Ee/I$ٶ#wgm}SO>-[vfsumh/?̼eO8bt2Nrs=o|_(/?8 $O\n>,I/Y 9ݟ h/?̼ef1mEg9s=okV-6AG\o>;2}<_+ͥY 趍{v{5'#o:v_/?̼e/res?GӛNGs>=?̼e2}ef8oݖs?GձC*%-s=o_(/? '9wgm}SWSıλ,vwe34Q^ϲ\kJӬvsv6:ʾu9g9ݟ h/?̼eO%;o_e;,y?GG^ϲGy>EsRG5'w4I_v31um}S@y>Ee/ᕋXٝb}MF,l1g9ݟ h/?̼eu oӬ9ٜv=}SJup۬,vs4yQ^ϲ\֒]۬,19ݟ jfcf۳;oyè\<Sv2V.sjl9}s?G6fwg99m}S@y>Ee/ζ6m1{>-ٜ99m}S@/y>Ee/Kvf۳;}M#kY1m}S@Gy>Ee/˶gvfwǜv6cvtGݜ:v6̼e2}ě6);}M)}۴299ݟ h/?vM$);Y+;-#Q--hi9N]dž _RM.KdPLOxH.(HW3E ԏY:ޝ\֭# :6ŗ;XN*ιc0Fծ|6nx֐;o祿=mVZj--Hj?_ ] 6K{+ꗙ#RN#_  6K{+K?u†oGI hJ#y)V;P<~ύfv 7Z?mQz[\j3W>$@: 6K{+>$qRmQz[\.GOSڸcv;o祿=mW|I ??-\dP]z[For'ĚcĚ4: 6K{+>$ԀDT~;#Psz[Fop'zv3\'ϛumQz[^ wA~R?w^=/mǿ 9~'x3m?)l 6K{+Ǔ⧈N7~(d`?^=omǿ 8>!IJEϖeܘmQz[^a/.6R^ xZGhK{({=-- I6Lu@ ^=3mǿ 7_'H_=mǿ ?@|Am 6K{+Ǜ⟈TEGjH>)q/#4o祿=mW[T=)'Ĥ-܈lH$Uk=)tbӭ&6|Cr)l=|h7ut,nmQz[^u:tW{z[FoymFqˬG-߻:ݷ 6K{+G?_|He,}"?U{.oo祿=)#, ?dGj9>&Zdƀ=kmǿ x&k?iU!+S9r*栺w:ϘJb)sZo{ҲeRw<#12Hm7=UuqIr2QL) _ꞻ _Ꞁ6%VzyڽbݿUjJq+>Q(RCd/!GSRRbϜ՗R)s1۴u4X{ԫn0Y4َhXP9*(c`S14@岧9'2$II Z(PGz7bȀ2jy76BL@V+^~\g4/yک zqV ҩOgKKjT/݄ʧlq@VAZüO#1AֲuQZGNx :z ZVgvu8k'@q5u7X\)ڰo@؎2kjy.R"`}"U=XnZ&Ϩܲo~A,! P)jrLvY6CW]̜ʹUIwzS%r#qgJu(X`9Tz0=MLv㹠Ts֤2:u>"q~{uXatm]]yߝˑe;~R=*ʃ9CTc@RL[4N|Ē*l _ZcMx9X|IZ|r0 @5 ɂI94{fyM! p=Ne\ C tTK qDWY( 8F3@S[;wcGC.bGL֗jߝ}qϸy?Chx!]+f{J9 { a3VW~B73 hW'@DZxᓞEeMn#2S)-ȬH m' ew.j)eN M2c4 vg;V]wA0*BR6@ MVPXO4OSqUoAZ=Ug`s@c\IWhUb!8#ڀ,"\ d 3iHR?KI9I@@FI [i0ӓ4^"Zt*$)4JQ< -4ߍո0XqVV5(N,\dWoy sՁ1e<>-ɮcebp{5j4j(+&ݍNZvo-Qɫ}Aaɠ||dUk0j574~r*z=ؤ\pցg!A iRx5X"G5t Z܋R}3@[I.TGzET@EcYwHOh ڀ)iW0 f-͓to*O"$hp(hEʮ=1Sr՟5P 5~1ۊ來\BL¸e*3><+ u5E1jp7oA5KћU2{G~2{G~TE_QVfE?5xS{?5xSݻĪwuw^W}^8>Mvw6YoZRnϿgq~tؖ8*'֖SLCp1U_sҴ*(hdF` Tnܞ*9]ڀ, yZJdV6 Bs⣱-<f5Zdr}*ⅷ<{թ$>Y=)2qAĨ4fUP?w0ZIAIu'&s@<$?ZgB*A5"K (NM2W/ H4d-'$fH+B;UKvۓP? V@TȬ 2(涘 cv$qg֬!IWi$'uP gVь cZ49uYSLPc1%9 (SciG͜Pg`⣓)X4sր)֗Noݏ#?5vp@~m;-y?C?gx!]+f{J9 { a[Cv_#O՗tFgڠGHU<}*l ☊NzgZsYwnZ`; (M瑚HB T6#w'ˌ?w/-3d^gkVնqY5 #pa܊]ïUdRR0WoCYcpB@*(yY"S.:v+"87) P\Nu5N\HoWp(qm2[0wKlJTb hBЬUYoӌRidm$TdV3s5VVI_85$nȮbfʮ( m),2k/JʹS5w;)pil;aV0ۦ@ěT+Tbbu0zgie y<%= r 5 `Q j9B{ktmZ2k*—7=ekAǺ+ekAǺ*(e(̊kWkW vUe)lFp|~USy^=zcҒ.^.%[C,*sڪ3mn iҘ@psQMp"'@jptwesҀ,HuS6Iҵ:}۳ZA4ᴊV%cqD3@y!P2<$nP8 ,qWű vx Ux'cdɩ#godc#Ҁ?зLj(^QG{L$^OJ' G"K"n`Yy8T8ZO7Z'J06 15 հNljOpC!'ozтu T ʶkyq>9/B(iG; M3t9sJd<2gs֬[d$8( [LftYV= c(,Vs@JP%1@o"[X3\֣4;FK̤ޙ!pA&t!J=+]Q gڣ >qp 3H<-*zVF6`qyNv1֜ y959ȩ7~}XsJNUxm9׊:SsM`p񻨩Bf0Ijq4=ڝ!>ؗr@ٲT6kBB?/M42di)b{ ,V䞘>jXF1R8}LGA략:әc@ x2q b)3ޱ/k{ N1ҫϧҫPQJS zAFc.vEH rKrhI'>v4&Nxc1PUG=*+#E;xzbHi@+"?5g܀QSE2TwJ)hI˰XaMd\\oShĮpf ٫ێ[x.O~㩧6?y[[$uZ  IՆ*ȅVXhj:u7|;@u|>I; g5I9X[UtCL7#4H[Is:UB[֮<*s a}QpFj5sRpYcBT0 HR`UaL[,"Lۉdzq]n*8(x@sWsp9Tf]jqZjU7T*Xv-L%'i l5UU{q@֢zc<֍m,x ͹rj5+o,N܊Ηk="D' {#:,n1ޮGdLp G>2հ#$EJF_#P6>ЩI4w9gr.ֵ4ȁ]A0!FUmdXi8L54:3 RNA=1J'5\K*L(e3OU ʒ$I-)Wq@ oZzz;Xu y=iBNԊC=!qtVf>#8Oeb;c{х$K|Z~H@ ҢJp @.TҦV}(Wqǥ!^@4/z}CWG]_3= lԏq_3?vGҺCCv_#Rjz[Tw~pR?:V\S#i4`8qrZ7pF\4~J$VT*`$P3߁ދhۜSV|S-۱?hJZejf##oNSy}i̿+61L䷠ ׈K 6EfnTMY$?+@"e#ʓ[n*Tc9x^5*Qo0Ji.ư}@"&ֵ-pIPS {VLYOP گ:֔RfS(/qkNYm8<ۜWcLF8"<RYR9z":֥|YZ;֟B=)/ %sT:1/sKj4, WpW ^k*Op{sۚ.<$NHpN2TTPJ&(݁5_&GWַ*B>u_WZx=ǽ cJýV C5}R>ʻ[?#]!{!/?[mCv_#M׎>V\Ricvi6)Ͻ1h {ZqQԓe?ך0@O3ʛڧR `MHqPܜ~㩪ۉ㠧7˸ e^] 1 &zO5u7;3JN({,͹YsU.b)03ձqE݄_/Jg 1kb9tA u|qLR[` =*KȒtQ3@ 6Z02⧶&S.q@a1v~Zn꒰WfZZ;6>jm6ݣT5+T(] L8ZZ9 K4b[ץkN(H%.2w ; #Z`EA ~^c̍Кu* bSP}ѷB\I)n|5$y'ehj '$G޳OZ)&Ta Es]˱6ȮB|t wMH$9&;ⷬ4d1fUgqtTҰnach3zZ`'AP2gRCOc@>1n1 c5pR=6$ېaaP; 9?уxt库ԏʣc 5vCcI*p5Af0bhp=h9x}vpD@w`foΤx>$Oas}^QIXx@n*$)Jsɧ\PJR'^(,<5.}k[6qk[@/)z3|/3Uh[:o{ұUh[:o{ҪˆV]*ȧ/zg/z۷oZRnϿgǙpq^n*]l8וCר"Cc>Gjb,nGj{,84w4A6,jzS!vƶaA*2DocH\I֕|GJ+I!V0pqҘѴjGVc$\TEgĨ#=)q@be x<y0Ҁ&T$u5u <`H,ۃpyWbvOZk;623ZkQq@3qR;yc- *zw%'ڀ,C t$TI#D8&(6n Ќ@UqkIqP22Ĉ|܈<`8xAV\ւB-eM XIXTH#5Jī_npn>AS,!m8#~R{sڪ.]^(m@ۖjgkI;%Qq@w.~y5e xP.q&-[Å|*c;gv:p0+ *m[~wcq$>C5}uUJ_]ǽݗvӵ [nj'!|a 6TN.H-hۇ8Ive[b-;2N{P[ åV`?=AŚp_?*R8݃ KC0ր'R@BNj$eFk!FmaW-#2L\'BG&AÌu %E^Xtvq$eTT |ǥT H]gҠhOր#Ӣ/7ZRE[M].{ҽAQ><Q6tyǃ*RB(ekmTu5чEV :r{qZK&jC: |;}!-E_2v=(=Ne>ǜ:<[UV6ˎxٞ XqߺC=rW֭>MXV4>o=1K1: CY*k>8g b+"DI.`*kze&tǥFѯ=E[q;rrSjo0|UA8)kV[LXB'2>@++WCk(g5<+[Bs[ ^ xz3"+gMuV1VAǺ*(e(̊kWkW vUe)lFp|Ч\cMh ˃X6;Ud(v5fXߺ1Y;XkjEMsμ[NߖG5CP̏1@bZcү1O^+?I6'K,'(n~^OsQfRy z "` [ + Sf3^Sⵡ\ rjRzʐ=jNLXe,pۀgڲ+43V 3 +y;bZ$%T=j̬ȁ5cMs( NnҨXڙNZ:x*#c4%k$S4YBsT]ۚ1F 7-nx]vrط\lss@J^{uPFXb6|U`HȮOb8N,Tʫ7s@ɒ*m&il(qmiڒJ:kGX=2+uqu ڀ.c5Vʦ(=w !W::}<Gx_E[ۆ:Wq}H<;F!ֲds]Kl-oc+2nV#=ʴDgVtx[+:ݣP5B(:( yj"v[]wdt_ 6-voqGCWG]_gx*lԏqGF{HWAcnk?Ƙ%h^nj}l*C89Ht*[-E5$8#< E*m?ѦcW2s%H<'ڠC.]t(ր:e :w<-¸y pe(+qlMwcͽ涮sg (M3\ľ!Z<2`~fLrmvFysDC@{WH1%LGnMc>Z ʞj]OJ`Yw)q E^\NDU]m7篵hXZ${I :]@cMY)mJ4|ƫpU ]+f\w+2M'ֶn|@(,Q8 $Rj=O(+\=jq`D8!A@bu$UiL r3Uv1ko12dm"9ַadwlґ@)YZݖvǥ3WIP^ł8CCU 43jBSͧ\|\U g]iAڮh fߟ&Ա5[R nMe_Rf_~g`h[:o{ұ״7=UODU߫.EfdS\=w\=m۷JWw[)N7u{g3MrEoZRnϿgg#i!NKYa3ySZS4WPGj95|X; -_ P6SN܃ZfR(m^GFN[""[c\ZlQ(cCVH8TH0Hh?E+V>C0oOZPrpOLUȇSqTdKzUX@ot^Ezrs(c'zf͞tWKV~p0:TWfXNW2I":.pC=/?1Dz!8t׵R+iPZJcSwA(X;4%ݐOlcֲ|;mͧi!dɀB``]/jA>O+ajk0zV'"Ifc6RxBpұhXq(2:# 0([epQ˦ۯJ$qheYc5C+ߛomwc=)kz]_\yWh2\ϡy?BʻK?#\YR>r6{GW7e]5 il;L!@[wnqVlfk9Okw$S\n8ػ+&h1]kNeROJcbE^TNW3XqRPü5iܛJ| 7&|W-KD ;HS6OB{Yz6qk3A$؈m2 Ho.CDpPn uѕB]SAB9n]ġ_eH=z{I.RxuF~`KKF$cᱎ;Oӡӣ!ga4;o 䁁ҟ =iiuu-̑_O) 6+5K e;]CG:BivA1q$S^G`1"`TNr=q9iA$P]ϭg5[pY}h{$֮11-i$k!b9y'5 1pk6`[Vv/^E@c8,}hګ95dc~+>;(6,y85nU&UjkXc+}i|8P@Mk&Wװ漐H$UH˺Nր')-Q3l*v @iY@xk-L]b=h1/ٹ:w(6Pڀ2n ȩH5 b/A5q%HV}i`0k^쨅F;Pp{ U0]Q_Bw*8I"?gjʻ_߀zԁe%A"r5YGp=8RD t-x hJ\k - HQV[Z3QS|zdW4d88Z:Lk h<O \z֞r%"SF)z3|/3״7=XEX??VΛ*o՗h2) _ꞻ _Ꞁ6%Vz0ȯ_oZRnϿg68̛k ub8"(XidlnHAo(/JD!Q&ݳ@'Қ!l:ǥ(g 4L~}8jLP3cs@mX ~w~b@pqI1ƻ ̈9i䤻Ivzʼ{y8phaRϻ`A,{(9'=3Nq1PI<>]&@#iZMv(2빇$X==+LD+U+bP=Px cZbt vE0sFrV1݁w,Ri 85mbG5*Z5Sm5 q8@iͷ=*;7=x⩖ & ݣk"n&Tkv->[ɿzNinP5Ɲ[@[rCJICҧUm8 sN#8e˳uћtsVmk!Sn5Z7lW)-yXjݛX lYm;?JO$(v6bI+l [fs'a؆BlN7L1v'zxJ|b }Q}ǎd D_*OΉNOZ[,֥ v4.uܰ݁TeXVf=יcq}>/TSu#P--|w*xP1r+4q^Z[\K 8Zh|Gyogwp[oOAd+e`<-sڊIk#Ѹꎸ#5w/$xZy9v%dVykaگ޽;r۱v:?<,6sl x4nke=G<u _ES#=Wig}+?3?vGҺCCv_#X_e9MnnkllbJC9= nVR̅9=+dmTiĊ3-Z֋:VM7\浬/pMg`mgzU[<.z&)qV5^m5ܷV"* }֨[iI+qZ;13ɠ zvy wEAY'r~ojkZU$.*qEA m[ wx9']NQgP[vVG*OEK=.96:%1o8t|Aԥ\,V]췓W8=2:-@*\8a彄g\M@nݎ3ZmMeRF>و@wAҮ^G, d+Ffi+ @O Ս@F{`VuZ(siOxzgӸE=jEI>o$+ VUx$s3裎i z9JK[hM6lyF8VD}v**MH|O“RNN1$Z=+ZS zk*{2*>bYFk5O34xEr9p(X&YRAiƻMM,aY(]ER1[M H{gjvuڀ+_) *DX4 ج'4Q^-]t#AbM-szIKg(dbZēF[4h Sj@0 2B>ڃf@J~sjپ_`GP+&vl\dŌvGZn(qڟ kX@-&Wzf{Uy.^FӊmMX:ktơu]<*Ż[ۮ*FqҀ:+ddEszeaگjl`{W#$\P!A 9e#4˘#C2P? @e֫\۷JWw[)N7u{g38$Ce8Q2.: $$)`W sW1C O4Q\LvV<׏u.o,".0qU*jY(Ps@ E‚rMG!A&vdtrhXYBp3OciTgp:5`9AUb<s'Fr!}*y^D2285H+n ycֳ5$9POZƺ )\Տjnէq0XZ k˟\ 4&JԱ$]n^VS1޸yHkEzs@=1z8j7('Ҁ92D pFje|yX60k&F,&i5 u:\"+e'ӥr+ C~ Xo>fœɻU>Vt$c 'ZdAeGjѱahu4Mi)e*. VF@@1g =kF&޸yWNq[Yy|8т]Ѯ JhzsޒYҀ+HnpZˇA3Wm|w0p Jq֢^V8@#|D\݉uܝEtrk=~lހ0#ҥ2ح-;GH:~y3SqPIDˉny) x~`9';nsZp `WʖFj ?*Jf,pEtp.#Kkk)s@V,zF8fh_z`'io,m(l3?fj#]سRk5Yw.(r䞔FCdQEjWC5}?QR>ş~Wig}+17e]5SŊ lf?w ;g=݇Hgu*~kQ,::N=*8{~!`sRnm.1Z7A`8J{n0p(RXԃگlR:cIf9SZ)Ƞ Ra7 Cg$Q= cJӸbKԟS\y3*ӉzVKPHjm*qW9.jx J㊱cl$; >(!+ cE7 =WۜPR $A"4HebZYy`95G6>_4XzL?n[3O 2B/e'>r\+6RJ|A I2yaqGkL\QKg7Teoz$D>lT7Oހ-H'5MsYo#*VOIXz7G(hbt =4j|wbOJʇ$hf aldUQ'ju(}xmGM6}:c4Md(nz(@&+,k3Vksǭnyb}qGJy&&7{+NQY&dEgtkؒz;f^K{goS*E'9c'N&RxxzڲNFҵm4QYFy'ok('@{WyQ71Mg$>6Ul2J;bjB8P~TjmaG'xWhʛO"0K.FO,L N&4X2=h[wF'U6#VMNvW{ĖAoӭgQ֋ oϾkfd8==-ZogH95 Һ}ND Ԏk@-I{H}kZ2lBBhXppsހ8 B@r.a"x64o TqUA䄍I8tye +zIKp QWIӖHqa" 'ya@ pڎrq+wooX玣zGo-w^q^[q2=GCWG]_sʻK?#\Y+R>r'N2|[Z>aTygtZn#6ߛjK/: Vņ< LG1"yNb'm Yɋv9R#]b紒Lp+ӧFb(Ib K4x.@ )y\z_6Y0kI/Li$(0(l&8ł ҴuU 0+InRv+CHyGQrj@Я:Sd-HJXM2T=EHwPLX(!88?R9xy=S+sX1<@la.eV]?*DZ\XG4IIL!>T8@LY"4v< ޞ &㠩b# @QҀ(l 3YU۫Ggaӽ!F2k5H9k3kI$@呤'"qUڜ3 hƣ1}ULc5jD4v/19KGRaJY-b.}5n^01qM[ Yeğ{4${eRMUkW],A #XdP=>э dsҩmV$0P]ƬNETW[*HSZD֚$|PfK3萗h=}bL qE8F9&im.(M֜Ҁ1ub&VT:@"\ Ս=ϥfu`9|XPY:К傩>=W3 *9X8=sRƀ5DBJGe 8+,B=N̑Ҁ{l ] pz+b8>UP#ya%xAb&K|㫟q֢yNE\B=G<u _EFkHW3\EvGҺCCv_#I vgݗvѿ!<#U+WyV1b1,TN:֍߳6{ ϶wI\yT"h'\sKkPBR.zJWTS1V-.M%鑶F2iS4IGGkycQ] [P`LxɠZW` o -A3Lcpjb8Dr2{xj$j2e tǭߒ{zTP xHq@/ڸbDFS֟!dub @Op7RKGAˍ/W\㰠 EL"6ۦ ;wBWd9\ΕwLl X>5녵b4Y2y}6 m v@fH~ZU ϥU-Rҫ mNB5F`MY2{`J ;%{/5gԚڄA1Ҁ&z⹍^;ڴK(ݕrNsP!){ pMjX>ϸ@XNw+rɇoJҐf*P74 ӑKeJ]פ:柧ߔ Ϸt82 * qSkX˓MֲSj];@`gqlbY @ Ӂi z=wҳBIZSWb(~٘,SK9L6΀4܈ڣ4^ 8U^Z1:S@s P~BkOmvG^3D+p٬s(+J}._+%*皪H>ncVGSVR4}4a:ҕBzaXb#\VU/Fo<=Wz+ȩ{'+kMuV+ȩ{'+kMuUSQ~7˴QEYpO]pO@vUSy^=z4@-W۷JWw[)N7u{g3qۼc8$6fprkFUW,1?ZJDxR7GJ6?Ú/4H'Zp晜?4.Ҁ8`IMǗ 2ww=iF>cȠ 34֧(fBW#8DxUkxs}jYumNim),z犊Q@< |q@(MD+V̉  !ֲc9>̪dəͳ2H\4֗WwՏ"q U[p|cw.2.F. S|$.2U݂GlG$bY3Z0 bqI S!(Ze&QU-4}y銰@nn#dy8ޅ@{IHb PX(ңzҳhEn 栝^?Q&XSd =((TLc?AQ=3R+f>h܂NnJjd4gwR8=;ѷ֥LF8Uku1q]3#d*BG'Ҁ1aakX!vłFNF(W۷Z!sR}E#B }8<in tv>^ 6KEZ@F3ҥp(( jޓҟ}SL#;-= sS<ؗS;!ϟC$>C5}FkHW3\}EvGҺCCv_#Oտ[S/7e]5.2 7386FhdsOLdV q1TES $a{O,+ Z#G֮#>nX t7Wꍁ4jiV8-ֱgIjΚkFs=+ZDs@,v:ր#h23Rcy|cFM.2栠?tj#x?I"=~ !@2aHDF<Z݉TN-.W> n'TI^iZ PhyY'UGCojh !ҀI;| ~aoQQh1MjC&-gkmT~5.-@ʠVVK&kc;۫JdpMiIT'ҏt#uZ| e/u6WcT[7Er ܂~oAɠV6lrЋM6j#p i!O ߟZ@ MNGҵ dJ>Fx8$  }hl(MYG {}mu5FC@b,9=rr5g6[?tֲ*5;E6h#t@^pj=qקyր$7Ϧ*aE sGuy'@f-rbj &R>Oq-`T֖9lBܴ8  F֟ sր% Ɨ`8`ziobDM y21M^s:RxS3ЏQ=(b}PۛFwc?<u _E6+R>ŷQ]ǽݗvv a5`?JC31|{"`"sb'.8zF"1TGU ^bQI-]桷y{sS[Yl$b5 Gml欐HPlu}aWFڱchfj\vDTpyҬ;Lb>@]JR/J_2S6 ~֐lOTZX3@Ce$(CKr/&xF>Z݊y(a^).(=@}O9W9'@,Nsln>j*p1gd<Ⱥqګɏ0h Ѹ2Y#yjn:Vqɠ e5308k.f+^*VrkBACTZCҀ)|y{vƨKIcw#(s;c㰦y}*lHp4k1*[wGjGe,85; q@JzuBi >=+IrrN~Y`]w>daSPנxr#̽KT!`T5 na֋93 \s@4Y jV 1@ozvWހHPc5[Y,(wI\t&t(.zbA ~FDq\CG@%rni4@0qiuȠ>Y-g]:P{t櫥zVTr&6y+2/8oj?qޮiSрG 9g";]dtxf?/zQ!>=hMlGiE׊jh@==R#V\E:A .ڧbIuOAOFSpڀ.ZYNoj܄&MegʿLJao dEmiJodEmiJ "Yv(3"U뽟UnݿUjJq+>QjC7S]-Īwuw^W}^8<@zRCbzTYlM<Zb#8 > jC&~U`!cz#<ܞMkF \tt! <7 -VUsOa!"to(KRJR|܁TЄץhG5ЄPP%?2b`iFQI. >nX+F>8b#X?)N r'7P~bNy_ծvprT(ƗJAzU隐`)H8VV-rMp#I.,:Vy2r~m}E@:zPTr}8=3:$#=wsho TmjGvFwc?5l@gÍMHۛFwc?<u _E#5Wig}+o>K?#]!{!/?JuF0_| C1 G$2y^yUUX|93Ňz8d$G(2+Uu*0ZnQ(fFqڣYT*Fu,A f_ by5T7S8w; T23HbWZP[ ӵeݐ< t,&QO@#^)zI-5F.wFkb&O/G5z*kxHT:@eaTvN˶'8,:֍i 7\|¹$rjʠ:{S\n'G&,z;EVryeWiQ U;I OJgJcր7t8‹c"z hƕ V| j[l$#J&u:4#~ nOletv۱jn'ހ'Qrqݱq2']E"+NWր2bgS屝E%OZt=jơj:q@{e4su@b=pՔW.%s$7IiaNli̢UF$޺v Ֆ{a2%`8ZTHET̏׌(S95$ƥTmoĥN {G@W6{T{ ;V8؊y&X**2n%5MP沯)z3|/3E8??[Zw{ұ[E8?[Zw{ҪˆV]*ȧ/zg/z۷oZRnϿg$OJm%Vz9I JTeFOrxb^)a*EsFs֦pQu@F ɴzVݼf(b* ;Py$A7 i\*&P;RwNZgkȠ em# )M)ڀިyx-Fyp8uk.?- opz ]éssNY bHSLN?*$}iQS֘dĨq4|71+Q@r\ƧL7j!jȵfB>ڡU;@ L 1(y!Jkm^LQҬokMV)XqҦϞqQ.&28힕rt*Y.p mM*n#\mZ͝ǘFsQ' ,vNy&3eCgޡTZM3@3]rl»mڱt 6 4/s](ǿJr8VWg4ҪYL&lĞkfO@&TG'ȵd(e}ϭg &J$UovھCPK*+<M5+=ylnT'p')bZY\ q@Z{S@8$~.%$15SN{ԑb{棽ޝչHЃ@XO ̢'rz/jV {U5:Չ}*4zBېOjkGL]>^:!7M0hK0Y,=ͽߌ\C3zWYvlր9}{O;G5ͧ+}{׫S̋@US=ZRpc<\hee r|Vր4т?J"dQA7>M`G^DK$Y lHF=*n.{jt6 DŽk: &e@k4b=kQ_F:se_Rf_~g7pײ"_bpת"_U?W~EUO p^*T p^*Tn*]l8וCר+:6wwUSy^=z`pi!oz̅R]&*nnjkUR#SR1%t^w;[u0}*B{u ȩ\_Jm"@  Ž"]I>X>8D8y@#1VX eJqqj/;1s)v۞*JqTe#AGuAmS15WmjpsWKq[Tvl}'ΤUNj`ݔ?J$SYח ],S8}FhAY>(ن</[jz,6>қj6$bNHXu8*fHd@lJ֤P_άN $8Ƞ|Ua8T D,yLqT^v=hi$ ;O>'IHגJPSV0&vdb9SC&$|#L~Qԋl/JFhK!ŧ P_}j`/{Ԙ:Pq["0 +Km#oD9>-U65#nn!ݎq$>C5}憷Q]1fԏt=F/MݗvoGe6Y?RTvr =k. j@s Ri)#)niyf2AȦn ̇oZŁ1O!$㊡-A zROZWʫb R rj0(G,n5)/^*c?FQ" }J(P9暀9Px<ʩRv',*n@A@UUmf_5ƀ* WEWR$1 qڠ\s]vX-V?"E%&YZ8d1nzW9j @prM[A*v5,~`(Â[]>A$-ٱ+x X3҆@1[^Ymb<:[fŠ1_,r:V}Vv?nP1-ߓ),(#+ I\3K6k#P; Ò ][q=j7.18ΎJՎF:PU9gX"XՕN+E1zB mcV|1\)ݝh dpŠif-㈟ր:  ڞW<<$f1pI kgPzQܨk#֒J瞔ajosלT 0|@ x_K_spb'֘JDץui\M5sh!NI1ێ+2&;,dpZf@@lT~bW56EzK*.wFydY<{?i!,:4kZ_Lx:JUQ;CcUی`b܂: jLsLDֱKttQ^(qjz^sK#dduVzKP[# o :퀋j v "_2PǧJ3ڒԄ\:%ت*%;ՒZFTSH8 :L <#W8_Ymk: I9Qןw3ZM{x!zg5;[D"6X c֔ÌюiA*{l77<Uk+@W~*GZI@XsU%B3ֳm-cD8ր5# 3z MtlE]Pd>8!uo` TND R#U@u6Q&Ǯi^?1]uF"S 8@\̬_,ɑ9=qWm-]GҀ9Sp)R3qךd21|쭦|#$P9$j Em.`˂N*熭fEQPIF,O5b?}q]l$/TCOs@4f/G{/&1^k~9E#閚 ӆN~ul\)W2:JK+ɬ<[s mrH9o-d]-r1cxi I"ϖ7ާmmDwc?9o9Z^|%nf>}CWG]_fԏq#5Wgg}+17e]5Z2ÝiU{!/?y`pO!"׷.r9fkk8yJ\zb1.ulޤ-P[ڳr fuNJ۳5~?n ShV նμm636h=gCj>5p>E]GZ8 iT_ךOZ]'2^_-NA=kF"k*X*}GVp'ζCut\zT\n>5kl6=(|wzbwtXWjOP/3^Mi`Dk>O$#5ɠ&v@4RL~Mdf-91ex<\USj}L@etZ}c;m$;p08f*xEd(Î=j݌\PJ;W9dS[׍r7 Aր(XD:pkv+Wm q?Y' *f)|@XחkN S۲80oxUOsK"h>zZ*.?wڬΪo4mK268t%+98Z m^4c+_005x}VUf<@r|Mՙ5[ 7;F(}5L_o* 4rAϵS1U3jn湽2atn@<܈~FMʷ 0p1Nbis5:,Ђ#+؞%o!sftГ$KGNIH'ҵ`3[6& ff:'BQ-`&"?&A*=8mc' ={n!VQ׮([8ɞ0AasNl5`fj'Ufɭ5S$t}.r-*c# DYW_߿pת"_bpת"_U?W~EUO p^*T p^*Tn*]l8וCר6`+%Vza9!ZdMy8 ZٷQLDf'UsS$H:lR+6\aҥDm#Jr¹ZQ^5X[zP4jRh;M`̣4|wfF4%WB((XUJpy qȪ8RzI68Sֶ$;Imdeq֝, y8@%@AM8AGpk9$!q-/8+e`8{Uk$6:QO*=i!ӟ41@\L̻YZLIZi$U@X (q]ą\e8m@dfm6H𥵽]5z~-Z52G-x=jgz#r7Cֻm lCO<($wVLbq5c >]Υ >g?`DZ6c nYo kMtop8Y0_!Ṅڵ.v v.`fOj "[Mx\oε0E!PTHNޔq"3ȫ˃z}(8X)&9#_DBucy@&@ݑS.+T 8)oo:1Ҁ0%:fq08VL'$1޳NZs|Zdq ('5^zzi ls3PfC `O\P"I!KxarG;?#\cqJ17e]5gdgVF#scHg5ʪ2yP mXHp&nbQq1ߖ>r&#EF ։q&*=4n ʾ U$ SI#. Y)v鏝quWE O@c#ڨKN[kŬEcpMhE,G4gR&7b}"cƒPt4w%+o0?Z{]( `]IfP>O>)IFk#.+"M2$lx@ͥK ~ Y!Ϯ+muJ Ű8:1iI$o aqLac`i%Ԗa{C 2 3N0;չU7Փ<^\گۉ}(sU^MI954 slzƭ<;jLP2j̶;զ@[5\1PJ>@ ScSOj۸3E5t&P[9 n`@4p[wV9J<c-d1"1JޫmQTџZ~UPJvU.Wdǃ֬iC8 n*'5-ʤGm,ƀܘnjqUVkEYDDG(2٦Q4/ֵ|+]4.@zњPdDUlb#hǹ5XS]S5% M~g?Pת"_c'ᄏ9n\(;=UhɨӓhEUE?5xS{?5xSݻĪwuw^W}^8>E*cW۷JWw[)N7u{g3kġi! ֺb ǂLCLCrAcҜPR^Y)vigH:ՋCU) T1 VDYKgꚉb&S5FNVnOl#w0RF}h9^KjWPhẼ;x8 n"p@Yrsq[j.8R7r%bu p_U[P+ֲiKc2+@wvb1=0ªG,:w>ڀ7c "/5 fA5mvU5g,S}PuflLJNx* l۱ZD `ӂRC] d U dP`\(n"kyPUyl؎NڠC dUtfv1Cȇ~1@oʸfsk}^@"2⼺8X3VtLwR}6.*.pzw໅IX =}y=.qv6-W7ulu*1? [Fi;?#\c?Wgg}(Cv_#TZ {!Wo7e]5[aX*C8ǴrĎ2#Mn4X<Ι-b3ad .Ȑn^Tv55=)ʌ).* 28Xր!-lmN].NV,EDy )SҔO[eVnDw3cށ]pT맚71G\ջF 5.r5ZM)na  #Ҳe6cVc %ƋRj̻ʧ55.H4|$PyrOՋ}B[,JlbBk9X?Zڶ֑E`\{񊣙M٠ SPL Vt8WvNrk*ٮ [Y :Pӌ&`b|[;~)t-j| rZø3ס3=}{;LV(v2$W0QVvq$P M1Za(-|#lqY:"(ur\tz+O5E W/NE6f+Rlqk&r{ֵ! 93V[?9 V$zg5V ^8kͅY@_P.sZ7AT k0q[vaְHŒwmnr={s@*3m= IޑA M#88;Eă-kWUFǥdBwphaztT5IAmf)`zV}nkfiNW~=z0x3V2~RBd*z kRIZ)ύ2*PK/AWWÚ\qJgbcx 9=:T> > #OTSWSTw^M;ryHG]46RX#WlȐ̔<$t⸝^.AtX^qTH#!}R1Y>'yy5]`Bv7ҽn?Z3cz+_ZűzK֠%|Tz߳qұ'ڽ=< [OM1%p1D>ib.;b?ҥ3V m-B;kh,:u&x7YU/;b'JûA>'KGh;"ae p@>G))83 j~oM$V_ҺKqgLojRJ=tUi,TWwx/ViCx/Ucᤵxy4ܴ;[&Y|:`$U_@[|OAjU˒3ޛimz(%U<':|VxʐXdjh>aUǂ<@ ;Z!@nT ͗ 5vDH|-}| *5:> Ռpu$^ԕtaRp:)m]?"|U;y`¹xP?J;YZ<7z%ylRKD.(/{TrÁҺƪ)\?[$aF>ZE:})>qC?4 3tۭ&dڅ爩W>Р(EvvGҸ,Wei}){!/?&mv鹇gtY5 9V?-!jX!xbǦLE+rJZ? d̄4Β8Zw8@ql}­=8OP7F8̓mǡGsqo2}P.,02x#HcX7޺ ?w*OPTsqfAOYdOǙOR?%dDs * F~PsW-KRncQ~F1')Y{VxrBVNvWipF*3Ҳfx#iJ }To$3B夘WLS[ yqB$5_lf9هkam+ƱN ۺ"9+Cު+x$Y>xX21TnZ;w?b_dƹ뿂7wnY*<2?4q^ 25臿ُM_W ӱʬ/~Zx@z_'q⪭˛ע_oPZvRV$$!OW%-u5Ȳ;T627ۉ#،K WُW5q8b3Jc"滨Ok0ڰskq<t/p18hGQ=+_\w/JIϷD}>U[f^ uMC.crm@3j^$̏|n#@ic"(ZZ+ WCnaXi> `M I KF?fgPHs9AkWo CUe̒o\C<ŶeۭsvR~^Ǩ6Q&?Փk! ܳوKBa{WQo܂5x;y'j|;LPx"ϭtnQ{ygj~CП*NUFG= ̟j8|l;K5FrzWmm˗$4lA=itZ~=k OD=}n-N~wRvKb0zV=qW]x"6%P[|?}nPQ{"ʵt_fj(bО6V ´_$2QLDrK_20ȬA( ?[r~4;Oֵm]@.|n|NcO8ڠ(ƙG溶дƦUjѷC(??#Lδ۷^B1=g]^?mEԻu^4Frc|F.Nn3ZPbQWuUUx."9c1\U홳,24 `VBŋm#%'I=ѴB+;6,ypM& 5]__4kmq51;:AxC+c89rpG}UmCc1ī;p08@&PEPEPEPEP=W_[~7g0wt秧5y_~~w4_<("]эST6v_/jaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPS ?g\AQWLZvc0LVS`$(,2Ik6zHebJb*\W v᷆gS6BE*Oni< R-Vyw5kjdo%1ǀXwh +S՛ ռ]Zew0و0h߸ uy#/o'}BY5UV< @qG@uQEQEQEQEQE2iT(ԳUP:OAO#"߼q/5ı1x?1B'+fh^F&7L[8IC3 Vv_/jycT ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( LUpOT> ?xM<_4o%O7CyUF#T (a{oy1,о7#T2@(((((n $`dM: ⹂9%E#eYO :̷ycT ݗQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQETg"CZVac Z"F09!AU;$)4ه ]moZpƶӘF6Ʈ 3汮XۿnโKG.YWH̲%srk7MQ oU*ߕn?_yoMRYtv:mC$9I%.7' cU / (A27,&c<М7C WA o 7OTW8}O&ecy&T"u>[A/=̎V #8=+m;Z}:kX\A qֆ ~To|du8&I?7MOp{Z}t4W= o 7GkOt4W= o 7GkOt4W= o 7GkOt4W= o 7GkOm46sKonn&D-!'Z.&K>!=vT&IA $!ŴD,PT_e}Q-ݗl6f&Qm ȿ6<mI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oEEPI_oE2 Hu #*uQEQEQEQEQEQEQEQEڻcY רהkn#/8nֶvG۝ǕEL0 (BG>TH9ڀp3P"խ{gY$aiyx~YF$ V9꫷u57$:,efD1<JdS-}w!l<Pr?,Zuāx=UvSMf #a_jJ(2yF?tI)dyn g(I:+g/X窮iPqy$l1c+Mf2$&~錓TP$yn goeƭzȷycTQE(((((((+<{Ia=veU WeS ֕YS4LSHWzӿ»׿綝o}a__f?闙v? 4"kwxCv64I *26~Tt8Tn?Ԩ8oWzӿ»׿綝f,g9RDk /.ۋhݍ®VYO/|37wgڏVR?]NQ ^w"kv-w- vXqX]Ja.+f}]"߷i}A,rQT{G+{{i?]NWl|as}-ܐCk$q.-20T܎$c<C=ߝgyʿ1mջ8Wzӿ»׿綝N+h-Ya"R2>T}zpǖ»׿綝޽=Ez}zpǖ»׿綝޽=Ez}zpǖ»׿綝-jNysf#3m*^w$Y%y G }wl]Zl>h6hdGRxZX:IM*'+ʹ?j2:޵u{5C},6mȌp ö ٯI?g\Aaळeuk>`TQ ?*}3AV?Mn H{me}dOn{=CWsk]M/!In%PJon@?)~:*rvcs=\\/icpU#"ۻ"|9١?ѽhm۾s]}utzYQxjMI|"{n_{qr݌.fajxRO nnRTvQKi`2m,*NFp+-< As.7Eі@dg<a 6XU3FaE ͞1Ju( h4Fy2JD H( ( (!ylqcG =*hVeV;44;O+BmSvVW&+h"RV4bƭǥQ_"-j?Du42š-AdP2Nr@qӵ{4iSTVǑVGRIKJu M~a)_F_UIB8# U>>ϱ}93:g\eyi˿#g1z+)kx/rrɝmg5%:&05iJ%J+QF>qڣҭ'Y%-bq'_1)(ѵWUe OY8Y؅UX!$ NA?E?ECGyex0 IdJk}ZIWKU$ NA?EV7}^}_f%:&0SboX{G*oW NA?EV7z_ʃfnSboG%:&0V[F$`WpcG=_f~1-\K~g:M28Ʀ;]&fN_h_ӿ)?ƏIt/ G#)V_-gJ&*$ǛmffBޝI4KoN9`]K]>Zja oU]_Mi\Ius5JAw,QE# ( ( ( LUpOT> ?q%ޝ_6cyh]B1o-5Iد&V9v@ O/JߟoNse៲i^-??mtw~I-Jj6֓zݖ[YcEI)}.jê֞3ӭMVR㳽xɛlo&eFrd'53RkW947!x}>\ :SNu(IqKw&\JUeӚB b3+).8nhXxP,b,wJfʫ0ܫ tY{S-$AkBɥFX*W >rPOrrsPEPEPEPEP7ic1 )n8ϥgxw_ʱ46ӽ sL 0#=Vkq4Sͅdc*{zNӭ4llaXmD_ԓԒy$IyG˹H <#Z7F>u*"@P\ ?ZA{ IxAUb!3/| "(7S)MJ<5VU嘲bR g=3kw0)刲#P.gt5ikP5ϝAUhSB>?<͵ 7I2$Q.ݣؿ>UʊE +5rIb'/| "F(?0 y͞}`*mZ5bؐH:ikP5ϝAP-T$r<}?(kK;_|oTkK;_/| "8(g+FOF(??(ӏ|utvWSpARkK;_/| "8(g)tѴH I ڪ9,OV#66NȠEaI?w5P*׎a!+5Ʒp?؃DGUGVV5$=DѼ}JӮz1o;}RH5##br+5ѥ[:?ڼCl A=v:W\g'm?NiB*ZOդb(aDYOq1O̭SVv,}V()%dBUA#K}r_+4η}F-z!^6eH_?RQ^qQEQEQE> ?*}3AV?Mn+tW>+ci?z\GK 1ϓ_V>im=̳:vBWd -q_`GDx-·6e{yȕqݰG%/Ibzg{G 6 u˭p^=*W;(Š((((9+{o3Xlp<zVGu&IG4[< Hꇷ#f&ycT ݗQEQEQEQEQEQY>)Ӽ#_ZIXO4Ov u?5/gݢ5/g`j_7k_v=[n+407 (ʊ!|Cv~CETy6|]Z5eJ\3J5##^'WM.Fw%Y$?~w?/._k=:zѩQݜ?!$K?'_qߛ/G#WZ6_G_!}BO%_]w:z?5uehS9}֬漴,L3IEw6Kgdj8_;Eƞ-ւ g\ʴFi+Dߢ5/g`j_7k_SvԿnֿ՟#ݭ߫?G + RZVT5k]WFO3kK`v­\":(O*'* LUpOS[[L4.M+tM:m-fEi5P݁3Y*;+Cka^tǝ!M:j*ai~簒EaAv9R'*[oYX69Db2`xF9\1;q[PEPEPEPEPEP7vkp r(bR0FG"[ADCHpIEd[뼿1j]эST (((((^"]jb].@wh&w,bi#H>d8w3Uȅ/覨MsYhGNm"If3y 9Uu EmGŗRkŢ:+{IXl9 ?B@s}&f۽͹K4FE`hNaמ*[Z]Yk$=gw !;8@y9U4&g1-D*!eT~@2I''$y/5;gR#?WK; k*@jĚ/l೵$7%yyf)C T[|2~& .B21*>c{.6V) +Цʥnʒ6u##sbNm"i[8. BD)cyZ>w`w7sg˝S[ ?,OvhKaQvǁNN9Vk/~ y۷o͍wsz_-HK: n'1 \.Dn@n*!Zu/^Ŧ%Ņ\;(,v]NUŤyOoz6Cë)ʻAPz\y';UWt) *yҁ^#QZMYlvUIϿv(Tz$^eLq82>\u*=ڂڃ]^VWWdyyI c9N : ~AVݤt]ZAfgَuTQE LUpOT> ?<9M/Ó_]˩ֶ_I#4 ;<@=B;֍8<)ņ'F̰&Ky@HN8缰4k HkhSq;Q@ 2y8uvEYc-#Xt)Xy9ums&^Asɡvd|3hml(۸ǥ:ޣSPԓH2j+ڹ6xc'$GaY'9-fX^-!q _)A 7r9枺u@mMv; =@402|?⋝{Umn$s pyLn2oQT Ѵgx-R&+Q89U((((~ɧ\mDIC'Os{Oc2!"t/j̼G#ִ5 i3Hߙbp#o㏙V%fLa ,òi7?UM>7?U2.ύU7eTBMEQE ( ( ( LUpOQE5 4. 'ē,*+39 *zT?h`O̞[0A+E00VOgoEȕ|b U8GV P6=ZyϥU+4Q@Q@Q@Q@Q@v_/j*QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEnip2-8.7.1/doc/src/config.tex0000644000175000017500000001022213351443023012636 00000000000000\chapter{Configuration} \mylabel{sec:config} Click on the \ctr{Edit}\ct{Preferences} to see all the preference options. There are a lot of things you can change (probably too many). This section will list the most important. \subsection{Calculation} This column has the options which control how \nip{} starts and how and when it calculates. \begin{description} \item[\ct{Data path}] This is a list of directories where \nip{} searches for data files. These are any files that \nip{} can use but which aren't loaded at startup. I usually append the main areas on my machine where I store image files, for example. The default value is \ct{["\$HOME/.\$PACKAGE-\$VERSION/data", "\$VIPSHOME/share/nip/data", "."]}. \item[\ct{Temporary files}] This is where any intermediate files will be stored. It defaults to a directory called \ct{tmp} under your home area's \ct{.nip2-xx} directory. If \ct{nip} crashes, it may leave old files here. \item[\ct{Start path}] This lists directories which are searched when \nip{} starts for any loadable files. Anything that \nip{} comes across will be loaded up. The default value is \ct{["\$HOME/.\$PACKAGE-\$VERSION/start", "\$VIPSHOME/share/nip/start"]}. \item[\ct{Auto-recalc}] With this on (the default) \nip{} will recalculate whenever anything changes. Turn this off if recalculations are taking a long time and you want to make a series of small changes. \item[\ct{Update sliders during drag}] This sets whether recalculation happens as sliders are dragged, or whether the recalculation waits until the drag finishes. There's a similar setting for regions. \item[\ct{Auto workspace save}] With this tured on (the default) \nip{} will save the current workspace to the temporary files area a second after the last recalculation. If \nip{} crashes, you can restart it and click \ctr{File}\ct{Search for Workspace Backups} and \nip{} will reload the last workspace where you made a change. \item[\ct{Auto-reload on file change}] With this turned on \nip{} will automatically reload any image files that change while it has them open. Handy if you're using \nip{} to watch a file that another program is updating. \item[\ct{Maximum text display}] This sets the number of characters \nip{} shows for string values. Turn it up if you want to see inside long strings. \item[\ct{Maximum heap}] This sets the limit on the heap size. Turn it up if you start getting \ct{Heap full} error messages. If you left-click on the space free label in the bottom right of the main window, it will change to display the current heap statistics. There's a useful tooltip as well. \item[\ct{Number of CPUs to use}] If you have a machine with more than one CPU, you can make \nip{} faster by upping this number. \end{description} \subsection{Image display} This set of options control the default image display window settings. Useful if you're always having to turn the status bar on (for example). The maximum size option is handy if you're using \nip{} on a machine with a small display. The \ct{Auto popup} option makes \nip{} pop up an image display window automatically whenever you make a new image object. \subsection{Other options} Other areas of preferences are less useful. \begin{description} \item[\ct{Display LEDs}] If you're using a theme which uses bitmaps for widgets, you won't be able to see the button colour changes \nip{} usually uses to indicate state. This option adds three small LEDs to each row which indicate select, busy and error. \item[\ct{Default image format}] By default \nip{} file browsers show only VIPS images. If you find you mostly use (for example) JPEG images, you'll save yourself a few clicks on every file operation by switching this option to JPEG format. \item[Image format options] You can set the save options for the various image formats. \item[Video for linux] If you running Linux and have a capture card that supports the V4L interface, you can capture straight from the card into \nip{}. Set the capture options here. \item[Paintbox] The paintbox normally tracks all undo operations. This can chew up a lot of memory, especially for flood fills. Reduce the number of undo steps to free up some RAM. \end{description} nip2-8.7.1/doc/src/reference.tex0000644000175000017500000006453513351443023013347 00000000000000\chapter{Reference} \mylabel{sec:reference} \noindent This chapter is supposed to be a user-interface reference. \cref{sec:menus} describes the items in the \ct{Toolkits} menu and \cref{sec:program} is the programming language reference. \cref{sec:tutorial} has a tutorial-style introduction. \section{Image view window} \mylabel{sec:view} \fref{fg:imageview} shows \nip{}'s image view window with all the toolbars turned on. If you press \ct{i} (or \ct{+}) with the keyboard focus on the image you will zoom in on the pixel your mouse pointer is over. Press \ct{o} (or \ct{-}) to zoom out again, or press the number keys \ct{1}, \ct{2}, \ct{4} and \ct{8} to jump straight to a particular magnification. If you hold down the Ctrl key while pressing these numbers, \nip{} will zoom out by that amount. If you press \ct{0} (the number zero), then \nip{} will pick a magnification or reduction which fits the image to the size of the window. When the image is too large for the window, you can use the scroll bars to move about the image. With the keyboard focus on the image the cursor keys left, right, up and down move a few pixels in each direction; hold down Shift as well to move a screenful at a time; hold down Ctrl as well to jump to the extreme edges of the image. You can also drag with the middle mouse button to pan around the image. Use the mousewheel to pan up and down, hold down Shift and the mousewheel to pan left and right. Use Ctrl and the mousewheel to zoom in and out. Use the \ct{View} menu to add extra elements to the window. You can turn the status bar on and off, and you can add a display control bar, a paintbox and a set of rulers to the window. \begin{fig2} \figw{6in}{ir2.jpg} \caption{The display control bar} \mylabel{fg:scr3} \end{fig2} If you select \ctr{View}\ctr{Toolbar}\ct{Display Control}, \nip{} will add a bar to the top of the window which you can use to change the contrast and brightness of the image you are viewing. The left-hand slider and text box set the gain for the image: each pixel is multiplied by this amount before display. The right-hand slider and text box set the offset: each pixel has this value added to it before display. This is useful for boosting the brightness in dark areas of images. \begin{figure} \figw{1.5in}{ir3.jpg} \caption{The display control bar menu} \mylabel{fg:scr4} \end{figure} If you click the left mouse button on the arrow to the left of the display control bar, \nip{} pops up a menu of useful display functions --- see \fref{fg:scr4}. \ct{Scale} searches the area of the image you are viewing for the darkest and brightest points and chooses settings for the gain and offset sliders which will stretch the image to use the full range of your screen. \ct{False colour} tries to make small differences in brightness more visible by colour-coding them. If \ct{Interpret} is turned on (it is by default), then \nip{} will look at the \ct{Type} field in the image header, and use that as a hint when transforming the image to a viewable form for you. This is usually the behaviour you want. \ct{Reset} moves the sliders back to the default positions of 1.0 and 0.0. \ct{Set As Workspace Default} makes the current display bar settings the default for all new image windows in this workspace. Finally, \ct{Hide} removes this display control bar. If you select \ctr{View}\ctr{Toolbar}\ct{Rulers}, \nip{} will add rulers to the edges of the window which you can use to measure numbers of pixels. If you left-drag from the ruler, you can create a guide. Guides are useful for lining up other things in the view window, and also affect paint box actions. A right-button menu on the rulers lets you use a mm scale rather than a pixel scale, and controls whether the \ct{Xoffset} and \ct{Yoffset} header fields are used. \mylabel{sec:paintbox} If you select \ctr{View}\ctr{Toolbar}\ct{Paint}, \nip{} adds a paint bar to the top of the window. You can use the paint bar to do simple edits to the image being displayed. See \fref{fg:paint}. While the paint bar is very limited, it does have two useful features. First, it can paint with any pixel value, even complex numbers. For example you can take the fourier transform of an image and paint out the peaks. Secondly, it doesn't operate on a memory copy of an image, it operates directly on the file on disc. This means that you can paint very quickly on images of any size, but it does make the paint bar a bit dangerous. Normally paint actions are live, that is, every time you paint something all the objects which depend on the thing you painted will recalculate. This can sometimes cause annoying delays: there's a preferences option to turn off automatic recalculations for the paint bar. \begin{fig2} \figw{6in}{ir4.jpg} \caption{The paint bar} \mylabel{fg:paint} \end{fig2} The \ct{Undo} and \ct{Redo} buttons move forward and back though paint actions. The \ct{Clear} button wipes the undo/redo history (useful if memory is getting low). There's an option in the preferences workspace which controls the number of undo steps \nip{} tracks. The slider sets the nib diameter for drawing operations, the black square is the current ink colour (you can drag and drop colour, or pixel values, from other parts of \nip2{}), and the text box at the far right is the text that will be drawn by the text tool. The paint tools will `snap' to guides, points and regions, so you can line things up easily. You can mark regions on images by holding down Ctrl and dragging down and right with the left mouse button. You can move the region about by dragging on the label with the left mouse button; you can resize it by dragging with the left mouse button in the border; you can get a useful context menu by right-clicking on the label; and you can pop up a box which will let you edit the region numerically by double-left-clicking on the label. If you drag up and left, you will make an \emph{arrow}. If you hold down Ctrl and just click the left mouse button, you will make a \emph{point}. If you drag from a horizontal or vertical ruler, you'll make a \emph{guide}. Guides are useful for lining up other things in the view window. \ctr{View}\ct{Image Header} shows the image metadata and history. Use the search box to filter large metadata sets. The \ct{File} menu contains two useful items: select \ct{Replace Image} to change the image which is being displayed in the window (you can also drag and drop new images in). Select \ct{Save Image} to save the image you are viewing to a file. See \pref{sec:loadsave} for details on \nip{}'s load and save dialogs. Use \ctr{File}\ct{New} to make regions, points, arrows and guides without the mouse. \section{File select dialogs} \mylabel{sec:loadsave} On most platforms you can drag files from your file manager directly to \nip{}'s main window. Alternatively, if you select \ctr{File}\ct{Open} in the main window, \nip{} will pop up a file dialog, see \fref{fg:open}. The open dialog has the following extra features: \begin{figure} \figw{2in}{ir5.jpg} \caption{Open dialog} \mylabel{fg:open} \end{figure} \begin{description} \item[Pin up button] Normally the file dialog closes after you have opened something. If this item is checked, the dialog will stay up instead --- this is useful if you want to load or save a series of objects. \item[Image type select] Use this menu to select the type of file you want \nip{} to display. There's a preference option to set the default image format. The VIPS file format is fast and accurate, but sadly not very widely supported (joke). You can also load and save images in TIFF, JPEG, PNG, HDR, CSV and PBM/PGM/PPM formats. You can usually load in many more formats, it depends how your \nip{} has been configured. \item[Image info] This displays a one-line summary of the selected image, plus a large thumbnail. \end{description} The save dialog adds one extra feature: \ct{Increment filename}. If pin up and increment are both selected, then after a save \nip{} will attempt to add one to the selected file name. For example, if you save a file called \ct{fred001.v}, after the save \nip{} will put the name \ct{fred002.v} into the selected file name box. Again, this is useful if you want to save a series of images. \section{Image processing window} \mylabel{sec:ipwindow} \fref{fg:startup} shows \nip{}'s main image processing window. The centre area is the workspace, the left-hand area is a pane you can reveal to write custom definitions for this workspace (see \ctr{View}\ct{Workspace Definitions}), and the right-hand pane is the toolkit browser (see \ctr{View}\ct{Toolkit Browser}). Drag with the middle mouse button to scroll the workspace window. Drop a file on to the workspace background (from your file manager) to load that file. If you right-click on the workspace background, a useful menu will appear. \begin{figure} \figw{3in}{ir7.jpg} \caption{\nip{}'s main image processing window} \mylabel{fg:startup} \end{figure} \begin{description} \item[Workspace] A workspace is split into a set of separate tabs. Right-click on a tab to get a useful menu. Press the add icon at the right to make a new tab. You can drag tabs between workspaces, or drag a tab to the desktop to make a new workspace. Use the syntax \ct{tab1.A1} to make references between tabs. \item[Tab] This area displays the current tab. Tabs are divided into columns of objects which each behave rather like windows: they can be moved around, folded away, loaded, saved and deleted. \item[Current column] One column is the current column. This is the column to which all new objects are added. Single-left-clicking on the title bar of a column makes that the current column. See \pref{sec:column}. \item[File, Edit, View] Use the \ct{File} menu to create or save work\-spaces, to open workspaces or load other objects into this workspace, to merge workspaces and to search for workspace backups. Use the \ct{Edit} menu to select, group, delete and duplicate sets of objects. Use \ct{View} to show and hide elements of the main window, and to set the object view mode. \item[Toolkits] This menu contains all of the image processing functions which are currently loaded into \nip{}. They are generally grouped by object type: all of the operations on matricies are under \ctr{Toolkits}\ct{Matrix}, for example. If you select one of these image processing operations, \nip{} will apply that operation to the bottom few items in the current column (however many are necessary --- two items for \ctr{Math}\ctr{Arithmetic}\ct{Add}, for example), or alternatively, if you have selected some objects explicitly, it will try to apply the operation to the selected objects. See \pref{sec:apply}. As you move the mouse pointer over menu items \nip{} tries to display some helpful information about the operation, including the number and type of arguments the operation expects. \item[Toolkit Browser] This side panel shows all the image processing operations again, but this time as a large flat list you can easily browse. Type into the search box at the top to filter operations by keyword. Doubleclick on an item to activate it. \item[Tab Definitions] This side pane shows private definitions for this tab. Programs you write here are loaded and saved with this workspace. See the Programming chapter for details on \nip{}'s programming language. \item[Free space] This displays the amount of disc space you have left in your temporary file area. See \pref{sec:config} if you want to change the directory \nip{} uses to store temporary files. If you left-click on the label, it changes to display the space \nip{} has free internally for performing calculations. You can change this limit in the \ct{Preferences} workspace. Click again to switch back to disc free. If you have objects selected, this area changes to show the names of the selected objects. \item[Status bar] As you move the mouse pointer about the window, this bar tries to display useful information about the thing you are pointing at. \end{description} \subsection{Columns} \mylabel{sec:column} Columns are split into a number of areas: \begin{description} \item[Column name] Each column has a name. You can pick any name you like when you make a new column with \ctr{File}\ctr{New}\ct{Column}. There's no way to rename a column, unfortunately. Objects in the column are named using the column name, plus a number. \item[Column title bar] Drag with the left mouse button held down on the column title bar to move the column around the workspace. Double-left-click on the title bar to change the comment attached to the column. Hold down the right mouse button on the column title bar to pop up a useful menu. The items in the menu let you edit the caption, select all the objects in the column, make a new column which is a copy of this column, save the column to a file, convert the column into a menu item (see \pref{sec:diaref}) and remove the whole column. \item[Column fold button] Left-clicking on the fold button folds the column away. Use this to hide columns which you still need, but which you are not interested in just now. \item[Expression entry] You can perform calculations by typing expressions directly into this box. For example, try entering the following expressions, and pressing Return: \begin{verbatim} 2 + 2 A1 + 120 "My cat likes\nlasagne" fred = 12 \end{verbatim} \noindent The last example shows custom button name creation. Normaly \nip{} will pick a name for you, but you can chose your own. \end{description} \subsection{Rows} \mylabel{sec:row} A column holds a number of rows. Each row comes in four main parts, not all of which are visible for all row values. Rows which represent classes have a pair or up/down arrows to the left of the row name button which you can use to control which parts of the row are visible. \begin{figure} \figw{1.5in}{ir8a.jpg} \caption{Components of a workspace row} \mylabel{fg:row} \end{figure} \begin{description} \item[Row name button] Each row has a name. The name is normally formed from the name of the current column, plus a number. If you double-left-click on the row name button, \nip{} will pop up a viewer or dialog box for the value of the row. If you left-click, \nip{} will select that row and deselect all other rows. If you click on an empty space in the workspace, it will deselect all rows. If you Ctrl-left-click, \nip{} will toggle selection of that row. If you select one row and then Shift-left-click on another row in the same column it will select the second row and all the rows in between. If you drag with the left button, you can change the order of rows in a column. Hold down the right mouse button for a useful menu. If you let the mouse linger over a button, a useful tooltip will appear. \item[Graphic] If the row's value is a class, and if the class is an instance of one of \nip{}'s graphic classes, then \nip{} will draw a graphic representation of the row's value. See \pref{sec:workspaces} for a more detailed explanation. \item[Members] If the row has a class for a value, then \nip{} will draw a sub-column listing the class members. Subcolumn members are in turn rows themselves. \item[Text] Finally, the text part normally shows a text representation of the row's value. If you left-click on the value, it changes to show the formula which generated that value. You can edit the formula and press Return to change it. Alternatively, selecting \ctr{View}\ct{Show Formula} toggles between displaying values for objects and displaying the formula. \end{description} \subsubsection{Object name colours} \nip{} changes the background colour of the row name button to show the state of the row. If background colours are not visible (perhaps your theme turns them off), try turning on the \ct{Display LEDs in workspace} option in \ct{Preferences}. Green means the row is selected (click on the background to unselect), red indicates an error (right-click on the row button ans select \ct{Recalculate} to see the full text of the error), brown indicates that the row value is out of date and needs recalculating and the various blues indicate parent and child relationships. \subsection{Applying operations to objects} \mylabel{sec:apply} There are three ways you can apply image processing operations to objects in your workspace: \begin{enumerate} \item Select the object you want to apply the operation to by single-left-clicking on the object name. When you single-click, the object name will change colour to show that it is selected, and \nip{} will display the name of the selected object at the left end of the status bar (this is useful if the selected object is scrolled off the edge of the window). You can select additional objects with Ctrl-left-click and Shift-left-click. This is necessary if you want to use an image processing operation that takes more than one argument. Once you have selected the rows (sometimes you need to select them in a certain order), click on the processing operation you want from the \ct{Toolkits} menu. \item If there are no objects selected when you click on an image processing operation, \nip{} uses the bottom few items (as many as are needed by the operation) in the current column. \item You can also type your formula directly into the expresion entry line at the bottom of the selected column. \cref{sec:program} describes the syntax in detail, but it's approximately C. \end{enumerate} \subsection{Batch processing} \mylabel{sec:batch} If you select a number of rows and then click \ctr{Edit}\ct{Group}, \nip{} will group the rows together. Now if you select the group and click on an item in the \ct{Toolkits} menu, \nip{} will apply that operation to every item in the group. You can group groups, and you can mix grouped and non-grouped rows freely. If you save a group, \nip{} will write each item in the group to a separate file, incrementing the filename each time. \subsection{Error handling} \mylabel{sec:error} If an object in your workspace has an error (for example, if you are trying to join two images of different types), then the object name button will turn red to show that this object contains an error and the tooltip for the button will show the error message. \subsection{Making menu items out of columns} \mylabel{sec:diaref} If you make a column that does something useful, you can make it into a menu item by following these steps: \begin{enumerate} \item Make your column look nice. Drag with the left mouse button on the object name buttons to re-order items in the column, and add comments to explain what are the input fields and what are the output. Double-click on the column title bar to add a helpful title to the column. Add a comment by typing your text (enclosed in double quotes) into the line at the bottom of the column. Left-drag the row to the right place. \item Select \ct{Make Column Into Menu Item} from the column title-bar menu, see \pref{sec:column}. This will open up a new dialog box which you can use to set a name for your new menu item and the name of the top level menu the item should be added to. \item That's it. You'll be prompted to save your new toolkit when you try to quit \nip{}. We recommend you just say \ct{OK} to the suggested location for the file. Edit your menus with the programming window, see \pref{sec:progwin}. \end{enumerate} \section{The programming window} \mylabel{sec:progwin} To pop up the programming window, click on \ctr{Toolkits}\ct{Edit Toolkits} in \nip{}'s main image processing window. The window shown in \fref{fg:Fred} should appear. Each of the things down the left of the program window is a toolkit. Each toolkit is a text file containing a set of definitions in \nip{}'s programming language. See \cref{sec:program} for details on the language. If you open a toolkit, \nip{} shows all of the definitions in that file. If you click on one of these \nip{} shows the source for that definition in the main part of the program window. After editing a definition, click on \ctr{File}\ct{Process} to make \nip{} read what you typed, compile it, and update itself. Click on \ctr{File}\ctr{New}\ct{Tool} to add a new definition to a toolkit, click on \ctr{File}\ctr{New}\ct{Toolkit} to make a completely new toolkit. You can also right-click on tools and toolkits to get a context menu, and you can left-drag tools to move them around within a toolkit or between toolkits. Some toolkits are loaded from files when \nip{} starts up, others are built from the VIPS operation database (for example, \ct{\_arithmetic}), and one (called \ct{\_builtin}) contains the functions that are built into \nip{}. If you select a tool and then click on \ctr{Help}\ct{Help on Tool}, \nip{} will try to display the relevant section from the VIPS manual in your web browser. Currently, this works only for things in the VIPS operation database: try \ctr{\_arithmetic}\ct{im\_add}, for example. There's a section in the \ct{Preferences} workspace to control which web browser \nip{} uses and how it asks for a page. Toolkits and tools whose names begin with an underscore character are not displayed in the main \ct{Toolkits} menu. The idea is that they represent little utility functions, rather than stuff a user might be interested in. See \pref{sec:tools} for more information on how tools and toolkits are displayed. You can have several programming windows open at the same time (often useful, if confusing). The \ct{Edit} menu lets you search for patterns across all definitions. The \ct{Jump To Definition} item jumps to the definition of a symbol. \mylabel{sec:trace} The \ct{Debug} menu has items which open a trace window (use this to track the actions taken by \nip{}'s reduction engine) and which report on unresolved symbols and list all current errors. \section{Command-line interface} \mylabel{sec:cmdline} You can use \nip{} from the command-line as well as from the GUI. This can be handy for automation: you can build a workspace and then run it over a whole set of images, or use \nip{} as part of a larger system. We've make websites which use \nip{} as the back-end. In command-line mode \nip{} runs without a GUI of any sort, it doesn't even need a window system to be installed on the machine. This makes it possible to use it in a server or batch context. These notes are for the Unix command-line, but they should work for Windows as well. \nip{} has three main modes of operation from the command-line: \begin{description} \item[\nip{} \emph{filename1} \ldots{}] Start \nip{} in GUI mode, loading the command-line arguments as files. Filenames can be images, workspaces, matricies, toolkits, and so on. \item[\nip{} \ct{-e} \emph{expression} \emph{arg1} \ldots{}] Start in no-GUI mode, print the value of \emph{expression}. The list \ct{argv} is set to be \verb+["filename","arg1",..]+. \item[\nip{} \ct{-s} \emph{filename} \emph{arg1} \ldots{}] Start in no-GUI mode, read in \emph{filename} as a set of definitions, print the value of symbol \ct{main}. The list \ct{argv} is set to be \verb+["filename","arg1",..]+. \end{description} You can use the \ct{-o} option to send output somewhere other than the screen. If these modes don't do quite what you need, you can get finer control of how \nip{} behaves with a set of other options: see the man page for details. \subsection{Using expression mode} The \ct{-e} option is very easy to use. For example: \begin{verbatim} nip2 -e "2 + 2" \end{verbatim} \noindent Prints 4 to stdout. \begin{verbatim} nip2 -e "99 + Image_file argv?1" -o result.png fred.jpg \end{verbatim} \noindent Loads argv1 (\ct{fred.jpg}), adds 99, writes the result to \ct{result.png}. \begin{verbatim} nip2 -e "Matrix [[1,2],[4,5]] ** -1" -o poop.mat \end{verbatim} \noindent Invert the 2x2 matrix and write the result to \ct{poop.mat}. If the result of the expression is a list, each item is printed on a new line. For example: \begin{verbatim} nip2 -e "[1..5]" \end{verbatim} \noindent Will print the numbers 1 to 5, each on a new line. If you have a list result and you are using \ct{-o} to direct the output to a file, the filename will be incremented each time you write. For example: \begin{verbatim} nip2 -e "map (add (Image_file argv?1)) [10, 20 .. 50]" -o result1.png fred.jpg \end{verbatim} \noindent Will load \ct{fred.jpg}, add 10, 20, 30, 40 and 50, then save those images to \ct{result1.png} to \ct{result5.png}. \subsection{Using script mode} With the \ct{-s} option you can use \nip{} as a Unix script interpreter. Create a file in your favourite text editor called \ct{brighten} containing: \begin{verbatim} #!/usr/bin/nip2 -s main = clip2fmt infile.format (infile * scale), argc == 3 = error "usage: infile scale -o outfile" { infile = Image_file argv?1; scale = parse_float argv?2; } \end{verbatim} \noindent The first line needs to be the path to \nip{} on your system. Use \ct{which nip2} to find the path if you don't know it. Mark the file as executable with \ct{chmod +x brighten}, then use it on one of your image files with: \begin{verbatim} brighten fred.jpg 1.5 -o bright_fred.png \end{verbatim} \noindent See \cref{sec:program} for details on the programming language. This program multiplies each input pixel by the constant, producing a floating point image, then then clips the result back to the same format as the original image (usually 8-bit unsigned). \nip{} takes a while (a few seconds) to start up, so this isn't going to be appropriate for small images or simple calculations. But for complex operations, or operations on large images, this mode can be very useful. \subsection{Using \ct{--set}} The \ct{--set} option (which can be abbreviated to \ct{-=}) lets you make changes to a workspace after loading it. Suppose the workspace \ct{test.ws} has a row called \ct{A1} with the value 12. Then entering: \begin{verbatim} nip2 test.ws --set Workspaces.test.A1=45 \end{verbatim} \noindent Will, as normal, start \nip{} and load \ct{test.ws}. But before the first recalculation, \nip{} will change the value of \ct{A1} to be 45. You can use \ct{--set} to create new symbols as well. \subsection{Other modes} A set of sub-options let you mix up other modes yourself. For example, it's common to want to run a workspace on many files. Suppose the workspace \ct{process.ws} loads an image in \ct{A1}, performs some processing and produces a result image \ct{A10}. If you run \nip{} with: \begin{verbatim} nip2 -bp \ -= 'Workspaces.process.A1=Image_file "fred.jpg"' \ -= main=Workspaces.process.A10 \ -o fred.jpg process.ws \end{verbatim} \noindent This will start \nip{} in batch (ie. no GUI) mode (the \ct{-b} switch), load \ct{process.ws}, change \ct{A1} to load another file, set \ct{main} to be the value of \ct{A10} and save the value of \ct{A10} to \ct{fred.jpg} (the \ct{-p} switch). nip2-8.7.1/doc/src/program.tex0000644000175000017500000014146313351443023013054 00000000000000\chapter{Programming} \mylabel{sec:program} \noindent \nip{} includes a tiny lazy functional programming language. You can use it to glue VIPS image processing functions together to perform more complicated tasks. All of the \nip{} toolkit menus are written in this language. These first sections just describe the programming language. See \pref{sec:progwin} for a description of the programming window. You use \nip{}'s programming language to control the user interface: the link between what happens inside a \nip{} function and what you see on the screen in covered in \pref{sec:bowser}. \section{Load and save} When \nip{} starts up it loads all of the definition files (files with a \ct{.def} extension) it can find in the directories listed in your start path. You can change the start path in Preferences. By default, the start path lists just two areas: a personal start directory that \nip{} makes in your home area, and the main system \nip{} start directory containing all the standard toolkits. If there are two files with the same name on the start path, then \nip{} will only load the first one. This means that if you modify one of \nip{}'s built-in menus and save it to your personal start directory, in future you'll just see your personalised version. You can load or reload a toolkit at any time with the \ctr{File}\ct{Open Toolkit} menu item in the program window. If you open a toolkit with the same name as an existing toolkit, \nip{} will remove the old toolkit before it loads the new one. \section{Using an external editor} If you're going to be doing any more than a little programming in \nip{} you probably won't want to use the built-in editor. I suggest you start your favorite editor in one window on the screen and then in the \nip{} program window click \ctr{File}\ct{Open Toolkit} and check the Pin-up box in the file selector. Now every time you want to try out your definition, save the file from your external editor and click OK in \nip{}'s file selector. \nip{}'s editor automatically adds some semicolon characters to separate definitions in a file. If you're using an external editor, you'll need to put these in yourself. Also check the syntax for adding separators and column items to menus. \section{Syntax} The most basic sort of definition looks like this: \begin{verbatim} // very simple! fred = 12 \end{verbatim} \noindent This defines a function called \ct{fred} whose value is the number 12. The \ct{//} marks a comment: everything to the end of the line is skipped. Case is distinguished, so \ct{Fred} and \ct{fred} are two different functions. You can use letters, numbers, underscores and single quotes in function names. You can have patterns on the left of the equals sign. For example: \begin{verbatim} [fred, petra] = [12, 13] \end{verbatim} \noindent defines \ct{fred} to have the value 12 and \ct{petra} to have the value 13. See \pref{sec:pattern} for details. Functions may take parameters: \begin{verbatim} /* A function with parameters. */ jim a b = a + b + 12 \end{verbatim} \noindent This defines a function called \ct{jim} which takes two parameters and whose value is the sum of the two parameters, plus 12. The \ct{/*} and \ct{*/} enclose a multi-line comment. Functions may have several right-hand-sides, each right-hand-side qualified by a guard expression. Guards are tested from top to bottom and the first guard which has the value \ct{true} causes the function to have the value of that right-hand-side. If no guard evaluates to \ct{true}, then the last right-hand-side is used. \begin{verbatim} jenny a b = 42, a + b >= 100 = 43, a + b >= 50 = 44 \end{verbatim} \noindent This defines a function called \ct{jenny} which takes two parameters and whose value is 42 if the sum of the parameters is 100 or greater; 43 if the sum is greater than or equal to 50 but less than 100; and 44 if the sum is less than 50. Any function may be followed by any number of local functions, enclosed in curly braces. So \ct{jenny} could be written as: \begin{verbatim} jenny a b = 42, sum >= 100 = 43, sum >= 50 = 44 { sum = a + b; } \end{verbatim} \noindent Note that you need a semi-colon after each local function. A local function may refer to anything in an enclosing scope, including itself. You can write \ct{if-then-else} expressions: \begin{verbatim} david a = if a < 12 then "my cat" else "likes lasagne" \end{verbatim} \noindent This is exactly equivalent to: \begin{verbatim} david a = "my cat", a < 12 = "likes lasagne" \end{verbatim} \noindent \ct{if-then-else} expressions are sometimes easier to read than guards. Functions application is with spaces (juxtaposition). For example: \begin{verbatim} harry = jim 2 3 \end{verbatim} \noindent defines \ct{harry} to have the value 17. All functions are curried, that is, they can accept their arguments in stages. For example: \begin{verbatim} sandro = jim 1 \end{verbatim} \noindent defines \ct{sandro}, a function which takes one parameter and will add 13 to it. This trick becomes very useful with list processing, see \pref{sec:lists}. \nip{} has some built-in functions, see \tref{tb:builtin}. They mostly take a single argument. All other functions are defined in the various standard toolkits and can be edited in the program window. \begin{tab2} \begin{center} \begin{tabular}{||l|l||} \hline Function & Description \\ \hline \ct{dir} \textit{any} & List names in scope \\ \ct{has\_member} \textit{[char]} \textit{any} & Does class have member \\ \hline \ct{name2gtype} \textit{[char]} & Search for a GType by name \\ \ct{gtype2name} \textit{real} & Return the name of a GType \\ \hline \ct{error} \textit{[char]} & Stop with error message \\ \ct{print} \textit{any} & Convert to string \\ \ct{expand} \textit{[char]} & Expand environment variables in string \\ \ct{search} \textit{[char]} & Search for a file \\ \ct{\_} \textit{[char]} & Translate string \\ \hline \ct{is\_image} \textit{any} & Test for image \\ \ct{is\_bool} \textit{any} & Test for boolean \\ \ct{is\_real} \textit{any} & Test for real \\ \ct{is\_class} \textit{any} & Test for class \\ \ct{is\_char} \textit{any} & Test for char \\ \ct{is\_list} \textit{any} & Test for list \\ \ct{is\_complex} \textit{any} & Test for complex \\ \ct{is\_instanceof} \textit{[char]} \textit{any} & Test for instance of class \\ \hline \ct{re} \textit{image}/\textit{complex}/\textit{class} & Extract real part of complex \\ \ct{im} \textit{image}/\textit{complex}/\textit{class} & Extract imaginary part of complex \\ \ct{hd} \textit{list} & Extract head of list \\ \ct{tl} \textit{list} & Extract tail of list \\ \ct{sin} \textit{image}/\textit{number}/\textit{class} & Sine \\ \ct{cos} \textit{image}/\textit{number}/\textit{class} & Cosine \\ \ct{tan} \textit{image}/\textit{number}/\textit{class} & Tangent \\ \ct{asin} \textit{image}/\textit{number}/\textit{class} & Arc sine \\ \ct{acos} \textit{image}/\textit{number}/\textit{class} & Arc cosine \\ \ct{atan} \textit{image}/\textit{number}/\textit{class} & Arc tangent \\ \ct{log} \textit{image}/\textit{number}/\textit{class} & Natural log \\ \ct{log10} \textit{image}/\textit{number}/\textit{class} & Base 10 log \\ \ct{exp} \textit{image}/\textit{number}/\textit{class} & e to the power \\ \ct{exp10} \textit{image}/\textit{number}/\textit{class} & 10 to the power \\ \ct{ceil} \textit{image}/\textit{number}/\textit{class} & Round up \\ \ct{floor} \textit{image}/\textit{number}/\textit{class} & Round down \\ \ct{gammq} \textit{real} \textit{real} & Normalised incomplete Gamma function \\ \hline \ct{vips\_image} \textit{[char]}& Load image from file \\ \ct{read} \textit{[char]} & Load file as a string \\ \hline \end{tabular} \end{center} \caption{\nip{} built in functions} \mylabel{tb:builtin} \end{tab2} \section{Naming conventions} You can name things in any way you like, but we've used the following conventions. \begin{itemize} \item Classes start with a capital letter, words are separated with underscores, subsequent words are not capitalised (eg. \ct{Image\_file}) \item Private names are prefixed with underscores (and are hidden by most of the user interface) \item Functions from the VIPS library are prefixed with \ct{im\_} \item Global utility functions (eg. \ct{map}), public members (eg. \ct{Colour.colour\_space}) are all lower case, words are separated with underscores, subsequent words are not capitalised \item Constants are capitalised (eg. \ct{Operator\_type.COMPOUND\_REWRAP}) \end{itemize} \section{Evaluation} \nip{} calculates the value of an expression by using the definitions you entered to successively reduce the expression until it becomes one of the base types. Sometimes there is a choice as to which part of the expression will be reduced next --- \nip{} will always choose to reduce the leftmost, outermost part of the expression first. For example, consider this definition: \begin{verbatim} factorial n = n * factorial (n - 1), n > 1 = 1 \end{verbatim} And here's how \nip{} will evaluate the expression \ct{factorial 3}: \begin{verbatim} factorial 3 --> 3 > 1 --> true 3 * factorial (3 - 1) --> (3 - 1) > 1 --> 2 > 1 --> true 3 * (2 * factorial (2 - 1)) --> (2 - 1) > 1 --> 1 > 1 --> false 3 * (2 * 1) --> 3 * 2 --> 6 \end{verbatim} \noindent Note how \nip{} delays evaluating parameters to functions until they are needed, but still shares the result. \ct{3 - 1} is only evaluated once, for example, even though the result is used three times. \nip{} has a trace window: click on \ctr{Debug}\ct{Trace} in the program window and check the \ctr{View}\ct{Operators} menu item. The advantage of this style of computation over conventional imperative programming languages is that you can reason about your program mathematically\footnote{Since programs are referentially transparent (that is, the value of an expression depends only upon its syntactic context, not upon computation history), you can easily do equational reasoning, proof by induction, and so on. Expressions are like theorems, definitions are like axioms, computation is like proof.}. This isn't the best way to write a factorial function. A function with lots of recursive calls can be hard to understand --- it's much better to use one of the higher order functions from the standard environment to encapsulate the type of recursion you want to use. The clearest definition for factorial is probably: \begin{verbatim} factorial n = product [1..n] \end{verbatim} \noindent See \pref{sec:listsyntax} for an explanation of the list syntax. \section{Operators} \mylabel{sec:operators} \nip{}'s expression syntax is almost exactly the same as C, with a few small changes. \tref{tb:precedence} lists all of \nip{}'s operators in order of increasing precedence. If you've used C, the differences are: \begin{itemize} \item C's \verb+?:+ operator becomes \ct{if-then-else}, see above \item Like almost every functional language, \nip{} uses square brackets for list constants (see \pref{sec:listsyntax}), so to index a list, \nip{} uses \ct{?} \item \nip{} adds \ct{@} for function composition, see \pref{sec:func} \item The \ct{:} operator is infix list cons, see \pref{sec:lists} \item The \ct{++} operator becomes an infix concatenation operator, \ct{--} becomes list difference. Again, see \pref{sec:listsyntax} \end{itemize} The only slightly tricky point is that function application binds very tightly (only list index and class project bind more tightly). So the expression: \begin{verbatim} jim = fred 2 + 3 \end{verbatim} \noindent binds as: \begin{verbatim} jim = (fred 2) + 3 \end{verbatim} \noindent This is almost always the behaviour you want. There are two special equality tests: \ct{===} and \ct{!==}. These test for pointer equality, that is, they return \ct{true} if their arguments refer to the same object. These are occasionally useful for writing interactive functions. \begin{tab2} \begin{center} \begin{tabular}{||l|l|l||} \hline Operator & Associativity & Description \\ \hline \ct{if then else} & Right & If-then-else construct \\ \ct{=>} & Left & Form name/value pair \\ \verb+||+ & Left & Logical or \\ \ct{\&\&} & Left & Logical and \\ \ct{@} & & Function composition (see \pref{sec:func}) \\ \verb+|+ & Left & Bitwise or \\ \rtp{} & Left & Bitwise exclusive or \\ \ct{\&} & Left & Bitwise and \\ \hline \ct{==} & Left & Equal to\\ \ct{!=} & & Not equal to\\ \ct{===} & & Pointer equal to\\ \ct{!==} & & Pointer not equal to\\ \hline \ct{<} & Left & Less than \\ \ct{<=} & & Less than or equal to\\ \ct{>} & & Greater than \\ \ct{>=} & & Greater than or equal to\\ \hline \ct{<<} & Left & Left shift \\ \ct{>>} & & Right shift \\ \hline \ct{+} & Left & Addition \\ \ct{-} & & Subtraction \\ \ct{*} & Left & Multiplication \\ $/$ & & Division \\ \ct{\%} & & Remainder after division \\ \ct{!} & Left & Logical negation \\ \verb+~+ & & One's complement \\ \ct{++} & & Join (see \pref{sec:listsyntax}) \\ \verb+--+ & & Difference (see \pref{sec:listsyntax}) \\ \ct{-} & & Unary minus \\ \ct{+} & & Unary plus \\ \ct{(}\emph{type}\ct{)} & & Type cast expression \\ \ct{**} & Right & Raise to power \\ \ct{:} & & List CONS (see \pref{sec:listsyntax}) \\ \emph{space} & Left & Function application \\ \ct{?} & Left & List index (see \pref{sec:listsyntax}) \\ \ct{.} & Left & Class project (see \pref{sec:class}) \\ \hline \end{tabular} \end{center} \caption{\nip{} operators in order of increasing precedence} \mylabel{tb:precedence} \end{tab2} \subsection{The real type} \nip{} has a single number type for integers and real numbers. All are represented internally as 64-bit floating point values. You can use the four standard arithmetic operators (\ct{+}, \ct{-}, \ct{*}, \ct{/}), remainder after integer division (\%), raise-to-power (\ct{**}), the relational operators (\ct{<}, \ct{<=}, \ct{>}, \ct{>=}, \ct{==}), the bitwise logical operators (\ct{\&}, \verb+|+, \rtp{}, \verb+~+), integer shift operators (\ct{<<}, \ct{>>}) and unary negation and positive (\ct{-}, \ct{+}). Other mathematical functions are pre-defined for you: \ct{sin}, \ct{cos}, \ct{tan}, \ct{asin}, \ct{acos}, \ct{atan}, \ct{log}, \ct{log10}, \ct{exp}, \ct{exp10}, \ct{ceil}, \ct{floor}. Each has the standard behaviour. You can use type-casts on reals. However, they remain 64-bit floating point, the range is simply clipped. Casting to \ct{unsigned short} produces a 64-bit float whose fractional part has been set to zero, and which has been clipped to the range 0 to 65535. This may or may not cause rounding problems. You can write hexadecimal number constants as \verb"0xff". \subsection{The complex type} Complex numbers are rather sketchily implemented. They are generally handy for representing vectors and coordinates rather than for doing arithmetic, so the range of operations is limited. Complex constants are written as two numbers enclosed in round brackets and separated by a comma. You can use the four standard arithmetic operators (\ct{+}, \ct{-}, \ct{*}, \ct{/}), raise-to-power (\ct{**}), and unary negation and positive (\ct{-}, \ct{+}). You can use \ct{==} only of the relational operators. You can mix complex and real numbers in expressions. You can cast reals to complex and back. Use the functions \ct{re} and \ct{im} to extract the real and imaginary parts. \begin{verbatim} (12, 13) + 4 == (16, 13) (12, 2 + 2) == (12, 4) re (12, 13) == 12 im (12, 13) == 13 \end{verbatim} \subsection{The character type} Character constants are written as single characters enclosed in single quotes. You can use the relational operators (\ct{<}, \ct{<=}, \ct{>}, \ct{>=}, \ct{==}) to sort characters by ASCII order. You can cast a character to a real to get its ASCII value. You can cast a real ASCII value to a character. You can use the standard C escapes to represent non-ASCII characters. \begin{verbatim} (int) 'A' == 65 (char) 65 == 'A' is_digit x = '0' <= x && x <= '9' newline == '\n' \end{verbatim} \subsection{The boolean type} The two boolean constants are written as \ct{true} and \ct{false}. Boolean values are generated by the relational operators. You can use the standard logical operators (\ct{\&\&}, \verb+||+, \ct{!}). You can use a boolean type as an argument in an \ct{if-then-else} expression. As with C, the logical operators do not evaluate their right-hand sides if their value can be determined just from evaluating their left-hand sides. \begin{verbatim} true && false == false true || error "boink!" == true if true then 12 else 13 == 12 \end{verbatim} \subsection{The list type} \mylabel{sec:listsyntax} Lists are created from two constructors. \ct{[]} denotes the empty list. The list construction operator (\ct{:}, pronounced CONS by LISP programmers) takes an item and a list, and returns a new list with the item added to the front. As a convenience, \nip{} has a syntax for list constants. A list constant is a list of items, separated by commas, and enclosed in square brackets: \begin{verbatim} 12:[] == [12] 12:13:14:[] == 12:(13:(14:[])) == [12,13,14] [a+2,3,4] == (a+2):3:4:[] [2]:[3,4] == [[2],3,4] \end{verbatim} Use the functions \ct{hd} and \ct{tl} to take the head and the tail of a list: \begin{verbatim} hd [12,13,14] == 12 tl [12,13,14] == [13,14] \end{verbatim} Use \ct{..} in a list constant to define a list generator. List generators build lists of numbers for you: \begin{verbatim} [1..10] == [1,2,3,4,5,6,7,8,9,10] [1,3..10] == [1,3,5,7,9] [10,9..1] == [10,9,8,7,6,5,4,3,2,1] \end{verbatim} \noindent List generators are useful for expressing iteration. Lists may be infinite: \begin{verbatim} [1..] == [1,2,3,4,5,6,7,8,9 ..] [5,4..] == [5,4,3,2,1,0,-1,-2,-3 ..] \end{verbatim} \noindent Infinite lists are useful for expressing unbounded iteration. See \pref{sec:lazy}. You can write list comprehensions like this: \begin{verbatim} [x :: x <- [1..]; x % 2 == 0] \end{verbatim} \noindent This could be read as {\em All x such that x is in \verb+[1..]+ and x is even}, that is, the list of even numbers. You can have any number of semicolon-separated qualifiers and each one can be either a generator (like \verb"x <- [1..]") introducing a new variable or pattern (see \pref{sec:pattern}), or a predicate (like \verb"x % 2 == 0") which filters the generators to the left of it. Later generators change more rapidly, so for example: \begin{verbatim} [(x, y) :: x <- [1..3]; y <- [x..3]] == [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] \end{verbatim} You can nest list comprehensions to generate more complex data structures. For example: \begin{verbatim} [[x * y :: x <- [1..10]] :: y <- [1..10]] \end{verbatim} \noindent will generate a times-table. You can use pattern-matching (see \pref{sec:pattern}) to loop over several generators at the same time. For example: \begin{verbatim} [(x, y) :: [x, y] <- zip2 [1..3] [1..3]] == [(1, 1), (2, 2), (3, 3)] \end{verbatim} As a convenience, lists of characters may be written enclosed in double quotes: \begin{verbatim} "abc" == ['a','b','c'] \end{verbatim} You can define a string constant which has the same form as a variable name (that is, letters, numbers, underscore and apostrophy only) with a \verb+$+ prefix. For example: \begin{verbatim} $form7 == "form7" \end{verbatim} \noindent \nip{} often uses these in option lists. You can define a name, value pair with the \ct{=>} operator. \begin{verbatim} $fred => 12 == ["fred", 12] \end{verbatim} \noindent Again, these pairs are frequently used to pass options to objects. A list may contain any object: \begin{verbatim} [1,'a',true,[1,2,3]] \end{verbatim} \noindent Mixing types in a list tends to be confusing and should be avoided. If you want to group a set of diverse objects, define a class instead, see \pref{sec:class}. Lists of lists of reals are useful for representing arrays. You can use the list index operator (\ct{?}) to extract an element from a position in a list: \begin{verbatim} [1,2,3] ? 0 == 1 "abc" ? 1 == 'b' \end{verbatim} You can use the list join operator (\ct{++}) to join two lists together end-to-end. \begin{verbatim} [1,2,3] ++ [4,5,6] == [1,2,3,4,5,6] \end{verbatim} You can use the list difference operator (\verb+--+) to remove elements of one list from another. \begin{verbatim} [1..10] -- [4,5,6] == [1,2,3,7,8,9,10] \end{verbatim} \subsection{The function type} \mylabel{sec:func} Functions are objects just like any other. You can pass functions to other functions as parameters, store functions in lists, and so on. You can create anonymous functions with \verb"\" (lambda). For example: \begin{verbatim} map (\x x + 2) [1..3] == [3, 4, 5] \end{verbatim} You can nest lambdas to make multi-argument anonymous functions, for example: \begin{verbatim} map2 (\x\y x + y) [1..3] [2..5] == [3, 5, 7] \end{verbatim} You can compose functions with the \ct{@} operator. For example, for two functions of one argument \ct{f} and \ct{g}: \begin{verbatim} f (g 2) == (f @ g) 2 \end{verbatim} \subsection{The image type} These represent a low-level handle to a VIPS image structure. You can make them with the \ct{vips\_image} builtin, and you can pass them as parameters to VIPS functions. The \ct{Image} class is built on top of them, see \pref{sec:Image}. As an accident of history, \nip{} also lets you do arithmetic with them. This will probably be removed in the next version or two, so it's best to go through the higher-level \ct{Image} class. \section{Lists and recursion} \mylabel{sec:lists} Functional programming languages do not have variables, assignment or iteration. You can achieve the same effects using just lists and recursion. There are two main sorts of recursion over lists. The first is called \emph{mapping}: a function is applied to each element of a list, producing a new list in which each element has been transformed. \begin{verbatim} map fn [a,b,c] == [fn a, fn b, fn c] \end{verbatim} The second main sort of recursion is called \emph{folding}: a list is turned into a single value by joining pairs of elements together with a function and a start value. \begin{verbatim} foldr fn start [a,b .. c] == (fn a (fn b (.. (fn c start)))) \end{verbatim} \noindent (The function is called \ct{foldr} as it folds the list up right-to-left. There is an analogous function called \ct{foldl} which folds a list up left-to-right, but because of the way lists work, it is much slower and should be avoided if possible.) \ct{map} is defined in the standard list library for you: \begin{verbatim} /* map fn l: map function fn over list l */ map fn l = [], l == [] = fn (hd l) : map fn (tl l) \end{verbatim} \noindent So, for example, you could use \ct{map} like this: \begin{verbatim} map (add 2) [1..5] == [3,4,5,6,7,8] \end{verbatim} \ct{foldr} is defined in the standard list library for you: \begin{verbatim} /* foldr fn st l: fold up list l, * right to left with function fn and * start value st */ foldr fn st l = st, l == [] = fn (hd l) (foldr fn st (tl l)) \end{verbatim} \noindent So, for example, you could use \ct{foldr} like this: \begin{verbatim} foldr add 0 [1..5] == 15 \end{verbatim} \noindent (Mathematically, \ct{foldr} is the more basic operation. You can write \ct{map} in terms of \ct{foldr}, but you can't write \ct{foldr} in terms of \ct{map}.) Unconstrained recursion over lists can be very hard to understand, rather like \ct{goto} in an imperative language. It's much better to use a combination of \ct{map} and \ct{foldr} if you possibly can. The toolkit \ct{\_list} contains definitions of most of the standard list-processing functions. These are listed in \tref{tb:list}. Check the source for detailed comments. \begin{tab2} \begin{center} \begin{tabular}{||l|l||} \hline Name & Description \\ \hline \ct{all l} & and all the elements of list \ct{l} together \\ \ct{any l} & or all the elements of list \ct{l} together \\ \ct{concat l} & join a list of lists together \\ \ct{drop n l} & drop the first \ct{n} elements from list \ct{l} \\ \ct{dropwhile fn l} & drop while \ct{fn} is true \\ \ct{extract n l} & extract element \ct{n} from list \ct{l} \\ \ct{filter fn l} & all elements of \ct{l} for which \ct{fn} holds \\ \ct{foldl fn st l} & fold list \ct{l} left-to-right with \ct{fn} and \ct{st} \\ \ct{foldl1 fn l} & like \ct{foldl}, but use the first element of the list as the start value \\ \ct{foldr fn st l} & fold list \ct{l} right-to-left with \ct{fn} and \ct{st} \\ \ct{foldr1 fn l} & like \ct{foldr}, but use the first element of the list as the start value \\ \ct{index fn l} & search list \ct{l} for index of first element matching predicate \ct{fn} \\ \ct{init l} & remove last element of list \ct{l} \\ \ct{iterate f x} & repeatedly apply \ct{f} to \ct{x} \\ \ct{last l} & return the last element of list \ct{l} \\ \ct{len l} & find length of list \ct{l} \\ \ct{limit l} & find the first element of list \ct{l} equal to its predecessor \\ \ct{map fn l} & map function \ct{fn} over list \ct{l} \\ \ct{map2 fn l1 l2} & map 2-ary function \ct{fn} over lists \ct{l1} and \ct{l2} \\ \ct{map3 fn l1 l2 l3} & map 3-ary function \ct{fn} over lists \ct{l1}, \ct{l2} and \ct{l3} \\ \ct{member l x} & true if \ct{x} is a member of list \ct{l} \\ \ct{mkset l} & remove duplicates from list \ct{l} \\ \ct{postfix l r} & add element \ct{r} to the end of list \ct{l} \\ \ct{product l} & product of list l \\ \ct{repeat x} & make an infinite list of \ct{x}es \\ \ct{replicate n x} & make \ct{n} copies of \ct{x} in a list \\ \ct{reverse l} & reverse list \ct{l} \\ \ct{scan fn st l} & apply \ct{(foldr fn r)} to every initial segment of list \ct{l} \\ \ct{sort l} & sort list \ct{l} into ascending order \\ \ct{sortc fn l} & sort list \ct{l} into order by using a comparison function \\ \ct{sortpl pl l} & sort list \ct{l} by predicate list \ct{pl} \\ \ct{sortr l} & sort list \ct{l} into descending order \\ \ct{split fn l} & break list \ct{l} into sections separated by predicate \ct{fn} \\ \ct{splits fn l} & break list \ct{l} into single sections separated by predicate \ct{fn} \\ \ct{splitpl pl l} & break list \ct{l} up by predicate list \ct{pl} \\ \ct{split\_lines n l} & break list \ct{l} into lines of length \ct{n} \\ \ct{sum l} & sum list l \\ \ct{take n l} & take the first \ct{n} elements from list \ct{l} \\ \ct{takewhile fn l} & take from the front of \ct{l} while \ct{fn} holds \\ \ct{zip2 l1 l2} & zip two lists together \\ \ct{zip3 l1 l2 l3} & zip three lists together \\ \hline \end{tabular} \end{center} \caption{Functions in the standard list-processing toolkit} \mylabel{tb:list} \end{tab2} \section{Lazy programming} \mylabel{sec:lazy} \nip{}'s programming language is \emph{lazy}, that is, it delays evaluation as long as it possibly can. For example, \ct{error} is a function which immediately halts execution of your function and pops up an alert window. So: \begin{verbatim} 12 + error "wombat!" \end{verbatim} \noindent Has no value: this expression will halt with an error message. However: \begin{verbatim} false && error "lasagne!" \end{verbatim} \noindent Will evaluate to \ct{false}, since \nip{} knows after looking at the left-hand-side of \ct{\&\&} that the result must be \ct{false}, and so does not evaluate the right-hand-side. \begin{verbatim} [12, error "hot chilli!"] ? 0 == 12 \end{verbatim} \noindent This also evaluates completely, since the second element of the list is never used, and therefore never evaluates. Things become more confusing when you start calling functions, since the arguments to a function call are also not evaluated until the function needs that value. For example: \begin{verbatim} foldr (error "boink!") 2 [] == 2 \end{verbatim} \noindent Again, this evaluates successfully, since the function is never used by \ct{foldr}. \section{Pattern matching} \mylabel{sec:pattern} Any time you define a name, you can use a pattern instead. For example: \begin{verbatim} [fred, petra] = [12, 13] \end{verbatim} \noindent defines \ct{fred} to have the value 12 and \ct{petra} to have the value 13. A pattern describes the structure you are expecting for the value. When the value is computed it is matched against the pattern and, if the match is successful, the names in the pattern are bound to those parts of the value. Our example is exactly equivalent to: \begin{verbatim} temp = [12, 13]; fred = temp?0, is_list temp && is_list_len 2 temp = error "pattern match failed"; petra = temp?1, is_list temp && is_list_len 2 temp = error "pattern match failed"; \end{verbatim} \noindent where \ct{temp} is an invisible, anonymous symbol. You can pattern match on any of \nip{}'s data structures and types. You can use: \begin{description} \item[\ct{a:b}] Tests for the value being a non-empty list and then assigns \ct{a} to the head and \ct{b} to the tail. \item[\ct{(a,b)}] Tests for the value being a complex and then assigns \ct{a} to the real part and \ct{b} to the imaginary. \item[\ct{[a,b,c]}] Tests for the value being a list of length three and then assigns \ct{a}, \ct{b} and \ct{c} to the three elements. \item[\ct{($class-name$ b)}] Tests for the value being an instance of the named class, then assigns \ct{b} to that class instance. \item[\ct{$constant$}] Tests for the value being equal to that constant. Constants are things like \ct{"hello world"} or \ct{12}. \end{description} You can nest patterns in any way you like. Patterns are useful in conjunction with list comprehensions, see \pref{sec:listsyntax}. You can't use patterns in function arguments in the current version, hopefully this will added shortly. \section{The standard libraries} \nip{} comes with a lot of little utility functions. The functions for list processing are listed in \tref{tb:list}. There are a huge number more, too many to really list here. \tref{tb:toolkits} lists all the utility toolkits with some hints about the kinds of function they contain. Read the (heavily commented) toolkits for details. \begin{tab2} \begin{center} \begin{tabular}{||l|l|l||} \hline Toolkit & Contains & Description \\ \hline \ct{\_convert} & \ct{parse\_int l}, \ldots{} & convert ascii text to numbers \\ & \ct{to\_matrix x}, \ldots{} & convert anything into a matrix \\ & \ct{colour\_transform\_to to x}, \ldots{} & convert between colour spaces \\ \hline \ct{\_generate} & \ct{image\_new w h ...} & make a blank image \\ & \ct{image\_white i} & look at image \ct{i}, try to guess what white is \\ & \ct{make\_xy w h} & make an image of size \ct{w} by \ct{h} whose pixel value are \\ & & their coordinates \\ \hline \ct{\_types} & \ct{Image i} & all the standard classes and support functions, \\ & & see \pref{sec:object} \\ \hline \ct{\_predicate} & \ct{is\_colour\_space i} & test for objects are in various categories or have \\ & & various properties \\ \hline \ct{\_stdenv} & \ct{logical\_and x}, \ldots{} & function versions of all the operators \\ & \ct{bandsplit i}, \ldots{} & break up and recombine images by band \\ & \ct{mean x}, \ldots{} & statistical ops on objects \\ & \ct{transpose x}, \ct{flipud x}, \ct{rot90 x}, \ldots{} & flips, rotates, etc. on objects \\ & \ct{rad x}, \ct{pi}, \ldots{} & trigonometry stuff \\ & \ct{sign x}, \ct{conj x}, \ct{polar x}, \ldots{} & complex stuff \\ & \ct{rint x}, \ct{ceil x}, \ldots{} & various rounding things \\ & \ct{fwfft x}, \ldots{} & fourier stuff \\ & \ct{dilate m x}, \ct{rank w h n i}, \ldots{} & morphology stuff \\ & \ct{conv m x}, \ldots{} & convolution stuff \\ & \ct{image\_set\_type t i}, \ldots{} & set various image header field \\ & \ct{resize x y i}, \ldots{} & resampling images \\ & \ct{recomb m i}, \ldots{} & recombinations \\ & \ct{clip2fmt f i}, \ldots{} & format conversions \\ & \ct{hist\_find m x}, \ldots{} & histogram stuff \\ & \ct{id x}, \ct{const x y}, \ldots{} & various useful operations on functions \\ & \ct{map\_binary fn x y}, \ldots{} & mapping over groups \\ \hline \end{tabular} \end{center} \caption{Useful utility functions --- see the source for details} \mylabel{tb:toolkits} \end{tab2} \section{Classes} \mylabel{sec:class} You can define new types using \ct{class}. For example: \begin{verbatim} Pasta_plain = class { lasagne = "large sheets"; fusilli = "sort of twisty"; radiatori = "lots of ridges"; } \end{verbatim} \noindent This defines a new class called \ct{Pasta\_plain}. The class has three members (\ct{lasagne}, \ct{fusilli} and \ct{radiatori}), each of which has a list of \ct{char} as its value. By convention, we've named classes with an initial capital letter, but of course you can do what you like. You can refer to the members of a class using the class project (\ct{.}) operator. For example: \begin{verbatim} Pasta_plain.lasagne == "large sheets" \end{verbatim} \noindent You can use an expression to the right of \ct{.} if you enclose it in brackets. For example: \begin{verbatim} Pasta_plain.("las" ++ "agne") == "large sheets" \end{verbatim} Classes can contain any objects as members, including functions and sub-classes. Functions may define local classes, classes may define local functions, and all may refer to each other using the usual scope rules. For example: \begin{verbatim} Pasta_all = class { filled = class { tortelloni = "venus' navel"; ravioli = "square guys"; } plain = Pasta_plain; } \end{verbatim} When you define a class, \nip{} adds a few extra members for you. \ct{name} is a list of \ct{char} giving the name of the class. \ct{this} and \ct{super} are the most-enclosing class instance and the class instance this class is derived from (see \pref{sec:inheritance}). \nip{} also adds a default constructor: a member with the same name as the class, pointing back to the class constructor. For efficiency reasons \nip{} does not allow mutual recursion at the top level. If two functions depend on each other, neither will ever be calculated. For example: \begin{verbatim} a = 1 : b; b = 2 : a; \end{verbatim} \noindent Neither \ct{a} nor \ct{b} will have a value. You can have mutual recursion between class members. For example: \begin{verbatim} Fred = class { a = 1 : b; b = 2 : a; } \end{verbatim} \noindent Now \ct{Fred.a} will have the value \ct{[1, 2, 1, 2, 1, \ldots{}]}. \subsection{Parameterised classes} Classes can have parameters. Parameters behave like class members initialised from arguments to the class constructor. For example: \begin{verbatim} My_pasta pasta_name cooked = class { is_ready t = "your " ++ pasta_name ++ " is " ++ state { state = "underdone!", t < cooked = "perfect", t == cooked = "yuk!"; } } \end{verbatim} \noindent This defines a class called \ct{My\_pasta} which takes a pasta name and a cooking time as parameters. Once you have made an instance of \ct{My\_pasta}, you can test if it's been cooked at a certain time with the \ct{is\_ready} member. For example: \begin{verbatim} tele = My_pasta "telephoni" 10; tele.is_ready 5 == "your telephoni is underdone!" \end{verbatim} \subsection{Inheritance} \mylabel{sec:inheritance} Classes can inherit from a super-class. For example: \begin{verbatim} Pasta_more = class Pasta_plain { macaroni = "tubes"; spaghetti = "long and thin"; lasagne = "fairly large sheets"; } \end{verbatim} \noindent Here the new class \ct{Pasta\_more} inherits members from the previous class \ct{Pasta\_plain}. It also overrides the definition of \ct{lasagne} from \ct{Pasta\_plain} with a new value. For example: \begin{verbatim} Pasta_more.macaroni == "tubes" Pasta_more.fusilli == "sort of twisty" Pasta_more.lasagne == "fairly large sheets" \end{verbatim} You can use \ct{this} and \ct{super} to refer to other members up and down the class hierarchy. \ct{super} is the class instance that the current class inherits from (if there's no super-class, \ct{super} has the value \ct{[]}), and \ct{this} is the most-enclosing class instance. \begin{verbatim} Pasta_more.super == Pasta_plain Pasta_more.this == Pasta_more Pasta_more.super.this == Pasta_more \end{verbatim} \noindent therefore: \begin{verbatim} Pasta_more.lasagne == "fairly large sheets" Pasta_more.super.lasagne == "large sheets" Pasta_more.super.this.lasagne == "fairly large sheets" \end{verbatim} There's a special symbol \ct{root} which encloses all symbols. For example: \begin{verbatim} fred = 12; Freddage = class { fred = 42; mystery = root.fred; } \end{verbatim} \noindent Now \ct{Fred.mystery} will have the value 12. There's another special symbol called \ct{scope} which encloses all symbols in the file this definition was loaded from. If you want to refer to another definition in the same file which is being masked somehow, use \ct{scope}. You can use the built in function \ct{is\_instanceof} to test whether an instance is or inherits from a class. For example: \begin{verbatim} is_instanceof "Pasta_more" Pasta_more == true is_instanceof "Pasta_plain" Pasta_more == true is_instanceof "Pasta_more" Pasta_plain == false \end{verbatim} The super-class constructor can take arguments, and these arguments can refer to class members. For example: \begin{verbatim} Fresh_pasta pasta_name = class My_pasta pasta_name cooked { cooked = 2; } \end{verbatim} \noindent Defines a class for fresh pasta, which always cooks in 2 minutes. You need to be careful not to make loops: if \ct{cooked} did tried to refer to something in the super-class, this class would never construct properly. \nip{} unfortunately does not check for this error. Finally, the superclass can be a fully constructed class. In this case, the superclass is cloned and the new class members wrapped around it. You can use this to write a class which can wrap any other class and add members to it. Many of the toolkit menu items use this trick to enable them to work for any object type. \subsection{Minor class features} There are a couple of other things you can do with classes. You can define a special member called \ct{\_check}. If this member is defined, then when a class instance is created, the check member is returned instead of the class itself. You can use this to implement class argument type checks, for example: \begin{verbatim} Fred a b = class { _check = this, is_real a && is_real b = error "args to Fred must " ++ "both be real" } \end{verbatim} \noindent Defines a class called \ct{Fred} which has to have two real numbers as arguments. You can define members called \ct{oo\_binary}, \ct{oo\_binary'} and \ct{oo\_unary} and do operator overloading. When \nip{} sees one of the standard operators being used on an instance of your class, it will look up one of these members and pass in the name of the operator and the argument. The two forms of the binary operator member are called for the class-on-left and the class-on-rights cases. So: \begin{verbatim} x = Fred 1 2 x + 12 == x.oo_binary "add" 12 12 + x == x.oo_binary' "add" 12 !x == x.oo_unary "negate" \end{verbatim} These two features are very primitive. The \ct{\_Object} class in the \ct{\_types} toolkit builds on these to provide a fairly high-level system for checking class arguments and defining the meaning of operators. See \pref{sec:object}. \section{Controlling the interface} \mylabel{sec:bowser} \nip{} looks at the scraps of program you type in and execute and tries to show them on the screen in a graphical way. The sorts of display you get depend on where in \nip{} you define the expression, and what sort of value it has. \subsection{Tools and toolkits} \mylabel{sec:tools} Definitions in toolkits are turned into menus off the \ct{Toolkits} menu in the main window, and added to the toolkit browser. Toolkits are loaded from files at startup or can be made in the program window. Toolkit or a definition names which start with an underscore character are hidden and not displayed. The toolkits are always displayed in alphabetical order, but you can order the items within a toolkit in any way you like. There are two ways to write toolkit definitions. Function definitions and zero-argument classes simply appear as menu items, built from static analysis of their source code. However, if a definition evaluates to an instance of the class \ct{Menu}, a menu item is built from dynamic analysis of the value of the definition. \subsubsection{Static menu items} Zero-argument classes within toolkits are displayed as pull-right menus. You can nest classes to any depth. \nip{} uses the first line of the comment before a definition as help text for that function, so it's a good idea to put a simple one-line description of the function at the start of a comment. For example, if the following text is placed in a file called \ct{Fred.def} on \nip{}'s start path, you'll get a menu in the tookits called \ct{Fred} with a pull-right and a tooltip. See \fref{fg:toolkit}. \begin{verbatim} Banana a = a * 3; Subfred = class { // add two things Jim a b = a + b; Apple e = e * 12; Harry z = 12 + z; } \end{verbatim} \begin{figure} \figw{2.5in}{toolkit.jpg} \caption{How \ct{Fred.def} will look} \mylabel{fg:toolkit} \end{figure} \subsubsection{Dynamic menu items} Dynamic menus give you much more control over the way menus are drawn and make it easy to reuse menus. A dynamic menu item is a class instance that is a sub-class of \ct{Menuitem}. It needs to have three members: \ct{label}, the text that should appear in the menu (with an underscore character to indicate the mnenonic); \ct{tooltip}, a short hint that appears as a tooltip or in the toolkit browser; \ct{icon}, an optional image file to be displayed in the menu next to the text; and \ct{action}, the function that is called when the menu item is activated. \ct{label} and \ct{tooltip} are constructor arguments for \ct{Menu}. So for example: \begin{verbatim} Wombat_find_item = class Menuitem "_Find Wombat" "analyse image and locate wombat" { icon = "nip-slider-16.png"; action x = im_wombat_locate x; } \end{verbatim} \noindent will appear as shown in \fref{fg:toolkit2}. \begin{figure} \figw{2.5in}{toolkit2.jpg} \caption{How \ct{Wombat\_find\_item} will look} \mylabel{fg:toolkit2} \end{figure} A dynamic pullright menu is a subclass of \ct{Menupullright}. It's just like \ct{Menuitem}, but without the need for an \ct{action} member. Any members which are subclasses of \ct{Menu} are displayed as items in the submenu. So again: \begin{verbatim} Wombat_item = class Menupullright "_Wombat" "wombat-related operations" { icon = "nip-slider-16.png"; item1 = Wombat_find_item; sep = Menuseparator; boink = Wombat_find_item; } \end{verbatim} \noindent will appear as shown in \fref{fg:toolkit3}. \begin{figure} \figw{2.5in}{toolkit3.jpg} \caption{How \ct{Wombat\_item} will look} \mylabel{fg:toolkit3} \end{figure} \subsection{Workspaces} \mylabel{sec:workspaces} Definitions in workspaces are displayed with \nip{}'s class browser. Each row is displayed in four main parts: a button for the row name, a line of text, a set of sub-rows for the members of the row's class, and a graphic display representing the row's value. See \fref{fg:row2}. \begin{figure} \figw{2.5in}{ir8a.jpg} \caption{Components of a workspace row} \mylabel{fg:row2} \end{figure} The text part of the right-hand-side of each row is always displayed, but the sub-rows are only displayed if the row represents a class, and the graphic is only displayed if the class is an instance of one of the classes in \tref{tb:classes}. You can subclass these if you want to use the graphic display in your own widgets. There are three separate ways to set the value for a row. You can edit the line of program text, you can edit one of the members, or you can manipulate the graphic representation (dragging a slider, or moving a region). These can be contradictory, so \nip{} resolves conflicts by always applying changes in the order text, then graphic, then member. When it applies a graphic change, \nip{} rebuilds the class using a class member called \emph{class-name}\ct{\_edit}, or if that is not defined, the class's constructor member. For example, the \ct{Colour} class can be defined as: \begin{verbatim} Colour colour_space value = class {} A1 = Colour "sRGB" [255,0,0]; \end{verbatim} \noindent There are two ways to change \ct{A1}. You can open \ct{A1} and change \ct{colour\_space} to \ct{"Lab"}, or you can double-click on the swatch and drag the disc. When you click \ct{OK} on the colour edit dialog, \nip{} searches for a member called \ct{Colour\_edit}, fails to find it, and so picks the \ct{Colour} member instead (the default constructor generated by \nip{}). It then replaces the value of A1 with [needs finishing] \begin{tab2} \begin{center} \begin{tabular}{||l|l||} \hline Class & Description \\ \hline \ct{Clock \emph{interval} \emph{value}} & A clock widget, handy for animations \\ \ct{Expression \emph{caption} \emph{expr}} & Displays an editable expression \\ \ct{Group \emph{value}} & A group of objects for iteration \\ \ct{List \emph{value}} & A list of related objects \\ \ct{Pathname \emph{caption} \emph{value}} & Displays a file browser \\ \ct{Fontname \emph{caption} \emph{value}} & Displays a font browser \\ \ct{Toggle \emph{caption} \emph{value}} & A toggle switch \\ \ct{Scale \emph{caption} \emph{from} \emph{to} \emph{value}} & A slider \\ \ct{Option \emph{caption} \emph{labels} \emph{value}} & Select one item from a list \\ \ct{Colour \emph{colour\_space} \emph{value}} & A patch of colour \\ \ct{Matrix\_vips \emph{value} \emph{scale} \emph{offset} \emph{filename} \emph{display}} & A matrix \\ \ct{Arrow \emph{image} \emph{left} \emph{top} \emph{width} \emph{height}} & Two points joined by a line on an image \\ \ct{Region \emph{image} \emph{left} \emph{top} \emph{width} \emph{height}} & A sub-area of an image \\ \ct{Plot \emph{options} \emph{value}} & Displays a plot widget \\ \ct{Image \emph{value}} & An image \\ \ct{Number \emph{caption} \emph{value}} & Displays an editable number \\ \ct{Real \emph{value}} & Displays a real number \\ \ct{Vector \emph{value}} & Displays a list of reals \\ \ct{String \emph{caption} \emph{value}} & Displays an editable string \\ \ct{Mark \emph{image} \emph{left} \emph{top}} & A point on an image \\ \ct{HGuide \emph{image} \emph{top}} & A horizontal line on an image \\ \ct{VGuide \emph{image} \emph{left}} & A vertical line on an image \\ \ct{Area \emph{image} \emph{left} \emph{top} \emph{width} \emph{height}} & A sub-area of an image, fixed in size \\ \hline \end{tabular} \end{center} \caption{\nip{} built in graphic classes} \mylabel{tb:classes} \end{tab2} \subsection{The \ct{Image} class} \mylabel{sec:Image}. say supports mioxed ops with real, vector and complex constants \subsection{The \ct{Colour} class} \mylabel{sec:colour} This class displays a swatch of colour. If you double-click on the \begin{verbatim} Pathname caption value = class {} \end{verbatim} \section{The \ct{\_Object} class} \mylabel{sec:object} \section{Optimisation} \mylabel{sec:optimise} \nip{} performs three useful optimisations on expressions. First, it finds and removes common sub-expressions in functions. So for example: \begin{verbatim} if a + b < 12 then a + b else b \end{verbatim} \noindent will only evaluate \ct{a + b} once. This can save a lot of time if \ct{a} or \ct{b} is a large image. Second, \nip{} detects arithmetic operations on \ct{unsigned char} images, and replaces them with look-up tables. For example: \begin{verbatim} a = vips_image "campin.v" b = a * (a - 1) ** 0.5 \end{verbatim} \noindent Provided \ct{campin.v} is an 8 bit image image, this expression will evaluate with a single call to \ct{im\_maplut()}. Finally, \nip{} has a VIPS operation cache. It memorises the arguments to the last few hundred calls to VIPS, and the result each call gave. Before calling VIPS again, it checks to see if there is a previous call with the same arguments and if there is, uses the result it obtained last time. \section{Calling VIPS functions} \mylabel{sec:callvips} You can call any VIPS operation which has the following properties: \begin{itemize} \item There must be at least 1 output argument. If there's a single output argument, that becomes the value of the function. If there is more than one output, then the function returns a list with the outputs as members. \item The output arguments must all be one of: \begin{itemize} \item \verb+IM_TYPE_DOUBLE+, \item \verb+IM_TYPE_INT+, \item \verb+IM_TYPE_COMPLEX+, \item \verb+IM_TYPE_STRING+, \item \verb+IM_TYPE_IMAGE+, \item \verb+IM_TYPE_DOUBLEVEC+, \item \verb+IM_TYPE_DMASK+, \item \verb+IM_TYPE_IMASK+ \end{itemize} \item The input arguments must all be one of the types above, or \verb+IM_TYPE_DISPLAY+. If an argument is an input display, \nip{} passes in its current display structure, it does not take a display from your program. \end{itemize} When \nip{} starts up, it loads any VIPS plug ins it can find on its data search path. You can call functions from plug ins in just the same way. For information on writing plug ins, see the \emph{VIPS Manual}. nip2-8.7.1/doc/src/nipguide.tex0000644000175000017500000000274213351443023013205 00000000000000\documentclass[a4paper,twocolumn,dvips]{book} \usepackage[dvips=false,pdftex=false,vtex=false]{geometry} \usepackage{relsize} \usepackage{ifpdf} \ifpdf \usepackage[pdftex]{graphicx,color} \else \usepackage{graphicx,color} \fi \usepackage{times} \usepackage{fancyhdr} \usepackage{ifthen} \input{mydefs} \fancyhead{} % clear all fields \fancyhead[LE,RO]{\leftmark} % left-even, right-odd \fancyhead[RE,LO]{\nip{} Manual} % right-even, left-odd \fancyfoot[LE,RO]{\thepage} % left-even, right-odd \fancyfoot[RE,LO]{December 2017} \begin{document} \pagenumbering{roman} \begin{titlepage} \thispagestyle{empty} \begin{center} \huge \nip{} Manual\\[0.2em] \large Version 8.6\\ \vspace{0.5in} \large John Cupitt, Rachel Billinge, Joseph Padfield, Clare Richardson, David Saunders\\ \end{center} % hmm ... must be a better way to get the quote at the bottom of the page \vspace{3in} \begin{center} \noindent \emph{``It's quite simple really, and at the same time, rather complicated.''} \\ --- A.\ Haddock, Sea captain (rtd.) \end{center} \vspace{3in} \noindent \small{This document formatted \today} \setcounter{page}{1} \end{titlepage} %\blankpage \tableofcontents \thispagestyle{plain} %\blankpage \listoffigures \thispagestyle{plain} %\blankpage \listoftables \thispagestyle{plain} \blankpage \pagenumbering{arabic} \thispagestyle{plain} \cfoot{} \input{intro} \input{tutorial} \input{infrared} \input{reference} \input{menus} \input{program} \appendix \input{config} \end{document} nip2-8.7.1/doc/src/tutorial.tex0000644000175000017500000005552513351443023013253 00000000000000\chapter{Tutorial} \mylabel{sec:tutorial} This chapter runs very quickly through how to use \nip{}'s user-interface. See \cref{sec:reference} if you want more details on how the different bits work. \section{Quick interface tour} \mylabel{sec:quicktour} Start up \nip{}. You should see something like \fref{fg:introwin} (the exact look might be different on your system). The menus at the top of the window are very ordinary, except for the \ct{Toolkits} menu which contains all of the image processing operations. The main part of the window shows a workspace. Workspaces are split into tabs (across the top) and each tab is made of a set of columns. The current column, where new objects appear, has a dark green bar across the top. Click on \ctr{File}\ct{Open} to get a file dialog and load up an image. \nip{} can load most image formats, try it and see. Check the \ct{Pin up} box to have the dialog remain after you press OK. You can also drag files from the desktop or from your file manager. After you've loaded an image, \nip{} should look like \fref{fg:loadedimage}. Double click on the thumbnail to open an image view window. Alternatively, select \ct{Edit} from the right-button menu on the thumbnail. See \fref{fg:imageview}. \begin{figure} \figw{3in}{snap2.jpg} \caption{After loading an image} \mylabel{fg:loadedimage} \end{figure} \begin{figure} \figw{3in}{snap3.jpg} \caption{Image view window} \mylabel{fg:imageview} \end{figure} As well as the standard keymappings, \nip{} has extra shortcuts for navigating images, see \tref{tb:shortcuts}. Use the \ctr{View}\ct{Toolbar} menu to turn on other features. You can have a status bar (shows image properties, mouse position and pixel value), a display control bar (lets you change scale and offset for display pixels, click on the arrow on the left for a useful extra menu), a paint bar and some rulers. \begin{tab2} \begin{center} \begin{tabular}{||l|l||} \hline Keys in image display widget & Action \\ \hline \ct{i}, \ct{+} & Zoom in on mouse pointer \\ \ct{o}, \ct{-} & Zoom out \\ Cursor up/down/left/right & Scroll a small amount in direction \\ Shift and cursor up/down/left/right & Scroll a screenful in direction \\ Ctrl and cursor up/down/left/right & Scroll to edge of image \\ Middle mouse drag & Pan image \\ Mouse wheel & Scroll up/down \\ Shift and mouse wheel & Scroll left/right \\ Ctrl and mouse wheel & Zoom in/out \\ \ct{0} (zero key) & Zoom out to fit image to window \\ \ct{1}, \ct{2}, \ct{4}, \ct{8} & Set magnification to 1, 2, 4 or 8 \\ Ctrl and \ct{2}, \ct{4}, \ct{8} & Set zoom out factor to 2, 4 or 8 \\ \hline \end{tabular} \end{center} \caption{\nip{} shortcuts for the image view window} \mylabel{tb:shortcuts} \end{tab2} You can mark things on an image. Hold down Ctrl and drag down and right with the left mouse button to mark a region. Ctrl-left-click to mark a point. Drag up and left to mark an arrow (two points connected by a line). Drag from the rulers to mark guides. Right-click on a label to get a menu which you can use to remove or edit one of these things. Left drag on a label to move the things around, left-drag on the edges or corners to resize. \fref{fg:imageviewregion} shows the same image with stuff marked on it. \begin{figure} \figw{3in}{snap4.jpg} \caption{Image view window with marked regions} \mylabel{fg:imageviewregion} \end{figure} Clean up any messing about and leave two regions on your image. The main window should now look something like \fref{fg:main2regions}. \begin{figure} \figw{3in}{snap5.jpg} \caption{Main window, two regions marked} \mylabel{fg:main2regions} \end{figure} There are three rows visible here, \ct{A1}, \ct{A4} and \ct{A7}. Each row has (from left to right) a pair of up/down arrows (these indicate that the row contains sub-rows: click on the down arrow several times to open the row up and see inside), the name button (left-click to select, Shift-left-click to extend-select, Ctrl-left-click to toggle select, click on the workspace background to unselect everything, left-drag on the name button to reorder items within the column, right-click to get a context menu) and the thumbnail image. Left-click on the name button of one of these images to select it, and then click on \ctr{Toolkits}\ctr{Image}\ctr{Transform}\ctr{Rotate}\ct{Free} (alternatively, if nothing is selected when you click on one of the toolkit menus, \nip{} will apply the operation to the bottom object in the current column). A new row will appear representing the rotation operation. Drag the slider to rotate the image (or type an angle in degrees into the box to the left of the slider and press Return). Pick an interpolation type from the option menu and zoom in on some pixels to check the result. See \fref{fg:rotate}. \begin{figure} \figw{3in}{snap6.jpg} \caption{Using \ctr{Rotate}\ct{Free}} \mylabel{fg:rotate} \end{figure} The same thing works for image processing operations that take two arguments. Left-click on one of your original regions, Ctrl-left-click on the rotated image (the box at the left of the main window status bar says what's selected and in what order), and click on \ctr{Toolkits}\ctr{Image}\ctr{Join}\ct{Left to Right}. A new row appears representing the join operation. Click on \ct{Background Colour}, type in 128 and press Return. Drag the \ct{shim} slider to 50 (or type 50 into the box just to the left of the slider and press Return). See \fref{fg:join}. \begin{figure} \figw{3in}{snap7.jpg} \caption{Using \ctr{Join}\ct{Left to Right}} \mylabel{fg:join} \end{figure} The \ct{Toolkits} menu is large and can be slow and annoying to find things in, so \nip{} has several shortcuts. First, you can tear-off menus by clicking on the dotted line at the top. If you're going to be using one of the sub-menus repeatedly this can save a lot of clicking. Next, you can set keyboard shortcuts for menu items by moving the mouse pointer over the item and pressing the key combination you want to set. Some systems won't let you edit menu shortcuts by default. For example, on GNOME, you need to enable this in \ctr{System}\ctr{Preferences}\ct{Menus \& Toolbars}. Finally, there is a toolkit browser: this shows the same set of items, but in an easier-to-browse way. Click on \ctr{View}\ct{Toolkit Browser} and the browse side-panel will appear, see \fref{fg:browse}. It shows all of the items as a single long list. Type into the search box at the top to only show items which match. Double-click (or press Return) on an item to activate it. Scroll to the right to see what arguments the item needs and what menu it appears in. \begin{figure} \figw{3in}{snap7a.jpg} \caption{The toolkit browser} \mylabel{fg:browse} \end{figure} The box at the bottom of each column is for entering new expressions. You can type stuff here, and \nip{} will make a new row for each item you enter. Try typing \ct{2 + 2} and pressing Return. The syntax is (almost, with a few small differences) the same as the C programming language. See \pref{sec:operators} for a list of the differences. Try multiplying the joined images by a small amount (eg. type something like \ct{A9 * 1.2} and press Return). Normally \nip{} will pick names for new objects for you (like \ct{A1}), but you can set a name yourself if you like. Try entering \ct{fred = 12}. Click the down button once on your brightened image and left-click on the area just below the thumbnail. You should see the stuff you typed to make that row. You can edit it to be anything else, press Return and \nip{} will recalculate. Try going back to your original image (the one you loaded from a file), open an image view window, and try dragging one of the regions. You can change any of the sliders in the rotate or the join rows as well. Right-click on a thumbnail for a useful menu. Use \ct{Save As} to save an image to a file. Use \ct{Replace From File} to change the image in a row (and recalculate the rest of your workspace, very handy). Use \ct{Header} to view an image's metadata. You can also edit the insides of objects. Click the down button next to one of your regions until the \ct{width} and \ct{height} rows appear, click on \ct{width} and type \ct{height * 2}. Now open the image window the region is defined on and try to resize it: you'll find that the width of the region is fixed, but that if you change the height, the width changes with it. This is a very general property of classes in \nip{}: you can use it to join objects together in complex ways, and to modify the behaviour of interactive objects. Right click on a column title bar to get a useful menu. Click on \ctr{File}\ctr{New}\ct{Column} make another column (handy for organising a workspace). If you drag from an image thumbnail on to the workspace background, \nip{} will make a new column for you. You can drop thumbnails on to other thumbnails to make links. There's a useful right-click menu on the tab name. Duplicating tabs is a very easy way to try something out: make a copy of your tab, try changing something, if it doesn't work out, just delete your new tab and go back to where you were. You can drag tabs between workspaces, and you can drag a tab to the desktop to make a new workspace. You can make references between tabs with the tab name and a dot, for example {\ct{tab1.A1}}. You can save columns, tabs or workspaces to workspace files, then merge them back into a colum, as part of a tab, or as a new tab. If \nip{} falls over (I do hope it doesn't), you can usually get your work back by restarting \nip{} and clicking on \ctr{File}\ct{Search for Workspace Backups}. There are a lot of preferences (perhaps too many), see \aref{sec:config}. There is a lot of stuff in the \ct{Toolkits} menus, but they do almost all have tooltips. If you let your mouse hover over a menu item for a moment you should get some helpful text. The toolkit menu is organised by object type. If you want to do something to a matrix, look in the \ctr{Toolkits}\ct{Matrix} menu. The exception is \ctr{Toolkits}\ct{Tasks} which repeats many of the regular toolkit items, but groups them by typical tasks instead. Operations can work on groups as well as on single images, so you can batch things up. If you save a group of images, \nip{} will number each image sequentially for you. You can use \ctr{Edit}\ct{Duplicate} to make copies of objects. If you select lots of objects and duplicate them, \nip{} will (fairly intelligently) rename everything for you so it all still works. \section{\nip{} for reflectogram mosaics} \mylabel{sec:irtut} This section quickly builds an infrared reflectogram mosaic using the sample images that come with \nip{}. See \cref{sec:ir} for detailed coverage. Click on \ctr{File}\ct{Open Examples}. You should see a directory called \ct{1\_point\_mosaic}. Doubleclick and you'll see a file called \ct{1pt\_mosaic.ws}. Doubleclick that and you'll load the workspace for this example. If you'd rather make the workspace yourself, click on the file type filter and select \ct{All files}. A set of 8 images should appear. Click on the first file, shift-click on the last, and click \ct{Open}. This will create a group of all eight images. Right-click on the row and select \ct{Ungroup} to unpack to a set of rows. See \fref{fg:loadsamples}. \begin{figure} \figw{3in}{snap14.jpg} \caption{Loading the sample images} \mylabel{fg:loadsamples} \end{figure} The images have been named to match their positions in the mosaic, so for example \ct{cd2.1.jpg} is the first image in row two. Open up viewing windows for the first two images by double clicking on the thumbnails. Move the two opened images viewers so that they are side by side. Adjust the zoom (using the \ct{i} and \ct{o} keys) and the pan (by dragging with the middle mouse button) so that the overlap area is visible in both images. Mark a tie-point on each image by Ctrl-left-clicking on a feature you can see in both images, see \fref{fg:readyjoin}. Move a point after you've marked it by dragging on the label. You don't need to be exact: \nip{} just uses the point you select as the start point for a search. It can cope with misses of up to about 10 pixels. To mosaic the two images together, click on \ctr{Toolkits}\ctr{Tasks}\ctr{Mosaic}\ctr{One Point}\ct{Left to Right}. See \fref{fg:joined}. \begin{figure} \figw{3in}{snap15.jpg} \caption{Ready to join} \mylabel{fg:readyjoin} \end{figure} \begin{figure} \figw{3in}{snap16.jpg} \caption{Joined images} \mylabel{fg:joined} \end{figure} Picking items deep in the toolkit menu is fiddly, so \nip{} has several shortcuts. First, you can tear off any toolkit menu by clicking on the dotted line at the top. Secondly, you can assign any keyboard accelerator to any menu item. Navigate to the menu item and while it is selected, press the key combination you want to use as a shortcut (for example, Ctrl-L might be good for \ctr{Mosaic}\ctr{One Point}\ct{Left to Right}). Now whenever you press Ctrl-L with the keyboard focus in the main window, you will do a left-right mosaic join. Finally, you can use the toolkit browser to display a selection of the tools in a pane on the right-hand side of the main window. Click on \ctr{View}\ct{Browse Toolkits}, then type ``mosaic'' into the search box at the top. The toolkit browser will display all items related to mosaicing. Double-click an item to do that action. Some systems won't let you edit menu shortcuts by default. For example, on GNOME, you need to enable this in \ctr{System}\ctr{Preferences}\ct{Menus \& Toolbars}. Join the rest of the pairs of sample images together left-right. Once you have made all the rows, join the rows together in turn to make the complete image using \ctr{Mosaic}\ctr{One Point}\ct{Top to Bottom}. When you've built the whole thing you'll see that there are differences in brightness between the tiles that make up your composite image. You can fix most problems like this automatically by selecting your final mosaiced image and clicking on \ctr{Mosaic}\ct{Balance}. This operation takes your mosaic apart, examines the overlap areas for differences in brightness, calculates a set of adjustment factors to minimise these differences, and then rebuilds the mosaic. There can be some problems left even after mosaic balance. Use \ctr{Mosaic}\ct{Tilt Brightness} to remove any left-right or up-down graduations in brightness. Save your mosaic workspace for future reference by clicking on \ctr{File}\ct{Save Workspace}. To save just the mosaiced image, right click on the thumbnail and select \ct{Save As}. \section{\nip{} for nerds} \mylabel{sec:nerdtour} This section sprints through a bit of \nip{} programming, see \pref{sec:program} for full details and a more formal definition of the language. The insides of \nip{} are built with \nip{}'s own programming language. It's a pure lazy functional language with classes. It's C's expression syntax (more or less) plus approximately Miranda/Haskell function syntax, plus some basic class stuff. \nip{}'s main window is a class browser for this programming language. Click on \ctr{Toolkits}\ct{Edit Toolkits} in \nip{}'s main window to pop up the programming window (see \pref{sec:progwin} for details on all the bits in the window), then in the edit area there type: \begin{verbatim} // add two things Fred a b = class { sum = a + b; } \end{verbatim} This defines a class called \ct{Fred} whose constructor takes two arguments, \ct{a} and \ct{b}. There's one member, called \ct{sum}, which is \ct{a} and \ct{b} added together. In the program window, click \ctr{File}\ct{Process}. This makes \nip{} read what you typed, parse it, compile it and update itself. The program window should now look like \fref{fg:Fred}. \begin{figure} \figw{3in}{snap8.jpg} \caption{Programming \ct{Fred}} \mylabel{fg:Fred} \end{figure} If you look back at the main \nip{} window, a new menu will have appeared under \ct{Toolkits} called \ct{untitled}. If you click on that, there will be a menu item called \ct{Fred}. Let your mouse linger, and you'll see a tooltip too. In the main window, type \ct{Fred 2 3} into the box at the bottom of the current column. Press Return and \nip{} will make a \ct{Fred} for you. Click on the down arrow to the left of your new \ct{Fred} once to see the members of \ct{Fred} (just \ct{sum} in this case), click again to see the class parameters too. The main window should look like \fref{fg:mainFred}. \begin{figure} \figw{3in}{snap9.jpg} \caption{Main window \ct{Fred}} \mylabel{fg:mainFred} \end{figure} Click to the right of \ct{b}, type in a new value and press Return. The \ct{sum} member should update. \nip{} keeps track of dependencies between rows, but it also tracks dependencies inside rows, both ones that come from the class, and ones created by any edits you do to the class instance after creating it. You won't see it in a simple example, but \nip{} also discovers and tracks dependencies which can arise at run time. Click on the text just to the right of the \ct{b} button again, type \ct{a} and press Return. Now edit \ct{a}: press Return and both \ct{b} and \ct{sum} will update. You can use \ct{Fred} to add any two things together. Click on \ctr{Toolkits}\ctr{Widgets}\ct{Scale} to make a scale widget, press Ctrl-U (the keyboard shortcut for \ctr{Edit}\ct{Duplicate}) to duplicate it, and finally click on \ctr{Toolkits}\ctr{untitled}\ct{Fred}. Open up the new \ct{Fred} and try dragging some of the scales around. The main window will look like \fref{fg:slideFred}. \begin{figure} \figw{3in}{snap10.jpg} \caption{Scale \ct{Fred}} \mylabel{fg:slideFred} \end{figure} The scales are classes too (instances of \ct{Scale}). You can open them up and do strange things with them as well. Open up one of the scales you made (eg. \ct{A2} in \fref{fg:slideFred}) and change the \ct{from} parameter to be \ct{A3.value}. Now try dragging the sliders again. Try dragging the \ct{sum} slider. Now go back and drag one of the original sliders. You'll see that \ct{sum} no longer updates, it's stuck at the last position you dragged it to. This is because there are now two things affecting the value of \ct{sum}: the underlying code (the \ct{a + b} inside \ct{Fred}), and the position you dragged the slider representing \ct{sum} to. \nip{} has the rule that graphical edits (dragging the slider) override code. To make \ct{sum} update again, right click on the \ct{sum} button and select \ct{Reset} from the pop up menu. Now drag one of the input sliders again, and \ct{sum} will start updating once more. Classes can inherit from other classes. Go back to the program window, click on \ctr{File}\ctr{New}\ct{Tool} to clear the edit window, and type: \begin{verbatim} // multiply two things Jim a b = class Fred a b { product = a * b; } \end{verbatim} This defines a class called \ct{Jim} which inherits from \ct{Fred}. Click \ctr{File}\ct{Process}, then back in the main window, type \ct{Jim 4 5} into the bottom of the column. Click down once to expose the members (just \ct{product}), click again to expose the parameters as well (\ct{a} and \ct{b}), and click a third time to expose the superclass member (which should be an instance of \ct{Fred}). You can also open up the \ct{super} member and see inside the \ct{Fred} that this \ct{Jim} is using as its superclass. \ct{A5} will respond to both \ct{product} and \ct{sum}. See \fref{fg:Jim}. \begin{figure} \figw{3in}{snap11.jpg} \caption{Browsing \ct{Jim}} \mylabel{fg:Jim} \end{figure} \nip{} has about 20 different graphical classes like \ct{Scale}. Whenever a row takes a new value, \nip{} checks to see if that value is an instance of one of these special classes, and if it is, it will add a graphical element to the row display which represents that class's value. It builds the graphical part by looking inside the class for certain members (for example, the scale graphic looks for members called \ct{from}, \ct{to} and \ct{value}). When you change the graphic (maybe by dragging the scale), \nip{} rebuilds the class by looking inside for a edit member (eg. \ct{Scale\_edit}) or if that's not defined, a constructor member (eg. \ct{Scale}). You can make your own graphic widgets by subclassing \nip{}'s built-in ones. By selectively overriding default constructors and adding edit members, you can control how your new widget will behave in expressions, and how it will behave if it's edited graphically. Make a new column, load up an image (use \ctr{File}\ct{Open}), open an image viewer (double-click on the thumbnail), drag out two regions on it (hold down Ctrl and the left mouse button and drag down and right). Your main window should look like \fref{fg:twomoreregions}. \begin{figure} \figw{3in}{snap12.jpg} \caption{Two more regions} \mylabel{fg:twomoreregions} \end{figure} \ct{im\_insert} is a VIPS operation that puts one image inside another at an (x, y) position. VIPS operations work on VIPS images. The \ct{value} member of an \ct{Image} or \ct{Region} is the VIPS image that underlies the \nip{} row. You can use \ct{im\_insert} to make a thing to join two images together. Back in the program window, click on \ctr{File}\ctr{New}\ct{Tool} and enter: \begin{verbatim} // join two images left-right Join a b = class Image value { shim = Scale "Spacing" 0 1000 0; value = im_insert a.value b.value (a.width + shim.value) 0; } \end{verbatim} \noindent Click \ctr{File}\ct{Process}. This defines a class \ct{Join} which subclasses the \ct{Image} graphic. Now select your two regions (click on the first one, shift-click on the second) and click on \ctr{Toolkits}\ctr{untitled}\ct{Join}. Alternatively, just click \ct{Join} and it'll be given the borrom two items in the column. A new \ct{Join} row will appear. Open it up and drag the slider to set the spacing between the two joined images. Go back to the image viewer for the image file you loaded and try dragging one of the regions. \fref{fg:myjoin} shows this class in action. The thing in \ctr{Toolkits}\ctr{Image}\ctr{Join}\ct{Left to Right} is just a slightly fancier version of this. \begin{figure} \figw{3in}{snap13.jpg} \caption{Joining two images with \ct{Join}} \mylabel{fg:myjoin} \end{figure} You can change how the graphic widgets behave by subclassing them. Try: \begin{verbatim} Scale_int c f t v = class scope.Scale c f t ((int) v) { Scale = Scale_int; } \end{verbatim} \noindent This defines a new scale class called \ct{Scale\_int} which can only take integer values. The \ct{Scale = Scale\_int;} line is \ct{Scale\_int} overriding \ct{Scale}'s constructor, so that a \ct{Scale\_int} stays a \ct{Scale\_int} when you drag. Because there's a local called \ct{Scale}, \ct{Scale\_int} needs to use \ct{scope.Scale} to refer to the superclass. Here's a version of \ct{Mark} which can only be dragged in a circle. You pass it an image to display on, an xy centre position, a radius and a start angle. \begin{verbatim} Mark_circle image x y r a = class scope.Mark image _x' _y' { // get rect cods for our point _pos = (x, y) + rectangular (r, a); _x' = re _pos; _y' = im _pos; Mark i l t = this.Mark_circle i x y r a' { // vector from centre of // circle to new position u = (l, t) - (x, y); // angle of vector a' = im (polar u); } } \end{verbatim} nip2-8.7.1/doc/src/menus.tex0000644000175000017500000005160513351443023012532 00000000000000\chapter{Image processing menus} \mylabel{sec:menus} \noindent This chapter is runs quickly through the \ct{Toolkits} menu. See \cref{sec:program} if you want to understand how the menus are written (or want to add more of your own). Use the Toolkit Browser to find stuff. Some things are common to almost all menu items: \begin{description} \item[Tooltips] If you rest your mouse pointer over an item, you'll see a quick description of what the item does. \item[Grouping] You can select several objects, click \ctr{Edit}\ct{Group}, and then when you click the item, it will operate on all the objects in the group. \item[Any type] Almost all items will work on any object. You can add an image and a number, for example, find the colour difference between a number and an image, or transform a matrix from LAB to XYZ. \end{description} \section{Colour} \mylabel{sec:menu-colour} This menu groups operations on colorimetric images and patches of colour. A colour patch is three float numbers plus a tag saying how those number should be interpreted as colour (for example, as a colour in CIE LAB colourspace). You can drag and drop between colour patches, and into and from the inkwell in an image paint window. Double-left-click on a colour patch to open a colour select dialog. \nip{} has 9 main types of colorimetric image, see \tref{tb:colour}. All these types are D65 (that is, daylight) absolute colorimetric. When it displays an image, \nip{} uses the \ct{Type} field in the image header as a hint on how to transform the numbers in the image into RGB for the display. The current \ct{Type} is displayed at the end of the caption line below an image thumbnail. The \ct{Mono}, \ct{GREY16} and \ct{RGB16} types are not really calibrated themselves: they are usually whatever you get by loading an image from a file. You'll usually need an extra step, such as applying an embedded ICC profile, before you get accurate colour. \begin{tab2} \begin{center} \begin{tabular}{||l|l|l||} \hline Name & Format & Notes \\ \hline \ct{Mono} & One band 8 bit & Not calibrated \\ \ct{sRGB} & Three band 8 bit & Screen device space for the sRGB standard \\ \ct{GREY16} & One band 16 bit & Not calibrated \\ \ct{RGB16} & Three band 16 bit & Not calibrated \\ \ct{Lab} & Three band float & The 1976 version of the CIE perceptual colourspace \\ \ct{LabQ} & Four band 8 bit & Like \ct{Lab}, but represented as 10:11:11 bits \\ \ct{LabS} & Three band 16 bit & Like \ct{Lab}, but represented as 15:16:16 bits \\ \ct{LCh} & Three band float & \ct{Lab}, but with polar coordinates \\ \ct{XYZ} & Three band float & The base CIE colourspace \\ \ct{Yxy} & Three band float & Sometimes useful for colour meters \\ \ct{UCS} & Three band float & Highly uniform space from the CMC(l:c) standard \\ \hline \end{tabular} \end{center} \caption{\nip{} colourspaces} \mylabel{tb:colour} \end{tab2} \begin{description} \item[\ct{New}] Make a patch of colour, or pick a colour from a slice through CIELAB colourspace. \item[\ct{Convert To Colour}] Convert anything into a Colour object. \item[\ct{Colourspace}] Change the colourspace. The stored numbers change, but the visual appearance should stay the same. \item[\ct{Tag As}] Change the colourspace tag (the \ct{Type} field in the image header). The stored numbers stay the same, but the visual appearance should change. \item[\ct{Colour Temperature}] Change the colour temperature. \ct{Move Whitepoint} just adjusts the ratios of X and Z using the CIE standard illuminants. \ct{D65 to D50} and \ct{D50 to D65} transform using either a 3x3 matrix which is numerically minimal in XYZ space with respect to the colours on a Macbeth Color Checker, or via Bradford cone space. The Bradford transform omits the power term. The final two items go from XYZ to LAB and back, but with D50 normalisation rather than the default D65. \item[\ct{ICC}] Transform images (not patches of colour) device space to profile connection space (LAB float) and back. You need to be careful about colour temperature issues: all printers work with D50, and \nip{} is all D65. Use the D65 to D50 interchange items in the \ct{Colour Temperature} menu to swap back and forth. All printers also work with relative colorimetry, and \nip{} is generally absolute. Use \ct{Absolute to Relative} to scale an absolute colorimetric image by a media white point. \item[\ct{Radiance}] \nip{} can read and write images written by the Radiance family of programs (usually with the suffix \ct{.hdr}), commonly used in HDR photrography. Images in this format used a packed floating point layout for their pixels. Items in this menu pack and unpack pixels for you. \item[\ct{Difference}] Calculate various colour difference metrics. You can mix patches of colour and colour images. \item[\ct{Adjust}] Change colour in a colorimetric way. \ct{Recombination} multiplies each pixel in an image through a matrix. \ct{Cast} displaces the neutral axis in LAB space. \ct{HSB} lets you adjust an image in LCh colourspace. \item[\ct{Similar Colour}] find pixels in an image with a similar colour to a patch of colour. \item[\ct{Measure Colour Chart}] This takes a trimmed image of a colour chart (a rectangular grid of coloured squares), measures the average pixel value in the centre 50\% of each square, and returns a matrix of the measured values. Use \ct{Make Synthetic Colour Chart} to make a colour chart image from a matrix of measurements. \item[\ct{Plot ab Scatter}] draws a 2 dimensional histogram of the distribution of pixel colours in LAB colourspace. \end{description} \section{Filter} \mylabel{sec:menu-filter} This menu groups operations which filter images, or which are filters in the photoshop sense. \begin{description} \item[\ct{Convolution}] This menu has several standard convolution operations (blur, sharpen, edge detect, etc.), plus the option to convolve with a custom kernel. Two menu items are slightly more complicated. \ct{Unsharp Mask} transforms to CIE LAB colour space, then sharpens just the L band with a cored unsharp filter. The \ctr{Tasks}\ct{Print} menu has a version of this filter tuned for typical inkjet printers. \ct{Custom Blur} builds and applies a square or gaussian convolution kernel for you based on a radius setting. \item[\ct{Rank}] A preset median filter, and a custom rank filter that lets you specify window size and rank. The \ct{Image Rank} item does pixel-wise ranking of a set of images. \item[\ct{Morphology}] These menu items implement basic morphological operations. Images are zero for background and non-zero (usually 255) for object. Matricies are shown as 0, 1 and * for background, object and don't-care. The \ct{Threshold} item does a simple level threshold. Use the \ctr{Math}\ct{Relational} menu to construct more complex image binarisations. Use \ctr{Math}\ct{Boolean} to combine morphologies. The first half of the menu lists simple erode and dilate operations, 4- and 8-way connected. The second half contains several useful compound filters. See also \ctr{Histogram}\ct{Find Profile} for something that can search an image for object edges. And \ct{Math}\ctr{Statistics}\ct{Edges} can count the number of edges across and down an image. \item[\ct{Fourier}] A selection of ideal, Gaussian and Butterworth Fourier space filters. You can make other mask shapes yourself using the \ctr{Image}\ct{Make Patterns} menus, then apply them using \ctr{Math}\ct{Fourier}. You can also use the image paintbox to directly paint out peaks in a fourier-space image before transforming back to real space. \item[\ct{Enhance}] A selection of simple image enhancement filters. \ct{Statistical Difference} passes a window over an image and tries to match the region statistics at each point to a target mean and deviation. \item[\ct{Spatial Correlation}] Place a small image at every possible position in a big image and calculate the correlation at each position. \ct{Simple Difference} is the much faster unnormalised version. \item[\ct{GREYCstoration}] VIPS includes a copy of the CImg library and you can use two useful CImg operations from this menu: denoising and enlarging. \item[\ct{Tilt Brightness}] A selection of tools for adjusting the brightness of an image across it's surface. Useful for correcting lighting problems. \item[\ct{Blend}] Blend two objects together using either a third object to control the blend at each point, or a slider to set all points together. You can blend almost anything with anything. One useful version is to use a text image (see \ctr{Image}\ctr{Make Patterns}\ct{Text}) to blend between two colours (see \ctr{Colour}\ct{New}). \ct{Along Line} does a left/right or top/bottom fade between two images. \item[\ct{Overlay}] Make a colour overlay of two monochrome images. Useful with \ctr{Image}\ctr{Transform} for testing image superposition. \item[\ct{Colourize}] Use a colour image to tint a monochrome image. Useful in conjunction with \ctr{Image}\ctr{Transform}. \item[\ct{Browse}] Look at either the bits or the bands of an image. \item[\ct{Photographic Negative} and friends] A small selection of simple, faintly photoshop-style filters. \end{description} \section{Histogram} \mylabel{sec:menu-histogram} This menu groups operations for finding and transforming image histograms. \nip{} represents histograms and lookup tables as images with \ct{Type} set to \ct{Histogram}. Histograms may have pixels in any format and any number of bands. You can only find histograms of unsigned 8- and 16-bit images. \begin{description} \item[\ct{New}] This makes a new ramp histogram. A set of sliders let you adjust the shape. Use \ct{Map Histogram} to apply your ramp to an image. \ct{Build LUT from Scatter} makes a histogram from a matrix of $(x, y)$ values. \ct{Tag Image as Histogram} marks an image as actually being a histogram after all. \ct{Tone Curve} builds a tone curve which you can later apply to an image. \item[\ct{Find}] A one dimensional histogram treats each band as an independent variable. An $n$-dimensional histogram treats each pixel as a vector of $n$ elements, where $n$ is the number of bands in the image. \item[\ct{Map}] Looks up each pixel in the input in the histogram and sends the found value to the output. \item[\ct{Equalise}] Find the global or locally histogram equalised image. \item[\ct{Cumulative}] Use this and friends to calculate a cumulative histogram (integrate), normalise a histogram and match two histograms. \item[\ct{Find Profile}] Searches from the edges of an image for the first non-zero pixel and returns a profile histogram. \item[\ct{Find Projections}] Sum columns and rows in an image. \item[\ct{Plot Slice}] Mark a guide on an image (drag from the image rulers, or click \ctr{File}\ctr{New}\ct{Guide}) and click \ct{Plot Slice} to make a histogram which is a horizontal or vertical slice through an image. Use \ct{Extract Arrow} to extract the area around an arrow or guide. Use \ct{Plot Object} to make a plot of any object. \end{description} \section{Image} \mylabel{sec:menu-image} This menu groups operations which apply only to images. \begin{description} \item[\ct{New}] Makes a new image. \ct{Region on Image} makes a new region, arrow, guide or mark on an image. It's usually easier to open a viewer on an image and Ctrl-drag. \item[\ct{Convert to Image}] Try to make an image out of anything. \item[\ct{Format}] Switch between the various precisions. \item[\ct{Header}] Try to change or examine the image header in various ways. \item[\ct{Cache}] This caches an image in RAM. Use this to save the results of a long computation. \item[\ct{Levels}] Various tools that change the levels in an image. \ct{Tone Curve} is the only complex one: it lets you adjust the image levels with a set of sliders. \item[\ct{Transform}] Various tools that change the geometry of an image. To use \ctr{Rotate}\ct{Straighten}, mark an arrow on an image (Ctrl-drag up and left in an image view window) along a near-horizontal or near-vertical edge. When you click on \ctr{Rotate}\ct{Straighten}, \nip{} will rotate the image by the smallest amount that makes that edge exactly horizontal or vertical. \ct{Linear Match} takes two images and rotates and scales the second so that the images can be superimposed. Drag the tie-=points to mark common features. Use \ctr{Filter}\ct{Overlay} or \ctr{Filter}\ct{Colourize} to actually superimpose them. \ct{Rubber Sheet} is useful for fixing things like lens distortion. You give \ct{Find} two images, a reference and a distorted version of that reference, and it automatically finds a transform which will map the distorted image back on to the reference image. Use \ct{Apply} to apply the discovered transform to another image. \item[\ct{Band}] Extract/insert/delete image bands. Use \ct{To Dimension} to change image bands into a horizontal or vertical dimension. Use \ct{To Bands} to compress the horizontal or vertical dimension into bands (small images only!). \item[\ct{Crop}] Crops an image. It's often easier to drag out a region. This menu item is only really useful for cropping large groups of images. \item[\ct{Insert}] This takes two images and pastes the smaller into the centre of the larger. The two images have to have the same number of bands. If you open an image viewer on the large image, you'll see an area which you can drag around to set the exact insert point. \item[\ct{Select}] Draw elipses and polygons on an image. Useful for selecting defined areas. \item[\ct{Join}] Use to join two images together bandwise, left/right or up/down. \ct{Array} joins a list of lists of images together into a single large image. \item[\ct{Tile}] Repeat an image horizontally and vertically to make a larger image, or chop an image into a set of tiles. \item[\ct{Patterns}] These items all make useful images for you, from checkerboards to gaussian masks. \ct{XY Image} is the most useful: you can use it to build other patterns. \item[\ct{Test Images}] These items make a variety of useful testcharts for evaluating spatial response and colour. \end{description} \section{Math} \mylabel{sec:menu-math} Basic maths operations on any combination of any objects. You can add a slider to a matrix, for example, then divide by an image. Hopefully most of these are obvious. \begin{description} \item[\ctr{Arithmetic}\ct{Absolute Value Vector}] The absolute value item normally calculates mod of each band of an image separately. By contrast, \ct{Absolute Value Vector} treats each pixel as a vector and calculates the modulus of that. \item[\ct{List}] These aren't really maths operations, but they're in here too. \end{description} \section{Matrix} \mylabel{sec:menu-matrix} This menu groups operations which operate on matricies. \nip{} has four ways of displaying a matrix, but they all behave in the same way under the skin. Almost all the items in the \ct{Math} menu will work on matricies. Most of the matrix operations will also work on images. \begin{description} \item[\ct{New}] The first four items make matricies which display and edit in various ways useful for different applications. The final two make matricies which are pre-filled with useful numbers. \item[\ct{Convert to Matrix}] Try to make anything into a matrix. \item[\ct{Extract}] This group of items extracts various submatricies. You can also do this graphically: just drag-select an area in matrix. \item[\ct{Insert}, \ct{Delete}, \ldots] Also work on images, which can be handy. A 45 degree rotate will only work for square matricies with odd-length sides. \item[\ct{Invert}] Simple matrix-only maths operations. \item[\ct{Plot Scatter}] This takes a two-column matrix where the columns are the X and Y positions of points and draws a scatter graph. \end{description} \section{Object} \mylabel{sec:menu-object} This groups a few items which had no obvious home and which change the format of objects. \begin{description} \item[\ct{Duplicate}] Copy an object, stripping off any derived classes. For images, this really takes a copy of the underlying object (using \ct{im\_copy()}). \item[\ct{List to Group}] Changes lists (see \ctr{Math}\ct{List}) into Groups (see \ctr{Edit}\ct{Group}) and back. A list os an ordered collection of objects. A group is a list that \nip{} will automatically iterate over. \item[\ct{Break Up Object}] This tries to take an object apart. So a multi-band image becomes a list of 1-band images. A matrix becomes a list of vectors, and so on. \ct{Assemble Object} is the inverse. \end{description} \section{Tasks} \mylabel{sec:menu-tasks} This menu repeats many items from other menus, but tries to group them by tasks they are useful for, rather than by function. \subsection{Capture} \mylabel{sec:menu-capture} This menu groups operations which are useful in capturing images, or for the initial processing you might want to do to an image captured from another program. \begin{description} \item[\ct{CSV Import}] Import an image from a CSV file, with a few controls. \item[\ct{Interpret Analyze 7 Header}] Read the meta fields for volume layout and calibration from the Analyze header and reformat the image appropriately. \item[\ct{Capture Video Frame}] This menu item will currently only work on Linux machines with a compatible video4linux capture card. See \pref{sec:vidpref} for notes on how it works. \item[\ct{Smooth}] Use this to remove texture from images. It's handy in conjunction with \ct{Flatfield}. \item[\ct{Flatfield}] Use this to correct homogeneity. Select an image of a piece of white (or mid-grey) card, then select the image to correct, then click \ct{Flatfield}. Use \ct{Smooth} to renmove texture from the white card if necessary. You can select a single white and a group of images to correct a large set in one step \item[\ct{White Balance}] Use this to move the white point to make an area of the image you know to be white, white. Mark a region on an image, enclosing a patch you know to be white. Select the region and the image and click on \ct{White Balance}. \item[\ct{Find Colour Calibration}] Use this to colour calibrate an image. Drag a region enclosing an image of a Macbeth Color Checker Chart and click \ct{Find Colour Calibration}. \item[\ct{Apply Colour Calibration}] Use this to apply the transform calculated by the previous item to another image. Select the calibration object, select the RGB image you want calibrated, and click \ct{Apply Colour Calibration}. \end{description} \subsection{Mosaic} \mylabel{sec:menu-mosaic} The items in this menu are discussed in appalling detail in \cref{sec:ir}. \begin{description} \item[\ct{One Point}] Join two images left-right or top-bottom with a simple translation. Mark a point on each image to be joined (open image view window, Ctrl-left-click, drag to position), then click on the mosaic button. The operation performs elaborate tie-point adjustment, so your selection of a common feature does not have to be exact. The \ct{Manual} versions do not perform automatic tie-point correction and are useful when joing very difficult images. \item[\ct{Two Point}] Do a join, but allow the right-hand (or bottom) image to rotate and scale if it will improve the match. You need to pick two points on each image. \item[\ct{Balance}] Break a mosaic apart, examine average pixel value in the overlap regions, adjust brightness to match, and reassemble. This only works for images which have been produced just by mosaic joins! If you've done anything else to the image since loading it, the balance will fail with a mysterious message. \item[\ct{Manual Balance}] Adjust the brightness in a set of masked areas to match. Useful for removing shadows. \item[\ct{Rebuild}] Use this to mosaic up one set of files based on joins you made in another. Breaks a mosaic part to component files, performs a string substitution on the file names, and reassembles. \item[\ct{Clone Area}] Select over- or under-exposed pixels in one image and replace them with the corresponding pixels from another image. Useful for removing lead numbers used to identify X-ray plates. The function operates on two 8-bit mono images. Move and resize the region on the first image to define the area around the white number. Move the region on the second to overlapping area. A section of the area on the second image is cloned and blended into the first image. The amount of the defined area to be cloned in defined by a slider within the output image. \end{description} \subsection{Picture Frame} \mylabel{sec:menu-picture-frame} Items useful for mocking up painting frames. \subsection{Print} \mylabel{sec:menu-print} Items useful while preparing an image for printing. \begin{description} \item[\ct{Sharpen}] Sharpen an image for printing. This is a version of \ctr{Filter}\ctr{Convolution}\ct{Unsharp Mask} tuned for typical inkjet printers. \item[\ct{Adjust Tone Curve}] Adjust the reproduction tone curve in LAB. Most useful for offset work, especially from transparencies. \end{description} nip2-8.7.1/doc/src/intro.tex0000644000175000017500000000210713351443023012527 00000000000000\chapter{Getting started} \noindent \nip{} is a user interface for the VIPS image processing library. It is designed to be fast, even when working with very large images, and to be easy to extend. This guide is split into quite a few chapters: \begin{itemize} \item If you want to use \nip{} to assemble infrared mosaics, you should read \cref{sec:ir}. The middle section in the tutorial (see \pref{sec:irtut}) does IR mosaics very quickly. \item If you want to use \nip{} for general image processing, work through \cref{sec:tutorial}. \item If you have specific questions about some part of \nip{}'s user-interface, look at \cref{sec:reference}. \item If you're really hardcore, take a look at \cref{sec:program}, which covers programming. \item If you want to know more about VIPS, the image processing package underlying \nip{}, try the \emph{VIPS Manual}. \end{itemize} If \nip{} has installed correctly you should see something like \fref{fg:introwin} when it starts up. \begin{figure} \figw{3in}{snap1.jpg} \caption{\nip{} as it starts up} \label{fg:introwin} \end{figure} nip2-8.7.1/doc/src/mydefs.tex0000644000175000017500000000505213351443023012665 00000000000000% My defs % Computer Text, Computer text=>, Computer Text Display \newcommand{\ct}[1]{\textsf{\smaller{}#1}} \newcommand{\ctr}[1]{\ct{#1} / } \newenvironment{ctd}{\begin{quote}\footnotesize\tt}{\end{quote}} \pagecolor{white} % abbreviations \newcommand{\nip}{\ct{nip2}} \newcommand{\bs}{$\backslash$} \newcommand{\rtp}{\^{ }} \newcommand{\cielab}{\emph{CIE~}$L^{*}a^{*}b^{*}$} \newcommand{\ciexyz}{\emph{CIE XYZ}} \newcommand{\cross}{$\times{}$} % make a label ... override this for HTML output and insert an anchor \newcommand{\mylabel}[1]{\label{#1}} % generate " on page xx" if a label is referring to something on another page % override this for HTML output \newcounter{boink} \newcommand{\onpage}[1]{% \addtocounter{boink}{1}% \label{atref\theboink{}}% \ifthenelse{\pageref{atref\theboink{}}=\pageref{#1}}% {}% { on page~\pageref{#1}}} % format a reference to a section .. "$3.11 on page 37" \newcommand{\pref}[1]{\S\ref{#1}\onpage{#1}} \newcommand{\tref}[1]{Table~\ref{#1}\onpage{#1}} \newcommand{\fref}[1]{Figure~\ref{#1}\onpage{#1}} \newcommand{\cref}[1]{Chapter~\ref{#1}\onpage{#1}} \newcommand{\aref}[1]{Appendix~\ref{#1}\onpage{#1}} % Insert a file ... height and name. \newcommand{\fig}[2]{ \begin{center} \includegraphics[height=#1]{figs/#2} \end{center} } % Insert a file ... width and name. \newcommand{\figw}[2]{ \begin{center} \includegraphics[width=#1]{figs/#2} \end{center} } % make a 2-column figure ... define our own so we can easily override in html % output \newenvironment{fig2}{\begin{figure*}}{\end{figure*}} % same for 2-col tables \newenvironment{tab2}{\begin{table*}}{\end{table*}} % causes problems for htlatex :-( % make this a noop for now % \newcommand{\dtxt}[1]{\multicolumn{25}{@{\hspace{0.2em}}l}{#1}} \newcommand{\dtxt}[1]{#1} % Insert a blank page \newcommand{\blankpage}{% \newpage ~~~~ \pagestyle{plain} \newpage % Another one necessary in twocolumn mode ~~~~ \newpage \pagestyle{fancy} } %\addtolength{\headheight}{3pt} % Make text a bit wider, since we are two column. \addtolength{\textwidth}{0.5in} \addtolength{\oddsidemargin}{-0.25in} \addtolength{\evensidemargin}{-0.25in} % twocolumn seems to remove the binding offset ... add it back %\addtolength{\oddsidemargin}{-0.2in} %\addtolength{\evensidemargin}{0.2in} % More space between headers and footers and the body \addtolength{\topmargin}{-0.5em} \addtolength{\headsep}{0.5em} \addtolength{\footskip}{0.5em} % Swap left and right binding offsets \newlength{\fred} \setlength{\fred}{\oddsidemargin} \setlength{\oddsidemargin}{\evensidemargin} \setlength{\evensidemargin}{\fred} nip2-8.7.1/doc/src/Makefile0000644000175000017500000000172113351443023012313 00000000000000# PDF = nipguide.pdf SRC = \ config.tex \ infrared.tex \ intro.tex \ program.tex \ reference.tex \ menus.tex \ tutorial.tex \ mydefs.tex mkinstalldirs = $(SHELL) ../../mkinstalldirs destdir = ../ all: $(PDF) html install: all $(PDF) html -rm -f ${destdir}/pdf/$(PDF) -mkdir -p ${destdir}/pdf -cp $(PDF) ${destdir}/pdf -rm -rf ${destdir}/html/figs -rm -f ${destdir}/html/*.html -rm -f ${destdir}/html/*.css -mkdir -p ${destdir}/html -cp -r nipguide/* ${destdir}/html $(PDF): $(SRC) pdflatex nipguide.tex pdflatex nipguide.tex .PHONY: html html: -rm -rf nipguide -mkdir -p nipguide htlatex nipguide.tex html.cfg,3 "" -dnipguide/ cp -r figs nipguide -rm nipguide/*.jpg -rm nipguide/*.png .PHONY: clean clean: -rm -f *.4ct -rm -f *.4tc -rm -f *.log -rm -f *.xref -rm -f *.tmp -rm -f *.html -rm -f *.css -rm -f *.lg -rm -f *.idv -rm -f *.aux -rm -f *.dvi -rm -f *.lof -rm -f *.lot -rm -f *.toc -rm -f *.pdf -rm -rf nipguide nip2-8.7.1/doc/doc-programmer/0000755000175000017500000000000013351443023013061 500000000000000nip2-8.7.1/doc/doc-programmer/imageview0000644000175000017500000000057613351443023014711 00000000000000imagemodel is the base model class ... imageview_new makes the imagemodel, then all the component widgets (imagepresent, statusview, paintboxview, conversionview, imageview) watch this for updates the conversion from the real image to the display image is handled by conversion, a sub-model of imagemodel imageview holds the ref to imagemodel ... destroy this and everything goes nip2-8.7.1/doc/doc-programmer/menu.txt0000644000175000017500000001412313351443023014507 00000000000000nip menu organisation here's how it's currently arranged, all ideas for new arrangements welcome you can change the name of any item, move between menus etc. once we pick an arrangement, we're stuck with it forever :-( top level menus are always sorted alphabetically, within each menu, you can have any order you like I was thinking (for example) maybe there should be a "Capture" menu: we could put all the stuff you tend to do when acquiring images in there (eg. crop, white balance, New_video, etc.) Arithmetic Add Subtract Multiply Divide Remainder ------- Absolute_value Absolute_value_vector like abs, but treat pixels as vectors Sign unit vector in direction of value Negate value * -1 Photographic_negative 255 - value (255 == max value for type) Boolean And Or Eor Not ------- Left_shift bitwise left/right shift Right_shift ------- If_then_else Band_and and the bands of an image together Band_or or the bands of an image together Colour Mono_to Mono XYZ Yxy Lab LCh UCS RGB sRGB LabQ LabS Falsecolour XYZ_to Mono XYZ Yxy Lab LCh UCS RGB sRGB LabQ LabS etc. etc. ... every combination of the 10 colour spaces ------- Recombination linear recombination with editable matrix ------- dE_ calculate colour difference between two objects CIELAB UCS ------- Tint_mono_image apply coloured tint to mono image Colour_chart_from_matrix make a synthetic colour chart from a matrix Colour_from_image make a colour from the average colour in image Image_from_colour make a patch of pixels from a colour Similar_colour find similar colours Complex Complex_extract Real extract real part of complex Imaginary extract imaginary part of complex Complex_build combine two reals to make a complex ------- Polar rectangular to (amplitude, phase) Rectangular polar to rectangular Convert Decompose break up compound object Compose combine small objects to make a bigger one ------- Cast_to unsigned_8bit convert numeric types signed_8bit unsigned_16bit signed_16bit unsigned_32bit signed_32bit float_32bit float_64bit complex_64bit complex_128bit Ceil round up Floor round down Rint round nearest Scale_to_byte ------- Convert_to_matrix try to make a matrix from an object Convert_to_image try to make an image from a thing ------- Falsecolour Filter Blur Sharpen Median Laplacian Sobel Linedet Emboss ------- Custom_rank rank filter with editable params Custom_convolution convolution filter with editable params Fourier Fourier_transform Fourier_inverse ------- Ideal_fourier_filter High_low Ring Band Gaussian_fourier_filter High_low Ring Band Butterworth_fourier_filter High_low Ring Band Histogram Hist_find Hist_map Hist_cumulative Hist_normalise Hist_match ------- Hist_equalise Global Local Guide_slice graph pixel values along a guide Image Copy ------- Adjust_scale_offset Adjust_gamma Custom_sharpen White_balance Light_correct_white_image Smooth_image Drop_shadow Join Abut Left_right Top_bottom Crop List Head Tail Init Last ------- Reverse Sort Make_set Transpose_list Concat ------- Length Subscript Take Drop ------- Join Cons Zip Log Exponential Log_natural ------- Log10 Exponential10 ------- Raise_to_power Morphology Dilate8 Dilate4 Erode8 Erode4 ------- Open Close Clean Thin ------- Dilate Erode Dilate_multiple Erode_multiple ------- Custom_morphology Find_profile search an image for edge profiles Mosaic Mosaic_translate the two-point funcs Left_right Top_bottom Mosaic_affine the four-point funcs Left_right Top_bottom ------- Mosaic_balance Tilt_brightness Left_right Top_bottom ------- Mosaic_rebuild rebuild mosaic with different files New New_slider New_toggle New_option New_matrix Convolution Recombination Morphology New_image New_colour New_video just linux video at the moment ------- New_eye New_zone_plate New_grey New_xy New_gauss_noise New_fractal New_CRT_test_chart New_frequency_test_chart New_checkerboard New_grid New_ideal High_low this set of items make fourier filter masks Ring Band New_gaussian High_low Ring Band New_butterworth High_low Ring Band ------- New_CIELAB_slice slice through cielab New_LAB_colour pick a colour with a poiont on a LAB slice Plot Plot_scatter Print ICC_export PCS -> device ICC_import device -> PCS ICC_transform device -> device ICC_ac2rc ------- D65XYZ_to change white point for measure/print D50XYZ D50XYZ_to D65XYZ D50XYZ_to Lab D50Lab_to XYZ ------- Sharpen_for_print Morph_for_print Relational Equal Not_equal More Less More_equal Less_equal Resize Resize_image change size by a scale factor Resize_xy_image separate xy scale factors Resize_canvas ------- Shrink_to Quicklook shrink to smallest axis == 64 pixels Icon shrink to smallest axis == 400 pixels Rotate Rotate_fixed r90 r180 r270 r45 Rotate_free rotate with a slider ------- Flip up_down left_right Transpose ------- Straighten_arrow rotate to get an arrow straight Statistics Mean Deviation Stats ------- Max Min Maxmin Maximum_position Minimum_position ------- Count_set Count_clear ------- Measure_colour_chart Statistical_difference more of a filter really :-( Count_lines Trig Sin Cos Tan ------- Asin Acos Atan ------- Rad Deg ------- Angle_range is angle within arc ... clock arithmetic nip2-8.7.1/doc/doc-programmer/hierarchy.txt0000644000175000017500000000304313351443023015520 00000000000000class hierarchy =============== GObject | +-iObject | +-Heap +-Imagemodel +-Toolviewitemgroup +-iContainer | +-Compile +-Expr +-Imageinfo +-Watch +-Model | +-Conversion +-Toolkitgroup +-Workspacegroup +-Filemodel | | | +-Tool | +-Toolkit | +-Column | +-Symbol | | | +-Workspace | +-Heapmodel | +-Rhs +-Subcolumn +-iText +-Row +-Classmodel | +-Slider +-Patch +-Filename +-Fontname +-Expression +-Number +-Matrix +-String +-Option +-Toggle +-iRegiongroup +-iArrow +-iImage | +-iRegion GtkVBox View Textview Workspacegroupview Workspaceview Toolkitgroupview Toolkitview Toolview Graphicview Toggleview Sliderview Patchview Filenameview Fontnameview Optionview iArrowview Matrixview Regionview iImageview iRegionview Editview Stringview Numberview Expressionview Rhsview Rowview Subcolumnview Spin Columnview iRegiongroupview Imagepresent GtkFrame Conversionview Statusview GtkDrawingArea Imagedisplay GtkWindow iWindow Imageview Program Trace iDialog Namecaption Find Imageheader Browse Filesel GtkEventBox Formula nip2-8.7.1/doc/doc-programmer/regionview0000644000175000017500000000073313351443023015105 00000000000000how regionviews are built and maintained iregion iregionview end of parent_add, make iregiongroup child iregiongroup iregiongroupview monitor object updates, on iregiongroupview_refresh() create and set and unset model->display destroy regionview ... watches iregion model regionview_new( iregion, area, imagepresent ) does not view_link(), since it's not a true view ... adds own signal handlers for "changed" and "destroy" on iregion/iarrow nip2-8.7.1/doc/doc-programmer/makeindex.pl0000755000175000017500000000021713351443023015306 00000000000000#!/usr/bin/perl # my labels = `grep '&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # 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: